Skip to content

PreToolUse hook to enforce devkit workflow step progression #63

Description

@5uck1ess

Problem

devkit_start returns a per-step prompt and the instruction "call devkit_advance when this step is complete," but nothing actually enforces that. The engine can reject out-of-order advances (via enforce: hard), but it can't force the agent to come back at all — there's no mechanism for an MCP server to veto the agent's next tool call. Once the first step is returned, the agent can make arbitrary unrelated tool calls, skip the remaining 5 steps of a 6-step workflow, and the session just sits running forever.

This was discovered during a PR #62 mega-review where the tri-review workflow's step-1 gather prompt was returned, and then all subsequent steps were silently skipped until it was noticed mid-conversation. The determinism work (24 skills → 8 YAML workflows in the engine) correctly made step ordering, gates, and loops deterministic inside a workflow — but the outer "force the agent to actually use the workflow" loop was never closed.

Proposed architecture

PreToolUse hook that reads devkit session state and blocks non-devkit tool calls when a workflow session is running and the current step is un-advanced.

Components:

  1. Engine CLI flag: devkit-engine session-status [--session <id>] that prints active sessions from the state store as JSON. Read-only, no MCP round-trip needed. Lets a shell hook introspect the engine without depending on the stdio transport.

  2. New hook script: hooks/devkit-workflow-guard.sh — runs as PreToolUse, calls devkit-engine session-status, and if any session is running:

    • Allow: mcp__plugin_devkit_devkit-engine__devkit_advance, devkit_status, and a small read-only allowlist (Read, Grep, Glob, Bash gated on a non-destructive set?) so the agent can gather evidence for the step output.
    • Block everything else with a clear veto message: devkit workflow <name> is at step N/M — call devkit_advance before other tool calls.
  3. Hook registration: add the new hook to the plugin's hooks manifest so it runs on every PreToolUse.

Acceptance criteria

  • After devkit_start, calling any non-allowlisted tool returns a hook veto with the step number + workflow name in the message.
  • devkit_advance correctly advances the step and re-checks the block condition.
  • Session completion (workflow complete) clears the block and normal tool access resumes.
  • Parallel workflows (e.g., mega-pr dispatching tri-review + pr-review-toolkit) either both run to completion or the parent skill only dispatches one at a time — figure out which during design.
  • Unit tests for the allowlist logic + an integration test that exercises the full "start → try to call disallowed tool → blocked → advance → unblock" path.

Out of scope

Context

Discovered in the PR #62 mega-review conversation when 5/6 steps of the tri-review workflow were silently skipped. The engine behaved correctly (returned step 1 prompt, waited for advance); I just never called devkit_advance. A hook is the only layer that can actually veto the next tool call — MCP servers structurally cannot.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions