The harness: maintainability, fitness, and a gate your agent must pass
Letting an agent write code is easy. Stopping it from quietly rotting your architecture is the hard part. SpecShip turns the graph into checks — coupling, god-files, cycles, layering rules — composed into one opt-in CI gate.
Handing a coding agent the keys to your repository is a strange trade. It can move faster than any human reviewer, and it will — including in directions you didn't ask for. A function grows a tenth parameter. A UI module starts reaching into the database layer. Two modules quietly begin importing each other. None of it fails a test. All of it is debt the next change pays for.
The usual answer is "review harder," which doesn't scale against an agent that opens ten PRs a day. SpecShip's answer is different: the same graph that powers retrieval already knows the shape of your codebase. So we turn that shape into checks — and let the agent gate itself against them.
Maintainability, read off the graph
The first piece is a maintainability harness. It derives findings straight from the index — no second parse, no extra tooling — and each one tells you why it flagged:
- Coupling hotspots — symbols half the codebase depends on. Change one and the blast radius is enormous; the graph already knows the in-degree.
- Oversized symbols and god-files — the functions and files that have quietly become too big to reason about.
- Dependency cycles — modules that import each other, directly or through a chain.
- Dead-code candidates — exported symbols with no inbound edge anywhere in the graph.
Run it from the terminal with specship maintainability, open the Maintainability page in the dashboard, or let your agent call it. The thresholds aren't ours to dictate — what counts as "too coupled" differs per project — so they live in specship.config.json and you tune them as you go.
Architecture fitness: rules the agent must follow
Maintainability tells you where the rot is forming. Fitness functions let you forbid it outright. You declare the rules your architecture depends on, in plain config, and specship fitness checks them against the real dependency graph — not a convention, not a lint heuristic, the actual edges.
{
"fitness": {
"rules": [
{ "forbid": "src/ui/**", "from-importing": "src/db/**" },
{ "layers": ["routes", "services", "db"] },
{ "isolated": "src/payments/**" }
]
}
} Each violation is reported with its source → target and a file:line, so it's actionable, not a vague "layering smell." Crucially the command exits non-zero when a rule is broken, which is what lets it gate CI. And a rule whose target matches nothing is reported as a config error rather than silently passing — a green check should mean "we checked," never "we found nothing to check."
specship_fitness, so an agent can check its own change against the architecture rules before it ever asks you to merge — and fix the violation in the same turn.One gate, strictly opt-in
Drift, fitness, maintainability, and a spec → test → verify behaviour check are useful on their own. specship check composes them into a single CI gate — but the design principle that makes it adoptable is restraint:
With no enforce config, it only advises and exits 0. Adding it to an existing repo never breaks the build.
You turn on whichever checks you want to gate, one at a time, as your team agrees on them. A check you haven't opted into still runs and still reports — it just doesn't fail the build. That's the difference between a tool a team actually rolls out and one that gets disabled the first morning it blocks a hotfix.
# gated (enforced): drift ok 0 drifted links fitness FAIL src/ui/Cart.tsx:42 → src/db/pool.ts (forbidden) # advisory (not gating): maintain warn 2 god-files, 1 cycle behaviour ok 12/12 spec links verified exit 1
Why this belongs in the graph, not a linter
A linter sees one file at a time and reasons about syntax. Every check here reasons about relationships across the whole repo — in-degree, reachability, layering, the path from a route to a database call. That's a graph question, and the graph is already built and already current. The harness isn't a bolt-on; it's the index, asked a different question.
Letting an agent write code is easy. The hard, valuable part is making sure that a year of agent-written code still has a shape a human can hold in their head. That's harness engineering — and it's the quiet half of what SpecShip does.