Skip to content

feat: inject effort as soft default via CLI flags instead of env var (unlocks /effort and ultracode switching)#104

Open
TeigenZhang wants to merge 1 commit into
Ark0N:masterfrom
TeigenZhang:feat/effort-soft-default
Open

feat: inject effort as soft default via CLI flags instead of env var (unlocks /effort and ultracode switching)#104
TeigenZhang wants to merge 1 commit into
Ark0N:masterfrom
TeigenZhang:feat/effort-soft-default

Conversation

@TeigenZhang
Copy link
Copy Markdown
Contributor

Problem

Codeman currently carries the Thinking Effort setting as the CLAUDE_CODE_EFFORT_LEVEL env var (set via tmux setenv from envOverrides). The env var is a hard override in Claude Code: it locks effort for the whole session and makes the CLI reject in-session /effort switching with:

CLAUDE_CODE_EFFORT_LEVEL=high overrides effort this session — clear it and ultracode takes over

This makes it impossible to run a session at a normal effort level and temporarily switch to ultracode (xhigh + dynamic workflow orchestration, claude >= 2.1.154) — or any other level — without recreating the session.

Solution

Carry effort as a dedicated effort payload field and inject it at spawn time as a soft default the user can override anytime via /effort:

Level Carrier Why
low / medium / high / xhigh / max claude --effort <level> the settings effortLevel key is enum(["low","medium","high","xhigh"]).catch(undefined)max gets silently dropped there
ultracode claude --settings '{"ultracode":true}' dedicated boolean settings key; rejected by the --effort flag

Both carriers verified against claude CLI 2.1.167: effort is active at spawn (banner + status bar) and /effort switching works freely in both directions.

Changes

  • Schemas: effort enum field on CreateSessionSchema / QuickStartSchema / RalphLoopStartSchema
  • Backend: threaded through Session._effortCreateSessionOptions / RespawnPaneOptionsbuildSpawnCommand (tmux) and buildInteractiveArgs (direct-PTY fallback); persisted in SessionState.effort and restored on reboot recovery
  • buildEffortCliArgs() in session-cli-builder.ts — single source for both carriers, allowlist-validated (injection-safe)
  • Frontend: buildEnvOverrides() no longer emits CLAUDE_CODE_EFFORT_LEVEL; new getEffortSetting() validates and sends the effort field from quick-start, session create, resume, and Ralph wizard payloads
  • Settings UI: Ultracode (multi-agent workflows) option added to the Thinking Effort dropdown; hint updated
  • Legacy migration (3 paths):
    • Session constructor extracts CLAUDE_CODE_EFFORT_LEVEL from persisted __envOverrides into effort
    • applyEnvOverrides() unconditionally unsets the stale var on the tmux session so respawned panes are no longer locked
    • invalid legacy values are dropped instead of forwarded
  • Tests: test/effort-injection.test.ts — 13 cases covering carrier mapping, injection guards, args building, and constructor migration
  • Docs: CLAUDE.md gotcha documenting why effort must never be an env var

Test plan

  • tsc --noEmit, lint, format:check clean
  • npm test -- test/effort-injection.test.ts — 13/13
  • E2E: quick-start with effort=max → process spawned with --effort max, banner shows max effort, /effort ultracode switch works
  • E2E: quick-start with effort=ultracode--settings '{"ultracode":true}', status bar shows ultracode · xhigh effort + dynamic workflows, /effort high/effort ultracode switching works
  • Legacy session with env var in state.json recovers with effort migrated and tmux var unset
  • Playwright: settings dropdown renders all 7 options, getEffortSetting() validation verified in-page

CLAUDE_CODE_EFFORT_LEVEL hard-locks effort for the whole session and makes
Claude reject in-session /effort switching (incl. ultracode). Carry effort
as a dedicated payload field instead, injected at spawn as a soft default:

- regular levels (incl. max) -> claude --effort <level>
  (the settings effortLevel key is enum([low,medium,high,xhigh]) with
  .catch(undefined), so max would be silently dropped there)
- ultracode -> claude --settings '{"ultracode":true}'
  (dedicated boolean settings key, rejected by the --effort flag)

Changes:
- add effort enum field to create/quick-start/ralph-loop schemas and thread
  it through Session -> CreateSessionOptions/RespawnPaneOptions -> spawn
- buildEffortCliArgs() in session-cli-builder, shared by tmux spawn command
  and direct-PTY fallback args
- frontend: buildEnvOverrides() no longer emits CLAUDE_CODE_EFFORT_LEVEL;
  validated effort goes into payloads via getEffortSetting()
- settings UI: add Ultracode option to the Thinking Effort dropdown
- legacy migration: Session constructor extracts CLAUDE_CODE_EFFORT_LEVEL
  from persisted envOverrides; applyEnvOverrides() unsets the stale tmux
  session var so respawned panes are no longer locked
- tests: test/effort-injection.test.ts (13 cases)
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