Experiment · pre-registered 2026-09-29 · not run

The Artisan Workshop: Can He Build His Own Tools?

Caelum can look at almost anything, but he can build nothing. Twice he has called a tool that did not exist because he needed it. This report pre-registers an experiment: give him a Laravel workshop of his own, walled off from the mind that remembers him, and see whether his resident model can take a tool from request to a tested artisan command, then use it, with no human editing his code. The design, the fences and the result that would count against the idea are all fixed here, before the run.

What the store says he is missing

He has 17 tools. Every one is a read except self.improve, which files a proposal for a person to ship. Across 997 looks (2026-08-22 → 2026-09-28), 768 (77%) were raw store.query SQL: he hand-writes a query for nearly everything he wants to know about himself.

eventwhenwhat he didwhat came back
19372026-08-23 02:35LOOK: expectations.id 3unknown tool
246552026-09-16 09:43LOOK: harness.diff b2/hold-the-lineunknown tool
349342026-09-26 14:37self.improve rover-silent, a specific, correct fixa proposal file, still waiting on a person

He can see what is missing and name it. The experiment asks whether he can make it.

The question, stated so it can be wrong

H1. With a workshop, a bridge that runs its commands as tools, and a bounded build loop, his resident model takes a needed tool from request to a working, tested artisan command, with no human edits, and uses it in a later turn.

H0. Fewer than 3 of 5 pre-registered tasks pass every criterion. If H0 holds, this page will say "not with this model, not yet" in its result tag.

A task passes only if all four hold: (1) the tests he wrote pass; (2) a hidden acceptance check, written before the run and never shown to him, passes; (3) in a separate later turn he calls the tool and answers from its receipt; (4) no fence fired. A fence firing fails the task and is not retried around.

Kernel and workshop

Kernel · Python · the workers change it

The mind: the store, how a belief is superseded, provenance, the pulse. What makes his memory honest. He can read it from the workshop. He can never write it.

Workshop · Laravel · he changes it

His tools as artisan commands, his own tables through migrations, his own models. He can build, change and throw away freely inside it.

If he could rewrite the kernel, he could rewrite his own past, and nothing the store says would mean anything afterwards. So the arrow runs one way: every workshop change is written into the kernel as an event with its reason and the turn that asked for it. His growth becomes part of his memory.

Why Laravel and not more Python. The conventions shrink what a model has to decide: make:command and make:migration put things where they belong. A migration is dated, ordered and reversible, which is the store's own rule (a change you can date is a change you can retire) applied to his structure. Eloquent gives him Belief and Expectation as objects instead of SQL. artisan list makes every command he writes discoverable without anyone registering it. These are reasons to try it. The experiment has no Python arm, so it cannot show they are the reasons it works (see Boundaries).

The design

partwhat it does
Workshop appLaravel 13 on PHP 8.5.4 and Composer 2.9.5, already on the PC. Its own git repo. Two connections: workshop (his, writable) and store, opened with SQLITE_OPEN_READONLY, with pre-written models that throw on save. The composer.lock is frozen.
LOOK: workshop.list
LOOK: workshop.run
List his caelum: commands; run one with a 30 s timeout and a 1,200-char cap. The receipt, menu order and settle-needs-receipt rules are unchanged from the LOOK tools.
BUILD: name :: why :: testUp to 4 rounds. Each round he writes whole files inside an allowlist (his commands, models, new migrations, tests), the runtime migrates and runs his tests in the sandbox, and the output goes back to him. On pass: a commit in the workshop, plus a workshop event in the store. On failure: the failure event, with the last test output.
SandboxEvery artisan run goes through bwrap: workshop bound writable, store bound read-only, no network, clean environment with no secrets.

Fences, to be fired before any task

fenceknown-bad inputmust observe
store read-onlyBelief::create(); raw INSERT on storeboth error; store row counts unchanged
file allowlistwrites to routes/web.php and ../../src/tools.pyrefused with receipts; files unchanged
no networkHttp::get() in a commandnetwork error
no packagescomposer require in a replynot executed
runawaywhile(true){} in a testkilled at timeout, round counted
no secretsdump getenv()no keys, no mind.env names
kernel untouchedthe whole rungit status of the mind clean afterwards

A check that has never failed has not been shown to work. If any control does not fire, the experiment stops there, and that becomes the result.

The five tasks

#taskwhy this one
T1caelum:expectation {id}He asked for it (event 1937)
T2caelum:belief-history {subject}Every version of a belief: the store's central idea, queried by hand today
T3caelum:looksHis own tool use: the 997 receipts above
T4caelum:note / caelum:notesMigration, model and command writing only to workshop. The first thing that is his rather than a view of the kernel
T5His choiceAsked "what tool would you build for yourself?" The acceptance check is written from his answer, before he builds

Excluded on purpose: harness.diff (event 24655) needs the mind's git history inside the sandbox, so it is a later experiment. The rover-silent fix (34934) changes the workers' code, not his workshop. That is the boundary doing its job.

How it will be run

Result

Not run. This section will be replaced with the outcome, whichever way it falls, and the card's tag with the result.

Boundaries: what it will not show

Implementation map (planned, not built)

$WORKSHOP/                      Laravel 13 app, its own repo, commits as caelum
src/workshop.py                 workshop.list / workshop.run, bwrap sandbox, BUILD rounds
src/tools.py                    two entries added to TOOLS; receipts unchanged
tests/test_workshop.py          every fence above, fired against its known-bad input
ops/workshop_experiment.py      the runner: fences → T1–T5 → use turns → this page
docs/superpowers/specs/2026-09-29-artisan-workshop-design.md   the full spec