Install
$ agentstack add skill-jdpalumbo2-claude-skills-clodex ✓ 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 — the front door
Overview
One entry point for all work, so nobody has to remember stage names. This skill runs five things in order and then hands off:
- Preflight — prove the environment before a stage burns tokens on it.
- Open-run detection — a run already in flight is resumed, never
overwritten.
- Profile — load
.clodex/profile.json, or interview once and write it. - Lane classification — feature-shaped work enters the core path; every
other shape is named and handed back, because those lanes are v0.2.
- Change boundary — record what was already dirty, and never let the run
commit someone else's work.
Then it opens the run and hands to a stage skill.
This skill does not edit code, does not call Codex, and does not run release actions. The stage skills own all three.
Paths and commands
CLODEX_HOME="${CLODEX_HOME:-$HOME/.claude/skills/clodex}" # the dir holding this SKILL.md
STATE="$CLODEX_HOME/state/clodex_state.py"
REPO="$(git rev-parse --show-toplevel)"
cd "$REPO" # do this, do not just assume it
REMOTE="$(git rev-parse --abbrev-ref '@{upstream}' 2>/dev/null | cut -d/ -f1 || true)"
[ -n "$REMOTE" ] || REMOTE="$(git remote | head -1)" # empty = this repo has no remote
Shell variables do not survive between separate command invocations, so re-establish this block at the top of any shell you run these procedures in. Later sections use $REPO, $STATE, and $REMOTE as if it were already there.
Every command below runs from $REPO. git check-ignore, the repo inspection in §3, and git add all resolve relative paths against the current directory, so from a subdirectory they answer the wrong question — a correct .gitignore reads as missing. If a step cannot cd, use git -C "$REPO" ….
| Thing | Path | Committed? | |---|---|---| | Run-state engine | $STATE | catalogue | | Profile schema | $CLODEX_HOME/profile.schema.json | catalogue | | Codex runner (stages only, never here) | $CLODEX_HOME/runner/run-codex.sh | catalogue | | Repo profile | $REPO/.clodex/profile.json | yes | | Run directory | $REPO/.clodex// ($RUN_DIR below) | no — gitignored |
A run's state is its directory: events.ndjson is an append-only event log and is the record of what happened; run.json is a snapshot derived from it by replaying the log; lock.json says which session owns the run; write.lock serializes writes and is not something you reason about. You add to a run only by appending an event.
Engine commands (payloads travel on stdin, never argv):
python3 "$STATE" status "$RUN_DIR" # human summary, incl. the lock line
python3 "$STATE" rebuild "$RUN_DIR" # full snapshot JSON
python3 "$STATE" append "$RUN_DIR" /plan-reviewer/.envelope.json",
"input_hashes": [""],
"duration_s": 501, "resumed": false}}
```
`invocation_id` and `role` are required — a record nothing can be matched to
would read as evidence that a round happened. Everything comes off the
envelope the runner already wrote; `input_hashes` is what binds a review to
the plan version it actually read.
**A leg, not an invocation.** A resumed round overwrites its own envelope,
which then reports only the resume — the pilot's envelopes under-reported the
review by 25% that way. So append one `codex` block for the interrupted leg
(`"status": "interrupted"`) and another for the resume (`"resumed": true`),
both with the same `invocation_id`. The legs sum to what the round cost.
Attach a `codex` block to the first event that invocation causes — the finding
it raised, the `batch:reviewed` it produced, the `plan:amended` it forced. A
round that found nothing still gets one: put it on the event its clean result
unlocked (`plan:approved`, `batch:reviewed`), or the log cannot tell "reviewed
clean" from "never reviewed".
**Copied, never estimated.** `duration_s` is the envelope's `exit.duration_ms`
over 1000, and `status` is the envelope's `status` — never a number you
remember, never a state you assert. Estimated durations ran 1.1–1.8× actuals
the first weekend this was tested at scale, and two logs contradicted their
envelopes' status outright. And because the attach discipline itself fails
under load — seven completed invocations went unrecorded that same weekend —
every stage reconciles at its exit step:
```bash
python3 "$STATE" telemetry-sync "$RUN_DIR" "$REPO/.clodex/runner"
Exit 1 means it printed one ready-to-attach codex block per orphaned envelope, every field copied from disk. Attach each block to an event that stage still appends — any event carries one codex block. The diff is recomputable, so a block with no carrier left is not hand-carried in prose: it surfaces again at the next stage's reconcile, whose own appends can carry it.
finding:recorded additionally takes severity, summary, location, detail, recommendation, round, invocation and plan_hash — location and detail copied verbatim from the envelope's finding, so the manifest can answer where and why without anyone opening envelopes — and finding:disposed's note is promoted into the snapshot beside them. See clodex-plan §9.
Long rounds: --detach, and how to watch one
A review or implementer round can outlive a harness tool timeout. Do not babysit it in the foreground and do not hand-roll nohup — the runner does it:
bash "$RUNNER" --role implementer --repo "$REPO" \
--run-id "$(basename "$RUN_DIR")" --prompt-file "$PROMPT" --detach
# -> detached pid log
Watch both signals, because either alone lies: the pid (gone means the run ended, says nothing about how) and the runner log's final status line — grep -E '^(complete|partial|interrupted|failed) ' — which also names the envelope. Heartbeats stream into the same log, so a stalled run and a slow one are distinguishable mid-flight. When the pid is gone, map the status the way the stage skills' rc tables do. --resume works alone: the runner recorded the prompt path in the invocation's meta.
Stage skills always pass --run-id "$(basename "$RUN_DIR")". It keys the runner state by run (.clodex/runner///…), so two runs in one repo never interleave their envelopes.
1. Preflight — before any stage runs
Run every check. A failed check stops here; do not "proceed and see." Report the results in chat and carry them into the run: the run:opened event in §6 takes a preflight field holding every check's verdict, so "was this environment ever verified?" is answerable from the manifest instead of from a transcript. Preflight that runs again — on a resume, or after the user fixes a failed check — rides on whatever event you append next, and appends a second record rather than replacing the first.
A run that is resumed rather than opened has no run:opened to carry it: put the preflight field on the stage:*:entered event the stage skill appends, which is the first event of the resumed session.
When a check fails, the invocation does not end: name the check, say exactly what would fix it, and wait for the user. When they say it is fixed, resume from that check — re-run it and continue down the list. Do not silently re-run the checks that already passed, and do not skip the ones after it.
Order on a first run: checks 4 and 6 read the profile, which does not exist yet. Do checks 1–3 and 5, run the interview (§3), then come back and finish 4 and 6. A first run also has no .clodex/ directory, so §2 finds nothing and costs one ls.
- Repo root.
git rev-parse --show-toplevel. Not inside a work tree → stop
and ask where the work lives. Also note the branch: git rev-parse --abbrev-ref HEAD.
- Remote state.
$REMOTEcomes from the preamble — the remote is not
always named origin, and halting a workflow over a hardcoded name is a self-inflicted outage: ``bash if [ -n "$REMOTE" ]; then git ls-remote --exit-code "$REMOTE" HEAD >/dev/null else echo "no remote configured" fi git status -sb | head -1 # ahead/behind ` ls-remote` proves the remote is reachable and that credentials work. Report divergence now — a repo behind its remote gets resolved before planning, never at ship. "No remote configured" is a pass, not a failure: say so out loud, because ship will have no push step.
.clodex/ignore rule. Run state must never be committed; the profile
must be: ``bash git check-ignore -q .clodex/ANY-RUN-ID/events.ndjson # expect exit 0 (ignored) git check-ignore -q .clodex/profile.json # expect exit 1 (NOT ignored) ` check-ignore tests the path against the ignore rules, so neither path has to exist and ANY-RUN-ID is a stand-in, not a reserved name. Exit 1 on the second probe is the **pass**, not an error — run them as two separate commands so a shell with set -e cannot swallow the result. Either result wrong → the remedy is the **nested ignore file**, .clodex/.gitignore, self-contained inside the directory it governs so no other session's edit to the shared .gitignore can collide with it (that collision once nearly swept 56 events into someone else's commit): ` * !.gitignore !profile.json !claims.json ` The !.gitignore line lets the file exempt itself; without it the remedy ignores its own carrier. claims.json is the shared-claims ledger (check 8) — committed state like the profile, so it gets the same negation (for a root-style remedy: !.clodex/claims.json). Show the user, write it after they agree, and make sure it gets **committed** (§3 step 4 commits it beside the profile) — an uncommitted nested file does not exist in a fresh worktree, which is exactly where run state most needs ignoring. Root-.gitignore lines (.clodex/* + !.clodex/profile.json`) remain a legal remedy where a repo already has them; do not migrate a working one.
Second ignore mechanisms replace .gitignore — probe every one present. .gcloudignore, .dockerignore, .vercelignore, .npmignore: each makes its uploader ignore its list instead of git's, so a repo whose git ignore is perfect can still ship run state — sixteen worktrees of clodex logs and evidence screenshots once entered a production Cloud Build upload exactly this way. For each such file that exists: ``bash for f in .gcloudignore .dockerignore .vercelignore .npmignore; do [ -f "$f" ] && { grep -qE '(^|/)\.clodex(/|$)|^\.clodex\b' "$f" \ || echo "$f does not exclude .clodex/ — run state will ride its uploads"; } done ` A miss is handled the way this check handles .gitignore: show the exact lines to add (.clodex/ — plus worktrees/` when lanes live under the repo), and write them only after the user agrees.
- Runtimes. For each entry in the profile's
runtimes: `command -v
, plus the version check when min_version is set. Missing runtime → stop; it fails later and more expensively inside a stage. An empty list is a legal answer (this repo pins no runtimes); a *missing* runtimes` key is a profile that never answered the question — go fix it in §3.
In a worktree, a missing prerequisite gets an offer — never an auto-run, never a shrug. The profile's commands.install is required by the schema, filled at the interview, and executed by nothing — while every lane rediscovers the same folklore (symlinked env files, a venv built from the parent checkout) by hand. When this check, or a dry probe of the test command, shows dependencies, a venv, or an env file absent in a worktree: offer to run commands.install, and offer to materialize the env files the main checkout carries (symlink or copy; the user names which files, and their contents are never read or printed). Run either only after the user says yes. Preflight's charter stays proof, not construction — the offer is the construction path, and it is theirs to take.
- Codex auth.
command -v codex, thencodex login status(expect exit 0
and a logged-in line). Codex is not optional: plan review is default-on and build delegates to it. Not logged in → stop and ask the user to run codex login.
- Credentials. For each name in the profile's
required_env:
``bash printenv "$NAME" >/dev/null || echo "missing credential: $NAME" `` Names only. Never print, echo, log, or write a credential value.
- Bootstrap (worktree lanes only). When this checkout is a linked
worktree — git rev-parse --git-dir differs from git rev-parse --git-common-dir — first-run setup must already be committed, never re-created here: ``bash git ls-files --error-unmatch .clodex/profile.json # expect exit 0 (tracked) ` Tracked → record {"name": "bootstrap", "status": "pass"}` among the preflight checks. Not tracked → stop; a lane never interviews. Two lanes once interviewed independently, six minutes apart, produced contradictory profiles, and merge order silently picked the winner — every later lane inherited answers nobody chose. The fix is the bootstrap ritual (§3), run once from the main checkout on the default branch before lanes fork; tell the user that, and wait. In the main checkout this check is a no-op — §3 handles the first run there.
- Claims (when
.clodex/claims.jsonexists). The shared-claims ledger:
collision-prone resources — migration numbers, ports, workflow ids, property names — claimed for the repo's concurrent lanes. Orchestrator- owned: only the orchestrator writes or commits it; lanes read. Shape: ``json {"claims": [{"resource": "migration-008", "holder": "lane-C", "note": "room-liveness schema"}]} ` Check every resource this run will need — the brief usually names them, and the plan's Claims: line (clodex-plan §5) re-checks at plan time: `bash python3 - "$REPO/.clodex/claims.json" ... -- until it appears — no new event, no shared mutable state, and the poll answers from committed truth rather than from another lane's promises.
2. Is a run already open?
ls -1d "$REPO"/.clodex/r-*/ 2>/dev/null
python3 "$STATE" status "$REPO/.clodex/"
A run is open when status shows a stage: other than closed.
stage: - is not an open run — it is a directory that never got its run:opened event, left by a session that died in the window §6 opens between mkdir and the first append. It has no brief, lane, or start commit, so there is nothing to resume. Close it out and open a new run: echo '{"e":"run:closed"}' | python3 "$STATE" append "$RUN_DIR" (legal on an empty log; it yields stage: closed).
**One open run per checkout. A linked worktree is its own checkout with its own .clodex/, which is what lets parallel lanes each carry a run — a documented feature, not an accident of --show-toplevel. Within one checkout: if you find two open runs, the older is the one whose run id sorts first — the ids are r--, so plain lexicographic order is chronological. Resume it, or close it with the same run:closed append, before opening anything new. The repo-wide** picture — every run in the main checkout and every worktree — is the index, not a rule:
python3 "$STATE" runs ""
One line per run: path, stage, open findings, release state. It replaces the shell loop every orchestrator otherwise hand-rolls over worktrees/*/.
status also prints a lock: line when lock.json exists. That line decides what you may do:
| status shows | What it means | What to do | |---|---|---| | no lock: line | no write is in flight and no writer died mid-write | Offer resume (below); an append will be accepted. This is the normal state even while
…
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.