agentdoctor

Your agent’s config fails silently.
This does not.

agentdoctor lints AI coding-agent configuration — permissions, hooks, MCP servers, skills, memory files — and reports what is broken, dangerous, or expensive, with line numbers and fixes. Zero dependencies. No telemetry. MIT.

npx @jqntn/agentdoctor
Get started Star on GitHub
agentdoctor scanned 1 config file in /work/api

.claude/settings.json
  3:15    error  "Bash(*)" auto-approves every shell command, including ones you have not seen.
                 | Bash(*)
                 -> Replace the wildcard with the specific commands you actually want
                    unattended, e.g. "Bash(npm test:*)" or "Bash(git status)". A blanket allow
                    means any command the model proposes runs without asking you.
                 security/unrestricted-bash

  4:14    error  "bash(curl:*)" targets unknown tool "bash". Did you mean "Bash"? This deny rule currently blocks nothing.
                 | bash(curl:*)
                 -> Tool names are case-sensitive. A rule naming a tool that does not exist
                    never matches anything, so a deny rule written this way protects nothing.
                 correctness/permission-unknown-tool

  7:21    error  "PostToolUsee" is not a hook event. Did you mean "PostToolUse"? As written, this hook never runs.
                 -> Valid events: PreToolUse, PostToolUse, UserPromptSubmit, Notification, Stop,
                    SubagentStop, PreCompact, SessionStart, SessionEnd. Events are
                    case-sensitive and a misspelled one never fires.
                 correctness/unknown-hook-event

  1       info   No deny rules cover .env, SSH keys or cloud credentials.
                 -> Add a deny list such as ["Read(./.env*)", "Read(**/.ssh/**)",
                    "Read(**/*.pem)", "Read(**/.aws/credentials)"]. Deny rules are the only
                    guardrail that survives an accepted prompt, since they are checked before
                    anything runs.
                 security/missing-secret-denies

  2:18    info   This project defines deny rules, but any contributor can still start a session in bypassPermissions mode and skip them.
                 -> Set permissions.disableBypassPermissionsMode to "disable" in committed
                    project settings to stop anyone opting out of prompts in this repo.
                 security/bypass-mode-not-locked

Summary  Grade F  3 errors, 2 info  (72 rules, 11ms)
         Share the grade with `agentdoctor --share`, or gate it in CI with `--init-ci`.

Nothing validates this config. The failures don’t error — they just don’t work.

"SubAgentStop"

One capital letter off. Valid JSON. The hook never fires, and nothing tells you.

"bash(curl:*)"

A deny rule naming a tool that doesn’t exist blocks nothing — while looking exactly like a guardrail.

"Bash(*)"

In an allow list, every command the model proposes runs without asking you. Including the ones you haven’t seen.

What it checks

The bar for a rule is that it catches a failure that actually happens and stays quiet on legitimate config — a correctly configured project reports nothing, asserted by a fixture in the test suite. False positives are treated as more severe than missed findings, because a linter that cries wolf gets uninstalled and then catches nothing at all. 72 rules today, each with a test.

Security 22

Pre-approved destructive commands, curl | sh hooks, committed credentials (always redacted), unpinned MCP packages, loader-hijacking env vars, world-writable config.

Correctness 26

Invalid JSON that silently voids permission rules, misspelled keys and hook events with did-you-mean, dead deny rules, malformed hooks, duplicate agents.

Cost 8

Memory files priced in tokens and dollars — with stated caching assumptions — duplicated instructions, pasted code blocks, vague skill descriptions.

Hygiene 8

Ungitignored local settings, machine-specific paths in committed config, shadowed settings, empty skills.

Policy 8

Commit one agentdoctor.policy.json and every repo is held to it: required denies, forbidden allows, approved MCP servers, context budgets.

CI-native

SARIF annotations on the PR diff, exit-code gating, and content-anchored baselines that survive unrelated edits.

Built for agents, audited by agents

Deterministic, non-interactive, machine-readable end to end: --json with a shipped JSON Schema, --explain for every rule, secrets redacted in every format so findings are safe in model context. This site serves llms.txt and every docs page as raw markdown. A ready-made Claude Code skill turns findings into fixes.

# the agentic fix loop
agentdoctor . --no-user --json     # findings, sorted most-severe-first
#   edit finding.file at finding.line (configPath names the exact key)
agentdoctor . --no-user --quiet    # exit 0 = verified fixed

Every audit ends in a grade

A+ zero findings · A info only · B/C warnings · D/F errors. The formula fits in a sentence, because a grade nobody can explain is a grade nobody trusts. --share prints a paste-ready score card and --badge a README badge — both carry rule ids and counts only, never messages or paths, so they are safe to post from private repos.

npx @jqntn/agentdoctor --init-ci      # gate every PR: SARIF annotations + exit code
npx @jqntn/agentdoctor --init-skill   # let Claude Code audit and fix config itself
npx @jqntn/agentdoctor --badge        # show your grade in the README

Sixty seconds to a verdict

npx @jqntn/agentdoctor                    # audit this project + ~/.claude
npx @jqntn/agentdoctor --only security    # one category
npx @jqntn/agentdoctor --explain security/hook-remote-code
npx @jqntn/agentdoctor --init-policy      # start a team standard

Read the docs