A small, deterministic preflight check for coding-agent plans. It reads the steps in a Markdown plan, compares file references with the checkout, and exits non-zero when the plan points at missing files, forgets a corresponding test, or contains a risky command.
The point is deliberately modest: catch cheap mistakes before an agent starts editing. There is no model call, API key, telemetry, or network access, so the same plan produces the same result locally and in CI.
From this checkout, the following command runs without installing anything:
PYTHONPATH=src python -m agent_planlint \
fixtures/broken_force_push/plan.md \
--repo fixtures/broken_force_pushIt exits 1 and prints:
1 finding(s) in fixtures/broken_force_push/plan.md:
[error] destructive-step:3 Step 1: destructive heuristic matched (git_force_push)
For normal use:
python -m pip install -e .
agent-planlint path/to/plan.md --repo path/to/checkoutPython 3.11 or newer is required.
| Rule | Signal |
|---|---|
undefined-path |
A repository-relative path mentioned by a step does not exist. External URLs are ignored. |
missing-test |
An implementation step names a source file, but no conventionally named test exists. Common src/ to tests/ layouts are supported. |
destructive-step |
A force push, unprotected database migration, or broad rm -rf appears in a step. Cleanup of known generated directories such as build, dist, and node_modules is accepted. |
Headings at levels two through six are treated as steps. A heading may be
written as ## Step 2: Add retry handling or simply ## Add retry handling.
Paths can be bare or wrapped in backticks; commands are usually best placed in
backticks or fenced shell blocks.
--sarif writes SARIF 2.1.0 with repository-relative locations, suitable for a
code-scanning upload:
agent-planlint plan.md --repo . --sarif planlint.sarifUse --format sarif to print JSON, or --format both for text followed by
JSON. Exit codes are 0 for a clean plan, 1 for findings, and 2 for bad
input such as a missing plan or repository root.
This is a linter, not a sandbox or a plan judge. It never executes the plan and cannot tell whether the proposed design is sensible.
- Path checking uses the checkout as it exists now. A genuinely new file will be reported unless the workflow creates it before linting.
- Test discovery follows filenames and directory conventions; it does not read build configuration or test manifests.
- The destructive-command rule is intentionally conservative. Its generated- directory allowlist is small and explicit.
- The Markdown parser is a purpose-built subset, not a full CommonMark parser.
These limits are kept visible because a quiet false sense of safety would be worse than a noisy lint result.
python -m pip install -e ".[dev]"
pytest -q
python -m buildThe fixture directories are tiny example repositories. Each one keeps its
plan.md next to the exact tree the rule is expected to accept or reject,
which makes a failed heuristic easy to inspect.
Adjacent projects worth comparing include
cirbuk/plan-lint, which evaluates
structured plan policies, and
dshills/RealityCheck, which uses
model-based criticism. agent-planlint stays focused on Markdown-to-checkout
static checks.
MIT licensed. See LICENSE.