@jqntn/agentdoctor 0.1.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/docs/api.md ADDED
@@ -0,0 +1,100 @@
1
+ # Programmatic API
2
+
3
+ agentdoctor is an ES module with no dependencies, so embedding it is one import.
4
+
5
+ ```js
6
+ import { run } from '@jqntn/agentdoctor';
7
+
8
+ const result = run('/path/to/repo', { includeUserScope: false });
9
+
10
+ for (const finding of result.findings) {
11
+ console.log(finding.severity, finding.ruleId, `${finding.display}:${finding.line}`);
12
+ }
13
+ process.exitCode = result.findings.some((f) => f.severity === 'error') ? 1 : 0;
14
+ ```
15
+
16
+ ## `run(root, options?)`
17
+
18
+ The one-call entry point: discovers config, loads any team policy, runs every rule.
19
+
20
+ | Option | Type | Default | Effect |
21
+ |---|---|---|---|
22
+ | `includeUserScope` | boolean | `true` | Also scan `~/.claude` |
23
+ | `home` | string | `os.homedir()` | Override the home directory (useful in tests) |
24
+ | `policyPath` | string | auto-detect | Explicit policy file path |
25
+ | `only` | string[] | all | Restrict to categories or rule ids |
26
+ | `disabled` | string[] | none | Skip rules or categories |
27
+ | `minSeverity` | `'error'\|'warning'\|'info'` | `'info'` | Severity floor |
28
+ | `baseline` | `Set<string>` | empty | Fingerprints to suppress |
29
+
30
+ Returns `{ findings, ran, suppressed, workspace, elapsedMs, version }`.
31
+
32
+ ### Finding shape
33
+
34
+ ```ts
35
+ {
36
+ ruleId: string; // e.g. "security/unrestricted-bash"
37
+ severity: 'error' | 'warning' | 'info';
38
+ category: 'correctness' | 'security' | 'cost' | 'hygiene' | 'policy';
39
+ message: string; // what is wrong, specific to this occurrence
40
+ help?: string; // what to do instead, from the rule
41
+ file: string; // absolute path
42
+ display: string; // repo-relative (or ~/) path for humans
43
+ line: number; // 1-based
44
+ column?: number;
45
+ configPath?: string; // e.g. "permissions.allow[0]"
46
+ snippet?: string; // offending value, secrets redacted
47
+ }
48
+ ```
49
+
50
+ Findings are pre-sorted by severity, then file, then line.
51
+
52
+ ## Lower-level building blocks
53
+
54
+ All exported from the package root:
55
+
56
+ - `discover(root, { includeUserScope, home })` — collects and parses every config file, with
57
+ per-value source positions. Never opens credential files.
58
+ - `lint(workspace, { rules, disabled, minSeverity, baseline })` — runs rules over a discovered
59
+ workspace. Pass your own `rules` array to run a custom subset or add your own rules.
60
+ - `fingerprint(finding)` — the stable identity used by baselines. Anchored to the offending
61
+ value, then config path, then message hash — never line numbers.
62
+ - `allRules`, `CATEGORIES` — the catalogue.
63
+ - `loadPolicy(root, explicitPath?)` — reads `agentdoctor.policy.json`.
64
+ - `helpers` — utilities handed to rules: `parsePermission`, `estimateTokens`, position lookup.
65
+
66
+ ## Writing a custom rule
67
+
68
+ A rule is a plain object; `lint` accepts any array of them.
69
+
70
+ ```js
71
+ import { discover, lint, allRules, helpers } from '@jqntn/agentdoctor';
72
+
73
+ const noOpusInProjects = {
74
+ id: 'org/no-opus-model',
75
+ category: 'policy',
76
+ severity: 'warning',
77
+ title: 'Project pins an Opus-tier model',
78
+ help: 'Our org standard is sonnet for project config; sessions can override per run.',
79
+ check({ files, report, helpers }) {
80
+ for (const file of files) {
81
+ if (file.kind !== 'settings' || file.data?.model !== 'opus') continue;
82
+ const position = helpers.at(file, 'model');
83
+ report({ file, line: position.line, column: position.column,
84
+ configPath: 'model', message: 'model is pinned to opus.' });
85
+ }
86
+ },
87
+ };
88
+
89
+ const workspace = discover(process.cwd(), { includeUserScope: false });
90
+ const result = lint(workspace, { rules: [...allRules, noOpusInProjects] });
91
+ ```
92
+
93
+ The `check` function receives `{ workspace, files, report, helpers }`. Throwing inside a rule
94
+ does not crash the run — it surfaces as an `internal/rule-crashed` warning finding.
95
+
96
+ ## Stability
97
+
98
+ The exported API surface is small on purpose: `run`, `discover`, `lint`, `fingerprint`,
99
+ `allRules`, `CATEGORIES`, `loadPolicy`, `helpers`, `VERSION`. Anything not exported from the
100
+ package root is internal and may change without notice.
@@ -0,0 +1,90 @@
1
+ # Architecture
2
+
3
+ Four stages, each a plain module with no dependencies: **discover → parse → lint → report**.
4
+
5
+ ```
6
+ bin/agentdoctor.js CLI: flags, exit codes, EPIPE handling
7
+ src/
8
+ discover.js finds config files; never opens credential files
9
+ parse.js position-tracking JSON + frontmatter parsers
10
+ engine.js runs rules, suppression, baselines, fingerprints
11
+ rules/
12
+ correctness.js (26) config the harness silently ignores
13
+ security.js (22) config that widens the execution surface
14
+ cost.js (8) always-on context, priced with stated assumptions
15
+ hygiene.js (8) config that confuses the next person
16
+ policy.js (8) team standards from agentdoctor.policy.json
17
+ report/
18
+ terminal.js json.js sarif.js
19
+ ```
20
+
21
+ ## Discovery
22
+
23
+ `discover()` walks the project for every file the agent harness reads: settings at three
24
+ scopes (project, local, user), `.mcp.json`, memory files at any depth, agents, skills,
25
+ commands, hooks, keybindings. Vendor directories (`node_modules`, `dist`, `.venv`, …) are
26
+ skipped, walk depth is capped, and files over 4 MB are recorded as skipped rather than read.
27
+
28
+ Two properties are deliberate and load-bearing:
29
+
30
+ - **Credential files are never opened.** `.credentials.json`, `.netrc`, private keys are
31
+ excluded by *path* before any `readFile`, and a test asserts a tripwire value planted in a
32
+ credentials file can never reach output. A security tool's own behavior is part of its
33
+ threat model.
34
+ - **No network calls, ever.** Not for updates, not for telemetry. The entire run is local
35
+ file reads.
36
+
37
+ ## Position-tracking parsing
38
+
39
+ Findings are only actionable if they point at a line, so agentdoctor does not use
40
+ `JSON.parse`. `src/parse.js` is a hand-written JSON parser that records the `line:column` of
41
+ every value, keyed by config path (`permissions.allow[0]`). It is also deliberately tolerant:
42
+ trailing commas and comments — common in hand-edited config — parse fine, so one stray comma
43
+ yields real findings instead of a single parse error. A genuinely broken file becomes a
44
+ `correctness/invalid-json` **error**, because the harness ignores the entire file in that
45
+ case, including any permission rules in it.
46
+
47
+ Agent and skill definitions carry config in YAML frontmatter. The frontmatter parser supports
48
+ the documented subset (scalars, inline and dash lists, one nesting level) rather than taking a
49
+ YAML dependency.
50
+
51
+ ## The rule engine
52
+
53
+ A rule is a plain object: `{ id, category, severity, title, help, check() }`. The engine calls
54
+ each rule with the workspace and a `report()` callback, then handles everything rules should
55
+ not re-implement:
56
+
57
+ - **Suppression** — inline `agentdoctor-disable` comments, `--disable`, `--only`,
58
+ `--min-severity`, and baselines all apply centrally.
59
+ - **Fingerprints** — each finding gets a stable identity anchored to the offending value,
60
+ then config path, then message hash. Never line numbers: a baseline must survive unrelated
61
+ edits ([why](baselines.md)).
62
+ - **Crash isolation** — a throwing rule becomes an `internal/rule-crashed` warning; it cannot
63
+ take the run down.
64
+ - **Ordering** — findings sort by severity, file, line, so output is deterministic.
65
+
66
+ ## Design principles
67
+
68
+ 1. **False positives are worse than false negatives.** A linter that cries wolf gets
69
+ uninstalled, at which point it catches nothing. The test suite contains a fully
70
+ well-configured fixture project that must produce **zero** findings; any rule that fires on
71
+ it is wrong by definition.
72
+ 2. **Every finding says why and what to do.** `message` states the specific problem; `help`
73
+ states the fix and the reasoning. `--explain <rule-id>` prints the full rationale.
74
+ 3. **Silent failure is the enemy.** The highest-value rules are the ones that catch config
75
+ the harness ignores without any error: misspelled hook events, deny rules naming
76
+ nonexistent tools, hooks pointing at missing scripts.
77
+ 4. **Zero dependencies, permanently.** This tool warns about supply-chain risk in MCP
78
+ servers; its own `npm install` footprint is part of the product. The JSON parser, YAML
79
+ subset, ANSI styling, and SARIF writer are all in-tree.
80
+ 5. **Estimates state their assumptions.** Cost rules price always-on context using a model
81
+ that accounts for prompt caching, and say so in the message. The token count is the fact;
82
+ the money is a model.
83
+
84
+ ## Testing
85
+
86
+ `node --test`, no framework. The suite covers every rule (a meta-test fails if a rule id
87
+ appears in no test file), parser positions, discovery, baselines (insertion-stability
88
+ regression tests), CLI behavior including piping and exit codes, and docs consistency — the
89
+ README's rule counts are asserted against the actual catalogue so marketing copy cannot drift
90
+ from the code.
@@ -0,0 +1,56 @@
1
+ # Baselines: adopting agentdoctor on an existing repo
2
+
3
+ An established project will have findings on day one. Fixing all of them before turning on CI
4
+ enforcement is how adoption dies. A baseline records the current findings as accepted, so CI
5
+ fails only on **new** problems.
6
+
7
+ ## Workflow
8
+
9
+ ```sh
10
+ # once, reviewed and committed like any other change
11
+ agentdoctor --no-user --write-baseline .agentdoctor-baseline.json
12
+ git add .agentdoctor-baseline.json
13
+
14
+ # in CI, from then on
15
+ agentdoctor --no-user --baseline .agentdoctor-baseline.json
16
+ ```
17
+
18
+ Fix things over time, then shrink the baseline by regenerating it:
19
+
20
+ ```sh
21
+ agentdoctor --no-user --write-baseline .agentdoctor-baseline.json
22
+ ```
23
+
24
+ The file is plain JSON — a list of finding fingerprints — so shrinkage is visible in diffs and
25
+ code review. A growing baseline is a red flag a reviewer can see.
26
+
27
+ ## Why baselines survive edits
28
+
29
+ A baseline that breaks when someone inserts an unrelated line is a baseline people stop
30
+ trusting. agentdoctor anchors each fingerprint to the most stable identity available, in order:
31
+
32
+ 1. **The offending value itself** (e.g. the text of the permission rule). Permission rules
33
+ live in arrays, so a positional anchor like `permissions.allow[0]` changes meaning the
34
+ moment anyone inserts a rule above it. The rule text does not.
35
+ 2. **The config path**, for structural findings with no single value (an empty deny list, a
36
+ missing required key).
37
+ 3. **A hash of the finding's message**, for whole-file findings.
38
+
39
+ Line numbers are never part of the identity. Concretely:
40
+
41
+ - Insert a new (bad) rule anywhere in the allow list → exactly one new finding surfaces.
42
+ - Add unrelated keys above the offending line → nothing resurfaces.
43
+ - Fix a finding → its fingerprint disappears on the next `--write-baseline`.
44
+
45
+ Each of these is a regression test in the suite (`test/baseline.test.js`).
46
+
47
+ ## Baselines vs inline suppression
48
+
49
+ | | Baseline | `agentdoctor-disable` comment |
50
+ |---|---|---|
51
+ | Scope | Whole project, one file | One rule, one file |
52
+ | Visibility | A count in every summary + a diffable JSON file | A comment next to the code |
53
+ | Use for | The adoption backlog | A deliberate, permanent exception |
54
+
55
+ Rule of thumb: baselines are for *debt*, inline suppressions are for *decisions*. If you find
56
+ yourself regenerating the baseline to absorb new findings, you have turned the fire alarm off.
package/docs/ci.md ADDED
@@ -0,0 +1,87 @@
1
+ # Running agentdoctor in CI
2
+
3
+ ## GitHub Actions, as code scanning annotations
4
+
5
+ Findings appear inline on the pull request diff.
6
+
7
+ ```yaml
8
+ name: agentdoctor
9
+
10
+ on: [pull_request]
11
+
12
+ permissions:
13
+ contents: read
14
+ security-events: write
15
+
16
+ jobs:
17
+ audit:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-node@v4
22
+ with: { node-version: 22 }
23
+
24
+ # continue-on-error so the SARIF still uploads when findings exist;
25
+ # the gate job below is what actually fails the build.
26
+ - run: npx @jqntn/agentdoctor --no-user --sarif > agentdoctor.sarif
27
+ continue-on-error: true
28
+
29
+ - uses: github/codeql-action/upload-sarif@v3
30
+ with:
31
+ sarif_file: agentdoctor.sarif
32
+
33
+ - name: Fail on errors
34
+ run: npx @jqntn/agentdoctor --no-user --quiet
35
+ ```
36
+
37
+ `--no-user` matters in CI: there is no `~/.claude` on a runner, and scanning it locally would
38
+ report findings a reviewer cannot act on.
39
+
40
+ ## Any other CI
41
+
42
+ ```sh
43
+ npx @jqntn/agentdoctor --no-user --json > agentdoctor.json # exit 1 if errors exist
44
+ npx @jqntn/agentdoctor --no-user --max-warnings 0 # also fail on warnings
45
+ ```
46
+
47
+ Exit codes are the contract:
48
+
49
+ | Code | Meaning |
50
+ |---|---|
51
+ | 0 | No errors (and warnings within `--max-warnings`) |
52
+ | 1 | At least one error, or too many warnings |
53
+ | 2 | Bad usage: unknown flag, missing path, unreadable baseline |
54
+
55
+ ## Adopting on a repo that already has findings
56
+
57
+ Fail on new problems without having to fix the backlog first:
58
+
59
+ ```sh
60
+ # once, on a green-ish commit
61
+ npx @jqntn/agentdoctor --no-user --write-baseline .agentdoctor-baseline.json
62
+ git add .agentdoctor-baseline.json
63
+
64
+ # in CI, from then on
65
+ npx @jqntn/agentdoctor --no-user --baseline .agentdoctor-baseline.json
66
+ ```
67
+
68
+ Baseline entries are fingerprints of `rule id + file + config path`, so moving a rule within a
69
+ file keeps it suppressed, while adding a genuinely new one does not.
70
+
71
+ Shrink the baseline as you fix things:
72
+
73
+ ```sh
74
+ npx @jqntn/agentdoctor --no-user --write-baseline .agentdoctor-baseline.json
75
+ ```
76
+
77
+ ## Enforcing one standard across many repos
78
+
79
+ Commit the same `agentdoctor.policy.json` to every repo, or fetch it from a central location in
80
+ CI, and the policy rules hold each repo to it:
81
+
82
+ ```yaml
83
+ - run: curl -sSf https://internal.example.com/agentdoctor.policy.json -o agentdoctor.policy.json
84
+ - run: npx @jqntn/agentdoctor --no-user --quiet
85
+ ```
86
+
87
+ The policy rules activate on the presence of the file — nothing else to configure.
@@ -0,0 +1,115 @@
1
+ # Configuration
2
+
3
+ agentdoctor needs no config file to run. Everything is a CLI flag, an inline comment, or (for
4
+ team standards) an `agentdoctor.policy.json`.
5
+
6
+ ## CLI reference
7
+
8
+ ### Output
9
+
10
+ | Flag | Effect |
11
+ |---|---|
12
+ | *(default)* | Human-readable report, colored when stdout is a TTY |
13
+ | `--json` | Machine-readable findings on stdout ([format](output.md)) |
14
+ | `--sarif` | SARIF 2.1.0 for GitHub code scanning and other CI |
15
+ | `--quiet`, `-q` | Print nothing; rely on the exit code |
16
+ | `--no-color` / `--color` | Force color off/on (also honours `NO_COLOR` and `FORCE_COLOR`) |
17
+
18
+ ### Scope
19
+
20
+ | Flag | Effect |
21
+ |---|---|
22
+ | `[path]` | Project root to audit (default: current directory) |
23
+ | `--no-user` | Skip `~/.claude`. Recommended in CI, where user scope does not exist |
24
+ | `--only <cat,...>` | Run only these categories or rule ids |
25
+ | `--disable <id,...>` | Skip specific rules or whole categories |
26
+ | `--min-severity <level>` | `error`, `warning`, or `info` (default) |
27
+
28
+ Categories: `correctness`, `security`, `cost`, `hygiene`, `policy`.
29
+
30
+ ```sh
31
+ agentdoctor --only security,correctness
32
+ agentdoctor --disable cost/no-cleanup-period,hygiene
33
+ agentdoctor --min-severity warning
34
+ ```
35
+
36
+ ### CI
37
+
38
+ | Flag | Effect |
39
+ |---|---|
40
+ | `--max-warnings <n>` | Exit 1 if more than n warnings (errors always exit 1) |
41
+ | `--baseline <file>` | Suppress findings recorded in the baseline ([guide](baselines.md)) |
42
+ | `--write-baseline <file>` | Record current findings as accepted |
43
+
44
+ ### Team policy
45
+
46
+ | Flag | Effect |
47
+ |---|---|
48
+ | `--policy <file>` | Policy file path (default: `agentdoctor.policy.json` at the root) |
49
+ | `--init-policy` | Write a starter policy file ([guide](policy.md)) |
50
+
51
+ ### Adopt & share
52
+
53
+ | Flag | Effect |
54
+ |---|---|
55
+ | `--init-ci` | Write `.github/workflows/agentdoctor.yml`: SARIF annotations + exit-code gate. Refuses to overwrite. |
56
+ | `--init-skill` | Install the config-audit skill (SKILL.md + fix recipes) for Claude Code. Refuses to overwrite. |
57
+ | `--init-agents` | Add a marked audit section to `AGENTS.md` for Codex, Cursor, Gemini CLI and every other tool that reads it. Creates or appends; refuses to duplicate. |
58
+ | `--badge` | Print README markdown for a badge showing the current grade |
59
+ | `--share` | Print a paste-ready score card: grade, counts, top rule ids. Never includes messages, paths, or snippets, so it is safe to share from private repos. Always exits 0. |
60
+
61
+ ### Introspection
62
+
63
+ | Flag | Effect |
64
+ |---|---|
65
+ | `--list-rules` | The full catalogue (add `--json` for machine-readable) |
66
+ | `--explain <rule-id>` | What a rule checks, why it matters, how to suppress it |
67
+ | `--version`, `--help` | The usual |
68
+
69
+ ## Suppressing a rule for one file
70
+
71
+ Put a comment anywhere in the offending file:
72
+
73
+ ```
74
+ // agentdoctor-disable security/hook-unpinned-path
75
+ ```
76
+
77
+ In JSON config, a comment works (agentdoctor's parser tolerates comments) — or use a string
78
+ key that contains the directive:
79
+
80
+ ```json
81
+ {
82
+ "// agentdoctor-disable security/hook-unpinned-path": "hooks come from vendored bin/",
83
+ "hooks": { }
84
+ }
85
+ ```
86
+
87
+ Accepted forms:
88
+
89
+ - `agentdoctor-disable <rule-id>` — one rule
90
+ - `agentdoctor-disable <category>` — a whole category
91
+ - `agentdoctor-disable all` — everything, for this file
92
+ - Multiple ids separated by commas or spaces
93
+
94
+ Suppressions are file-scoped by design: a suppression you can see next to the code it affects
95
+ is one a reviewer can question.
96
+
97
+ To mark a credential-looking string as a deliberate placeholder:
98
+
99
+ ```
100
+ agentdoctor-allow-secret
101
+ ```
102
+
103
+ on the same line as the value.
104
+
105
+ ## Precedence
106
+
107
+ 1. `permissions.deny`-style hard skips: credential files are never read, regardless of flags.
108
+ 2. `--only` narrows the rule set first.
109
+ 3. `--disable` removes rules or categories from whatever `--only` left.
110
+ 4. Inline `agentdoctor-disable` comments suppress findings per file.
111
+ 5. `--baseline` suppresses previously accepted findings.
112
+ 6. `--min-severity` filters what is left.
113
+
114
+ Suppressed counts are always reported in the summary, so a silenced finding is visible as a
115
+ number even when its detail is not.
package/docs/faq.md ADDED
@@ -0,0 +1,83 @@
1
+ # FAQ
2
+
3
+ ## Is my config uploaded anywhere?
4
+
5
+ No. agentdoctor makes zero network calls — no telemetry, no update checks, no license pings.
6
+ The entire run is local file reads. It also never opens credential files
7
+ (`.credentials.json`, `.netrc`, private keys); they are excluded by path before anything
8
+ reads them, and the summary reports how many were skipped.
9
+
10
+ ## Why did it find nothing?
11
+
12
+ Probably because your config is small. A 10-line `settings.json` with two permission rules
13
+ has little to get wrong, and agentdoctor is deliberately quiet on healthy setups — the test
14
+ suite asserts zero findings on a well-configured project. The findings density rises with
15
+ hooks, MCP servers, subagents, skills, and memory files.
16
+
17
+ ## Isn't this just a JSON schema?
18
+
19
+ A schema catches type errors. It cannot tell you that `Bash(*)` is a bad idea, that your hook
20
+ script does not exist on disk, that your deny rule names a tool that does not exist (and
21
+ therefore blocks nothing), or that your `CLAUDE.md` costs real money per month. Most of the
22
+ catalogue is semantic, not structural.
23
+
24
+ ## Why do you report warnings on things that are technically legal?
25
+
26
+ Because the failure mode this tool exists for is config that is *legal and inert*. A
27
+ misspelled hook event is valid JSON. It just never fires, and nothing tells you. When
28
+ agentdoctor is unsure, it says `info`; when something is legal but almost certainly not what
29
+ you meant, `warning`; when a guardrail provably does nothing or a real hazard is
30
+ pre-approved, `error`.
31
+
32
+ ## A rule fired on something intentional. What now?
33
+
34
+ Suppress it where it fired, visibly:
35
+
36
+ ```
37
+ // agentdoctor-disable security/hook-unpinned-path
38
+ ```
39
+
40
+ If you believe the rule is wrong in general, that is a bug — false positives are treated as
41
+ more severe than false negatives. Open an issue with the config that triggered it.
42
+
43
+ ## How accurate are the cost estimates?
44
+
45
+ The token counts are direct estimates from file size. The money figures are a *model*, and the
46
+ message says so: they assume the memory file stays prompt-cached (it sits at the front of the
47
+ prompt, which is exactly the content that caches) and state the request volume they assume.
48
+ The uncached worst case is also shown where it matters. Assumptions live in
49
+ `src/rules/cost.js` where you can disagree with them.
50
+
51
+ ## Does it modify my config?
52
+
53
+ No. agentdoctor reports; you decide. Every finding includes what to change and why, but the
54
+ edit is yours. The only file it ever writes is a baseline, and only when you pass
55
+ `--write-baseline`.
56
+
57
+ ## Which harnesses does it understand?
58
+
59
+ The `.claude/` configuration surface (Claude Code and compatible tooling), `.mcp.json` MCP
60
+ server definitions, and the `CLAUDE.md`/`AGENTS.md` memory-file convention. The rule engine is
61
+ harness-agnostic — discovery is the only layer that knows file layouts — so support for other
62
+ agent config formats is an issue away.
63
+
64
+ ## Does it work on Windows?
65
+
66
+ Yes, with one deliberate gap: the two rules that inspect file permissions
67
+ (`security/world-writable-config` and the permission half of
68
+ `security/hook-script-not-executable`) do nothing on Windows. Node synthesizes POSIX mode bits
69
+ there — every file reports `0666` — so the check would fire on everything while telling you
70
+ nothing. Windows ACLs are a different model than this rule can speak to. Every other rule
71
+ behaves identically across Linux, macOS and Windows, and paths in output always use forward
72
+ slashes so a baseline recorded on one platform matches on another.
73
+
74
+ ## Why Node 20+? Why zero dependencies?
75
+
76
+ Node 20 is the oldest LTS with everything the tool needs built in. Zero dependencies is a
77
+ security decision, not an aesthetic one: a tool that warns you about unpinned supply chains
78
+ should not install one.
79
+
80
+ ## Can I use it as a library?
81
+
82
+ Yes — `import { run } from '@jqntn/agentdoctor'` and you get structured findings. See the
83
+ [API docs](api.md), including how to add organisation-specific rules.
@@ -0,0 +1,99 @@
1
+ # Getting started
2
+
3
+ ## Requirements
4
+
5
+ Node 20 or newer. Nothing else — agentdoctor has zero dependencies and installs no transitive
6
+ packages.
7
+
8
+ ## Run it
9
+
10
+ No install needed:
11
+
12
+ ```sh
13
+ npx @jqntn/agentdoctor
14
+ ```
15
+
16
+ Or install it:
17
+
18
+ ```sh
19
+ npm install -g @jqntn/agentdoctor # global CLI
20
+ npm install -D @jqntn/agentdoctor # per-project, for CI
21
+ ```
22
+
23
+ By default it audits the current directory plus your user-level config in `~/.claude`. To audit
24
+ a specific project, pass the path:
25
+
26
+ ```sh
27
+ agentdoctor path/to/repo
28
+ agentdoctor --no-user # project config only (use this in CI)
29
+ ```
30
+
31
+ ## What gets scanned
32
+
33
+ | File | What it is |
34
+ |---|---|
35
+ | `.claude/settings.json` | Project settings: permissions, hooks, env, model |
36
+ | `.claude/settings.local.json` | Personal overrides (should be gitignored) |
37
+ | `~/.claude/settings.json` | User-level settings |
38
+ | `.mcp.json` | MCP server definitions |
39
+ | `CLAUDE.md`, `CLAUDE.local.md`, `AGENTS.md` | Memory files, at any depth |
40
+ | `.claude/agents/*.md` | Subagent definitions |
41
+ | `.claude/skills/*/SKILL.md` | Skill definitions |
42
+ | `.claude/commands/*.md` | Slash commands |
43
+ | `.claude/hooks/*` | Hook scripts (existence and permissions only) |
44
+ | `.claude/keybindings.json` | Key bindings |
45
+
46
+ **Never scanned:** `.credentials.json`, `.netrc`, private keys. These are skipped by path
47
+ before anything opens them, and the summary reports how many files were skipped. agentdoctor
48
+ also makes no network calls — nothing leaves your machine.
49
+
50
+ ## Reading a finding
51
+
52
+ ```
53
+ .claude/settings.json
54
+ 4:7 error "Bash(*)" auto-approves every shell command, including ones
55
+ you have not seen.
56
+ | Bash(*)
57
+ -> Replace the wildcard with the specific commands you actually
58
+ want unattended, e.g. "Bash(npm test:*)".
59
+ security/unrestricted-bash
60
+ ```
61
+
62
+ Top to bottom: file, `line:column`, severity, what is wrong, the offending value, what to do
63
+ instead, and the rule id. Every rule id works with `--explain`:
64
+
65
+ ```sh
66
+ agentdoctor --explain security/unrestricted-bash
67
+ ```
68
+
69
+ ## The grade
70
+
71
+ Every report ends with a health grade - `A+` (zero findings), `A` (info only), `B`/`C`
72
+ (warnings), `D`/`F` (errors). It is computed from what is actionable today, so fixing or
73
+ deliberately suppressing findings raises it. `agentdoctor --share` prints a paste-ready
74
+ score card (rule ids and counts only - safe to share from private repos), and
75
+ `agentdoctor --badge` emits README markdown for it.
76
+
77
+ ## Severities
78
+
79
+ | Severity | Meaning |
80
+ |---|---|
81
+ | `error` | Broken or dangerous. A guardrail that does not work, a pre-approved destructive command, a committed credential. |
82
+ | `warning` | Very likely a problem, occasionally intentional. |
83
+ | `info` | Worth knowing; act on it or ignore it. |
84
+
85
+ ## Exit codes
86
+
87
+ | Code | Meaning |
88
+ |---|---|
89
+ | 0 | No errors (and warnings within `--max-warnings`, if set) |
90
+ | 1 | At least one error, or too many warnings |
91
+ | 2 | Bad usage: unknown flag, missing path, unreadable baseline |
92
+
93
+ ## Next steps
94
+
95
+ - [Configuration](configuration.md) — every flag, suppression, disabling rules
96
+ - [CI setup](ci.md) — SARIF annotations, exit-code gating
97
+ - [Baselines](baselines.md) — adopting agentdoctor on a repo that already has findings
98
+ - [Team policy](policy.md) — holding many repos to one standard
99
+ - [Rule reference](rules.md) — all 72 rules and the reasoning behind each