Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 24 additions & 26 deletions exact_dot_claude/rules/offload-to-deterministic-substrate.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
# Offload Mechanical Work to a Deterministic Substrate

The agent and the substrate it runs on have complementary strengths, and the
recurring quality problem is putting work on the wrong one. The agent is good
at **judgment** — reading intent, weighing trade-offs, synthesizing. It is bad
at being **repeatable**: ask it to count, parse, audit, or enforce the same
thing twice and you get two slightly different answers, each consuming scarce,
lossy context. Scripts, hooks, justfile recipes, and structured-output
contracts are the opposite — narrow, but byte-identical every run, and free of
context cost once written.
The agent and its substrate have complementary strengths, and the recurring
quality problem is putting work on the wrong one. The agent is good at
**judgment** — reading intent, weighing trade-offs, synthesizing — and bad at
being **repeatable**: ask it to count, parse, audit, or enforce the same thing
twice and you get two slightly different answers, each burning scarce, lossy
context. Scripts, hooks, and structured-output contracts are the opposite —
narrow, but byte-identical every run and free of context cost once written.

So the law:

Expand All @@ -19,14 +18,14 @@ So the law:

## Three distinct claims (don't conflate them)

The principle is load-bearing in three different ways. Naming them separately
is what lets you decide *which* substrate fits a given task.
The principle is load-bearing three ways; naming them separately tells you
*which* substrate fits a task.

| Claim | Why it matters | The lever |
|---|---|---|
| **Context economy** | The context window is the bottleneck and it is *lossy* — summarized across turns, drifts over a long session. Every token spent watching the agent grep/count/parse is a token unavailable for reasoning. | A script returns a compact `STATUS=` / `KEY=VALUE` rollup; the agent reads the verdict, not the computation. |
| **Determinism / reproducibility** | Correctness you rely on must be repeatable. An agent re-doing a mechanical task varies run-to-run; a script does not. | Encode the check once. The agent consumes its result; it never recomputes. |
| **Independent enforcement** | An agent asked to *both* do the work *and* judge whether it followed the rules is biased toward "done" (it optimizes for completion, not correctness). | A hook judges from outside, with no stake in the outcome — the agent cannot rationalize past it. |
| **Context economy** | The context window is the bottleneck and *lossy* — it drifts over a session. Every token spent watching the agent grep/count/parse is one unavailable for reasoning. | A script returns a compact `STATUS=`/`KEY=VALUE` rollup; the agent reads the verdict, not the computation. |
| **Determinism** | Correctness you rely on must be repeatable. An agent re-doing a mechanical task varies run-to-run; a script does not. | Encode the check once; the agent consumes its result, never recomputes. |
| **Independent enforcement** | An agent asked to *both* do the work *and* judge whether it followed the rules is biased toward "done". | A hook judges from outside, with no stake — the agent cannot rationalize past it. |

## Routing a task to the right substrate

Expand All @@ -38,33 +37,32 @@ is what lets you decide *which* substrate fits a given task.
| The exit/"done" judgment of a loop | A mechanical gate (green suite, `tsc` exit 0) or a **fresh** independent verifier | The worker has a stake in finishing; the judge must not (`loop-integrity.md`). |
| A drift sweep that already exists as a script | The existing script, mounted on an autonomous **trigger** | The gap is usually triggering, not logic — don't rewrite the sweep (`drift-detection-triggering.md`). |
| Pinning a fixed bug so it can't silently return | A regression **test/script check** | The fix survives in a deterministic gate, not in the agent's promise to remember. |
| A membership/ownership/security fact a subagent would **infer** (tracked? public? managed-by-X?) | A deterministic lookup (`chezmoi managed`, `git ls-files`) passed **in** as ground truth | Agents conflate co-location with membership: a live `~/.gemini/` cred was mis-reported as tracked-and-public (false leak) until checked against `chezmoi managed`. Treat such a tag as an unverified claim. |

## The litmus test

Before letting the agent do something by hand, ask: *"Would a script give the
same answer every time, and would I trust that answer more?"* If yes, the work
wants a script or hook — write it once and have the agent invoke it. Reserve
the agent's reasoning for the part that genuinely needs judgment.
same answer every time, and would I trust it more?"* If yes, write it once and
have the agent invoke it. Reserve the agent's reasoning for what genuinely needs
judgment.

Two cautions so this doesn't overreach:

- **Don't pre-build substrate for a one-off.** YAGNI applies (`code-quality.md`).
The payoff is in *repeated* mechanical work; a single throwaway computation is
fine inline.
- **Don't double-gate.** A hook that re-implements a check auto mode (or another
- **Don't pre-build substrate for a one-off.** YAGNI (`code-quality.md`): the
payoff is in *repeated* mechanical work; a throwaway computation is fine inline.
- **Don't double-gate.** A hook re-implementing a check auto mode (or another
hook) already performs just adds friction — make it defer
(`claude-code-auto-mode.md`).

## Rationale

This is the parent principle behind a family of rules that each apply it to one
situation — structured script output, drift-trigger separation, loop integrity,
regression tests, the Bash→tool hooks, prefer-inline-pass-over-fan-out. Each was
written to solve its own problem; the common law underneath is that **the lossy,
probabilistic agent should not be the system of record for anything a
deterministic artifact can compute, enforce, or remember.** Putting mechanical
work back in the agent's loop is the silent tax — it burns context, drifts
between runs, and lets the agent grade its own homework.
regression tests, the Bash→tool hooks, prefer-inline-pass-over-fan-out. The
common law underneath: **the lossy, probabilistic agent should not be the system
of record for anything a deterministic artifact can compute, enforce, or
remember.** Putting mechanical work back in the agent's loop is the silent tax —
it burns context, drifts between runs, and lets the agent grade its own homework.

## Related

Expand Down
Loading