@haystackeditor/cli 0.25.1 → 0.26.0
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.
- package/README.md +39 -455
- package/dist/capture/app-config.js +25 -1
- package/dist/commands/capture-brief.js +41 -32
- package/dist/commands/feedback.js +66 -0
- package/dist/commands/init-telemetry.js +53 -7
- package/dist/commands/init.js +7 -2
- package/dist/commands/lockfile-pin.js +307 -0
- package/dist/commands/verify.js +68 -13
- package/dist/index.js +27 -923
- package/dist/schema.js +4 -10
- package/dist/utils/haystack-api.js +0 -36
- package/package.json +1 -5
- package/schemas/feedback.v1.json +13 -0
- package/schemas/pre-verify.v2.json +240 -0
- package/schemas/verify-raw.v1.json +1132 -0
- package/schemas/verify.v2.json +655 -0
- package/dist/assets/hooks/agent-context/detect.ts +0 -316
- package/dist/assets/hooks/agent-context/format.ts +0 -100
- package/dist/assets/hooks/agent-context/index.ts +0 -41
- package/dist/assets/hooks/agent-context/parsers/claude.ts +0 -262
- package/dist/assets/hooks/agent-context/parsers/codex.ts +0 -416
- package/dist/assets/hooks/agent-context/parsers/gemini.ts +0 -155
- package/dist/assets/hooks/agent-context/parsers/opencode.ts +0 -174
- package/dist/assets/hooks/agent-context/tsconfig.json +0 -14
- package/dist/assets/hooks/agent-context/types.ts +0 -58
- package/dist/assets/hooks/llm-rules-template.md +0 -59
- package/dist/assets/hooks/package-lock.json +0 -598
- package/dist/assets/hooks/package.json +0 -12
- package/dist/assets/hooks/scripts/commit-msg.sh +0 -5
- package/dist/assets/hooks/scripts/post-commit.sh +0 -5
- package/dist/assets/hooks/scripts/pre-commit.sh +0 -175
- package/dist/assets/hooks/scripts/pre-push.sh +0 -25
- package/dist/assets/hooks/scripts/prepare-commit-msg.sh +0 -5
- package/dist/assets/hooks/truncation-checker/ast-analyzer.ts +0 -528
- package/dist/assets/hooks/truncation-checker/index.ts +0 -595
- package/dist/assets/hooks/truncation-checker/tsconfig.json +0 -13
- package/dist/assets/skills/map-cloud-verifier-universe/SKILL.md +0 -2051
- package/dist/assets/skills/map-cloud-verifier-universe/agents/openai.yaml +0 -4
- package/dist/assets/skills/map-cloud-verifier-universe/references/output-contract.md +0 -3411
- package/dist/assets/skills/map-your-system.md +0 -143
- package/dist/assets/skills/submit.md +0 -200
- package/dist/commands/ask.js +0 -20
- package/dist/commands/cloud-verifier-behaviors.js +0 -218
- package/dist/commands/cloud-verifier-data-store-census.js +0 -539
- package/dist/commands/cloud-verifier-data-store-drift.js +0 -158
- package/dist/commands/cloud-verifier-identity-census.js +0 -4060
- package/dist/commands/cloud-verifier-materialization.js +0 -704
- package/dist/commands/cloud-verifier-pascal-selector-census.js +0 -1382
- package/dist/commands/cloud-verifier-python-manifest-selector-census.js +0 -2015
- package/dist/commands/cloud-verifier-specialized-operational-census.js +0 -11432
- package/dist/commands/cloud-verifier-universe.js +0 -10178
- package/dist/commands/config.js +0 -549
- package/dist/commands/design-verify.js +0 -311
- package/dist/commands/dismiss.js +0 -159
- package/dist/commands/hooks.js +0 -226
- package/dist/commands/inbox.js +0 -137
- package/dist/commands/mcp.js +0 -201
- package/dist/commands/policy.js +0 -371
- package/dist/commands/pr-status.js +0 -207
- package/dist/commands/pr.js +0 -105
- package/dist/commands/prepare-universe-review.js +0 -1092
- package/dist/commands/production-source-deny-policy.js +0 -100
- package/dist/commands/request-review.js +0 -74
- package/dist/commands/review.js +0 -191
- package/dist/commands/rules.js +0 -98
- package/dist/commands/scaffold-provisional-universe.js +0 -806
- package/dist/commands/setup.js +0 -1170
- package/dist/commands/skills.js +0 -447
- package/dist/commands/submit.js +0 -745
- package/dist/commands/system-map.js +0 -228
- package/dist/commands/triage.js +0 -598
- package/dist/commands/webhooks.js +0 -241
- package/dist/states.js +0 -46
- package/dist/tools/detect.js +0 -832
- package/dist/triage/astra.js +0 -202
- package/dist/triage/prompts.js +0 -188
- package/dist/triage/runner.js +0 -200
- package/dist/triage/types.js +0 -7
- package/dist/utils/action-output.js +0 -26
- package/dist/utils/analysis-api.js +0 -416
- package/dist/utils/design-verifier-api.js +0 -294
- package/dist/utils/design-verifier-history.js +0 -79
- package/dist/utils/design-verifier-result.js +0 -424
- package/dist/utils/github-api.js +0 -324
- package/dist/utils/pending-state.js +0 -86
- package/dist/utils/pr-ref.js +0 -56
- package/dist/utils/prompter.js +0 -328
- package/schemas/action.v1.json +0 -22
- package/schemas/ask.v1.json +0 -40
- package/schemas/inbox.v1.json +0 -27
- package/schemas/pr-status.v1.json +0 -61
- package/schemas/pr.v1.json +0 -97
- package/schemas/pr.v3.json +0 -45
- package/schemas/setup.v1.json +0 -75
- package/schemas/submit.v1.json +0 -90
- package/schemas/triage.v1.json +0 -103
- package/schemas/triage.v2.json +0 -64
package/README.md
CHANGED
|
@@ -37,49 +37,24 @@ or `HAYSTACK_TELEMETRY_DISABLED=1` to turn this telemetry off.
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## For
|
|
41
|
-
|
|
42
|
-
Most
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
command
|
|
56
|
-
|
|
57
|
-
`
|
|
58
|
-
- **PR refs are uniform.** Every command taking a PR accepts `123`, `#123`,
|
|
59
|
-
`owner/repo#123`, or a GitHub PR URL. Bare numbers infer the repo from the
|
|
60
|
-
`origin` remote.
|
|
61
|
-
- **Exit codes**: 0 = the requested action happened (a created PR with findings
|
|
62
|
-
is still 0 — read the verdict from the JSON); 1 = it did not. Commands never
|
|
63
|
-
print an error and exit 0.
|
|
64
|
-
- **Waiting is bounded and skippable.** `submit` waits up to 10 min for
|
|
65
|
-
analysis, `triage` polls up to 5 min, `review` up to 25 min; every waiting
|
|
66
|
-
command takes `--no-wait`. Non-terminal outcomes include a `next` field with
|
|
67
|
-
the follow-up command (usually `haystack triage <ref> --json`).
|
|
68
|
-
- **"review" disambiguation**: `haystack review` re-runs the *machine*
|
|
69
|
-
analysis. For *human* review use `haystack submit --review` or
|
|
70
|
-
`haystack request-review`.
|
|
71
|
-
|
|
72
|
-
**The agent workflow for submitting:**
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
haystack submit --json # emits the submit payload incl. ref + analysis verdict
|
|
76
|
-
haystack triage <ref> --json # poll findings later / after --no-wait
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
**`haystack mcp`** runs a stdio MCP server exposing the same payloads as tools:
|
|
80
|
-
`inbox_list`, `pr_get`, `pr_status`, `triage_get`, `ask_haystack`,
|
|
81
|
-
`dismiss`, `mark_reviewed`, `undismiss`, `request_review`, `trigger_review`,
|
|
82
|
-
and `schema`.
|
|
40
|
+
## For coding agents
|
|
41
|
+
|
|
42
|
+
Most users of this CLI are coding agents. What to know:
|
|
43
|
+
|
|
44
|
+
- **After a change, run `haystack verify`** inside the checkout. Nothing needs
|
|
45
|
+
to be committed or pushed. Say what you were asked to do with
|
|
46
|
+
`--intent "<the task, in the user's words>"`, and what to try with
|
|
47
|
+
`--idea "<as you would tell a tester>"` (repeat it for more).
|
|
48
|
+
- **First time in a repository**, `haystack init --yes` sets it up and starts
|
|
49
|
+
onboarding the app. `haystack verify onboarding` shows where onboarding is.
|
|
50
|
+
When onboarding asks a question, answer it with
|
|
51
|
+
`haystack verify answer <question-id> <choice>`.
|
|
52
|
+
- **`--json` means pure stdout.** stdout carries exactly one JSON document and
|
|
53
|
+
everything else goes to stderr. A failure still prints the error envelope
|
|
54
|
+
(`haystack schema error`) and exits 1. `haystack schema <name>` prints any
|
|
55
|
+
command's contract.
|
|
56
|
+
- **When Haystack gets in your way**, tell us in a sentence and keep going:
|
|
57
|
+
`haystack feedback "<what happened>"`. The team sees it at once.
|
|
83
58
|
|
|
84
59
|
**`haystack verify`** shows the product blast radius of your current change:
|
|
85
60
|
where it shows up in the running app, and what broke. Inside a git checkout
|
|
@@ -126,45 +101,25 @@ is no time limit, and Ctrl-C stops waiting, never the crawl. It then prints:
|
|
|
126
101
|
|
|
127
102
|
`--no-wait` prints the crawl's current state and returns. `--account <login>`
|
|
128
103
|
picks a saved account, and `--repo owner/repo` names the repository when
|
|
129
|
-
`origin` does not. `--json` prints
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
`haystack schema verify`
|
|
134
|
-
|
|
104
|
+
`origin` does not. `--json` prints the same report as one document: the
|
|
105
|
+
headline, the findings (bugs first, each with its steps), where the change showed
|
|
106
|
+
up, what became of each idea, and what never ran (`haystack schema verify`).
|
|
107
|
+
`--raw` prints the crawl's whole record as the service returns it, for scripts;
|
|
108
|
+
it is large (`haystack schema verify-raw`). Exit codes: 0 when the crawl
|
|
109
|
+
answered or finished (the bugs
|
|
135
110
|
it found are in the output) or is still running under `--no-wait`; 2 when it ended
|
|
136
111
|
without finishing (stopped early, or cancelled because a newer stop in the
|
|
137
112
|
repository replaced it) or the machines it used could not be proven shut down;
|
|
138
113
|
1 when the command failed or no crawl could be started.
|
|
139
114
|
|
|
140
|
-
**The stop hook.** `haystack
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
the crawl it started.
|
|
149
|
-
|
|
150
|
-
The hosted fleet run of exact pushed commits stays available:
|
|
151
|
-
|
|
152
|
-
```bash
|
|
153
|
-
haystack verify hosted start owner/repo --base <sha> --head <sha> --json
|
|
154
|
-
haystack verify hosted status cv_<48-lowercase-hex-characters> --wait --json
|
|
155
|
-
haystack verify history owner/repo --limit 20
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
Intent is optional there: `--intent-file <path>` accepts JSON with exactly
|
|
159
|
-
`problem`, `goal`, and `intended_outcomes`. It waits up to 35 minutes by
|
|
160
|
-
default; pass `--no-wait` to return after the fleet run is queued. Repeating the
|
|
161
|
-
same repository, commits, and intent reuses the same run; choose a new
|
|
162
|
-
`--idempotency-key` when a fresh execution is intentional. A fresh run on the
|
|
163
|
-
same base reuses the repository's onboarding: phases that finished are not
|
|
164
|
-
redone, and a phase that stopped terminally starts again once the fleet runs a
|
|
165
|
-
different engine release (on the same release it stays stopped). A wait that expires
|
|
166
|
-
prints `timed_out: true` and `next_command`, then exits 2. Use the returned
|
|
167
|
-
account-bound `next_command` verbatim on machines with multiple saved accounts.
|
|
115
|
+
**The stop hook.** `haystack init` installs a Claude Code Stop hook that runs
|
|
116
|
+
`haystack verify precompute --hook` whenever an agent turn stops. It captures
|
|
117
|
+
the checkout within five seconds and hands the request to a detached sender;
|
|
118
|
+
the service then starts the change's crawl in the background, so
|
|
119
|
+
`haystack verify` usually finds the crawl already running or finished. A newer
|
|
120
|
+
stop in the same repository replaces an older crawl that has not finished.
|
|
121
|
+
`haystack verify precompute` (without `--hook`) submits the same capture in the
|
|
122
|
+
foreground and prints one line for the crawl it started.
|
|
168
123
|
|
|
169
124
|
Retained fleet cases remain available through their exact case IDs:
|
|
170
125
|
|
|
@@ -173,67 +128,10 @@ haystack verify cases <run-id> --repo owner/repo
|
|
|
173
128
|
haystack verify explore <run-id> <case-id> --repo owner/repo
|
|
174
129
|
```
|
|
175
130
|
|
|
176
|
-
Agents can use the same lifecycle with `haystack verify hosted mcp --account
|
|
177
|
-
<login>`. Its tools are `verify_start`, `verify_status`, and `verify_wait`.
|
|
178
|
-
|
|
179
|
-
To repeat independent fleet runs for one exact commit pair:
|
|
180
|
-
|
|
181
|
-
```bash
|
|
182
|
-
haystack verify hosted reproducibility owner/repo \
|
|
183
|
-
--base <40-character-commit-sha> \
|
|
184
|
-
--head <40-character-commit-sha> \
|
|
185
|
-
--runs 3 --json
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
The report includes each run's fleet receipt. Each ordinal has a distinct
|
|
189
|
-
idempotency key derived from the printed series key, repository, commits, and
|
|
190
|
-
intent; `--series-key <key>` resumes the same series. Independent plans do not
|
|
191
|
-
share an execution identity, so reproducibility remains unestablished and the
|
|
192
|
-
command exits 2. A timeout stops the series and includes the active run's resume
|
|
193
|
-
command.
|
|
194
|
-
|
|
195
|
-
**`haystack case-batch`** runs an already-generated product-fuzzing case
|
|
196
|
-
batch on the hosted coordinator. The laptop only submits and polls: it holds no
|
|
197
|
-
fleet credential, creates no VM, and kills nothing.
|
|
198
|
-
|
|
199
|
-
```bash
|
|
200
|
-
haystack case-batch submit --repository owner/repo \
|
|
201
|
-
--base <40-character-commit-sha> --head <40-character-commit-sha> \
|
|
202
|
-
--cases cases.json --combinations space.json --max-concurrent 200 --json
|
|
203
|
-
haystack case-batch status <run-id> --repository owner/repo --watch --json
|
|
204
|
-
haystack case-batch cancel <run-id> --repository owner/repo
|
|
205
|
-
haystack case-batch bundle <run-id> --repository owner/repo --out ./bundle
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
Cases and the combination space travel inline and the whole request is bounded
|
|
209
|
-
at 8 MiB; no source patch is sent unless `--source-patch <file>` names the
|
|
210
|
-
precompute-captured `{ cacheKey, patchSha256, patchGzBase64 }` record.
|
|
211
|
-
`status` follows the case cursor to the end of the list and prints one row per
|
|
212
|
-
case — id, position, status, unknown reason, wall time and whether cleanup was
|
|
213
|
-
proven — including when the batch ends `incomplete`, which exits 2 with a
|
|
214
|
-
summary rather than a single failure. `haystack schema case-batch` prints the
|
|
215
|
-
`--json` schema.
|
|
216
|
-
|
|
217
|
-
**`haystack setup --json`** speaks NDJSON: events (`question`, `permission`,
|
|
218
|
-
`progress`, `result`) on stdout, replies on stdin keyed by
|
|
219
|
-
`requestID`/`permissionID`. `haystack schema setup` documents the full
|
|
220
|
-
protocol, including the reply shapes. Pre-supply answers with `--repo`,
|
|
221
|
-
`--yes`, `--no-auto-merge`, or `--answers <file>` to skip questions. Note:
|
|
222
|
-
`--yes` enables auto-merge (the wizard default) — pass `--no-auto-merge` to
|
|
223
|
-
opt out.
|
|
224
|
-
|
|
225
131
|
---
|
|
226
132
|
|
|
227
133
|
## CLI Commands
|
|
228
134
|
|
|
229
|
-
### `haystack setup`
|
|
230
|
-
|
|
231
|
-
Interactive onboarding wizard — scan your repos and generate `.haystack.json`:
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
haystack setup
|
|
235
|
-
```
|
|
236
|
-
|
|
237
135
|
### `haystack init`
|
|
238
136
|
|
|
239
137
|
Sets the repository up for `haystack verify` and starts onboarding the app. It
|
|
@@ -278,311 +176,18 @@ without waiting, shows them to you, then runs `haystack login` to finish.
|
|
|
278
176
|
haystack logout
|
|
279
177
|
```
|
|
280
178
|
|
|
281
|
-
### `haystack
|
|
282
|
-
|
|
283
|
-
Create a PR from current changes. Runs pre-PR triage (code review, rules validation), pushes your branch, and opens the PR.
|
|
284
|
-
|
|
285
|
-
```bash
|
|
286
|
-
haystack submit # Triage -> create PR -> wait for analysis
|
|
287
|
-
haystack submit --json # Agent mode: one JSON doc on stdout, progress on stderr
|
|
288
|
-
haystack submit --title "Fix auth" # Custom PR title
|
|
289
|
-
haystack submit --draft # Create as draft PR
|
|
290
|
-
haystack submit --force # Skip triage checks
|
|
291
|
-
haystack submit --no-wait # Don't wait for analysis results
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
**Pre-PR triage**: two checkers run in parallel, each one structured call to
|
|
295
|
-
`gpt-6-astra` over the OpenAI Responses API at reasoning effort `xhigh`.
|
|
296
|
-
The key comes from `OPENAI_API_KEY`
|
|
297
|
-
if set, else from the SSM SecureString `/haystack/secrets/shared/prod/OPENAI_API_KEY`
|
|
298
|
-
(us-west-2) through the default AWS credential chain (e.g. `AWS_PROFILE=prod`).
|
|
299
|
-
With neither, each checker reports `no OpenAI key (...)` and submit continues.
|
|
300
|
-
|
|
301
|
-
- **code-review** reads `git diff -U10 origin/<base>...HEAD` and reports objective bugs.
|
|
302
|
-
- **rules-validator** runs when `.haystack/pr-rules.yml` or an agent
|
|
303
|
-
instruction file (`CLAUDE.md`, `AGENTS.md`, `COPILOT.md`, `.cursorrules`,
|
|
304
|
-
`.github/copilot-instructions.md`) exists, and checks the diff against them.
|
|
305
|
-
|
|
306
|
-
Each finding carries `file`, `line`, `severity` (`error`/`warning`/`info`),
|
|
307
|
-
`category`, a one-sentence summary and a concrete failure scenario; results
|
|
308
|
-
are saved to `.haystack/triage/<checker>.json`. A finding with severity
|
|
309
|
-
`error` stops the submit (`--force` skips triage). A checker that cannot run
|
|
310
|
-
(missing key, API error, stalled stream) prints `code review failed: <error>`
|
|
311
|
-
and the submit continues. The reviewer sees only the diff, not the rest of the
|
|
312
|
-
repository. `--triage-timeout <sec>` (or `.haystack.json` `triage.timeoutMs`)
|
|
313
|
-
aborts a checker whose response stream has been silent that long (default
|
|
314
|
-
300s); there is no total-time cap.
|
|
315
|
-
|
|
316
|
-
The `--json` payload (`haystack schema submit`) reports the PR ref, the
|
|
317
|
-
resolved title/body and where each came from, auto-merge/auto-fix state with
|
|
318
|
-
its source (flag vs `.haystack.json`), and the analysis outcome in the shared
|
|
319
|
-
verdict vocabulary.
|
|
320
|
-
|
|
321
|
-
**Review routing**: By default, PRs go to the auto-merge queue -- if analysis passes, the PR is merged automatically. Use `--review` to route it for human review instead:
|
|
322
|
-
|
|
323
|
-
```bash
|
|
324
|
-
haystack submit --review # Needs review (goes to assignment queue)
|
|
325
|
-
haystack submit --review octocat # Request review from a specific teammate
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
When `--review` is used without a username, the PR is labeled `haystack:needs-review` and appears in your team's assignment queue. When a username is provided, that person is also requested as a reviewer on GitHub.
|
|
329
|
-
|
|
330
|
-
### `haystack triage`
|
|
331
|
-
|
|
332
|
-
View Haystack analysis results for any PR. Shows the same data as the Haystack web feed: rating, verdict, structured findings with details, verified bugs, human review reasons, and agent fix prompts.
|
|
333
|
-
|
|
334
|
-
```bash
|
|
335
|
-
haystack triage # Last submitted PR
|
|
336
|
-
haystack triage 42 # Current repo, PR #42
|
|
337
|
-
haystack triage owner/repo#99 # Fully qualified
|
|
338
|
-
haystack triage https://github.com/o/r/pull/1 # From GitHub URL
|
|
339
|
-
haystack triage 42 --json # Machine-readable JSON output
|
|
340
|
-
haystack triage 42 --no-wait # Don't wait if analysis is pending
|
|
341
|
-
haystack triage --hook # Minimal one-liner (for session hooks)
|
|
342
|
-
haystack triage --clear # Clear pending submit state
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
When called without a PR identifier, checks the last PR submitted via `haystack submit`. The `--hook` flag produces a single-line summary with the Haystack rating, designed for session-start hooks.
|
|
346
|
-
|
|
347
|
-
The `--json` output includes every finding and its customer-facing `suggested_fix` when available.
|
|
348
|
-
|
|
349
|
-
### `haystack inbox list`
|
|
350
|
-
|
|
351
|
-
List PRs in your Haystack inbox with the reason each PR is present and the next action:
|
|
352
|
-
|
|
353
|
-
```bash
|
|
354
|
-
haystack inbox list
|
|
355
|
-
haystack inbox list --json
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### `haystack pr get`
|
|
359
|
-
|
|
360
|
-
Get the useful state of one PR: triage and minimal merge blockers:
|
|
361
|
-
|
|
362
|
-
```bash
|
|
363
|
-
haystack pr get 42
|
|
364
|
-
haystack pr get owner/repo#42 --json
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
### `haystack ask`
|
|
368
|
-
|
|
369
|
-
Ask Haystack Chat about a PR. Machine output contains the answer and every customer-facing source Chat consulted:
|
|
370
|
-
|
|
371
|
-
```bash
|
|
372
|
-
haystack ask 42 "Why is this finding legitimate?"
|
|
373
|
-
haystack ask owner/repo#42 "Show the implementation" --json
|
|
374
|
-
haystack ask owner/repo#42 "What about its callers?" --session <session-id> --json
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
Chat may search the complete authorized repository when the changed files are insufficient. Search results and fetched source are included in `evidence`.
|
|
378
|
-
|
|
379
|
-
### `haystack review`
|
|
380
|
-
|
|
381
|
-
Trigger a fresh *machine* analysis of a PR's current head (Haystack analyzes once at PR open; later pushes only get a resolution check). For requesting *human* review, use `haystack request-review`.
|
|
382
|
-
|
|
383
|
-
```bash
|
|
384
|
-
haystack review 42 # Re-analyze and wait for the result
|
|
385
|
-
haystack review 42 --no-wait # Trigger and exit
|
|
386
|
-
haystack review 42 --json # Machine-readable outcome (schema: action)
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
### `haystack request-review`
|
|
179
|
+
### `haystack feedback`
|
|
390
180
|
|
|
391
|
-
|
|
181
|
+
Tell the Haystack team something went wrong, confused you, or is missing. It
|
|
182
|
+
lands with the team at once, with the CLI version, your platform and the
|
|
183
|
+
checkout's repository.
|
|
392
184
|
|
|
393
185
|
```bash
|
|
394
|
-
haystack
|
|
395
|
-
haystack
|
|
396
|
-
haystack
|
|
186
|
+
haystack feedback "verify said the app never started, but it was up on :3000"
|
|
187
|
+
haystack feedback --run cv_<id> "the bug it reported is the intended change"
|
|
188
|
+
echo "longer report" | haystack feedback -
|
|
397
189
|
```
|
|
398
190
|
|
|
399
|
-
### `haystack dismiss`
|
|
400
|
-
|
|
401
|
-
Dismiss analysis findings for a PR, moving it from "Issues Found" to "Good to Merge" in the feed. The override is tied to the PR's current HEAD commit.
|
|
402
|
-
|
|
403
|
-
```bash
|
|
404
|
-
haystack dismiss 42 # Dismiss findings for PR #42
|
|
405
|
-
haystack dismiss acme/widgets#99 # Dismiss for specific repo
|
|
406
|
-
haystack dismiss 42 --json # Machine-readable (schema: action)
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
### `haystack undismiss`
|
|
410
|
-
|
|
411
|
-
Clear all overrides (dismissed findings and/or review-not-needed) for a PR, returning it to its original feed bucket.
|
|
412
|
-
|
|
413
|
-
```bash
|
|
414
|
-
haystack undismiss 42 # Undo overrides for PR #42
|
|
415
|
-
haystack undismiss acme/widgets#99 # Undo for specific repo
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
### `haystack mark-reviewed`
|
|
419
|
-
|
|
420
|
-
Mark human review as not needed for a PR, moving it from "Needs Review" to "Good to Merge" in the feed. The override is tied to the PR's current HEAD commit.
|
|
421
|
-
|
|
422
|
-
```bash
|
|
423
|
-
haystack mark-reviewed 42 # Mark review not needed for PR #42
|
|
424
|
-
haystack mark-reviewed acme/widgets#99 # Mark for specific repo
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
### `haystack pr-status`
|
|
428
|
-
|
|
429
|
-
Show what bucket a PR is in within the Haystack pipeline (analyzing, good-to-merge, issues, needs-assignment, etc.):
|
|
430
|
-
|
|
431
|
-
```bash
|
|
432
|
-
haystack pr-status 42 # Current repo, PR #42
|
|
433
|
-
haystack pr-status acme/widgets#99 # Specific repo
|
|
434
|
-
haystack pr-status https://github.com/o/r/pull/1 # From URL
|
|
435
|
-
haystack pr-status 42 --json # Machine-readable output
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
### `haystack config`
|
|
439
|
-
|
|
440
|
-
Manage user preferences:
|
|
441
|
-
|
|
442
|
-
```bash
|
|
443
|
-
# Agentic tool selection
|
|
444
|
-
haystack config agentic-tool # Show current setting
|
|
445
|
-
haystack config agentic-tool opencode # Use Haystack billing (default)
|
|
446
|
-
haystack config agentic-tool claude-code # Use your Claude Max subscription
|
|
447
|
-
haystack config agentic-tool codex # Use your ChatGPT subscription
|
|
448
|
-
|
|
449
|
-
# Auto-merge for safe PRs
|
|
450
|
-
haystack config auto-merge # Show current status
|
|
451
|
-
haystack config auto-merge on # Enable auto-merge
|
|
452
|
-
haystack config auto-merge off # Disable auto-merge
|
|
453
|
-
|
|
454
|
-
# AI reviewer wait list (merge queue waits for ALL configured bots before merging)
|
|
455
|
-
haystack config wait-for-reviewers # Show status
|
|
456
|
-
haystack config wait-for-reviewers add cursor # Wait for Cursor BugBot
|
|
457
|
-
haystack config wait-for-reviewers add cursor coderabbit # Add multiple
|
|
458
|
-
haystack config wait-for-reviewers remove cursor # Stop waiting
|
|
459
|
-
haystack config wait-for-reviewers clear # Wait for none
|
|
460
|
-
# Also accepts raw GitHub bot usernames (must end in [bot]):
|
|
461
|
-
haystack config wait-for-reviewers add cursor-bugbot[bot]
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
Reviewer names are validated: anything that is neither a known friendly name
|
|
465
|
-
nor a `...[bot]` username is rejected (a stored typo would make the merge
|
|
466
|
-
queue wait forever for a bot that can't post).
|
|
467
|
-
|
|
468
|
-
### `haystack skills`
|
|
469
|
-
|
|
470
|
-
Manage AI skills for your coding CLI:
|
|
471
|
-
|
|
472
|
-
```bash
|
|
473
|
-
haystack skills install # Install portable .agents/skills
|
|
474
|
-
haystack skills install --cli codex # Portable install for Codex
|
|
475
|
-
haystack skills install --cli claude # Also install Claude command shims
|
|
476
|
-
haystack skills install --cli manual # Install portable skills and print their location
|
|
477
|
-
haystack skills list # List available skills
|
|
478
|
-
haystack skills scaffold-provisional-universe --input /tmp/facts.json # Write a missing-authority receipt
|
|
479
|
-
haystack skills prepare-universe-review --json # Build a filtered reviewer source snapshot
|
|
480
|
-
haystack skills validate-universe --json # Parse and cross-check universe artifacts
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
Installed skills include `/map-cloud-verifier-universe`, which asks the
|
|
484
|
-
customer's coding agent to map the application's production dependencies and
|
|
485
|
-
uses a read-only reviewer subagent to check the map before Cloud Verifier
|
|
486
|
-
onboarding. It first checks for an authoritative hosted-deployment source; if
|
|
487
|
-
that source is private, it produces a provisional map and one bounded request
|
|
488
|
-
for a summary from the customer's local replicator or catalog. It never asks
|
|
489
|
-
for production credentials or direct Haystack access to production.
|
|
490
|
-
|
|
491
|
-
Start a customer-owned Cloud Verifier adapter before a universe map exists, from
|
|
492
|
-
only the three selections the user actually makes — which application, which
|
|
493
|
-
environment, and which approved replica destination:
|
|
494
|
-
|
|
495
|
-
```bash
|
|
496
|
-
haystack cloud-verifier connector bootstrap \
|
|
497
|
-
--application-id Checkout \
|
|
498
|
-
--environment-id production \
|
|
499
|
-
--destination-policy-file ./replica-destination-policy.json
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
Application and environment accept a plain name and are normalized to stable IDs
|
|
503
|
-
(`application:checkout`, `environment:production`); pass an explicit
|
|
504
|
-
`application:<id>` when you want to choose it yourself. The destination is named
|
|
505
|
-
by its approved policy document, whose SHA-256 the command computes and reports.
|
|
506
|
-
Pass `--destination-policy-sha256 <64-hex>` instead only if your tooling already
|
|
507
|
-
holds the digest. Exactly one of the two is required.
|
|
508
|
-
|
|
509
|
-
The scaffold stays blocked until the customer's coding agent completes bounded
|
|
510
|
-
local discovery and provider-profile conformance. It includes the lifecycle and
|
|
511
|
-
binding executable, encrypted connector-owned vault contract, cold golden
|
|
512
|
-
refresh scheduler, and a setup/update-only reviewer-subagent request. No
|
|
513
|
-
reviewer runs on ordinary verification requests or routine golden refreshes.
|
|
514
|
-
|
|
515
|
-
### `haystack hooks`
|
|
516
|
-
|
|
517
|
-
Manage git hooks for AI agent quality checks:
|
|
518
|
-
|
|
519
|
-
```bash
|
|
520
|
-
# Install hooks
|
|
521
|
-
haystack hooks install
|
|
522
|
-
haystack hooks install --force # Overwrite existing hooks
|
|
523
|
-
|
|
524
|
-
# Status
|
|
525
|
-
haystack hooks status # Check installation status
|
|
526
|
-
|
|
527
|
-
# Session hooks (triage on CLI start; Claude Code's Stop hook starts a crawl,
|
|
528
|
-
# see `haystack verify`)
|
|
529
|
-
haystack hooks install-session # Auto-detect CLIs
|
|
530
|
-
haystack hooks install-session --cli claude # Claude Code only
|
|
531
|
-
haystack hooks install-session --cli all # All detected CLIs
|
|
532
|
-
haystack hooks session-status # Check session hook status
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
### `haystack case-batch`
|
|
536
|
-
|
|
537
|
-
Submit and poll product-fuzzing case batches on the hosted coordinator
|
|
538
|
-
(`CASE-BATCH-V1`):
|
|
539
|
-
|
|
540
|
-
```bash
|
|
541
|
-
# Submit an ordered batch against one frozen world pair
|
|
542
|
-
haystack case-batch submit --repository owner/repo \
|
|
543
|
-
--base <sha> --head <sha> \
|
|
544
|
-
--cases cases.json --combinations space.json \
|
|
545
|
-
--base-world frz_<16-hex> --head-world frz_<16-hex> \
|
|
546
|
-
--max-concurrent 200 --per-case-wall-ms 15000 --total-budget-ms 600000 --json
|
|
547
|
-
|
|
548
|
-
# Read every per-case outcome; --watch polls until terminal or --max-wall
|
|
549
|
-
haystack case-batch status <run-id> --repository owner/repo --watch --json
|
|
550
|
-
|
|
551
|
-
# Request cancellation (a claimed batch drains until its owner proves cleanup)
|
|
552
|
-
haystack case-batch cancel <run-id> --repository owner/repo
|
|
553
|
-
|
|
554
|
-
# Download the replay bundle, verifying every artifact digest
|
|
555
|
-
haystack case-batch bundle <run-id> --repository owner/repo --out ./bundle
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
`bundle` requires the service's sealed SHA-256 for `manifest.json` (served as
|
|
559
|
-
its ETag), because the manifest is the one artifact with no parent digest to
|
|
560
|
-
check it against; without it the command fails and writes nothing. Every other
|
|
561
|
-
artifact is checked against the sha256 and byte length the manifest declares
|
|
562
|
-
for it.
|
|
563
|
-
|
|
564
|
-
Knobs and what turning them does:
|
|
565
|
-
|
|
566
|
-
| Flag | Default | Effect |
|
|
567
|
-
|------|---------|--------|
|
|
568
|
-
| `--max-concurrent <n>` | the case count, capped at 500 | Ceiling only. Admitted concurrency is the smaller of it and the fleet's free capacity; the run's receipt reports both. |
|
|
569
|
-
| `--per-case-wall-ms <ms>` | 120000 | A case that overruns is killed and recorded `UNKNOWN`/`wall-budget`, never dropped. Above the MVP's measured 103.8 s maximum, so it does not kill cases running at today's cost. |
|
|
570
|
-
| `--total-budget-ms <ms>` | 1800000 (the contract ceiling) | Bounds launches from the first launch. Cases already launched run to their own wall budget. |
|
|
571
|
-
| `--warm-settle-ms <ms>` | absent (0) | Each arm adopts only a warm clone that has been ready at least this long, 0 to the per-case wall. A clone adopted right after its restore attaches cold (quiet fleet: connectMs 5.8 s at 0 vs 1.1 s after 3.5-6 s of idle); each second of settle can delay a case's first create by up to a second. |
|
|
572
|
-
| `--idempotency-key <key>` | derived from the whole submission | An exact retry returns the original run; a new key is a new execution. |
|
|
573
|
-
| `--interval <seconds>` | 10 | Polling interval while `--watch` is set. |
|
|
574
|
-
| `--max-wall <minutes>` | 45 | Total polling wall. Hitting it prints the snapshot, says `timed_out`, and exits 2. |
|
|
575
|
-
|
|
576
|
-
`status` exits 0 for a `completed` batch with cleanup proven, and 2 for
|
|
577
|
-
`incomplete`, `cancelled`, unproven cleanup, or a wait that hits `--max-wall`.
|
|
578
|
-
Either way every per-case row is printed. A `--json` row from a v4 batch also
|
|
579
|
-
carries `node_ids: { base1, head }` (the node each arm's VM was placed on) and
|
|
580
|
-
`failure: { source, arm, error_class, error_code, node_id }` (the typed fact
|
|
581
|
-
behind an `UNKNOWN` that is not an arrival or wall outcome, and behind an
|
|
582
|
-
`arrival-failed` whose two arms stalled on the same step, `same-step-stall`); each
|
|
583
|
-
is `null` when the outcome has none. A case in `--cases` may carry `repeatIndex` (1-16), which
|
|
584
|
-
must be part of its `contentDigest`, to run as a repeat next to its original.
|
|
585
|
-
|
|
586
191
|
### `haystack db profile`
|
|
587
192
|
|
|
588
193
|
Describe your production Postgres database so Haystack can build a full-size
|
|
@@ -722,27 +327,6 @@ whole profile succeeds. On a primary, dead-row shares come from
|
|
|
722
327
|
`pg_stat_user_tables`; a table with rows but no counts there (statistics reset)
|
|
723
328
|
stops the run and asks for `ANALYZE` on that table.
|
|
724
329
|
|
|
725
|
-
### `haystack policy`
|
|
726
|
-
|
|
727
|
-
Manage review policies (`.haystack/review-policy.md`):
|
|
728
|
-
|
|
729
|
-
```bash
|
|
730
|
-
# List and inspect
|
|
731
|
-
haystack policy list # List all policies
|
|
732
|
-
|
|
733
|
-
# Add policies
|
|
734
|
-
haystack policy add # Interactive add
|
|
735
|
-
haystack policy add "Database changes" # Start with name
|
|
736
|
-
haystack policy add-instruction "Never flag weak test coverage as needing review"
|
|
737
|
-
|
|
738
|
-
# Remove policies
|
|
739
|
-
haystack policy remove "Database changes"
|
|
740
|
-
|
|
741
|
-
# Initialize with defaults
|
|
742
|
-
haystack policy init # Create with sensible defaults
|
|
743
|
-
haystack policy init --force # Overwrite existing
|
|
744
|
-
```
|
|
745
|
-
|
|
746
330
|
---
|
|
747
331
|
|
|
748
332
|
## How It Works
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
* publish the directories (relative to the app) the build step publishes the manifest into, so haystack-capture-step,
|
|
13
13
|
* which loads nothing of the CLI, can withdraw a stale current.json there when the manifest was not made.
|
|
14
14
|
*/
|
|
15
|
+
import { spawnSync } from 'node:child_process';
|
|
15
16
|
import { existsSync, readFileSync } from 'node:fs';
|
|
16
|
-
import { join } from 'node:path';
|
|
17
|
+
import { join, posix } from 'node:path';
|
|
17
18
|
import { CAPTURE_KEY_PATTERN, CAPTURE_STATUS_PATH, CAPTURE_VERSION } from '../commands/capture-contract.js';
|
|
18
19
|
import { haystackFetch, haystackJson } from '../utils/haystack-api.js';
|
|
19
20
|
export const CAPTURE_CONFIG_PATH = '.haystack/capture.json';
|
|
@@ -42,6 +43,29 @@ export function readCaptureConfig(appDir) {
|
|
|
42
43
|
}
|
|
43
44
|
return parsed;
|
|
44
45
|
}
|
|
46
|
+
/** The directories (repository-relative, posix; '.' for the root) holding a .haystack/capture.json: those git lists
|
|
47
|
+
* (committed, or not yet), and the candidates that have one even when ignored. */
|
|
48
|
+
export function captureConfigDirs(gitRoot, candidates) {
|
|
49
|
+
const listed = spawnSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard', '--', CAPTURE_CONFIG_PATH,
|
|
50
|
+
`:(glob)**/${CAPTURE_CONFIG_PATH}`], { cwd: gitRoot, encoding: 'utf8' });
|
|
51
|
+
if (listed.status !== 0)
|
|
52
|
+
throw new Error(`git ls-files failed in ${gitRoot}: ${listed.stderr.trim()}`);
|
|
53
|
+
return [...new Set([...listed.stdout.split('\0').filter(path => path !== '' && !path.split('/').includes('node_modules'))
|
|
54
|
+
.map(path => posix.dirname(posix.dirname(path))), ...candidates])].filter(dir => existsSync(captureConfigFile(join(gitRoot, dir)))).sort();
|
|
55
|
+
}
|
|
56
|
+
/** The apps (repository-relative, posix; '.' for the root) whose .haystack/capture.json records them: the user's earlier
|
|
57
|
+
* answer to which app serves production. Records git lists (committed, or not yet), and those in the candidate app
|
|
58
|
+
* directories even when ignored. */
|
|
59
|
+
export function recordedApps(gitRoot, candidates) {
|
|
60
|
+
return captureConfigDirs(gitRoot, candidates).filter(dir => {
|
|
61
|
+
try {
|
|
62
|
+
return readCaptureConfig(join(gitRoot, dir))?.app === dir;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
throw new Error(`${posix.join(dir, CAPTURE_CONFIG_PATH)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
45
69
|
export function formatCaptureConfig(config) {
|
|
46
70
|
return `${JSON.stringify(config, null, 2)}\n`;
|
|
47
71
|
}
|