agentic-preflight 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentic_preflight/__init__.py +0 -0
- agentic_preflight/__main__.py +4 -0
- agentic_preflight/_bundled_skill/SKILL.md +400 -0
- agentic_preflight/_bundled_skill/reference/commands.md +294 -0
- agentic_preflight/_bundled_skill/reference/docs-rubric.md +88 -0
- agentic_preflight/_bundled_skill/reference/findings-schema.md +102 -0
- agentic_preflight/approval.py +122 -0
- agentic_preflight/attestation.py +220 -0
- agentic_preflight/cli.py +600 -0
- agentic_preflight/config.py +277 -0
- agentic_preflight/dependencies.py +225 -0
- agentic_preflight/diff.py +267 -0
- agentic_preflight/envelope.py +125 -0
- agentic_preflight/errors.py +219 -0
- agentic_preflight/findings.py +161 -0
- agentic_preflight/gitx.py +353 -0
- agentic_preflight/hook.py +158 -0
- agentic_preflight/initcmd.py +141 -0
- agentic_preflight/integrations.py +490 -0
- agentic_preflight/machine.py +356 -0
- agentic_preflight/mergeback.py +158 -0
- agentic_preflight/models.py +322 -0
- agentic_preflight/publish/__init__.py +0 -0
- agentic_preflight/publish/gate.py +52 -0
- agentic_preflight/py.typed +0 -0
- agentic_preflight/risk.py +146 -0
- agentic_preflight/runs/__init__.py +38 -0
- agentic_preflight/runs/_session.py +206 -0
- agentic_preflight/runs/lifecycle.py +304 -0
- agentic_preflight/runs/mergeback.py +234 -0
- agentic_preflight/runs/publish.py +226 -0
- agentic_preflight/runs/resolve.py +238 -0
- agentic_preflight/runs/review.py +763 -0
- agentic_preflight/runs/stages.py +400 -0
- agentic_preflight/runs/start.py +413 -0
- agentic_preflight/runtime.py +299 -0
- agentic_preflight/stages/__init__.py +0 -0
- agentic_preflight/stages/change_scope.py +57 -0
- agentic_preflight/stages/detect.py +116 -0
- agentic_preflight/stages/docs.py +154 -0
- agentic_preflight/stages/shellstage.py +244 -0
- agentic_preflight/store.py +276 -0
- agentic_preflight/sync.py +119 -0
- agentic_preflight/worktree.py +289 -0
- agentic_preflight-0.3.0.dist-info/METADATA +498 -0
- agentic_preflight-0.3.0.dist-info/RECORD +49 -0
- agentic_preflight-0.3.0.dist-info/WHEEL +4 -0
- agentic_preflight-0.3.0.dist-info/entry_points.txt +2 -0
- agentic_preflight-0.3.0.dist-info/licenses/LICENSE +201 -0
|
File without changes
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentic-preflight
|
|
3
|
+
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.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# agentic-preflight
|
|
7
|
+
|
|
8
|
+
You review, judge, and fix. The CLI holds all state and tells you what to do next.
|
|
9
|
+
Python here never calls a model — every judgment in this workflow is yours.
|
|
10
|
+
|
|
11
|
+
## Non-negotiables
|
|
12
|
+
|
|
13
|
+
1. **You think, the CLI holds state.** Never guess where a run is. Ask `status`.
|
|
14
|
+
2. **Parse stdout as JSON and obey `next`.** Every command prints exactly one JSON
|
|
15
|
+
object. `next.command` is the single next legal move. Follow it. On any
|
|
16
|
+
**non-`ok`** envelope, print the whole `data` object — never a selection of keys
|
|
17
|
+
you expected. Failure payloads carry recovery material that success payloads do
|
|
18
|
+
not (`resolution`, `conflicting_files`, `candidates`, `by_file`), and some of it
|
|
19
|
+
exists nowhere else afterwards.
|
|
20
|
+
3. **Never invent code-assigned finding fields.** You submit `path`, optional delivered
|
|
21
|
+
review `unit`, `line`, `severity`, `action`, `title`, `detail`, and `suggestion`.
|
|
22
|
+
Sending `id`, `stage`, or `code_owned` is a hard validation error, not a nudge.
|
|
23
|
+
4. **Never run `git push --no-verify`.** It exists for humans, not for you.
|
|
24
|
+
5. **Never push without user authorization.** An explicit request to push, publish, or
|
|
25
|
+
create/open a pull request authorizes the matching push in that task; after `gate`,
|
|
26
|
+
show what will be pushed and proceed without asking a second time. If publication
|
|
27
|
+
was not explicitly requested, or the remote, branch, commits, or risk summary is
|
|
28
|
+
materially different from what the user authorized, show the summary and wait for
|
|
29
|
+
an actual answer. A generic request to implement, commit, or "proceed" is not push
|
|
30
|
+
authorization. `[pr] mode = "auto"` is standing authorization to open or reuse the
|
|
31
|
+
pull request after the authorized push and preflight finish. With `mode = "manual"`,
|
|
32
|
+
never open the PR for them.
|
|
33
|
+
6. **Never resolve a merge-back conflict.** Paste the resolution block and stop.
|
|
34
|
+
7. **Keep the validation checkout clean for the whole run.** The default
|
|
35
|
+
`in_place` mode uses the current checkout, so only deliberate repair commits may
|
|
36
|
+
move its branch; uncommitted changes or an unaccounted commit stop the run.
|
|
37
|
+
`.agentic-preflight.toml` must be committed **before `start`** and must not be edited
|
|
38
|
+
mid-run. In `reusable` or `strict` mode, make repairs only in the absolute
|
|
39
|
+
`worktree_path` returned by the CLI.
|
|
40
|
+
8. **Never merge a high-risk `manual_merge` pull request or enable auto-merge.** The
|
|
41
|
+
hosted check fails while auto-merge is enabled; when successful, it records that the
|
|
42
|
+
user must perform the merge and is not authorization for the agent to merge.
|
|
43
|
+
|
|
44
|
+
## The loop
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
$ agentic-preflight start --intent "<the user's objective and acceptance criteria>"
|
|
48
|
+
{"ok":true,"run_id":"r_4f2a","state":"REVIEW_AWAITING_FINDINGS",
|
|
49
|
+
"data":{"worktree_path":"/repos/my-project","worktree_mode":"in_place","changed_files":["src/auth.py"]},
|
|
50
|
+
"next":{"instruction":"Fetch the diff before judging it.","command":"agentic-preflight context"}}
|
|
51
|
+
|
|
52
|
+
$ agentic-preflight context
|
|
53
|
+
{"ok":true,"state":"REVIEW_AWAITING_FINDINGS",
|
|
54
|
+
"data":{"diff":"diff --git a/src/auth.py ...","changed_files":["src/auth.py"],
|
|
55
|
+
"review_coverage":{"manifest":"<digest>","total_units":1,"units":[{"id":"U0001",...}]}},
|
|
56
|
+
"next":{"command":"agentic-preflight submit-findings --file findings.json"}}
|
|
57
|
+
|
|
58
|
+
# If `next.command` is `agentic-preflight review run`, do not submit your own findings.
|
|
59
|
+
# The configured independent reviewer receives this same data bundle and returns the
|
|
60
|
+
# strict submission through the same validation path.
|
|
61
|
+
$ agentic-preflight review run
|
|
62
|
+
|
|
63
|
+
# You read the diff and decide. Write findings.json, then:
|
|
64
|
+
$ agentic-preflight submit-findings --file findings.json
|
|
65
|
+
{"ok":true,"state":"REVIEW_AWAITING_RESPONSES","blocking":[{"id":"F001","severity":"high",...}],
|
|
66
|
+
"next":{"command":"agentic-preflight respond --id F001 --action fixed --commit <sha>"}}
|
|
67
|
+
|
|
68
|
+
# Fix it in data.worktree_path, commit there, then:
|
|
69
|
+
$ cd /repos/my-project && git add -A && git commit -m "use constant-time compare"
|
|
70
|
+
$ agentic-preflight respond --id F001 --action fixed --commit 9c3d1ab
|
|
71
|
+
{"ok":true,"state":"REVIEW_FIXING","next":{"command":"agentic-preflight verify"}}
|
|
72
|
+
|
|
73
|
+
$ agentic-preflight verify
|
|
74
|
+
{"ok":true,"state":"REVIEW_AWAITING_FINDINGS","data":{"coverage_invalidated":true},
|
|
75
|
+
"next":{"command":"agentic-preflight context"}}
|
|
76
|
+
|
|
77
|
+
# The fix changed the snapshot. Review the complete current diff and submit its new
|
|
78
|
+
# manifest. With no new issue, every unreferenced unit is explicitly examined clean.
|
|
79
|
+
$ agentic-preflight context
|
|
80
|
+
$ agentic-preflight submit-findings --file findings-clean.json
|
|
81
|
+
{"ok":true,"state":"REVIEW_GREEN","next":{"command":"agentic-preflight context --section docs"}}
|
|
82
|
+
|
|
83
|
+
$ agentic-preflight context --section docs
|
|
84
|
+
{"ok":true,"state":"DOCS_AWAITING_FINDINGS","data":{"doc_surface":[{"path":"README.md",...}]},
|
|
85
|
+
"next":{"command":"agentic-preflight submit-findings --file findings.json"}}
|
|
86
|
+
|
|
87
|
+
$ agentic-preflight submit-findings --file findings.json # often just {"findings": []}
|
|
88
|
+
{"ok":true,"state":"DOCS_GREEN","next":{"command":"agentic-preflight stage run lint"}}
|
|
89
|
+
|
|
90
|
+
$ agentic-preflight stage run lint
|
|
91
|
+
{"ok":true,"state":"LINT_GREEN","next":{"command":"agentic-preflight stage run test"}}
|
|
92
|
+
|
|
93
|
+
# For a documentation/CI-configuration-only diff, green lint instead records test
|
|
94
|
+
# as skipped and returns TEST_GREEN with mergeback as next. Obey the envelope.
|
|
95
|
+
|
|
96
|
+
$ agentic-preflight stage run test
|
|
97
|
+
{"ok":true,"state":"TEST_GREEN","next":{"command":"agentic-preflight mergeback"}}
|
|
98
|
+
|
|
99
|
+
$ agentic-preflight mergeback
|
|
100
|
+
{"ok":true,"state":"VERIFIED","data":{"worktree_mode":"in_place","applied":[],"tree_equivalent":true},
|
|
101
|
+
"next":{"command":"agentic-preflight gate"}}
|
|
102
|
+
|
|
103
|
+
$ agentic-preflight gate
|
|
104
|
+
{"ok":true,"state":"AWAITING_PUSH_CONFIRM","data":{"token":"a1b2c3d4","pr_mode":"auto","commits":[...]},
|
|
105
|
+
"next":{"command":"agentic-preflight push --confirm a1b2c3d4"}}
|
|
106
|
+
|
|
107
|
+
# Show the remote, branch, and commits. If this task explicitly requested a push,
|
|
108
|
+
# publish, or pull request and the summary matches, that request is the confirmation.
|
|
109
|
+
# Otherwise STOP and ask whether to push. Once authorized:
|
|
110
|
+
$ agentic-preflight push --confirm a1b2c3d4
|
|
111
|
+
$ agentic-preflight finish
|
|
112
|
+
$ agentic-preflight gc
|
|
113
|
+
|
|
114
|
+
# Auto PR mode: after preflight finishes, reuse an existing PR for the branch or
|
|
115
|
+
# create one automatically without asking about PR creation.
|
|
116
|
+
$ gh pr create --title "Use constant-time password comparison" --body-file pr-body.md
|
|
117
|
+
$ gh pr checks --watch
|
|
118
|
+
|
|
119
|
+
# Manual PR mode: never create it. Give the user the repository compare URL instead.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Work happens in the absolute **validation checkout** named by `worktree_path`. In the
|
|
123
|
+
default `in_place` mode that is the current PR checkout; in `reusable` and `strict`
|
|
124
|
+
modes it is an isolated worktree. Never assume `cd` persists between tool calls.
|
|
125
|
+
The complete command and option reference is in `reference/commands.md`; use it when
|
|
126
|
+
an envelope calls for a command or recovery path not expanded in this playbook.
|
|
127
|
+
|
|
128
|
+
## How to review
|
|
129
|
+
|
|
130
|
+
Judge the diff, not the repo. Only findings against changed files are accepted.
|
|
131
|
+
Account for the complete `review_coverage` manifest returned by `context`; never reuse a
|
|
132
|
+
manifest after a commit. The payload's one `examined: "all"` assertion keeps clean hunks
|
|
133
|
+
quiet while code verifies that no delivered unit disappears.
|
|
134
|
+
|
|
135
|
+
| Severity | Means | Example |
|
|
136
|
+
|---|---|---|
|
|
137
|
+
| `critical` | Data loss, security hole, corruption | Password compared with `==`; SQL built by string concatenation |
|
|
138
|
+
| `high` | Wrong behaviour a user will hit | Off-by-one dropping the last record; error swallowed silently |
|
|
139
|
+
| `medium` | Real problem, not urgent | Duplicated logic that will drift; missing edge-case handling |
|
|
140
|
+
| `low` | Style, naming, nits | Inconsistent naming; a stale comment |
|
|
141
|
+
|
|
142
|
+
`critical` and `high` block by default. Pick the action deliberately:
|
|
143
|
+
|
|
144
|
+
- **`auto_fix`** — mechanical and locally verifiable. You can fix it correctly
|
|
145
|
+
without asking anyone. Most findings should be this.
|
|
146
|
+
- **`ask_user`** — behavioural, API, or product judgment. **Blocks at any
|
|
147
|
+
severity**, because choosing for the user *is* the decision you declined to make.
|
|
148
|
+
- **`no_op`** — worth recording, not worth acting on.
|
|
149
|
+
|
|
150
|
+
Be specific. "Consider improving error handling" is not a finding. "Line 42 swallows
|
|
151
|
+
`ConnectionError`, so a network failure looks like an empty result" is.
|
|
152
|
+
|
|
153
|
+
## How to check docs
|
|
154
|
+
|
|
155
|
+
One question, and only this one:
|
|
156
|
+
|
|
157
|
+
> **Would a reader following the current documentation now be wrong?**
|
|
158
|
+
|
|
159
|
+
Not "could the docs be better" — they always could. Zero findings is a **normal and
|
|
160
|
+
common outcome**, and reporting zero is a success, not a failure to try.
|
|
161
|
+
|
|
162
|
+
Docs findings may target files the diff never touched — that is the entire point. But
|
|
163
|
+
they must land on documentation: a finding against `src/auth.py` is a review finding
|
|
164
|
+
wearing a docs hat, and is rejected. `context --section docs` gives you `doc_surface`;
|
|
165
|
+
use it rather than hunting for docs yourself.
|
|
166
|
+
|
|
167
|
+
The surface is an allowlist, and a rejection is not a verdict on the finding. Repos
|
|
168
|
+
often keep their binding rules outside it — `.claude/rules/*.md`, `PRODUCT.md`,
|
|
169
|
+
`DESIGN.md`. If a genuinely stale doc sits outside the allowlist, fix it in the same
|
|
170
|
+
commit anyway, say in the commit message that it could not be filed, and tell the user
|
|
171
|
+
to add it to `[docs] paths` so the next run can see it.
|
|
172
|
+
|
|
173
|
+
Full rubric: `reference/docs-rubric.md`.
|
|
174
|
+
|
|
175
|
+
## Findings schema
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{"coverage": {"manifest": "<from context>", "examined": "all"}, "findings": [
|
|
179
|
+
{"unit": "U0001", "path": "src/auth.py", "line": 42,
|
|
180
|
+
"severity": "high", "action": "auto_fix",
|
|
181
|
+
"title": "Password compared with ==",
|
|
182
|
+
"detail": "Timing-variable comparison leaks length. Use secrets.compare_digest.",
|
|
183
|
+
"suggestion": "if secrets.compare_digest(supplied, stored):"}
|
|
184
|
+
]}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**No `id`. No `stage`. No `code_owned`.** All three are assigned by the CLI. IDs run
|
|
188
|
+
`F001`, `F002`, … continuously across the whole run — docs findings continue review
|
|
189
|
+
numbering, they do not restart. Full field reference:
|
|
190
|
+
`reference/findings-schema.md`.
|
|
191
|
+
|
|
192
|
+
## Exit codes
|
|
193
|
+
|
|
194
|
+
| Code | Meaning | What to do |
|
|
195
|
+
|---|---|---|
|
|
196
|
+
| 0 | OK | Follow `next` |
|
|
197
|
+
| 1 | Usage or internal error | Read `error.message`; fix your invocation |
|
|
198
|
+
| 2 | Stage failed | Read the log, fix the cause, re-run the stage |
|
|
199
|
+
| 3 | Precondition violated | **Run `status`, then obey `next`** |
|
|
200
|
+
| 4 | Human resolution required | Stop. Show the user. Do not improvise |
|
|
201
|
+
| 5 | Confirmation required | Ask the user, then re-run with the token |
|
|
202
|
+
| 10 | Hook blocked a push | Run the gate: `agentic-preflight start --intent "..."` |
|
|
203
|
+
|
|
204
|
+
**Universal recovery rule: any exit 3 → run `status` → obey `next`.** `status` is legal
|
|
205
|
+
in every state. If you are ever unsure where you are, that is always the right call.
|
|
206
|
+
|
|
207
|
+
## Failure playbooks
|
|
208
|
+
|
|
209
|
+
**Merge-back conflict (exit 4, isolated modes only).** The branch has already been
|
|
210
|
+
restored exactly and your fix commits are safe in the worktree. Paste
|
|
211
|
+
`data.resolution` to the user verbatim and **stop**. Do not cherry-pick, do not force,
|
|
212
|
+
do not pick a side. A conflict is a content decision and it is not yours to make.
|
|
213
|
+
|
|
214
|
+
The full conflict report is stored in the event log and replayed by `status`. After a
|
|
215
|
+
person resolves or restores the reported paths, `mergeback` is the legal retry and
|
|
216
|
+
completed verification remains intact when the resulting tree is still identical to
|
|
217
|
+
the verified tree. A different tree must go through a fresh run. Before concluding
|
|
218
|
+
the conflict is real, check the user's tree was clean — see non-negotiable 7.
|
|
219
|
+
|
|
220
|
+
**Stage red after max attempts (exit 4).** Stop retrying — you have already tried
|
|
221
|
+
`max_attempts` times and the tool is telling you the loop is not converging. Show the
|
|
222
|
+
user `agentic-preflight logs --stage <name>` output and ask how to proceed.
|
|
223
|
+
|
|
224
|
+
**Hosted CI failed.** Inspect the failed check with `gh pr checks` and `gh run view
|
|
225
|
+
--log-failed`. Fix and commit the source branch, then start a fresh synchronized
|
|
226
|
+
preflight run with the original intent. Do not push the repair until the new
|
|
227
|
+
review → docs → lint → test run reaches green. Push through the gate again, then
|
|
228
|
+
resume check monitoring with `gh`.
|
|
229
|
+
|
|
230
|
+
**Stale head (exit 3, `stale_run`).** The branch moved after review began, so
|
|
231
|
+
everything verified so far describes a tree that no longer exists. There is no partial
|
|
232
|
+
recovery: run `agentic-preflight abort --force`, then run the fresh `start` command from
|
|
233
|
+
the abort response. It preserves the original user intent.
|
|
234
|
+
|
|
235
|
+
**Diff too large (exit 2, `diff_too_large`).** The diff is never truncated, so
|
|
236
|
+
reviewing part of it is not an option. Look at `data.by_file`; if the bulk is generated
|
|
237
|
+
(lockfiles, vendored code, snapshots), add those globs to `[diff] exclude`. Raise
|
|
238
|
+
`[diff] max_bytes` only if the change genuinely is that large.
|
|
239
|
+
|
|
240
|
+
**No command configured (exit 2, `needs_command`).** For lint/test, pick from
|
|
241
|
+
`data.candidates` and re-invoke with `--command`; offer to write it into `[commands]` so
|
|
242
|
+
it is settled. For review, configure `[review] command` and retry `review run` — reviewer
|
|
243
|
+
commands are never detected. If lint/test `candidates` is empty, the repo simply has no
|
|
244
|
+
manifest detection understands (Unity,
|
|
245
|
+
Unreal, Xcode, most engine projects) — ask the user for the invocation instead of
|
|
246
|
+
hunting for a build file that does not exist.
|
|
247
|
+
|
|
248
|
+
Then treat its first green as unproven. Pass/fail is the exit code alone, so a command
|
|
249
|
+
that no-ops and exits 0 reads as a pass forever — and a false green retires the check
|
|
250
|
+
instead of costing a retry. Confirm the run actually did work (a test count, a results
|
|
251
|
+
file, a non-empty log) before believing it. The trap is usually a flag: `-quit` on a
|
|
252
|
+
Unity `-runTests` invocation exits 0 having run zero tests.
|
|
253
|
+
|
|
254
|
+
**Stage far slower than normal.** Check `[worktree] mode`. The default `in_place` mode
|
|
255
|
+
uses the checkout's existing environment and does not run an automatic dependency
|
|
256
|
+
install. The reusable runner retains ignored build caches and skips Node installation
|
|
257
|
+
while its fingerprint matches. Strict mode has no build cache and runs the frozen
|
|
258
|
+
install every time. Isolated modes do not share the source checkout's `node_modules`;
|
|
259
|
+
use `[worktree] setup_command` to prepare non-Node caches.
|
|
260
|
+
`copy_files` is for ignored files such as `.env`, not directories. Do not raise
|
|
261
|
+
`[stage] max_attempts` to paper over it.
|
|
262
|
+
|
|
263
|
+
**Copy refused (exit 3).** A `copy_files` entry is not gitignored. Do not work around
|
|
264
|
+
it — tell the user to gitignore and commit it first. This guard prevents a secret
|
|
265
|
+
being committed and pushed.
|
|
266
|
+
|
|
267
|
+
**Stage reports zero files to work on.** Check where `worktree_path` actually points.
|
|
268
|
+
If it is under `.git/`, tools that skip VCS directories cannot see it and will exit
|
|
269
|
+
non-zero on an empty set, which reads as a red stage. Jest is the common case:
|
|
270
|
+
`jest-haste-map` ORs a hardcoded `/.git/` ignore into its crawl with no config
|
|
271
|
+
override, so it finds zero test files no matter how healthy the code is. Symlinks do
|
|
272
|
+
not help — real paths are resolved. Confirm by running the same command in a worktree
|
|
273
|
+
outside `.git`; if that finds files, point the stage command at a script that checks
|
|
274
|
+
the commit under test out to a non-`.git` path and runs there. Never point an isolated
|
|
275
|
+
run at the source checkout: that reports on the wrong content and is a false green.
|
|
276
|
+
|
|
277
|
+
**Green in your shell, red under the gate.** Stages run non-interactively, so
|
|
278
|
+
version-manager shims (nvm, rbenv, pyenv, asdf) are absent and tools resolve to
|
|
279
|
+
system-wide installs. Compare the toolchain version *inside the stage* against the
|
|
280
|
+
project's declared range before you debug the code — a native module built for another
|
|
281
|
+
ABI fails as missing bindings, not as a version error. A repo with no `.nvmrc` (or
|
|
282
|
+
equivalent) has nothing pinning it, so this bites fresh clones and CI too, not just
|
|
283
|
+
the gate.
|
|
284
|
+
|
|
285
|
+
## Escalation etiquette
|
|
286
|
+
|
|
287
|
+
At the gate, show the user — in plain prose, not JSON:
|
|
288
|
+
|
|
289
|
+
- which **remote and branch** the push targets
|
|
290
|
+
- the **commit subjects** being pushed
|
|
291
|
+
- the deterministic **risk level and verdict**, including every matched
|
|
292
|
+
`human_review_path`
|
|
293
|
+
- anything you resolved as `ask_user`, and what you decided
|
|
294
|
+
- any finding you dismissed, and why
|
|
295
|
+
|
|
296
|
+
If the user explicitly asked in this task to push, publish, or create/open a pull
|
|
297
|
+
request, and this summary matches that request, display it as a progress update and
|
|
298
|
+
continue with the token. Do not ask them to confirm the same publication twice.
|
|
299
|
+
|
|
300
|
+
Otherwise ask, plainly: *"Ready to push this to `origin/feature-x`?"* Wait for a real
|
|
301
|
+
answer. A request only to implement or commit, or a generic "proceed" from a previous
|
|
302
|
+
step, is not consent for the push gate. Ask again if the summary reveals an unexpected
|
|
303
|
+
remote, branch, commit, or risk decision.
|
|
304
|
+
|
|
305
|
+
In `[pr] mode = "auto"`, the committed configuration is standing authorization for PR
|
|
306
|
+
creation. After the authorized push, `finish`, and `gc`, reuse an existing pull request
|
|
307
|
+
for the branch or call `gh pr create` automatically without asking about the PR.
|
|
308
|
+
|
|
309
|
+
In `[pr] mode = "manual"`, ask only whether to push. Afterward, never open a pull
|
|
310
|
+
request; construct the forge compare URL from the repository URL, base branch, and head
|
|
311
|
+
branch and give it to the user.
|
|
312
|
+
|
|
313
|
+
If risk returns `needs_human`, explain the merge restriction before pushing, then follow
|
|
314
|
+
the configured `[approval] mode`. An explicit request to create the pull request still
|
|
315
|
+
authorizes publication when the gate summary matches:
|
|
316
|
+
|
|
317
|
+
- `manual_merge`: the hosted check reports success only while auto-merge is disabled;
|
|
318
|
+
never merge or enable auto-merge, and tell the user that they must review and merge the
|
|
319
|
+
pull request manually.
|
|
320
|
+
- `environment`: wait for approval through the configured GitHub Environment before the
|
|
321
|
+
hosted approval check can pass.
|
|
322
|
+
- `peer_review`: require an eligible repository-associated person other than the author
|
|
323
|
+
to approve the exact current head.
|
|
324
|
+
|
|
325
|
+
Only an explicit `[gate] mode = "manual"` hands the push itself to a person.
|
|
326
|
+
|
|
327
|
+
For `ask_user` findings, present the trade-off and let them choose. Do not present a
|
|
328
|
+
decision you have already made as if it were a question.
|
|
329
|
+
|
|
330
|
+
Branch names are often poor human-facing PR titles, so offer a concise title that
|
|
331
|
+
describes the verified change before calling `gh pr create`.
|
|
332
|
+
|
|
333
|
+
When an automatic pull request is opened or an existing one is reused, report its URL
|
|
334
|
+
and tell the user exactly what a later cleanup request will do: verify that this PR was
|
|
335
|
+
merged, switch a clean source checkout to the base branch when necessary, remove only
|
|
336
|
+
this run's validation worktree and `ap/*` branch, delete the local PR branch and its
|
|
337
|
+
remote branch, and fast-forward the base branch.
|
|
338
|
+
|
|
339
|
+
## What to publish, and what it proves
|
|
340
|
+
|
|
341
|
+
Publish the **findings** in the PR body passed to `gh`: id, severity, path, and the
|
|
342
|
+
commit that resolved each. That is the part CI cannot reproduce — no test
|
|
343
|
+
suite tells a reviewer which judgment calls were made — and it stops a human
|
|
344
|
+
re-deriving what the gate already caught.
|
|
345
|
+
|
|
346
|
+
The commit's Git-note attestation already carries review coverage plus the local stage
|
|
347
|
+
commands, exit codes, and output hashes. Do not copy those into the PR body; if the repo
|
|
348
|
+
runs CI, point at the forge's execution for stronger, remote evidence.
|
|
349
|
+
|
|
350
|
+
Publish the gaps in the same breath: a bypassed hook, a stage that could not run, a
|
|
351
|
+
SHA with no green run. An attestation that can only report success is marketing, and a
|
|
352
|
+
partial record that reads as complete is worse than none.
|
|
353
|
+
|
|
354
|
+
State the limit plainly when you show it: this proves what the gate *reported*, including
|
|
355
|
+
that every delivered unit was cited or marked examined clean; it does not prove the agent
|
|
356
|
+
understood those units or that the review was good. The same diff reviewed twice can
|
|
357
|
+
yield different findings. It is an audit trail, not a quality proof, and it substitutes
|
|
358
|
+
for neither CI nor a human reviewer.
|
|
359
|
+
|
|
360
|
+
## Project uninstall trigger (`agentic-preflight:uninstall`)
|
|
361
|
+
|
|
362
|
+
When the user says `agentic-preflight:uninstall`, treat that exact phrase as approval
|
|
363
|
+
to remove agentic-preflight from the current repository without another confirmation.
|
|
364
|
+
Resolve the repository root with `git rev-parse --show-toplevel`; stop if the current
|
|
365
|
+
directory is not inside a Git repository.
|
|
366
|
+
|
|
367
|
+
Before changing anything, resolve the actual hook path with `git rev-parse --git-path
|
|
368
|
+
hooks/pre-push` and inspect both it and the repository status. Then:
|
|
369
|
+
|
|
370
|
+
- delete only the repository root's `.agentic-preflight.toml` file, if present;
|
|
371
|
+
- if the pre-push hook is the standalone generated hook marked `Installed by
|
|
372
|
+
agentic-preflight` and ending in `exec agentic-preflight hook-check`, delete it;
|
|
373
|
+
- if it is a shared or custom hook, remove only the clearly bounded
|
|
374
|
+
agentic-preflight invocation and its associated wrapper logic; and
|
|
375
|
+
- stop and report the exact hook path instead of modifying it if the
|
|
376
|
+
agentic-preflight portion cannot be separated confidently.
|
|
377
|
+
|
|
378
|
+
Do not remove other hook behavior, `.git/agentic-preflight` run history, or
|
|
379
|
+
`refs/notes/agentic-preflight`. Report every path removed, anything already absent,
|
|
380
|
+
and anything deliberately preserved.
|
|
381
|
+
|
|
382
|
+
## Cleanup after a merge
|
|
383
|
+
|
|
384
|
+
An explicit user request to clean up a merged pull request is the approval for the
|
|
385
|
+
whole run-scoped operation. Inspect the exact targets and verify through `gh` that the
|
|
386
|
+
PR is merged, then perform the cleanup in the same turn without asking again. Re-check
|
|
387
|
+
the merge and head/base branches immediately before mutation, switch a clean source
|
|
388
|
+
checkout to the base branch when necessary, remove only that run's validation worktree
|
|
389
|
+
and `ap/*` branch, delete the local PR source branch and the remote PR source branch,
|
|
390
|
+
then run `git pull --ff-only` so the base checkout contains the merged result.
|
|
391
|
+
|
|
392
|
+
Stop instead of deleting if the PR is not merged, the checkout is dirty, the PR head or
|
|
393
|
+
base differs from the disclosed cleanup scope, or a branch is checked out in an
|
|
394
|
+
unrelated worktree. Cleanup never performs a blanket `ap/*` deletion. Afterward, report
|
|
395
|
+
the exact targets removed and whether the remote branch was already absent.
|
|
396
|
+
|
|
397
|
+
For a pushed run with no PR, follow `finish` with `gc`. `gc` compares original fixes
|
|
398
|
+
with post-mergeback history using stable patch IDs. Only patch-equivalent fixes are
|
|
399
|
+
reclaimed automatically; anything unmerged is retained unless the user explicitly
|
|
400
|
+
chooses `--force`. Run directories remain because they hold durable stage logs.
|