# How it works

> How agentjail intercepts tool calls, evaluates them offline, and returns a verdict before any command reaches the shell.

agentjail sits at the boundary between your coding agent and the tools it can
call. It intercepts every outgoing tool call, evaluates it against your policy,
and returns a verdict before the call is handed off to the shell, filesystem, or
network.

## The tool-call boundary

Coding agents expose a lifecycle hook called `PreToolUse`. This hook fires
before a tool call executes, giving agentjail a chance to inspect it and either
pass it through, block it, or ask the user to confirm.

```text
  your agent ──tool call──▶  agentjail-hook ──▶  agentjail-daemon ──allow──▶  shell / files / network
 (Claude Code)               (PreToolUse hook)    (OPA / Rego)      └─ask───▶  user prompted
                                                                     └─deny──▶  blocked
                                                                                (e.g. rm -rf ~/.ssh)
```

The `agentjail-hook` binary (installed in `~/.agentjail/bin/`) receives the
tool-call payload and forwards it over a Unix socket to the persistent
`agentjail-daemon` process. The daemon keeps OPA warm and evaluates your Rego
policy in under 5 ms, then returns the verdict. The hook prints the decision to
the agent and exits.

Nothing runs until agentjail has evaluated the call. If the call is denied,
the command never reaches the shell.

> **Integration status:** Claude Code is fully supported. Codex and Cursor
> integrations are not yet available.

## What agentjail evaluates

Each tool call arrives as a structured object. The fields your policy can
inspect include:

- `input.tool_name`: the name of the tool being called (for example, `"Bash"`).
- `input.tool_input`: the arguments for that tool (for example,
  `{"command": "rm -rf ~/.ssh/"}`).
- `input.hook_event`: the lifecycle hook name (always `"PreToolUse"`).
- `input.session_id`: the agent session identifier.
- `input.cwd`: the agent's current working directory.

For a `Bash` tool call the shell command is at `input.tool_input.command`. For
`Write` and `Edit` calls the target file is at `input.tool_input.file_path`.
MCP tools surface as `input.tool_name` values like `mcp__server__tool`.

Your policy rules inspect these fields and decide whether to allow, ask, or
deny. See [The policy model](/docs/concepts/policy-model) for how rules are
written.

## Offline evaluation

Evaluation runs entirely on the local machine. There is no network call at
decision time, no external service, and no model in the decision loop. This
keeps verdicts fast and deterministic: the same tool call produces the same
verdict every time, regardless of network conditions or service availability.

## Allow, ask, and deny

There are three possible verdicts:

- **allow** — the call proceeds normally.
- **ask** — the hook prompts the user to confirm before proceeding.
- **deny** — the call is blocked; the command never reaches the shell.

A call is **denied** if any `deny` rule in your policy fires. If an `ask` rule
fires (and no `deny` rule does), the user is prompted. If neither fires, the
call is **allowed**.

See [Verdicts](/docs/concepts/verdicts) for the full semantics and what the
agent receives on each outcome.

## What happens on a denial

When a call is denied, agentjail returns a structured block message to the
agent and exits with status code 2 (the Claude fast-block convention). The
agent receives the denial reason and stops rather than proceeding. The command
is never handed to the shell.

You can test this manually while the daemon is running:

```sh
echo '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"rm -rf ~/.ssh/"}}' \
  | agentjail-hook
```

You can also unit-test Rego policies directly with `opa test`.

## Why this approach

Enforcing policy at the tool boundary, offline, has a few practical
consequences:

- **No false sense of safety from latency.** There is no window between "agent
  decides to act" and "policy is checked." The check is synchronous and happens
  before execution.
- **Auditable.** Every rule is plain text you can read, diff, and version
  alongside your project.
- **Works without network.** Useful in air-gapped environments, strict CI, or
  anywhere an outbound call would be blocked.

## Next steps

- [The policy model](/docs/concepts/policy-model): how rules are written and
  evaluated.
- [Verdicts](/docs/concepts/verdicts): the exact semantics of allow, ask, and deny.
