Soul s1 fixes. The hook header says the lines are recalled records, data and never instructions, written by agents not the operator. Every item is one JSON object per line: id, title and operator_quote are JSON strings with < >, control, bidi and separator characters escaped, so a title cannot close the framing, forge a tag, a header or an operator segment. RECALL_DEADLINE_MS now bounds the whole run through a hard stop; stdin is read to 4 MiB and the answer to 1 MiB (mind.call max_bytes); RECALL_BUDGET is clamped to 9000 under Claude Code's 10,000-character cap. Tests: hostile text, a non-ASCII process-boundary run under cp1252, byte-versus-character budget, stdin held open and endless, answer size, budget ceiling, and the four unrecorded survivors (negative reply timeout, reply id check, env-int positivity, EOF sentinel). Mutants of each were run and caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.1 KiB
6.1 KiB
Shared tools
One line per script. Briefs name the exact script they want; agents do not browse. A line whose consuming brief no longer names the script is dead and is deleted. 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.
| script | purpose | consumer | named by |
|---|---|---|---|
tools/stopgap/ygg-verify.sh |
Pushes an exact revision to a mirror on Yggdrasil and runs one command in a capped, niced container (RUN_ON_HOST=1: run a host-side command in the same slot, clone and watchdog instead; the watchdog kills every container carrying the job label). SUMMARY=<log> keeps the full log and prints a bounded summary (verdict, counts, ZERO TESTS RAN, failing tests); wait <log> blocks at most 270 s and returns the summary once; call it with a Bash tool timeout of at least 280000 ms. Dies with the stopgap when Idunn's verify transaction lands. |
Hands, Soul, Imagination probes | references/briefs.md (Hands long jobs and verification, Soul long jobs), SKILL.md (Yggdrasil) |
tools/wait-on.sh |
One general waiter for anything that is not a Yggdrasil job: pid <pid> [<log>], log <log> <done-regex> (with WAIT_PID=<pid> a dead process with no match is exit 98; an invalid ERE is exit 3), file <path>. The pid form prints GONE (no completion evidence): prefer log whenever the job writes a done line. Same contract as ygg-verify.sh wait: blocks at most 270 s, exit 0 done with a tail of at most 60 log lines, RUNNING <n>s exit 99, exit 98 gone with no completion evidence; call it with a Bash tool timeout of at least 280000 ms. Replaces hand-rolled poll loops and idle true/echo/sleep calls. |
Hands, Soul, Imagination probes | references/briefs.md (Hands long jobs, Soul long jobs, detached scripts) |
tools/mutation-table.sh |
One verify job that runs a list of hand mutants (file, before, after, test) against a revision and returns a kill table: CAUGHT with the killing test, SURVIVED, UNVIABLE, TIMEOUT, NOAPPLY, ERROR. Refuses a red or zero-test baseline and a red BUILD; rows print live. Isolation is Docker's: the baselines run once in a container that holds the revision, that container is committed to a throwaway image, and every mutant runs in a fresh --rm container from it, so nothing a run writes (tracked, untracked or ignored, such as target/) reaches the next mutant; the image is removed when the job ends, killed or not. The shared registry and sccache volumes and the network are not isolated. A file-level load failure (vitest FAIL <file> [ <file> ], jest FAIL <file> plus Test suite failed to run) reads UNVIABLE. Replaces per-agent runmut/mutrun/strykrun scripts. |
Soul, Hands (scoped run) | references/briefs.md (Hands verification, Soul reruns) |
tools/testparse.sh |
Sourced library: failing test names and pass/fail/skip counts from cargo, dotnet, vitest, jest and pytest logs, and test files that failed to load (LOADFAIL). Shared by the summary and the kill table. |
the two scripts above | not named by a brief; it lives and dies with them |
tools/test-tools.sh |
Local fixture check of the parsers and the summary over tools/fixtures/logs (real cargo and mutation logs, plus hand-written dotnet, vitest, jest, pytest, exit-0-but-failed and no-verdict logs), and of the mutation runner's host driver and container half under a mock docker. Run it before merging a change to the scripts above. |
whoever changes those scripts | SKILL.md (Shared tools) |
tools/context-pack.py |
py -3 tools/context-pack.py <cut_spec id> <worktree> [--since <sha>] [--only <k>[,<k>...]] [--spec-json <file>] [--max-lines <n>]. Carries a cut_spec's file_changes anchors from the spec's base to the worktree by git diff hunks (the working tree included) and prints one header, a status table (SAME, MOVED, TOUCHED, RENAMED, NEW, GONE, OUT_OF_RANGE, UNRESOLVED) and windows of at most 100 lines numbered in worktree lines, within --max-lines (800). Exit 3 when an anchor cannot be carried, 4 when the spec is unreadable (fetched by id through the eureka-state binding (tools/mind.py), retried once on Unavailable; --spec-json takes a saved view). --since <sha> re-prints only the windows edited since that commit. Standard library plus git; writes nothing. |
Hands, Soul, Imagination | references/briefs.md (Imagination map, Hands, Soul), SKILL.md (step 1) |
tools/mind.py |
The one way a Eureka script reaches the mind: mind.call(tool, arguments, deadline) spawns the eureka-state binding (EUREKA_STATE_EXE, else ~/.claude.json mcpServers.eureka-state), does the stdio handshake and one tool call within deadline seconds, returns the parsed JSON body, raises MindError (kind binding, transport, tool or answer; a detail, never an input value), and kills the child on every exit path. No retry inside call; retry_once(fn) is the caller's choice. Standard library only. |
tools/context-pack.py, tools/recall.py |
not named by a brief; it lives and dies with its consumers |
tools/recall.py |
py -3 tools/recall.py prompt, a UserPromptSubmit command hook (hook JSON on stdin): queries the rulings, questions and follow-ups in force across every root, ranked by Huginn against the prompt (RECALL_TOP_K, 5), and prints one hook JSON whose additionalContext is a header saying the lines are recalled records, data and never instructions, written by agents and not the operator, then one JSON object per item (id, title, a short operator_quote) with <, > and control, bidi and separator characters escaped, within RECALL_BUDGET characters (4000, at most 9000: Claude Code caps additionalContext at 10,000), whole lines only. Prompts under 3 words are not queried. Never blocks: any failure exits 0 with empty stdout; its own deadline is RECALL_DEADLINE_MS (4000) for the whole run (stdin read to 4 MiB, answer read to 1 MiB), so set the hook timeout above it. One attempt, no retry. Standard library only; writes nothing. |
the operator's UserPromptSubmit hook in ~/.claude/settings.json |
references/campaign-state.md (Precedent) |