vigiles 5.0.0 → 5.0.1
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 +71 -111
- package/package.json +27 -4
package/README.md
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
<h1 align="center">vigiles</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<
|
|
8
|
+
<strong>Lint & test the harness your AI agent runs on.</strong>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<
|
|
13
|
-
vigiles <strong>lints</strong> the references your instruction files make — linter rules, file paths, scripts, code symbols — and <strong>tests</strong> whether your hooks, skills, and CLAUDE.md actually change what the agent does.
|
|
12
|
+
Your CLAUDE.md, hooks, and skills steer the agent — but nothing checks they're <em>true</em>, and nothing tests they <em>work</em>. vigiles does both.
|
|
14
13
|
</p>
|
|
15
14
|
|
|
16
15
|
<p align="center">
|
|
@@ -22,113 +21,17 @@
|
|
|
22
21
|
---
|
|
23
22
|
|
|
24
23
|
`Agent = Model + Harness`. You'd never ship an app without a linter and a test
|
|
25
|
-
suite — yet
|
|
26
|
-
deterministic layer for
|
|
27
|
-
files make and **tests** that your hooks and skills actually fire. Two independent
|
|
28
|
-
pillars — adopt either, or both:
|
|
24
|
+
suite — yet the harness steering your agent runs on vibes. vigiles[^name] is the
|
|
25
|
+
deterministic layer for it, and does two independent things — adopt either, or both:
|
|
29
26
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
27
|
+
| | |
|
|
28
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
29
|
+
| **🔎 Lint** | Every file path, script, code symbol, and linter rule your CLAUDE.md cites is checked against reality — so a renamed file or a disabled rule can't silently mislead the agent. **[→](docs/verifying-instruction-files.md)** |
|
|
30
|
+
| **🧪 Test** | Hooks, skills, and subagents are code. vigiles tests they _do their job_ — and almost all of it is **deterministic, no API key**; the real-model evals run on your **Claude subscription**, not metered tokens. **[→](docs/harness-testing.md)** |
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
## ① Lint — your CLAUDE.md lies to your agent
|
|
40
|
-
|
|
41
|
-
Your CLAUDE.md says _"enforce `eslint/no-console`."_ But it was switched off
|
|
42
|
-
months ago — and the agent trusts the claim. (Same story for the file path it
|
|
43
|
-
cites that got renamed, and the script that was deleted.)
|
|
44
|
-
|
|
45
|
-
**Without vigiles:** nobody checks. The agent acts on fiction.
|
|
46
|
-
|
|
47
|
-
**With vigiles:** `npx vigiles lint` resolves every reference against reality —
|
|
48
|
-
|
|
49
|
-
```text
|
|
50
|
-
CLAUDE.md (inline mode):
|
|
51
|
-
✗ line 1: Rule "eslint/no-console" exists but is disabled in eslint config
|
|
52
|
-
✓ line 2: eslint/eqeqeq
|
|
53
|
-
✗ line 3: Rule "no-consoel" not found in eslint. Did you mean: "eslint/no-console"?
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
It resolves rule names across **7 linter catalogs** — the rule exists **and is
|
|
57
|
-
enabled** — and checks file paths, scripts, and code symbols the same way. Start
|
|
58
|
-
with one comment, no new files:
|
|
59
|
-
|
|
60
|
-
```md
|
|
61
|
-
<!-- vigiles:enforce eslint/no-console "Route output through logger.ts" -->
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Step up to a typed `.spec.ts` (compiled to CLAUDE.md, compiler-grade) when you
|
|
65
|
-
want it. **[Full guide →](docs/verifying-instruction-files.md)**
|
|
66
|
-
|
|
67
|
-
## ② Test — does your harness actually fire?
|
|
68
|
-
|
|
69
|
-
A hook can be wired wrong, a skill's description can fail to trigger, injected
|
|
70
|
-
context can never reach the model — silently, all passing a naive "did it run?"
|
|
71
|
-
check.
|
|
72
|
-
|
|
73
|
-
**Without vigiles:** you assume your `--no-verify` guard blocks. You don't know.
|
|
74
|
-
|
|
75
|
-
**With vigiles:** a deterministic test proves it — no model, no API key,
|
|
76
|
-
milliseconds:
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
import { runHook } from "vigiles/testing";
|
|
80
|
-
|
|
81
|
-
const r = runHook(guard, {
|
|
82
|
-
hook_event_name: "PreToolUse",
|
|
83
|
-
tool_name: "Bash",
|
|
84
|
-
tool_input: { command: "git commit --no-verify" },
|
|
85
|
-
});
|
|
86
|
-
assert(r.blocked); // a red ✗ here means your hook silently lets it through
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
```text
|
|
90
|
-
✓ guard blocks --no-verify and allows a clean commit
|
|
91
|
-
|
|
92
|
-
2 passed.
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Three tiers, cheapest first: **`runHook`** (a hook's logic), **`runHarnessTest`**
|
|
96
|
-
(the real agent CLI against a scripted mock model), and the real-model scored tier
|
|
97
|
-
(**`measure`** / **`runEval`**). **Testing a skill?** Two questions, both covered:
|
|
98
|
-
does its description **fire** (`measureTriggerRate` — recall across varied prompts
|
|
99
|
-
without hijacking unrelated ones, precision), **and** does its guidance actually
|
|
100
|
-
**work**. For "is this exact skill any good?" score the output directly —
|
|
101
|
-
`measure({ checks: [judged(rubric)] })` + `assertRates` (the **absolute** oracle,
|
|
102
|
-
what promptfoo/DeepEval lead with; no on/off baseline needed). When you need the
|
|
103
|
-
**relative** lift over no-skill — regression, or proving the change isn't noise —
|
|
104
|
-
A/B it on-vs-off with `runEval` + `assertSignificant`. Description _and_ behavior,
|
|
105
|
-
not just one. **Need a safety property** — that the agent
|
|
106
|
-
**didn't** push to the wrong branch or call a paid API? `notTool` + `interceptTools`
|
|
107
|
-
intercept the tool in the real hook layer, so the attempt is caught and the side
|
|
108
|
-
effect never happens. **[Full guide →](docs/harness-testing.md)** · vigiles runs
|
|
109
|
-
foreign code (and a real model) safely by default — **[safety model →](docs/safety.md)**
|
|
110
|
-
|
|
111
|
-
Most of what real plugins do is testable cheaply — fire / trigger / contract /
|
|
112
|
-
safety, plus **record-replay** for the tool/API results a skill consumes (recorded
|
|
113
|
-
once from the real tool, replayed deterministically — no live service, no Docker).
|
|
114
|
-
That covers ~90%+ of real plugin surface on your subscription; the rare case that
|
|
115
|
-
needs a real browser or database **composes with Docker** rather than us
|
|
116
|
-
reinventing the sandbox. **[What we test, how →](research/eval-coverage-and-isolation.md)**
|
|
117
|
-
|
|
118
|
-
**Affordable by design — the eval you can actually run.** Almost nobody evals
|
|
119
|
-
their harness, because the usual tools (promptfoo, DeepEval, …) hit the API SDK
|
|
120
|
-
and bill **per token on every run**. vigiles inverts that: most questions are
|
|
121
|
-
answered with **no model at all** (free, every commit), and when you do reach for
|
|
122
|
-
a real-model eval, vigiles drives your `claude` CLI — so it runs on the **Pro/Max
|
|
123
|
-
subscription you already pay for**, not metered API billing. CI runs only the free
|
|
124
|
-
deterministic tiers; you run the real-model eval where the subscription already is
|
|
125
|
-
— a Claude Code session or locally — when it's worth it, not on every PR.
|
|
126
|
-
|
|
127
|
-
This affordability story is **ToS-clean**: vigiles drives _your own_ `claude` CLI
|
|
128
|
-
to test _your own_ harness on _your own_ subscription — the same thing you do when
|
|
129
|
-
you run Claude Code. (The Claude Agent SDK's ToS restricts _productizing_ claude.ai
|
|
130
|
-
login/limits in a third-party offering; running your own tests on your own sub is
|
|
131
|
-
exactly the supported posture, not that.)
|
|
32
|
+
Pick the one that hurts today. **Works with Claude Code and Codex**
|
|
33
|
+
([`vigiles/codex`](docs/harnesses.md)) behind a five-port adapter;
|
|
34
|
+
[custom adapters welcome](docs/authoring-an-adapter.md).
|
|
132
35
|
|
|
133
36
|
## Quick start
|
|
134
37
|
|
|
@@ -137,7 +40,7 @@ exactly the supported posture, not that.)
|
|
|
137
40
|
```text
|
|
138
41
|
Install vigiles in this repo and run it. Verify my CLAUDE.md / AGENTS.md
|
|
139
42
|
references and show me what's stale, then write and run a harness test for one
|
|
140
|
-
of my hooks or skills. Use good defaults (
|
|
43
|
+
of my hooks or skills. Use good defaults (lint + test, non-interactive), but
|
|
141
44
|
ask me first whether to gate it in CI, whether to add a real-model eval, and
|
|
142
45
|
whether to enforce strictly (--strict).
|
|
143
46
|
```
|
|
@@ -145,7 +48,7 @@ whether to enforce strictly (--strict).
|
|
|
145
48
|
Or do it yourself:
|
|
146
49
|
|
|
147
50
|
```bash
|
|
148
|
-
npx vigiles init # sets up
|
|
51
|
+
npx vigiles init # sets up lint + test: spec + harness test + CI + plugin
|
|
149
52
|
```
|
|
150
53
|
|
|
151
54
|
It's interactive in a terminal and non-interactive for agents/CI (or with
|
|
@@ -156,7 +59,7 @@ tell your agent _"test my skills"_ and it picks the tier and writes the test.
|
|
|
156
59
|
<details>
|
|
157
60
|
<summary>What <code>init</code> sets up</summary>
|
|
158
61
|
|
|
159
|
-
- **Both
|
|
62
|
+
- **Both lint and test** by default; scope with `--lint` / `--test` (one or both).
|
|
160
63
|
- Adds `vigiles` to your `devDependencies`.
|
|
161
64
|
- Installs the Claude Code plugin (skills + hooks) via the marketplace —
|
|
162
65
|
globally, never vendored into your repo.
|
|
@@ -172,6 +75,61 @@ Prefer to write tests yourself? They can be JS **or** TS
|
|
|
172
75
|
|
|
173
76
|
</details>
|
|
174
77
|
|
|
78
|
+
## ① Lint — your CLAUDE.md lies to your agent
|
|
79
|
+
|
|
80
|
+
Your CLAUDE.md points the agent at `src/auth/login.ts` and tells it to run
|
|
81
|
+
`npm run check`. But the file moved to `src/auth/session.ts` six commits ago, and
|
|
82
|
+
the script was renamed. The agent trusts the stale claim and acts on fiction.
|
|
83
|
+
|
|
84
|
+
`npx vigiles lint` resolves every reference against reality:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
CLAUDE.md:
|
|
88
|
+
✗ src/auth/login.ts — no such file (renamed or moved?)
|
|
89
|
+
✗ npm run check — not in package.json. Did you mean: "check:types"?
|
|
90
|
+
✓ @typescript-eslint/no-floating-promises — exists and enabled in eslint config
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
File paths, scripts, and code symbols — plus linter rules across **7 catalogs**
|
|
94
|
+
(the rule exists **and is enabled**). Start with one inline comment, no new files;
|
|
95
|
+
step up to a typed `.spec.ts` (compiled to CLAUDE.md, compiler-grade) when you want
|
|
96
|
+
it. **[Full guide →](docs/verifying-instruction-files.md)**
|
|
97
|
+
|
|
98
|
+
## ② Test — does your harness do its job?
|
|
99
|
+
|
|
100
|
+
A hook can be wired wrong. A skill's description can fail to trigger — or hijack
|
|
101
|
+
unrelated prompts. Injected context can never reach the model. All of it passes a
|
|
102
|
+
naive "did it run?" check. vigiles tests the assembled harness for real:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { runHook } from "vigiles/testing";
|
|
106
|
+
|
|
107
|
+
const r = runHook(guard, {
|
|
108
|
+
hook_event_name: "PreToolUse",
|
|
109
|
+
tool_name: "Bash",
|
|
110
|
+
tool_input: { command: "git commit --no-verify" },
|
|
111
|
+
});
|
|
112
|
+
assert(r.blocked); // a red ✗ means your guard silently lets it through
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
It goes well past _"did it fire?"_:
|
|
116
|
+
|
|
117
|
+
- **Hooks block** what they must — `runHook`, or the real agent CLI via `runHarnessTest`.
|
|
118
|
+
- **Skills trigger** on the right prompts and stay quiet on the wrong ones — recall _and_ precision (`measureTriggerRate`).
|
|
119
|
+
- **Behaviour is good** — score a skill's output directly, or A/B it on-vs-off for the real lift over no-skill (`measure` / `runEval`, with significance testing).
|
|
120
|
+
- **Safety holds** — the agent _didn't_ push to the wrong branch or hit a paid API; `interceptTools` catches the attempt so the side effect never happens.
|
|
121
|
+
|
|
122
|
+
**The eval you can actually afford.** Almost every tier runs with **no model and
|
|
123
|
+
no API key** — milliseconds, on every commit. The rest drive your own `claude` CLI:
|
|
124
|
+
|
|
125
|
+
| | Runs on | Cost |
|
|
126
|
+
| ---------------------- | ----------------------- | ------------------------------------------- |
|
|
127
|
+
| promptfoo, DeepEval, … | metered API SDK | billed **per token, every run** |
|
|
128
|
+
| **vigiles** | your Claude Pro/Max sub | **$0 extra** — and most tiers need no model |
|
|
129
|
+
|
|
130
|
+
That's why you can eval your harness on every change, not just once.
|
|
131
|
+
**[How it works →](docs/harness-testing.md)** · **[Why it's affordable →](docs/eval-architecture.md)** · **[Safety model →](docs/safety.md)**
|
|
132
|
+
|
|
175
133
|
## More
|
|
176
134
|
|
|
177
135
|
- **[CLI & GitHub Action →](docs/cli.md)** — every command, the Action (inputs / output / versioning), the Claude Code plugin, and the five `lint` rules.
|
|
@@ -182,3 +140,5 @@ Prefer to write tests yourself? They can be JS **or** TS
|
|
|
182
140
|
## License
|
|
183
141
|
|
|
184
142
|
[MIT](LICENSE)
|
|
143
|
+
|
|
144
|
+
[^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_).
|
package/package.json
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigiles",
|
|
3
|
-
"version": "5.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "5.0.1",
|
|
4
|
+
"description": "Lint & test the harness your AI agent runs on — verify the references in your CLAUDE.md / AGENTS.md and test that your hooks and skills actually work.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude-code",
|
|
7
|
+
"codex",
|
|
8
|
+
"agents",
|
|
9
|
+
"agentic",
|
|
10
|
+
"ai",
|
|
11
|
+
"llm",
|
|
12
|
+
"harness",
|
|
13
|
+
"hooks",
|
|
14
|
+
"skills",
|
|
15
|
+
"claude",
|
|
16
|
+
"agents-md",
|
|
17
|
+
"eval",
|
|
18
|
+
"testing",
|
|
19
|
+
"linter"
|
|
20
|
+
],
|
|
21
|
+
"homepage": "https://github.com/zernie/vigiles#readme",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/zernie/vigiles.git"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/zernie/vigiles/issues"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
5
30
|
"bin": {
|
|
6
31
|
"vigiles": "dist/cli.js"
|
|
7
32
|
},
|
|
@@ -46,7 +71,6 @@
|
|
|
46
71
|
"lint": "eslint src/",
|
|
47
72
|
"fmt": "prettier --write .",
|
|
48
73
|
"fmt:check": "prettier --check .",
|
|
49
|
-
"demo": "npm run build && bash examples/demo/run.sh",
|
|
50
74
|
"test:unit": "npm run build && vitest run --project unit",
|
|
51
75
|
"test:integration": "npm run build && vitest run --project integration",
|
|
52
76
|
"test:e2e": "npm run build && vitest run --project e2e",
|
|
@@ -56,7 +80,6 @@
|
|
|
56
80
|
"test:vitest": "npm run build && vitest run --project runners",
|
|
57
81
|
"test:jest": "npm run build && jest",
|
|
58
82
|
"test:types": "npm run build && tsc --noEmit -p test/types/tsconfig.json",
|
|
59
|
-
"demo:plugin": "npm run build && node examples/plugin-test-demo.mjs",
|
|
60
83
|
"api:report": "npm run build && node scripts/api-extractor.mjs --local",
|
|
61
84
|
"api:check": "npm run build && node scripts/api-extractor.mjs",
|
|
62
85
|
"docs:api": "npm run api:report && api-documenter markdown -i temp -o api-reference"
|