@chimix/agentscan 1.0.0 → 1.3.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/CHANGELOG.md +234 -0
- package/README.md +207 -68
- package/dist/cli.js +9102 -6630
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<img src="https://img.shields.io/badge/checks-
|
|
9
|
-
<img src="https://img.shields.io/badge/tests-
|
|
8
|
+
<img src="https://img.shields.io/badge/checks-99-111111?style=flat-square" alt="99 checks">
|
|
9
|
+
<img src="https://img.shields.io/badge/tests-457%20passing-111111?style=flat-square" alt="457 tests">
|
|
10
10
|
<img src="https://img.shields.io/badge/network-none-111111?style=flat-square" alt="No network">
|
|
11
11
|
<img src="https://img.shields.io/badge/writes-none-111111?style=flat-square" alt="Writes nothing">
|
|
12
12
|
<img src="https://img.shields.io/badge/runs%20on-node%20%C2%B7%20bun-111111?style=flat-square" alt="Node or Bun">
|
|
13
13
|
<img src="https://img.shields.io/npm/v/@chimix/agentscan?style=flat-square&color=111111&label=npm" alt="npm version">
|
|
14
14
|
<img src="https://img.shields.io/badge/license-MIT-111111?style=flat-square" alt="MIT license">
|
|
15
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-1.
|
|
15
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-1.3.0-111111?style=flat-square" alt="Changelog"></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
19
|
-
<strong>
|
|
20
|
-
<sub>An offline linter for Claude Code, portable Agent Skills, nested AGENTS.md, and the MCP / hooks / rules surfaces that 1.
|
|
19
|
+
<strong>99 checks · offline · 0 network calls on <code>check</code> · provenance on every rule</strong><br>
|
|
20
|
+
<sub>An offline linter for Claude Code, Command Code, Grok Build, Windsurf, portable Agent Skills, nested AGENTS.md, Copilot CLI hooks, and the MCP / hooks / rules surfaces that 1.3.0 actually implements. Spec-required checks cite a published line in <a href="docs/spec/">docs/spec/</a>. Heuristics stay at <code>info</code> and say so. The coverage matrix below is the honesty contract — five dimensions, and a documented global location that is not scanned stays unread.</sub>
|
|
21
21
|
</p>
|
|
22
22
|
|
|
23
23
|
---
|
|
@@ -63,9 +63,9 @@ of the filesystem**, where nothing else in your stack will ever tell you.
|
|
|
63
63
|
No AI, no network on `check`. Read the config, read the disk, compare:
|
|
64
64
|
|
|
65
65
|
```
|
|
66
|
-
1. Discover .claude/ .agents/ .vscode/ .cursor/ .codex/ .gemini/ .github/ .continue/ AGENTS.md skills-lock.json
|
|
66
|
+
1. Discover .claude/ .commandcode/ .grok/ .agents/ .vscode/ .cursor/ .codex/ .gemini/ .github/ .continue/ AGENTS.md skills-lock.json
|
|
67
67
|
2. Extract immutable facts — never re-read during checking
|
|
68
|
-
3. Check
|
|
68
|
+
3. Check 99 checks, each labeled spec-required, vendor-recommendation,
|
|
69
69
|
security, internal-consistency, or heuristic
|
|
70
70
|
4. Report text · --json · --output prompt (handoff for a fixing agent)
|
|
71
71
|
```
|
|
@@ -116,10 +116,10 @@ too close to an unrelated `agent-scan`. The command you type stays `agentscan`.
|
|
|
116
116
|
bun add -d @chimix/agentscan # then: bunx agentscan check
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
-
Point it at a project that actually has agent config — a `.claude
|
|
120
|
-
an `.mcp.json`, an `AGENTS.md`. A directory with
|
|
121
|
-
`package.json` is still scannable. On a directory with
|
|
122
|
-
clear error.
|
|
119
|
+
Point it at a project that actually has agent config — a `.claude/`,
|
|
120
|
+
`.commandcode/`, or `.grok/` directory, an `.mcp.json`, an `AGENTS.md`. A directory with
|
|
121
|
+
agent config and no `package.json` is still scannable. On a directory with
|
|
122
|
+
neither it exits with a clear error.
|
|
123
123
|
|
|
124
124
|
```bash
|
|
125
125
|
# what it could possibly report, before you run it
|
|
@@ -186,7 +186,7 @@ Flags for `check`:
|
|
|
186
186
|
| `--verbose` | Show KEEP + info-severity findings, and print each finding's id |
|
|
187
187
|
| `--fail-on <level>` | `never` (default) · `warning` · `error` |
|
|
188
188
|
| `--fail-under <0-100>` | Fail when the score drops below this floor |
|
|
189
|
-
| `--global` | Also scan `~/.claude/skills`
|
|
189
|
+
| `--global` | Also scan `~/.claude/skills`, `~/.codex/skills`, `$CODEX_HOME` / `~/.codex/config.toml`, `~/.commandcode/skills`, `~/.agents/skills`, and `$GROK_HOME` / `~/.grok` (see below) |
|
|
190
190
|
| `--config <path>` | Config file path |
|
|
191
191
|
|
|
192
192
|
**v1 does not write the tree** — no `apply`, no skill delete/install. Findings may *suggest* shell commands; you run them yourself.
|
|
@@ -199,7 +199,7 @@ Flags for `check`:
|
|
|
199
199
|
│ ⌒ │ 6 error · 2 warning · 11 info hidden (--verbose)
|
|
200
200
|
└─────┘
|
|
201
201
|
|
|
202
|
-
agentscan v1.
|
|
202
|
+
agentscan v1.3.0 — touchagency
|
|
203
203
|
|
|
204
204
|
Scanned: 46 deps · 108 skills · 1 mcp · 2 agents · packageManager=bun
|
|
205
205
|
|
|
@@ -231,7 +231,7 @@ JSON shape (abridged):
|
|
|
231
231
|
|
|
232
232
|
```json
|
|
233
233
|
{
|
|
234
|
-
"version": "1.
|
|
234
|
+
"version": "1.3.0",
|
|
235
235
|
"root": "/path/to/project",
|
|
236
236
|
"factsSummary": {
|
|
237
237
|
"packageManager": "bun",
|
|
@@ -259,10 +259,18 @@ Same tree → same sorted findings, with stable unique `id`s.
|
|
|
259
259
|
|
|
260
260
|
### `--global`
|
|
261
261
|
|
|
262
|
-
Adds `~/.claude/skills
|
|
263
|
-
`
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
Adds `~/.claude/skills`, `~/.codex/skills`, `~/.commandcode/skills`,
|
|
263
|
+
`~/.agents/skills`, `$CODEX_HOME` / `~/.codex` (`config.toml` MCP plus
|
|
264
|
+
`AGENTS.override.md` / `AGENTS.md`), and `$GROK_HOME` / `~/.grok` (skills,
|
|
265
|
+
hooks, `config.toml`) to the structural checks: a `SKILL.md` that is malformed
|
|
266
|
+
is malformed wherever it lives, and those findings carry a `source: global`
|
|
267
|
+
evidence entry so you can tell them apart. Codex and Command Code skills use
|
|
268
|
+
the Agent Skills contract (`name` and `description` required). Grok skills do
|
|
269
|
+
not — `name` and `description` are optional. `--global` also inventories user
|
|
270
|
+
Command Code agents (`~/.commandcode/agents`), MCP (`~/.commandcode/mcp.json`
|
|
271
|
+
and user settings `mcp.servers`), and memory (`~/.commandcode/AGENTS.md`). It
|
|
272
|
+
never opens `auth.json`, `mcp-tokens.json`, Codex `auth.json`, or Grok
|
|
273
|
+
`auth.json` / `mcp_credentials.json`.
|
|
266
274
|
|
|
267
275
|
Lockfile checks stay project-scoped — a project lockfile cannot pin a skill that
|
|
268
276
|
lives in your home directory, so reporting one as "not in the lockfile" could
|
|
@@ -342,8 +350,8 @@ Optional `.agentscanrc.json` (create with `agentscan init`):
|
|
|
342
350
|
|
|
343
351
|
```json
|
|
344
352
|
{
|
|
345
|
-
"skillPaths": [".agents/skills", ".claude/skills", "skills", ".cursor/skills", ".codex/skills"],
|
|
346
|
-
"mcpPaths": [".mcp.json", ".claude/mcp.json", "mcp.json", ".vscode/mcp.json", ".cursor/mcp.json", ".agents/mcp_config.json", ".codex/config.toml"],
|
|
353
|
+
"skillPaths": [".agents/skills", ".claude/skills", "skills", ".cursor/skills", ".codex/skills", ".commandcode/skills"],
|
|
354
|
+
"mcpPaths": [".mcp.json", ".claude/mcp.json", "mcp.json", ".vscode/mcp.json", ".cursor/mcp.json", ".agents/mcp_config.json", ".codex/config.toml", ".gemini/settings.json", "opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc", ".continue/config.yaml", ".continue/mcpServers"],
|
|
347
355
|
"policyFiles": ["AGENTS.md", "CLAUDE.md"],
|
|
348
356
|
"ignoreSkills": [],
|
|
349
357
|
"ignoreRules": [],
|
|
@@ -352,8 +360,8 @@ Optional `.agentscanrc.json` (create with `agentscan init`):
|
|
|
352
360
|
"includeGlobal": false,
|
|
353
361
|
"requireLock": false,
|
|
354
362
|
"thresholds": {
|
|
355
|
-
"
|
|
356
|
-
"
|
|
363
|
+
"skillListingChars": 8000,
|
|
364
|
+
"skillListingMaxDescChars": 1536,
|
|
357
365
|
"mcp": 5,
|
|
358
366
|
"agentsMdLines": 150,
|
|
359
367
|
"claudeMdLines": 200,
|
|
@@ -434,29 +442,69 @@ internal-consistency, or heuristic. `agentscan rules` lists them all.
|
|
|
434
442
|
| `claude.agent.missing-frontmatter` | error | A Claude agent definition with no `---` block |
|
|
435
443
|
| `claude.agent.missing-description` | error | Claude agent frontmatter has no `description` |
|
|
436
444
|
| `claude.agent.missing-name` | error | Claude agent frontmatter has no `name` |
|
|
437
|
-
| `claude.agent.invalid-name` | warning | Claude agent name is not lowercase letters
|
|
445
|
+
| `claude.agent.invalid-name` | warning | Claude agent name is not lowercase letters and hyphens (error if it starts with `-` or contains `:`; filename is not compared) |
|
|
438
446
|
| `claude.agent.duplicate-name` | error | Multiple Claude agent files declare the same name |
|
|
439
447
|
| `claude.mcp.no-launch` | error | A Claude MCP server with neither `command` nor `url` |
|
|
440
|
-
| `claude.mcp.url-without-type` | error | A Claude remote MCP server with a `url` but no `type` — read as stdio and skipped |
|
|
448
|
+
| `claude.mcp.url-without-type` | error | A Claude remote MCP server with a `url` but no `type` — read as stdio and skipped. On shared `.mcp.json`, a Command Code `transport` field satisfies the other consumer and this check does not fire |
|
|
449
|
+
| `claude.mcp.reserved-name` | error | A Claude-consumed MCP server named with a reserved identifier (`workspace`, `claude-in-chrome`, `computer-use`, `Claude Preview`, `Claude Browser`) — skipped at load |
|
|
441
450
|
| `vscode.mcp.no-launch` | error | A VS Code MCP server (`servers`) with neither `command` nor `url` |
|
|
442
451
|
| `cursor.mcp.no-launch` | error | A Cursor MCP server with neither `command` nor `url` |
|
|
443
452
|
| `antigravity.mcp.no-launch` | error | An Antigravity MCP server with neither `command` nor `serverUrl` |
|
|
444
453
|
| `codex.mcp.no-launch` | error | A Codex `[mcp_servers.*]` entry with neither `command` nor `url` |
|
|
445
454
|
| `gemini.mcp.no-launch` | error | A Gemini MCP server with neither `command`, `url`, nor `httpUrl` |
|
|
455
|
+
| `gemini.mcp.underscore-alias` | warning | A Gemini MCP server alias contains `_`, which can make policies fail silently |
|
|
446
456
|
| `opencode.mcp.no-launch` | error | An OpenCode MCP server with neither `command` nor `url` |
|
|
447
457
|
| `opencode.mcp.missing-type` | error | An OpenCode MCP server missing `type: local` or `type: remote` |
|
|
448
458
|
| `opencode.mcp.local-without-command` | error | An OpenCode `type: local` server with no `command` |
|
|
449
459
|
| `opencode.mcp.remote-without-url` | error | An OpenCode `type: remote` server with no `url` |
|
|
450
460
|
| `opencode.mcp.invalid-launch-for-type` | error | An OpenCode server whose launch field does not match its `type` |
|
|
461
|
+
| `opencode.mcp.command-not-array` | error | An OpenCode V2 local `command` that is not an argv array |
|
|
451
462
|
| `continue.mcp.no-launch` | error | A Continue MCP server with neither `command`, `url`, nor `uses` |
|
|
463
|
+
| `continue.mcp.missing-block-metadata` | error | A standalone `.continue/mcpServers/*.yaml` block missing `name`, `version`, or `schema` (not applied to copied JSON) |
|
|
464
|
+
| `commandcode.mcp.no-launch` | error | A Command Code settings / user MCP server with neither `command` nor `url` |
|
|
465
|
+
| `commandcode.mcp.invalid-transport` | error | A Command Code MCP `transport` / `type` that is not `http` or `stdio` (Claude `sse` / `ws` on shared `.mcp.json` is skipped) |
|
|
466
|
+
| `commandcode.mcp.http-without-url` | error | A Command Code HTTP MCP server with no `url` |
|
|
467
|
+
| `commandcode.mcp.stdio-without-command` | error | A Command Code stdio MCP server with no `command` |
|
|
452
468
|
| `claude.hook.command-without-command` | error | A Claude `type: command` hook with no `command` |
|
|
453
|
-
| `claude.hook.
|
|
469
|
+
| `claude.hook.http-without-url` | error | A Claude `type: http` hook with no `url` |
|
|
470
|
+
| `claude.hook.mcp-tool-without-server-or-tool` | error | A Claude `type: mcp_tool` hook missing `server` or `tool` |
|
|
471
|
+
| `claude.hook.unknown-handler-type` | error | A Claude hook whose required `type` is missing or not one of command, http, mcp_tool, prompt, agent |
|
|
472
|
+
| `claude.hook.prompt-without-prompt` | error | A Claude `type: prompt` or `type: agent` hook with no `prompt` |
|
|
473
|
+
| `claude.hook.incompatible-handler` | error | A Claude handler type that the event does not support |
|
|
474
|
+
| `claude.hook.invalid-group` | error | A Claude hook matcher group with no nested `hooks` array (flat handler arrays are invalid) |
|
|
475
|
+
| `vscode.hook.invalid-group` | error | A VS Code hook group that is not a command handler array |
|
|
476
|
+
| `vscode.hook.command-without-command` | error | A native VS Code `type: command` hook with no `command` |
|
|
477
|
+
| `vscode.hook.unknown-handler-type` | error | A native VS Code hook whose `type` is not `command` |
|
|
478
|
+
| `copilot.hook.unknown-event` | error | A Copilot CLI hook registered under an event that is never dispatched |
|
|
479
|
+
| `copilot.hook.missing-script` | error | A Copilot CLI command hook whose script does not exist |
|
|
480
|
+
| `copilot.hook.command-without-command` | error | A Copilot CLI command hook with none of `bash`, `powershell`, or `command` |
|
|
481
|
+
| `copilot.hook.http-without-url` | error | A Copilot CLI `type: http` hook with no `url` |
|
|
482
|
+
| `copilot.hook.prompt-without-prompt` | error | A Copilot CLI `type: prompt` hook with no `prompt` |
|
|
483
|
+
| `copilot.hook.unknown-handler-type` | error | A Copilot CLI hook whose `type` is not command, http, or prompt |
|
|
484
|
+
| `copilot.hook.incompatible-handler` | error | A Copilot CLI prompt hook registered on an event other than `sessionStart` |
|
|
485
|
+
| `commandcode.hook.unknown-event` | error | A Command Code hook registered under an event that is never dispatched (four events only) |
|
|
486
|
+
| `commandcode.hook.missing-script` | error | A Command Code command hook whose script does not exist |
|
|
487
|
+
| `commandcode.hook.invalid-group` | error | A Command Code hook group missing the required nested `hooks` array, or a non-string `matcher` |
|
|
488
|
+
| `commandcode.hook.command-without-command` | error | A Command Code `type: command` hook whose `command` is missing, empty, or not a string |
|
|
489
|
+
| `commandcode.hook.unknown-handler-type` | error | A Command Code hook whose `type` is missing, not a string, or not `"command"` |
|
|
490
|
+
| `commandcode.hook.timeout-out-of-bounds` | error | A Command Code hook `timeout` outside 0–600 seconds |
|
|
491
|
+
| `commandcode.agent.reserved-name` | error | A Command Code custom agent named `explore`, `plan`, `review`, or `general` — ignored at load |
|
|
492
|
+
| `commandcode.agent.invalid-permission-mode` | error | A Command Code agent `permissionMode` that is not a documented value |
|
|
493
|
+
| `commandcode.agent.invalid-field-type` | error | A Command Code agent field whose type the spec does not accept |
|
|
494
|
+
| `grok.mcp.no-launch` | error | A Grok `[mcp_servers.*]` entry with neither `command` nor `url` |
|
|
495
|
+
| `grok.hook.unknown-event` | error | A Grok hook registered under an event that is never dispatched (14 events) |
|
|
496
|
+
| `grok.hook.missing-script` | error | A Grok command hook whose script does not exist |
|
|
497
|
+
| `grok.hook.invalid-group` | error | A Grok hook group missing the required nested `hooks` array, or a non-string `matcher` |
|
|
498
|
+
| `grok.hook.command-without-command` | error | A Grok `type: command` hook with no `command` |
|
|
499
|
+
| `grok.hook.http-without-url` | error | A Grok `type: http` hook with no `url` |
|
|
500
|
+
| `grok.hook.unknown-handler-type` | error | A Grok hook whose `type` is missing or not `command` / `http` |
|
|
501
|
+
| `grok.skill.missing-frontmatter` | warning | Grok `SKILL.md` with no `---` block |
|
|
454
502
|
| `mcp.command-missing` | error | An MCP `command` that is a path-like value whose file does not exist on disk |
|
|
455
503
|
| `security.hardcoded-secret` | error | A token-shaped literal in MCP config (the value is never echoed back) |
|
|
456
504
|
| `mcp.literal-env` | warning | Secret-named `env` values that are literals instead of interpolation |
|
|
457
505
|
| `skill.missing-skill-md` | warning | A directory under a skill path with no `SKILL.md` |
|
|
458
506
|
| `claude.skill.missing-frontmatter` | warning | Claude `SKILL.md` with no `---` block |
|
|
459
|
-
| `claude.skill.missing-description` | info | Claude frontmatter has no `description`
|
|
507
|
+
| `claude.skill.missing-description` | info | Claude frontmatter has no `description` and no first markdown paragraph |
|
|
460
508
|
| `agent-skills.skill.missing-frontmatter` | error | Portable skill `SKILL.md` has no YAML frontmatter |
|
|
461
509
|
| `agent-skills.skill.missing-name` | error | Portable skill frontmatter has no required `name` |
|
|
462
510
|
| `agent-skills.skill.missing-description` | error | Portable skill frontmatter has no required `description` |
|
|
@@ -464,11 +512,15 @@ internal-consistency, or heuristic. `agentscan rules` lists them all.
|
|
|
464
512
|
| `agent-skills.skill.name-does-not-match-directory` | error | Portable skill `name` does not match its directory |
|
|
465
513
|
| `agent-skills.skill.name-too-long` | error | Portable skill name exceeds 64 characters |
|
|
466
514
|
| `agent-skills.skill.description-too-long` | error | Portable skill description exceeds 1024 characters |
|
|
515
|
+
| `agent-skills.skill.invalid-compatibility` | error | Portable skill `compatibility` is present but is not a 1–500 character string |
|
|
516
|
+
| `agent-skills.skill.invalid-metadata` | error | Portable skill `metadata` is present but is not `map<string, string>` |
|
|
517
|
+
| `agent-skills.skill.invalid-allowed-tools` | error | Portable skill `allowed-tools` is present but is not a string |
|
|
518
|
+
| `agent-skills.skill.body-too-large` | info | Portable skill `SKILL.md` exceeds the 500-line recommendation |
|
|
467
519
|
| `skill.broken-reference` | warning | The body points at a bundled file that does not exist |
|
|
468
520
|
| `skill.duplicate-description` | info | Two or more skills carry an identical description (heuristic) |
|
|
469
521
|
| `skill.locked-not-installed` | warning | `skills-lock.json` pins a skill that is not on disk |
|
|
470
522
|
| `skill.not-in-lock` | info | A skill on disk that the lockfile does not track (installer policy) |
|
|
471
|
-
| `skill.description-budget` | info | Claude skill
|
|
523
|
+
| `skill.description-budget` | info | Claude skill listing text (description or first paragraph, plus `when_to_use`) exceeds the 1% context-window budget, with an 8000-character fallback and a 1536-character per-entry cap |
|
|
472
524
|
| `skill.no-lockfile` | info | Skills present with no lockfile at all (only with `requireLock`) |
|
|
473
525
|
| `budget.agents-md` | info | `AGENTS.md` past a secondary 150-line hint (heuristic; not an AGENTS.md requirement) |
|
|
474
526
|
| `budget.claude-md` | info | `CLAUDE.md` past the official “target under 200 lines” recommendation |
|
|
@@ -476,45 +528,62 @@ internal-consistency, or heuristic. `agentscan rules` lists them all.
|
|
|
476
528
|
| `budget.mcp` | info | More MCP servers than a tool-selection hint (>5) — heuristic proxy |
|
|
477
529
|
| `codex.budget.instructions` | info | Codex root→cwd `AGENTS.md` chain exceeds the default 32 KiB |
|
|
478
530
|
| `cursor.rule.too-large` | info | A `.cursor/rules/*.mdc` file exceeds the 500-line recommendation |
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
`
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
|
498
|
-
|
|
499
|
-
|
|
|
500
|
-
|
|
|
501
|
-
|
|
|
502
|
-
|
|
|
503
|
-
|
|
504
|
-
|
|
531
|
+
| `windsurf.rule.too-large` | info | A Windsurf workspace rule exceeds 12,000 characters |
|
|
532
|
+
| `windsurf.rule.global-too-large` | info | `~/.codeium/windsurf/memories/global_rules.md` exceeds 6,000 characters |
|
|
533
|
+
| `windsurf.rule.missing-trigger` | warning | A `.devin/rules` / `.windsurf/rules` file omits frontmatter `trigger` |
|
|
534
|
+
| `windsurf.mcp.no-launch` | error | Windsurf MCP server declares neither `command`, `serverUrl`, nor `url` |
|
|
535
|
+
|
|
536
|
+
### Coverage in 1.3.0
|
|
537
|
+
|
|
538
|
+
Each cell is one coverage dimension. There is no `full` / `partial` label: a
|
|
539
|
+
documented global or static location that is not opened stays **unread**.
|
|
540
|
+
|
|
541
|
+
Dimensions:
|
|
542
|
+
|
|
543
|
+
- **project discovery** — documented in-repo files the scanner opens
|
|
544
|
+
- **global discovery** — documented user / machine locations; `--global` is named when that is the only path that opens them
|
|
545
|
+
- **schema** — spec-required (and labeled vendor-recommendation) field checks
|
|
546
|
+
- **precedence** — documented merge / override / shadowing
|
|
547
|
+
- **conformance** — official-shaped fixture or equivalent negative tests
|
|
548
|
+
|
|
549
|
+
| Ecosystem | project discovery | global discovery | schema | precedence | conformance |
|
|
550
|
+
|-----------|-------------------|------------------|--------|------------|-------------|
|
|
551
|
+
| Agent Skills | `.agents/skills` (and Cursor / Codex / Command Code skill trees) | `--global` `~/.agents/skills`, `~/.codex/skills` | required `name` / `description` plus optional `compatibility` / `metadata` / `allowed-tools`; 500-line info | n/a | `agent-skills` fixture |
|
|
552
|
+
| AGENTS.md | nested walk-up | n/a | no required fields | nearest-wins | tests |
|
|
553
|
+
| Claude Code | project settings, skills, agents, `CLAUDE.md`, `.mcp.json` / `.claude/mcp.json` | unread `~/.claude/settings.json`, managed policy, marketplace plugins | 33 events; required handler `type`; MCP reserved names; first-paragraph skill description; listing budget | walk-up `CLAUDE.md` / `.claude/agents` | `claude-json` fixture |
|
|
554
|
+
| Command Code | git-root project files; per-directory `AGENTS.md` else `.commandcode/AGENTS.md` | `--global` `~/.commandcode/*`; unread `projects/{slug}/mcp.json` | 4 events; command handlers; Agent Skills; MCP `transport` / `type` | settings merge; project+user hooks coexist; skill/MCP shadow | `commandcode` fixture |
|
|
555
|
+
| Codex | `.codex/config.toml`, `.codex/skills`, AGENTS chain | `--global` `$CODEX_HOME` / `~/.codex/config.toml` MCP; `AGENTS.override.md` then `AGENTS.md`; unread system, managed, requirements, profiles, plugins, trust | TOML MCP; `project_doc_max_bytes`; Agent Skills | override > `AGENTS.md` > fallbacks; one file per dir; root→cwd; `project_root_markers`; MCP user+project both inventoried | `codex-toml` fixture |
|
|
556
|
+
| VS Code | `.github/hooks` without `version: 1`, instruction files, `.github/agents`, `.vscode/mcp.json` | `--global` `~/.copilot/hooks` without `version: 1`; unread policy dirs | 8 events; command-only | workspace over user | `vscode-hooks`, `vscode-json` |
|
|
557
|
+
| Copilot CLI | `.github/hooks` with `version: 1` | `--global` `~/.copilot/hooks` with `version: 1`; unread `/etc/github-copilot/policy.d` | camelCase + PascalCase map; `bash` / `powershell` / `command`; `cwd`; `timeoutSec`; prompt on `sessionStart` | documented sources coexist; policy unread | `copilot-hooks` fixture |
|
|
558
|
+
| Cursor | nested `.cursor/skills`, `.cursor/mcp.json`, `.cursor/rules` | unread documented Cursor user/global paths | Agent Skills; MCP launch; 500-line rules | n/a | `cursor-json` fixture |
|
|
559
|
+
| Grok | `.grok/config.toml` walk-up; `.grok/hooks/*.json`; `.grok/skills`; `.grok/rules/*.md`; `Agents.md` / `AGENT.md` | `--global` `$GROK_HOME` or `~/.grok` config/hooks/skills; unread managed, requirements, plugins, `[skills] paths`, agents, credentials | `command` / `url` MCP (no `type`); 14 events; command/http; frontmatter required, name/description optional; no rules cap | closer project wins; project same-name replaces user | `grok-toml` fixture |
|
|
560
|
+
| Antigravity | `.agents/mcp_config.json` | none | `serverUrl` launch | n/a | `antigravity-json` fixture |
|
|
561
|
+
| Gemini | `.gemini/settings.json` | unread `~/.gemini/settings.json` unless `--global` is wired for it (it is not) | `command` / `url` / `httpUrl`; underscore-alias warning | n/a | `gemini-json` fixture |
|
|
562
|
+
| Windsurf | `.devin/rules/*.md` (preferred), `.windsurf/rules/*.md` (fallback), `.windsurfrules`; portable `AGENTS.md` / `agents.md` | `--global` `~/.codeium/windsurf/mcp_config.json` and `~/.codeium/windsurf/memories/global_rules.md`; unread auto memories, Devin CLI MCP, system `/etc/devin/rules` | 12k / 6k character rules; workspace `trigger`; MCP `command` / `serverUrl` / `url` (no `type`) | n/a (no project MCP; both rule trees inventoried) | `windsurf-rules` fixture |
|
|
563
|
+
| Kiro | none | none | none | n/a | none |
|
|
564
|
+
| Cline | none | none | none | n/a | none |
|
|
565
|
+
| Roo | none | none | none | n/a | none |
|
|
566
|
+
| Kilo | none | none | none | n/a | none |
|
|
567
|
+
| OpenCode | `opencode.json(c)` V1 and V2 | none | V2 local `command` must be an argv array | n/a | `opencode-json` fixture |
|
|
568
|
+
| Junie | none | none | none | n/a | none |
|
|
569
|
+
| Continue | `.continue/config.yaml`, `.continue/mcpServers/*` | none | launch `command` / `url` / `uses`; standalone YAML `name` / `version` / `schema` | n/a | `continue-yaml`, `continue-mcpservers` |
|
|
570
|
+
|
|
571
|
+
Cursor project rules (`.cursor/rules/**/*.mdc`) are a separate surface: discovery plus `cursor.rule.too-large` at info. Claude `.claude/rules/**/*.md` is inventoried and has no published line budget. Windsurf workspace rules use a 12,000-character budget (`windsurf.rule.too-large`); do not apply the Cursor 500-line check. Portable `AGENTS.md` / `agents.md` stay `sourceProvider: unknown` — this scanner does not claim exclusive Windsurf ownership.
|
|
505
572
|
|
|
506
573
|
Old 0.7 rule ids still work in `ignoreRules` and `explain` (for example `hook.missing-script` aliases `claude.hook.missing-script`).
|
|
507
574
|
|
|
508
|
-
Agent definitions are checked for structure only.
|
|
509
|
-
is not compared to the filename; it must
|
|
510
|
-
and unique.
|
|
511
|
-
|
|
512
|
-
|
|
575
|
+
Agent definitions are checked for structure only. A Claude agent's frontmatter
|
|
576
|
+
`name` is not compared to the filename; it must be lowercase letters and
|
|
577
|
+
hyphens and unique. Command Code supplies `name` from the filename when
|
|
578
|
+
frontmatter omits it, and does not emit missing-name or missing-description.
|
|
579
|
+
Model identifiers and tool names are likewise not validated: both would need a
|
|
580
|
+
hardcoded list, which is the shape that already shipped a false error. See
|
|
581
|
+
[plans/003](plans/003-validate-agent-definitions.md).
|
|
513
582
|
|
|
514
583
|
`skill.broken-reference` reads the body, not just the frontmatter. It looks for
|
|
515
584
|
paths under the conventional bundled directories (`scripts/`, `references/`,
|
|
516
|
-
`assets/`, `templates/`, `examples/`)
|
|
517
|
-
|
|
585
|
+
`assets/`, `templates/`, `examples/`). Agent Skills references resolve from the
|
|
586
|
+
skill root only. Claude native skills also try the repo root — of 1674
|
|
518
587
|
references measured across 17 projects, 1645 resolved skill-relative and 12 only
|
|
519
588
|
at the root. Fenced code blocks are stripped first: a path in an example is
|
|
520
589
|
illustration, not a pointer.
|
|
@@ -522,7 +591,8 @@ illustration, not a pointer.
|
|
|
522
591
|
### Where it looks for hooks
|
|
523
592
|
|
|
524
593
|
The Claude hooks reference lists seven places a hook can be registered. agentscan
|
|
525
|
-
reads the four that live inside the scanned project, plus VS Code workspace hooks
|
|
594
|
+
reads the four that live inside the scanned project, plus VS Code workspace hooks
|
|
595
|
+
and Command Code settings hooks:
|
|
526
596
|
|
|
527
597
|
| Registered in | Script paths resolve against |
|
|
528
598
|
|---|---|
|
|
@@ -530,7 +600,12 @@ reads the four that live inside the scanned project, plus VS Code workspace hook
|
|
|
530
600
|
| A plugin's `hooks/hooks.json` (a directory with `.claude-plugin/plugin.json`, or the scan root itself) | the plugin root, `${CLAUDE_PLUGIN_ROOT}` |
|
|
531
601
|
| `SKILL.md` frontmatter | the skill's own directory, then the project root |
|
|
532
602
|
| `.claude/agents/*.md` frontmatter | the agent file's directory, then the project root |
|
|
533
|
-
| `.github/hooks/*.json` (VS Code) | project root and the hooks directory |
|
|
603
|
+
| `.github/hooks/*.json` without `version: 1` (native VS Code) | project root and the hooks directory |
|
|
604
|
+
| `.github/hooks/*.json` with `version: 1` (Copilot CLI) | project root, `cwd`, host `bash` / `powershell` / `command` |
|
|
605
|
+
| `~/.copilot/hooks` under `--global` | same split on `version: 1` |
|
|
606
|
+
| `.commandcode/settings.json` · `.commandcode/settings.local.json` (and user settings under `--global`) | Command Code project root (git root, or cwd outside a git repo), `$COMMANDCODE_PROJECT_DIR`, `$COMMANDCODE_CWD` |
|
|
607
|
+
| `.grok/hooks/*.json` | project root and the hooks directory |
|
|
608
|
+
| `$GROK_HOME/hooks` or `~/.grok/hooks` under `--global` | same Grok 14-event / command-or-http split |
|
|
534
609
|
|
|
535
610
|
`${CLAUDE_PLUGIN_ROOT}` is expanded **only** for a hook that came from a plugin.
|
|
536
611
|
In a settings file it names nothing, so the path is skipped rather than guessed
|
|
@@ -543,17 +618,18 @@ A value is only resolved when it is path-like and the answer is certain; shell
|
|
|
543
618
|
programs (`a && b`, `$(...)`, pipes), bare PATH binaries (`npx`, `uvx`), and
|
|
544
619
|
unresolved env vars are skipped. A false "broken" on a working `npx` server
|
|
545
620
|
would be worse than silence. `node -e "<code>"` is never treated as a path.
|
|
546
|
-
Only `$CLAUDE_PROJECT_DIR
|
|
547
|
-
|
|
548
|
-
shaped entry will start
|
|
621
|
+
Only `$CLAUDE_PROJECT_DIR`, `$COMMANDCODE_PROJECT_DIR`, and `$COMMANDCODE_CWD`
|
|
622
|
+
are expanded — other variables are left alone rather than guessed at. Schema
|
|
623
|
+
checks judge misconfiguration, not whether a correctly shaped entry will start
|
|
624
|
+
at runtime.
|
|
549
625
|
|
|
550
626
|
Spec-required checks are written against published pages, not against what
|
|
551
627
|
happens to appear in real projects. Two that were written the other way round
|
|
552
628
|
shipped as false positives — a nine-name hook-event list where the spec has 31,
|
|
553
629
|
and a `name` must equal the directory rule that Claude's spec explicitly
|
|
554
630
|
contradicts. Both are gone. Heuristics that remain (`skill.duplicate-description`,
|
|
555
|
-
the installer lock checks, and the size budgets other than `budget.claude-md`
|
|
556
|
-
are labeled in the registry and stay at `info`.
|
|
631
|
+
the installer lock checks, and the size budgets other than `budget.claude-md`
|
|
632
|
+
and `skill.description-budget`) are labeled in the registry and stay at `info`.
|
|
557
633
|
|
|
558
634
|
Assumptions are recorded in **[docs/spec/](docs/spec/)** with source URL, read
|
|
559
635
|
date, and provenance. When adding a spec-required check, add its spec line there
|
|
@@ -572,11 +648,52 @@ first.
|
|
|
572
648
|
- **Runtime split.** Source development and the composite Action use Bun; the
|
|
573
649
|
published `dist/cli.js` runs on Node 20.11+ or Bun. The source entrypoint uses
|
|
574
650
|
Bun's `import.meta.dir` / `import.meta.main` and is not the Node entrypoint.
|
|
575
|
-
- **
|
|
651
|
+
- **Grok compatibility and unpublished surfaces are unread.** Managed
|
|
652
|
+
(`~/.grok/managed_config.toml`, `/etc/grok/managed_config.toml`) and
|
|
653
|
+
requirements TOML are not opened. Plugins, marketplaces, personas, and
|
|
654
|
+
`[skills] paths` (no quoted resolution base) stay unread. `.grok/agents/`
|
|
655
|
+
is unread because the page names the directory but not a filename pattern
|
|
656
|
+
or required fields. Claude / Cursor / `.mcp.json` files keep their own
|
|
657
|
+
schemas — this scanner does not add `consumedBy: grok` to them. Grok’s
|
|
658
|
+
“skip gitignored instruction files” is unread: agentscan does not honor
|
|
659
|
+
`.gitignore`. `auth.json` and `mcp_credentials.json` are never opened.
|
|
660
|
+
Spec/runtime Grok MCP checks skip shadowed same-name servers; secrets
|
|
661
|
+
still inspect every readable MCP file.
|
|
662
|
+
- **Codex admin and profile layers are unread.** System `/etc/codex/config.toml`,
|
|
663
|
+
managed preferences, `requirements.toml`, `$CODEX_HOME/<name>.config.toml`
|
|
664
|
+
profiles, plugin MCP, and `trust_level` are not opened. User
|
|
665
|
+
`$CODEX_HOME/config.toml` (or `~/.codex/config.toml`) MCP is scanned only
|
|
666
|
+
under `--global`. `auth.json` is never opened. Same-name user and project
|
|
667
|
+
MCP servers are both inventoried — the published page does not quote a
|
|
668
|
+
replace-entirely rule. User-file `project_doc_*` knobs are not applied.
|
|
669
|
+
- **Command Code local MCP is unread.** `~/.commandcode/projects/{project}/mcp.json`
|
|
670
|
+
is keyed by a working-directory slug that the sessions page does not publish.
|
|
671
|
+
Until it does, that path is skipped rather than guessed. Bundled Command Code
|
|
672
|
+
skills and `--skill` launch flags are not project files and are not scanned.
|
|
673
|
+
`mods.paths` are inventoried; the TypeScript is never executed or imported.
|
|
674
|
+
`auth.json` and `mcp-tokens.json` are never opened. Command Code project
|
|
675
|
+
root is the git root (or cwd outside a git repo); a child `.cursor` does
|
|
676
|
+
not hide `<git-root>/.commandcode/`. Spec/runtime Command Code checks skip
|
|
677
|
+
shadowed lower-precedence definitions; secrets still inspect every readable
|
|
678
|
+
MCP file.
|
|
679
|
+
- **Three Claude hook locations are unread.** `~/.claude/settings.json`, managed policy
|
|
576
680
|
settings, and installed marketplace plugins under `~/.claude/plugins` all sit
|
|
577
681
|
outside the scanned project, and the docs say a plugin's install directory
|
|
578
682
|
changes on every update. A hook registered in one of those, pointing at a
|
|
579
683
|
missing script, is not reported.
|
|
684
|
+
- **Copilot CLI policy hooks are unread.** `/etc/github-copilot/policy.d` and the
|
|
685
|
+
Windows policy directory are machine-wide admin files. User
|
|
686
|
+
`~/.copilot/hooks` is scanned only under `--global`. Inline Copilot
|
|
687
|
+
`.github/copilot/settings.json` hooks are unread.
|
|
688
|
+
- **Gemini user settings are unread.** `~/.gemini/settings.json` is outside a
|
|
689
|
+
normal project scan.
|
|
690
|
+
- **Windsurf Devin CLI MCP and auto memories are unread.** Cascade MCP is
|
|
691
|
+
global-only (`~/.codeium/windsurf/mcp_config.json`, `--global`). The Devin
|
|
692
|
+
Local agent uses unpublished CLI config files — that path is not guessed.
|
|
693
|
+
Auto-generated files under `~/.codeium/windsurf/memories/` other than
|
|
694
|
+
`global_rules.md` are not opened. System / enterprise rule directories
|
|
695
|
+
(`/etc/devin/rules`, `/etc/windsurf/rules`) stay unread. There is no
|
|
696
|
+
quoted project MCP path.
|
|
580
697
|
- **Bounded reads.** A `SKILL.md` is read to 64 KB and a policy file to 100 KB,
|
|
581
698
|
so `skill.broken-reference` and `policyLines` see only that much of a larger
|
|
582
699
|
file. This is reported — `scan.truncated`, at `info` — rather than left
|
|
@@ -590,6 +707,28 @@ Notes for every published version are in [CHANGELOG.md](CHANGELOG.md).
|
|
|
590
707
|
GitHub already has pages for [v0.1.0](https://github.com/SimaAlexandru99/agentscan/releases/tag/v0.1.0)
|
|
591
708
|
and [v0.4.0](https://github.com/SimaAlexandru99/agentscan/releases/tag/v0.4.0).
|
|
592
709
|
|
|
710
|
+
**1.3.0** (31 August 2026) adds native Windsurf / Cascade coverage: workspace
|
|
711
|
+
`.devin/rules` and `.windsurf/rules`, portable `agents.md`, and `--global`
|
|
712
|
+
`mcp_config.json` plus `global_rules.md`. Devin CLI MCP, auto memories,
|
|
713
|
+
system rules, and a project MCP path stay unread.
|
|
714
|
+
|
|
715
|
+
**1.2.1** (31 August 2026) opens Codex user MCP (`$CODEX_HOME/config.toml`
|
|
716
|
+
or `~/.codex/config.toml`) under `--global`. Same-name user and project
|
|
717
|
+
servers are both inventoried. System, managed, requirements, profiles,
|
|
718
|
+
plugins, and `trust_level` stay unread. `auth.json` is never opened.
|
|
719
|
+
|
|
720
|
+
**1.2.0** (31 August 2026) adds a native Grok Build provider: project
|
|
721
|
+
`.grok/*` plus `$GROK_HOME` / `~/.grok/*` under `--global`. Compatibility
|
|
722
|
+
with Claude or Cursor is not schema identity. Agents, managed/requirements
|
|
723
|
+
TOML, plugins, `[skills] paths`, and `.gitignore` skip stay unread.
|
|
724
|
+
|
|
725
|
+
**1.1.0** (31 August 2026) adds a native Command Code provider and finishes the
|
|
726
|
+
correctness pass across registered checks: hook schema profiles, Agent Skills
|
|
727
|
+
optional fields, Claude listing budget, Codex chain knobs, and Copilot CLI
|
|
728
|
+
`version: 1` files. Still offline on `check`. Shared `.mcp.json` is `mcp-json`
|
|
729
|
+
(Claude and Command Code), not Claude-only — that MCP hotfix is **1.0.1** in
|
|
730
|
+
the changelog and ships inside this package version.
|
|
731
|
+
|
|
593
732
|
**1.0.0** (30 August 2026) is the first stable release: 59 checks, 345 tests,
|
|
594
733
|
still offline on `check`. It adds portable Agent Skills (including Cursor and
|
|
595
734
|
Codex skill trees), MCP profiles for VS Code / Cursor / Codex / Antigravity /
|