agentic-tdd
Test-driven development for behaviour a unit test cannot reach, by writing the expectation…
Prove that a command-line tool actually did what it said, instead of trusting its exit code and its output. Snapshots the filesystem before and after, names the expected consequence in advance, and returns one of four verdicts with what could not be seen. Use after running a
$ npx -y skills add reticlehq/reticle --skill verify-cli-run --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/verify-cli-runContext preview
The summary Claude sees to decide when to auto-load this skill.
Prove that a command-line tool actually did what it said, instead of trusting its exit code and its output. Snapshots the filesystem before and after, names the expected consequence in advance, and returns one of four verdicts with what could not be seen. Use after running a
name: verify-cli-run description: Prove that a command-line tool actually did what it said, instead of trusting its exit code and its output. Snapshots the filesystem before and after, names the expected consequence in advance, and returns one of four verdicts with what could not be seen. Use after running a build, a migration, a scaffolder, a formatter, a codegen step, or an AI coding CLI; when a command printed success and you are about to report "done"; when you are about to write "exit code 0, so it worked"; or when a tool claims it edited files. Needs nothing installed. license: Apache-2.0 metadata: version: 3.7.0 homepage: https://www.reticle.sh repository: https://github.com/reticlehq/reticle
A command exited 0 and printed `✓ done`. You have learned that the tool reached its own success branch. You have not learned that anything happened.
This is the whole problem with verifying a CLI: **the two things everybody checks are both the tool describing itself.** The exit code is chosen by the same code that did the work. The output is written by it. When a tool is wrong about what it did, it is wrong on both, in agreement. That is exactly why their agreement proves nothing.
This skill needs no tools installed. It is four rules and some `git`.
> **Evidence for a consequence must not come from the thing that performed the action.**
Grade every fact before you use it:
| What you have | Grade | Can it prove the command worked? | | --- | --- | --- | | Files on disk, before vs after | **consequence** | **Yes.** The filesystem decided whether the write landed, not the tool | | An API answering when you ask it afterwards | **consequence** | **Yes.** Another party, answering you rather than the tool | | Exit code | presence | No. The tool chose it | | stdout / stderr | context | No. The tool wrote it | | The tool's own `--verbose` report | context | No |
Everything in the bottom three rows is real information and none of it is proof. Use it to explain a verdict, never to reach one.
This is the method. An expectation written after you see the output can be talked into agreeing with whatever happened; one written in advance can only be met or missed.
Write it down in one line, in the transcript, before the command:
EXPECT: dist/index.js is rewritten, and no file outside dist/ changes. EXPECT: src/utils.ts gains a function called parseConfig. EXPECT: the migration creates 3 files under migrations/ and nothing else.
A consequence you cannot state in advance is one you cannot verify. If you cannot name one, say so and stop. That is an honest `no-fault`, not a pass.
**In a git repo.** This is the good case, and it is one line:
git status --porcelain > /tmp/before.txt
`git status --porcelain` is a near-perfect evidence channel: structured, cheap, and independent of the tool. Git's index records what landed on disk, not what the tool meant to do.
**Not in a git repo**, or the paths are outside it:
find <declared-root> -type f -newermt '1970-01-01' -exec shasum -a 256 {} + | sort > /tmp/before.txtThree rules for the roots you declare:
The commonest false green in CLI work: `dist/index.js` exists, so "the build produced `dist/index.js`" passes, on a no-op rebuild that did nothing at all.
Before running, check whether your expected consequence **already holds**. If it does, the command cannot prove it. Either pick a consequence the command changes, or delete the artifact first and say that you did.
<the command> > /tmp/out.txt 2> /tmp/err.txt; echo "exit=$?"
Keep the exit code. You are not going to use it as proof. You are going to use it to explain the verdict, and to notice when it disagrees with the filesystem.
Two things worth knowing:
git status --porcelain > /tmp/after.txt; diff /tmp/before.txt /tmp/after.txt git diff -- <the paths you expected to change>
Now answer your step-1 expectation against **this** and nothing else.
Two checks worth making every time, because they cost nothing:
Not two. The two extra values are the point: they are the ones that stop ignorance being rounded towards good news.
| Verdict | When | | --- | --- | | **yes** | The consequence you named in step 1 is visible in the diff, and it was not already true | | **no** | The diff contradicts it, or the tool claimed something the filesystem does not show | | **unknown** | You could not see what you needed. Nothing was watching, the window was wrong, or the effect is somewhere you were not looking | | **no-fault** | Everything was watched, nothing was w
AI agents can generate code, but still struggle to understand what they build. Reticle brings Jev-style machine-native runtime perception to web & desktop applications.
Repo: reticlehq/reticle
Test-driven development for behaviour a unit test cannot reach, by writing the expectation…
Sweep a whole running web app for what is broken, without writing a script or knowing the…
Find out why something in a running web app does not work, when the console is empty and the…
Check that the UI you actually rendered uses the design system, by reading computed styles in…
Drive and verify an Electron or Tauri desktop app from the inside, including the main-process…
Find out why the tests pass but the app is broken. Catches false greens: a green suite over a…