Skip to main content
Glama

Coding agents start as soon as they are asked, whatever the request leaves out. The omissions are not random. Security posture, compliance constraints and operational requirements are the least covered dimensions in real requests, and the code that comes back looks finished either way.

Most tooling helps you write a specification. spec-gate decides whether the specification is sufficient to start, and writes down the decision.

request ──▶ score against profile ──▶ below threshold?  ──▶ BLOCK + the questions that close the gap
                                          │
                                          └─ at or above ──▶ PROCEED + a committed record of why

It refuses. Below the threshold it returns a block, not a warning. An override is allowed and must carry a written reason, which lands in the record.

Why a threshold, and not just more questions

Asking the model to clarify sounds like the safe option. Measured across five models on 100 deliberately underspecified requests, clarification without a stopping rule made critical omissions worse on four of them. Gating on a sufficiency threshold reduced them on all five.

Model

Direct generation

Clarification, no gate

Gated

Reduction

GPT-OSS 20B

10.9%

11.7%

5.4%

−50%

Qwen 2.5 7B

28.2%

36.0%

14.6%

−48%

Mistral 7B

31.4%

45.3%

17.3%

−45%

GPT-4o-mini

18.5%

36.0%

11.7%

−37%

Llama 3.2 3B

34.8%

38.2%

24.8%

−29%

Critical omission rate: the share of safety, compliance and operational requirements the output left out. Lower is better. Method, baselines and full results: IEEE RE 2026.

Two caveats the paper states and this README will not bury. Answers came from a simulated user who always knew the right answer, so those reductions are an upper bound. Scorer agreement with human annotation was 0.71 (Cohen's kappa): good enough to gate on, not good enough to trust silently, which is why every score carries its evidence.

Related MCP server: docscanner-mcp

Interface

Two tools over MCP. One implementation, usable from any client that speaks the protocol.

score_request

Scores a request, returns a verdict. Writes nothing.

// in
{
  "request": "Add SSO to the admin dashboard",
  "context": ["repo:acme/admin", "file:docs/auth.md"]   // optional
}

// out
{
  "verdict": "block",                 // "proceed" | "block"
  "sufficiency": 0.62,                // weighted coverage, 0 to 1
  "threshold": 0.8,
  "profile": {"id": "agent-task", "version": "0.1.0", "source": ".spec-gate.yml"},
  "scorer": {"type": "deterministic+declared", "independent": false},
  "dimensions": [
    {"id": "must_not_change", "coverage": 0.4, "method": "model",
     "evidence": "mentions SSO, says nothing about existing sessions",
     "ask": "Which current behaviour must keep working exactly as it does now?"},
    {"id": "test_contract", "coverage": 0.0, "method": "deterministic",
     "evidence": "no test file or assertion named in the request",
     "ask": "Which tests already assert behaviour this change must not break?"}
  ],
  "blocking": ["must_not_change", "test_contract"]
}

One question per uncovered dimension, ordered by how much it moves the verdict. The caller decides whether to put them to the user.

The profile is not a parameter. It comes from .spec-gate.yml in the repo, so a caller cannot quietly choose a softer one.

write_record

Stores the decision. This is the artifact, and the reason the tool exists.

// in
{"request": "...", "answers": [...], "decision": "proceed"}
// or
{"request": "...", "decision": "override", "override": {"reason": "hotfix, gap accepted", "by": "pedram"}}

// out
{"path": ".spec-gate/2026-09-16-add-sso.json", "hash": "sha256:9f2c...", "decision": "proceed"}

The record

A decision record answers one question: why was this allowed to proceed? It holds the request, the profile and its version, per-dimension coverage with the evidence behind each score and whether a rule or a model produced it, every question asked and the answer given, the constraints and assumptions that resulted, any override with its reason and author, which scorer ran, and a timestamp. Full contract: schema/record.schema.json.

Every record gets a Markdown sibling, so a reviewer who does not read JSON can still read the decision in a pull request:

### Add SSO to the admin dashboard
**Proceeded** at 0.86 against a threshold of 0.80 · profile `agent-task@0.1.0` · scorer: rules + declared (not independent)

**Constraints**  existing sessions stay valid through rollout · tokens never written to logs
**Assumptions**  IdP is the existing Entra tenant (unconfirmed)
**Asked**        Which current behaviour must keep working? → "existing sessions must not drop"

Records are committed to the repository they belong to. Uncommitted evidence is not evidence, and a record next to the change it authorised is reviewable where the change is reviewed.

Assert on the stored record, never on console output. Tests read the JSON fields.

Profiles

Dimensions are data, so a team can fit them to its own failures. A profile sets the dimensions, their weights, the coverage rubric and the threshold.

Profile

For

Dimensions

Status

agent-task

Autonomous queues, where an item runs with no human in the loop

What must not change · what the tests assert · blast radius · definition of done

v0.1

sdlc-critical

Security, compliance and operations-critical work

The paper's ten, grounded in ISO/IEC/IEEE 29148 and Volere

v0.2

Where a dimension can be checked without a model, it is. A rule cannot be talked out of its answer.

Scoring

Rules first, declaration second, and a rule always wins.

A rule that misses is decisive: if nothing in the request, the target path or the user's answer names a test, test_contract is capped at zero and no declaration can lift it. A rule that matches is not: seeing a test path proves a test was named, not that it binds this change, so the cap lifts and judgement goes back to the caller. Whatever the rules cannot answer, the caller declares against the rubric with evidence, and a declared score is marked as declared in the record.

The rules read the request, the target path and what the user actually answered. They do not read the caller's own reasoning, or the veto would be advisory. "I checked the tests and they are fine" scores zero; a named test file does not.

An independent scorer is configurable for anyone who wants the judge separated from the judged.

This is deliberately not MCP sampling. Sampling was deprecated in the 2026-07-28 spec revision, and of the clients people actually use only VS Code implements it, so a design resting on it would not run where it is needed. Blocking questions are put to the user through elicitation instead, which is supported in Claude Code, Cursor, VS Code and Codex.

Scorer agreement with human annotation was 0.71 (Cohen's kappa) in the paper. Good enough to gate on, not good enough to trust silently, which is why every score carries its evidence.

Design decisions

The reasoning, and what was deliberately excluded, is in DECISIONS.md. In short:

  • It refuses rather than warns. A gate with an escape hatch is a warning.

  • Overrides are never silent. A reason, an author and a timestamp, in the record.

  • The repo picks the profile, not the caller.

  • Records are committed, JSON as the source of truth, Markdown for humans.

  • No signing or hash chaining. Git history already gives tamper evidence here.

  • Not a spec generator, not a plan mode, not a linter. It runs once, before the work starts, and anything outside the profile passes untouched.

Enforcement

Calling the gate is voluntary until a hook makes it not. .claude/settings.json registers a PreToolUse hook that denies file edits in a gated repository until a record authorises the work:

Write src/auth/session.ts
  └─ hook: no decision record authorises this work → denied, with instructions

An authorisation is for a piece of work, not a standing permission: it is scoped to the session that earned it and goes stale after twelve hours. A blocked record authorises nothing. A record whose hash no longer matches its content authorises nothing either. A repository with no .spec-gate.yml is not gated at all, so the hook is silent everywhere else.

An override still works, and still costs a written reason on the record.

Shadow mode

Before a gate is allowed to stop anything, it should prove it would stop the right things. enforce: shadow in .spec-gate.yml lets every edit through, tells the agent what a real gate would have said, and appends the would-have-blocked decision to .spec-gate/shadow.jsonl:

enforce: shadow    # deny (default) · shadow · off
{"at":"2026-09-16T09:12:04Z","session":"…","tool":"Write","file":"src/auth/session.ts","would_block":true,"reason":"spec-gate: no decision record authorises this work…"}

Run it that way in a repo where an autonomous agent is working and you learn two things nothing else tells you: how often it would fire, and whether it would fire on the right things. Enforce afterwards, on evidence.

A broken config blocks rather than disabling the gate. A typo in .spec-gate.yml is not permission to skip it, and enforce: off is a decision someone has to write down. Editing .spec-gate.yml itself is always allowed, so a bad config can always be repaired.

Run it

git clone https://github.com/PedramMadani/spec-gate && cd spec-gate && npm install
claude mcp add spec-gate -- npx tsx /absolute/path/to/spec-gate/src/index.ts

Or in .mcp.json (Claude Code) or .cursor/mcp.json (Cursor):

{ "mcpServers": { "spec-gate": { "command": "npx", "args": ["tsx", "/absolute/path/to/spec-gate/src/index.ts"] } } }

Then put a .spec-gate.yml in the repo you want gated.

Not on npm yet.

Status

Working. The gate refuses, rules veto declared scores, records are written and hashed, and a hook enforces them. What is left is elicitation for the blocking questions, the sdlc-critical profile, and real use.

Scope

v0.0.1

Server over stdio, both tools working, deterministic rule veto, records written and hashed, PreToolUse hook with deny / shadow / off, 47 tests

v0.1

Elicitation for blocking questions, published to npm, running against one real autonomous queue

v0.2

sdlc-critical profile

Open tasks: TASKS.md. Omissions it has caught in real use: CATCHES.md.

This is a reference implementation of a published method, maintained as time allows. No support commitment and no roadmap. Issues are welcome, answers are not guaranteed.

Citation

@inproceedings{madani2026rsga,
  author    = {Madani, Mohammadamin and Nahhas, Abdulrahman and Chernigovskaya, Maria and Turowski, Klaus},
  title     = {Requirements Sufficiency Gating for {LLM}-Assisted Automation: When Should Generation Proceed?},
  booktitle = {2026 IEEE 34th International Requirements Engineering Conference (RE)},
  year      = {2026},
  pages     = {262--272},
  address   = {Montreal, QC, Canada},
  publisher = {IEEE},
  doi       = {10.1109/RE68928.2026.00028}
}

Licence

Code Apache-2.0. Dimension spec, profiles and schema CC-BY-4.0.

Available Tools

2 tools
score_requestScore a request before starting workA

Scores a request against the repository profile and returns a proceed or block verdict with the questions that close the gap. Writes nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
cwdNoDirectory to resolve .spec-gate.yml from. Defaults to the process cwd.
targetNoPath the work will touch, used to select the profile. Does not choose the profile directly.
requestYesThe request as received, verbatim.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rubricYes
scorerYes
profileYes
verdictYes
blockingYes
thresholdYes
dimensionsYes
sufficiencyYes
instructionsYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It explicitly states 'Writes nothing,' which is a key behavioral trait (non-destructive), and mentions the output (proceed or block verdict). This adds value beyond the schema, though it does not detail other side effects like logging or rate limits, which is acceptable for a read-only evaluation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the core action and output, then appends the non-mutation note. Every word earns its place with zero redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema exists, so return values need no explanation. The description covers the purpose, non-mutating behavior, and output type. The only minor gap is not explicitly stating when to use this versus write_record, but the sibling name and 'Writes nothing' make the distinction clear enough.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description does not add meaningful parameter semantics beyond what the schema already provides; it mentions 'request' but the schema already describes it as 'The request as received, verbatim.' No extra context is given for cwd or target.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb (scores) and resource (request against repository profile), and clearly distinguishes from the sibling tool by noting 'Writes nothing.' This makes the tool's function unambiguous and differentiates it from write_record.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The title 'Score a request before starting work' gives clear temporal context, and the description's 'Writes nothing' implies it is for evaluation rather than mutation. However, it does not explicitly mention when not to use it or name write_record as the alternative, so it falls short of fully explicit guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

write_recordWrite the decision recordB

Stores the decision as a committed record: what was missing, what was assumed, who authorised proceeding. The verdict is computed from the declared coverage, not accepted from the caller.

ParametersJSON Schema
NameRequiredDescriptionDefault
cwdNo
targetNo
requestYesThe request as received, verbatim.
sessionNoSession id, so the pre-work hook can scope authorisation to this run.
overrideNoOnly to proceed below the threshold. The reason is stored verbatim and is not optional.
dimensionsYesOne entry per profile dimension, scored against the rubric.
assumptionsNoCarried but not established. Listing them is what makes them visible.
constraintsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
hashYes
pathYes
vetoedYesDimensions where a rule capped the declared score.
missingYes
decisionYes
thresholdYes
sufficiencyYes
markdown_pathYes

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden. It discloses that the verdict is computed from declared coverage rather than accepted from the caller, which is a key behavioral trait. However, it omits details on side effects (e.g., persistence, idempotency) or error behavior, leaving gaps for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loaded with the core action, and contains no fluff. Every word contributes to understanding the tool's purpose and a critical behavioral detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema, the description is too sparse for a tool with 8 parameters, nested objects, and a sibling tool. It lacks usage context, parameter guidance, and behavioral completeness, leaving an agent with insufficient information to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 63%, moderate. The description adds no parameter-level meaning; it does not explain the missing cwd, target, or constraints fields or clarify their roles. The schema provides descriptions for several fields, but the description fails to compensate for the uncovered parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool stores a decision record and lists what is recorded (missing, assumed, authorised). However, it does not differentiate from the sibling score_request, leaving the distinction to inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given on when to use this tool versus score_request. The description implies it operates after scoring but provides no explicit when-to-use or when-not-to-use instructions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.0.1
    • First observedscore_request
    • First observedwrite_record

TDQS

A3.6/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct purposes: score_request evaluates and returns a verdict, while write_record persists the decision. No overlap in functionality or ambiguity in selection.

Naming Consistency5/5

Both tools follow a consistent verb_noun pattern (score_request, write_record), making the naming predictable and easy to infer for an agent.

Tool Count3/5

With only 2 tools, the server feels thin for a domain like spec gating, but the tools cover the core workflow (scoring and recording). It's borderline but not unreasonable for a narrow purpose.

Completeness3/5

The tool set covers scoring and storing decisions but lacks obvious operations like retrieving past records or updating profiles. These gaps are notable but can be worked around for the primary gating use case.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Exposes the squad-dev workflow as deterministic MCP tools, enabling task classification, risk scoring, specialist reviewer selection, and advisory verdict consolidation for code changes.
    27
    43 npm
    4
    Apache 2.0
  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides lightweight documentation review tools including issue detection, readability scoring, style checking, and document summarization for integration with MCP-compatible clients.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server that enforces governance on agentic decisions with auditable evidence records, providing tools for understanding, calibrating confidence, and navigating handoffs based on policy.
    1
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Evidence-first delivery audit MCP server that evaluates task requirements against delivery evidence and returns a reproducible pass/needs_review/fail decision with a deterministic receipt.
    MIT