build-a-toy
Skill23 starsChanged yesterdayApache-2.0View on GitHub
Build a toy from a Design Contract until it conforms - run `workshop wish` as round 0, detect every nonconformance against the contract, and run `workshop fix` rounds until none remain, publishing only the conforming build. Can run unattended - one session launches, watches and diagnoses every attempt, fixes Contract Contradictions at the root and relaunches, resuming from the ledger alone. Use after `design-a-toy` produces a contract, when an existing toy drifted from its contract, or to run or resume a toy's unattended loop.
We split this skill into the rules it gives an agent
21 rules. About 0 are common, 3 are distinctive, and 18 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
18
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 13
Use the vocabulary in CONTEXT.md: Design Contract, Conformance,
- Very specific: line 18
Every run this skill starts, whether wish or fix, uses:
- Very specific: line 41
Create the ledger <contract-dir>/build-a-toy/ledger.json or resume from it.
- Very specific: line 164
Follow DETECT.md for this round.
- Very specific: line 218
Check the receipt's References: line against the contract's reference count, exactly as in Step 2, and stop if they differ.
- Very specific: line 224
Only a build with zero findings is published.
- Distinctive: line 239
Every stop of the whole build ends here, whether it conformed, stopped to ask or ran out of budget.
- Very specific: line 248
Keep only Wiki Rules: knowledge of how to model, print or move a part.
- Distinctive: line 253
Ask of each one: if it were deleted, would a skill still run its steps and pass its gates correctly?
- Very specific: line 257
Write the rules to the upstream autonomous-product-to-cad wiki through GitHub, never in the owner's local checkout of it:
- Very specific: line 269
Follow that wiki's own SKILL.md.
- Very specific: line 311
Watch: Run scripts/watch.sh <wish-id>.
- Very specific: line 316
Diagnose: every other stop (loop.state: diagnosing).
- Very specific: line 329
Write the evidence to build-a-toy/r00/attempt<N>-<id>/evidence.json (with the run's LESSON-PROPOSALS.md, if any, beside it for Step 8), …
- Distinctive: line 361
Never answer it inside the run, and never pick one statement over the other in a brief.
- Very specific: line 464
Run the full test suite: PYTHONPATH=src uv run python -m unittest discover -s tests -t .
- Very specific: line 493
Every changed file is listed by path with its old and new sha256.
- Very specific: line 523
every stop of the attempt in stops, with a class from evidence.
- Very specific: line 524
every Contract Contradiction in contract_contradictions with its rows, its amendment, its re-audit and its design-a-toy check.
- Very specific: line 526
every applied in-run Contract Amendment in in_run_amendments, folded into CONTRACT.md.
- Very specific: line 528
every harness issue the loop opened in harness_issues, merged or stopping the loop.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Build a toy to its Design Contract
design-a-toy settles what the toy is. This skill owns everything after
that: it builds the toy, checks the build against the contract, and corrects
it until the two agree. The output is one published toy that conforms to its
contract, or a plain report of why no build conformed.
Use the vocabulary in CONTEXT.md: Design Contract, Conformance,
Requirement Scope, Unique Geometry, Component (not "part").
The settled run parameters
Every run this skill starts, whether wish or fix, uses:
| Flag | Value | Why |
--contract | always | Seals the Design Contract into the run (ADR 0072). The host refuses to complete the run unless its review carries every one of the contract's requirements, in order, each visibly matching — conformance for requirements is established by the run itself, not by this skill re-deriving coverage from a Manager-written list |
--no-publish | always, round 0 included | Nothing reaches Factory until it conforms |
--turn-minutes | 360 | The maximum. The clock is not the limit |
--max-tokens | 100000000 | This is the real backstop. With 360-minute turns and unlimited resume, a run stops when its tokens run out |
--ref | every contract reference, every run | The assembly round scores every sealed reference that no current component round already scored (ADR 0072). A description of an image is no substitute for the image |
--guide | every contract Guide Image (guides[], schema 5), every run, after the --ref images | Guide Images explain the design to the Manager and the workers and are never compared (ADR 0089); the contract refuses a run that leaves one out |
--print-art | every contract print art file (print.art, schema 6), every run, after the --guide images | The art printed on the toy's Print Sheets (ADR 0091), never compared as a likeness target; the contract refuses a run that leaves one out |
--check-motion | true when the contract has any moving part, on every wish, fix and resume | workshop resume reselects this option and defaults it to false. Broken God v01 was resumed without it, and its final verification skipped the motion check and shipped with its wings unverified |
--effort, --model | only if the person passed them | Both are frozen for the run and cannot change on resume, so never raise them yourself |
Step 1 - Load and validate the contract
Inputs: the path to CONTRACT.md, and optionally an existing toy (a
toys/<slug> directory or a wish id). Validate the contract against
CONTRACT-FORMAT.md. If the person has only a
design-a-toy spec and no block, draft the block from the spec, show it next
to the prose, and wait for explicit approval. The person approves the list of
requirements; you only transcribe it.
Create the ledger <contract-dir>/build-a-toy/ledger.json or resume from it.
It records each round's number, kind (wish or fix), wish id, run
workspace, toy directory, final status, brief path and finding ids, and, in
the unattended mode, the loop's own fields (LEDGER.md). Resuming
this skill in a later session starts from the ledger, not from memory.
Done when: the contract validates with no errors, and the ledger exists.
Step 2 - Round 0: the wish
Skip this step when an existing toy was given. That toy is round 0: run Step 4 on it.
--contract seals its file byte for byte as the objective, so the round's
name cannot be a line appended after the fact: copy CONTRACT.md to
build-a-toy/r00/CONTRACT.md with one line prepended, Name this toy
exactly: <title> v01., ahead of the prose. This does not touch the fenced
design-contract block, only the prose above it. Every build in the chain
takes a suffixed name. A local, unpublished projection can never overwrite a
different toys/<slug>, so reusing a name strands the run at its last step.
Build the command:
uv run workshop wish --contract build-a-toy/r00/CONTRACT.md --inventor <inventor> \
--ref <contract-dir>/ref-01-<slug>.png --ref ... \
[--guide <contract-dir>/guide-01-<slug>.png --guide ...] \
[--print-art <contract-dir>/print-01-<slug>.png --print-art ...] \
--no-publish --turn-minutes 360 --max-tokens 100000000 [--check-motion true]Show the person the exact command and wait for explicit approval. Then run
it. When the receipt prints, check that its References: line reports as
many images as the contract lists, its Guides: line as many Guide
Images, and its Print art: line as many print art files. If the counts
differ, stop: the reviewers would judge the wrong set.
A schema 6 toy (ADR 0091) ships its Print Sheets: the accepted receipt
lists each on a Print Sheet: line, and the toy archive holds them under
make/print/sheets/ (print-sheets.pdf, one sheet-<stock>-<n>.png per
page) beside the STEP models. Detection reads those previews with the
contract's print section: a piece missing from the sheets, or art that is
not the approved art, is a finding.
Done when: the run is started, the receipt's reference count matches, and the wish id is in the ledger.
Step 3 - Carry the run to completion
Poll uv run workshop status <wish-id> --json. Its status is active,
waiting, failed or complete.
complete: go to Step 4.waitingwith a receiptneedsentry naming a Reference Camera mismatch (schema 3 contracts, ADR 0083): the Component Reviewer saw the model from a different side than the reference shows. Answer it yourself; do not ask the person. Open the named reference image, check the landmarks the need names against it, and estimate the camera again by eye in the Display Pose frame, rounded to 15 degrees. Then resume withuv run workshop resume <wish-id> --reference-camera <file>=AZ,EL --turn-minutes 360 --json, adding--check-motion truewhenever the run was started with it. This changes only that reference's camera: never edit the image, a requirement or the contract file to answer it. Record the old and new camera and the cue in the ledger.waitingwith aneednaming a Tree defect (schema 7 kits, ADR 0092 decision 10): Make found the sealed Assembly Tree itself inconsistent: a Print Piece or Bought Part it cannot account for, a leaf in two steps, a Part in no step or Component, or a leads step below its lamps. A labelling slip (the built bodies not matching a sound tree) is not one: the run repairs it like any gate and never stops for it (owner decision Q28, 2026-10-23). In the pilot nothing repairs the tree on its own, not the run and not this loop. Append one row to the toy'stoys-spec/<toy>/TREE-ISSUES.md(create it with this header if absent), then ask the owner and wait:| Date | Wish | Caught by | Kind | Part | Detail | Owner's decision | |---|---|---|---|---|---|---| | 2026-10-24 | wish-... | make_round component:cabinet | missing | B02-cabinet-door | no body labelled B02-cabinet-door | (pending) |Caught byis the gate scope the need names, or the review that saw it (a Component Reviewer, DETECT, an image check). Log a contract defect a review finds the same way, even when no gate fired; a Part merely missing from a model is a difference the run repairs, not a row. Fill in the owner's decision when it comes; only the owner changes the tree.- Anything else means the run is incomplete, which is not a design
result. Read the receipt's
stop_category(present wheneverstatusis notcomplete) to decide what to do next, rather than guessing fromstatus,stageor token counts:transportorinspection-in-progress: the stop is resumable and, forinspection-in-progress, still converging. Resume it:uv run workshop resume <wish-id> --turn-minutes 360 --json, adding--check-motion truewhenever the run was started with it, because a resume without it turns the motion check off. Leave--max-tokensout, because a resume keeps the saved budget. Resumes are unlimited and never count as a round.usage-limit(statuswaiting): the Claude Code or Codex account hit its provider usage limit, so the session could not start or continue. It is resumable, but not until the limit resets: a resume before then fails the same way. Wait, then resume with the same command astransport; if it stops atusage-limitagain, wait an hour and retry. It is not a budget stop, so leave--max-tokensout.budget: report plainly that the token budget, the run's only backstop, is exhausted. Hand the decision to the person. A resume without a new--max-tokenscannot proceed past it. In the unattended mode the loop diagnoses it instead (see below). The loop raises the cap on its own at most once per attempt (budget-progressing, recordedbudget_raised: true); any other raise is the owner's. Record an owner-approved raise on the stop it answers asbudget_raised: "owner"withowner_decision: {"at": <stop time>, "limit_before": <tokens>, "limit_after": <tokens>}, and resume with--max-tokens <limit_after>.gate-refusalorunclassified: stop and show the person the receipt. A host gate refusal will not be resolved by resuming unchanged, and an unclassified stop is not safe to guess about. Ask the person how to proceed.
Done when: the status is complete, and the ledger records the run
workspace and toy directory. The workspace is
$(uv run python -c "from workshop.runtime.package_data import default_workshop_home as h; print(h())")/runs/<wish-id>/workspace.
The toy directory is the toys/<inventor>-<slug>/ whose wish/wish.json
carries this wish id.
Step 4 - Detect nonconformance
Follow DETECT.md for this round. It writes
build-a-toy/r<NN>/findings.json, with every contract check listed once, as
either a finding or a pass.
Done when: findings.json is complete and in the ledger.
Step 5 - Decide
Compare this round's finding ids with the previous round's:
- No findings means the toy conforms. Go to Step 7.
- Five fix rounds already spent means stop. Round 0 does not count. Publish nothing, and report the remaining findings for each round. The person decides whether to publish the closest build.
- This fix round removed no finding id that the previous round had, so it did not converge. Stop and report the same way.
- Otherwise go to Step 6.
Step 6 - A correction round
Write build-a-toy/r<NN>/brief.md:
- Its first line is
Name this revision exactly: <title> v<NN+1>.Round 0 isv01, so fix round 1 isv02. Every build in the chain has a different name. - Each finding follows, as the contract value, the measured value, and the evidence. Give a concrete repair only where the fix is unambiguous. Otherwise state the target and leave the method to Make.
- Then this line: every other requirement of the Design Contract still holds; a correction may not trade one requirement for another.
- Then a size budget, so the next round can still chain:
assembled.stepunder 12 MB, and the heaviest Component under 4 MB.
fix --contract seals CONTRACT.md into the correction separately from the
brief (it does not replace --prompt-file), so the brief itself only needs
the findings, not a second copy of the whole contract. The brief becomes part
of the correction run's Wish objective, which is limited to 50,000
characters; if it is over the limit, shorten the findings and show the
person, rather than cutting anything the run is judged against.
Show the person the brief and the exact command, and wait for explicit
approval. Then run the correction from the previous round's run
workspace, not from toys/. The workspace is smaller than the published
archive, and it stays within fix's 128 MiB source limit.
uv run workshop fix "<previous-run-workspace>" --prompt-file build-a-toy/r<NN>/brief.md \
--contract <contract-dir>/CONTRACT.md \
--ref <contract-dir>/ref-01-<slug>.png --ref ... \
[--guide <contract-dir>/guide-01-<slug>.png --guide ...] \
[--print-art <contract-dir>/print-01-<slug>.png --print-art ...] \
--no-publish --turn-minutes 360 --max-tokens 100000000 [--check-motion true]Check the receipt's References: line against the contract's reference
count, exactly as in Step 2, and stop if they differ. Record the new wish id in
the ledger, then return to Step 3.
Step 7 - Publish the conforming build
Only a build with zero findings is published. It carries a suffixed title
such as <title> v03. Publish it under the clean <title> with
uv run workshop publish <wish-id> --title "<title>". This re-seals only the
host's own Release; Make's sealed bytes are untouched, no correction run is
spent, and no detection needs to run again. Omit --title to publish under
the exact suffixed name Make sealed instead.
Its summary line can report effect.factory failed after the listing
actually went live. Before concluding anything, read the effect ledger in
<workshop-home>/state/<wish-id>/factory-effects.sqlite3 and fetch the live
page. Rows marked factory-publish|unknown mean the publication went out, so
do not publish again.
Step 8 - Write back what the build taught
Every stop of the whole build ends here, whether it conformed, stopped to ask or ran out of budget. Nobody reviews the result first. Its sources are:
- each attempt's Lesson Proposals, the
LESSON-PROPOSALS.mdat its run workspace root (<workshop-home>/runs/<wish-id>/workspace/), copied beside that attempt'sevidence.jsonwhen the attempt stopped; - what the diagnoses found: a repeated print defect and the fix that ended it, a gate that passed a defect, a kernel workaround.
Keep only Wiki Rules: knowledge of how to model, print or move a part.
A lesson about designing the toy instead (how a contract row read two ways,
what a reference image misled, the judgment behind a Contract Contradiction
fix) goes to design-a-toy's LESSONS.md under
that skill's rules, committed with the loop's other harness changes.
Ask of each one: if it were deleted, would a skill still run its steps and
pass its gates correctly? If not, it is a workflow change (code, a gate, a
skill's protocol). Fix that through the harness-defect path instead.
Write the rules to the upstream autonomous-product-to-cad wiki through
GitHub, never in the owner's local checkout of it:
S=.claude/skills/build-a-toy/scripts/wiki_writeback.sh
$S clone <scratch>/upstream-wiki
# search first; extend a page before adding one (`wiki new` refuses a taken slug)
cd <scratch>/upstream-wiki && python3 skills/wiki/scripts/wiki search <words>
# ... edit pages under skills/wiki/, `wiki lint`, commit ...
$S push <scratch>/upstream-wikiFollow that wiki's own SKILL.md. Each rule:
- carries
sources: "experience: <the failure class that taught it>"; - states the number or the assert;
- names no toy, run, Component Worker or other Workshop-only term.
push refuses commits outside skills/wiki/ and stops on a rebase
conflict. Merge that by hand, keeping both rules. Runs read the rules after
the owner's next resync-vendored-skills. When nothing new was learned,
push nothing and say so in the report.
Unattended mode
The person can hand a toy's whole loop to one supervising session ("run
Broken God unattended"). That session launches each attempt, watches it,
diagnoses every stop, fixes what it found, and launches the next attempt. It
writes no handoff file: build-a-toy/ledger.json is its only memory, and
its fields are in LEDGER.md. A new session resumes the loop by
reading the ledger alone:
python3 .claude/skills/build-a-toy/scripts/ledger.py next <contract-dir>/build-a-toy/ledger.jsonIt does what that prints: launch, watch, diagnose, fix,
resume-budget, resume-amendment, ask-owner, or migrate for a ledger
that predates this mode. A diagnose that carries then_ask_owner is still done first, so the
owner is asked once, with the diagnosis in hand. Write every decision into the ledger before acting on it, then run
ledger.py check on it. The tools are under scripts/, run from the
Workshop checkout with uv run python; none assumes a platform or a home
directory.
Starting the loop is the person's approval of every Step 2 command and Step 6 brief it builds with the settled run parameters. What still waits for the person is listed under "When the loop stops and asks".
One loop pass
- Launch. Make a fresh detached worktree at
origin/main(git fetch origin && git worktree add --detach <dir> origin/main) and run Step 2's command from it. The round's name takes the next suffix (<title> v<NN>). Record the attempt inrounds, setloop.attempt,loop.wish_id,loop.source_commitandloop.state: watching. - Watch. Run
scripts/watch.sh <wish-id>; it prints a line whenever the run's state changes and exits when the run stops. Answer a Reference Camera need, resume atransportorinspection-in-progressstop and wait out ausage-limitstop exactly as Step 3 says, and keep watching. Acompleterun goes to Step 4 as usual. Diagnose every other stop (
loop.state: diagnosing). Gather the evidence, never guess it:- the receipt:
uv run workshop status <wish-id> --json(stop_category,needs,blocked_reports,reference_conflicts,contract_amendments); - progress:
scripts/tally.py <wish-id> --json(locked,repeated_print_defects) against the previous attempt's; - cost:
scripts/tokens.py <wish-id> --json(cost_units), added tocost_units.by_attempt; - the Component Workers' and the root's transcripts and the component rounds, for what a worker reported blocked and what a repeated print defect is made of.
Write the evidence to
build-a-toy/r00/attempt<N>-<id>/evidence.json(with the run'sLESSON-PROPOSALS.md, if any, beside it for Step 8), classify it withledger.py classifyon that file, and record onestopsentry with the class, the evidence and the progress.- the receipt:
- Fold in-run amendments into the contract, whatever the class (below).
- Fix by class (the table below), then run
ledger.py next. It printsresume-amendmentwhen the stopped run can take the fix as an owner amendment (below); otherwise setloop.state: launchonce nothing is pending. - Check the stop conditions with
ledger.py next. It printsask-ownerwith every reason that holds; otherwise the next pass starts at 1.
Diagnosis classes
Each stop is classified from evidence into exactly one class. The order is the
precedence: a budget stop whose evidence also shows a contradiction is a
Contract Contradiction (Broken God attempt 15 stopped on budget with a
worker blocked on two rows).
| Class | Evidence | What the loop does |
| Camera need | a Reference Camera mismatch need | Step 3's path, unchanged |
contract-contradiction | a need quoting contradicting statements, a Blocked Report open or waiting (except at a progressing attempt's first budget stop with no other such evidence: the raise gives the root its turn to answer), a Component Worker's report quoting rows that cannot both hold, or a repeated print defect that a contract row forces | Fix it at the root (below); resume the stopped run with an invisible fix as an owner amendment, else relaunch |
reference-mismatch | an image contradicts the contract or the camera beyond what a Reference Conflict absorbs | Fix the image with design-a-toy Stage 3b; it is a visible change |
tree-defect | a need beginning "Tree defect" (ADR 0092 decision 10): the sealed Assembly Tree itself is inconsistent. A labelling slip (bodies not matching a sound tree) is not one; it is a failing gate the run repairs (Q28) | Log a TREE-ISSUES.md row (Step 3) and ask the owner; never repair the tree or relabel around it |
harness-defect | Workshop itself went wrong: a false stop, a miscount, a guard or tool refusing valid work | Open an issue, fix and merge it (below) |
budget-progressing | stop_category budget, and more Components locked or fewer repeated print defects than the previous attempt, with no raise yet in this attempt | Resume once with the cap raised by 100M tokens: uv run workshop resume <wish-id> --max-tokens <limit + 100000000> --turn-minutes 360 --json, with --check-motion true when the run has it; record budget_raised: true |
other | anything else, including a second budget stop in one attempt | Ask the owner; when the owner raises the token cap, record budget_raised: "owner" and owner_decision {at, limit_before, limit_after} (never true: that is the loop's one raise), then resume with --max-tokens <limit_after>. A later budget stop in the attempt is still other |
Fixing a Contract Contradiction at the root
Never answer it inside the run, and never pick one statement over the other in a brief. (A contradiction the run's own Contract Amendment removed is not one of these: fold it as above.) Fix the contract:
- Amend the contract with the smallest change that removes the
contradiction, in
design-a-toy's resolution order (Stage 3c and 3d). Back up the current contract and references, writebuild-a-toy/drafts/amend-<x>-notes.md, addamend-<x>tocontract_versions, and record acontract_contradictionsentry: both rows verbatim, asignatureof<check>:<component>(thedesign-a-toycheck that covers this class, and the Component), and the amendment. - Re-audit the whole contract with
design-a-toyStages 3a (the Contract Proof on the amended contract, with a fresh read when a shape, size or position changed), 3b (for every image the amendment touches), 3c and 3d: every Component and every check, not only the changed row. Record the notes' path inreaudit. A new contradiction the re-audit finds goes into the same amendment. - Give
design-a-toya check that would have caught it, when it has none: open a harness issue and fix it like any harness defect, and record it in the entry'sdesign_check. The swept-volume-over-ceiling check in Stage 3c is the first such check (attempt 15). - Apply it, or batch it for the owner, by the approval rule below.
Resume the stopped run with it when it is invisible. Once every Contract Contradiction of the attempt is applied, invisible (
visible: false) and nothing else is pending,ledger.py nextprintsresume-amendment. Resume the run that stopped instead of relaunching, so its locked Components keep their locks:uv run workshop resume <wish-id> --amend-contract <contract-dir>/CONTRACT.md \ --turn-minutes 360 --json [--check-motion true]The host records it as an Owner Contract Amendment (issue #100): it refuses anything beyond requirement text, Interface text and prose, keeps the run's sealed name line (so the root file's own
Name this toy exactlyline, or none, is fine) and unlocks only the Components whose own rows changed. Fold the run's applied in-run amendments intoCONTRACT.mdfirst, asledger.py nextrequires, or the file would undo them. On success set each entry'sresume: resumedandloop.state: watching, and keep watching the same attempt. A run materialized before #100 refuses it ("materialized before owner contract amendments") and nothing is recorded: setresume: refusedand launch the next attempt. A visible change redraws an image, which only a new attempt seals, so it is always relaunched.
Folding in-run Contract Amendments back
A run may amend its own contract when a Contract Contradiction's fix is
invisible: the Workshop Manager proposes it and a fresh Contract Reviewer
confirms it (ADR 0085). The run builds to the amended rows, but the toy's
CONTRACT.md does not change, so the next attempt would meet the same
contradiction. After every attempt, complete or not, fold each applied
amendment back:
uv run workshop status <wish-id> --json > build-a-toy/r00/attempt<N>-<id>/status.json
python3 .claude/skills/build-a-toy/scripts/ledger.py fold <contract-dir>/CONTRACT.md \
build-a-toy/r00/attempt<N>-<id>/status.json --attempt <N> --out build-a-toy/drafts/amend-<x>.mdIt replaces each amended row's text inside the design-contract block and
leaves every other byte of the contract as it is; a change already in the
contract is skipped. Back up CONTRACT.md, review the draft, then copy it
over CONTRACT.md and add amend-<x> to contract_versions. Append each
printed entry to in_run_amendments with contract_version: amend-<x>. It
needs no owner approval (the run's Contract Reviewer found it invisible) and
no separate re-audit beyond the Contract Proof (Stage 3a) on the folded
contract and Stage 3c and 3d on the rows it changed. A change
fold refuses (the row no longer reads as the run quoted it, because an
outer-loop amendment changed it since) is folded by hand, leaving folded:
false until it is; ledger.py next lists it as pending. A refused
in-run amendment is a need like any other and is diagnosed by class.
An applied amendment may also name Guide Image panels it makes wrong
(guides_wrong in its review, printed as "Guide Image to redraw", ADR 0089).
They never stopped the run. Before the next attempt, redraw each named panel
with design-a-toy from the folded contract, and show the owner the changed
Guide Image with the next images they approve; the run is not relaunched for
it alone.
Approval: only visible changes wait for the owner
A change is visible when a reference image would have to be redrawn
because of it. A visible change waits for the owner: all of a loop pass's
visible changes go on one review page,
toys-spec/<toy>/review-amend-<x>/index.html in the main checkout, laid out
as design-a-toy Stage 4 lays out its review (old and new image side by side,
one plain line each). The loop then stops with loop.state: awaiting-owner.
On approval, set the entry's approved to owner <date>, apply it, and set
applied: true.
An invisible change (a clearance, a print stance, hidden geometry, a value
the images do not show) is applied without asking: set approved to
not-needed, apply it, and set applied: true.
Harness defects: fixed and merged automatically
- Open the issue with
gh issue createand record it inharness_issueswithopened_by_loop: true. The loop implements and merges only issues it opened itself. - Implement it in a subagent, in a fresh worktree from
origin/main(status: implementing), following the repository'sAGENTS.md. - Run the full test suite:
PYTHONPATH=src uv run python -m unittest discover -s tests -t . -p 'test_*.py'. git fetch origin && git rebase origin/main, run the suite again, and push the result tomainas a fast-forward. Never force-push. Recordstatus: mergedand themerge_commit.- A conflict with someone else's change on
main(status: conflict), or a test failure it cannot fix (status: failed), stops the loop.
The next attempt then runs from a fresh worktree at the new origin/main.
Delivering a fix to a running run
A merged tool fix reaches a stopped run that should continue, not restart,
only through workshop resume --refresh-tools. That rewrites every host tool
the run carries from the checkout the command runs in, so a refresh from
main also brings every other tool change merged since the run started, and
those can stop the run (Broken God attempt 18 lost every locked Component's
review to unrelated sheet-review gates). Never refresh a running run from
main. Refresh from the run's own source commit plus only the fix:
- Make a branch at the run's source commit, the
loop.source_commitof its attempt:git worktree add -b refresh/<wish-id> <dir> <source_commit>. - Cherry-pick only the fix's commits onto it (
git cherry-pick <sha>...). Resolve a conflict toward the source commit; never pull in a second change to make the fix apply. - From that worktree, list what the refresh would change without
rewriting anything, naming the skill tree the fix touches:
uv run workshop resume <wish-id> --refresh-tools --dry-run --refresh-tree <tree>. Every changed file is listed by path with its old and new sha256. AWARNINGnames any tree beyond the named one; if a listed change is not part of the fix, fix the branch and list again. - Refresh and resume from the same worktree with Step 3's resume command
plus
--refresh-tools --refresh-tree <tree>, and record the branch, its commits and the listed files on the stop the fix answers.
When the loop stops and asks
ledger.py next prints ask-owner, with every reason that holds, when:
- a Contract Contradiction it already fixed comes back: a later entry has the
signatureof one already applied; - 3 consecutive attempts made no progress: none locked more Components or had fewer repeated print defects than the attempt before it;
- the cumulative cost passed
cost_units.cap, 100 cost units for the toy unless the owner set another cap; - a harness fix fails tests the loop cannot fix, or meets a merge conflict;
- a visible change awaits approval.
Set loop.state: awaiting-owner with those reasons in loop.awaiting, and
tell the owner in a few plain lines, with the review page's link when there is
one. Record the owner's answer where it clears its reason: approved on the
visible change, recurrence_acknowledged on the contradiction that came back,
a new cost_units.cap, loop.no_progress_cleared_through, or the harness
issue's new status. Then clear loop.awaiting and run ledger.py next
again.
Done when, for each pass, the ledger shows:
- every stop of the attempt in
stops, with a class from evidence; - every Contract Contradiction in
contract_contradictionswith its rows, its amendment, its re-audit and itsdesign-a-toycheck; - every applied in-run Contract Amendment in
in_run_amendments, folded intoCONTRACT.md; - every harness issue the loop opened in
harness_issues, merged or stopping the loop; - the attempt's cost in
cost_units; ledger.py checkvalid, andledger.py nextprinting either the next attempt'slaunchorask-ownerwith its reasons.
The loop ends when an attempt conforms and is published by Step 7 (loop.state:
done), or when the owner stops it (stopped). Either way it runs Step 8.
The report
End every stop, whether it conformed, hit the cap, did not converge or ran out of budget, with:
- each round's wish id, toy directory, and finding ids;
- which findings were unverified rather than failed;
- what was published, if anything, and how it was confirmed;
- the Wiki Rules Step 8 pushed upstream, with the commit, or "none".
In this repository7 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .agents/product-run/AGENTS.mdAGENTS.md
- harness/AGENTS.mdAGENTS.md
- brainstorm-conceptsSkill
- brainstorm-trendSkill
- design-a-toySkill
- resync-vendored-skillsSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

