What the agent runs asked for — 2026-10-07
The follow-ups from the agent usability runs:
the lines each page lacked, three changes to m0, and the two skills.
Each stumble the runs counted became a line on a page, a change to the
tool, or a line in a skill. SPEC N27 and N52; decision D66.
Lines on the pages
The Python quickstart's serve commands pass --host 127.0.0.1, here and
on the page after it, and the page says the default is every interface.
It says the binary resolves libpython from PATH's python3, so a start
script activates the virtualenv. It says what publish() does with a line
break and what its return value means, and that a form a page posts meets
Django's CSRF check. The home page says, above its first fold, that
llms.txt indexes every page and that each page is Markdown at its URL
with .md in place of the trailing slash: four of five Python runs
fetched the HTML page first, through a fetch that summarises and drops
code blocks.
On the Mojo side, the overview has a table of the API pieces and the page
each is on, links llms.txt, and no longer says "no form library" of a
framework with form(req). The views page gives reply.problem its four
arguments, the other reply helpers beside it. The host and views pages
say where a send from a view reaches. The scaffold's AGENTS.md names the
host and views pages by URL before it names the installed source, which is
where all five runs went first.
Three changes to m0
m0 new .writes the empty current directory and takes its name. Every Mojo run wrote./NAMEand then moved the files up a level; one then sawm0 doctorreport the moved files.- The printed next step binds
127.0.0.1, as do both quickstarts. --template boardis a list every tab shares, whose sender is a view. Every run choseliveand deleted about half of it, because its producer is a timer and the task's sender was a request.
The board, and two facts it rests on
POST /messages appends to a list held in the state and publishes the
whole board through the state's DatastarStream: no producer, no
database. Two facts about Datastar 1.0.4 shaped the rest, each read off
the bundle rather than remembered.
- An action's answer is applied only when its status is 200. The
fetch code returns after its retry decision for any other status, so a
422 fragment never reaches the page, unlike htmx 4, which swaps every
4xx. The board keeps an empty message in the browser with
required, and answers a client that bypasses it withreply.problem. - The morph keeps a typed value unless the
valueattribute changed: it compares the old element's attribute with the new one's, not the property. Answering the form again would not have cleared it. The input is bound to$text, and the POST answersapplication/json{"text":""}, which Datastar reads as a signal patch.
The form is a fragment of its own outside the streamed board, so a frame replaces the board in every tab and leaves another visitor's draft alone.
Every view that touches the state is on_loop=True. Under
--blocking-threads N the host builds a state for each pool thread, and a
post answered there lands in a list and a stream nobody reads. The gate
serves the board behind a pool for that reason, and the template's own
smoke.sh serves it without one, so both shapes are on the wire. Each
on_loop reverted alone fails the gate in its own way: the post reaches
no stream, the stream is refused 409, or the document shows an empty
board.
The same rule found a defect in live: its /events view was not
on_loop, and its handler answered only stateless loop routes, so behind
a pool every stream was refused 409. Nothing served live behind one.
The gate now serves both streaming templates behind a pool.
ViewsApp forwards three stream hooks and not sse_peer_frame, so a
views application cannot deliver another worker's frame. The board stays
one process (max_workers() -> 1), and D66 records what would add the
hook.
The gate
smoke-scaffold holds the board as it holds the others, and adds the
current directory to every template's new phase. sabotage-scaffold
gained ten rules for the board, two for live's stream and two for
m0 new, each run once before landing.
The skills
skills/m0serve/SKILL.md and skills/m0/SKILL.md carry what the runs
looked for and where they found it. They live in this repository, so a
change to the product changes its skill in the same pull request. The
repository is public, which makes it where a reader installs them from;
the owner's private wtalcott marketplace carries them as a plugin whose
upstream is this directory. The run harness gained --plugin-dir, which
loads a plugin into every session of a run and records its version and a
hash of its files.
The Python track with its skill
Five more runs of the Python brief, with the m0serve skill loaded and
the site as it stood before this change:
| track | tool calls, median (range) | wall clock | cost |
|---|---|---|---|
| m0serve, no skill | 13 (13–15) | 88 s | $0.37 |
| m0serve, with the skill | 8 (7–10) | 74 s | $0.27 |
All five met the contract, each invoked the skill first, and each fetched one page, the quickstart as Markdown. Every flagged result was this machine's: three runs still chose the port the desk server holds, and each read the bind failure in its log and moved. The skill did not change the first port choice.
The Mojo track after the release
Ten more runs of the Mojo brief, with m0 0.9.0 on PyPI and the site
deployed from these pages, five of them with the m0 skill loaded:
| track | tool calls, median (range) | wall clock | cost |
|---|---|---|---|
| m0 0.8.0, the pages before this change | 33 (24–34) | 196 s | $1.14 |
| m0 0.9.0, these pages | 14 (11–25) | 100 s | $0.46 |
| m0 0.9.0, with the skill | 8 (8–9) | 65 s | $0.29 |
All ten met the contract. Every run wrote --template board with m0 new ., and none read the framework's source, where every earlier run had.
One stumble was left, in all five runs without the skill. Each ran
m0 --help, which did not list the templates, then a bare m0 new .
before it knew one's name. Each got views and replaced it with board
once m0 new --help had named it. In two, the session refused the
rm -rf that emptied the directory, and those are the 15- and 25-call
runs.
So the top-level help now lists the four templates, a line each, and an
m0 new given no template says it took the default and lists the other
three (SPEC N27). Both read one table in new.py, which m0 new --help
reads too. The next m0 release carries it.