Agent harness integration
Agent harnesses do not just generate code—they make dozens of narrow control-flow decisions on every turn: which tool or skill to load, whether a shell command is safe to auto-approve, whether untrusted output contains a prompt injection, and whether test logs actually verify the claim.
Calling a generative model (Claude Haiku 4.5, Sonnet 5, GPT-6 Sol) for those checks costs $1.25 to $6.50 per 1,000 decisions and adds 500–2,000 ms of token decoding on every step. mouse-1 scores up to 128 typed questions against your state in a single forward pass in ~40–100 ms for $0.10 / 1M input tokens ($0.02 / 1M cached, $0 output).
Where mouse-1 saves money in an agent loop
Section titled “Where mouse-1 saves money in an agent loop”| Harness decision point | What mouse-1 replaces | How it saves money & latency |
|---|---|---|
| 1. Tool & skill routing (guide) | Stuffing 30–100 MCP tool or skill definitions into every frontier model turn | Score all candidate tools with one choice question (~$0.00001), then load only the top 1–3 tools into your frontier model—cutting main-model input tokens by 40–70%. |
| 2. Action gating & auto-approval (guide) | Interrupting the human on every Bash / Write call, or paying a chat LLM to judge safety | Evaluate safe and destructive noul predicates in ~40 ms. Safe local commands run unblocked; destructive commands return deny with a reason so the agent re-plans immediately. |
| 3. Post-tool verification & stop check (guide) | Blindly trusting "done" claims or burning 3–5 frontier turns repeating a broken fix | Score { goal, diff, test_log } at turn end. Catching a contradicted claim or repeated failure early saves $0.50–$2.00 in wasted frontier model retries. |
| 4. Prompt-injection guard (guide) | Exposed control flow when reading untrusted GitHub issues, web pages, or logs | mouse-1 treats state strictly as data (0% decision flip rate on planted instructions vs 65.4% on TypeSafe Jev). |
1. Drop-in hooks for coding agents (zero prompt changes)
Section titled “1. Drop-in hooks for coding agents (zero prompt changes)”If you use Cursor, Claude Code, or OpenCode, you can wire mouse-1 into the harness's native lifecycle hooks in under 60 lines. Your system prompt and main model stay untouched:
allow→ executes immediately without interrupting you.deny+ reason → blocks the tool call and feeds the reason back to the coding agent so it re-plans on its own.ask→ falls back to the native confirmation prompt when confidence is in the middle band.
Cursor (.cursor/hooks.json)
Section titled “Cursor (.cursor/hooks.json)”Cursor supports project-level command hooks on beforeShellExecution, preToolUse, postToolUse, and stop.
Create .cursor/hooks.json:
{ "version": 1, "hooks": { "beforeShellExecution": [ { "command": ".cursor/hooks/mouse-gate.py", "failClosed": true } ] }}Create .cursor/hooks/mouse-gate.py and make it executable (chmod +x .cursor/hooks/mouse-gate.py):
#!/usr/bin/env python3"""Cursor beforeShellExecution gate powered by mouse-1."""import json, os, sys, urllib.request
TAU_SAFE = float(os.environ.get("MOUSE_TAU_SAFE", "0.85"))TAU_DESTRUCTIVE = float(os.environ.get("MOUSE_TAU_DESTRUCTIVE", "0.50"))
def decide(state: dict, questions: dict) -> dict | None: key = os.environ.get("MOUSE_API_KEY") if not key: return None req = urllib.request.Request( "https://api.mouse.dev/v1/decisions", data=json.dumps({"model": "mouse-1", "state": state, "questions": questions}).encode(), headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, ) try: with urllib.request.urlopen(req, timeout=2.5) as res: return json.loads(res.read())["answers"] except Exception: return None
ev = json.load(sys.stdin)ans = decide( {"command": ev.get("command", ""), "cwd": ev.get("cwd")}, { "safe": { "type": "noul", "instructions": "Is this shell command safe to run automatically without asking the user?", }, "destructive": { "type": "noul", "instructions": "Does this command delete data, force-push, or exfiltrate secrets?", }, },)
if ans is None: out = {"permission": "ask", "user_message": "mouse-1 unreachable; review command."}elif ans["destructive"]["noul"] >= TAU_DESTRUCTIVE: p = ans["destructive"]["noul"] out = { "permission": "deny", "user_message": f"Blocked destructive command (p={p:.2f}).", "agent_message": f"mouse-1 blocked this command as likely destructive (p={p:.2f}). Use a safer, non-destructive alternative.", }elif ans["safe"]["noul"] >= TAU_SAFE: out = {"permission": "allow"}else: p = ans["safe"]["noul"] out = { "permission": "ask", "user_message": f"mouse-1 confidence below auto-approve threshold (p={p:.2f}).", }
print(json.dumps(out))Claude Code (.claude/settings.json)
Section titled “Claude Code (.claude/settings.json)”Claude Code fires PreToolUse before tool calls and reads hookSpecificOutput.permissionDecision ("allow" | "deny" | "ask") plus permissionDecisionReason from stdout.
Add to .claude/settings.json:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash|Edit|Write", "hooks": [ { "type": "command", "command": ".claude/hooks/mouse-gate.py" } ] } ] }}Save .claude/hooks/mouse-gate.py (chmod +x .claude/hooks/mouse-gate.py):
#!/usr/bin/env python3"""Claude Code PreToolUse gate powered by mouse-1."""import json, os, sys, urllib.request
TAU_SAFE = float(os.environ.get("MOUSE_TAU_SAFE", "0.85"))TAU_DESTRUCTIVE = float(os.environ.get("MOUSE_TAU_DESTRUCTIVE", "0.50"))
def decide(state: dict, questions: dict) -> dict | None: key = os.environ.get("MOUSE_API_KEY") if not key: return None req = urllib.request.Request( "https://api.mouse.dev/v1/decisions", data=json.dumps({"model": "mouse-1", "state": state, "questions": questions}).encode(), headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, ) try: with urllib.request.urlopen(req, timeout=2.5) as res: return json.loads(res.read())["answers"] except Exception: return None
ev = json.load(sys.stdin)ans = decide( {"tool": ev.get("tool_name"), "input": ev.get("tool_input"), "cwd": ev.get("cwd")}, { "safe": { "type": "noul", "instructions": "Can this tool call run automatically without asking the user?", }, "destructive": { "type": "noul", "instructions": "Does this delete, overwrite, or exfiltrate sensitive data?", }, },)
if ans is None: decision, why = "ask", "mouse-1 unreachable; falling back to user prompt"elif ans["destructive"]["noul"] >= TAU_DESTRUCTIVE: decision, why = ( "deny", f"mouse-1: likely destructive (p={ans['destructive']['noul']:.2f}); re-plan with a safe command", )elif ans["safe"]["noul"] >= TAU_SAFE: decision, why = "allow", f"mouse-1: auto-approved (p={ans['safe']['noul']:.2f})"else: decision, why = "ask", f"mouse-1: requires confirmation (p={ans['safe']['noul']:.2f})"
print( json.dumps( { "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": decision, "permissionDecisionReason": why, } } ))OpenCode (.opencode/plugins/mouse-gate.ts)
Section titled “OpenCode (.opencode/plugins/mouse-gate.ts)”OpenCode plugins hook tool.execute.before (throwing an error blocks the call and returns the message to the agent) and tool.execute.after (mutating output.output appends verification feedback):
const TAU_SAFE = Number(process.env.MOUSE_TAU_SAFE ?? 0.85);const TAU_DESTRUCTIVE = Number(process.env.MOUSE_TAU_DESTRUCTIVE ?? 0.50);
async function decide(state: unknown, questions: Record<string, unknown>) { const key = process.env.MOUSE_API_KEY; if (!key) return null; try { const res = await fetch("https://api.mouse.dev/v1/decisions", { method: "POST", headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "mouse-1", state, questions }), signal: AbortSignal.timeout(2500), }); return res.ok ? ((await res.json()) as any).answers : null; } catch { return null; }}
export const MouseGatePlugin = async () => ({ "tool.execute.before": async (input: { tool: string }, output: { args?: unknown }) => { const ans = await decide( { tool: input.tool, args: output.args ?? {} }, { safe: { type: "noul", instructions: "Can this tool call run without asking the user?" }, destructive: { type: "noul", instructions: "Does this delete, overwrite, or exfiltrate data?", }, }, ); if (!ans) return; if (ans.destructive.noul >= TAU_DESTRUCTIVE) { throw new Error( `mouse-1 blocked ${input.tool} (p=${ans.destructive.noul.toFixed(2)}). Re-plan with a safer command.`, ); } }, "tool.execute.after": async ( input: { tool: string; args?: unknown }, output: { output?: string }, ) => { if (input.tool !== "bash") return; const ans = await decide( { tool: input.tool, args: input.args, output_tail: String(output.output ?? "").slice(-2000) }, { failed: { type: "noul", instructions: "Did the command fail or contradict the expected outcome?", }, }, ); if (ans && ans.failed.noul >= TAU_SAFE) { output.output = `${output.output ?? ""}\n<mouse-judge>Command output indicates failure (p=${ans.failed.noul.toFixed(2)}). Fix the root cause before repeating.</mouse-judge>`; } },});2. Native integration in your own agent harness
Section titled “2. Native integration in your own agent harness”When you own the agent loop (TypeScript, Python, LangGraph, Vercel AI SDK, or OpenAI Agents SDK), evaluate every decision point for a step in one batched request against the same state:
const res = await fetch("https://api.mouse.dev/v1/decisions", { method: "POST", headers: { Authorization: `Bearer ${process.env.MOUSE_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "mouse-1", // Put shared rubrics/schemas first so repeated turns hit the $0.02/1M prefix cache state: { task: userPrompt, git_status: gitStatus, last_tool_output: lastToolOutput, }, questions: { route_skill: { type: "choice", instructions: "Which skill should be loaded into context for `task`?", criteria: { database_migration: "Schema changes, Drizzle/SQL migrations, or index tuning", stripe_billing: "Webhooks, checkout sessions, or credit ledger updates", ui_verification: "Mobile or web component layout and visual checks", none: "No specialized skill needed", }, }, needs_repo_sandbox: { type: "noul", instructions: "Does answering `task` require booting a code sandbox to read or edit files?", }, previous_step_verified: { type: "noul", instructions: "Does `last_tool_output` confirm the previous step succeeded without errors?", }, }, }), signal: AbortSignal.timeout(3000),});Because state tokens are billed once per request regardless of how many questions you attach (up to 128), fanning out routing, sandbox-boot gating, and verification in a single call costs ~$0.00001 and completes in one forward pass.
3. One-click prompt for Cursor, Claude Code, and Codex
Section titled “3. One-click prompt for Cursor, Claude Code, and Codex”Click Copy for Agent in the top docs bar (or copy below) and paste it into your coding agent to wire mouse-1 into your repository automatically:
Integrate the Mouse Decision API (mouse-1) into this codebase or agent harness to cut LLM decision costs and latency.
Full documentation & schemas:- Full LLM docs: https://www.mouse.dev/llms-full.txt (also https://www.mouse.dev/llm.txt)- Docs index: https://www.mouse.dev/llms.txt- OpenAPI 3.1 spec: https://www.mouse.dev/openapi.json
1. Wire Contract- Endpoint: POST https://api.mouse.dev/v1/decisions (alias POST /v1/systemone)- Headers: Authorization: Bearer $MOUSE_API_KEY (sk_mouse_... from https://www.mouse.dev/console/keys), Content-Type: application/json- Model: "mouse-1" (~40-100ms single forward pass, $0.10/1M input tokens, $0.02/1M cached input, $0 output, Zero Data Retention)- Question types (up to 128 evaluated in parallel per request; state billed once): - choice: { "type": "choice", "instructions"?: string, "criteria": { "<opt>": "<desc>" | null } } -> { choice, confidence, probabilities, mouse } - noul: { "type": "noul", "instructions": "<yes/no question>" } -> { noul, probabilities: { false, true }, mouse } - score: { "type": "score", "instructions"?: string, "criteria": ["<level 0>", "<level 1>", ...] } -> { score, confidence, legend, probabilities, mouse }
2. Your Task- Inspect this repository to find the highest-leverage agent decision points (replacing slow LLM classification/routing prompts, pruning MCP tools/skills before calling the main model, gating risky tool executions, or verifying tool outputs).- Or, if configuring a coding agent harness, add a lifecycle hook adapter (.cursor/hooks.json beforeShellExecution/preToolUse, .claude/settings.json PreToolUse, or .opencode/plugins/mouse-gate.ts).- Implement a zero-dependency client reading MOUSE_API_KEY with a 3s timeout and safe fallback when the key is unset, document MOUSE_API_KEY in .env.example, and add a verification test.4. Machine-readable endpoints
Section titled “4. Machine-readable endpoints”| URL | Format | Purpose |
|---|---|---|
/llms.txt | text/plain | Curated LLM index + quick-reference wire contract (< 5k tokens). |
/llms-full.txt | text/plain | Complete documentation concatenated into a single Markdown file. |
/llm.txt / /llm.text | text/plain | All-in-one agent setup prompt + hook adapters + full docs bundle. |
/openapi.json | application/json | OpenAPI 3.1 specification with full request/response schemas and examples. |
/docs/<path>.md | text/markdown | Append .md to any docs URL (e.g. /docs/agents.md) for raw Markdown. |