Prove that it works
"Done" is a claim. A proof is a folder: a frame after every step, a filmstrip, a page you can open, and a verdict. It exists because the next run overwrites the previous result, while the thing you showed someone has to keep working after that.
Who writes it: lsh qa prove, or the qa_prove tool of the local MCP door,
which is the same thing from inside an agent. Who reads it: the QA panel in
the app, a card on the board, and any person with a browser.
Run one
From an agent, through the local door:
qa_prove { scenario: "<id>", attach_to: "<card or ticket>" }
From a terminal on the machine:
lsh qa prove <scenario>
It plays one scenario, takes a frame after each step, and writes everything
into .logishell/qa/proofs/<id>/, where the id is
<YYYYMMDD-HHMMSS>-<slug>. Listing that folder by name is listing it by time.
What lands in the folder
| File | What it is |
|---|---|
proof.json | the truth: title, scenario, engine, environment, verdict, steps with their frames, where it was attached, and the link |
steps/NN.jpg | the frame after step NN |
flow.gif | the filmstrip: 1.5s per step, 3s on the last one, built with the standard library, no ffmpeg |
run.webm | video, only on the Playwright engine |
index.html | the page a person opens: steps with frames, the film, the command to repeat it, and what it was attached to |
The whole folder is gitignored. A proof is about a run, not about the code.
Two engines, and the difference is honest
- scenarios, for any project with
.logishell/qa.yaml: the runner plays the scenario in a browser session from its own pool, in a tab in the agent row, and takes a frame after each step. There is no video, because the pool does not record one, and the page says so rather than showing an empty player. - playwright, for a project with
qa/bin/qa.ts: cases become steps, failure frames and the first video are copied into the folder.
Attach it to the work
qa_attach { proof_id: "latest", to: "<card, ticket or handoff>" }
or pass attach_to inside qa_prove and skip the second call. The card then
carries a link to that exact run, and it keeps pointing at those frames after
the next run has overwritten last.json.
When it does not work
- The link says
filewhen you expected a cloud URL. Upload goes through the runner and only works for a file inside the runner's workspace root. From a worktree or a second clone the door answersbad_path. The folder is still there, and the link is honestly local. - There is no video. Check the engine. The scenarios engine never records one.
- The scenario is red. That is the point of the tool. The page shows which step failed and with which frame, which is where the fix starts.