# Use agentseam without chock

Install agentseam, write a handler, wire it into your agents' hooks and see it refuse, from a recorded run.

A handler is a Python function that takes an Event and returns a Decision. Agentseam wires the command that runs it into each agent's hook config. Every output on this page is from a real run, recorded with the agentseam release this site documents.

> Ask the user before running any command on this page: each one changes how their agent or repository behaves.

## Install

Agentseam is one Python package with no runtime dependencies and one console script, `agentseam`. Installing chock installs it too, at the commit below. Agentseam's README installs it from PyPI with `pip install agentseam`. A PyPI release can differ from this commit. To get the code these pages document, install from the commit (ask the user before running it):

```bash
pip install "agentseam @ git+https://github.com/open-coder-ai/agentseam@17dd700eb0b1f8af9c6bfd42bd9438fd5e4445cb"
```

It needs Python >=3.9.

## The files

The run below starts in an empty git repository holding these files. `my_handler.py` is the handler from agentseam's README Quick start, word for word. The site's tests check it against agentseam's `docs/quickstart.sh` at the pinned commit. The two payloads take the shape of the Claude Code `PreToolUse` example in agentseam's `examples/generated/claude_code.md`, with their content changed. [examples/generated/claude_code.md](https://github.com/open-coder-ai/agentseam/blob/17dd700eb0b1f8af9c6bfd42bd9438fd5e4445cb/examples/generated/claude_code.md)

### my_handler.py

The handler. `run(handler)` reads one payload from stdin, identifies the agent that sent it (best effort, with `adapters.detect`), calls the handler with the normalized Event, and prints the reply in that agent's dialect.

```python
from agentseam import run, Decision

def handler(event):
    if event.event == "pre_tool" and "AKIA" in (event.content or ""):
        return Decision.deny("no AWS keys in memory files")
    return Decision.allow()

run(handler)
```

### deny.json

A Claude Code PreToolUse payload: the agent wants to write a line with `AKIA` in it to AGENTS.md.

```json
{"cwd": "/repo", "hook_event_name": "PreToolUse", "permission_mode": "default", "session_id": "example", "tool_input": {"content": "aws_access_key_id = AKIA-PLACEHOLDER", "file_path": "AGENTS.md"}, "tool_name": "Write", "transcript_path": "/repo/.claude/transcript.jsonl"}
```

### allow.json

The same payload with harmless content.

```json
{"cwd": "/repo", "hook_event_name": "PreToolUse", "permission_mode": "default", "session_id": "example", "tool_input": {"content": "Use ruff for lint.", "file_path": "AGENTS.md"}, "tool_name": "Write", "transcript_path": "/repo/.claude/transcript.jsonl"}
```

### in_process.py

The same check called in process with `handle()`, which returns the reply instead of printing it.

```python
import json

from agentseam import Decision, handle


def handler(event):
    if event.event == "pre_tool" and "AKIA" in (event.content or ""):
        return Decision.deny("no AWS keys in memory files")
    return Decision.allow()


with open("deny.json", encoding="utf-8") as payload:
    raw = json.load(payload)
text, code, event, decision = handle(raw, handler, "claude_code")
print("event:", event.agent, event.event, event.tool, event.path)
print("decision:", decision.outcome, decision.reason)
print("exit code:", code)
print("printed:", text)
```

## The recorded run

Real runs, recorded by `python -m sitegen.agentseamdoc run --record` with agentseam at the pinned commit. The steps of `data/agentseam-run.yaml` ran in order, offline, in one fresh git repository at `/work/demo` (made with `git init -b main`), with HOME at `/home/demo`. Those paths stand for the throwaway folders the runs used. Output is stdout and stderr together. CI re-runs the steps and fails when any output or exit code differs.

Step 1 of 9, exit code 0. The version of the installed agentseam. Ask the user before running the commands below:

```text
$ agentseam --version
0.4.1
```

Step 2 of 9, exit code 0. Every agent in agentseam's matrix: its id, tier and hook config file. `install` takes these ids, or `all`. Ask the user before running the commands below:

```text
$ agentseam agents
aider            none           (no hook config)
amp              unadapted      (no hook config)
antigravity      block+rewrite  .agents/hooks.json
claude_code      block+rewrite  .claude/settings.json
cline            block          .clinerules/hooks
codex_cli        block+rewrite  .codex/hooks.json
copilot          unadapted      (no hook config)
cursor           block+rewrite  .cursor/hooks.json
deepseek_harness unadapted      (no hook config)
devin            block+rewrite  .devin/hooks.v1.json
factory_droid    block          .factory/hooks.json
gemini_cli       block+rewrite  .gemini/settings.json
goose            block          .agents/plugins/agentseam/hooks/hooks.json
grok             block          .grok/hooks/agentseam.json
junie            block+rewrite  ~/.junie/config.json
kilo_code        unadapted      (no hook config)
kimi_code        block          ~/.kimi-code/config.toml
kiro             unadapted      (no hook config)
mistral_vibe     block+rewrite  .vibe/hooks.toml
opencode         unadapted      (no hook config)
openhands        block          .openhands/hooks.json
replit           unadapted      (no hook config)
roo_code         unadapted      (no hook config)
tabnine          block+rewrite  .tabnine/agent/settings.json
vscode_copilot   block+rewrite  .github/hooks/*.json
windsurf         block          .devin/hooks.json
zed              none           (no hook config)
```

Step 3 of 9, exit code 0. The README's install line. It wires `python3 my_handler.py` at `pre_tool` into each agent that has a hook adapter, and prints each agent's grade there. Junie's and Kimi Code's config files sit under HOME. Ask the user before running the commands below:

```text
$ agentseam install all 'python3 my_handler.py' --events pre_tool --repo .
wired antigravity      -> .agents/hooks.json   [pre_tool=best-effort]
wired claude_code      -> .claude/settings.json   [pre_tool=best-effort]
wired cline            -> .clinerules/hooks   [pre_tool=best-effort]
                       not live until trusted: in the VS Code extension, tick Enable Hooks under Cline's Feature settings; hooks run on macOS and Linux only
wired codex_cli        -> .codex/hooks.json   [pre_tool=best-effort]
                       not live until trusted: run /hooks in Codex and trust the new hook (trust is per hook hash: re-trust after any change)
wired cursor           -> .cursor/hooks.json   [pre_tool=enforceable]
wired devin            -> .devin/hooks.v1.json   [pre_tool=best-effort]
wired factory_droid    -> .factory/hooks.json   [pre_tool=best-effort]
wired gemini_cli       -> .gemini/settings.json   [pre_tool=best-effort]
wired goose            -> .agents/plugins/agentseam/hooks/hooks.json   [pre_tool=best-effort]
wired grok             -> .grok/hooks/agentseam.json   [pre_tool=best-effort]
                       not live until trusted: trust it in the agent
wired junie            -> /home/demo/.junie/config.json   [pre_tool=best-effort]
wired kimi_code        -> /home/demo/.kimi-code/config.toml   [pre_tool=best-effort]
wired mistral_vibe     -> .vibe/hooks.toml   [pre_tool=best-effort]
                       not live until trusted: trust it in the agent
wired openhands        -> .openhands/hooks.json   [pre_tool=best-effort]
wired tabnine          -> .tabnine/agent/settings.json   [pre_tool=best-effort]
wired vscode_copilot   -> .github/hooks/agentseam.json   [pre_tool=best-effort]
wired windsurf         -> .devin/hooks.json   [pre_tool=best-effort]
```

Step 4 of 9, exit code 0. What it wrote for Claude Code. Agentseam marks each entry `_agentseam`, so `uninstall` removes only its own entries. Ask the user before running the commands below:

```text
$ cat .claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 my_handler.py claude_code",
            "_agentseam": "agentseam"
          }
        ],
        "_agentseam": "agentseam"
      }
    ]
  }
}
```

Step 5 of 9, exit code 0. The hook as Claude Code runs it, fed the payload with `AKIA`. The handler returned `Decision.deny`, and agentseam printed the refusal in Claude Code's `PreToolUse` dialect. Ask the user before running the commands below:

```text
$ python3 my_handler.py < deny.json
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "no AWS keys in memory files"}}
```

Step 6 of 9, exit code 0. The harmless payload. The handler returned `Decision.allow()`, and agentseam printed nothing: the exit code carries the answer. Ask the user before running the commands below:

```text
$ python3 my_handler.py < allow.json
```

Step 7 of 9, exit code 0. In process, `handle()` returns the normalized Event, the Decision, the exit code and the text `run()` would print. Ask the user before running the commands below:

```text
$ python3 in_process.py
event: claude_code pre_tool Write AGENTS.md
decision: deny no AWS keys in memory files
exit code: 0
printed: {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "no AWS keys in memory files"}}
```

Step 8 of 9, exit code 0. `uninstall all` removes agentseam's entries from every agent's config. Ask the user before running the commands below:

```text
$ agentseam uninstall all --repo .
antigravity      removed
claude_code      removed
cline            removed
codex_cli        removed
cursor           removed
devin            removed
factory_droid    removed
gemini_cli       removed
goose            removed
grok             removed
junie            removed
kimi_code        removed
mistral_vibe     removed
openhands        removed
tabnine          removed
vscode_copilot   removed
windsurf         removed
```

Step 9 of 9, exit code 0. Claude Code's settings file after uninstall. Ask the user before running the commands below:

```text
$ cat .claude/settings.json
{}
```


---

Built from engine [5a4b6287a46e](https://github.com/open-coder-ai/chock/commit/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021) and catalog [1e60d211c1bb](https://github.com/open-coder-ai/chock-catalog/commit/1e60d211c1bb767152c6ab0167932da06ab3a10f).
