vigiles 12.7.0 → 13.0.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
@@ -40,8 +40,10 @@
40
40
  SPINE = proof/demo-led. Real, screenshotable catches on shipped plugins, THEN
41
41
  mechanism. Every proof traces to a real dogfood run (research/dogfood/) — NEVER
42
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
43
+ rules-not-enforced → secrets-exfil gotcha LAST as the bite). The intro triplet
44
+ maps to the three "vibes break silently" proofs (1, 2, 4); Proof 3 (your rules →
45
+ enforced) pays off the TAGLINE's rule-follows-half-the-time pain. Security is ONE
46
+ dev-native GOTCHA proof, never the brand. Add a repro
45
47
  line ("run `npx vigiles audit <any-repo>` for your own") + a one-line note that
46
48
  examples use CC subagents but the checks run on Codex too. FALSE CONFIDENCE is
47
49
  the coined term (a guard that looks like it works and silently doesn't), defined
@@ -59,8 +61,11 @@
59
61
  block; ONE idea per sentence; NO internal vocabulary (moat/flywheel) / NO
60
62
  research/ links / NO enterprise/national-interest framing — name the user
61
63
  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.
64
+ vigiles-audit.png is a REPRESENTATIVE report ("my-plugin", C 77) — the verdict-
65
+ led header + ranked fixes + the "Your rules enforced" section (the new rule-
66
+ compile capability). Re-render via headless Chromium if the UI changes: build
67
+ report/, screenshot report/dist/index.html (falls back to the sample fixture),
68
+ inject the dark :root tokens before </body> for the dark render.
64
69
  -->
65
70
 
66
71
  <p align="center">
@@ -102,10 +107,10 @@ It's free and open-source, runs entirely on your machine, and never bills per to
102
107
  ## What it caught
103
108
 
104
109
  <p align="center">
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" />
110
+ <img src="vigiles-audit.png" width="760" alt="vigiles audit report for my-plugin: a verdict header reading 'Two one-line fixes away from a B.' next to a C (77/100) grade, a five-category strip (Truthfulness, Triggering, Structure, Safety, Tested), ranked fix cards with '+N pts' impact badges, and a 'Your rules → enforced' section showing a prose rule the config silently turns off" />
106
111
  </p>
107
112
 
108
- **Like Google's Lighthouse, but for your agent harness.** One command grades it A–F across five categories, every fix shown inline:
113
+ **Like Google's Lighthouse, but for your agent harness.** One command grades it A–F across five categories, leads with a plain-English verdict — _"two one-line fixes away from a B"_ — and ranks every fix by the points it buys back:
109
114
 
110
115
  - **Truthfulness** — do the references resolve?
111
116
  - **Triggering** — do skills fire, without colliding?
@@ -113,6 +118,8 @@ It's free and open-source, runs entirely on your machine, and never bills per to
113
118
  - **Safety** — any way for the agent to leak your data?
114
119
  - **Tested** — does the harness ship tests?
115
120
 
121
+ And it closes the loop from prose to enforcement: **your rules → enforced** maps each rule you wrote to the lint rule that actually enforces it — already on, one config line away, or silently turned off (below).
122
+
116
123
  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. ↓
117
124
 
118
125
  ## Proof 1 — a tool your agent thinks it has and doesn't
@@ -132,10 +139,23 @@ This subagent — a helper your main agent hands work to — lists a tool that d
132
139
  apart, so the wrong one fires (e.g. "agent-coder" ↔ "agent-tester", 83% alike)
133
140
  ```
134
141
 
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.
142
+ One popular plugin ships **45 pairs** of near-identical skill descriptions. Your agent picks a skill by _reading_ them so when two match, it fires the wrong one. Still perfectly valid markdown.
136
143
  **[How triggering works →](docs/measuring-skills.md)**
137
144
 
138
- ## Proof 3 — it can quietly read your secrets and send them out
145
+ ## Proof 3 — a rule you wrote that nothing enforces
146
+
147
+ Point vigiles at your own repo and the rules section maps each prose rule to the lint rule that enforces it — then checks your config. Representative output:
148
+
149
+ ```text
150
+ Your rules → enforced 1 of 4 enforced · 2 one line away · 1 contradicted by config
151
+ └ "always use ===" → eqeqeq is set to "off" in your ESLint config
152
+ your CLAUDE.md says enforce it; your config quietly turns it off
153
+ ```
154
+
155
+ You wrote the rule. Your agent treats it as gospel and follows it — until it doesn't, and nothing tells you which time. vigiles checks each mapped rule three ways: enforced, **one line away**, or — the one people screenshot — documented but silently **turned off**. Deterministic, no model. Want the rest compiled — a custom rule for a rule no linter ships, a hook for `git push`, the judgment calls honestly left alone? That's the opt-in `compile` tier (one model pass, then CI is plain lint).
156
+ **[How enforcement works →](docs/verifying-instruction-files.md)**
157
+
158
+ ## Proof 4 — it can quietly read your secrets and send them out
139
159
 
140
160
  ```text
141
161
  ◑ Safety 80 (80/100)
@@ -144,7 +164,7 @@ One popular plugin ships **45 pairs of skills** with near-identical descriptions
144
164
  · can send data out (Bash, WebFetch)
145
165
  ```
146
166
 
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.
167
+ Hand one subagent all three powers and a poisoned web page can make it read your `.env` and POST it anywhere — no exploit code, just the tools it was given. The **80 looks like a B** — and that's the trap: a healthy grade hiding a subagent that's a data-leak waiting to happen. vigiles spots it from the tool list alone, free, no model.
148
168
 
149
169
  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
170
  **[Everything it catches →](docs/what-vigiles-catches.md)** · point `audit` at a whole marketplace and it ranks every plugin the same way.
@@ -160,7 +180,7 @@ That's the whole idea: it checks your harness against **reality, not style**. Ev
160
180
  | `test` | Does the harness behave? | No — a scripted stand-in | Every commit |
161
181
  | `eval` | Does a skill actually help? | Yes — your subscription | On demand |
162
182
 
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.)
183
+ **One engine, two doors.** `audit` is the local report; **`lint` is the CI gate** that fails the build on the same deterministic checks — broken refs, bad tool contracts, dead hooks, skill collisions (Proofs 12). `test` and `eval` go further: past _does it exist_ to _does it work_. (`init` / `compile` / `eject` manage the spec layer underneath you rarely run them by hand.)
164
184
 
165
185
  ### 🔎 Lint — your instructions stop lying
166
186
 
@@ -172,7 +192,7 @@ Every path, script, symbol, and rule verified against reality — plus tool cont
172
192
  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.
173
193
  **[How testing works →](docs/harness-testing.md)**
174
194
 
175
- ### 📊 Eval — does a skill help, or just cost more?
195
+ ### 📊 Eval — the only way to put a real number on cost
176
196
 
177
197
  _"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
198
 
@@ -237,18 +257,26 @@ Targets Claude Code and Codex out of the box, or [your own harness](docs/authori
237
257
  - **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.
238
258
  - **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.
239
259
  - **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)).
260
+ - **Is it stable enough to adopt?** The CLI you run is small and rarely changes; the library API still moves between releases. The high version number is release automation (a new major per breaking change), not age — see [Stability](STABILITY.md).
241
261
  - **Non-JS repo?** `npx vigiles lint` verifies your CLAUDE.md or AGENTS.md with no install (Ruff/Clippy/Pylint/… too).
242
262
 
243
263
  **[Full FAQ →](docs/faq.md)**
244
264
 
245
265
  **Not for you if** you want a model/capability benchmark or runtime guardrails in the request path — vigiles is build-/CI-time.
246
266
 
247
- ## More
267
+ ## Docs
268
+
269
+ The **[docs index](docs/README.md)** is the full map, grouped by what you're doing:
270
+
271
+ - **Guides** — [verify instruction files](docs/verifying-instruction-files.md) · [test your harness](docs/harness-testing.md) · [measure a skill](docs/measuring-skills.md) · [ship a plugin](docs/for-plugin-authors.md) · [Codex & other harnesses](docs/harnesses.md)
272
+ - **Reference** — [CLI](docs/cli.md) · [rules matrix](docs/verifying-instruction-files.md#the-validation-rules--the-full-matrix) · [testing API](docs/testing-api.md) · [full API](https://zernie.github.io/vigiles/)
273
+ - **Explanation** — [what it catches](docs/what-vigiles-catches.md) · [how it compares](docs/comparison.md) · [FAQ](docs/faq.md)
248
274
 
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/)**
275
+ **Project** — [Stability](STABILITY.md) · [Related tools](docs/comparison.md#what-vigiles-composes-with)
250
276
 
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).
277
+ <!-- The "companion to [Feedback Loop Is All You Need](https://zernie.com/blog/feedback-loop-is-all-you-need)"
278
+ link is temporarily removed while AgenticDev paper #1 is under blind review: repo → blog is a
279
+ deanonymization path (the reviewer-offer email links this repo). RESTORE after notification (2026-08-21). -->
252
280
 
253
281
  ## License
254
282
 
@@ -13,10 +13,13 @@
13
13
  */
14
14
  import { type AuditScore } from "./audit-score.js";
15
15
  import { type Recommendation } from "./optimize.js";
16
+ import { type Verdict } from "./audit-verdict.js";
16
17
  import type { LedgerSummary } from "./observe.js";
17
18
  import type { AdoptabilityResult } from "./adoptability.js";
18
19
  import type { ScanReport, MarketplaceInfo } from "./scan.js";
19
20
  import type { PluginScore } from "./leaderboard.js";
21
+ import type { RuleInventoryItem } from "./rule-inventory.js";
22
+ import type { RuleRouting } from "./rule-routing.js";
20
23
  /** The current schema version. Bump only on a BREAKING change to the shape. */
21
24
  export declare const AUDIT_SCHEMA_VERSION = 1;
22
25
  export interface AuditReportMeta {
@@ -80,6 +83,13 @@ export interface AuditReport {
80
83
  readonly meta: AuditReportMeta;
81
84
  /** The five deterministic category rings + the weighted overall + grade. */
82
85
  readonly score: AuditScore;
86
+ /**
87
+ * The one-line verdict + per-recommendation `pointsIfFixed`, both derived by
88
+ * RE-SCORING (never a hardcoded number). Drives the report's verdict-led header
89
+ * ("Two one-line fixes away from a B.") and the `+N pts` badges on fix cards.
90
+ * Pure/deterministic — always present.
91
+ */
92
+ readonly verdict: Verdict;
83
93
  /** The deterministic, ranked fixes (the inline recommendations). */
84
94
  readonly recommendations: readonly Recommendation[];
85
95
  readonly inventory: AuditInventory;
@@ -104,6 +114,24 @@ export interface AuditReport {
104
114
  * the pure builder stays fs-free.
105
115
  */
106
116
  readonly observations?: LedgerSummary;
117
+ /**
118
+ * The deterministic rule-inventory teaser — prose rules in the harness that
119
+ * map to an off-the-shelf lint rule + whether that rule is already in the
120
+ * config (the one-line-config-fix nudge). No model, no config execution. The
121
+ * CLI computes it (reads the instruction + config text, calls
122
+ * `buildRuleInventory`) and passes it in, so the pure builder stays fs-free.
123
+ * Present only when at least one intent resolves. Additive/optional — schema
124
+ * version unchanged. See `research/audit-rule-compile-tier.md`.
125
+ */
126
+ readonly rulesInventory?: readonly RuleInventoryItem[];
127
+ /**
128
+ * The deterministic State-B routing PREVIEW — the instruction file segmented
129
+ * into atomic rules, each routed (reuse / hook / semantic / unrouted) to how
130
+ * it would be enforced, with per-category counts. No model, fs-only. Grounds
131
+ * the report's "compile" upsell in real numbers instead of generic copy.
132
+ * Present only when at least one atomic rule was segmented. Additive/optional.
133
+ */
134
+ readonly ruleRouting?: RuleRouting;
107
135
  }
108
136
  export interface BuildAuditReportOptions {
109
137
  readonly harness: string;
@@ -117,6 +145,16 @@ export interface BuildAuditReportOptions {
117
145
  * when there's nothing to adopt.
118
146
  */
119
147
  readonly adoptableSurfaces?: readonly string[];
148
+ /**
149
+ * The rule-inventory items the CLI computed via `buildRuleInventory` (reading
150
+ * the instruction + config text). Omit/empty when nothing resolved.
151
+ */
152
+ readonly rulesInventory?: readonly RuleInventoryItem[];
153
+ /**
154
+ * The State-B routing preview the CLI computed via `routeRules`. Omit when
155
+ * nothing segmented.
156
+ */
157
+ readonly ruleRouting?: RuleRouting;
120
158
  }
121
159
  /**
122
160
  * Assemble the versioned {@link AuditReport} from a scan report — pure, no clock.
@@ -19,6 +19,7 @@ exports.buildMarketplaceReport = buildMarketplaceReport;
19
19
  */
20
20
  const audit_score_js_1 = require("./audit-score.js");
21
21
  const optimize_js_1 = require("./optimize.js");
22
+ const audit_verdict_js_1 = require("./audit-verdict.js");
22
23
  /** The current schema version. Bump only on a BREAKING change to the shape. */
23
24
  exports.AUDIT_SCHEMA_VERSION = 1;
24
25
  /** The one command that adopts every un-spec'd surface (bare `init`). */
@@ -47,6 +48,9 @@ function buildAdoptable(surfaces) {
47
48
  */
48
49
  function buildAuditReport(report, opts) {
49
50
  const adoptable = buildAdoptable(opts.adoptableSurfaces);
51
+ const score = (0, audit_score_js_1.auditScore)(report);
52
+ const recommendations = (0, optimize_js_1.optimize)(report).recommendations;
53
+ const verdict = (0, audit_verdict_js_1.computeVerdict)({ report, score, recommendations });
50
54
  return {
51
55
  meta: {
52
56
  schemaVersion: exports.AUDIT_SCHEMA_VERSION,
@@ -56,8 +60,9 @@ function buildAuditReport(report, opts) {
56
60
  harness: opts.harness,
57
61
  dir: report.dir,
58
62
  },
59
- score: (0, audit_score_js_1.auditScore)(report),
60
- recommendations: (0, optimize_js_1.optimize)(report).recommendations,
63
+ score,
64
+ verdict,
65
+ recommendations,
61
66
  inventory: {
62
67
  skills: report.skills.length,
63
68
  agents: report.agents.length,
@@ -71,6 +76,12 @@ function buildAuditReport(report, opts) {
71
76
  },
72
77
  ...(adoptable ? { adoptable } : {}),
73
78
  ...(opts.observations ? { observations: opts.observations } : {}),
79
+ ...(opts.rulesInventory && opts.rulesInventory.length
80
+ ? { rulesInventory: opts.rulesInventory }
81
+ : {}),
82
+ ...(opts.ruleRouting && opts.ruleRouting.segmented > 0
83
+ ? { ruleRouting: opts.ruleRouting }
84
+ : {}),
74
85
  };
75
86
  }
76
87
  /** Assemble the versioned {@link LeaderboardReport} — pure, no clock. */