Skip to content

scope client env to sessions so herdr extensions see the right pane - #303

Merged
kevinjosethomas merged 11 commits into
mainfrom
feat/herdr-env-per-session
Jul 2, 2026
Merged

scope client env to sessions so herdr extensions see the right pane#303
kevinjosethomas merged 11 commits into
mainfrom
feat/herdr-env-per-session

Conversation

@kevinjosethomas

@kevinjosethomas kevinjosethomas commented Jul 1, 2026

Copy link
Copy Markdown
Member
  • extensions run in the daemon, so a shared daemon served every herdr pane the env of whichever client spawned it first; Pass herdr env vars from interactive client through daemon protocol to extensions #276 fixed this by mutating global process.env on create/attach, which lets concurrent panes clobber each other.
  • the interactive client now forwards an allowlist of herdr env vars on create and attach, and the daemon stores them per session instead of touching its own env.
  • extension subprocesses get the session's env merged over process.env at exec time, and extension loading (plus /reload) runs in a serialized scoped-env window since extensions capture pane identity synchronously at load.

Note

Medium Risk
Touches daemon session lifecycle, concurrent env-window locking, and subprocess env for all extension exec paths; wrong scoping could leak or mix pane identity across sessions.

Overview
Replaces shared daemon process.env mutation with per-session client env so concurrent herdr panes no longer clobber each other.

Interactive clients send an allowlisted herdr env on create (and primary attach with sendClientEnv). The daemon stores it on ActiveSessionState, adopts-if-absent when reusing env-less sessions (e.g. cron), and never overwrites an existing identity.

withClientEnv temporarily pins that env during extension load/reload and serializes exclusive windows vs env-less loads. setRuntimeEnvScope / scopedBuild wrap every runtime rebuild (new/switch/fork/import, subagents). pi.exec merges session env at spawn via getExecEnv / execEnvForSession without mutating the daemon’s global env. Subagents inherit the parent’s clientEnv.

Reviewed by Cursor Bugbot for commit a39171b. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope client env to daemon sessions so extensions see the correct environment per pane

  • Adds a DaemonClientEnv allowlist and protocol fields so create and attach commands carry the client's env to the daemon; attach adopts env only if the session has none (adopt-if-absent).
  • Pins a per-session exec env provider so pi.exec() subprocesses use the session's client env rather than the daemon's global process.env.
  • Wraps all extension load windows (runtime builds, reloads, subagent creation) in withClientEnv to ensure extension modules see the correct env during evaluation.
  • Subagents inherit their parent session's client env for both extension loading and exec.
  • Risk: withClientEnv uses an exclusive lock during env-bound loads; high session concurrency may serialize extension reloads briefly.

Macroscope summarized a39171b.

Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-client-env.ts
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-protocol.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts Outdated
Comment thread packages/coding-agent/src/main.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium

The new_session, switch_session, fork, and import_jsonl handlers rebuild the runtime via state.runtime's stored factory, which calls createAgentSessionRuntime() with the unwrapped this.options.createRuntime. Extensions are loaded during that factory call without withClientEnv(state.clientEnv, ...), so state.clientEnv is never applied to process.env and pane-scoped extensions cannot read their client identity (e.g. HERDR_PANE_ID). Only the explicit reload command wraps extension loading in withClientEnv, so any session-replacement flow silently drops client env from extension load context.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/modes/daemon/daemon-mode.ts around line 1311:

The `new_session`, `switch_session`, `fork`, and `import_jsonl` handlers rebuild the runtime via `state.runtime`'s stored factory, which calls `createAgentSessionRuntime()` with the unwrapped `this.options.createRuntime`. Extensions are loaded during that factory call without `withClientEnv(state.clientEnv, ...)`, so `state.clientEnv` is never applied to `process.env` and pane-scoped extensions cannot read their client identity (e.g. `HERDR_PANE_ID`). Only the explicit `reload` command wraps extension loading in `withClientEnv`, so any session-replacement flow silently drops client env from extension load context.

Comment thread packages/coding-agent/src/core/exec.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 423de56. Configure here.

Comment thread packages/coding-agent/src/modes/daemon/daemon-client-env.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-client-env.ts
…ssion

# Conflicts:
#	packages/coding-agent/src/modes/daemon/daemon-mode.ts
#	packages/coding-agent/test/daemon-mode.test.ts
@kevinjosethomas
kevinjosethomas merged commit f4cfde0 into main Jul 2, 2026
3 checks passed
@kevinjosethomas
kevinjosethomas deleted the feat/herdr-env-per-session branch July 8, 2026 00:29
zhengr pushed a commit to zhengr/prime-agent that referenced this pull request Aug 8, 2026
…rimeIntellect-ai#303)

* pass herdr client env through the daemon scoped per session

* inherit client env in subagents and guard against watcher and cross-session env leaks

* bind client env once at session creation and never rebind on reuse

* scope env around the daemon reload command and adopt env on env-less session reuse

* propagate adopted client env to subagents spawned before adoption

* let the primary interactive attach adopt env for env-less sessions

* scope client env around all runtime rebuilds via a runtime env scope hook

* cover adopt-if-absent client env semantics on session reuse

* pin allowlisted exec env per session so foreign env windows cannot leak into subprocesses

* pin the full allowlist inside env windows so partial client env cannot mix with ambient values
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant