# Connect a Live Agent

The [enforced gates](/harness/overview) only do their job when something **feeds** them. Wiring your coding host to feed and gate is the last mile of harness engineering. In Fowler's terms, this is the user's **outer harness**: the model executes, and the hooks feed the sensors and enforce the gates.

## Hooks call the gates blind

The per-change gate commands **auto-resolve** the active change when `--change` is omitted (see [Session timeline](/harness/timeline)). That means a hook can call `forge trace record` or `forge budget record` without ever knowing the change name — Forge resolves the single active change under `.forge/changes/`.

## Ready-to-paste Claude Code hooks

Add this to your `~/.claude/settings.json` (or a project `.claude/settings.json`):

```json
{
  "hooks": {
    "PostToolUse": [
      { "matcher": "*", "hooks": [
        { "type": "command", "command": "forge trace record --kind tool --summary \"agent tool use\" >/dev/null 2>&1 || true" },
        { "type": "command", "command": "forge budget record --tool-calls 1 --max-tool-calls 500 >/dev/null 2>&1 || true" }
      ]}
    ],
    "Stop": [
      { "hooks": [ { "type": "command", "command": "forge verify --change \"$(basename \"$(ls -dt .forge/changes/*/ | grep -v /archive/ | head -1)\")\" || echo 'forge: verify gate — review before continuing'" } ]}
    ]
  }
}
```

## What each hook does

- **`PostToolUse`** appends a `tool` event to the [timeline](/harness/timeline) and increments the tool-call budget on the active change. The event is attributed to the git identity (see [Team collaboration](/features/team)). The `--max-tool-calls 500` gives the [budget](/harness/budget) a ceiling to check against — set `--max-tokens` / `--max-usd` too if your host exposes those numbers. Because this line feeds best-effort with `|| true`, the ceiling is recorded but not surfaced here; the `Stop` gate below is where a non-zero exit actually reaches the human.
- **`Stop`** runs the [verify circuit-breaker](/harness/circuit-breaker) against the most recent non-archived change when the agent stops.

::: warning `|| true` vs. deliberate non-zero
The `|| true` on the feeding commands keeps best-effort feeding from ever interrupting the agent — a failed log write must not derail a run. The enforcing gates deliberately do **not** get `|| true`: the verify gate is *meant* to return non-zero so the host surfaces it and the human reviews before continuing.
:::

## The `Stop` hook and OpenCode's `session.idle`: clarify-gate

Forced interactive clarification wires a second, lighter-weight sensor into
the same lifecycle-end moment. `forge install` also appends
`forge clarify-gate` to Claude Code's `Stop` array, next to the verify
circuit-breaker entry above:

```json
{ "hooks": { "Stop": [
  { "hooks": [ { "type": "command", "command": "forge verify --change \"$(basename \"$(ls -dt .forge/changes/*/ | grep -v /archive/ | head -1)\")\" || echo 'forge: verify gate — review before continuing'" } ] },
  { "hooks": [ { "type": "command", "command": "forge clarify-gate --cwd \"${CLAUDE_PROJECT_DIR:-$PWD}\"" } ] }
] } }
```

No `|| true` and no `|| echo` here either — same reasoning as the verify
entry: `clarify-gate` is meant to return non-zero so Claude Code surfaces it.
Unlike verify, it is **not** an enforced gate: it warns on an unresolved
clarifying-question marker and lets the session continue either way. See
[Interactive Clarification](/harness/clarify-gate) for the marker lifecycle
and the honest trust-gap caveat around the `answer` path.

OpenCode has no `Stop` hook, so `forge install` wires the structural
equivalent instead — a `session.idle` plugin at
`~/.config/opencode/plugins/clarify-gate.ts` that `execFile`s
`forge clarify-gate --session-id <id> --format json` when the agent's turn
ends, and surfaces any warning as a toast rather than a console print.

::: warning Two of twelve harnesses
This wiring exists for **Claude Code and OpenCode only**. The other ten
supported harnesses carry the canonical callout Guide in their assets, but no
`Stop`/`session.idle`-equivalent Sensor reads the marker at all — see
[Interactive Clarification](/harness/clarify-gate#the-v1-non-goal-ten-harnesses-are-not-covered)
for the full gap.
:::

## The richer alternative: `forge hook post-tool-use`

Once wired, prefer the single `forge hook post-tool-use` command. It reads the host's payload on stdin and extracts the real tool name, so your timeline records *which* tool was used instead of a generic "agent tool use". Use it in place of the two hand-rolled `PostToolUse` commands when your host delivers a structured payload.

## Marking session boundaries: `forge hook session-start`

If your host also exposes a `SessionStart` lifecycle event, wire it to `forge hook session-start`:

```json
{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "forge hook session-start" } ] } ] } }
```

`PostToolUse` events only exist once a tool has already run, so they can't tell the timeline *when* a distinct session began — gaps between tool-call timestamps don't reliably distinguish "the model thought for a while" from "the agent was restarted". `session-start` records a `session` event on the active change's timeline exactly once per session, without touching the tool-call budget.

## The honest limit

Tool-call count is **reliably** reportable from a `PostToolUse` hook — one call, one increment. Token and dollar spend need **host support**: only your host knows real usage. If it exposes those numbers, pipe them into the ledger:

```sh
forge budget record --tokens <n> --usd <x>
```

::: tip Feed first, then enforce
Start by feeding the timeline and tool-call budget — that works everywhere. Turn on token/$ enforcement only once your host can report the numbers to feed it. See [Spend budget](/harness/budget) for the enforcement semantics.
:::

## Next steps

- [The enforcement doctrine](/harness/overview) — the four controls your hooks feed and gate.
- [The guardrails gate](/harness/guardrails) — the PreToolUse hook that blocks dangerous actions.
- [Verify circuit-breaker](/harness/circuit-breaker) — the gate the `Stop` hook runs.
- [Spend budget](/harness/budget) — the ledger the `PostToolUse` hook feeds.
- [Session timeline](/harness/timeline) — the record every hook writes into.
- [Interactive Clarification](/harness/clarify-gate) — the warn-only `Stop`/`session.idle` sensor and its two-of-twelve-harnesses gap.
