Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Workflow Gate

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.

Before vs After

The Problem

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.

How It Works

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

Architecture

Quick Start

1. Install

git clone https://github.com/PaddyGilliland1/workflow-gate.git
cd workflow-gate
pip install -e .

2. Create Your Config

Copy an example and customise:

cp examples/workflow-steps-basic.json /path/to/your/project/workflow-steps.json

Edit to match your workflow. Each step has:

  • step_id — unique identifier Claude uses to mark it complete
  • description — what needs to happen
  • mandatorytrue = blocks the gate, false = tracked but not blocking
  • one_of_group — optional: any one step in the group satisfies all of them

3. Add MCP Server to Your Project

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"
      }
    }
  }
}

4. Add Hooks

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
        }]
      }
    ]
  }
}

5. Add to .gitignore

.workflow-gate-state.json
.workflow-gate-archive.jsonl

6. Restart Claude Code

MCP servers and hooks load at session start. Restart to activate.

MCP Tools

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

Hook Scripts

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.

Configuration

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 complete
  • mandatory: false — tracked but doesn't block
  • blocking: 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")

Override Mechanism

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.

State Files

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)

Integrating with Slash Commands

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.

Examples

Tech Stack

  • 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

Running Tests

pip install -e ".[dev]"
pytest tests/ -v

Why Not Just Better Prompts?

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.

Contributing

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/

License

MIT

About

Mandatory workflow enforcement for Claude Code via MCP + hooks. Makes AI coding assistant rules impossible to skip.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages