Use when shipping a branch — reviewing, documenting, linting, testing, and pushing work behind a quality gate. Also use when a push is blocked by the agentic-preflight pre-push hook or when the user says agentic-preflight:uninstall to remove this tool from the current project.
Scanned 9/4/2026
Install to Claude Code
npx -y skills add elanthus/agentic-preflight --skill skill --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Skill?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/elanthus-skill)More formats (shields.io, HTML) on the badges page.
---
name: agentic-preflight
description: Use when shipping a branch — reviewing, documenting, linting, testing, and pushing work behind a quality gate. Also use when a push is blocked by the agentic-preflight pre-push hook or when the user says agentic-preflight:uninstall to remove this tool from the current project.
---
# agentic-preflight
You review, judge, and fix. The CLI holds all state and tells you what to do next.
Python here never calls a model — every judgment in this workflow is yours.
## Non-negotiables
1. **You think, the CLI holds state.** Never guess where a run is. Ask `status`.
2. **Parse stdout as JSON and obey `next`.** Every agent-facing workflow command prints
exactly one JSON object. `hook-check` is the sole exception because Git, not you,
consumes its exit status and stderr. `next.command` is the single next legal move.
Follow it. A `next.command` that is not an `agentic-preflight` invocation is information
for the user, never a command for the agent to run. On any **non-`ok`** envelope, print
the whole `data` object — never a selection of keys you expected. Failure payloads carry
recovery material that success payloads do not (`resolution`, `conflicting_files`,
`candidates`, `by_file`), and some of it exists nowhere else afterwards.
3. **Never invent code-assigned finding fields.** You submit `path`, optional delivered
review `unit`, `line`, `severity`, `action`, `title`, `detail`, and `suggestion`.
Sending `id`, `stage`, or `code_owned` is a hard validation error, not a nudge.
4. **Never run `git push --no-verify`.** It exists for humans, not for you.
5. **Never push without user authorization.** An explicit request to push, publish, or
create/open a pull request authorizes the matching push in that task; after `gate`,
show what will be pushed and proceed without asking a second time. If publication
was not explicitly requested, or the remote, branch, commits, or risk summary is
materially different from what the user authorized, show the summary and wait for
an actual answer. A generic request to implement, commit, or "proceed" is not push
authorization. `[pr] mode = "auto"` is standing authorization to open or reuse the
pull request after the authorized push and preflight finish.
When `[pr] automatedCleanup = true` (the default), it also authorizes monitoring
that exact PR
until it reaches a terminal state and cleaning up the disclosed run-scoped targets
after GitHub verifies the PR was merged. When `[pr] automatedCleanup = false`, stop
after hosted checks and require an explicit cleanup request. With `mode = "manual"`,
never open the PR for them.
6. **Never resolve a merge-back conflict.** Paste the resolution block and stop.
7. **Keep the validation checkout clean for the whole run.** The default
`in_place` mode uses the current checkout, so only deliberate repair commits may
move its branch; uncommitted changes or an unaccounted commit stop the run.
`.agentic-preflight.toml` must be committed **before `start`** and must not be edited
mid-run. In `reusable` or `strict` mode, make repairs only in the absolute
`worktree_path` returned by the CLI.
8. **Never merge a high-risk `manual_merge` pull request or enable auto-merge.** The
hosted check fails while auto-merge is enabled; when successful, it records that the
user must perform the merge and is not authorization for the agent to merge.
9. **Runs belong to source worktrees, not clones.** Other linked worktrees may have
independent active runs. Use `status` for the invoking worktree, `status --all` for
the clone inventory, and `agentic-preflight --run RUN_ID ...` for explicit recovery.
## The loop
```
$ agentic-preflight start --intent "<the user's objective and acceptance criteria>"
{"ok":true,"run_id":"r_4f2a","state":"REVIEW_AWAITING_FINDINGS",
"data":{"worktree_path":"/repos/my-project","worktree_mode":"in_place","changed_files":["src/auth.py"]},
"next":{"instruction":"Fetch the diff before judging it.","command":"agentic-preflight context"}}
$ agentic-preflight context
{"ok":true,"state":"REVIEW_AWAITING_FINDINGS",
"data":{"diff":"diff --git a/src/auth.py ...","changed_files":["src/auth.py"],
"review_coverage":{"manifest":"<digest>","total_units":1,"units":[{"id":"U0001",...}]}},
"next":{"command":"agentic-preflight submit-findings --file findings.json"}}
# If `next.command` is `agentic-preflight review run`, do not submit your own findings.
# The configured independent reviewer receives this same data bundle and returns the
# strict submission through the same validation path.
$ agentic-preflight review run
# You read the diff and decide. Write findings.json, then:
$ agentic-preflight submit-findings --file findings.json
{"ok":true,"state":"REVIEW_BLOCKED","blocking":[{"id":"F001","severity":"high",...}],
"next":{"command":"agentic-preflight respond --id F001 --action fixed --commit <sha>"}}
# Fix it in data.worktree_path, commit there, then:
$ cd /repos/my-project && git add -A && git commit -m "use constant-time compare"
$ agentic-preflight respond --id F001 --action fixed --commit 9c3d1ab
{"ok":true,"state":"REVIEW_BLOCKED","next":{"command":"agentic-preflight verify"}}
$ agentic-preflight verify
{"ok":true,"state":"REVIEW_AWAITING_FINDINGS","data":{"coverage_invalidated":true},
"next":{"command":"agentic-preflight context"}}
# The fix changed the snapshot. Review the complete current diff and submit its new
# manifest. With no new issue, every unreferenced unit is explicitly examined clean.
$ agentic-preflight context
$ agentic-preflight submit-findings --file findings-clean.json
{"ok":true,"state":"REVIEW_GREEN","next":{"command":"agentic-preflight context --section docs"}}
$ agentic-preflight context --section docs
{"ok":true,"state":"DOCS_AWAITING_FINDINGS","data":{"doc_surface":[{"path":"README.md",...}]},
"next":{"command":"agentic-preflight submit-findings --file findings.json"}}
$ agentic-preflight submit-findings --file findings.json # often just {"findings": []}
{"ok":true,"state":"DOCS_GREEN","next":{"command":"agentic-preflight stage run lint"}}
$ agentic-preflight stage run lint
{"ok":true,"state":"LINT_GREEN","next":{"command":"agentic-preflight stage run test"}}
# For a documentation/CI-configuration-only diff, green lint instead records test
# as skipped and returns TEST_GREEN with mergeback as next. Obey the envelope.
$ agentic-preflight stage run test
{"ok":true,"state":"TEST_GREEN","next":{"command":"agentic-preflight mergeback"}}
$ agentic-preflight mergeback
{"ok":true,"state":"VERIFIED","data":{"worktree_mode":"in_place","applied":[],"tree_equivalent":true},
"next":{"command":"agentic-preflight gate"}}
$ agentic-preflight gate
{"ok":true,"state":"AWAITING_PUSH_CONFIRM","data":{"token":"a1b2c3d4","pr_mode":"auto","automated_cleanup":true,"commits":[...]},
"next":{"command":"agentic-preflight push --confirm a1b2c3d4"}}
# Show the remote, branch, and commits. If this task explicitly requested a push,
# publish, or pull request and the summary matches, that request is the confirmation.
# Otherwise STOP and ask whether to push. Once authorized:
$ agentic-preflight push --confirm a1b2c3d4
$ agentic-preflight finish
$ agentic-preflight gc
# Auto PR mode: after preflight finishes, reuse an existing PR for the branch or
# create one automatically without asking about PR creation. Continue into the
# polling and cleanup flow below only when automated_cleanup is true.
$ gh pr create --title "Use constant-time password comparison" --body-file pr-body.md
$ gh pr checks --watch
$ gh pr view "$PR_URL" --json url,state,mergedAt,headRefName,headRefOid,baseRefName
# While state is OPEN, wait 5 minutes and query those same fields again.
# If it is MERGED, perform the disclosed run-scoped cleanup. If it is CLOSED
# without mergedAt, stop without deleting anything.
# Manual PR mode: never create it. Give the user the repository compare URL instead.
```
Work happens in the absolute **validation checkout** named by `worktree_path`. In the
default `in_place` mode that is the current PR checkout; in `reusable` and `strict`
modes it is an isolated worktree. Never assume `cd` persists between tool calls.
The complete command and option reference is in `reference/commands.md`; use it when
an envelope calls for a command or recovery path not expanded in this playbook.
## How to review
Judge the diff, not the repo. Only findings against changed files are accepted.
Account for the complete `review_coverage` manifest returned by `context`; never reuse a
manifest after a commit. The payload's one `examined: "all"` assertion keeps clean hunks
quiet while code verifies that no delivered unit disappears.
| Severity | Means | Example |
|---|---|---|
| `critical` | Data loss, security hole, corruption | Password compared with `==`; SQL built by string concatenation |
| `high` | Wrong behaviour a user will hit | Off-by-one dropping the last record; error swallowed silently |
| `medium` | Real problem, not urgent | Duplicated logic that will drift; missing edge-case handling |
| `low` | Style, naming, nits | Inconsistent naming; a stale comment |
`critical` and `high` block by default. Pick the action deliberately:
- **`auto_fix`** — mechanical and locally verifiable. You can fix it correctly
without asking anyone. Most findings should be this.
- **`ask_user`** — behavioural, API, or product judgment. **Blocks at any
severity**, because choosing for the user *is* the decision you declined to make.
- **`no_op`** — worth recording, not worth acting on.
A low- or medium-severity `auto_fix` finding does not make the stage red, but it still
needs an explicit disposition before following the normal stage continuation. Use
`fixed --commit <sha>` to register the repair, or `accepted --note <reason>` to record
why the valid finding is not worth fixing. A green-stage repair changes the reviewed
snapshot and returns the run to review; a note-only disposition leaves it green.
Be specific. "Consider improving error handling" is not a finding. "Line 42 swallows
`ConnectionError`, so a network failure looks like an empty result" is.
## How to check docs
One question, and only this one:
> **Would a reader following the current documentation now be wrong?**
Not "could the docs be better" — they always could. Zero findings is a **normal and
common outcome**, and reporting zero is a success, not a failure to try.
Docs findings may target files the diff never touched — that is the entire point. But
they must land on documentation: a finding against `src/auth.py` is a review finding
wearing a docs hat, and is rejected. `context --section docs` gives you `doc_surface`;
use it rather than hunting for docs yourself.
The surface is an allowlist, and a rejection is not a verdict on the finding. Repos
often keep their binding rules outside it — `.claude/rules/*.md`, `PRODUCT.md`,
`DESIGN.md`. If a genuinely stale doc sits outside the allowlist, fix it in the same
commit anyway, say in the commit message that it could not be filed, and tell the user
to add it to `[docs] paths` so the next run can see it.
Full rubric: `reference/docs-rubric.md`.
## Findings schema
```json
{"coverage": {"manifest": "<from context>", "examined": "all"}, "findings": [
{"unit": "U0001", "path": "src/auth.py", "line": 42,
"severity": "high", "action": "auto_fix",
"title": "Password compared with ==",
"detail": "Timing-variable comparison leaks length. Use secrets.compare_digest.",
"suggestion": "if secrets.compare_digest(supplied, stored):"}
]}
```
**No `id`. No `stage`. No `code_owned`.** All three are assigned by the CLI. IDs run
`F001`, `F002`, … continuously across the whole run — docs findings continue review
numbering, they do not restart. Full field reference:
`reference/findings-schema.md`.
## Exit codes
| Code | Meaning | What to do |
|---|---|---|
| 0 | OK | Follow `next` |
| 1 | Usage or internal error | Read `error.message`; fix your invocation |
| 2 | Stage failed | Read the log, fix the cause, re-run the stage |
| 3 | Precondition violated | **Run `status`, then obey `next`** |
| 4 | Human resolution required | Stop. Show the user. Do not improvise |
| 5 | Confirmation required | Ask the user, then re-run with the token |
| 10 | Hook blocked a push | Run the gate: `agentic-preflight start --intent "..."` |
**Universal recovery rule: any exit 3 → run `status` → obey `next`.** `status` is legal
in every state. If you are ever unsure where you are, that is always the right call.
## Failure playbooks
Recovery detail lives in `reference/playbooks.md`. Read the matching entry when a run
stops — do not improvise a recovery from the symptom alone.
| Symptom | Playbook |
|---|---|
| Git operation already in progress (exit 3, `operation_in_progress`) | Stop; the user must finish or abort it |
| Merge-back conflict (exit 4, isolated modes only) | Paste `data.resolution` verbatim and stop |
| Stage red after max attempts (exit 4) | Stop retrying; show a stage log, or abort if baseline setup never produced one |
| Hosted CI failed | Fix on the source branch, re-run the whole gate |
| Stale head (exit 3, `stale_run`) | Run `start` again; it preserves the old run as `ORPHANED` |
| Abandoned run | `status --all`; inspect explicitly with `--run RUN_ID` |
| Diff too large (exit 2, `diff_too_large`) | Exclude generated globs; never review part of it |
| No command configured (exit 2, `needs_command`) | Pick from `data.candidates`; distrust the first green |
| Setup failed (exit 2, `setup_failed`) | Obey `status`: abort initial setup or preserve the baseline retry |
| Stage far slower than normal | Check `[worktree] mode` before raising `max_attempts` |
| Copy refused (exit 3) | `copy_files` entry is not gitignored; do not work around it |
| Stage reports zero files to work on | Check whether `worktree_path` is under `.git/` |
| Green in your shell, red under the gate | Compare the gate's non-interactive toolchain and `PATH` with your shell |
## Escalation etiquette
At the gate, show the user — in plain prose, not JSON:
- which **remote and branch** the push targets
- the **commit subjects** being pushed
- the deterministic **risk level and verdict**, including every matched
`human_review_path`
- anything you resolved as `ask_user`, and what you decided
- any finding you dismissed, and why
If the user explicitly asked in this task to push, publish, or create/open a pull
request, and this summary matches that request, display it as a progress update and
continue with the token. Do not ask them to confirm the same publication twice.
Otherwise ask, plainly: *"Ready to push this to `origin/feature-x`?"* Wait for a real
answer. A request only to implement or commit, or a generic "proceed" from a previous
step, is not consent for the push gate. Ask again if the summary reveals an unexpected
remote, branch, commit, or risk decision.
In `[pr] mode = "auto"`, the committed configuration is standing authorization for PR
creation. After the authorized push, `finish`, and `gc`, reuse an existing pull request
for the branch or call `gh pr create` automatically without asking about the PR. When
the gate reports `automated_cleanup: true`, disclose the exact cleanup scope, monitor
that PR, and clean up automatically after GitHub reports it merged.
Do not ask for a separate cleanup confirmation. When it reports
`automated_cleanup: false`, stop after hosted checks without polling the merge state or
deleting anything; cleanup requires a later explicit user request.
In `[pr] mode = "manual"`, ask only whether to push. Afterward, never open a pull
request; construct the forge compare URL from the repository URL, base branch, and head
branch and give it to the user.
If risk returns `needs_human`, explain the merge restriction before pushing, then follow
the configured `[approval] mode`. An explicit request to create the pull request still
authorizes publication when the gate summary matches:
- `manual_merge`: the hosted check reports success only while auto-merge is disabled;
never merge or enable auto-merge, and tell the user that they must review and merge the
pull request manually.
- `environment`: wait for approval through the configured GitHub Environment before the
hosted approval check can pass.
- `peer_review`: require an eligible repository-associated person other than the author
to approve the exact current head.
Only an explicit `[gate] mode = "manual"` hands the push itself to a person.
For `ask_user` findings, present the trade-off and let them choose. Do not present a
decision you have already made as if it were a question.
Branch names are often poor human-facing PR titles, so offer a concise title that
describes the verified change before calling `gh pr create`.
When an automatic pull request is opened or an existing one is reused and
`automated_cleanup` is true, report its URL and disclose the exact run-scoped cleanup
targets before monitoring begins: the PR head and base branches,
the expected gated head commit, this run's validation worktree and `ap/*` branch, the
local PR branch, and its remote branch. Record the full PR URL as
`PR_URL`, then query it explicitly with `gh pr view "$PR_URL" --json
url,state,mergedAt,headRefName,headRefOid,baseRefName`; never rely on the current branch
to select the PR. Require the returned URL, branches, and `headRefOid` to match the
disclosed PR and gated commit. While it remains open, wait 5 minutes between identical
queries; use the host's durable wait or recurring-task mechanism when available so
monitoring survives an ordinary turn boundary. Do not poll more frequently, silently
stop after checks pass, or impose an arbitrary timeout.
If a check fails, inspect and repair it through the normal hosted-CI playbook, push the
newly gated head, disclose and record that new expected head commit, and resume the same
5-minute PR-state loop. If the PR closes without being merged, stop monitoring and
preserve every cleanup target. If the user cancels monitoring, stop without cleanup.
Only a terminal `MERGED` state with a non-null `mergedAt` value advances to automatic
cleanup.
## What to publish, and what it proves
Publish the **findings** in the PR body passed to `gh`: id, severity, path, and the
commit that resolved each. That is the part CI cannot reproduce — no test
suite tells a reviewer which judgment calls were made — and it stops a human
re-deriving what the gate already caught.
The commit's Git-note attestation already carries review coverage plus the local stage
commands, exit codes, and output hashes. Do not copy those into the PR body; if the repo
runs CI, point at the forge's execution for stronger, remote evidence.
Publish the gaps in the same breath: a bypassed hook, a stage that could not run, a
SHA with no green run. An attestation that can only report success is marketing, and a
partial record that reads as complete is worse than none.
State the limit plainly when you show it: this proves what the gate *reported*, including
that every delivered unit was cited or marked examined clean; it does not prove the agent
understood those units or that the review was good. The same diff reviewed twice can
yield different findings. It is an audit trail, not a quality proof, and it substitutes
for neither CI nor a human reviewer.
## Project uninstall trigger (`agentic-preflight:uninstall`)
When the user says `agentic-preflight:uninstall`, treat that exact phrase as approval
to remove agentic-preflight from the current repository without another confirmation.
Resolve the repository root with `git rev-parse --show-toplevel`; stop if the current
directory is not inside a Git repository.
Before changing anything, resolve the actual hook path with `git rev-parse --git-path
hooks/pre-push` and inspect both it and the repository status. Then:
- delete only the repository root's `.agentic-preflight.toml` file, if present;
- if the pre-push hook is the standalone generated hook marked `Installed by
agentic-preflight` and ending in `exec agentic-preflight hook-check`, delete it;
- if it is a shared or custom hook, remove only the clearly bounded
agentic-preflight invocation and its associated wrapper logic; and
- stop and report the exact hook path instead of modifying it if the
agentic-preflight portion cannot be separated confidently.
Do not remove other hook behavior, `.git/agentic-preflight` run history, or
`refs/notes/agentic-preflight`. Report every path removed, anything already absent,
and anything deliberately preserved.
## Cleanup after a merge
For an automatically opened or reused PR, the disclosed cleanup scope, `[pr] mode =
"auto"`, and `automated_cleanup: true` authorize the whole run-scoped cleanup operation
once monitoring verifies the merge. If `automated_cleanup` is false, or for any other
PR, an explicit later user cleanup request grants the same authorization. In either
case, inspect the exact targets and verify through `gh` that the PR
is merged, then perform the cleanup in the same turn without asking again. Immediately
before mutation, query the recorded full PR URL again for `url`, `state`, `mergedAt`,
`headRefName`, `headRefOid`, and `baseRefName`; do not infer the PR from the current
checkout. Re-resolve the local and remote source-branch tips. Delete either source branch
only when the PR head, local tip, and remote tip that exist still equal the disclosed
expected head commit. If any of those commits changed, preserve both source branches and
report the mismatch, but still reclaim this run's validation worktree and `ap/*` branch
when their run identity and the PR's URL, merged state, and head/base branch names match.
Switch a clean source checkout to the base branch when necessary, then fast-forward it
with `git pull --ff-only` so it contains the merged result.
Stop instead of deleting if the PR is not merged, the checkout is dirty, the PR head or
base branch name differs from the disclosed cleanup scope, or a branch is checked out
in an unrelated worktree. Cleanup never performs a blanket `ap/*` deletion. Afterward,
report the exact targets removed, every preserved mismatch, and whether either source
branch was already absent.
For a pushed run with no PR, follow `finish` with `gc`. `gc` compares original fixes
with post-mergeback history using stable patch IDs. Only patch-equivalent fixes are
reclaimed automatically; anything unmerged is retained unless the user explicitly
chooses `--force`. Run directories remain because they hold durable stage logs.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!