Summary
Starting a session for a Docker-linked case fails with Claude CLI not found when the corresponding agent CLI is not installed on the host. For a Docker case the CLI runs inside the container, so the host copy is never executed — the guard is a precondition for a value that the docker branch discards a few lines later.
shell mode works, every agent mode fails.
Environment
- Codeman v1.21.0, installed with
npm install -g aicodeman
- Host: Debian 13 (trixie), Node 22.23.2, tmux 3.5a, Docker 29.6.2
- Codeman runs as a systemd user service
- Agent image built locally from
docker/agent.Dockerfile — contains claude 2.1.240, codex 0.149.0, gemini 0.56.0, opencode 1.18.21, agy 1.1.18, pi 0.84.2
- No agent CLIs installed on the host
Steps to reproduce
- Install Codeman on a host that has no agent CLI:
npm install -g aicodeman
- Build the agent image from
docker/agent.Dockerfile
- Create a Docker case (New case → Docker) pointing at an existing repo directory
- Start a Shell session → works, runs inside the container
- Start a Claude session → fails
Expected
The Claude session starts inside the container, exactly like the Shell session does. docker/agent.Dockerfile ships claude, so nothing is missing where the CLI actually runs.
Actual
[Session] Starting interactive Claude session (with tmux)
[Session] Failed to create mux session, falling back to direct PTY: Error: Claude CLI not found. Install it with: curl -fsSL https://claude.ai/install.sh | bash
Server PATH: /home/USER/.npm-global/bin:/usr/local/bin:/usr/bin:/bin
Login shell: /bin/bash -i -l
Checked directories: /home/USER/.local/bin, /home/USER/.claude/local, /usr/local/bin, /home/USER/.npm-global/bin, /home/USER/bin
at TmuxManager.createSession (.../dist/tmux-manager.js:1625:19)
[Session] Interactive PTY spawned with PID: 3086948
[Session] Interactive PTY exited with code: 1
The pane in the web UI shows:
execvp(3) failed.: No such file or directory
docker exec <container> tmux -L codeman-docker ls shows only the Shell session — no container-side tmux session was ever created.
Root cause
Line references against 88bb98de (master).
TmuxManager.createSession resolves the host CLI and throws before the docker branch is reached — src/tmux-manager.ts#L1890-L1892:
const { pathExport, dir: cliDir } = this.buildPathExport(mode);
if (mode === 'claude' && !cliDir) {
throw new Error(getClaudeNotFoundMessage());
}
Forty lines later the docker branch discards pathExport (and the whole localFullCmd it feeds) — src/tmux-manager.ts#L1934-L1938:
const fullCmd = docker
? buildDockerLaunchCommand(resolveDockerLaunchOptions(mode, docker, sessionId, resumeSessionId))
: remote
? buildRemoteSessionCommand({ mode, remote, sessionId, claudeMode, allowedTools })
: localFullCmd;
buildDockerLaunchCommand uses defaultDockerCommandForMode, which is a bare binary name resolved inside the container — src/docker-hosts.ts#L142:
claude: 'exec claude --dangerously-skip-permissions',
So the host path is never used on the docker path. The same guards exist for opencode, codex, gemini, antigravity and pi, so every mode except shell is affected.
This also contradicts the intent already stated for the remote/docker branches in src/web/routes/session-routes.ts#L2700-L2702:
the LOCAL availability gates below (isCodexAvailable() etc.) don't apply and would wrongly reject a machine that hasn't got the CLI installed locally.
That reasoning holds inside quick-start, but TmuxManager.createSession applies the gate regardless.
Note that _setupOrAttachMuxSession (src/tmux-manager.ts#L2161) calls the same buildPathExport without the throw, so only the create path is affected — which is why an already-created session can be re-attached but never started.
Suggested fix
Skip the not-found guards when the session is docker- or remote-backed. Either wrap the block:
if (!docker && !remote) {
if (mode === 'claude' && !cliDir) throw new Error(getClaudeNotFoundMessage());
// ... the other five
}
or move the guards below the fullCmd branch and apply them only on the local path.
Workaround
Install the agent CLIs on the host so the resolver finds them. They are never executed for docker cases:
npm install -g @anthropic-ai/claude-code @openai/codex
Summary
Starting a session for a Docker-linked case fails with
Claude CLI not foundwhen the corresponding agent CLI is not installed on the host. For a Docker case the CLI runs inside the container, so the host copy is never executed — the guard is a precondition for a value that the docker branch discards a few lines later.shellmode works, every agent mode fails.Environment
npm install -g aicodemandocker/agent.Dockerfile— contains claude 2.1.240, codex 0.149.0, gemini 0.56.0, opencode 1.18.21, agy 1.1.18, pi 0.84.2Steps to reproduce
npm install -g aicodemandocker/agent.DockerfileExpected
The Claude session starts inside the container, exactly like the Shell session does.
docker/agent.Dockerfileshipsclaude, so nothing is missing where the CLI actually runs.Actual
The pane in the web UI shows:
docker exec <container> tmux -L codeman-docker lsshows only the Shell session — no container-side tmux session was ever created.Root cause
Line references against
88bb98de(master).TmuxManager.createSessionresolves the host CLI and throws before the docker branch is reached —src/tmux-manager.ts#L1890-L1892:Forty lines later the docker branch discards
pathExport(and the wholelocalFullCmdit feeds) —src/tmux-manager.ts#L1934-L1938:buildDockerLaunchCommandusesdefaultDockerCommandForMode, which is a bare binary name resolved inside the container —src/docker-hosts.ts#L142:So the host path is never used on the docker path. The same guards exist for
opencode,codex,gemini,antigravityandpi, so every mode exceptshellis affected.This also contradicts the intent already stated for the remote/docker branches in
src/web/routes/session-routes.ts#L2700-L2702:That reasoning holds inside
quick-start, butTmuxManager.createSessionapplies the gate regardless.Note that
_setupOrAttachMuxSession(src/tmux-manager.ts#L2161) calls the samebuildPathExportwithout the throw, so only the create path is affected — which is why an already-created session can be re-attached but never started.Suggested fix
Skip the not-found guards when the session is docker- or remote-backed. Either wrap the block:
or move the guards below the
fullCmdbranch and apply them only on the local path.Workaround
Install the agent CLIs on the host so the resolver finds them. They are never executed for docker cases: