@jqntn/agentdoctor 0.1.2 → 0.1.3

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 the agentdoctor authors
3
+ Copyright (c) 2026 Julien QUENTIN
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -63,17 +63,24 @@ CLAUDE.md
63
63
  (~$25/month at 3,300 requests, assuming it stays prompt-cached).
64
64
  cost/memory-file-too-large
65
65
 
66
- Summary Grade F 3 errors, 1 warning - 72 rules in 41ms
66
+ Summary Grade F 3 errors, 1 warning (72 rules, 41ms)
67
67
  ```
68
68
 
69
69
  Zero dependencies. No network calls. Credential files are never opened. MIT — all of it.
70
70
 
71
71
  ## What it checks
72
72
 
73
- **72 rules across five categories.** Full reasoning for every rule:
74
- [rule reference](docs/rules.md), or `agentdoctor --explain <rule-id>`.
73
+ Findings fall into five categories. The bar for a rule is that it catches a failure that
74
+ actually happens **and** stays quiet on legitimate config: a correctly configured project
75
+ reports nothing, which the test suite asserts against a fixture. False positives are treated
76
+ as more severe than missed findings, because a linter that cries wolf gets uninstalled and
77
+ then catches nothing at all.
75
78
 
76
- ### Security (22 rules)
79
+ Every rule states what is wrong, why it matters, and what to change instead, and every rule
80
+ has a test. There are 72 today; the current catalogue is always in the
81
+ [rule reference](docs/rules.md), or `agentdoctor --list-rules`.
82
+
83
+ ### Security
77
84
 
78
85
  The config surface is an execution surface. Blanket `Bash(*)` allows; destructive commands
79
86
  pre-approved without confirmation (`sudo`, `rm -rf`, force push, `terraform destroy`,
@@ -83,7 +90,7 @@ Slack, Stripe keys, JWTs, private keys — always reported **redacted**); MCP se
83
90
  unpinned packages or carrying tokens in URLs; `bypassPermissions` committed to shared repos;
84
91
  loader-hijacking env vars; world-writable config.
85
92
 
86
- ### Correctness (26 rules)
93
+ ### Correctness
87
94
 
88
95
  Config that is silently ignored is worse than config that errors, because you believe it is
89
96
  working. Invalid JSON (which voids the whole file, permission rules included); misspelled
@@ -92,7 +99,7 @@ that block nothing (an **error**, because it is a guardrail that only looks like
92
99
  malformed hooks and invalid matcher regexes; duplicate agent/skill names; MCP servers with no
93
100
  way to start.
94
101
 
95
- ### Cost (8 rules)
102
+ ### Cost
96
103
 
97
104
  Memory files and MCP tool schemas ride along on every request. Token counts for every memory
98
105
  file with an estimated monthly cost — the estimate assumes the file stays prompt-cached
@@ -100,13 +107,13 @@ file with an estimated monthly cost — the estimate assumes the file stays prom
100
107
  duplicated across files; pasted code blocks that belong behind a file path; skill
101
108
  descriptions too vague for the model to ever load them.
102
109
 
103
- ### Hygiene (8 rules)
110
+ ### Hygiene
104
111
 
105
112
  `settings.local.json` not gitignored; machine-specific absolute paths in committed config;
106
113
  local settings silently shadowing project settings; empty skill/agent bodies; duplicate
107
114
  keybindings.
108
115
 
109
- ### Policy (8 rules)
116
+ ### Policy
110
117
 
111
118
  Team standards, enforced mechanically across every repo. Commit an
112
119
  `agentdoctor.policy.json` and these activate — no flag, no account:
@@ -151,7 +158,7 @@ unrelated edits never invalidate them:
151
158
 
152
159
  ```sh
153
160
  agentdoctor --write-baseline .agentdoctor-baseline.json # once
154
- agentdoctor --baseline .agentdoctor-baseline.json # in CI
161
+ agentdoctor --baseline .agentdoctor-baseline.json # in CI
155
162
  ```
156
163
 
157
164
  [CI guide](docs/ci.md) · [Baselines](docs/baselines.md)
@@ -164,13 +171,18 @@ deterministic ordering, redacted secrets safe for model context, pipe-safe outpu
164
171
  site serves `llms.txt` and raw markdown.
165
172
 
166
173
  The repo is also a **Claude Code plugin**: it ships the
167
- [config-audit skill](skills/config-audit/SKILL.md) (audit -> fix loop, with fix recipes) and
168
- an `/agentdoctor:audit` command. Install it any of three ways:
174
+ [config-audit skill](plugin/skills/config-audit/SKILL.md) (audit -> fix loop, with fix recipes) and
175
+ invokable as `/agentdoctor:config-audit`. Install it any of three ways:
169
176
 
170
177
  ```
171
- /plugin marketplace add jqntn/agentdoctor # in Claude Code, then: /plugin install agentdoctor
172
- npx @jqntn/agentdoctor --init-skill # copies the skill into this project
173
- cp -r node_modules/@jqntn/agentdoctor/skills/config-audit .claude/skills/ # manual
178
+ # in Claude Code, then: /plugin install agentdoctor
179
+ /plugin marketplace add jqntn/agentdoctor
180
+
181
+ # copies the skill into this project only
182
+ npx @jqntn/agentdoctor --init-skill
183
+
184
+ # by hand, from an installed package
185
+ cp -r node_modules/@jqntn/agentdoctor/plugin/skills/config-audit .claude/skills/
174
186
  ```
175
187
 
176
188
  [Agent guide](docs/agents.md)
@@ -192,7 +204,7 @@ cp -r node_modules/@jqntn/agentdoctor/skills/config-audit .claude/skills/ # ma
192
204
  |---|---|
193
205
  | [Getting started](docs/getting-started.md) | Install, first run, reading findings, exit codes |
194
206
  | [Configuration](docs/configuration.md) | Every flag, suppression, disabling rules |
195
- | [Rule reference](docs/rules.md) | All 72 rules with reasoning |
207
+ | [Rule reference](docs/rules.md) | Every rule, with the reasoning behind it |
196
208
  | [CI setup](docs/ci.md) | GitHub Actions, SARIF, exit-code gating |
197
209
  | [Baselines](docs/baselines.md) | Adopting on an existing repo |
198
210
  | [Team policy](docs/policy.md) | One standard across many repos |
@@ -212,4 +224,4 @@ invariants (every rule tested, zero findings on the clean fixture, zero dependen
212
224
 
213
225
  ## License
214
226
 
215
- [MIT](LICENSE). All 72 rules, every output format, no accounts, no telemetry, no paid tier.
227
+ [MIT](LICENSE). Every rule, every output format, no accounts, no telemetry, no paid tier.
package/docs/agents.md CHANGED
@@ -48,9 +48,11 @@ When an agent decides this tool belongs in a project (for example after an audit
48
48
  findings), the full adoption is three non-interactive, idempotent-safe commands:
49
49
 
50
50
  ```sh
51
- npx @jqntn/agentdoctor --init-ci # writes .github/workflows/agentdoctor.yml (SARIF + gate)
52
- npx @jqntn/agentdoctor --init-skill # writes .claude/skills/config-audit/SKILL.md
53
- npx @jqntn/agentdoctor --write-baseline .agentdoctor-baseline.json # only if findings exist today
51
+ npx @jqntn/agentdoctor --init-ci # writes .github/workflows/agentdoctor.yml
52
+ npx @jqntn/agentdoctor --init-skill # writes .claude/skills/config-audit/SKILL.md
53
+
54
+ # only if the project already has findings today
55
+ npx @jqntn/agentdoctor --write-baseline .agentdoctor-baseline.json
54
56
  ```
55
57
 
56
58
  Each `--init-*` command writes exactly one well-known file, refuses to overwrite, and exits 2
@@ -65,7 +67,7 @@ agent that can run a shell command can use agentdoctor. What differs per tool is
65
67
 
66
68
  | Agent | Mechanism | Install |
67
69
  |---|---|---|
68
- | Claude Code | Skill + plugin (`/agentdoctor:audit`) | `/plugin marketplace add jqntn/agentdoctor` or `npx @jqntn/agentdoctor --init-skill` |
70
+ | Claude Code | Skill + plugin (`/agentdoctor:config-audit`) | `/plugin marketplace add jqntn/agentdoctor` or `npx @jqntn/agentdoctor --init-skill` |
69
71
  | OpenAI Codex | `AGENTS.md` | `npx @jqntn/agentdoctor --init-agents` |
70
72
  | Cursor | `AGENTS.md` | `npx @jqntn/agentdoctor --init-agents` |
71
73
  | Gemini CLI / Jules | `AGENTS.md` | `npx @jqntn/agentdoctor --init-agents` |
@@ -87,13 +89,16 @@ across projects):
87
89
 
88
90
  ```sh
89
91
  mkdir -p ~/.codex/prompts
90
- npx @jqntn/agentdoctor --init-agents # project instructions
91
- cp node_modules/@jqntn/agentdoctor/skills/config-audit/SKILL.md ~/.codex/prompts/audit-config.md # optional /audit-config
92
+ # project instructions, read by Codex
93
+ npx @jqntn/agentdoctor --init-agents
94
+
95
+ # optional: a reusable /audit-config prompt, user-scoped across projects
96
+ cp node_modules/@jqntn/agentdoctor/plugin/skills/config-audit/SKILL.md ~/.codex/prompts/audit-config.md
92
97
  ```
93
98
 
94
99
  ## The standalone skill and plugin
95
100
 
96
- The canonical skill lives at [`skills/config-audit/`](https://github.com/jqntn/agentdoctor/tree/main/skills/config-audit)
101
+ The canonical skill lives at [`plugin/skills/config-audit/`](https://github.com/jqntn/agentdoctor/tree/main/plugin/skills/config-audit)
97
102
  in the repo and inside the npm package. It contains the audit -> fix workflow plus
98
103
  `references/fix-recipes.md` with per-rule fix patterns, and its `description` frontmatter is
99
104
  written to trigger on config-audit requests, edits to `.claude/` files, and "my hook isn't
@@ -103,9 +108,9 @@ Three ways to install it:
103
108
 
104
109
  | Method | Command | Scope |
105
110
  |---|---|---|
106
- | Claude Code plugin | `/plugin marketplace add jqntn/agentdoctor` then `/plugin install agentdoctor` | everywhere (also adds `/agentdoctor:audit`) |
111
+ | Claude Code plugin | `/plugin marketplace add jqntn/agentdoctor` then `/plugin install agentdoctor` | everywhere, invokable as `/agentdoctor:config-audit` |
107
112
  | CLI | `npx @jqntn/agentdoctor --init-skill` | this project |
108
- | Manual | `cp -r node_modules/@jqntn/agentdoctor/skills/config-audit .claude/skills/` | anywhere |
113
+ | Manual | `cp -r node_modules/@jqntn/agentdoctor/plugin/skills/config-audit .claude/skills/` | anywhere |
109
114
 
110
115
  All three install the same files - `--init-skill` copies them out of the package, so the
111
116
  installed skill cannot drift from the published one (test-enforced).
@@ -16,7 +16,7 @@ npx @jqntn/agentdoctor
16
16
  Or install it:
17
17
 
18
18
  ```sh
19
- npm install -g @jqntn/agentdoctor # global CLI
19
+ npm install -g @jqntn/agentdoctor # global CLI
20
20
  npm install -D @jqntn/agentdoctor # per-project, for CI
21
21
  ```
22
22
 
@@ -96,4 +96,4 @@ score card (rule ids and counts only - safe to share from private repos), and
96
96
  - [CI setup](ci.md) — SARIF annotations, exit-code gating
97
97
  - [Baselines](baselines.md) — adopting agentdoctor on a repo that already has findings
98
98
  - [Team policy](policy.md) — holding many repos to one standard
99
- - [Rule reference](rules.md) — all 72 rules and the reasoning behind each
99
+ - [Rule reference](rules.md) — every rule and the reasoning behind it
@@ -0,0 +1,60 @@
1
+ # Privacy
2
+
3
+ **agentdoctor collects nothing, transmits nothing, and has no servers.**
4
+
5
+ That claim is easy to make and hard to trust, so here is exactly what the tool does, and how
6
+ you can verify each point yourself.
7
+
8
+ ## What it reads
9
+
10
+ Only files in the project you point it at, plus your user-level configuration in `~/.claude`
11
+ unless you pass `--no-user`:
12
+
13
+ `.claude/settings.json`, `.claude/settings.local.json`, `~/.claude/settings.json`, `.mcp.json`,
14
+ `CLAUDE.md` / `CLAUDE.local.md` / `AGENTS.md`, `.claude/agents/*.md`,
15
+ `.claude/skills/*/SKILL.md`, `.claude/commands/*.md`, `.claude/hooks/*`,
16
+ `.claude/keybindings.json`, and `.gitignore`.
17
+
18
+ ## What it never reads
19
+
20
+ Credential files are excluded **by path, before anything opens them**:
21
+ `.credentials.json`, `credentials.json`, `.netrc`, `id_rsa`, `id_ed25519`. The report tells you
22
+ how many files were skipped for this reason. A test in the suite plants a tripwire value inside
23
+ a credentials file and asserts it can never appear in any output.
24
+
25
+ ## What leaves your machine
26
+
27
+ Nothing. There is no telemetry, no analytics, no crash reporting, no licence check, no update
28
+ check, and no phone-home of any kind. The tool makes **zero network requests**. You can confirm
29
+ this by running it with the network disabled, or by reading the source — there is no HTTP client
30
+ in it, and it has zero dependencies, so there is no transitive code that could add one.
31
+
32
+ ## What it writes
33
+
34
+ Nothing, unless you explicitly ask:
35
+
36
+ - `--write-baseline <file>` writes a list of accepted finding fingerprints
37
+ - `--init-ci`, `--init-skill`, `--init-agents`, `--init-policy` each create one well-known file
38
+ and refuse to overwrite an existing one
39
+
40
+ It never edits your configuration. Findings tell you what to change; the change is yours.
41
+
42
+ ## Secrets in output
43
+
44
+ When a rule detects a credential-shaped value, the finding shows a short prefix and suffix with
45
+ `(redacted)` — never the value. This holds in every output format, so reports are safe to paste
46
+ into an issue, a CI log, or a model's context.
47
+
48
+ `--share` goes further: it emits only rule ids and counts, never file paths, messages, or
49
+ snippets, so a score card is safe to post publicly from a private repository.
50
+
51
+ ## This website
52
+
53
+ Static files served by GitHub Pages. No analytics, no cookies, no trackers, no fonts or scripts
54
+ loaded from third parties. The one exception is a linked badge image hosted by openhunts.com in
55
+ the footer; requesting it reveals your IP address to that host, as any remote image does.
56
+
57
+ ## Contact
58
+
59
+ Questions or a discrepancy between this page and the code:
60
+ <https://github.com/jqntn/agentdoctor/issues>
package/docs/rules.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Rule reference
2
2
 
3
- 72 rules. `agentdoctor --explain <rule-id>` prints any of these from the CLI.
3
+ Every rule, with the reasoning behind it - 72 in total. `agentdoctor --explain <rule-id>`
4
+ prints any of these from the CLI, and `--list-rules` prints the catalogue.
4
5
 
5
6
  ## Correctness
6
7
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jqntn/agentdoctor",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Lint and grade your AI coding-agent configuration: permissions, hooks, MCP servers, skills, subagents and CLAUDE.md. Catches silent failures, security holes and context waste, with fixes. Zero dependencies, no telemetry.",
5
5
  "keywords": [
6
6
  "agent",
@@ -57,7 +57,7 @@
57
57
  "LICENSE",
58
58
  "docs",
59
59
  "schemas",
60
- "skills"
60
+ "plugin"
61
61
  ],
62
62
  "scripts": {
63
63
  "test": "node --test",
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "agentdoctor",
3
+ "description": "Audit and fix AI coding-agent configuration: permissions, hooks, MCP servers, skills and memory files. Adds the config-audit skill, invokable as /agentdoctor:config-audit. The linter itself runs via npx - nothing else to install.",
4
+ "version": "0.1.3",
5
+ "author": {
6
+ "name": "Julien QUENTIN",
7
+ "url": "https://github.com/jqntn"
8
+ },
9
+ "homepage": "https://jqntn.github.io/agentdoctor/",
10
+ "repository": "https://github.com/jqntn/agentdoctor",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "lint",
14
+ "audit",
15
+ "security",
16
+ "agent-config",
17
+ "mcp",
18
+ "hooks",
19
+ "permissions"
20
+ ]
21
+ }
@@ -0,0 +1,10 @@
1
+ # agentdoctor (Claude Code plugin)
2
+
3
+ This directory is the installable plugin: a manifest and the `config-audit` skill, and nothing
4
+ else. It is deliberately separate from the repository root so that installing the plugin fetches
5
+ only these files — not the linter's source, its test fixtures, or the site generator.
6
+
7
+ The skill shells out to `npx @jqntn/agentdoctor`, so the plugin itself installs no binary.
8
+
9
+ - Source and issues: <https://github.com/jqntn/agentdoctor>
10
+ - Documentation: <https://jqntn.github.io/agentdoctor/>
@@ -5,8 +5,8 @@ description: Audit and fix AI coding-agent configuration with agentdoctor. Use w
5
5
 
6
6
  # Audit agent configuration with agentdoctor
7
7
 
8
- agentdoctor is a zero-dependency linter for agent config (72 rules: security, correctness,
9
- cost, hygiene, team policy). It makes no network calls and never opens credential files, so it
8
+ agentdoctor is a zero-dependency linter for agent config, covering security, correctness,
9
+ cost, hygiene and team policy. It makes no network calls and never opens credential files, so it
10
10
  is safe to run unattended in any project.
11
11
 
12
12
  ## Run the audit
package/src/adopt.js CHANGED
@@ -54,11 +54,11 @@ jobs:
54
54
  export const SKILL_PATH = '.claude/skills/config-audit';
55
55
 
56
56
  /**
57
- * The canonical skill ships inside the package at skills/config-audit/ - the
58
- * same files served by the plugin marketplace - so an installed skill can
59
- * never drift from the published one.
57
+ * The canonical skill ships inside the package at plugin/skills/config-audit/ -
58
+ * the same files the plugin marketplace serves - so a skill installed either
59
+ * way can never drift from the published one.
60
60
  */
61
- const PACKAGED_SKILL = join(dirname(fileURLToPath(import.meta.url)), '..', 'skills', 'config-audit');
61
+ const PACKAGED_SKILL = join(dirname(fileURLToPath(import.meta.url)), '..', 'plugin', 'skills', 'config-audit');
62
62
 
63
63
  /** Writes a file if absent. Returns a { written, path, message } outcome. */
64
64
  function writeOnce(root, relative, contents) {
package/src/index.js CHANGED
@@ -3,7 +3,7 @@ import { lint, fingerprint, helpers } from './engine.js';
3
3
  import { allRules, CATEGORIES } from './rules/index.js';
4
4
  import { loadPolicy } from './rules/policy.js';
5
5
 
6
- export const VERSION = '0.1.2';
6
+ export const VERSION = '0.1.3';
7
7
 
8
8
  /**
9
9
  * One-call entry point: discover config, load any team policy, run every rule.
@@ -120,7 +120,7 @@ function summaryLine(s, counts, input) {
120
120
  const summary = parts.length ? parts.join(', ') : s.green('clean');
121
121
  const grade = computeGrade(input.findings);
122
122
  const gradeColor = grade.startsWith('A') ? s.green : (grade === 'B' || grade === 'C' ? s.yellow : s.red);
123
- lines.push(`${s.bold('Summary')} ${s.bold(gradeColor(`Grade ${grade}`))} ${summary} ${s.dim(`- ${input.ran.length} rules in ${input.elapsedMs}ms`)}`);
123
+ lines.push(`${s.bold('Summary')} ${s.bold(gradeColor(`Grade ${grade}`))} ${summary} ${s.dim(`(${input.ran.length} rules, ${input.elapsedMs}ms)`)}`);
124
124
 
125
125
  if (input.suppressed > 0) {
126
126
  const word = input.suppressed === 1 ? 'finding' : 'findings';
@@ -128,8 +128,9 @@ function summaryLine(s, counts, input) {
128
128
  }
129
129
  const skipped = input.workspace.skipped ?? [];
130
130
  if (skipped.length > 0) {
131
- lines.push(s.dim(` ${skipped.length} file(s) skipped - credential files are never read`));
131
+ const fileWord = skipped.length === 1 ? 'file' : 'files';
132
+ lines.push(s.dim(` ${skipped.length} ${fileWord} skipped: credential files are never read`));
132
133
  }
133
- lines.push(s.dim(` Share the grade: agentdoctor --share - gate it in CI: agentdoctor --init-ci`));
134
+ lines.push(s.dim(' Share the grade with `agentdoctor --share`, or gate it in CI with `--init-ci`.'));
134
135
  return lines.join('\n');
135
136
  }