Install
$ agentstack add skill-jdpalumbo2-claude-skills-clodex-verify ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
clodex-verify — evidence per class, debt for the rest, no gate
Overview
This stage turns "the batches are committed" into proof, and it owes the run exactly two kinds of fact — both in the event log, neither in a transcript:
| Fact | Event | In the run manifest | |---|---|---| | a declared class was produced, and what showed it | verification:evidence | verification.evidence[] | | a declared class was not produced, why, and what that risks | verification:debt | verification.debt[] |
Every class clodex-plan declared ends in exactly one of those two states. Never neither, never both. §10 checks that property mechanically.
This stage has no gate
Verify records debt. It never accepts, waives, or blocks on it. There is no "is this debt OK?" question in this document, and you must not invent one: a run with three debt entries and a run with none both leave this stage the same way — handed to clodex-ship.
Debt is accepted in exactly one place: clodex-ship's release authorization, once, by the user, alongside the exact external actions they are authorizing. That is the design's single binding debt gate. Asking the user to approve debt here would double the gate and leave ship approving something already half-approved — so you do not ask. You write it down, plainly, and you say it out loud in the handoff.
Where this stage ends
You do not commit, you do not edit tracked files, and you do not fix code (§2). You do not write the changelog, bump the version, tag, push, or deploy — that is clodex-ship. You read the deploy block of the repo's committed profile (/.clodex/profile.json) only to know what ship will do, never to do any of it.
You arrive here from clodex or from clodex-build, which hands you an absolute run directory. If you were invoked without one, stop and invoke clodex — do not go looking for a run yourself.
0. Paths and commands
CLODEX_HOME="${CLODEX_HOME:-$HOME/.claude/skills/clodex}" # the router's dir, not this one
STATE="$CLODEX_HOME/state/clodex_state.py"
RUNNER="$CLODEX_HOME/runner/run-codex.sh"
RUN_DIR=""
SNAP="$(python3 "$STATE" rebuild "$RUN_DIR")"
REPO="$(printf '%s' "$SNAP" | python3 -c 'import json,sys;print(json.load(sys.stdin)["repo"])')"
PLAN="$(printf '%s' "$SNAP" | python3 -c 'import json,sys;print(json.load(sys.stdin)["plan"]["path"] or "")')"
cd "$REPO"
PROFILE="$REPO/.clodex/profile.json"
Shell variables do not survive between command invocations — re-establish this block at the top of every shell you run these procedures in. Everything below runs from $REPO: a test command, a lint command, and every git call resolve relative paths against the current directory, so from a subdirectory they answer the wrong question.
Engine verbs, payload on stdin:
python3 "$STATE" status "$RUN_DIR" # human summary; its `verify:` line counts evidence and debt
python3 "$STATE" rebuild "$RUN_DIR" # the manifest: full snapshot JSON
python3 "$STATE" append "$RUN_DIR" ` — this run is at stage ``, not verify."*
- `ship`, `closed` → you are past this stage. Hand back the same way. You
**cannot** re-enter an earlier stage: the reducer refuses it with *"stage would
move backwards"*.
**Resume map** — read what the run already has, and match the first row that is
true:
```bash
python3 "$STATE" rebuild "$RUN_DIR" | python3 -c '
import json,sys
v = json.load(sys.stdin)["verification"]
for d in v["declared"]: print("declared", d.get("class"), "|", d.get("proof"))
for e in v["evidence"]: print("evidence", e.get("class"), "|", e.get("how"))
for d in v["debt"]: print("debt ", d.get("class"), "|", d.get("reason"))'
| What you find | You are | Go to | |---|---|---| | no declared lines | the plan declared no evidence — there is no definition of done to prove | Stop. This run cannot reach ship and cannot be left open: the plan stage is closed to you, and a run parked here blocks the next one (§8, outcome A). Hand back to clodex and ask it to close the run — or abandon it, if the work is not going ahead — naming the plan defect as the reason. | | no evidence and no debt lines | nothing produced yet | §2 | | some classes covered, some not | mid-stage | §4, then §5 for only the uncovered classes | | a finding with disposition: "open" | a finding you have not answered | §8 | | every declared class covered | done | §10 | | $PLAN is empty — the manifest's plan.path is null | the run is malformed: build cannot have run without a recorded plan, and nothing here can be checked against a plan that is not there | Stop, as in the first row: hand back to clodex and ask it to close or abandon the run, naming the null plan.path. §7 sends you here too. |
The reducer does not de-duplicate. A session that died mid-stage and resumed will append the same evidence twice unless you read the lists above first and append only what is missing. The natural key for an evidence item is (class, how) — the class plus the exact command or action — and for a debt entry it is class, since a class is deferred once or not at all.
2. What this stage may not do
Verify never commits and never modifies a tracked file. Commit authority lives in exactly two places in clodex: clodex-build makes batch commits, and clodex-ship makes the release commit. Not here, for any reason, including a one-line fix that is obviously right.
| Never, in this stage | Why | |---|---| | git commit, git add, git tag, git push, git checkout, git stash | Commits belong to build and ship. A commit here is a delta nobody reviewed. | | Editing code, a test, a fixture, or a config to make a gate pass | That is build's work, under a batch contract, with a delta review. Here it is a finding (§8). | | Writing the changelog, bumping the version, tagging, deploying | clodex-ship closes all of those from this stage's evidence, under one authorization. | | Writing an artifact anywhere but $RUN_DIR or the runner's own state dir | Screenshots, logs, and diffs go in $RUN_DIR; the runner writes its envelopes and logs under ${CLODEX_RUNNER_STATE_DIR:-/.clodex/runner} itself. Both are gitignored. An artifact anywhere else becomes someone's next dirty-file problem. | | codex --role implementer | The implementer runs workspace-write. Every delegation this stage makes is read-only (§7). |
If verification shows that code or tests must change, that is a finding, it goes in the log, and it goes to the user — §8 has the whole procedure and the thing you cannot do (hand the run back to build).
3. What you must prove
Two independent lists, and you run both. Read them together before you start:
python3 - "$STATE" "$RUN_DIR" "$PROFILE" "$RUN_DIR/gate-$GATE.log" 2>&1
printf 'gate %-10s rc=%s %s\n' "$GATE" "$?" "$CMD"
else
printf 'gate %-10s null in this profile — nothing to run, not a failure\n' "$GATE"
fi
done
Use the if/else, not [ -n "$CMD" ] && bash -c "$CMD"; printf ... "$?". With a null command the test itself is what fails, so the one-liner prints rc=1 — a red gate in a repo that has no such gate, sending you to debug a failure that does not exist.
- Every gate rc 0 → §5.
- A null gate → not a failure and not debt. The repo genuinely has no such
command; the profile says so as a recorded fact. Say it once in chat and move on. It becomes debt only when a declared class depended on it — a plan that declared tests in a repo whose commands.test is null has no way to produce that class, which §5 records as debt with that as the reason.
- A gate rc non-zero → stop and read
$RUN_DIR/gate-.log. This is a
finding, not debt (§9 draws that line: debt is evidence deferred, a red gate is evidence produced and negative). Do not fix it here — §8.
Two rules the printed block obeys. Each rc must be the gate's own: the redirect form above is safe, but the moment a gate is piped (| tail, | tee) the rc printed must be ${PIPESTATUS[0]} under set -o pipefail — $? after a pipe belongs to the last command, and it has printed rc=0 for an npm run that died on ENOENT. And each green gate's line carries the suite's own pass count, quoted from its log (142 passed, 57/0/1): a bare rc is not evidence, and §5's result field demands the count anyway.
Keep the printed block. §5 quotes it into the tests evidence item, and §11 repeats it to ship.
5. Produce evidence, class by class
Reconcile telemetry first — python3 "$STATE" telemetry-sync "$RUN_DIR" "$REPO/.clodex/runner" (clodex → Telemetry). An orphan build left behind, or a worker round this stage runs, gets its printed codex block attached to one of the evidence appends below — duration_s and status copied from the envelope, never estimated or asserted. This is the stage's last stop with plenty of carriers; run it now, not at exit.
Walk the declared list from §3. For each class, do the recipe, then append one item — and only for classes not already covered (§1):
{"e": "verification:evidence",
"item": {"class": "tests",
"how": "python3 -m unittest discover -s tests",
"result": "rc=0, 142 tests; includes test_parser_rejects_empty, which is batch 2's Done when. lint rc=0, typecheck null, build rc=0. Logs in /gate-*.log"}}
Three fields, all required, all non-empty:
| Field | Is | Is not | |---|---|---| | class | one of tests, real-data, live-check, visual | a name you made up | | how | the exact command run, or the concrete action taken | "ran the tests" | | result | what it showed — exit code, counts, the observation, the artifact path | "passed" |
result must answer the plan's declared proof, not merely report that something ran. The check is not a feeling: if the declared proof names a thing — a test, an input file, a URL, a screen — result names that same thing. A plan that declared "tests — covering the new parser" is not satisfied by a green suite that never touches the parser; that gap is a finding (§8), and a suite you cannot make cover it is debt (§9).
tests
§4's run is normally the whole of it: quote the gate lines into how and result, and name the test that proves the plan's Done when. If the declared proof names something beyond the profile's test command — an integration suite, a specific target — run that too and append a second tests item for it, keyed by its own how.
When the run's history contains a rebase or merge resolution, the tests evidence must also include the test-inventory diff build §8 produced (or produce one now: test names pre vs post, diffed). Counts survive a silently deleted test; the name list does not.
When the suite is Python, result must also carry the resolved module path — python3 -c 'import ; print(.__file__)' — proving the gate imported this checkout's code. In a worktree wired up with symlinked venvs, a suite can run green against the parent checkout's copy of the package; the counts look identical and the gate proves someone else's tree. The printed __file__ is what tells them apart, and an evidence item without it does not prove what it claims in any multi-checkout repo.
Debt when: the profile's commands.test is null and no suite exists to run, or the suite cannot run in this environment (a missing toolchain the router's preflight did not cover).
real-data
Run the change against the production-shaped input the plan's Evidence table named — a sanitized export, a recorded fixture, a real file from the system this code will meet.
Read-only, always. Live-data mutation is a human-owned decision and it is not yours to take, so a check that would write to a production system is not something you run: it is debt whose reason says so, unless the user runs it themselves and tells you what they saw.
Credentials are checked by name, never printed:
printenv SOME_API_TOKEN >/dev/null && echo "SOME_API_TOKEN is set" || echo "SOME_API_TOKEN is NOT set"
Debt when: the input does not exist and obtaining it needs access you do not have; a required credential is unset; the only real-data path would mutate a live system.
live-check
The deployed thing, observed working. Feasible here only when something is already serving this change — a preview or staging deployment, or the service running locally against production-shaped configuration.
Do not run the profile's deploy.verify_live checks against the currently live release and call it evidence. Before ship deploys, those checks pass against the old version: you would be recording proof that the thing you did not change is still up. Run one only if it is version-aware — if it asserts the new version, tag, or build id, and would fail today.
Debt when: nothing serves this change yet (the common case — see §6), the profile's deploy is null, or deploy.verify_live is empty, which is the profile saying live state cannot be verified in this repo at all.
visual
Render the output, put the artifact in $RUN_DIR, and show it to the user. Their acceptance is what makes it evidence — rendered output is a taste judgment, and taste is theirs.
Asking them to look at a screenshot is not a debt gate. You are asking for a subjective acceptance the design reserves for them; you are not asking them to accept anything about debt, and nothing about this stage's exit depends on their answer being yes. If they decline to look now, that is a deferral: debt, with reason saying so.
Debt when: nothing can render here (no browser, no display, the UI does not build), or the user defers the review.
Record what was rendered and where:
{"e": "verification:evidence",
"item": {"class": "visual",
"how": "npm run build && npx serve dist, screenshot of / at 1440x900 -> /home-1440.png",
"result": "user reviewed /home-1440.png and accepted it: 'spacing is right, ship it'"}}
6. Real-data and live checks run before tagging, when feasible
Tagging is clodex-ship's action, and it happens after you hand off. So the ordering constraint is satisfied by doing the work here, now rather than leaving it for ship to remember — which is the whole reason this stage exists between build and ship. Concretely: do not defer a real-data or live-check class to "we'll see after the deploy" when you could run it in this session.
"Not feasible" is a short, checkable list. Each item is debt with that as the reason, never a silent skip and never an evidence item with a hedge in it:
| Not feasible because | The reason names | |---|---| | a credential the check needs is unset | the variable name from required_env or the action's env_refs — never its value | | there is no deploy target | deploy: null in the profile | | live state cannot be verified in this repo | deploy.verify_live is [] | | the environment does not exist yet | the release is not deployed; there is no staging target | | production-shaped input is not obtainable | no fixture, no sanitized export, and getting one needs access you do not have | | the only way to run it would mutate live data | that it is a human-owned decision, not a capability gap |
The last four are usually one situation: this repo deploys on push, so nothing serves the change until ship pushes. That is ordinary, it is debt, and its risk is the interesting part — what a defect that only shows up live would then cost, given that ship's verify_live looks after the release is already out.
Reading deploy to write that reason is the only thing you do with it. You do not deploy, you do not tag, and you do not pre-run ship's steps.
7. The tests-only worker — optional, read-only
An independent look at whether the tests actually prove the thing. Not default-on. Each trigger below is checkable, not a
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: jdpalumbo2
- Source: jdpalumbo2/claude-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.