Skip to main content

Local Agent Hook Setup

This guide captures Claude Code and Codex sessions as Oliver events. Codex hooks capture prompt submit and stop events; Claude Code hooks also capture tool use events.

The current path is split in two:

  • olivergraph (the oliver CLI): installs Claude/Codex hooks, writes hook payloads to a local queue, and can run a periodic uploader.
  • cmd/api: backend server that accepts authenticated POST /events writes scoped by bearer token and X-Workspace.

The uploader normalizes queued hook payloads into Oliver events and posts them to authenticated POST /events.

Prerequisites

Run commands from the repository root unless a step says otherwise.

The CLI targets production by default. For local development, point it at your local stack once per shell (or pass --env local on each command):

export OLIVER_ENV=local
  1. Start the Oliver local stack. For local development:
scripts/start-local-stack.sh
  1. Sign in (optional — oliver start opens this same login on first run):
oliver login

oliver login opens the portal, signs in with Supabase, creates access to the shared default workspace, and saves local credentials in .oliver/agent-hooks. You can skip this and let oliver start prompt the login for you; run it explicitly when you want to re-authenticate or switch workspace.

For headless/dev fallback, mint a token manually and export it:

cd backend
go run ./cmd/issue-token \
--kind agent \
--display-name "Local Agent Hooks" \
--workspace default \
--workspace-name "Default"
cd ..
export OLIVER_API=http://127.0.0.1:8081
export OLIVER_TOKEN=usr_...
export OLIVER_WORKSPACE=default

You can also create a key in the portal under API Keys, copy it once, and save it while starting the uploader:

oliver start --api-key usr_... --workspace default

--api-key is accepted on oliver start only. It writes the token to .oliver/agent-hooks/auth.json and does not pass the token as a daemon argument.

extensions/agent-hooks/.env.example contains the same uploader variables as a local template. Source a copied .env yourself if you prefer file-based setup.

If your API runs on port 8080, use OLIVER_API=http://127.0.0.1:8080.

Install And Start

Install the CLI globally, then run oliver start in the repo you want to capture:

npm install -g olivergraph
cd your-project
oliver start

oliver start is the single entry point: it wires the hooks (idempotent), then runs the background uploader, opening the portal to sign in on first run. It updates only repo-local files by default:

  • .codex/config.toml
  • .claude/settings.local.json
  • .oliver/agent-hooks/config.json

These files are local machine state and are ignored by git. They contain the absolute path to the installed CLI so Claude/Codex can call the collector. Install globally rather than via npx, since an npx cache path can be garbage-collected out from under the installed hooks.

To wire user-global agent config, opt in explicitly:

OLIVER_AGENT_HOOK_SCOPE=user oliver install

That writes ~/.codex/config.toml and ~/.claude/settings.json, so it may need normal filesystem permission to edit files outside the repo.

oliver install (advanced) wires the hooks without starting the uploader — useful for CI, headless setups, or user-scope installs where the uploader runs elsewhere. oliver start covers it for the common case.

Local Queue And Upload

Hook commands return quickly. They write raw payloads to:

.oliver/agent-hooks/pending.jsonl

The collector includes an uploader that wakes up on a fixed interval, normalizes queued payloads into local_agent_event records, and sends them to POST /events. The default interval is five minutes:

OLIVER_AGENT_PUSH_INTERVAL_SECONDS=300

Start the uploader when you want to inspect or test that path:

oliver start

If you created a portal API key instead of using oliver login, pass it on the first start:

oliver start --api-key usr_... --workspace default

It writes uploader state and logs under .oliver/agent-hooks. Check or stop it with:

oliver status
oliver stop

You can try a manual flush to inspect the current uploader behavior:

oliver flush

Or keep a foreground uploader running:

oliver watch

Configuration:

  • OLIVER_API: backend API URL, default http://127.0.0.1:8081
  • OLIVER_APP: portal URL for browser login, default http://127.0.0.1:5173
  • OLIVER_TOKEN: bearer token for the user or agent writing events; normally saved by login
  • OLIVER_WORKSPACE: workspace slug for event writes, default default
  • OLIVER_AGENT_PUSH_INTERVAL_SECONDS: uploader/flush cadence, default 300
  • OLIVER_AGENT_PUSH_BATCH_SIZE: max events to flush per pass, default 100
  • OLIVER_PROJECT: project target value, default default

Verify Capture

After triggering a Claude Code prompt/tool call or a Codex prompt/stop event, check local status. It includes pending queue size, successful submitted counts, and uploader process state:

oliver status

Then list recent stored events:

curl -H "Authorization: Bearer $OLIVER_TOKEN" \
-H "X-Workspace: $OLIVER_WORKSPACE" \
"$OLIVER_API/events?limit=20"

Captured events have:

  • kind: local_agent_event
  • session_id: a stable local_agent:<agent>:<session>:<turn>:<hook> style key
  • targets: project, source, agent, hook_event, session, turn, tool, cwd, and transcript when present
  • model and usage when the hook payload includes them

Compatibility Listener

The older listener still works for setups that prefer direct HTTP hooks:

cd backend

go run ./cmd/agent-hook-listener \
--project oliver \
--port 8765 \
--verbose

It accepts native hook payloads on:

http://127.0.0.1:8765/agent-hooks/{codex|claude}

Unlike the npm collector, the listener receives hook payloads over HTTP and forwards each normalized event to the API immediately.

Privacy And Safety

Payloads are redacted for common secret keys and token-looking text before storage in the backend, but prompts, tool inputs, tool outputs, paths, and transcript references may still contain sensitive project data. Configure these hooks only for users and repos whose agent activity should be stored in Oliver.

The local queue is unredacted because it stores native hook payloads before normalization. Keep .oliver/ local and do not commit it.

Troubleshooting

  • No events appear in Oliver: run oliver status, then run oliver flush.
  • Codex does not call the hook: restart Codex after installation, trust the hook command if prompted, and use /hooks to confirm Codex found the configured hooks.
  • Claude does not call the hook: restart Claude Code after installation and confirm it is loading the repo-local .claude/settings.local.json or the user-level settings file.
  • Backend rejects uploads: confirm OLIVER_TOKEN is valid, the user belongs to OLIVER_WORKSPACE, and the backend API URL points at the current Oliver service.