Gathers your coding-agent conversation history from every machine you use into one place to browse and search.
A Collector runs on each machine. It finds each coding tool's history on disk and ships it, raw, to one Hub. The Hub keeps every record verbatim, parses it into readable transcripts, and serves a web UI with full-text search. It never deletes anything.
Supported today: Claude Code, Codex, oh-my-pi, opencode and Hermes Agent.
- One feed for every Machine. Every session from every tool, newest first, filtered by Machine, tool or project.
- Full-text search across every transcript, with highlighted matches and counts by Machine, tool and project.
- Readable transcripts. Markdown and syntax-highlighted code, images, tool calls folded into one line each (or hidden entirely), a list of your own prompts to jump between, and sub-agent sessions linked from the session that started them.
- Live. Open pages update as sessions grow; the Collector ships new history in the background as soon as it's written.
- Nothing is lost. The Hub keeps every original record verbatim and never deletes. When an upgrade improves a parser, existing history is parsed again automatically.
- Recall from your agent. A read-only MCP endpoint lets Claude Code or Codex search your past sessions mid-task.
- Keep projects private. Sessions from directories you exclude never leave the Machine.
- Small to run. One Docker image with SQLite inside, daily backups, and a backup before every schema change. The Collector is one binary that runs as a launchd or systemd user service.
The feed: every session from every machine, newest first.
Search: matches grouped by session, with the hits highlighted.
A transcript, with tool calls collapsed.
Warning
The Hub has no authentication and no TLS. Run it on a private network
(a VPN such as Tailscale or WireGuard), or put your own reverse proxy in
front of it. Its MCP endpoint at /mcp hands your whole
history, from every machine, to any agent that can reach the Hub.
The Hub is a Docker image, ghcr.io/tedkulp/agent-history-hub, for
linux/amd64 and linux/arm64. Run it with Docker Compose or plain
Docker. Both keep the database in ./data and daily backups in
./backups.
- Local disk only.
./datamust not be on NFS, SMB or any other network filesystem; SQLite corrupts or deadlocks there. More - uid 1000. The Hub runs as uid/gid 1000, so
dataandbackupsmust be writable by it. On Linux, ifid -uisn't 1000, then after themkdirbelow either runsudo chown -R 1000:1000 data backups, or run the Hub as their owner withuser: "<uid>:<gid>"incompose.yamlor--user "$(id -u):$(id -g)"ondocker run. Otherwise the Hub exits at start-up with a permission error in the logs. Docker Desktop on macOS needs neither. More - Settings are env vars. The ones you're most likely to set:
TZ(Web UI and backup time zone, default UTC),AGENT_HISTORY_BACKUP_AT(daily backup time, default03:00) andAGENT_HISTORY_BACKUP_KEEP(daily backups kept, default7). Pass them underenvironment:or with-eondocker run. All settings
Save this as compose.yaml (it is the compose.yaml in
this repo):
services:
hub:
image: ghcr.io/tedkulp/agent-history-hub:v0.13
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./data:/data
- ./backups:/backups
environment:
TZ: America/New_York
# AGENT_HISTORY_BACKUP_KEEP: "7"
# user: "1000:1000" # match the owner of ./data and ./backupsThen, in the same directory:
mkdir -p data backups
docker compose up -d
docker compose ps # STATUS shows "healthy" once the Hub is readyThe healthcheck is built into the image, so compose.yaml doesn't need
one.
mkdir -p data backups
docker run -d --name agent-history-hub -p 8080:8080 -v "$PWD/data:/data" -v "$PWD/backups:/backups" --restart unless-stopped ghcr.io/tedkulp/agent-history-hub:v0.13
docker ps --filter name=agent-history-hub # STATUS shows "(healthy)" once the Hub is readyEither way, open http://<host>:8080/. That address is the --hub you
give each Collector.
| Tag | Points at |
|---|---|
vX.Y.Z, e.g. v0.1.0 |
That exact release |
vX.Y, e.g. v0.1 |
The newest vX.Y.* patch release |
latest |
The newest release |
Pin vX.Y: you get bug fixes with each pull, and move to a new minor
version only when you change the tag.
Upgrade the Hub before the Collectors. With Compose:
docker compose pull && docker compose up -dWith plain Docker, pull, remove the container, and run the same
docker run command again; the data stays in ./data:
docker pull ghcr.io/tedkulp/agent-history-hub:v0.13
docker rm -f agent-history-hub
docker run -d --name agent-history-hub -p 8080:8080 -v "$PWD/data:/data" -v "$PWD/backups:/backups" --restart unless-stopped ghcr.io/tedkulp/agent-history-hub:v0.13To move to a new minor version, change the tag first. An upgrade that
changes the database schema backs it up to backups/pre-migrate-<n>.db
first; rolling back, backups and TLS are in
docs/hub-deploy.md.
The Hub serves a read-only MCP endpoint
at /mcp, so a coding agent can recall your past sessions mid-task: "how
did I fix the sqlite lock last month?", "what did I work on this week?".
Its tools are search, list_sessions and get_transcript; none of them
change anything.
Claude Code:
claude mcp add --transport http agent-history http://<hub>:8080/mcpCodex, in ~/.codex/config.toml:
[mcp_servers.agent-history]
url = "http://<hub>:8080/mcp"Results link to each session's page in the web UI, built from the address
the agent used. Behind a reverse proxy, set AGENT_HISTORY_PUBLIC_URL
(see docs/hub-deploy.md).
On each macOS or Linux machine, download the latest release into a
directory on your PATH, then set it up:
os=$(uname -s | tr '[:upper:]' '[:lower:]')
arch=$(uname -m); case $arch in x86_64) arch=amd64;; aarch64) arch=arm64;; esac
curl -fsSL "https://github.com/tedkulp/agent-history/releases/latest/download/agent-history_${os}_${arch}.tar.gz" | tar -xz agent-history
mkdir -p ~/.local/bin && install -m 755 agent-history ~/.local/bin/
agent-history init --hub http://<host>:8080init writes ~/.config/agent-history/collector.toml, registers the
machine with the Hub, and installs a launchd or systemd user service that
runs ~/.local/bin/agent-history and keeps shipping new history in the
background. Check on it with:
agent-history statusTo upgrade, download the new release the same way and replace the file
with install -m 755 (or mv). Never cp over it: Linux refuses to
overwrite a running binary ("text file busy"), and on macOS an in-place
overwrite can break it. The running service restarts itself onto the new
version within one rescan.
On macOS, use curl as above rather than a browser: a browser download is
quarantined, and Gatekeeper refuses to run the unsigned binary. If you did
use a browser, clear it with xattr -d com.apple.quarantine agent-history.
mise works too:
mise use -g github:tedkulp/agent-history
agent-history init --hub http://<host>:8080The service then runs mise's shim, and mise upgrade upgrades it; the
running service restarts itself onto the new version.
init and service install pick the mise shim when it exists, otherwise
the binary you ran, so after moving from mise to a manual install, remove
the shim (mise uninstall github:tedkulp/agent-history) before running
init again. Pass --exec <path> to choose another path.
Add exclude globs to ~/.config/agent-history/collector.toml. A session
whose starting directory matches, and any sub-agent session it starts,
never leaves the Machine:
exclude = [
"/Users/me/src/client-secret/**",
]The Collector reads its config only at start, so run
agent-history service restart afterwards. Sessions already shipped stay
on the Hub: exclude a project before its first sync. Every setting, including
per-tool root and enabled, is in
docs/spec/collector.md.
You need Go (see go.mod) and just.
just check # gofmt, go vet, go test
just hub # run a Hub on :8080 with its data in .data/
just collector # ship this Machine's history to that Hub, beside any installed Collector
just build # build both binaries into bin/
just screenshots # redo the README screenshots from fake history (needs python3, firefox)just lists every recipe. The build-ready design lives in
docs/spec/, with the vocabulary in
GLOSSARY.md. Releases are cut by pushing a tag; see
docs/releasing.md.