A state machine harness for AI agent tool enforcement.
6 layers, left-to-right data flow:
- External Actors — AI agents (opencode, Claude Code, Cursor) + Developers
- Plugin Layer — Thin adapters (<100 lines each) that intercept tool calls
- MCP Gateway — MCP Streamable HTTP server plus FastAPI services for auth, session management, workflow CRUD, and run history
- Python Engine — Pure FSM function
check(phase, tool, workflow) → bool - Session Store — Redis (hot sessions), Turso (persistent data), horizontally scalable
- Dashboard — Vanilla JS SPA: visual editor, YAML editor, run history
Kitsune wraps your AI coding agent in a finite state machine. Each workflow phase gates which tools are available.
PLAN → read, grep, glob
IMPLEMENT → read, edit, write
TEST → read, bash (pytest, npm test, cargo test)
DONE → workflow complete
The agent must emit triggers (READY, DONE, PASS, FAIL) to advance. Try the wrong tool in the wrong phase? Blocked. Tests fail? Loops back to IMPLEMENT.
Design workflows on a canvas, lock tools to each phase, and export to YAML — all from your browser.
# 1. Sign up at kitsune.ai → Generate API key
# 2. Install plugin
opencode plugin install kitsune
opencode configure kitsune --key sk_live_abc123
# 3. Design workflow in browser, then run agent
opencode "fix the bug in auth.py"Connect an MCP client to the Streamable HTTP endpoint at /mcp/ and send the
Kitsune API key in the api-key header. The server exposes:
kitsune_check_tool— checks a proposed agent tool call against the active phasekitsune_transition— applies a workflow transition triggerkitsune_get_state— returns the active phase and session counters
The previous REST endpoints remain available at /internal/mcp/check,
/internal/mcp/transition, and /internal/mcp/get_state for debugging and a
gradual client migration. Their original /mcp/... aliases are temporarily
retained for backward compatibility.
id: bugfix
initial: plan
phases:
plan:
tools: [read, grep, glob]
max_turns: 8
on:
READY: implement
implement:
tools: [read, edit, write]
max_edits: 20
on:
DONE: test
test:
tools: [read, bash]
commands: [pytest, cargo test, npm test]
on:
PASS: done
FAIL: implement
done:
type: final- Bash discernment — blocks redirects, destructive ops, script interpreters
- Edit limits — max lines per edit, max files per phase
- Command allowlists — only allowed test commands
- Turn limits — breaks read-loop death spirals
- Approval gates — human review before advancing


