> ## Documentation Index
> Fetch the complete documentation index at: https://prism.ntecdev.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR-28: Bash scripts and MCP verbs split along TTY ownership

> 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

<Info>**Status:** `accepted` · **ADR-28** · Filed 2026-04-28</Info>

## 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.
