# How Nested Herdr Detection Is Implemented: Environment Variables and Configuration

> Learn how nested Herdr detection works using environment variables and configuration settings. Understand the HERDR_ENV=1 variable and allow_nested flag.

- Repository: [Can Celik/herdr](https://github.com/ogulcancelik/herdr)
- Tags: internals
- Published: 2026-05-31

---

**Nested Herdr detection relies on an environment variable (`HERDR_ENV=1`) injected into every spawned pane and validated at startup against the experimental `allow_nested` configuration flag to prevent recursive UI sessions by default.**

The `ogulcancelik/herdr` repository implements nested Herdr detection using a lightweight inheritance-based mechanism to identify when a new instance launches inside an existing Herdr-managed pane. This approach prevents confusing recursive terminal sessions while allowing power users to opt-in via explicit configuration settings.

## Environment Variable Injection in Pane Spawning

Herdr marks every pane it creates by setting a specific environment variable that propagates to all child processes. In [`src/pane.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/pane.rs), both the `spawn_with_initial_history` and `spawn_shell_command` functions build a `CommandBuilder` that explicitly injects the marker before launching the shell or command:

```rust
cmd.env(crate::HERDR_ENV_VAR, crate::HERDR_ENV_VALUE);

```

This corresponds to lines 77-78 in [`src/pane.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/pane.rs), where `HERDR_ENV_VAR` and `HERDR_ENV_VALUE` resolve to `HERDR_ENV` and `1` respectively. Because environment variables automatically inherit through subprocesses, any command—including a new Herdr binary—launched from within that pane will carry `HERDR_ENV=1` in its environment.

## Detection Logic at Startup

When Herdr initializes, it immediately checks for the presence of this inherited marker to determine if it is running inside an existing Herdr session.

### The should_block_nested_for_env Check

The core validation occurs in [`src/main.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/main.rs) within the `should_block_nested_for_env` function (lines 79-81). This helper checks two conditions simultaneously:

1. The `HERDR_ENV` environment variable is set to the magic value `1`.
2. The `allow_nested` configuration flag is `false` (the default setting).

If both conditions evaluate to true, the function returns true, signaling that the current launch should be blocked to prevent nesting.

### Consistency in Self-Updates

The same environment variable check is reused in [`src/update.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/update.rs) during Herdr’s self-update process. This ensures that update operations maintain consistency with the nested detection logic and do not inadvertently spawn recursive instances during version upgrades.

## Configuration Override and Blocking Behavior

Users who require nested Herdr sessions can bypass the default protection through an experimental configuration toggle.

### The allow_nested Experimental Flag

In [`src/config/model.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/config/model.rs) (lines 339-340), the configuration struct defines:

```rust
pub allow_nested: bool,

```

When users set `allow_nested = true` under the `[experimental]` section of [`herdr.toml`](https://github.com/ogulcancelik/herdr/blob/main/herdr.toml), the `should_block_nested_for_env` check returns false regardless of the environment variable’s presence. This permits the nested instance to initialize normally.

### Process Termination with exit_if_nested_disabled

If nesting is detected and the configuration flag remains false, [`src/main.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/main.rs) invokes `exit_if_nested_disabled` (lines 94-100). This function prints a clear error message explaining that nested Herdr is disabled by default, selects a random quip from the `NESTED_HERDR_MESSAGES` array (defined in lines 12-18), and terminates the process with exit status 1.

## Practical Usage Examples

Attempting to launch Herdr inside an existing Herdr pane without configuration changes results in immediate termination:

```bash

# Inside a Herdr-managed pane

$ herdr server
error: nested herdr is disabled by default.
see configuration if you want to enable it.

"inception detected. we need to go deeper... said no one ever."

```

To enable nested sessions, create or modify your [`herdr.toml`](https://github.com/ogulcancelik/herdr/blob/main/herdr.toml) configuration file:

```toml
[experimental]
allow_nested = true

```

After reloading the configuration, the same command will succeed because `should_block_nested_for_env` no longer triggers the exit handler.

## Summary

- **Environment marking**: [`src/pane.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/pane.rs) sets `HERDR_ENV=1` on every spawned pane, creating an inheritance chain that identifies Herdr-managed contexts.
- **Dual-condition check**: [`src/main.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/main.rs) uses `should_block_nested_for_env` to verify both the environment variable and the `allow_nested` config flag before proceeding.
- **Graceful blocking**: `exit_if_nested_disabled` terminates prohibited nested launches with a helpful error and a random message from `NESTED_HERDR_MESSAGES`.
- **User override**: The `allow_nested` boolean in [`src/config/model.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/config/model.rs) provides an opt-in mechanism for power users who need recursive terminal sessions.
- **Update consistency**: [`src/update.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/update.rs) reuses the same detection logic to ensure self-update operations respect nesting constraints.

## Frequently Asked Questions

### How does Herdr detect if it is running inside another Herdr instance?

Herdr checks for the `HERDR_ENV` environment variable at program startup in [`src/main.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/main.rs). This variable is set to `1` by the `CommandBuilder` in [`src/pane.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/pane.rs) (lines 77-78) whenever Herdr spawns a new pane. If the variable is present and the `allow_nested` configuration flag is false, Herdr recognizes itself as nested and invokes `exit_if_nested_disabled` to prevent initialization.

### Can I disable nested Herdr detection to run recursive sessions?

Yes. Set `allow_nested = true` under the `[experimental]` section in your [`herdr.toml`](https://github.com/ogulcancelik/herdr/blob/main/herdr.toml) configuration file. According to the source in [`src/config/model.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/config/model.rs) (lines 339-340), this boolean changes the behavior of `should_block_nested_for_env` in [`src/main.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/main.rs) to permit the nested instance to run regardless of the environment variable’s presence.

### Where exactly is the HERDR_ENV variable set in the source code?

The variable is injected during pane creation in [`src/pane.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/pane.rs). Specifically, the `spawn_with_initial_history` and `spawn_shell_command` functions call `cmd.env(crate::HERDR_ENV_VAR, crate::HERDR_ENV_VALUE)` before launching the child process. This ensures every shell or command running inside a Herdr pane inherits `HERDR_ENV=1`.

### What error appears when trying to run Herdr inside an existing Herdr pane?

The process exits with status code 1 after `exit_if_nested_disabled` (lines 94-100 in [`src/main.rs`](https://github.com/ogulcancelik/herdr/blob/main/src/main.rs)) prints a standard error message stating that nested Herdr is disabled by default. This is followed by a randomly selected string from the `NESTED_HERDR_MESSAGES` array, such as "inception detected. we need to go deeper... said no one ever."