Skip to main content

Generated, harness-agnostic workflow gates for spec-kit projects

Project description

speckit-gate

Harness-agnostic workflow gates for spec-kit projects.

Prevents out-of-order spec-kit command invocations by evaluating prerequisite artefacts at hook time. Supports hard-deny enforcement on Claude Code and Codex; advisory-only enforcement on all other spec-kit harnesses.

Install

Option 1 — uvx (one-shot, no install required)

# Scan and initialise gates in the current project
uvx speckit-gate init --defaults
uvx speckit-gate compile

# Install Claude Code hooks
uvx speckit-gate install --harness claude

Option 2 — Claude Code plugin (persistent, recommended for Claude Code)

# From within Claude Code, or via the CLI:
claude plugin install srobroek/speckit-gate

The .claude-plugin/plugin.json in adapters/claude/ wires UserPromptExpansion, PreToolUse:Skill, and PreToolUse:Agent hooks.

Option 3 — spec-kit bundle (all harnesses, advisory enforcement)

# Add the community bundle catalog and install
specify bundle catalog add https://github.com/srobroek/speckit-gate/releases/latest/download/bundles.json --id speckit-gate
specify bundle install speckit-gate

See Bundle adapter rationale below.

Option 4 — APM external source

# In apm.yml:
dependencies:
  apm:
    - repo: srobroek/speckit-gate
      ref: ">=0.1.0"
apm install

Quick start

# gates.yaml — 10-line example
config:
  prefix: speckit.
  feature_root: specs
  resolve: [git-branch, newest-dir]

gates:
  plan:
    requires: [specify]
    produces: [specs/<feat>/plan.md]
    context: Decomposes spec into implementation plan.
  tasks:
    requires: [plan]
    produces: [specs/<feat>/tasks.md]
    context: Decomposes plan into discrete tasks.

Compile to nodes.json:

speckit-gate compile
# → Compiled 2 gates → .specify/gates/nodes.json

Agent-driven interview

Use the speckit-gate skill (in skills/speckit-gate/SKILL.md) with Claude Code or any skill-capable harness. The skill:

  1. Scans the project for spec-kit commands.
  2. Shows a full proposal table (known prerequisites pre-filled).
  3. Asks ONE question per unknown command.
  4. Writes gates.yaml via init --answers and runs compile.

For no-agent setup run speckit-gate init --interactive or speckit-gate init --defaults.

Harness enforcement matrix

A gate is only as strong as its blindest channel, and every harness differs by invocation channel: what happens when the user types a command vs. when the model (a workflow engine, a subagent) evokes one mid-run. A gate that covers only the user channel is silently bypassed by agent-driven runs — so the matrix is per-channel. All deny rows below are verified against harness source (mid-2026); adapters currently ship for Claude Code and Codex.

Harness User invocation Model/agent evocation Adapter
Claude Code denyUserPromptExpansion, sees command name denyPreToolUse: Skill|Agent shipped
Qwen Code denyUserPromptExpansion, sees command_name (+ UserPromptSubmit post-expansion) denyPreToolUse on skill/agent tools (full prompt); model-invoked commands re-fire UserPromptExpansion. SubagentStart cannot block planned
Codex CLI denyUserPromptSubmit (raw human text; text-match, no command structure; requires [features] hooks = true) none — skills inject as context with no event; SubagentStart is metadata-only (continue:false at best). Artifact gates are the backstop shipped
Gemini CLI denyBeforeAgent (expanded template text only — no command name, no slash-origin marker; content-match required) n/a — model cannot invoke .toml commands by design planned
Mistral Vibe none — slash/skill input expands in the UI layer, invisible to hooks denybefore_tool on the skill tool (sees skill name; flag: enable_experimental_hooks). Note: skill loads bypass Vibe's user-approval prompt, so this hook is the only programmatic gate planned
GitHub Copilot hooks exist; deny semantics unverified unverified
Cursor, Zed, Cline, Goose, Devin, Trae, Lingma, Kimi, ZCode, Firebender, Junie, Auggie, + ~14 more static context only — no hook system static context only spec-kit bundle (advisory text)

Where a channel shows none/static, enforcement falls back to artifact gates: a downstream gated command hard-requires the report file the skipped step should have produced, so out-of-order runs still fail at the next enforceable point.

deny = the hook emits permissionDecision: deny or decision: block, preventing the tool from running.

advisory = the gate injects prerequisite context into the model's context window (via spec-kit's before_* hook infrastructure) but does not block execution.

Bundle adapter rationale

spec-kit supports 36+ harnesses. Of these, only Claude Code and Codex expose a real hook system (PreToolUse / UserPromptExpansion / UserPromptSubmit) that can deny tool calls before they run. All other harnesses receive spec-kit's advisory prompt injection as their only integration path — there is no hook event to intercept.

The spec-kit bundle is therefore the only distribution path that reaches advisory harnesses. It ships an extension that registers /speckit.gate.init and emits prerequisite context before each spec-kit command via spec-kit's built-in before_* advisory hooks.

The bundle does not duplicate Claude Code or Codex enforcement — those harnesses should use the plugin or install --harness path for real deny gates.

CLI reference

Verb Description
scan Scan project for spec-kit commands
propose Show prerequisite proposal table
init Write gates.yaml (--defaults / --answers / --interactive)
compile Compile gates.yaml.specify/gates/nodes.json
compile --check Drift check only; exit 1 if stale
install --harness Install hook adapters (claude/codex/speckit/all)
explain <cmd> Show prerequisites for a command
dry-run <cmd> Simulate a hook event
`dispatch pre post`

gates.yaml schema

config:
  prefix: speckit.          # command prefix; default "speckit."
  feature_root: specs       # feature artefact root; default "specs"
  resolve: [git-branch, newest-dir]
  messages:
    no_feature: "..."       # block reason when no feature resolved

gates:
  <command>:
    requires: [cmd-or-artefact, ...]
    produces: [artefact, ...]
    deprecated: true|false
    spawn_agent: true|false  # adds PreToolUse:Agent gate (Claude only)
    context: "..."           # advisory context injected into the model

compile derives edges by matching producesrequires and writes .specify/gates/nodes.json in the flat dispatcher format the hook reads.

Presets

Preset Description
presets/core.gates.yaml Spec-kit built-in commands only (analyze, checklist, clarify, constitution, converge, implement, plan, specify, tasks, taskstoissues). Safe to use on any spec-kit project.
presets/extensions.example.gates.yaml Example file showing how to gate community and custom extensions. Not an installable preset — copy individual entries into your gates.yaml.

Copy the core preset as your starting gates.yaml:

curl -sL https://raw.githubusercontent.com/srobroek/speckit-gate/main/presets/core.gates.yaml \
  > gates.yaml
speckit-gate compile

Extending for custom extensions

If your project uses community extensions (e.g. speckit.verify-tasks, speckit.agent-assign.*, speckit.refine.*), add gates for them on top of the core preset. See presets/extensions.example.gates.yaml for documented patterns covering:

  • requires-chain — sequencing a community command after a built-in artefact
  • spawn_agent — gating commands that spawn sub-agents via PreToolUse:Agent
  • deprecated — emitting an upgrade hint instead of a prerequisite block
  • produces-artefact — requiring a specific artefact path rather than a command name
# Copy entries you need from the example into your gates.yaml:
curl -sL https://raw.githubusercontent.com/srobroek/speckit-gate/main/presets/extensions.example.gates.yaml

Plain-python fallback

For exec-tax-sensitive environments (slow filesystem, EDR overhead) where uvx startup latency matters even with caching, use the installed console script directly:

pip install speckit-gate  # or uv pip install speckit-gate
# then in hooks.json:
# "command": "speckit-gate dispatch pre"

The dispatcher (dispatch.py) is stdlib-only with no import overhead. uvx caches after first run and is the default wiring; switch to the installed path only when profiling shows hook latency is a problem.

Development

uv sync --dev
uv run pytest
uv run speckit-gate --help

License

Apache-2.0

Project details


Download files

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

Source Distribution

speckit_gate-0.2.1.tar.gz (50.2 kB view details)

Uploaded Source

Built Distribution

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

speckit_gate-0.2.1-py3-none-any.whl (30.2 kB view details)

Uploaded Python 3

File details

Details for the file speckit_gate-0.2.1.tar.gz.

File metadata

  • Download URL: speckit_gate-0.2.1.tar.gz
  • Upload date:
  • Size: 50.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for speckit_gate-0.2.1.tar.gz
Algorithm Hash digest
SHA256 b72d8dc1558056057ade6c939c5efb135d6433efa43a74a1f827d1d5840a10b2
MD5 74b53d2c0604aeb31384083e95a876ff
BLAKE2b-256 8652cb5a20d146dcd6ee60b957fbaba5aca8c0a107fc4db11377c8eee72e9f1a

See more details on using hashes here.

Provenance

The following attestation bundles were made for speckit_gate-0.2.1.tar.gz:

Publisher: release-please.yml on srobroek/speckit-gate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file speckit_gate-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: speckit_gate-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 30.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for speckit_gate-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b8c03fad924e6c4eadc8c88834800f5234224a526a081b5d6eeee26a8c03acac
MD5 abf40e8b07de57264220e376e5715329
BLAKE2b-256 03b730593815688dbcf1e81f7ea79f6b75947bcc0f21748d37d89c7b46865f8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for speckit_gate-0.2.1-py3-none-any.whl:

Publisher: release-please.yml on srobroek/speckit-gate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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