Skip to main content
Status: accepted · ADR-28 · Filed 2026-04-28

Decision

Bash scripts in this repo own the TTY surface. MCP verbs own the state-and-network surface. The dividing line is whether the work touches the user’s terminal FD — OSC sequences, ANSI colors, interactive prompts, background watcher subshells, exec-into-foreground-editor, job control. Concretely:
  • Stays a script: launchers (coder.sh), bootstrap (bootstrap.sh, start-backend.sh), in-container entrypoints (docker-entrypoint.sh), interactive restore flows (prism-restore.sh), and CI/lint tools that don’t run in agent hot-paths (spec049_grep_guard.sh, proto-codegen.sh).
  • Becomes a verb: deploys, backups, clone-from-remote, perf probes — any work that returns structured data and isn’t tied to the user’s terminal.
  • Hybrid: scripts that must run on a remote host (root on server1) stay scripts on the host but get a thin local verb wrapper that SSHs in, runs the script with --json, and returns parsed output (prism-server-install.sh, prism-server-clean.sh).
Inner units inside surviving TTY-bound scripts (env detection, project resolution, identity validation, credentials lookup) should call verbs once those exist (SPEC-051 Phase 3 prism_resolve) rather than reimplement.

Rationale

Two forces:
  1. Token cost. Bash tool calls dump stdout+stderr verbatim into the agent’s conversation transcript. A 50-line docker-compose run becomes 50 lines of context that has to be re-cached on every cache miss (Anthropic’s 5-min prompt-cache TTL). Equivalent verb returns structured JSON — typically 10× smaller. Empirically the largest single token leak in agent transcripts is bin/prism-deploy-server1.sh (150–300 lines per call × 5–15 calls per active dev session).
  2. Performance. Recurring shell calls pay cold-start tax per invocation: ssh handshake (~200–800ms), shell spawn (~30ms), docker CLI startup (~100ms). Verbs can hold persistent backend resources (ssh ControlMaster, docker socket, Postgres/Redis pools) and amortize the cost across calls.
These forces only apply where the work is purely state/network. They break down for TTY-bound work — backend processes cannot own the user’s terminal FD, so OSC sequences, interactive prompts, and exec-into-foreground must stay shell-native.

Alternatives Considered

  • Keep all bash. Token-bloat in agent transcripts compounds with session length; ssh/docker cold-start tax stacks per recurring call. Rejected.
  • Port everything to verbs. Impossible — TTY constraints don’t bend. Interactive read -p prompts and OSC title sequences can’t live in a remote backend process. Rejected.
  • Extract a shared bash helper library. Dedupes script-internal duplication but does nothing for agent token cost — agents still invoke bash, still see the output. Rejected as the primary approach (still recommended for surviving scripts that share env/project resolve logic — but they should call the verb instead, see SPEC-051 Phase 3).
  • Move bash → TypeScript CLI. TS CLI cold-start (~100–200ms node startup) is better than bash but no connection-pooling, and agents still read stdout via the Bash tool. Equivalent to bash for token cost. Rejected.
Tracked by: SPEC-051.
Last modified on April 29, 2026