Agents Observe turns Claude Code hook events into a live session dashboard
Real-time observability of claude code sessions & multi-agents.
At a glance
- What is it?
- Agents Observe is a TypeScript project that captures Claude Code and Codex hook events and streams them to a browser dashboard, with the agent hierarchy, tool calls, replay and token usage stats. It is installed as a Claude Code plugin, runs its server in Docker on port 4981, and stores everything in a local SQLite database.
- Who is it for?
- Adopt Agents Observe if you run Claude Code or Codex agents that spawn subagents and you need to see which tools were called and in what order, because the project records every hook event with full payloads instead of relying on the terminal summary.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 49 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What a hook event stream gives you that the terminal does not
The argument in the README is about visibility. When Claude Code runs on its own, spawning subagents, calling tools, reading files and executing commands, the terminal shows a fraction of the activity. Subagents are invisible, tool calls blur together, and when something goes wrong three agents deep in a parallel run, you are left reading logs after the fact.
Agents Observe captures every hook event as it happens and streams it to a live dashboard. You see what each agent is doing, which tools it calls, what files it touches, and how subagents relate to their parents. The README frames this in four claims: multi-agent work is opaque without it, tool calls are the ground truth because assistant text is only a summary, debugging becomes time travel through the exact event sequence with full payloads, and sessions are ephemeral while patterns across sessions are not, so you can see which tools agents favour and where they get stuck.
The practical feature list is concrete. You can watch tool calls stream in from PreToolUse to PostToolUse with results, see the full agent hierarchy, filter by agent or tool type, search across all events, expand any event to its full payload, command and result, click timeline icons to jump to a point in the stream, and browse historical sessions that carry human-readable names such as twinkly-hugging-dragon.
Installing it as a Claude Code plugin takes four commands
The documented quick start is a plugin install. You add the repository as a marketplace, install the plugin, and then run claude as usual, because the plugin starts the MCP server and captures events on its own:
claude plugin marketplace add simple10/agents-observe
claude plugin install agents-observe
claudeThe plugin also ships a skill you invoke inside Claude with slash commands such as /observe status, /observe debug, /observe logs and /observe restart, and the dashboard itself opens at http://localhost:4981.
Three prerequisites are listed, and all three are real: Docker, because the server runs as a container, Node.js, because the hook scripts run through node, and Bash, because the hooks are configured to use hooks.sh for fast fire and forget event logging. The README is blunt that if docker, node or bash are missing on the host, the plugin will fail to properly load, and it points at the /observe debug command for exactly this situation.
The skills list is a small operations surface. /observe view opens the current session in the dashboard, /observe stats opens the stats modal, /observe checks the dashboard URL and whether the server is running, and /observe start, /observe stop and /observe restart manage the server, with /observe logs showing recent Docker container logs.
The four stage pipeline from hook to WebSocket
The README draws the architecture as a single line, and each stage has a defined job:
Claude Code Hooks → observe_cli.mjs → API Server (SQLite) → React Dashboard
(agent-lib build) (HTTP POST) (parse + store) (WebSocket live)The hook stage builds the event. observe_cli.mjs reads the raw event from stdin and dispatches to an agent-class-specific module under hooks/scripts/lib/agents/<class>.mjs, whose buildHookEvent() constructs the envelope, including agent-class-aware flags such as meta.isNotification and meta.clearsNotification. It then POSTs the envelope to the server over HTTP.
The server applies those flags mechanically to its stored state, for example pending_notification_ts, and forwards events to subscribed WebSocket clients. The README stresses that the server stays agent-class-neutral, so adding a new kind of agent does not mean teaching the server about it. The React dashboard then derives all agent state, including status, event counts and timing, from the event stream alone.
That last point is the design decision that matters. There is no second source of truth for agent state, so what you see in the browser is what actually happened, not a reconstruction from a status field.
Where the SQLite database lands, and how to move it
Data location depends on how you run the tool, and the README is specific about it. When running as a Claude plugin, the SQLite database and logs live under $CLAUDE_PLUGIN_DATA, which Claude Code names <plugin>-<marketplace>, so a marketplace install lands at ~/.claude/plugins/data/agents-observe-agents-observe/ and a --plugin-dir install at ~/.claude/plugins/data/agents-observe-inline/. Outside Claude, meaning Codex, manual CLI or development, the location is ~/.agents-observe/.
Inside that root, the database sits at <root>/data/observe.db and logs at <root>/logs/.
To pin the location somewhere else, for example on an external volume, you set AGENTS_OBSERVE_LOCAL_DATA_ROOT in your ~/.claude/settings.json, in the env section:
// ~/.claude/settings.json
"env": {
"AGENTS_OBSERVE_LOCAL_DATA_ROOT": "/path/to/your/dir"
}Upgrading the plugin preserves your database. If you come from a pre-fix version, that is 0.9.8 or earlier, the server scans for a database under the old version-scoped install directory on first start and copies it into the stable location, and the record of that is written to <root>/data/.migrated-from.json. So the upgrade path for a long-lived install is a one-time copy, and the file to look at afterwards is that migration record.
The compose file binds to loopback on purpose
The Docker Compose file in the repository is marked as a reference and quick testing aid rather than the normal path, since the plugin and the local dev scripts do not use it, and the README recommends the just start and just dev commands instead. Even so, it is the clearest statement of the deployment defaults.
The server port defaults to 4981, the database path inside the container is /data/observe.db, the client dist path is /app/client/dist, the log level defaults to debug and the runtime is set to docker. The port mapping is the interesting line:
ports:
- "${AGENTS_OBSERVE_BIND:-127.0.0.1}:${AGENTS_OBSERVE_SERVER_PORT:-4981}:${AGENTS_OBSERVE_SERVER_PORT:-4981}"
volumes:
- ./data:/dataThe default bind address is 127.0.0.1, and the comment explains why: so the unauthenticated dashboard and WebSocket are not exposed beyond the machine, which the compose file attributes to issue #22. Setting AGENTS_OBSERVE_BIND to 0.0.0.0 opens it to the LAN, and the env example also documents AGENTS_OBSERVE_CORS_ORIGINS as a comma-separated allowlist that defaults to loopback origins only.
The volume mapping is what makes the data survive container restarts, with the host's ./data directory mounted at /data.
The container image builds the client and ships no build tools
The Dockerfile is a two-stage build on node:22-slim. The builder stage installs python3, make and g++, which the README's comment explains is for native addons, specifically better-sqlite3 via node-gyp. It installs the server dependencies, installs and builds the client, and copies the root package.json in because vite.config.ts reads ../../package.json, which resolves to /package.json inside the image.
The production stage starts from node:22-slim again, copies the built node_modules including the compiled better-sqlite3 binary, the built client dist, the server source and its tsconfig and package.json, plus the VERSION file for the /api/health endpoint and CHANGELOG.md for the /api/changelog endpoint. It exposes 4981 and runs npx tsx src/index.ts as its command, with the working directory set to /app/server.
The practical consequence is that the container has no compiler, so any native module has to be built in the builder stage and copied across, which the image does. The health and changelog endpoints also mean the running version is queryable, which matters when a plugin and a server are on different versions.
Cost, licence and the shape of the project
The package is private, version 0.9.12, and the licence is MIT. The root package.json holds only a thin set of scripts: start runs node start.mjs, test chains the script tests with the server and client test suites, and fmt runs prettier across the server, client, hook scripts and tests. The build tooling for the app itself is in app/, with app/server and app/client as separate packages, and the repository also holds hooks/, skills/, scripts/, test/, docs/, a justfile, a Dockerfile, a docker-compose.yml and a .mcp.json.
The release record is regular: v0.9.10 on 2026-05-29, v0.9.11 on 2026-06-04 and v0.9.12 on 2026-07-22, with the last push to main on 2026-09-04. The README also notes that version 0.9.7 added token usage and cost breakdowns in the session stats, which is the feature that turns the dashboard into something a cost-conscious team can use rather than just a debugger.
The limitation to keep in mind is the one the project states about itself: the dashboard and the WebSocket are unauthenticated. That is a deliberate choice for a local tool, and it is why the bind address defaults to loopback.
Editorial conclusion
Adopt Agents Observe if you run Claude Code or Codex agents that spawn subagents and you need to see which tools were called and in what order, because the project records every hook event with full payloads instead of relying on the terminal summary. Skip it if you have no container runtime available, since Docker, Node.js and Bash are hard prerequisites, and treat the dashboard as a local tool rather than a shared service, because it is unauthenticated and published on loopback by default. Before you rely on it, confirm Docker, node and bash are all present, decide where the SQLite database should live with AGENTS_OBSERVE_LOCAL_DATA_ROOT, and read the bind address settings before you expose the port beyond your machine, because the compose file deliberately keeps the dashboard on 127.0.0.1.
Frequently asked questions
How do I install Agents Observe for Claude Code?
Add the repository as a marketplace with claude plugin marketplace add simple10/agents-observe, then install it with claude plugin install agents-observe and run claude, which starts the MCP server and captures events automatically. The dashboard is then at http://localhost:4981.
What does Agents Observe need installed on the host?
Docker, because the server runs as a container, Node.js, because hook scripts run via node, and Bash, because the hooks use hooks.sh for fire and forget event logging. The README says the plugin will fail to properly load if any of them is missing, and points at the /observe debug command for troubleshooting.
Where does Agents Observe store its data?
Under $CLAUDE_PLUGIN_DATA when running as a Claude plugin, which is ~/.claude/plugins/data/agents-observe-agents-observe/ for a marketplace install, and under ~/.agents-observe/ when running outside Claude. The database is at <root>/data/observe.db and logs at <root>/logs/.
Can I move the Agents Observe database to another directory?
Yes, by setting AGENTS_OBSERVE_LOCAL_DATA_ROOT in the env section of your ~/.claude/settings.json to the directory you want. Upgrading the plugin preserves the database, and versions 0.9.8 or earlier are copied into the stable location on first start.
Is the Agents Observe dashboard safe to expose on a network?
The dashboard and WebSocket are unauthenticated, so the Docker Compose file publishes on 127.0.0.1 by default to keep them off the network, and setting AGENTS_OBSERVE_BIND to 0.0.0.0 is what opens LAN access. AGENTS_OBSERVE_CORS_ORIGINS sets the browser API allowlist, which defaults to loopback origins only.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/simple10-agents-observe)Was this useful?