Summary
F-mcp-agent-loop — the composed prompt → wait → read loop over any
session termherd hosts, shell or Claude alike. The primitive already shipped as
run_in_session (#194); what is left is the composition, the guards, and the
opt-in.
Child of the F-mcp-control-surface 🧬 split — the rungs and their rationale
are recorded in the F-mcp-control-surface entry of
ROADMAP.md,
readable by any contributor.
Not just an agent driving an agent
The original framing ("an outer Claude session orchestrates an inner one") was
too narrow, and it made the scope question look bigger than it is. The target
session is addressed by its stable handle and is kind-agnostic:
Action::Run applies Event::TerminalInput to whatever pane hosts the handle
(Shell::act_run, crates/app/src/shell/orchestrate.rs). Typing into a plain
shell pane — run a build, a test, a git command in the pane the user is
watching, then read what it printed — is the primary case, and the one that
makes the dev loop work.
type_into_terminal as a new tool is therefore redundant: run_in_session
already types arbitrary bytes into any session as if typed at the keyboard.
Scope
Scope question — narrowed, not open
The blocking question was "is an agent piloting an agent in termherd's product
scope?". Reframed: the tool is terminal input, which termherd already
exposes; the nested-Claude case is one use of it behind an opt-in, not the
feature's reason to exist. The shell case stands on its own.
Relationships
Summary
F-mcp-agent-loop— the composed prompt → wait → read loop over anysession termherd hosts, shell or Claude alike. The primitive already shipped as
run_in_session(#194); what is left is the composition, the guards, and theopt-in.
Child of the
F-mcp-control-surface🧬 split — the rungs and their rationaleare recorded in the
F-mcp-control-surfaceentry ofROADMAP.md,readable by any contributor.
Not just an agent driving an agent
The original framing ("an outer Claude session orchestrates an inner one") was
too narrow, and it made the scope question look bigger than it is. The target
session is addressed by its stable handle and is kind-agnostic:
Action::RunappliesEvent::TerminalInputto whatever pane hosts the handle(
Shell::act_run,crates/app/src/shell/orchestrate.rs). Typing into a plainshell pane — run a build, a test, a
gitcommand in the pane the user iswatching, then read what it printed — is the primary case, and the one that
makes the dev loop work.
type_into_terminalas a new tool is therefore redundant:run_in_sessionalready types arbitrary bytes into any session as if typed at the keyboard.
Scope
— shipped astype_into_terminal(session, text)run_in_session(F-mcp-orchestration: open_session / split / focus / rename / run_in_session tools #194), already kind-agnostic (shell or Claude).
wait_for_status, thenreturn the terminal read — one round trip instead of three, with the
three-call form staying available.
wait_for_status5-min ceiling), atimeout on every step, no unbounded feedback loop.
per-session), off by default. Typing into a shell pane the user opened
does not carry the same risk surface as prompting a nested Claude, and
should not be gated by the same switch.
Scope question — narrowed, not open
The blocking question was "is an agent piloting an agent in termherd's product
scope?". Reframed: the tool is terminal input, which termherd already
exposes; the nested-Claude case is one use of it behind an opt-in, not the
feature's reason to exist. The shell case stands on its own.
Relationships
F-mcp-terminal-sync(F-mcp-terminal-sync: wait_for_status + read_terminal (act -> wait -> observe) #195) —wait_for_status+read_terminal(
screenshot). Together the three close the loop neededto test gestures: drive the UI → see the pixels → read the terminal.