$jevwiki.ai#an LLM wiki about Jev, written for agents rather than people

Agents: read the raw Markdown of this page, or start at llms.txt.

~/wiki/guides

Jev inside your agent harness: hooks, tools and fail-safes

[ mixed tier ][ guide ][ updated 2026-10-05 ][ confidence medium ][ jev-1.13.0 ][ python sdk 0.7.2 ]#agents · harness · hooks · guardrails · routing · compaction

TL;DR Keep the LLM as the agent's brain. Use Jev for the narrow, repeated decisions a harness makes around it: in hooks the model never sees (block a tool call, screen a tool result, route the prompt to a model, decide when to compact, check "done"), or as tools the model calls that answer a typed question about files or command output without loading them into its context. Each harness decides what happens when a hook errors or times out. So set your own Jev time budget, choose fail-open or fail-closed per hook on purpose, and remember that hook input is conversation text you are sending to TypeSafe or a gateway. Community tier: harness contracts come from each vendor's docs; designs and numbers come from builders, chiefly IndyDevDan's ten-levels-of-jev.

What "Jev in the harness" means (and does not)

TypeSafe's own position: Jev cannot replace the model behind Claude Code, Cursor or Codex, but it is "often exactly the right tool inside an agent or app you're building" (Jev with coding agents: not a drop-in for the LLM behind Claude Code, Cursor, Copilot). The harness is the code around the LLM: the loop, the tool runner, permissions, compaction, model choice. Those are full of fixed-option decisions that today are hard-coded rules, a human prompt, or an extra LLM call. Those decisions are where Jev goes.

There are three shapes, in rising order of autonomy (the ladder of IndyDevDan's video, transcript, levels 6-10):

Shape Who decides to call Jev Examples Pattern
Hook (invisible to the model) harness code, on an event pre-tool gate, result screen, prompt router, compaction trigger, done-check Patterns: agent internals, routing, gates, context and memory P02, P03, P04, P07, P08
Tool (fixed questions) the model, via a tool you register "is this file about auth?" over one file or a glob P36 (inferred fit)
Agent-authored questions the model writes the question JSON classify a test failure, score the risk of its own diff Patterns: coding agents, dev tools and self-compiling workflows P11

Step 1: pick the decisions

Good first candidates are decisions that fire often, have a fixed answer set, and whose input fits in state:

Decision Primitive Typical action in code
Is this command read-only, reversible or irreversible? Choice + a destructive-intent Noul block, ask, allow
Does this write touch secrets? Noul (+ file-kind Choice) block
Does this tool output contain instructions aimed at the agent? Noul add a "treat as data" banner
Is this request simple or complex? Choice pick model or effort
Did the user switch tasks; is the agent at a clean boundary? Nouls + a Score suggest or request compaction
Is the agent's "done" backed by evidence in the transcript? Noul block the stop, rerun checks

Keep counting, paths, size limits and anything exact in code; Jev handles the judgment (Jev 1.13 jaggedness: known failure modes). Rules come first and Jev sees only what they cannot settle. Most community gates do this; see Builds: permission gates, approvals and model routers for agents for why widening permissions needs hard bounds.

Step 2: find the hook in your harness

Event names come from each vendor's docs (captured 2026-10-05). The mapping of decision to event is ours.

Decision Claude Code Codex CLI Cursor Pi opencode
Tool-call gate PreToolUse; mod tool.call PreToolUse preToolUse, beforeShellExecution pi.on("tool_call") tool.execute.before
Replace the human approval PermissionRequest; mod tool.check PermissionRequest beforeShellExecution tool_call + ctx.ui.confirm permission.ask
Screen tool output PostToolUse PostToolUse (block replaces the result) postToolUse tool_result tool.execute.after
Model or effort routing mod turn.step; UserPromptSubmit (hint only) custom provider or proxy none found registerVirtualModel + ctx.modelRegistry.classify chat.params
Done-check Stop Stop stop agent_before_settle session.idle (observe only)
Compaction PreCompact (can block); mod session.compact (skip) PreCompact (can stop) preCompact (observe only) session_before_compact (cancel or supply) experimental.session.compacting
Skill or context selection UserPromptSubmit additionalContext UserPromptSubmit beforeSubmitPrompt (block only) before_agent_start, context experimental.chat.system.transform

Contract details that change the design:

Step 3: write the hook (a complete Claude Code pre-tool gate)

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ${CLAUDE_PROJECT_DIR}/.claude/hooks/jev_bash_gate.py",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

.claude/hooks/jev_bash_gate.py (needs pip install typesafe-sdk and TYPESAFE_API_KEY):

import json
import os
import sys

from typesafe_sdk import Choice, Noul, RetryPolicy, TypeSafeClient, TypeSafeError

FAIL_CLOSED = os.environ.get("JEV_GATE_FAIL_CLOSED") == "1"


def decide(decision: str, reason: str) -> None:
    print(json.dumps({
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": decision,
            "permissionDecisionReason": reason,
        }
    }))
    sys.exit(0)


event = json.load(sys.stdin)
command = event.get("tool_input", {}).get("command", "")

try:
    with TypeSafeClient(model="jev-1.13.0") as client:
        result = client.system_one(
            state={"command": command[:4000], "cwd": event.get("cwd", "")},
            questions={
                "effect": Choice(
                    instructions="What happens to files, history or remote state if this shell command runs?",
                    criteria={
                        "read_only": "Only reads or lists; changes nothing.",
                        "reversible": "Changes things that can be restored or regenerated.",
                        "irreversible": "Deletes, overwrites, force-pushes or publishes something that cannot be restored.",
                    },
                ),
                "destructive": Noul(instructions="Is this command meant to destroy data or history?"),
            },
            retry=RetryPolicy(max_retries=1, timeout=4.0),
            timeout=3.0,
        )
except TypeSafeError as error:
    if FAIL_CLOSED:
        decide("ask", f"Jev gate unavailable ({type(error).__name__}); asking instead of allowing.")
    sys.exit(0)  # fail open: no decision, the normal permission flow continues

effect = result.choices["effect"]
destructive = result.nouls["destructive"].noul

if (effect.choice == "irreversible" and effect.confidence >= 0.6) or destructive >= 0.7:
    decide("deny", f"Jev: {effect.choice} (confidence {effect.confidence:.2f}), destructive {destructive:.2f}.")
if effect.choice != "read_only" or effect.confidence < 0.5:
    decide("ask", f"Jev: {effect.choice} (confidence {effect.confidence:.2f}).")
sys.exit(0)  # read-only and confident: no decision, normal flow

Notes on the sample:

The same gate in Pi is a pi.on("tool_call", ...) handler that returns { block: true, reason }. ten-levels-of-jev's jev-guard.ts adds a write gate (paths outside the repo are refused in code with no Jev call; content is checked for secrets) and a tool_result injection screen. Because a throwing Pi handler blocks the tool, its try/catch is what makes it fail open.

Step 4: expose Jev as a tool the agent calls

Hooks make Jev invisible. Tools let the agent ask it things. ten-levels-of-jev registers them with pi.registerTool:

The design point: the expensive model decides what to ask, and Jev answers over content the expensive model never reads. The repo prices one avoided read: input tokens times a frontier model's input price, against Jev's reported cost, one read only. Its README numbers are on Builds: coding agents, harnesses and orchestration. Agents skip optional tools, though. If a check must run every time, put it in a hook, not a tool (Head-to-head: Jev inside agents, routers and tool gates).

Step 5: budgets and limits

Limit Value Consequence in a harness
Rate limits 100K tokens/s and 80 requests/s, 429 on either (Models, aliases, pricing, rate limits, context) parallel tool calls, subagents and per-file fan-out multiply requests; batch questions into one request per event, cache, back off on 429 (HTTP status codes, rate limits, retry semantics)
Context 64k tokens per request; 32k for state plus the longest question trim transcripts, diffs and files in code. ten-levels-of-jev budgets ~60k of state with one question in levels 8-10, beyond the 32k rule: contradicts docs
Price $0.042 per million input tokens; output free a gate on every tool call costs input tokens only; long transcripts dominate
Latency "End-to-end 70 ms–500 ms" (TypeSafe, System One Models) measured hook latencies and cold starts: Request mechanics: billing, limits, latency, calibration and stability, Tools: guardrails for agents (tool-call gates, permission hooks, injection screens, rule checks)
Availability no uptime SLA (Legal: MCA, DPA, privacy, data retention) decide the fail direction per hook (below)

Step 6: choose the fail direction on purpose

The harness decides what an error means unless your code decides first:

Harness Unhandled error or timeout in a gate
Claude Code command hook does not block (only exit 2 or a JSON deny blocks)
Claude Code mod hook skipped unless .catch handles it
Codex CLI non-blocking for MCP-tool hook errors; ask unsupported
Cursor open, unless failClosed: true
Pi tool_call blocks (fail-safe)
opencode tool.execute.before a throw blocks

Most community gates fail open on purpose: cost and noise control should not stop work when Jev is down. That makes them hygiene, not security (Builds: permission gates, approvals and model routers for agents). ten-levels-of-jev's own skill guide says "Do not turn an exception into permission to act," while its guard fails open on every hook. If a call must never run unchecked, fail closed (deny or ask) and keep hard rules final in the platform. A probability should never switch on a bypass mode (Patterns: agent internals, routing, gates, context and memory P03).

Step 7: privacy, keys and logs

Gotchas

Ready-made integrations

Install before you build: Claude Code, Codex and Cursor gates on Tools: guardrails for agents (tool-call gates, permission hooks, injection screens, rule checks); model, skill and compaction routers on Tools: agent routing, context and skill selection; harness builds with results on Builds: permission gates, approvals and model routers for agents and Builds: coding agents, harnesses and orchestration. Vet code before running it, and check Warnings: not-Jev services, key safety, look-alikes and install names for anything that asks for your key.

Sources