Files
Codeman/.changeset/ba4bc996.md
T
Codeman maintainer 86c78fece3 fix(pi): align the doctor with the pi resolver, correct the strip rationale, update the skill
Second review pass on #282, the three items left open after f4dcfbe.

1. `codeman doctor` and the run mode disagreed about pi. The registry entry
   accepted a bare `which pi` hit while pi-cli-resolver demanded semver-shaped
   `--version` output, so the Dependencies panel could report an installed Pi CLI
   on a box where Run Pi stays hidden, which reads as a broken mode rather than a
   missing install. Both sides now share one exported PI_VERSION_REGEX, and
   PathResolver gains an opt-in `requireVersionMatch` so a binary that fails the
   shape check is reported MISSING instead of installed-with-unknown-version.
   Only pi sets it; every other tool keeps its current behaviour.

2. The isAltScreenStripMode comment justified excluding pi with "the alt screen
   is load-bearing for its fullscreen TUI". That is not what exclusion does: pi
   is tmux-backed, so it falls through to isMuxAltScreenOnlyStripMode, which
   strips the alt-screen toggles anyway. What exclusion actually preserves is
   `\x1b[3J` and the mouse DECSETs, which is the real reason (pi renders into the
   main screen and is mouse-aware). Comment and changeset now say that, and state
   the consequence: fullscreen pi paints into the main buffer, like vim in a tmux
   shell session.

3. skills/codeman still enumerated the five pre-pi modes in nine places, telling
   agents a backend does not exist and understating class-wide caveats by one
   mode. All updated, plus stale session.ts line references refreshed.

Tests: a new static guard derives the mode set from the Zod schema (not a copy)
and fails when a skill enumeration lists a partial set of external CLIs, verified
by mutation. It also documents the one legitimate exception it found: the "writes
no transcript" lists drop codex, which does write a rollout Codeman reads back.
Plus doctor cases for an unrelated `pi` on PATH and registry/resolver regex parity.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 17:41:44 +02:00

4.4 KiB

aicodeman
aicodeman
minor

Add Pi (pi.dev) as a sixth CLI run mode (#206).

SessionMode gains 'pi', a first-class backend alongside Claude Code, OpenCode, Codex, Gemini and Antigravity: its own PTY, tmux session, rose tab identity, welcome button, run-mode entry, cron agentType, Docker and remote-SSH command defaults, and clone-repo Brain option.

  • New resolver src/utils/pi-cli-resolver.ts. Unlike the sibling resolvers it sanity-probes pi --version and requires semver-shaped output, because pi is a short generic name that a stray binary on $PATH can shadow; the rejected path is logged. GET /api/pi/status returns { available, path, version } so a misresolution is diagnosable.
  • PiConfig maps to --model (accepts provider/id and a :thinking suffix), --provider, --thinking, --session/-c, and the tri-state --approve / --no-approve. Every value is regex-allowlisted and dropped on failure. --api-key is deliberately never wired: it would put a provider secret on the spawn command line.
  • No bypass flag. Pi has no permission prompts and no sandbox, so there is no --dangerously-skip-permissions analog. Its privilege-shaped knob is approveProjectTrust, which makes pi load and execute repo-local .pi/extensions TypeScript and install missing project packages. clampExternalCliBypassForOwner() therefore puts pi in the materialize branch: a non-granted multi-user owner gets --no-approve even when no config was sent, because pi's own default is an interactive prompt the session user could answer themselves. The same materialization applies to cron-fired jobs (clampCronExternalCliConfigs), which carry no per-CLI config and would otherwise launch on pi's own default. Both helpers had no test coverage at all; they now do, for every CLI.
  • Env allowlist gains only the PI_* prefix. Pi's ~34 provider key vars share no prefix and ALLOWED_ENV_PREFIXES is one global list with no mode context, so admitting them would widen the allowlist for every mode at once. Users authenticate via pi's /login or the server process's own environment.
  • Pi stays out of isAltScreenStripMode(). Its default TUI renders into the main screen with terminal-owned scrollback and is mouse-aware, so it consumes \x1b[3J and the mouse DECSETs that the full strip removes, unlike an Ink TUI repainting in place. Note what exclusion does NOT do: pi is tmux-backed, so it still falls through to the narrow isMuxAltScreenOnlyStripMode() strip and its alt-screen toggles are dropped either way. Pi's runtime-switchable fullscreen TUI therefore paints into the main buffer, exactly like vim inside a tmux shell session.
  • Docker: pi installs in its own --ignore-scripts step so that flag cannot affect the other four CLIs, and its credentials are seeded per-file (auth.json, settings.json, trust.json, models.json, models-store.json) rather than whole-dir, since ~/.pi/agent also holds sessions, extensions and installed package trees.
  • Local echo: pi lands on the buffer overlay. Verified that codex's per-keystroke starvation does not reproduce — pi's slash picker re-filters on the whole composer content, so a one-shot flush behaves identically to per-keystroke typing.
  • Mode-list parity: pi is excluded from the Ralph tracker auto-enable on POST /api/sessions/:id/interactive (like every other external CLI, whose output the tracker never parses), carries a REMOTE_CLI_BIN entry so a remote-SSH pi session reports its CLI version, and gets its own badge in the desktop home rail instead of rendering like Claude. The packaged agent skill's mode enumerations list pi too, pinned by a new guard that derives the mode set from the Zod schema instead of restating it.
  • codeman doctor and the run mode agree about pi. The registry entry resolved a bare which pi while pi-cli-resolver demanded semver output, so the Dependencies panel could report an installed Pi CLI that sessions refuse to launch. Both now share one exported regex, and the registry's new requireVersionMatch reports a non-semver pi as missing rather than installed. Only pi sets it; every other tool keeps its existing behaviour.
  • Installer detection, docs (docs/pi-integration.md), READMEs, and the architecture invariants are updated. Tests: test/pi-mode.test.ts and test/routes/external-cli-bypass-clamp.test.ts, plus extensions to the run-mode, mobile-overview, render-index-html, system-routes and local-echo suites.