vigiles 12.2.0 → 12.4.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 CHANGED
@@ -1,88 +1,66 @@
1
1
  <!--
2
2
  README DIRECTION — read before editing; keep changes aligned.
3
- This file is the FRONT DOOR + a marketing asset for someone who already lives
4
- in Claude Code / Codex. Optimize for a phone-skimmer.
5
-
6
- TAGLINE = VERIFY-FIRST (decided 2026-07): "Catch the silent breakage in your
7
- Claude Code & Codex setup" + subhead "verify your CLAUDE.md, skills, and hooks
8
- are real — and prove they actually work." Lead with references-are-real (the
9
- unique catch only vigiles makes); test/observe fold in AFTER. Do NOT revert to
10
- the old test-first "tests your skills never had" tagline. Stay coding-scoped
11
- (name CC/Codex + CLAUDE.md/skills/hooks) so it's never mistaken for a
12
- general-agent tool. NOT "observability" as the headline (it undersells verify +
13
- reads as the general-app category).
14
-
15
- SPINE = CONCEPT 5 (proof/demo-led). Lead with REAL, screenshotable catches on
16
- plugins people actually ship, THEN explain the mechanism. The proofs are not
17
- illustrative — every block traces to a real dogfood run captured in
18
- research/dogfood/. THREE COMMUNITY catches, anonymized (2026-06-29: Proof 1 is now a
19
- lethal-trifecta exfil path Safety 80, from madappgang's `tester` shown as
20
- "my-plugin" added to pay off the new Safety-ring hero; Proof 2 a skill-description
21
- collision → wrong-skill-fires (claude-flow, Triggering F); Proof 3 an
22
- AskUserQuestion-never-available tool) all real GRADED/structural defects that
23
- REPRODUCE on current main. NEVER replace a real catch with a fabricated one. (The
24
- earlier Proof 1 was a missing-SKILL.md/Truthfulness catch, swapped 2026-06-28: its
25
- source (superpowers) is clean on current main and NO reproducible dead-file-ref
26
- exists in popular OSS — those are an adopt+strengthen payoff, see
27
- research/oss-audit-render-findings.md.)
28
-
29
- WHY ONLY TWO (decided 2026-06-28): the earlier Proofs 3-4 leaned on
30
- pr-review-toolkit's "review agents inherit all tools" as an official-plugin
31
- defect. But inherit-all (a subagent with no `tools:` line) is now ADVISORY, not a
32
- graded penalty omitting the tool contract is a near-universal, legitimate
33
- authoring style (an OSS sweep of 122 plugins found 109 whose only finding was
34
- this), so penalizing it cried wolf. With that change the official plugins are all
35
- a clean A, so a "even Anthropic has bugs" proof would be dishonest — Proofs 3-4
36
- were DROPPED rather than reframed. The leaderboard feature still exists; it just
37
- isn't a headline proof.
38
-
39
- DON'T SHAME OSS: community catches are real but ANONYMIZED in public copy (no
40
- obra/superpowers, madappgang by name) real names live only in research/dogfood/.
41
- If an official/vendor proof returns, punch UP (name Anthropic's own); never name a
42
- volunteer's repo to show its bug.
43
-
44
- 1. LEAD WITH BENEFITS / the reader's CONCRETE PAIN, never an apology, caveat, or
45
- competitor. A bolded lead-in is the first thing read make it the hook/win.
46
- End a section on the win, not the trade-off. A paragraph is ≤ ~3 lines.
47
- 2. PROOF FIRST, mechanism second. The three instruments (Lint/Test/Eval) come
48
- AFTER the proof stack as "how it does it", not as a competing front door.
49
- 3. SPEC-FIRST IS THE DEFAULT but easy — `init` ADOPTS your CLAUDE.md into a spec,
50
- skills edit it, you rarely hand-write .spec.ts. Give it ONE home (Quick start),
51
- not five scattered mentions. `eject` always reverses. Inline markdown is the
52
- zero-TS floor.
53
- 4. Guard / compiled hooks is PARKED FOR LAUNCH (see research/roadmap.md). Live set
54
- is Lint/Test/Eval. Do NOT make the 2/7→7/7 battery the hero — re-add post-HN.
55
- 5. SCANNABLE + SHORT ~200-line cap; punchy cells, bullets, runnable blocks.
56
- Push depth into docs/ and LINK it.
57
- 6. NO INTERNAL VOCABULARY (moat / measurement-authority / flywheel) and NO
58
- research/ links name the user benefit.
59
- 7. ASSETS: the hero vigiles-audit.png is a REAL current report (a community
60
- plugin rendered as "my-plugin" to anonymize) C 72 with five rings, the
61
- SAFETY ring (80) flagging a subagent holding all three lethal-trifecta legs
62
- (a prompt-injection exfil path) + an inline subagent-tool-contract fix; the
63
- dramatic Safety catch is the whole point of leading with this report (chose
64
- the "bite" over a clean A 92 on 2026-06-29). No dialect-drift banner (HTML
65
- report is terminal-banner-free by design). Re-render via headless Chromium on
66
- the React report if the UI changes (recipe: copy a trifecta-bearing plugin to
67
- my-plugin/, `node dist/cli.js audit my-plugin --no-json --no-serve`,
68
- headless_shell `--window-size=820,1180 --force-device-scale-factor=2
69
- --screenshot` on vigiles-report.html, then `rm -rf my-plugin
70
- vigiles-report.html`). (vigiles-demo.gif was removed
71
- from Proof 1 — it rendered as a frozen half-typed terminal and was redundant
72
- with the code block; if a lint demo returns, it belongs in the Lint section
73
- with a non-frozen asset.)
74
-
75
- READABILITY (the 2026-06-29 pass — why this reads the way it does):
76
- A. ONE bold per block, on the single phrase the eye should catch. Bold
77
- everywhere = bold nowhere. Link CTAs may stay bold (they're navigation).
78
- B. ONE idea per sentence. No em-dash clause-chains, no stacked parentheticals.
79
- If a clause needs a paren, cut it or give it its own line.
80
- C. PLAIN words in every LEAD; push jargon (rings, recall/precision,
81
- interceptTools, selector, deterministic) into the linked docs. A skimmer who
82
- lives in Claude Code still may not know the vocabulary.
83
- D. SHOW via the proofs/code blocks; don't stack adjectives ("real, popular,
84
- free, model-less") on top of what the block already proves.
85
- E. SELL the outcome before the mechanism; the instruments come AFTER the proofs.
3
+ Front door + marketing asset for someone who lives in Claude Code / Codex.
4
+ Optimize for a phone-skimmer who must come away knowing WHAT IT IS and wanting
5
+ to run it — never scared off. Validated by a 6-persona cold-read (2026-07):
6
+ newcomer / power-user / plugin-author / skeptical-senior / decision-maker /
7
+ Codex-user. The fixes below trace to that review don't regress them.
8
+
9
+ HOOK = FELT PAIN, then breadth (founder direction 2026-07). Bold tagline is a
10
+ specific second-person pain: "You have a rule your agent follows half the time
11
+ and no way to know which one." It's rhetorical (the reader's own uncertainty),
12
+ NOT an ecosystem stat — do NOT reintroduce a bare "%"/number in the tagline (the
13
+ doc mocks uncited stats: "'65% fewer tokens.' Says who?", so a fake stat up top
14
+ reads as hypocrisy). Dev-native CRAFT bait, NOT enterprise fear (OSS dev tool,
15
+ not a security product). The report-card + 5 rings RIGHT BELOW show the breadth
16
+ so the specific hook doesn't read as narrow.
17
+
18
+ DEFINE "HARNESS" on first use (the load-bearing noun, used ~15×) gloss it as
19
+ "the CLAUDE.md/AGENTS.md rules, skills, subagents, and hooks steering your
20
+ agent." 4 of 6 personas bounced on it being undefined. Keep the gloss.
21
+
22
+ INSTRUCTION-NEUTRAL NOUNS (Codex was the lowest score): body copy says CLAUDE.md
23
+ OR AGENTS.md, never CLAUDE.md alone. The tagline may keep punch, but Codex must
24
+ appear within the first sentence or two (the harness gloss names AGENTS.md), and
25
+ every "adopts your CLAUDE.md"/"verifies your CLAUDE.md" gets "or AGENTS.md".
26
+
27
+ CATEGORY = A TOOL YOU RUN (ESLint/Lighthouse/npm audit class), NOT a framework,
28
+ NOT a lib-collection. The FAQ says this outright — it's the #1 thing that scares
29
+ people off. The library/subpath exports are the automation door for the 5%.
30
+
31
+ AUDIT vs LINT ONE CONSISTENT, ACCURATE STORY (a persona caught 3 conflicting
32
+ answers): `lint` = the CI gate on the deterministic checks (broken refs, tool
33
+ contracts, dead hooks, skill collisions Proofs 1 & 2). `audit` = those same
34
+ checks + the Safety ring + two opt-in LIVE checks (MCP connects? skills fire?)
35
+ + the graded report. Do NOT claim lint gates the lethal-trifecta Safety flag
36
+ (it's an audit ring, not a default gating rule) and do NOT say lint is
37
+ refs-only. The table row, the reconciliation line, and the Lint subsection must
38
+ all agree.
39
+
40
+ SPINE = proof/demo-led. Real, screenshotable catches on shipped plugins, THEN
41
+ mechanism. Every proof traces to a real dogfood run (research/dogfood/) NEVER
42
+ fabricate one. Order = most-RELATABLE first (broken tool ref → skill collision →
43
+ secrets-exfil gotcha last as the bite). The intro triplet maps 1:1 to the 3
44
+ proofs. Security is ONE dev-native GOTCHA proof, never the brand. Add a repro
45
+ line ("run `npx vigiles audit <any-repo>` for your own") + a one-line note that
46
+ examples use CC subagents but the checks run on Codex too. FALSE CONFIDENCE is
47
+ the coined term (a guard that looks like it works and silently doesn't), defined
48
+ once in the Test section.
49
+
50
+ FUNNEL: "How it works" opens with the audit/lint/test/eval verb-map table the
51
+ load-bearing "one tool, not four" fix. Frame it vibes verified. Name that
52
+ init/compile/eject manage the spec layer (personas noticed the verb-count gap).
53
+
54
+ DON'T SHAME OSS: catches are ANONYMIZED (no obra/superpowers, madappgang,
55
+ claude-flow by name)real names live only in research/dogfood/.
56
+ Guard/compiled-hooks + the 2/7→7/7 battery are PARKED FOR LAUNCH — not the hero.
57
+
58
+ RULES: lead with the reader's CONCRETE PAIN; ≤ ~3-line paragraphs; ONE bold per
59
+ block; ONE idea per sentence; NO internal vocabulary (moat/flywheel) / NO
60
+ research/ links / NO enterprise/national-interest framingname the user
61
+ benefit; ~220-line body cap; push depth into docs/ and LINK it. Assets: the hero
62
+ vigiles-audit.png is a REAL current report (a community plugin as "my-plugin"),
63
+ C 72, five rings re-render via headless Chromium if the UI changes.
86
64
  -->
87
65
 
88
66
  <p align="center">
@@ -92,11 +70,11 @@
92
70
  <h1 align="center">vigiles</h1>
93
71
 
94
72
  <p align="center">
95
- <strong>Catch the silent breakage in your Claude Code &amp; Codex setup.</strong>
73
+ <strong>You have a rule your agent follows half the time and no way to know which one.</strong>
96
74
  </p>
97
75
 
98
76
  <p align="center">
99
- Verify your CLAUDE.md, skills, and hooks are real — and prove they actually work.
77
+ Verify your CLAUDE.md or AGENTS.md, skills, and hooks are real — and prove they actually work.
100
78
  </p>
101
79
 
102
80
  <p align="center">
@@ -107,44 +85,44 @@
107
85
 
108
86
  ---
109
87
 
110
- **Your skills, hooks, and instructions are your agent's harness — the half you wrote, and the half nothing checks.**
88
+ **You review every PR. Nothing reviews your CLAUDE.md.**
111
89
 
112
- A subagent wired to a tool that doesn't exist. A hook that looks like it blocks and doesn't. Two skills the agent can't tell apart. It all looks fine, and it breaks silently mid-task.
90
+ Your **harness** the CLAUDE.md or AGENTS.md rules, skills, subagents, and hooks steering your agent is the one part nobody checks. Nobody verified it's real. Nobody tested it works. That's not a system. That's vibes.
113
91
 
114
- vigiles checks your harness is _real_, not just well-formed:
92
+ And vibes break silently mid-task: a subagent wired to a tool that doesn't exist, two skills your agent can't tell apart, one helper quietly able to read your secrets and send them out.
93
+
94
+ vigiles[^name] checks your harness is _real_, not just well-formed — Claude Code and Codex alike. One command, no key, no config, safe on any repo:
115
95
 
116
96
  ```bash
117
97
  npx vigiles audit
118
98
  ```
119
99
 
120
- No key, no config, safe on any repo. Here's what it caught on plugins people actually
121
- ship. ↓
100
+ It's free and open-source, runs entirely on your machine, and never bills per token. (`eval` is the only step that calls a model — on your own Claude subscription.) Here's what it caught on plugins people actually ship. ↓
122
101
 
123
102
  ## What it caught
124
103
 
125
104
  <p align="center">
126
- <img src="vigiles-audit.png" width="760" alt="vigiles audit report scoring my-plugin C (72/100): five categories scored A–F — Truthfulness, Triggering, Structure, Safety, Tested — with the Safety category flagging a subagent that holds all three lethal-trifecta legs (a prompt-injection exfil path), plus an inline fix card for a subagent declaring a tool that doesn't exist" />
105
+ <img src="vigiles-audit.png" width="760" alt="vigiles audit report scoring my-plugin C (72/100): five categories scored A–F — Truthfulness, Triggering, Structure, Safety, Tested — with an inline fix card for a subagent declaring a tool that doesn't exist" />
127
106
  </p>
128
107
 
129
- **Like Google's Lighthouse, but for your agent harness.** Five categories, each scored
130
- A–F — Truthfulness, Triggering, Structure, Safety, Tested — with every fix shown inline.
108
+ **Like Google's Lighthouse, but for your agent harness.** One command grades it A–F across five categories, every fix shown inline:
109
+
110
+ - **Truthfulness** — do the references resolve?
111
+ - **Triggering** — do skills fire, without colliding?
112
+ - **Structure** — are tool contracts and configs valid?
113
+ - **Safety** — any way for the agent to leak your data?
114
+ - **Tested** — does the harness ship tests?
131
115
 
132
- It runs locally and only reads, so it's safe on any repo and the same on every OS.
133
- For CI gating, use `vigiles lint` instead. **[Audit a harness →](docs/for-plugin-authors.md)**
116
+ These are real scans of public plugins run `npx vigiles audit <any-repo>` for your own. The examples below use Claude Code subagents; the same checks run on Codex `AGENTS.md`, skills, and hooks. ↓
134
117
 
135
- ## Proof 1 — your agent can read your secrets and ship them out
118
+ ## Proof 1 — a tool your agent thinks it has and doesn't
136
119
 
137
120
  ```text
138
- Safety 80 (80/100)
139
- subagent "tester" holds all three lethal-trifecta legs:
140
- reads private data (Bash, Read) · takes in untrusted web content (WebFetch)
141
- · can send data out (Bash, WebFetch)
121
+ tester — Tool "AskUserQuestion" is never available to a subagent.
122
+ remove or correct it it's silently dropped from the contract.
142
123
  ```
143
124
 
144
- Give one subagent all three powers and it's a **prompt-injection exfil path**: a poisoned
145
- web page can tell it to read your `.env` and POST it anywhere — no exploit code, just the
146
- tools it was handed. vigiles flags it from the tool list alone, free, no model.
147
- **[How the Safety check works →](docs/for-plugin-authors.md)**
125
+ This subagent a helper your main agent hands work to — lists a tool that doesn't exist for it. The harness drops it without a word, so the agent quietly loses a capability it thinks it has. The markdown is perfectly valid. vigiles catches it and hands you the **one-line fix**.
148
126
 
149
127
  ## Proof 2 — two skills your agent can't tell apart
150
128
 
@@ -154,62 +132,58 @@ tools it was handed. vigiles flags it from the tool list alone, free, no model.
154
132
  apart, so the wrong one fires (e.g. "agent-coder" ↔ "agent-tester", 83% alike)
155
133
  ```
156
134
 
157
- One popular plugin ships **45 pairs of skills** with near-identical descriptions. The
158
- agent picks which skill to run by reading those descriptions, so when two match it
159
- fires the wrong one. The markdown is perfectly valid.
135
+ One popular plugin ships **45 pairs of skills** with near-identical descriptions. Your agent picks which skill to run by _reading_ those descriptions, so when two match it fires the wrong one. Still perfectly valid markdown.
160
136
  **[How triggering works →](docs/measuring-skills.md)**
161
137
 
162
- ## Proof 3 — a tool your subagent silently can't call
138
+ ## Proof 3 — it can quietly read your secrets and send them out
163
139
 
164
140
  ```text
165
- tester — Tool "AskUserQuestion" is never available to a subagent.
166
- remove or correct it it's silently dropped from the contract.
141
+ Safety 80 (80/100)
142
+ subagent "tester" holds all three lethal-trifecta legs:
143
+ reads private data (Bash, Read) · takes in untrusted web content (WebFetch)
144
+ · can send data out (Bash, WebFetch)
167
145
  ```
168
146
 
169
- This subagent a helper your main agent hands a task to declares a tool that
170
- doesn't exist. The harness drops it silently, so the agent loses a capability it
171
- thinks it has. vigiles catches it and gives you the **one-line fix**.
147
+ Hand one subagent all three powers and a poisoned web page can tell it to read your `.env` and POST it anywhere — no exploit code, just the tools it was given. The **80 still looks like a B**that's the point: a healthy-looking grade can hide a single subagent that's a data-leak waiting to happen. vigiles spots it from the tool list alone, free, no model.
172
148
 
173
- That's the whole idea it checks your harness against reality, not style. Every
174
- referenced tool, hook, file, script, and skill is verified to actually resolve — and
175
- where you name a linter rule, it's checked to exist _and_ be enabled (ESLint, Ruff,
176
- Clippy and more).
177
- **[Full guide →](docs/verifying-instruction-files.md)**
149
+ That's the whole idea: it checks your harness against **reality, not style**. Every tool, hook, file, script, and skill you reference is verified to actually resolve — and where you name a linter rule, it's checked to exist _and_ be enabled (ESLint, Ruff, Clippy, and more).
150
+ **[Everything it catches →](docs/what-vigiles-catches.md)** · point `audit` at a whole marketplace and it ranks every plugin the same way.
178
151
 
179
- All three catches are free and need no model and vigiles **prevents** other whole
180
- classes of bug by construction (a typed spec or compiled hook just won't compile).
181
- **[Everything it catches and prevents →](docs/what-vigiles-catches.md)** · point `audit`
182
- at a whole marketplace and it ranks every plugin the same way.
183
- **[Audit a marketplace →](docs/for-plugin-authors.md)**
152
+ ## How it worksvibes verified
184
153
 
185
- ## How it works
154
+ `audit` shows you where your setup is still vibes. Turning that into _verified_ is four commands over one engine — and almost none of it needs a model or a key.
186
155
 
187
- The model isn't yours to fix. Your harness is. `audit` shows you the problems — here's
188
- what fixes and proves each one, almost all of it with no model and no key.
156
+ | Command | Answers | Needs a model? | When to run |
157
+ | ------- | ------------------------------ | ------------------------ | ------------------------ |
158
+ | `audit` | Everything, graded A–F | No — read-only[^audit] | Anytime; it's the report |
159
+ | `lint` | Do the structural checks pass? | No | CI gate, every push |
160
+ | `test` | Does the harness behave? | No — a scripted stand-in | Every commit |
161
+ | `eval` | Does a skill actually help? | Yes — your subscription | On demand |
189
162
 
190
- ### 🔎 Lint — your CLAUDE.md stops lying
163
+ `audit` and `lint` share one engine. **`lint` is the CI gate** it fails the build on broken references, bad tool contracts, dead hooks, and skill collisions (Proofs 1 and 2). **`audit`** runs those same checks, adds the Safety ring, renders the graded report, and can also run two opt-in _live_ checks (does your MCP server connect, do your skills fire). `test` and `eval` go past _does it exist_ to _does it work_. (`init` / `compile` / `eject` manage the spec layer underneath; you rarely run them by hand.)
191
164
 
192
- Every path, script, symbol, and rule verified against reality — the catches above.
193
- You don't write the checks: `npx vigiles init` turns your CLAUDE.md, skills, and
194
- subagents into _specs_ (same content, plus a layer vigiles can verify). Non-destructive,
195
- edited by your agent in plain English, undone by `eject`.
165
+ ### 🔎 Lint your instructions stop lying
166
+
167
+ Every path, script, symbol, and rule verified against reality — plus tool contracts, skill collisions, and dead hooks (the catches above). You don't write the checks. `npx vigiles init` writes a `CLAUDE.md.spec.ts` beside your file: the same rules, each reference now wrapped so vigiles can confirm it exists. `compile` turns that back into the `CLAUDE.md` (or `AGENTS.md`) your agent already reads. Your agent edits the spec in plain English; `eject` deletes it and leaves your original untouched.
196
168
  **[How →](docs/verifying-instruction-files.md)**
197
169
 
198
170
  ### 🧪 Test — does the harness actually do its job?
199
171
 
200
- A hook that blocks nothing, a skill that hijacks unrelated prompts, context that never
201
- reaches the model — each passes a naive "did it run?" check. vigiles tests the real
202
- thing: hooks **block**, skills **fire**, subagents **finish what they promised**, and a
203
- stray `git push` is caught before it happens. No model, no key, on every commit.
172
+ A hook that blocks nothing, a skill that hijacks unrelated prompts, context that never reaches the model — each passes a naive "did it run?" check. That gap is **false confidence**: a guard that looks like it works and silently doesn't. vigiles tests the real thing — hooks block, skills fire, subagents finish what they promised, a stray `git push` is caught before it happens. It drives a scripted stand-in for the model, not a live call, so it needs no key and runs on every commit.
204
173
  **[How testing works →](docs/harness-testing.md)**
205
174
 
206
175
  ### 📊 Eval — does a skill help, or just cost more?
207
176
 
208
- _"65% fewer tokens." Says who?_ vigiles[^name] A/Bs the claim on real coding tasks and reports
209
- the token bill, whether it hit its target, and whether the code still works. promptfoo
210
- and DeepEval bill **per token, every run**; vigiles runs on your own Claude Pro/Max
211
- subscription. Evals run locally a committed lock then lets **CI catch stale results with no
212
- model call**. **[Measure a skill →](docs/measuring-skills.md)**
177
+ _"Caveman Mode cuts 65% of your tokens." Says who?_ vigiles A/Bs the claim on real coding tasks and hands you three numbers: the **token bill**, whether it hit its **target**, and whether your code still **works**.
178
+
179
+ ```text
180
+ caveman vs verbose · haiku · $0 on your subscription
181
+ output tokens 762 842 (+11% the "saving" reversed)
182
+ correctness 1.0 → 1.0 (the fact survived)
183
+ ```
184
+
185
+ Point it at any harness change that claims a number — does a compression skill pay for itself, is a subagent worth its cost, which model is cheapest here. promptfoo and DeepEval bill **per token, every run**; vigiles runs on your own Claude Pro/Max subscription, so you measure on every change, not once. A committed lock file (like `package-lock`) keeps CI honest without re-calling the model. (Claude Code today; Codex landing.)
186
+ **[Measure a skill →](docs/measuring-skills.md)**
213
187
 
214
188
  ## Quick start
215
189
 
@@ -232,21 +206,19 @@ Or run it yourself:
232
206
 
233
207
  ```bash
234
208
  npx vigiles init # adopts your files (non-destructive — eject reverses), adds CI,
235
- # installs the Claude Code plugin globally
209
+ # installs vigiles's skills + hooks as a Claude Code plugin (in
210
+ # ~/.claude/, not your repo). On Codex, skills install globally too.
236
211
  ```
237
212
 
238
- Interactive in a terminal, non-interactive for agents/CI (or `--yes`).
213
+ Interactive in a terminal, non-interactive for agents/CI (or `--yes`). **Works with Claude Code and Codex** — vigiles verifies `CLAUDE.md` and `AGENTS.md` the same way. **[Codex setup →](docs/harnesses.md)**
239
214
 
240
- **Adoption is smooth: one command, then your agent does the rest.** `init` installs
241
- the **skills and hooks**, so a plain-English ask does the work — no specs to
242
- hand-write, no hooks to wire:
215
+ **Adoption is smooth: one command, then your agent does the rest.** `init` installs the **skills and hooks**, so a plain-English ask does the work — no specs to hand-write, no hooks to wire:
243
216
 
244
217
  - _"test my skills"_ → scaffolds **and runs** a trigger/behaviour test, then commits its result so CI can check it (`test-harness`)
245
218
  - _"harden my rules"_ → upgrades prose guidance into enforced linter rules (`strengthen`)
246
- - _"add a rule to my CLAUDE.md"_ → edits the source and recompiles (`edit-spec`)
219
+ - _"add a rule to my CLAUDE.md or AGENTS.md"_ → edits the source and recompiles (`edit-spec`)
247
220
 
248
- The **hooks** keep it honest in-loop — nudging the agent to mark a reference or
249
- refresh a stale eval — so there are no chores to remember.
221
+ The **hooks** keep it honest in-loop — nudging the agent to tag a linter-rule mention so vigiles can verify it, or to re-run a test whose result just went stale — so there are no chores to remember.
250
222
 
251
223
  <details>
252
224
  <summary>What <code>init</code> sets up</summary>
@@ -254,35 +226,34 @@ refresh a stale eval — so there are no chores to remember.
254
226
  - **Both lint and test** by default; scope with `--lint` / `--test`.
255
227
  - **Already have a CLAUDE.md / AGENTS.md, skills, or subagents? `init` adopts them all** into specs faithfully and **non-destructively** — untouched until you `compile` (and `eject` undoes it).
256
228
  - Adds `vigiles` to `devDependencies`; installs the Claude Code plugin (skills + hooks) via the marketplace — globally, never vendored.
257
- - Wires CI as a `zernie/vigiles@v1` workflow that posts a sticky PR comment + a `valid` output.
229
+ - Wires CI as a `zernie/vigiles@v1` workflow (needs only read + PR-comment permissions) that posts a sticky PR comment + a `valid` output.
258
230
 
259
- Works with **Claude Code and Codex** ([`vigiles/codex`](docs/harnesses.md)) or
260
- [your own harness](docs/authoring-an-adapter.md). Prefer to write tests yourself?
261
- JS **or** TS (`*.harness.{mjs,ts}`) — run with `npx vigiles test`.
231
+ Targets Claude Code and Codex out of the box, or [your own harness](docs/authoring-an-adapter.md). Prefer to write tests yourself? JS **or** TS (`*.harness.{mjs,ts}`) — run with `npx vigiles test`.
262
232
 
263
233
  </details>
264
234
 
265
235
  ## FAQ
266
236
 
237
+ - **Is this a framework I have to build around?** No. It's a tool you run — like ESLint, Lighthouse, or `npm audit`. One command, a report, an optional CI gate. There's a library API for automation, but you never touch it to get value.
267
238
  - **Isn't this just a markdown linter?** No — it checks whether your instruction file is _true_ (every path/script/symbol/rule exists and is enabled), then tests and measures your harness. A style linter can't do any of that.
268
- - **Do I have to write TypeScript?** No — your agent writes the spec (`init` adopts your CLAUDE.md into one), or plain markdown lints with zero new files. Compiler-grade guarantees are opt-in, like TS's `strict` ([why?](docs/faq.md#why-are-the-strongest-guarantees-opt-in-not-the-default)).
269
- - **Non-JS repo?** `npx vigiles lint` verifies your CLAUDE.md with no install (Ruff/Clippy/Pylint/… too).
239
+ - **Do I have to write TypeScript?** No — your agent writes the spec (`init` adopts your CLAUDE.md or AGENTS.md into one), or plain markdown lints with zero new files. Compiler-grade guarantees are opt-in, like TS's `strict` ([why?](docs/faq.md#why-are-the-strongest-guarantees-opt-in-not-the-default)).
240
+ - **Is it stable enough to adopt?** Yes the CLI is stable; only the library API is still evolving ([details](STABILITY.md)).
241
+ - **Non-JS repo?** `npx vigiles lint` verifies your CLAUDE.md or AGENTS.md with no install (Ruff/Clippy/Pylint/… too).
270
242
 
271
243
  **[Full FAQ →](docs/faq.md)**
272
244
 
245
+ **Not for you if** you want a model/capability benchmark or runtime guardrails in the request path — vigiles is build-/CI-time.
246
+
273
247
  ## More
274
248
 
275
- - **[What vigiles catches and prevents →](docs/what-vigiles-catches.md)** the full matrix of harness problems it handles, biggest first, marked prevent / catch / measure.
276
- - **[CLI →](docs/cli.md)** · **[GitHub Action →](docs/github-action.md)** · the full **[lint rules matrix →](docs/verifying-instruction-files.md#the-validation-rules--the-full-matrix)** lives with the linting guide.
277
- - **[Skills →](docs/skills.md)** the skills `init` installs, and how the model-invocable ones trigger.
278
- - **[Ship plugins? The plugin-author guide →](docs/for-plugin-authors.md)** — scan a draft, make your skills fire, rank a whole marketplace — no key.
279
- - **[Docs index →](docs/README.md)** · **[API reference →](https://zernie.github.io/vigiles/)** · **[Related tools →](docs/related-tools.md)**.
280
- - **[Stability →](STABILITY.md)** — 0.x: the CLI is stable; the library API is still evolving.
281
- - **Not for you if** you want a model/capability benchmark or runtime guardrails in the request path — vigiles is build-/CI-time.
282
- - Companion to [Feedback Loop Is All You Need](https://zernie.com/blog/feedback-loop-is-all-you-need).
249
+ **Docs** **[What it catches and prevents →](docs/what-vigiles-catches.md)** · **[Verifying instruction files →](docs/verifying-instruction-files.md)** ([rules matrix](docs/verifying-instruction-files.md#the-validation-rules--the-full-matrix)) · **[Harness testing →](docs/harness-testing.md)** · **[Measuring skills →](docs/measuring-skills.md)** · **[CLI →](docs/cli.md)** · **[GitHub Action →](docs/github-action.md)** · **[Skills →](docs/skills.md)** · **[Plugin-author guide →](docs/for-plugin-authors.md)** · **[Docs index →](docs/README.md)** · **[API reference →](https://zernie.github.io/vigiles/)**
250
+
251
+ **Project** **[Stability →](STABILITY.md)** · **[Related tools →](docs/related-tools.md)** · companion to [Feedback Loop Is All You Need](https://zernie.com/blog/feedback-loop-is-all-you-need).
283
252
 
284
253
  ## License
285
254
 
286
255
  [MIT](LICENSE)
287
256
 
288
257
  [^name]: **vigiles** — the watchmen of ancient Rome, who guarded the city (and fought its fires) by night. _Quis custodiet ipsos custodes?_ — "who watches the watchmen?" (Juvenal, _Satire VI_).
258
+
259
+ [^audit]: `audit` reads only by default. Two deeper checks — live MCP connections and skill-firing — are opt-in and ask before they run.
@@ -46,6 +46,47 @@ export declare function discoverScripts(patterns: readonly string[], defaultGlob
46
46
  export declare function runScripts(files: readonly string[], cwd: string, env?: NodeJS.ProcessEnv): ScriptRunResult[];
47
47
  /** Whether any script FAILED (a skip is not a failure). */
48
48
  export declare function anyFailed(results: readonly ScriptRunResult[]): boolean;
49
+ /**
50
+ * What a `test`/`eval` invocation should do about actually RUNNING the discovered
51
+ * scripts:
52
+ * - `run` — proceed.
53
+ * - `confirm` — interactive human, no explicit intent: ask before firing `count`.
54
+ * - `refuse` — headless, no explicit intent: don't silently fire the whole tree.
55
+ */
56
+ export type RunScriptsDecision = {
57
+ readonly kind: "run";
58
+ } | {
59
+ readonly kind: "confirm";
60
+ readonly count: number;
61
+ } | {
62
+ readonly kind: "refuse";
63
+ readonly count: number;
64
+ };
65
+ export interface RunScriptsEnv {
66
+ /** `test` is free/deterministic → always runs. `eval` spends model quota. */
67
+ readonly kind: "test" | "eval";
68
+ /** The user named explicit target files/globs (positional args) — clear intent. */
69
+ readonly explicitTargets: boolean;
70
+ /** How many script files the discovery matched. */
71
+ readonly matchedCount: number;
72
+ /** A human at a terminal who can answer + wait. */
73
+ readonly isTTY: boolean;
74
+ /** `--all` — opt in to running the whole discovered set without a prompt. */
75
+ readonly all: boolean;
76
+ /** `--yes` / `--no-interactive` — agent/CI mode: never prompt. */
77
+ readonly yes: boolean;
78
+ }
79
+ /**
80
+ * Consent gate for a bare (no-target) `vigiles eval`. `eval` runs the REAL model
81
+ * on your subscription, and a no-target run discovers every `*.eval.*` over the
82
+ * whole tree — so a repo with many evals fires them all and spends quota. Mirrors
83
+ * `audit`'s read-vs-run consent (`decideExecute`): a paid, side-effecting verb
84
+ * never fans out over an unbounded glob without either an explicit target, an
85
+ * `--all` opt-in, or an interactive yes. `test` is free + deterministic, so it
86
+ * always runs. Total + pure, first match wins; the IO (prompt/refuse) lives in the
87
+ * CLI.
88
+ */
89
+ export declare function decideRunScripts(o: RunScriptsEnv): RunScriptsDecision;
49
90
  /** One line per file + an explicit pass/skip/fail tally. Skips are SHOWN, never
50
91
  * folded into "passed" — a `⊘ SKIPPED` is loud, not a silent green. */
51
92
  export declare function formatScriptSummary(results: readonly ScriptRunResult[]): string;
@@ -7,6 +7,7 @@ exports.detectNodeCaps = detectNodeCaps;
7
7
  exports.discoverScripts = discoverScripts;
8
8
  exports.runScripts = runScripts;
9
9
  exports.anyFailed = anyFailed;
10
+ exports.decideRunScripts = decideRunScripts;
10
11
  exports.formatScriptSummary = formatScriptSummary;
11
12
  /**
12
13
  * vigiles — run harness-test / eval script files via the CLI.
@@ -123,6 +124,31 @@ function runScripts(files, cwd, env = {}) {
123
124
  function anyFailed(results) {
124
125
  return results.some((r) => r.status === "fail");
125
126
  }
127
+ /**
128
+ * Consent gate for a bare (no-target) `vigiles eval`. `eval` runs the REAL model
129
+ * on your subscription, and a no-target run discovers every `*.eval.*` over the
130
+ * whole tree — so a repo with many evals fires them all and spends quota. Mirrors
131
+ * `audit`'s read-vs-run consent (`decideExecute`): a paid, side-effecting verb
132
+ * never fans out over an unbounded glob without either an explicit target, an
133
+ * `--all` opt-in, or an interactive yes. `test` is free + deterministic, so it
134
+ * always runs. Total + pure, first match wins; the IO (prompt/refuse) lives in the
135
+ * CLI.
136
+ */
137
+ function decideRunScripts(o) {
138
+ if (o.kind === "test")
139
+ return { kind: "run" };
140
+ if (o.explicitTargets)
141
+ return { kind: "run" };
142
+ if (o.all || o.yes)
143
+ return { kind: "run" };
144
+ // A bounded no-target run (0 = no-op, 1 = a single obviously-intended eval) is
145
+ // not the footgun; the footgun is fanning out over the whole tree.
146
+ if (o.matchedCount <= 1)
147
+ return { kind: "run" };
148
+ if (!o.isTTY)
149
+ return { kind: "refuse", count: o.matchedCount };
150
+ return { kind: "confirm", count: o.matchedCount };
151
+ }
126
152
  const MARK = {
127
153
  pass: "✓",
128
154
  skip: "⊘",
package/dist/cli.js CHANGED
@@ -3487,11 +3487,29 @@ async function handleGenerateHarness(args, restArgs) {
3487
3487
  console.log(`\n✓ Generated ${(0, generate_harness_js_1.labelFor)(process.cwd(), fullOut)}`);
3488
3488
  console.log(" `tsc --noEmit` over this file now checks every delegate target resolves.");
3489
3489
  }
3490
+ /** Minimal TTY yes/no prompt (readline). Returns true only on an explicit y/yes. */
3491
+ async function promptYesNo(question) {
3492
+ const readline = await import("node:readline");
3493
+ const rl = readline.createInterface({
3494
+ input: process.stdin,
3495
+ output: process.stdout,
3496
+ });
3497
+ try {
3498
+ const answer = await new Promise((res) => {
3499
+ rl.question(question, res);
3500
+ });
3501
+ return /^y(es)?$/i.test(answer.trim());
3502
+ }
3503
+ finally {
3504
+ rl.close();
3505
+ }
3506
+ }
3490
3507
  /**
3491
3508
  * `vigiles test` / `vigiles eval` — discover and run the two-tier harness
3492
3509
  * scripts (deterministic `*.harness.mjs` / real-model `*.eval.mjs`) as child
3493
3510
  * `node` processes, aggregating exit codes so they work as a CI command. See
3494
- * src/run-scripts.ts.
3511
+ * src/run-scripts.ts. A bare `vigiles eval` (no target) asks before fanning out
3512
+ * over the whole tree — it spends model quota (see `decideRunScripts`).
3495
3513
  *
3496
3514
  * `vigiles test` skips clean when the `claude` CLI is absent (the deterministic
3497
3515
  * tier needs it, just like the node:test suite). `--trials=N` is forwarded to
@@ -3532,7 +3550,7 @@ function resolveEvalLockEnv(args) {
3532
3550
  }
3533
3551
  return env;
3534
3552
  }
3535
- function handleRunScripts(kind, args, restArgs) {
3553
+ async function handleRunScripts(kind, args, restArgs) {
3536
3554
  const cwd = process.cwd();
3537
3555
  // Harness/eval scripts may be authored in JS or TS (see run-scripts.ts).
3538
3556
  const defaultGlob = (0, run_scripts_js_1.scriptGlob)(kind === "test" ? "harness" : "eval");
@@ -3563,6 +3581,33 @@ function handleRunScripts(kind, args, restArgs) {
3563
3581
  console.log(`No ${defaultGlob} files found.`);
3564
3582
  return;
3565
3583
  }
3584
+ // Consent gate for a bare `vigiles eval`: it runs the REAL model on your
3585
+ // subscription, and a no-target run discovered the whole tree — so never fan out
3586
+ // over an unbounded glob without explicit intent. Mirrors audit's read-vs-run
3587
+ // consent. `test` is free → always runs (decideRunScripts returns "run").
3588
+ const runDecision = (0, run_scripts_js_1.decideRunScripts)({
3589
+ kind,
3590
+ explicitTargets: restArgs.length > 0,
3591
+ matchedCount: files.length,
3592
+ isTTY: (process.stdin.isTTY ?? false) && (process.stdout.isTTY ?? false),
3593
+ all: args.includes("--all"),
3594
+ yes: args.includes("--yes") || args.includes("--no-interactive"),
3595
+ });
3596
+ if (runDecision.kind === "refuse") {
3597
+ console.error(`✗ vigiles eval: ${String(runDecision.count)} eval file(s) matched the whole tree, and each ` +
3598
+ "runs the real model on your subscription. Refusing to fire them all non-interactively.\n" +
3599
+ " → name the eval(s): vigiles eval path/to/x.eval.mjs\n" +
3600
+ " → or opt in to all: vigiles eval --all");
3601
+ process.exit(2);
3602
+ }
3603
+ if (runDecision.kind === "confirm") {
3604
+ const ok = await promptYesNo(`About to run ${String(runDecision.count)} eval file(s) against the real model on your ` +
3605
+ "subscription (uses your Claude quota). Continue? [y/N] ");
3606
+ if (!ok) {
3607
+ console.log("Aborted. Name specific eval(s), or pass --all to run them all.");
3608
+ return;
3609
+ }
3610
+ }
3566
3611
  // No blanket skip: unit-tier (runHook) tests need no `claude`, so always run.
3567
3612
  // A script whose tier DOES need `claude` self-reports `⊘ SKIPPED` (exit 77) —
3568
3613
  // loud, never a silent green. Just flag up front that some may skip.
@@ -4934,10 +4979,10 @@ async function main() {
4934
4979
  break;
4935
4980
  }
4936
4981
  case "test":
4937
- handleRunScripts("test", args, restArgs);
4982
+ await handleRunScripts("test", args, restArgs);
4938
4983
  break;
4939
4984
  case "eval":
4940
- handleRunScripts("eval", args, restArgs);
4985
+ await handleRunScripts("eval", args, restArgs);
4941
4986
  break;
4942
4987
  case "audit": {
4943
4988
  // The Lighthouse run: a plain `audit` is a deterministic READ — rings, each