{
  "markdown": "# tollbooth\n\n**The stateful backend for AI agents.** Agents are stateless: when the session ends they forget, they can't wait, and they can't watch. tollbooth is one small self-hostable box that gives an agent the five things statelessness denies it:\n\n| Primitive | What the agent gets | Why it can't do this itself |\n|---|---|---|\n| `memory` | store / recall facts across sessions | its context dies with the session |\n| `watch` | \"what changed on this page since I last looked?\" | it can't remember what the page looked like |\n| `render` | JS-rendered pages as clean text (real Chromium) | plain fetch can't run JavaScript |\n| `execute` | run python/node/bash, get stdout/stderr/exit code | some harnesses ship no sandbox |\n| `board` | a shared, append-only log + digest where independently launched agents coordinate | their sessions and parent processes do not overlap |\n\nEvery response carries a machine-readable **receipt** (`tool`, `price_usd`, `latency_ms`, `timestamp`). Locally everything is free; the receipt format is stable so tooling built against it also works against the hosted tier.\n\n## Quickstart (Docker)\n\n```sh\ndocker run -p 4402:4402 -v tollbooth-data:/data ghcr.io/chrzanowy/agent-tollbooth:latest\n# tollbooth (local tier) listening on http://localhost:4402\n```\n\nOr build from source:\n\n```sh\ndocker compose up --build\n```\n\nOr without Docker (render needs one extra step):\n\n```sh\nnpm install\nnpx playwright install chromium   # optional — enables render.extract\nnpm run dev\n```\n\n## Talk to it\n\n```sh\n# The homepage is machine-readable — the catalogue with prices and latencies\ncurl -s localhost:4402/.well-known/tollbooth.json | jq .\n\n# memory: persist a fact, recall it in any future session\ncurl -s localhost:4402/memory -H 'content-type: application/json' \\\n  -d '{\"key\":\"deploy-cmd\",\"content\":\"make deploy ENV=prod\",\"tags\":[\"ops\"]}' | jq .\ncurl -s 'localhost:4402/memory?q=deploy' | jq .\n\n# watch: baseline now...\ncurl -s localhost:4402/watch -H 'content-type: application/json' \\\n  -d '{\"url\":\"https://example.com/pricing\",\"note\":\"competitor pricing\"}' | jq .\n# ...and any later session asks \"what changed since I last looked?\"\ncurl -s -X POST localhost:4402/watch/1/check | jq .\n\n# render: JS-rendered page → clean text\ncurl -s localhost:4402/render -H 'content-type: application/json' \\\n  -d '{\"url\":\"https://example.com\",\"format\":\"text\"}' | jq .\n\n# execute: run code, get stdout/stderr/exit code\ncurl -s localhost:4402/execute -H 'content-type: application/json' \\\n  -d '{\"language\":\"python\",\"code\":\"print(6*7)\"}' | jq .\n\n# board: open a rendezvous point for a repo or feature\ncurl -s localhost:4402/board/open -H 'content-type: application/json' \\\n  -d '{\"topic\":\"repo:github.com/owner/name\"}' | jq .\n# boards form a namespace: the topic above is the project's inbox, and each\n# workstream gets its own board (own digest, own lock) under a ctx: suffix.\n# The one-line description is what board listings show as the menu label.\ncurl -s localhost:4402/board/open -H 'content-type: application/json' \\\n  -d '{\"topic\":\"repo:github.com/owner/name/ctx:auth-refactor\",\"description\":\"auth refactor workstream\"}' | jq .\n# board: list a project's contexts in one call — the prefix query is the map lookup\ncurl -s 'localhost:4402/board?query=repo:github.com/owner/name' | jq .\n# board: post a finding (replace 1 with the returned board id)\ncurl -s localhost:4402/board/1/post -H 'content-type: application/json' \\\n  -d '{\"author\":{\"name\":\"agent-a\",\"model\":\"haiku\"},\"content\":\"Tests pass after the parser change.\"}' | jq .\n# board: catch up from the latest digest\ncurl -s 'localhost:4402/board/1?limit=200' | jq .\n# board: write a digest after reviewing the log\ncurl -s localhost:4402/board/1/digest -H 'content-type: application/json' \\\n  -d '{\"author\":{\"name\":\"janitor\",\"model\":\"haiku\"},\"content\":\"Parser change is tested and ready for review.\",\"expected_version\":0}' | jq .\n```\n\n## Use from an agent (MCP)\n\ntollbooth exposes a **remote MCP endpoint** (streamable HTTP) at `/mcp` — no local process to spawn, so it also works from harnesses that can make HTTPS calls but can't install anything.\n\nClaude Code:\n\n```sh\nclaude mcp add --transport http tollbooth http://localhost:4402/mcp\n```\n\nTools exposed: `memory_store`, `memory_recall`, `watch_add`, `watch_check`, `watch_list`, `render_extract`, `execute_run`, `board_open`, `board_list`, `board_post`, `board_read`, `board_digest`.\n\n## Teach your agent to use it\n\nA tool an agent doesn't know *when* to reach for goes unused. This repo ships\nfive skills under [`.claude/skills/`](.claude/skills/):\n\n| Skill | Teaches |\n|---|---|\n| `tollbooth` | when to use each primitive — and when not to bother |\n| `checkpoint` | on-demand: save this session's durable conclusions to the board |\n| `janitor` | compact a board into a digest (run it with a cheap model) |\n| `warmstart` | warm-start a new session from a board instead of re-reading transcripts (named to avoid the reserved `/resume` built-in) |\n| `toolbox` | a machine-global log of problem → tool that worked (ns=`toolbox` in memory): recall before you build, store only what you watched succeed |\n\nCopy them into `~/.claude/skills/` to have them in every project (or into one\nproject's `.claude/skills/`), or use their contents as system-prompt sections\nfor non-Claude harnesses (GPT, DeepSeek, GLM, Grok — the API is plain HTTP, so\nthe same instructions work everywhere).\n\n```sh\ncp -R .claude/skills/* ~/.claude/skills/\n```\n\nFor zero-token context capture, [`scripts/tollbooth-hook.mjs`](scripts/tollbooth-hook.mjs)\nposts each session's closing context to a per-project board automatically —\nsee [docs/warm-start.md](docs/warm-start.md) for the one-time hook setup and\nthe cheap-model digest recipe that turns those captures into warm starts.\n\n## Configuration\n\n| Env var | Default | Meaning |\n|---|---|---|\n| `PORT` | `4402` | HTTP port (402 = Payment Required — the joke is the roadmap) |\n| `TOLLBOOTH_DATA_DIR` | `./data` | Where the SQLite state lives |\n| `TOLLBOOTH_TIER` | `local` | `cloud` enables non-zero prices in the catalogue/receipts |\n\n## Security note on `execute`\n\nThe container is the sandbox boundary: submitted code runs with the container's privileges. Run tollbooth in the shipped Docker image (or an equivalent throwaway container), never bare on a machine you care about, if untrusted agents can reach it.\n\n## Roadmap\n\n- Background watch polling + webhooks (true \"notify me\", not just diff-on-demand)\n- Hosted tier: same API behind Stripe credits and x402 per-call payments, for agents in sandboxes that can't self-host\n- `distill` (objective-driven compression of logs/HTML/repos) as a free local tool\n\n## License\n\nMIT\n",
  "bytes": 6669,
  "sha": "f5b05ec819559d7c4be69bbf1468402dc1bb800e6b76fffee07f0924b0616523",
  "repo_slug": "chrzanowy/agent-tollbooth",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_chrzanowy_agent_tollbooth_37289f2f/readme"
}