Make your AI coding assistant's rules mandatory, not advisory.
Workflow Gate is an MCP server + hook system that enforces development process steps in Claude Code. It physically blocks tool calls (Write, Edit, git commit) until required workflow steps are complete.
Your CLAUDE.md has rules: "run tests before committing", "include an issue ID", "initialise the session first." Claude follows them — mostly. Until context pressure, compaction, or a long session causes it to optimise for speed over process.
Rules are prompt-level. They compete with task instructions and can be skipped.
Hooks are infrastructure-level. They fire on every tool call, regardless of context.
Workflow Gate bridges the gap: your rules become gates that Claude structurally cannot skip.
CLAUDE.md rules (advisory, skippable)
|
workflow-steps.json (your rules become gate definitions)
|
MCP Server (Claude marks steps complete via tool calls)
|
Hook Scripts (read state file, block tool calls if steps missing)
|
Claude physically cannot skip steps
Three gates:
| Gate | Blocks | Until | Type |
|---|---|---|---|
| PRE-CODE | Write / Edit tools | Session init + issue review + work item selected | Mandatory |
| PRE-COMMIT | git commit | Tests passed + issue ID in commit message | Mandatory |
| POST-COMMIT | Nothing | Issue updated + pushed + closeout | Advisory |
git clone https://github.com/PaddyGilliland1/workflow-gate.git
cd workflow-gate
pip install -e .Copy an example and customise:
cp examples/workflow-steps-basic.json /path/to/your/project/workflow-steps.jsonEdit to match your workflow. Each step has:
step_id— unique identifier Claude uses to mark it completedescription— what needs to happenmandatory—true= blocks the gate,false= tracked but not blockingone_of_group— optional: any one step in the group satisfies all of them
Add to your project's .mcp.json:
{
"mcpServers": {
"workflow-gate": {
"command": "python",
"args": ["-c", "from workflow_gate.server import mcp; mcp.run(transport='stdio')"],
"env": {
"WFGATE_PROJECT_DIR": "/path/to/your/project",
"WFGATE_CONFIG": "workflow-steps.json"
}
}
}
}Add to your project's .claude/settings.local.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "WFGATE_PROJECT_DIR=/path/to/project bash /path/to/workflow-gate/hooks/check-gate.sh pre_code",
"timeout": 5000
}]
},
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash /path/to/workflow-gate/hooks/block-no-verify.sh",
"timeout": 3000
}]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "bash /path/to/workflow-gate/hooks/debug-warning.sh",
"timeout": 3000
}]
}
]
}
}.workflow-gate-state.json
.workflow-gate-archive.jsonlMCP servers and hooks load at session start. Restart to activate.
Claude calls these as part of its normal workflow:
| Tool | Purpose |
|---|---|
complete_step(step_id, evidence?) |
Mark a step as done (e.g., after running tests) |
check_gate(gate_id) |
Check if a gate is open or locked |
override_gate(gate_id, reason) |
Emergency bypass (min 10 chars, logged permanently) |
record_commit(hash, issue_id?) |
Record commit, reset pre-commit gate |
status() |
Full status of all gates |
reset_session() |
Archive current session, start fresh |
| Script | Trigger | Action |
|---|---|---|
check-gate.sh |
PreToolUse on Write/Edit | Blocks if pre-code gate locked |
check-gate.sh |
PreToolUse on git commit | Blocks if pre-commit gate locked |
record-commit.sh |
PostToolUse on git commit | Resets pre-commit gate, flags closeout |
block-no-verify.sh |
PreToolUse on Bash | Blocks --no-verify flag |
debug-warning.sh |
PostToolUse on Edit/Write | Warns about print/console.log/println! |
push-reminder.sh |
PreToolUse on git push | Reminds to run validation before push |
All gate-check hooks read the JSON state file directly — no MCP round-trip, <10ms execution.
workflow-steps.json is the control surface. Edit it to match your process:
{
"project": "my-project",
"gates": [
{
"gate_id": "pre_commit",
"description": "Must complete before git commit",
"blocking": true,
"steps": [
{
"step_id": "tests_passed",
"description": "pytest exits 0",
"mandatory": true
},
{
"step_id": "lint_passed",
"description": "Linter passes",
"mandatory": false
}
]
}
]
}Key concepts:
mandatory: true— blocks the gate until completemandatory: false— tracked but doesn't blockblocking: true— gate physically prevents tool calls (pre-code, pre-commit)blocking: false— gate is advisory only (post-commit)one_of_group— any step in the group satisfies all (e.g., "full validation" OR "quick validation")
Sometimes you need to bypass a gate ("just fix this typo"):
Claude calls: override_gate("pre_code", "User requested quick typo fix, skip full init")
Overrides require minimum 10 characters justification and are logged permanently to .workflow-gate-archive.jsonl. If Claude is gaming the system, you'll see it.
| File | Purpose | Committed? |
|---|---|---|
workflow-steps.json |
Your gate/step definitions | Yes |
.workflow-gate-state.json |
Current session state | No (gitignored) |
.workflow-gate-archive.jsonl |
Audit trail of all sessions | No (gitignored) |
Add complete_step() calls to your existing slash commands:
## Step 1: Read Configuration Files
...existing instructions...
After completing this step, call: `mcp__workflow-gate__complete_step` with step_id="configs_read"One line per step. Your existing workflow doesn't change — it just becomes enforced.
workflow-steps-basic.json— minimal 3-gate setupworkflow-steps-fullstack.json— full-stack project with version alignment, type checking, one-of groups
- Python 3.10+ with FastMCP
- Pydantic v2 for all state models
- Bash hook scripts (cross-platform via Python for JSON parsing)
- 39 tests covering models, state management, config loading, gates, overrides, persistence
pip install -e ".[dev]"
pytest tests/ -v| Approach | Reliability | Survives Compaction | Survives Context Pressure |
|---|---|---|---|
| CLAUDE.md rules | ~80% | No | No |
| Slash commands | ~90% | Partially | No |
| Workflow Gate | ~100% | Yes | Yes |
Rules are suggestions. Hooks are infrastructure. Infrastructure doesn't forget.
PRs welcome. The system is designed to be extended:
- New hook scripts in
hooks/ - New example configs in
examples/ - New gate types or step logic in
workflow_gate/
MIT

