maintainability-agent docs
Reference

CLI Reference

Interactive first-run on a TTY is the same setup questions as chat/MCP (first run and questions). There is not a CLI questionnaire. CI and a non-TTY never ask.

Audit

maintainability-agent --config maintainability-agent.json

Aliases:

MCP server

Install the optional extra, then start the same local MCP server through the package CLI (it writes only the five disclosed config/state artifacts — never source, never a report). The MCP audit_repository tool does not audit until configuration is answered and action is run; see first run and questions:

python3 -m pip install "maintainability-agent[mcp]"
maintainability-agent mcp --allow-root /absolute/path/to/repository

Repeat --allow-root to authorize unrelated repository directories. With no explicit root, the server permits only its launch directory. The standalone maintainability-agent-mcp console script remains available for existing IDE configurations.

Options

Option Purpose
--root Repository root to scan. Defaults to current directory.
--version Print the CLI version and exit.
--config JSON config path. Optional economic_context (ADR 004 v1) is described in config schema.
--format markdown, json or html. Omitted at a terminal, the CLI asks which presentation you want — chat (Enter), markdown, html or json; in CI it defaults to markdown and never asks (ADR 011). json emits the report dictionary the other presentations render, computing no score of its own.
--output Report output path.
--html-output Write the single-file HTML report (inlined CSS, deterministic SVG charts from the recorded history; opens offline).
--prompt-output AI remediation prompt output path.
--comment-output PR comment body output path.
--agent-instructions-output Audit-specific agent instructions output path.
--attestation-output Write the attestation: an independent, reproducible record of what was measured, what the change was told to do, what it did, and what moved. Populated by --conformance and --fail-on-regression; a question nobody asked renders as not asked, never as a pass. Reproducible and not signed — the digest is over the record's own content and nothing here holds a key.
--hostile-prompt-output Adversarial audit brief seeded from this run (ADR 013). Text only: it does not gate, score, or send anything.
--transformation Name the class of work this scan followed, e.g. react-18. Records the name on the scan and reports how this run of it compares with earlier ones — the movement in estimate between the previous recorded scan and this one, per run. A report, never a gate, and it changes no score. What it measures is the interval, not the transformation's effect: nothing in a tree says which transformation produced it, so the name is your claim and anything else that happened in the same interval is inside the number. It refuses across an instrument change and says how many runs it refused.
--sarif-input External SARIF file to summarize in the report. Repeatable.
--changed-only Git revspec for changed-file-only mode, e.g. main...HEAD.
--check PATH Read proposed content on stdin and report what its budgets say — the in-loop door, for an agent mid-edit. Needs no repository and no git: PATH names the content (it decides the language and appears in the output) and is never opened, so the content you pass is what gets measured rather than whatever is already on disk. Reports breaches, and for what still fits, how much room is left in every budget it can be failed on — length, cyclomatic and cognitive complexity, banded on whichever is worst, because a short function sitting on the complexity warn line has no room left in the budget that matters. A gate says no once it is too late to be cheap. Never scores: one file has no population to draw a rate from. A unified diff is refused in every language — by its format, not by a parser — because piping a diff instead of file content is the likeliest mistake at this door and it used to read as clean. A language with no declaration scanner says so rather than reporting nothing and looking clean. Refuses the flags it would have to ignore, sharing one list with --staged: a flag accepted and ignored teaches the caller it was honoured. Exit 1 on a breach, silently 0 when clear; --format json for agents.
--staged Scan what the git index will commit and exit — the pre-commit path. Reads the index rather than the working tree, so a half-staged file is measured as it will land. Reports threshold breaches and added suppression markers only, and never a score: a diff has no population to draw a rate from. Applies no repository gates, writes nothing, and never runs the opt-in test suite. Exit 1 blocks, 0 passes silently, 2 means the index could not be read — which also blocks, because a scan that could not be taken has not found nothing. Refuses the flags it would have to ignore rather than accepting them. Honours --format json.
--install-precommit-hook Write a git pre-commit hook that runs --staged, and exit. Refuses to replace a hook this tool did not write and prints the line to add to that hook instead; replaces its own without asking, because that is an upgrade rather than a clobber. Honours core.hooksPath and works in a linked worktree.
--baseline Existing baseline JSON file.
--write-baseline Write current findings as a baseline JSON file.
--fail-on-new Exit nonzero only for findings not in baseline.
--fail-on-gate Exit nonzero when hard gates fail.
--conformance Git revspec, e.g. main...HEAD. Reports how a diff relates to the work order it was given: which changed files the work order named, which are tests pairing to a named file, and which are neither — and any suppression marker (# noqa, eslint-disable, a skipped test) the diff added, flagging those landing on a file the work order named. The bounded prompt says fix exactly these and refactor nothing else; without this the bound is an instruction nothing checks. Reports only — it never scores, and it does not fail a build on its own. clean fails on a suppression directive the diff added to a file the work order named, and — since 3.11.0 — on any test file in the diff made unable to fail: a skip or suppression, an assertion that cannot fail, the assertion API replaced, a failing assertion swallowed, or assertions deleted with nothing in their place (_oracle, reported as oracle_weakened). Held to a precision bar frozen before the detector was written. --ask supplies an operator's ask in place of the work order.
--ask With --conformance, a file you name listing the paths and globs a task was asked to change, one per line (# for comments). The diff is read against this ask instead of the work order, for work this tool did not order: every change outside it — other than a test pairing to an asked file — is reported out of scope, production and tests counted apart. * matches across directories, and a glob that matched nothing is listed under ask_unmatched. An ask that names nothing is a usage error (exit 2). Read from your path, never discovered in the audited tree; shape, not correctness (Decision 13). Refused without --conformance.
--fail-on-regression Exit 1 when any scoring category is lower than the previous comparable scan. Reads the recorded history. Refuses — exit 2 — rather than comparing across an instrument change: two scans taken under different calibration or a different analyzer population cannot be subtracted, and 2.0.0 moving CALIBRATION_C would otherwise have read as a catastrophic regression everywhere.
--fail-on-out-of-scope With --conformance, exit 1 when the diff touched files the work order did not name and that are not a named file's test, or when it added a suppression to a flagged file. Scope alone is satisfiable by adding # noqa to the named file and changing nothing else, so the gate reads both. Opt-in, because a finding can legitimately require touching a caller nobody flagged.
--analyzers Force the external analyzer pool on, overriding analyzers.run. A configured repository runs its pool by default. A complete concept set moves the point estimate; otherwise the built-in fallback stands and the range widens. Missing-tool acquisition is separately controlled by analyzers.acquire_tools and defaults off. See the analyzer pool.
--no-analyzers Force the external analyzer pool off for this invocation, overriding analyzers.run.
--work AXIS=VALUE Narrow the work order. Repeatable; every criterion must match. Axes: band, finding_class, path, verification. Narrowing changes what is shown and never what anything scored.
--record-history Create or append this scan to .maintainability/history.jsonl. Once the file exists, every later successful scan appends to it and reads the resulting history without another flag.
--backfill REVSPEC Scan each commit in a range into the history and exit, e.g. HEAD~50..HEAD. Each commit is checked out in a temporary worktree; the working tree is never touched. Expensive, so it never runs as part of a normal scan.
--backfill-interval N With --backfill, scan every Nth commit instead of all of them.
--sarif-output Write SARIF report for GitHub code scanning.
--security-pillar Use this security-pillar.json, written by secure-code-agent --security-pillar, instead of running the tool. Without it, every audit runs secure-code-agent for the security pillar itself (ADR 007, D177); CI passes the document so the tool runs once, as its own gated step. A document sitting in the audited tree is not read on its own authority.
--init-agent-standards Generate model/tool-specific instruction files and exit without running an audit.
--install-skill Copy the packaged agent skill into the skills directory and exit. Re-run after every upgrade: an installed skill that drifts from the shipped one teaches agents a dead workflow. What it writes is the _skill_data payload inside the distribution; the command reads that payload and compares it against what is already installed, and it does not consult the repository. That the payload matches the reviewed skills/maintainability-agent/SKILL.md is held by the suite — tests/test_wheel_contents.py asserts it byte-for-byte against a staged build — not by a check at run time.
--skills-dir Where --install-skill writes (default ~/.claude/skills).
--update Upgrade this install to the newest release and exit. The installer resolves the version (uv pip install --upgrade, or pip without uv), so it never moves backwards; a lower result is refused and named. On an upgrade it re-syncs the skill (--install-skill) and records that the MCP server, which holds the code it loaded at spawn, needs a restart (D230).
--install-updater Write the macOS launch agent io.github.marshallguillory86.maintainability-agent.update, which runs --update hourly, load it, and exit. Removes the legacy com.marshallguillory.maintainability-agent-update agent so two updaters never run.
--home With --install-updater: the home directory to write the launch agent into (default ~).
--no-launchctl With --install-updater: write the launch agent without loading it.
--force-skill With --install-skill: overwrite a differing installed copy and remove files the package no longer ships. Without it, a differing copy is refused with the list of differences against the packaged payload.
--target Instruction target. Repeatable. Any name is accepted; one this tool has no built-in convention for must bring its own --target-path.
--target-path TARGET=PATH — where that agent reads its standing instructions, relative to --instructions-output-dir. Repeatable. Required for an agent with no built-in convention, and overrides the built-in path for one that has. The built-in list will always trail the market, and guessing a path writes a plausible file the agent never opens — so an unknown target is refused with the flag to use, rather than given a generated filename.
--instructions-output-dir Output directory for generated instruction files.

Examples

maintainability-agent \
  --config maintainability-agent.json \
  --output maintainability-report.md \
  --prompt-output maintainability-remediation-prompt.md \
  --comment-output maintainability-pr-comment.md
maintainability-agent \
  --config maintainability-agent.json \
  --changed-only main...HEAD \
  --fail-on-gate
maintainability-agent \
  --config maintainability-agent.json \
  --init-agent-standards \
  --target codex \
  --target claude-code \
  --target cursor