Skip to main content

intent-gate

English | 简体中文

License: MIT Python >=3.11 MCP PyPI

Stop AI coding agents from guessing.

Complex business requirements. A thin or sloppy PRD. No legacy code to reference. That is exactly where coding agents start inventing: "happy path only, no failure flow", "idempotency with no server-side design" — gaps get silently filled with plausible-looking guesses, and you find out far too late.

intent-gate moves intent alignment before coding, into the requirement-analysis stage: a PRD goes through an intent-confidence gate → gaps are resolved through a three-level funnel → the output is technically annotated Mermaid contracts (state machines / sequence diagrams / decision tables) → a mechanical lint gate must reach zero CRITICAL → only then is coding allowed to begin.

It runs as an MCP server (stdio subprocess) — plug-and-play with Claude Code and other MCP clients. No daemon, no credentials, zero config — full workflow out of the box.

Where it sits in a vibe-coding workflow

intent-gate owns exactly one stage of the pipeline, the requirement-analysis stage:

PRD ──▶ [ intent-gate: confidence gate → intent alignment → Mermaid contracts ]
          ──▶ summary.md (every edge technically annotated, lint CRITICAL = 0)
          ──▶ coding agent (Claude Code / Cursor / any agent) ──▶ tests ──▶ ship

The leverage is asymmetric: if the contracts land well, the coding stage is a free win — every edge, step and rule already has a home, so any competent agent can implement the spec. That is why intent-gate deliberately does NOT touch coding, review or deployment: downstream agents are interchangeable; the input contract is not.

A real run: the withdrawal confirmation page

What one real requirement looks like after a full intent-gate pass.

The requirement, in one sentence:

"A withdrawal confirmation page — show the loan details, allow changing the term, sign and submit. Must be duplicate-proof, expiry-proof, and masked."

That's it. Exactly where a coding agent starts guessing.

What happened along the way:

  1. The analyzer drew the state machine first — and stalled at "submit": what about failure? Should duplicate protection live on the server or the frontend?
  2. 🔴 Red-light questions were asked one at a time (≥3 mutually exclusive options): "How do you guard against double-submit on rapid clicks / refresh?"
  3. You ruled: "Server-side Redisson lock, wait 10s / lease 300s" → your words were logged verbatim → injected into the state-machine edge and decision-table BR-01.
  4. A mechanical lint gate ran before delivery: CRITICAL = 0 or it does not ship.

The output: a technically annotated Mermaid contract (full state machine):

stateDiagram-v2
    direction LR
    [*] --> WITHDRAW_CONFIRM: 进入确认页 (DB_QUERY_SIGN_ORDER, CHANNEL_ROUTING_QUERY)
    WITHDRAW_CONFIRM --> OPTIONAL_PERIOD_LOADING: 请求可选期数 (DECISION_GET_OPTIONAL_PERIOD)
    OPTIONAL_PERIOD_LOADING --> WITHDRAW_CONFIRM: 获取成功 (RETURN_PERIOD_LIST)
    OPTIONAL_PERIOD_LOADING --> WITHDRAW_CONFIRM: 获取失败 (RETURN_ERROR, PERIOD_EDIT_DISABLED)
    WITHDRAW_CONFIRM --> ROUTING_PROCESSING: 修改期数或金额 (DB_INSERT_SIGN_ORDER_CHANNEL, DB_UPDATE_SIGN_ORDER)
    ROUTING_PROCESSING --> WITHDRAW_CONFIRM: 路由成功 (DB_UPDATE_SIGN_ORDER_CHANNEL, RETURN_NEW_QUOTE)
    ROUTING_PROCESSING --> WITHDRAW_CONFIRM: 路由失败 (RETURN_ERROR, ROLLBACK_OR_KEEP_ORIGIN)
    WITHDRAW_CONFIRM --> EXPIRED: 签署时效超时 (RETURN_ERROR_CODE, GUIDE_REENTER)
    EXPIRED --> [*]: 引导回首页 (FRONTEND_NAVIGATE)
    WITHDRAW_CONFIRM --> SUBMITTING: 点击确认借款 (REDIS_LOCK_SUBMIT, FILE_SYSTEM_UPLOAD_SIGN_IMAGE)
    SUBMITTING --> STEP_QUERY: 提交成功 (DB_UPDATE_SIGN_ORDER, QUERY_CURRENT_STEP)
    SUBMITTING --> WITHDRAW_CONFIRM: 提交失败 (RELEASE_LOCK, RETURN_ERROR)
    SUBMITTING --> TERMINATE: 流程激活失败 (DB_UPDATE_WITHDRAW_STATUS_TERMINATE)
    STEP_QUERY --> LOADING: WithdrawStep=loading (RETURN_NEXT_STEP)
    STEP_QUERY --> PAYMENT_AUTH: WithdrawStep=paymentAuth (RETURN_NEXT_STEP)
    STEP_QUERY --> PAY_CHANNEL: WithdrawStep=payChannel (RETURN_NEXT_STEP)
    STEP_QUERY --> QUERY_PROGRESS: WithdrawStep=queryProgress (RETURN_NEXT_STEP)
    STEP_QUERY --> WITHDRAW_CONFIRM: WithdrawStep=withdrawConfirm (STAY_ON_PAGE)
    LOADING --> SUCCESS: 跳转下一步 (FRONTEND_NAVIGATE)
    PAYMENT_AUTH --> SUCCESS: 跳转下一步 (FRONTEND_NAVIGATE)
    PAY_CHANNEL --> SUCCESS: 跳转下一步 (FRONTEND_NAVIGATE)
    QUERY_PROGRESS --> SUCCESS: 跳转下一步 (FRONTEND_NAVIGATE)
    SUCCESS --> [*]: 确认流程结束 (END)
    TERMINATE --> [*]: 订单终止 (END)

Every edge carries a mandatory technical-action annotation — the edge WITHDRAW_CONFIRM --> SUBMITTING reads (REDIS_LOCK_SUBMIT, FILE_SYSTEM_UPLOAD_SIGN_IMAGE). What the coding agent receives is a spec, not an illustration.

Decision table (rule logic forced into a matrix — no "happy path only" survival):

Rule Condition Action Failure branch
BR-01 Submit: lock LOCK:withdraw:submit:{orderId} conflict Redisson lock serializes, concurrent submits rejected Lock conflict → error code DUPLICATE_SUBMIT
BR-07 Signing deadline signExpireTime 5-minute double check: page countdown + server-side fallback on submit Expired → SIGN_EXPIRED, guide re-entry

The full contract: 10 business rules (BR-01..BR-10) + 3 sequence diagrams + an intent-injection mapping table (15 Q&A rounds, every answer on record).

The mechanical lint gate (pre-delivery self-check report):

summary_lint: CRITICAL 0 / 2 findings total (all MINOR, human-review class)

  • [MINOR][L3] state STEP_QUERY has 5 outgoing edges — confirm triggers are distinguishable
  • [MINOR][L3] state SUBMITTING has 3 outgoing edges — confirm triggers are distinguishable

With CRITICAL > 0 the contract refuses to ship and coding refuses to start — this is checked by code, not self-reported by the model.

Same requirement without intent-gate (observed in our control run): the agent would front-end-disable the submit button instead of designing a server-side distributed lock, hardcode a success page instead of routing by queryCurrentStep, and never model the EXPIRED state at all. The guessing space is structurally compressed, not politely discouraged.

Where to put your PRD

intent-gate accepts UTF-8 text files or .docx (the dominant format for business requirements). Three ways to hand one over:

Way Example Notes
Absolute path analyze D:\docs\withdraw-confirm.docx Most reliable; readable from anywhere
Relative path analyze docs/withdraw-confirm.md Resolved against the project root (HG_WORKSPACE_ROOT, defaults to the startup directory)
Conversation attachment Drag the file into the chat; have the agent persist it first Attachments are conversation content to the host, not a path — the agent must write them to disk before handing over a path

Supported formats:

  • ✅ UTF-8 text: .md / .txt / .csv / .json and similar
  • .docx: native support — mammoth is a core dependency (installed automatically; tables become Markdown tables); if markitdown already exists in your environment (e.g. for another document MCP), it is reused for enhanced extraction
  • ❌ Legacy .doc / .pdf / .xlsx and other binaries: convert first — Word「Save As → .docx or Plain Text (.txt)」, PDF export/save-as text

Errors carry the next step: missing file, binary format, and encoding failures each return a distinct message telling you what to do.

Using it: what to say

Once installed, you drive it with plain language. This table is the whole manual:

You say Who picks it up What happens
"分析这个需求 / analyze this PRD"(贴文档或指文件) 🔴 Red team(requirement-alignment Reads the playbook first, runs the Step 0 confidence check, then asks you structured questions (≥3 options + "other"), one gap at a time
"画个状态机 / 生成 DDL" 🔴 Red team Same entry — pattern routing decides which diagrams your requirement actually needs
"继续"(中断后/新会话) 🔴 Red team Resumes from the on-disk ledger (.harness/requests/{feature}/_review/) — no session memory needed
回答它的提问:"1",或 "4 余额不足一律拒绝" the funnel Answer logged verbatim → injected into the diagrams → settled with a precise landing point
"红蓝对抗 / blue-team review" —— 另开新会话说 🔵 Blue team(red-blue-review Independent adversarial review of the delivered summary: R1–R9 checks → findings with verdict PASS / FAIL-可整改 / FAIL-重做
"按 findings 整改"(回到红军的会话里说) 🔴 Red team revision discipline Each finding settled into revision-log.md with a real landing point, lint re-runs to zero CRITICAL; anything conflicting with your earlier rulings comes back to you for a decision
什么都不说,直接让它写代码 SessionStart hook The agent reads the landed summary.md contract before coding; blocked or lint-CRITICAL contracts refuse to be coded against

Two rules worth remembering:

  • Answer its questions seriously — every answer becomes part of the contract your coding agent will execute against.
  • The blue team needs a fresh session — reviewing in the same session degrades adversarial review into self-check. Deliver with the red team, then open a new conversation and say "红蓝对抗".

Core mechanisms

Intent-confidence gate (Step 0): assess the light status before analyzing any requirement. Until 🔴 core-logic gaps are eliminated, the report status must be blocked, the first task in any breakdown is forced to be [BLOCKER], and downstream coding is forbidden from starting.

Three-level alignment funnel (Step 0.5) — cost decreases level by level, fully non-blocking throughout:

① Code-grounded verification: technical gaps are checked against the code first;
  a unique ground truth is recorded directly, zero interpersonal cost
② AI-disclosed inference: registered with an explicit evidence chain, batch-confirmed
  by a human at session end (pure inference is forbidden on money-critical main flows)
③ Human ruling: structured-option questions (≥3 mutually exclusive options + "other"),
  one question at a time

Mechanical enforcement (enforced by MCP tools, not by prompt self-discipline):

  • Once a gap is registered it is physically persisted to pending-questions.md; until every box is ticked you don't get intent_aligned_ready;
  • resolve_question mechanically rejects an empty landing point — every injected intent must be precise down to a state-machine edge, a sequence-diagram step, or a decision-table rule number; if no landing point is found, closing the question is forbidden and it must be asked again;
  • Landing-point anchors may not be handwritten — the draft_mapping script locates real section/rule/step numbers;
  • Pre-delivery lint_summary mechanical self-check (L0–L8: unparseable state machine (blind-guard) / missing terminal state / dead states / misplaced anchors / BR references / table read-write matrix…), CRITICALs must reach zero before delivery.

Why confidence is read off artifacts

The obvious challenge: "Claude Code can already generate Mermaid diagrams — even generate code — why do I need your MCP?"

Answer: a model drawing a diagram is not intent alignment. Intent confidence is not the model's self-assessment — it is the closure state of artifacts.

Asking a model to rate "how sure are you" is a dead channel: verbal confidence barely correlates with actual correctness (it's post-hoc rationalization, not a reading); token-level logprobs can't reach semantic-layer uncertainty ("should there be an intermediate state after a refund?") and the API doesn't expose them anyway. So this system never asks the model for a score — it makes the model produce, and reads the confidence off the artifacts.

Drawing diagrams (state machines / sequence diagrams / decision tables) is a measuring instrument, not a means of expression: what natural language can fudge, formalization cannot — "after the refund is processed, it's done" is one sentence, but in a state machine you must answer whether REFUNDING has an outgoing edge, where it points, and on what trigger. Every edge is a forced discrete decision; vague intent is invisible in prose but a hole on an edge.

The difference between "Claude Code drawing it" and "the intent-gate host drawing it": after Claude Code draws, nobody verifies — intent gaps stay on the diagram as-is; after intent-gate draws, the output must pass lint, every gap goes through alignment, and a human rules on each one — every cell of the artifact is closed.

Gaps come in four kinds, each with its own detector — "can't draw it" is only layer one:

Layer Mechanism What it catches
① Forced formalization Draw the diagram; mark wherever you can't Perceived gaps — the model knows it doesn't know
② Taxonomy sweep A nine-category ambiguity checklist (exception paths / rollback / condition combinations / field semantics / idempotency & privilege / terminology…) Semi-silent gaps — the model won't stall on its own, but sweeping element-by-element with the checklist exposes them
③ Mechanical lint L1 no successful terminal state / L2 dead states / L6 table has no writes… Fully silent gaps — places the model filled in without any awareness; enforced by code, zero reliance on self-discipline
④ Blue-team independent review Independent session + information diet (optional skill) Systematic blind spots of the author's attention — layers ①–③ are the same pair of eyes; this one swaps in a fresh pair

So a 🟢 green light doesn't mean "the model feels confident" — it means "every edge of the state machine is grounded, all nine minefields swept, lint CRITICALs at zero, and a human has ruled on every gap." Confidence is a property of the graph, not of the model. Drawing is the instrument, lint is the calibrator, human rulings are the reference source.

Optional add-ons

  • Red-blue adversarial review (red-blue-review skill): after a complex requirement's summary is delivered, optionally open an independent session — the blue team reads only the artifacts, not the red team's reasoning (information diet), runs the R1–R9 checks, and produces findings that drive a gated rectification loop. approved comes via exactly two paths — a blue-team PASS or a direct human ruling; the red team never self-grants. Circuit breaker: at most 2 rounds, still FAIL → ESCALATE to a human.
  • DingTalk group consensus channel (sister project intent-gate-service, a standalone MCP service): business gaps belong to business people, technical gaps to technical people — funnel level ③ can post to a DingTalk group @ the right role; replies land in the inbox via callback. The real value of the group channel is the paper trail: answers carry a staffId and the original wording and are publicly visible — no objection in the group ≈ consensus. The main plugin defaults to the single channel, zero config.

Environment requirements

Item Requirement Notes
Python ≥ 3.11 python.org; pipx/uv manage an isolated environment
Package manager pipx or uv Install pipx / Install uv
OS Windows / macOS / Linux On Windows, the plugin's SessionStart injection needs Git Bash (skipped silently when missing; everything else keeps working)
MCP client Any MCP-capable client Claude Code / Cursor / VS Code etc.; the skills/hooks plugin form is currently Claude Code-specific

Dependencies (installed automatically — nothing manual):

Package Purpose
mcp>=1.10,<2.0 MCP protocol (FastMCP 1.x)
pydantic>=2.6 / pydantic-settings>=2.2 Configuration & validation
mammoth>=1.11 .docx parsing engine (only dependency is cobble, pure Python, no onnxruntime)

Optional enhancement: if markitdown is already in your environment (e.g. installed for another document MCP), it is reused automatically for finer table/merged-cell extraction; otherwise mammoth handles it.

Quick start (Claude Code — two steps)

# 1) Install the MCP server — the enforcement half (tools, ledger, lint gates)
#    .docx is natively supported: mammoth is a core dependency, installed
#    automatically with the package — no extra required
pipx install intent-gate-mcp
# or: uv tool install intent-gate-mcp

# 2) Install the plugin — skills + hooks, auto-registers the MCP server
claude plugin marketplace add baixinghao/intent-gate
claude plugin install intent-gate@baixinghao-plugins

Restart your session. Done — entry discipline is auto-injected and the MCP tools are live.

⚠️ Step 1 is not optional. The plugin's skills are discipline; the MCP server is enforcement. A plugin-only install (no intent-gate command on PATH) leaves you with good advice and zero mechanical gates — no question ledger, no lint, no delivery blocking. The SessionStart hook self-checks at every session start: if the server is missing, your agent will tell you to run step 1.

Environment variables

Variable Default Description
HG_WORKSPACE_ROOT . (startup directory) Project root (where .harness lives); relative PRD paths resolve against it
HG_LOG_LEVEL INFO Log level (DEBUG / INFO / WARNING / ERROR)
HG_CHANNEL single Intent-alignment channel; only single (dialog fallback) is supported — the DingTalk group channel lives in the sister project intent-gate-service

Every variable has a default — zero config to use; copy .env.example to .env only when you want to adjust.

Other MCP clients

Install the server as in step 1, then point your client at the intent-gate command:

{
  "mcpServers": {
    "intent-gate": {
      "command": "intent-gate"
    }
  }
}

If your client speaks a network transport, expose MCP over SSE with intent-gate --mcp-transport sse --mcp-port 8400.

All intent-alignment capabilities work with zero configuration (single channel, chat dialog as fallback).

Notes

  • Document-parsing boundary: .docx only; .doc legacy / .pdf / .xlsx and other binaries must be converted first (Word「Save As → .docx or Plain Text (.txt)」, PDF export/save-as text)
  • The MCP server is generic (stdio/SSE, works with any MCP client); the skills/hooks plugin form is currently Claude Code-specific — other clients get the server half only
  • The ledger lives under {workspace_root}/.harness/requests/ and is tracked by git — add a .gitignore entry if you don't want it committed

Development (from a clone)

python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -e .
python -m unittest discover -s tests -v   # core-logic tests (no credentials needed)

Point command at the virtualenv interpreter: "command": "<repo>\\.venv\\Scripts\\python.exe", "args": ["-m", "intent_gate"] (on macOS/Linux: <repo>/.venv/bin/python), and set "env": { "PYTHONPATH": "<repo>\\src" }. Plugin-form skeleton: see docs/PLUGIN.md.

Project structure

src/intent_gate/
├── config.py / logging.py        # config (HG_* env vars, zero credentials), logging
├── models.py / security.py       # pure-stdlib core: tokens, allowlist, reply parsing, rate limiting
├── __main__.py                   # MCP entrypoint (stdio/SSE)
├── alignment/                    # intent-alignment subsystem (file-in-the-loop, non-blocking)
│   ├── store.py                  #   persistence: pending list / alignment log / inference list / inbox
│   ├── manager.py                #   business layer + contract functions (register_question /
│   │                             #   file_inbound_reply, reused by sister project intent-gate-service)
│   └── tools.py                  #   MCP tool registration (9 intent-alignment tools)
├── analysis/                     # requirement-analysis subsystem
│   ├── playbook.md               #   requirement-analysis playbook (distributed in full via MCP prompt)
│   ├── engine.py                 #   gap adjudication / host-judgment bookkeeping
│   ├── lint.py                   #   mechanical checker for analysis reports (L0-L8 + three matrices)
│   ├── mapper.py                 #   anchor locating for the intent-injection mapping table
│   └── tools.py                  #   MCP tool registration (analysis tools + playbook prompt)
skills/
├── using-intent-gate/            # entry discipline: when to escalate, where the optional capabilities live
├── requirement-alignment/        # intent-alignment workflow outline → points to the MCP prompt
└── red-blue-review/              # optional: red-blue adversarial review playbook (blue-team nine checks + red-team rectification discipline)
(sister repo) intent-gate-service # DingTalk group channel + decision gates (standalone MCP service)

Documentation

  • docs/STRUCTURE.mdstructure & usage guide (file-by-file across both repos; read this first)
  • docs/DESIGN.md — intent-alignment subsystem design (three-level funnel, file contract, sister-project split)
  • docs/ARCHITECTURE.md — architecture decisions (layering, long-connection trade-offs, failure posture)
  • intent-gate-service README — sister-project DingTalk configuration and integration

Roadmap

  • Coding-start gate: claim_task validates approved + injects contract slices (the last mile of intent alignment)
  • intent-gate-service: interactive cards + button callbacks (no text parsing needed)
  • intent-gate-service: gate audit persistence (SQLite) and replay
  • intent-gate-service: gateway mode for multi-agent instances (stream inbound converged into a single connection)

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

intent_gate_mcp-0.4.0.tar.gz (102.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

intent_gate_mcp-0.4.0-py3-none-any.whl (64.9 kB view details)

Uploaded Python 3

File details

Details for the file intent_gate_mcp-0.4.0.tar.gz.

File metadata

  • Download URL: intent_gate_mcp-0.4.0.tar.gz
  • Upload date:
  • Size: 102.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for intent_gate_mcp-0.4.0.tar.gz
Algorithm Hash digest
SHA256 d46d58cbd4a253f5e06a1e7dc151bb93263eaad98f53050276a4fd1e163332c9
MD5 8baa08536155fdeb7fe912f33732be3f
BLAKE2b-256 4b7f54a010cdcb206e9acc6b851f51c6977ae4ae66a0dbdef452fdfe9599600a

See more details on using hashes here.

File details

Details for the file intent_gate_mcp-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: intent_gate_mcp-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 64.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for intent_gate_mcp-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ba092fc72cee16dbf2021eb15c98de1f097b15e6081021ba99c41f6535c904d2
MD5 4f52dbcffbbb94ea9e6f3ae8878fe7a5
BLAKE2b-256 8708d3aada1b76d83dc3d85c1938ae2a24782021e1d1813b034a440480985bef

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page