Skip to content

refactor: pass envOverrides via tmux export instead of disk write#74

Merged
Ark0N merged 2 commits intoArk0N:masterfrom
TeigenZhang:refactor/envoverrides-tmux-export
Apr 28, 2026
Merged

refactor: pass envOverrides via tmux export instead of disk write#74
Ark0N merged 2 commits intoArk0N:masterfrom
TeigenZhang:refactor/envoverrides-tmux-export

Conversation

@TeigenZhang
Copy link
Copy Markdown
Contributor

Summary

Before this change, POST /api/sessions persisted envOverrides (e.g. CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS) to <case>/.claude/settings.local.json so Claude CLI would pick them up on spawn. That had two problems: UI dropdown state could drift from the file on disk, and the backend was silently writing into user project directories as a side-effect of opening a session.

This refactor makes envOverrides ephemeral spawn-time state:

UI dropdown → POST /api/sessions { envOverrides }
           → new Session({ envOverrides })
           → session._envOverrides
           → tmux-manager.buildEnvExports → `export KEY=<shellescape(VALUE)>` prepended to the pane's spawn command
  • Survives respawnPane cycles via session._envOverrides
  • Survives server restart via SessionState.envOverrides in state.json
  • Introduces session-ui.js#buildEnvOverrides(caseSettings, globalSettings) as the single source of truth for the payload
  • Removes updateCaseEnvVars import from session-routes.ts (now unused)

Benefits

  • No more stale .claude/settings.local.json files in user project directories
  • UI state and spawn env are guaranteed consistent (one code path, one source)
  • Frontend preview ("this is what will be exported") is trivially composable

Test plan

  • Session spawn with agentTeams enabled → tmux pane sees CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in env
  • Respawn pane preserves env overrides across restart
  • ~/.codeman/state.json contains envOverrides for each session, restored on server restart
  • No writes to <case>/.claude/settings.local.json triggered by session creation
  • npm run typecheck / npm run lint / npm run build pass

Teigen and others added 2 commits April 24, 2026 09:49
CLAUDE_CODE_EFFORT_LEVEL (and any CLAUDE_CODE_* / OPENCODE_* key) now flows:
  UI dropdown → POST /api/sessions { envOverrides }
             → new Session({ envOverrides })
             → this._envOverrides
             → tmux-manager.buildEnvExports appends `export KEY=<shellescape(VALUE)>`

Previously the API wrote envOverrides to <case>/.claude/settings.local.json, which
created stale state (UI dropdown disagreeing with disk) and polluted user project
directories. Now envOverrides are ephemeral spawn-time state, preserved across
respawnPane cycles via this._envOverrides and across server restart via
SessionState.envOverrides in state.json.

Also removes the now-unused updateCaseEnvVars import from session-routes.ts.
Resolved conflict in src/web/public/session-ui.js by keeping this
PR's buildEnvOverrides() helper — it already covers both
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS (this PR) and
CLAUDE_CODE_EFFORT_LEVEL (added in Ark0N#73), so the master-side inline
block is fully replaced.

Also fixed test/session-manager.test.ts MockSession to add a
getEnvOverridesForPersist() stub — without it,
SessionManager.updateSessionState's new call breaks 19 tests with
"TypeError: session.getEnvOverridesForPersist is not a function".

Verified: typecheck, lint, format:check, build, and
test/{session-manager,session-state,tmux-manager,tmux-restart-recovery}.test.ts
all pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Ark0N
Copy link
Copy Markdown
Owner

Ark0N commented Apr 28, 2026

Thanks for this — the refactor is well-thought-out and addresses a real wart (silent writes into user case dirs). The tmux setenv approach is the right call: keeps secret values off the bash command line (ps-visible) while still surviving respawn-pane. The __envOverrides internal field with CLAUDE_CODE_*-only persistence filter is a sensible compromise between recovery and not leaking OPENCODE_* secrets into state.json. And the buildEnvOverrides helper is a nice cleanup of the four duplicated frontend call sites.

Two things I had to handle before merging:

  1. Merge conflict with feat: thinking effort setting for new sessions (with xhigh/max) #73 (thinkingEffort) in src/web/public/session-ui.js. Resolved by keeping your buildEnvOverrides() helper — it already covers both CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS and CLAUDE_CODE_EFFORT_LEVEL, so the master-side inline block is fully replaced. Clean replacement, no behavioral drift.

  2. Test fix in test/session-manager.test.ts: the MockSession class doesn't extend the real Session, so it didn't have getEnvOverridesForPersist. After updateSessionState started calling it, 19 tests failed with TypeError. Added a stub that returns undefined (matches the real method's contract for sessions without overrides).

Verified locally: typecheck, lint, format:check, build, and the four most-relevant test files (session-manager, session-state, tmux-manager, tmux-restart-recovery) all pass.

Merging now. 🙏

@Ark0N Ark0N merged commit d07b59d into Ark0N:master Apr 28, 2026
1 check passed
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.

2 participants