docs(governance): D-263 — the primary user is an agent, and that changes things

Stated plainly because the record was quietly assuming otherwise: Jeroen runs
make and plays the game; the caller typing reach all day is Claude.

It resolves several arguments in the opposite direction from human-CLI
instinct. --help is a discovery mechanism rather than documentation, since it
is how the tool gets relearned from nothing every session — which makes the
domain list and closed-set enumeration load-bearing rather than polish. Output
volume is a context cost, so quiet-by-default is right for a better reason than
not spamming a hook. Latency matters less than legibility: nobody drums their
fingers at 300 ms, but a multi-minute silence is expensive because a wedge is
indistinguishable from work. And errors that name the next command are the
highest-value requirement here, because the reader is usually deciding what to
run next — "no" costs a whole exploratory turn.

One correction follows directly. D-263 had scoped streaming to "callers with no
escape — a human terminal, a Makefile, a git hook", reasoning that Claude
Code's background mode already solved the timeout for agents. That got the
audience backwards. Background mode solves the timeout and nothing else: it
returns when the process exits, so a nine-minute wedge still looks exactly like
nine minutes of work. Streaming is what makes a long run legible while it runs,
and reattach is worth most to the caller whose attention is not continuous.
Both are primary-user features, not fallbacks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-31 15:41:29 +02:00
co-authored by Claude Opus 5
parent 6b31111cd2
commit 91e25a3e7a
3 changed files with 60 additions and 1 deletions
+9 -1
View File
@@ -2611,6 +2611,14 @@ tooling/
- **Never literally interactive by default.** Any prompt is TTY-gated and suppressible with `--no-input`, which hooks pass unconditionally. `tea`'s interactive prompts *"crash in Claude Code (no TTY)"*; a helpful prompt that hangs a hook is worse than a terse exit code.
- **This is enforced by a conformance test, not by discipline** — every registered command must have help at its own level, and every declared failure path must name a next command. A contract nothing checks is a style guide.
**The primary user is an agent, not a human** *(stated 2026-08-31, and it settles arguments the rest of this record was having with itself)*. Jeroen runs `make` and plays the game; the caller typing `reach` all day is Claude. Design consequences, each of which contradicts an instinct applied earlier in this record:
- **`--help` is the discovery mechanism, not documentation.** An agent reads it instead of grepping the tree. That is why the domain list and the closed-set enumeration are load-bearing rather than polish — they are how the tool is *learned*, every session, from nothing.
- **Output volume is a real cost, not an aesthetic one.** Every emitted line spends the primary consumer's context window. "Quiet by default" is right for a better reason than not spamming the push hook: verbosity bills the caller who can least afford it. The `--verbose` gate on the invocation record stands.
- **Latency matters less than legibility.** An agent does not drum its fingers at 300 ms. The ~500 ms ceiling is therefore a sanity bound, not a target worth optimising toward — but a command that runs for minutes in silence is genuinely expensive, because the caller cannot tell a wedge from work.
- **Failures that name the fix are the highest-value requirement in this record.** The reader of an error message is usually an agent deciding what to run next. A message that says only "no" costs a whole exploratory turn; one that names the command costs none.
- **Machine-readable output is the default path, not the exception.** stderr is a pipe far more often than a terminal, so JSONL-when-not-a-TTY matches reality rather than accommodating an edge case.
**`make` and `reach` split by kind, not by preference** *(settled 2026-08-31)*. The Makefile has 84 targets and is today's front door, so "one CLI for all repo tooling" is not true until that relationship is stated. The boundary is **what the target actually does**, not who calls it:
- **`make` keeps genuine build and test orchestration** — cargo, Godot, the test gate, anything that sequences a build. That is what make is for, and `reach` would be a worse version of it.
@@ -2628,7 +2636,7 @@ tooling/
- **Streaming is additive to the failure contract, never a replacement for it.** A stream has no single moment of truth: a remedy emitted at line 400 of 900 is technically printed and practically invisible. **The verdict — outcome, exit code, and the command that fixes it — is still printed once, last, where it cannot be missed.** A stream that dissolved the summary would quietly undo the requirement this record cares most about.
- **The split follows the `core/` bound, and this is its first real test.** The primitives — emit, spawn, detach, redirect, record — are substrate and live in `core/`. The verbs `list`, `status`, `log`, `wait` have logic and state of their own, so they are a **domain**: `reach jobs …`. A job store in `core/` would be exactly the drift this record warns about.
- **Non-negotiable: a detached job's exit code must survive.** A runner that reports "started" and loses the failure is the exit-0 trap from the top of this record, relocated somewhere nothing is watching — which is worse. `reach jobs wait` exits with the job's code, and an unwaited failed job is visible in `reach jobs list`.
- **Where this overlaps the harness, prefer the harness.** Claude Code's `Bash` tool already has a background mode that solves the timeout *for agents*. What `reach` adds is for the callers with no such escape — a human terminal, a Makefile, a git hook — plus durable logs and job history. Scope it there rather than rebuilding what one caller already provides.
- **The harness overlaps but does not cover it** *(corrected 2026-08-31 — see the primary-user note below; the original text here scoped streaming to "callers with no escape, a human terminal, a Makefile, a git hook" on the reasoning that Claude Code's `Bash` background mode already solved the timeout for agents. That got the audience backwards.)* Background mode solves **the timeout** and nothing else: it returns when the process exits, so a nine-minute wedge still looks exactly like nine minutes of work. **Streaming is what makes a long run legible while it runs**, and the reattach path — `reach jobs log <id>` after a turn has moved on — is worth most to the caller whose attention is not continuous. Both are primary-user features, not fallbacks for callers who lack a better option.
**Constraints on execution (these are why the work is sequenced, not why it is hard):**