Ruling eureka-body:ruling:cli-over-mcp-agent-surface. Exact command forms in campaign-state.md; MCP kept as the fallback for shell-less clients. persona_get and persona_put have no CLI verb: recorded as a known gap. tools/mind.py and tools/recall.py (MCP-bound scripts) are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 KiB
| name | description |
|---|---|
| eureka | Eureka runs a foundation change as a faculty pipeline for Claude Code agents. It is the skill counterpart of Epiphany. The root agent acts as Self and routes the work. The target shape is written first, Imagination maps the cut, Hands executes one cut at a time, Soul verifies by trying to falsify what Hands promised, Life keeps memory honest at phase boundaries, and the operator rules on real forks. Use it for any migration, rebuild, teardown, cross-repo or cross-runtime change, infrastructure swap, or multi-cut refactor, especially on shared GameCult substrate (CultLib, CultCache, CultNet, CultMesh, CultMath). Also use it when the operator says "Eureka", "map the cut", "Imagination pass", "Soul pass", "Hands", "mini Epiphany loop", or "make this migration look like the last one", or asks to plan and land a change too big for one diff, even without naming the pipeline. |
Eureka
Eureka is the pipeline used by Claude Code agents. It sits next to Epiphany,
the running organism in F:\Projects\Epiphany, and shares its faculty
vocabulary and its document schemas.
Eureka keeps questions, rulings, cut specs, reports, verdicts, findings,
follow-ups and resolutions as typed documents in the instance's mind, held by
Huginn and reached through the huginn CLI (huginn whoami, huginn admit,
huginn view, huginn query; huginn --help is the source). Status is derived from those documents, never written. The committed
target and map keep only what has no kind: body facts, the model page and
rationale. references/campaign-state.md has the document set and the
selection recipes that every faculty reads state through.
This pipeline lands changes that are too large or too foundational to trust to one agent's judgment. It turns "migrate X" into a sequence of small, verified ownership changes. Each cut is specified tightly enough that Hands barely has to read, and each one is falsified by an agent that did not write it.
It exists because the failure it prevents is common and quiet: one agent plans,
implements, tests and reports on its own work. The tests then pin the agent's
spelling, not the operator's invariants, and the report is written by the party
with the most reason to believe it. In the Aetheria CultCache migration
(2026-09-12..15), 29 of 32 Soul passes found real defects that Hands' own green
tests had passed, about 75 in all: deadlocks, lost writes, a wire-parity split
between runtimes, untested operator rulings, and a writable catalog in the
editor. See references/postmortem-cultcache.md for the evidence.
The faculties
Faculties are postures, not personalities. The root agent is Self. It routes
work, admits the campaign's frame and the operator's rulings, commits the prose
map, and talks to the operator. Delegate every other faculty to a subagent with
its own brief. Each is a Claude Code subagent type of the same name
(imagination, hands, soul, eyes, modeling, life), and the dispatch
names it as subagent_type, which loads that faculty's charter. A faculty that
grades its own work has lost the point.
| Faculty | Runs against | Admits | Must not |
|---|---|---|---|
| Imagination | the Body (source, docs, probes), plus the target | questions and cut_specs specified to file:line, and follow_ups for work no cut owns; body facts, the model page and rationale go to the prose map |
commit code, choose a product fork silently |
| Hands | one cut_spec |
small pushed commits, then one cut_report |
redesign the spec, work around a fork |
| Soul | Hands' executed commits | one verdict and its findings |
edit or commit a repo, or review a plan (a pass on a plan is Imagination) |
| Life | memory surfaces | nothing: named mutations and proposals | touch Body code, restate what an owner records |
| Eyes (optional) | history, transcripts, logs | nothing: a facts file with evidence pointers | conclude or recommend |
| Operator | forks and product meaning | rulings, which Self admits | (not an agent) |
Admitting is a write to the Mind, not to the Body. Soul stays read-only on repos and still admits its verdict.
The operator's doctrine defines the faculties, and each charter owns its
faculty's identity, method and boundaries. Read ~/.claude/agents/soul.md and
~/.claude/agents/imagination.md. In short, a pass is named by what it produces, so a pass over a plan is Imagination, and a plan is
finished when Hands can go straight to the cut.
The loop
0. Reach the mind, map the substrate, scope, target
- Check that
huginnruns in this session (huginn --version; on Yggdrasil it is/opt/gamecult/huginn/current/huginn, andEUREKA_INSTANCEandHUGINN_ENDPOINTname the mind). If it is absent, stop and tell the operator. Never fall back to prose. A client without a shell (such as the operator's Windows desktop session) may use theeureka-stateMCP until a nativehuginnis installed there. - Run
huginn whoami. If it does not answer, follow "When the organ does not answer" inreferences/campaign-state.md: one retry, then stop. Pick a session label and give it in every brief; it attributes every admission. - Map the real substrate before you propose anything. Run parallel read-only exploration of the old system and the new one, of any prior attempts and why they failed (git history, rollbacks), and of every consumer across repos.
- Write and commit the target document first, on the campaign's working
branch: its rationale, and the design truths the migration will produce. The
campaignand thetargetcite it byDocRef, and aDocRefnames a commit. - Then admit the
campaignand thetarget(Self's checklist inreferences/briefs.md). The target holds the ends, not the means: labelled invariants that must survive (wire parity, one owner per decision, what the operator refuses to lose), and what is explicitly not a consumer. For example, AetheriaEve was "taxidermy", and saying so up front saved every later pass from considering it. - State the scope boundary out loud. The earlier Aetheria attempt failed because it bundled cache, mesh, eve and daemons into one change. One foundation per pipeline.
- Dispatch Life before the first consequential action. Global doctrine names the agent type that carries it.
0b. Settle identity, lifecycle and authority before any cut is mapped
Re-cutting is not usually caused by a map that was insufficiently detailed. It is caused by a question that was answerable on day one and got asked on day three. In the Eureka pipeline-state campaign every backtrack was one of three questions, and none of them needed a line of source to answer:
- Identity. The key grammar was redesigned after three patches because ids had no namespace. Every earlier cut specified behaviour over an unnamed space, so the same invariant kept reappearing one level up.
- Lifecycle. Cut 6d exists because the shape of each document was specified and its life was not: a subject that is resolved, withdrawn, resolved again, and transferred to another steward. Sequences had to be retrofitted into keys that were already landed.
- Authority. The repo-owned store died whole in Cut 4 because who owns a mind was never asked before the store was specified.
So produce one table before mapping any cut, with a row per persistent kind and three columns: what names it, what happens to it over time, and who decides. No cut is mapped while a cell is empty. This costs a page and an hour. The table is the model page in the prose map; no kind carries it.
Admit the operator's forks in the same pass, as questions in one batch. In
that campaign they surfaced across five cuts instead, so rulings kept landing on
code that was already written. Discovering that the operator wants something
different is not waste; discovering it after the code lands is.
1. Imagination maps the cut
Brief an Imagination agent to admit the cut_spec for the next cut against
the current Body; depends_on names the cut labels it waits on. The fields are the spec standard:
repo, branch and base; deletes first, with exact paths and line counts;
keeps_moves; adds; file_changes at file:line for code that exists;
an authority_map for anything that changes ownership; verification (builds,
tests with the rule each pins, negative greps, operator checks); an estimate
for the ledger; and the rulings and questions it rests on. A changed spec is
a new revision, admitted with the resolution that supersedes the old one, never
an edit.
Map only what is about to run. A cut_spec is admitted for a cut Self
dispatches as soon as the spec is in: its dependencies have landed or are in
their Soul pass, and Self has the head and the machine for it. That is the next
cut of a campaign, plus a sibling that can run beside it in its own worktree.
Every later cut is one line in the prose map's cut sequence (a title and what
it waits on), never a spec. A cut split for budget admits its first part; the
rest stay lines. A spec waits on the Body and goes stale: the variants specs of
2026-10-02 sat ten days behind a moving CultLib and needed a fresh Imagination
pass before Hands could use them. Operator, 2026-10-12: "Originally a spec
would get dispatched as soon as it's written, but we've been drifting way ahead
of the work". So the specs-with-no-report recipe is the dispatch queue, and a
spec on it that Self is not dispatching this session is a defect. A spec
already in force from before this rule is refreshed (revision N+1) or
withdrawn when its campaign's frontier reaches it, never dispatched on a base
tools/context-pack.py reports as moved.
Spend the detail where the map can be wrong, not where Hands will rewrite it
anyway. Anchors against existing code earn their length: they say what to
delete and what not to touch. They are also Hands' context pack, pinned at base
and carried to Hands' tree by tools/context-pack.py (ruling
context-pack-resolving-anchors), so each one is stated exactly at base. Transcribing the body of code that does not exist
yet does not. A cut section that runs to eight hundred lines against a crate
nobody has written is a 1:1 map, and the only spec complete enough at that scale
is the code itself. Soul catches a wrong function body cheaply; it cannot catch
a missing namespace. So for new code, name the types, the rules that must die
under their own mutation, and the boundaries, then stop.
Cutting faster means less prose per cut, never more code per cut. Small commits stay small.
Subtraction comes from a consumer audit of the public surface, not from taste:
- Count real use across every project the operator works in before sizing or cutting a feature, not only one runtime's repos. Atomic commit was nearly cut as "unused in C#", even though Ghostlight and Epiphany needed it. Call counts decided whether compare-exchange was in scope.
- A surface with design intent but no consumer is parked at a tag with a
note, not deleted. SoA was parked at
parked/cultcache-soa. - A capability the operator has needed across projects is reshaped, not removed, even when its current consumers are only tests.
- A general-purpose library is judged by what a reasonable consumer would expect, not by our own call counts. For CultLib, the consumer audit bounds internal duplication and dead internals. It never licenses cutting or omitting public capability. A math type that doesn't serialize, or a runtime missing a sibling runtime's feature, is a gap to fill, not a cut to take. When consumers each carry their own copy of something, the owner-level fix is usually to add it to the library. (Operator, 2026-09-30: "just because we're not using a feature doesn't mean we can cut it".)
- Where the operator's own original code exists, it is the style bar.
Keep subtraction cuts separate from behaviour cuts, so Soul can falsify each on its own.
Before specifying a domain concept, ask the operator what it is for. In the CultCache migration Imagination inferred loadouts' purpose from a broken legacy menu. The operator then redefined them three times in one evening, and each redefinition reworked shipped code. Stores, UI and pricing all follow from purpose, so the question is cheaper than the rework.
Design order as data, not as scheduling. A ticket system that serialized delivery was built, deadlocked, and was deleted for a per-cache sequence number. When a map needs ordering or concurrency guarantees, prefer carrying the order in the data the consumer reads.
Imagination must establish mechanism claims by running code: probes, scratch
builds, decoding a real file. It must not reason from names. A map built on
unprobed claims is where bad cuts come from. The probes and their results go in
the prose map's body facts. Real forks come back as questions with a
recommended option, never chosen silently.
Iterate with further Imagination passes, not Soul passes, until Hands could go straight to the cut. The admitted specs are the durable record of the means. Self commits the prose map when its body facts, model page or rationale change.
Check overlap before fanning Imagination out. Before dispatching Imagination passes in parallel, list the code and the decisions each will touch. Passes that overlap run in sequence, or one of them owns the shared decision and the others cite it. On 2026-10-08 two parallel passes over the same code made two owners of one decision twice: Title against DisplayName, and the Huginn crate move.
Templates are in references/briefs.md and references/campaign-state.md.
2. Operator rulings
Prior art comes before every nontrivial fork. Before a nontrivial question goes to the operator, Self stops the line that raised it. Self dispatches an Eyes pass over the research literature and over established implementations of the same problem: papers, the source and design notes of the systems that solved it, and their known failure modes. The question then cites that evidence, and the recommendation stands on it. Operator, 2026-10-02: "I feel like the default reflex is to defer to my judgment, and I'm neither a Dijkstra nor a Carmack." The operator rules on what the project is for and what it values. Self and the faculties owe them the field's state of the art first, so their judgment is not the only design input. A fork is trivial, and skips this, when it is a project default, a naming choice, or a guard against our own code (the proportion rule below). When unsure, run the pass.
Research is always kept. A prior-art or literature pass is committed where
it outlives the session: the project's docs/research/, or gamecult-ops
docs/research/ when it spans projects, with a header naming the fork or ruling
it served. Self commits it before putting the fork. A scratchpad facts file dies
with the session, and the next fork in the same field pays for the search again.
Operator, 2026-10-09: "Research should always be kept".
Put the open questions to the operator together, from the open-questions recipe,
each with its options, recommendation, and what depends on the answer. This
holds in a catch-up briefing too: read the options and context from the
question document, never from a handoff's one-line recommendation, so the
operator rules on the fork and not on Self's summary of it. Self
admits every answer as a ruling that answers its question, keeping the
operator's words in operator_quote when they carry meaning a paraphrase would
lose, and saying whether they decide, illustrate or sketch: her examples are
never a closed list (references/briefs.md, Self). An operator direction that
answers no question is still a ruling, with
no answers, authority: Operator and the words in operator_quote; briefs
cite its id, so agents read the operator's own words. A ruling that changes an
earlier one supersedes it by a resolution, never by an edit, so the
rulings-in-force recipe shows one live design.
The operator channel is this session. Eureka has no Persona: Self is the operator-facing surface, because a question costs one message and loses no context when the question and the tree share a session. When a blocking question is raised and the operator may be away, call whatever notification tool the user has configured (any MCP notifier) with the question, its options and the recommendation. Eureka owns no transport and names no provider. Answers come back in the session.
Distinguish a real fork from a default. "Should I use the conventional thing" is
not a question. "3-5 are not decisions," as the operator put it, is the failure
of asking about non-decisions. Weigh proportion too: a fork that guards only
against the project's own code, such as how strictly to enforce an internal
tripwire, gets a default and a recorded follow-up: a ruling with
authority: Defaulted, plus a follow_up. Asked how much one such question
mattered, the operator said not at all.
3. Hands executes one cut
Size the cut against Hands' context budget before dispatch. Self owns this, for map cuts and fix batches alike. Sonnet degrades at about 0.5M tokens of context (operator, 2026-09-25), and the sloppiness starts earlier: Aetheria's stats and shield Hands got "loopy" past 400k, and a StreamPixels fix batch past 550k produced sloppy code. Treat 0.5M as the danger line, never the target. Size by calls too: each call re-reads the context, so an agent's reads grow with the square of its calls. A cut that needs more than about 150 Hands calls is two cuts, or one cut and a continuation.
Before dispatch, Self estimates what the run will carry:
- the brief, and the
cut_specHands views; - the source Hands must read to edit safely: the files it touches and their direct callers, not the repo;
- one verification round at the end and one fix round, with their output; test and mutation logs are usually the largest items;
- the number of separate items. StreamPixels' ten-item batch ran to about 800k tokens; split per file, batches stayed at 200-400k. So a fix batch is one file's findings by default.
Runs overshoot their plans, so split when the estimate passes about half the line. Split by file or by deliverable, each part with its own verification. A late item gets its own brief; it never joins a batch that is already planned. Splitting a cut always beats a bloated brief. When the report comes back, compare the agent's reported token total with the estimate, and cut finer next time where it overran.
Brief Hands with the cut_spec id, the campaign session label, and the
rulings in force that the spec cites. Hands reads the spec with view, so
nothing is pasted or paraphrased. The brief says:
- Follow the spec, do not redesign. If the Body contradicts the spec, fix the
smallest thing that keeps the spec's intent true and record the discrepancy in
the report's
deviations. If it is a real fork, admit it as aquestionraised in the spec, stop, and report. A fork hit before the first commit ends the pass with the question alone: report its id and receipt, and admit nocut_report. - Gaps are filled in their owner, never worked around locally. If CultMath lacks a function, CultMath gets it; the consumer does not grow a helper.
- Delete before adding. No shims, no compatibility layers the map did not name.
- Small commits, each pushed, with explicit paths. See the git rules below.
- Every operator ruling and every new rule gets a test that fails when the rule breaks, and the test describes behaviour, not code shape. The operator, 2026-09-22: "Tests should cover how the code behaves, not how it is shaped."
- Measure the suite with the ecosystem's mutation tool, scoped to the cut's
diff: Stryker.NET for C#, cargo-mutants for Rust, StrykerJS for
TypeScript, mutmut for Python. The tool generates the mutants and nobody
writes an anchor. Every survivor is a finding about the tests, triaged by
name: a behavioural test is missing, a fixture is degenerate (see below),
or the mutant is equivalent and gets a one-line reason. Boundary flips on
float thresholds are equivalent by default and are not chased. The score is
not a gate; the triaged survivor list is the record. The report's
mutations(at most 64) holds every survivor and the kills Soul should rerun; the totals (generated, caught, unviable, missed) go in itsverificationevidence. Each survivor also gets adeviationsentry with its triage, because the mutation record has no field for it (substrate gapeureka-substrate:follow_up:gap-mutation-triage-field). Soul reruns the tool on the range rather than trusting Hands' triage. - No committed hand-written mutation suites, and no fallback harness. The operator ruled this on 2026-09-22: "Better to have nothing than a harness that punishes refactoring." Anchors couple a suite to the code's spelling. They strand on every refactor, and they can keep matching while silently re-targeting onto code the tests no longer run. Where no tool reaches (C++, shaders, editor code), the defence is behavioural: observe the rule where it is decided, for example with a dev-only seam and exact equality, and use scenarios at the layer where the rule would fail. Soul may still mutate code by hand as a one-off probe during a pass. Such a probe is never committed as a suite, and a kill it finds becomes a behavioural test.
- "This rule cannot be pinned" is a claim, and Soul falsifies it like any other. Recording an honest gap is right and beats inventing a kill, but the gap itself is a hypothesis about reachability, and it was wrong both times it was made in one day. A daemon arm was written off because its failure paths needed a corrupt store; a probe built from the crate's own public surface killed two mutants that the shipped suite let through. A bridge rule was written off because reaching it needed a listener, a credential and a connection; a client opening to a closed port reached it in about a millisecond, in fifteen lines, and the mutant crashed an ordinary optimised build on contact. So write the gap as not yet reached, never as unreachable, and put reaching it at the top of the next Soul brief. A rule written off as undefendable that is merely undefended is worse than a surviving mutant, because the suite and the prose agree with each other and both are wrong.
- Name the weakest thing that would still pass, and ask whether that is the rule. A test proves some property; the question is whether that property is the rule or a cousin of it that the rule implies. One bridge line, "the wait is the timeout the host asked for", took three passes because each fix proved a slightly stronger cousin. First the suite proved the wait was not one particular constant, which a different constant defeated. Then a scenario measured elapsed time at two values with non-overlapping bands and proved the wait was not any constant, which a clamp defeated: capping the wait so that shutdown gets noticed is the most ordinary spelling that line will ever be given, and it is a function of the argument rather than a replacement for it. So when a rule says a value is derived from an input, at least one mutant must itself be a function of that input — a clamp, an offset, a scale — and probe values must sit where such a function would show. Constants are never the hard case; they are only the first one.
- Put the observation where the rule is decided, not after it. A probe sited downstream of the thing it interrogates creates a blind spot by construction, and every mutant of that thing lands in it. A bridge scenario held its callers after the wait whose duration was the rule, so replacing a caller's timeout with a hard-coded two seconds walked through the entire committed matrix on both targets. The committed entry appeared to defend the rule, and only defended a constant smaller than another constant. When a mutant dies, ask which of the two it actually contradicted.
- A loosening that cannot fail is a finding about the fixtures, not licence to substitute an easier one. When the mutant that weakens a rule still passes, the usual cause is that every fixture differs in more ways than the rule cares about, so the weakened check keeps getting the right answer for the wrong reason. Report it and fix the fixture. In Cut 10 of the pipeline-state campaign, Hands quietly swapped two such loosenings for different ones and reported a clean sweep; Soul then found that comparing only the lengths of two instance names, or only their first bytes, survived both suites, because no fixture pair had ever shared a length. The rule had no defence and the suite said it had two.
- Admit one
cut_report: commits (and which don't build), the range, the verification evidence, mutations, deviations, forks, the structural delta, what was left undone, and the promises Soul will measure. The report to Self is its id plus raw output too long for an evidence line. Hands never edits the prose map.
Parallel Hands are fine when they touch different repos or worktrees. They are not fine in the same working tree, and never while a Soul pass reads that tree.
4. Soul falsifies
Brief Soul with the cut_report id and the session label. The report carries
the exact range and Hands' promises. Soul's claims are not bounded by what
Hands chose to promise. Soul also views every ruling the cut_spec cites and
makes one claim per ruling, runs the rulings-in-force recipe so that standing
operator directions reach it (including ones admitted after the spec), and
measures the target invariants the cut touches.
Hands' self-report is one input to attack, never the list of what gets checked.
Point Soul at the specific places a shortcut would hide. Soul:
- reruns builds, tests and captures itself instead of trusting the report.
It scopes its reruns to what the cut touches, runs one full suite at the end,
and batches its probes into as few verify jobs as it can (
briefs.md, Soul); - reruns a selection of Hands' mutations, and designs its own that are not plain reverts;
- builds scratch probes to reach behaviour the tests cannot see: round-trip every document type, decode a legacy file independently, compile the shader with the real compiler, run the other runtime's decoder;
- checks the invariant at the layer where it would actually fail (wire bytes, another runtime, the editor, the GPU), not only in the unit test;
- admits one
verdict, with a claim for every promise and for every cited ruling, together with itsfindings: eachConfirmedorPlausible, with locations, a failure scenario, a severity and the target invariants it breaks.
Soul works read-only on repos. It creates temporary worktrees for anything that needs a different checkout, removes them afterwards, and leaves every tree clean.
A probe that is the only thing defending a rule must be committed by Hands. Soul cannot commit, so its harnesses die with the session. In the QUIC cut the native bridge's entire mutation history — the consumer, the close scenarios, every kill they reported — lived in scratchpads that no longer exist. Two mutations could not even be re-marked, because their definitions were gone, and the rules they had protected turned out to be defended by nothing a future agent could rerun. Green history, empty repository.
So when Soul kills something with a probe the repository cannot reproduce, that is a finding in its own right, and the next Hands pass commits the harness. Reported kills are evidence only while the thing that did the killing still exists.
5. Triage and repeat
For each finding in force, decide:
- fix now: brief Hands with the finding's id. The fix batch's
cut_reportcites the finding's in-forcecut_specas its next attempt, on that spec's branch. If the fix must land elsewhere, Imagination (or Self) admits a revised spec first. Only Self closes the findingFixed, and only after a Soul pass on the fix's report holds; - operator fork: a
questionraised in the finding, with a recommendation; - defer: a
follow_upwith the reason it can wait, and the finding resolvedDeferredto it; - record or withdraw: a
RecordedorWithdrawnresolution.
Run Soul again on the fix batch. Do not cap the Soul loop early on a foundation cut. In the CultCache migration, Cuts 6 and 6b each needed four Soul passes, and the later passes still found real defects. Stop when a pass finds nothing that blocks, or only findings the operator chooses to record.
Quota is spent through scope and cut size, not through the number of
passes. On 2026-09-23, with 60% of the weekly quota gone in one day, the
operator redirected all work to the StreamPixels critical path. That spend was
legitimate work; the operator's regret was the model it ran on (2026-09-25).
Since then Self has run one full Soul gate per cut. A fix batch goes only to
findings on the critical path, and the rest are recorded as follow-ups. Every
later Soul pass covers only the fix batch's diff, as the second-pass clause in
briefs.md says, and a small delta gets a narrow Sonnet pass. Hands' share is
governed by the context budget in step 3. None of this caps the loop on a
foundation cut. It keeps each pass the right size.
When the same kind of finding recurs, the brief was missing context. Fix the brief template, not only the instance. That is how "operator rulings each need their own failing mutation" entered the Hands brief.
When the same kind of finding recurs against the same rule, the fault is in the observation, not in the brief. The trigger is the second beating, whether by mutants or by Soul findings: on 2026-10-27 a cacheless-write ownership rule was widened three passes running (claimant, compatible ids, shape) because two descriptions of one type reached the decision, and the fix was structural. If a second fix batch for one rule is again beaten by mutants from the same family, stop adding probes. Move the observation to the layer where the rule is decided, such as a dev-only seam that records the computed value, and let exact equality kill the whole family. The QUIC bridge's timeout took seven passes because each batch killed the last Soul's functions, and the next Soul found another that matched at every probe. A dev-only seam has two costs of its own. It splits the code into a debug form and a release form, so the timed checks must still run against the release build: that is what ships. And it must wrap the whole value the rule is about, not an input one token upstream. Soul's eighth pass found both gaps.
A release or tag is a cut and gets its Soul pass before the tag is pushed. The CultCache release cut skipped Soul. Its stale DLLs, SHA-bound byte checks and silently skipped publish jobs surfaced only after tags were out. CultLib 1.0.58 shipped a wire-parity defect that was found and corrected 74 minutes later.
6. Land, record, run Life
After each cut:
- Progress is a query, not a section to update: the recipes for specs with no report (minus those blocked on a question), reports with no verdict, and open questions, follow-ups and findings.
- Self reconciles the subtraction ledger with the ledger recipe (each spec's
estimateagainst its reports'structural_delta). A miss is allowed, but it must be explained. The CultCache core missed its size target by roughly 1,200 lines, and nobody looked, because the ledger stopped being updated after Cut 4. - Self commits and pushes the prose map when its body facts, model page or rationale changed. Hands and Soul never touch it.
- At phase boundaries, a Life pass moves durable rulings to their owners, retires superseded memory, and falsifies at least one persisted claim.
At the end, Self writes the postmortem (see references/postmortem-template.md)
and reconciles the target doc with the Body.
Self's discipline
- Never restate typed state in prose. Not in the map, not in a brief, not
in a summary for another agent: give the id, and let the reader
viewor query it. A paraphrase of a spec or a ruling is a second copy, and a second copy is how stale text gets read as live design. Tell the operator what matters in words. Tell agents the id. - When the organ does not answer, stop (the rule in
references/campaign-state.md). Say so to the operator. Continue a stopped agent withSendMessageoncewhoamianswers. Never keep the record in prose or memory "until it is back": that is a second copy, and the mind is the only store. Do not stop (TaskStop) an agent that halted onUnavailable: it holds the record it could not admit. Resume it when the organ answers. - Keep the prose map current. After a ruling changes a design, sweep the map's body facts, model page and rationale, and the target doc, for the old version the same day. The specs and rulings need no sweep, because their resolutions already say what is in force.
- One owner per decision, in code too. When Hands moves a decision partway, for
example the charge moving into
Materializewhile affordability stayed in the menu, send it back. Split authority is the defect Soul most often finds. - Relay findings plainly. The operator reads Self's summaries, not the agent reports. Say what broke, how it would fail, and what is being done.
- Choose models by how critical the pass is, and name the model and the
subagent_typeon every dispatch. Put the scarce strong model on Imagination and on Soul passes over cuts that put the foundation at risk. Hands, search, probes and Life take the cheaper tier, named explicitly: "default" inherits the root session's model, so a root running on the strong model silently spends it on every Hands pass unless Self says otherwise. A cheaper Soul model does not soften its brief: it still attacks, invariants first. When Fable ran out mid-migration, Opus carried every faculty and Soul still found the defects. - Give every parallel Hands its own worktree, and name it in the brief.
Self must create the worktree before dispatch, not leave the agent to find
somewhere to stand. On 2026-09-22 two Hands were dispatched into
F:\Projects\CultLibat once: one switched the branch out from under the other's running build. Nothing was lost, only because the second agent stopped and reported a concurrency hazard instead of forcing the checkout. A brief that names a repo path without naming a worktree is a defect in the brief. The worktree's branch is the spec'sbranchfield, spelled exactly: on 2026-10-13 the sensor-catalog worktree was cut oneureka/aetheria-release-sensor-catalog-r2, so the report's branch named a ref origin did not have and every later brief had to correct it. - Commit the prose map to
main, and name its branch in every brief. On 2026-09-22 a Hands agent found no fix-batch-4 section: the live copy was on Self's working branch, andmainwas a day behind. Specs now live in the mind, which has no branches; body facts and rationale still do. - A subtraction budget is pressure, not a metric. Say so when you set it, so Hands knows escalating a miss with an argument is allowed. Treat a suspiciously clean hit as a sign that unrelated code was deleted to meet the number.
- Track Soul's hit rate, not the ceremony. If an attacking pass stops finding anything across cuts, ask whether it has started confirming instead of attacking. Also ask whether it inspected an adjacent artifact rather than the thing that actually runs.
- Record the substrate you needed and did not have. When a faculty works
around a missing tool, service or typed surface, the workaround is the whole
record and the requirement evaporates. Name what was missing, what it would
have prevented, and where the run felt it. A campaign that hits the same gap
six times is the strongest requirements evidence anyone will ever get for
building the thing, and it is worth nothing once the run closes and the pain
is remembered only as "the docs got messy". This is not a reason to wait on
the missing thing or route work to it: work around it and leave evidence. The
evidence is a
follow_upwhose source is the document where the run felt the gap, and whose owner is the missing thing's owner. The gaps already known are follow-ups in the mind; "Substrate gaps" inreferences/campaign-state.mdgives the query and where a new one is admitted. - Never claim an agent's result before its notification arrives.
- Self's context is long-lived and mostly cache reads. It turns over far
less than a worker's, so a token of it is cheaper than a token of fresh
worker context, but every notification still re-reads all of it and a
session cut short by the window loses its unwritten thread. Rotate at about
400k context or at a phase boundary: write a short handoff and ask the operator to
/clear. A handoff is named by its area,HANDOFF-eureka-self-<area>-<date>.md(for exampleHANDOFF-eureka-self-eureka-2026-10-09.md), one per Self area; the campaigns an area covers are named inside it, and the next Self reads only its own area's. The handoff carries only what the mind does not hold: the session label, the next action by id, each agent in flight, and drafts not yet admitted. It never lists what landed or what is open; that is a second copy of the mind (see "Never restate typed state in prose"). On re-entry, Self rehydrates before briefing anyone:whoami, the campaigns recipe, then for every campaign in force the open questions and follow-ups, the specs with no report and the reports with no verdict; a report unverified for days gets a recovery Soul pass (on 2026-10-27 two such reports hid High defects). Before acting on a handoff's "landed" or "merged", check the repo's origin main and the cut_report; local checkouts lag. The handoff is a pointer into that state, not the ledger. Every campaign in force has exactly one area: before writing a handoff, Self runs the campaigns recipe and checks that each campaign in force is named by its own handoff or by another area's current one; on re-entry, a campaign in force that no current handoff names is adopted on the spot or put to the operator. A Self that hands a campaign to another area names it in both handoffs the same day. (On 2026-10-11 four campaigns in force, among them variants with a High finding open, had sat a week in neither area's list.) A clear ends the session's background agents: their commits survive on branches, their unadmitted reports and verdicts do not. Rotate when no agent is in flight; if one must be, the handoff lists its branch, worktree and owed admission, and the next Self sends a recovery Soul pass instead of waiting on it. Agents are capped at about 300k context or 150 calls, after which a fresh continuation agent takes over. Never read logs or diffs in the root;viewreports and verdicts. - A subagent that notifies before its report is a brief defect. Count finished notifications per agent. More than one means a turn ended mid-wait, and the brief template is what gets fixed.
Shared tools
Scripts that agents share live in this repo under tools/. tools/INDEX.md
lists each script, its consumer and the brief that names it; briefs name the
exact script they want and agents do not browse. Contributions come by branch
and Forgejo pull request (this repo lives on Yggdrasil's Forgejo), never a push
to main. A script that verdicts depend on gets a Soul pass before merge, and
bash tools/test-tools.sh passes first. The summary and wait modes of
tools/stopgap/ygg-verify.sh and tools/mutation-table.sh are such scripts. A script whose brief no longer names it is pruned.
Scripts that know a project's layout stay in that project.
Git and tooling rules (scars)
- Stage explicit paths. Never
git add -A. It swept an untracked local settings file into history. - Never amend or force-push a shared branch. In the Ghostlight play-agent pass, a Hands agent amended its pushed kernel commit and force-pushed it while Self was pushing map commits to the same branch. Nothing was lost, only because Hands had rebased on those commits. Fix a commit with a new commit.
- Never
git archiveto export source for a byte comparison. It applies text conversion. An export used for a reproducibility check carried 1,459 inserted carriage returns against the worktree, which poisons every byte count built on it. Read raw blobs and verify against the worktree's hash before comparing anything. - A shared build output directory belongs to one checkout of a repository.
Two worktrees of the same crate get the same artifact hash. Cargo decides
whether to rebuild by comparing modification times, so a plain
cargo testin the checkout with older sources ran the other checkout's last mutant binary. A surviving mutant can make an unmutated tree look green this way. A second checkout, such as Soul's clone or a parallel Hands worktree, gets its own target subdirectory. The stopgap's containers each build in their own scratch clone, so they are immune. - Heavy verification runs on Yggdrasil, not on the operator's workstation.
Heavy verification means builds, test suites and mutation tools. The owner
is Idunn's verify transaction (a campaign in progress, ruled 2026-09-22).
Until it lands, use the stopgap
tools/stopgap/ygg-verify.sh. It pushes an exact revision to a mirror on Yggdrasil and runs one command in a container capped at 4 CPUs and 6 GiB, niced, with at most 5 jobs at a time. The script owns these numbers (CPUS,MEM,SLOTS); where this text andygg-verify.shdisagree, the script is right — this line was already stale once. Every Hands and Soul brief says so. Starfire runs only what has to run on Windows, such as the QUIC win32 scenarios: one job at a time, never burners. The stopgap's container runs as root, so a test that expects a permission failure passes there for the wrong reason. A CultLib test expecting a write to a read-only directory to fail "failed" at every revision this way. Treat a permission-dependent result from the stopgap as unproven. Idunn's verify runner refuses uid 0, so it will not inherit this. - The operator's workstation has a load budget, and Self owns it. Running
stress under load there, with CPU burners, is forbidden: use a dedicated
host, or a container capped with
--cpus. Run at most one heavy verification job at a time, meaning a mutation run, a repeated test loop, or a workspace build. Parallel agents are sized to that limit, not to the pipeline's appetite. On 2026-09-22 the operator had to force a shutdown. At the time, 16nodeburners at twice the CPU count were running (Self's own stress rulings asked for them), killed by Git Bash PID and probably never actually stopped. A 30-run test loop and a workspace build were running beside them. - Kill processes by the PID you started, never by image name. A Hands pass
cleared its CPU burners with
taskkill /IM node.exe /T. That killed every Node process on the shared workstation, including other agents' and the operator's. Record the PID of every process you launch, and stop only those PIDs. - Commit from Git Bash with
git commit -F- <<'MSG'. PowerShell 5 here-strings break-mquoting, and itsOut-File/Set-Contentwrite a BOM into message files. - Push at most three tags per push. GitHub skips tag-triggered workflows when one push carries more tags, so the npm and PyPI publish jobs silently never ran.
- Keep release byte checks commit-independent. Exclude the source revision
and Source Link from the version, build non-incrementally, and use
/Breprofor native code. A committed DLL otherwise always carries its parent's SHA. - Operator-side builds run detached, with a log and a PID. Unity batchmode and similar builds must never be one attached call. Agents waiting on a job do so in the foreground, in calls of at most 270 s (briefs, Hands). Revert incidental asset churn afterwards, such as Unity's SDF font asset.
- Before a mass-spawn or process-launching probe, read how the child chooses its role. A probe that relaunched its own executable fork-bombed the workstation three times.
- Before a merge, verify every test project that consumes the changed package, not only the package's own. CultMath Phacelle merged on CultMath's green suite (2026-09-30); Caching checks every public CultMath value type for a converter, formatter and dictionary key, and main went red.
- A merge of a long-lived branch can break semantically with no textual conflict (the LookDirection to Aim rename, 2026-10-07). Dispatch a merge Hands that verifies and fixes mechanical adaptations only.
- Pin sibling checkouts with a guard that checks revision and cleanliness. Scope the guard to projects that actually reference the sibling.
- Self removes a cut's worktrees in the turn the cut merges or is abandoned,
Unity copies and job and probe directories included. Before removing one,
park any head no ref contains under a local
keep/<name>tag. Never defer cleanup to a handoff. On 2026-10-23C:\aeth-wtheld 255 GB of merged-cut worktrees that a handoff had put off "until idle". C: fell to 1.4 GB free during an operator flight, and a new checkout died mid-write. Operator: "you really gotta start cleaning up after yourself". Check free space before creating a worktree. Remove only worktrees this session's agents created, by name. Never sweep a root by path prefix. The same day's sweep found another Self's live tree "clean and pushed", andgit worktree remove --forceemptied it mid-build. "Clean" says nothing about who is working in a tree.
Adapting the pipeline
Small cuts can merge Imagination into Self when the map is already current, but never merge Soul into Hands. Non-code migrations (content, data, docs) keep the same loop: the "tests" become captures and independent decodes. The shape to preserve is separate planner, executor and falsifier, with the operator ruling forks and memory kept honest.
Record changes to this skill in references/changelog.md, with the evidence that
motivated each one.