beaver-gateway
A gateway for personal agents built on the Claude Agent SDK: conversations
with a lifecycle, windows to talk through, jobs, memory hooks, and a policy
boundary - without an opinion about what the agent is for. A setup is one
config.py (or a package next to it) that assembles a Gateway; this repo
holds the primitives, beaver-agent
is a full setup built on them.
What it gives a setup
- agents/ - what an agent is: a Claude agent with a prompt per
conversation kind, skill sets per kind, gateway tools, a
PreToolUsepolicy; a Raycast agent for cheap fast answers. - backends/ - how a turn runs: the Claude Agent SDK subprocess with a session pool, transcripts and session stores; the Raycast wire.
- conversations/ - the model of a conversation: kinds (master, branch, deep, job, fork), rows and windows, the inject queue with priorities, seeds, turns, questions, closing through a distiller, master rotation, the envelope, the in-process gateway tools.
- jobs/ - cron, webhook and event jobs on pgqueuer, deferred injects, the subscription budget.
- frontends/ - the windows: Telegram (master = General, topic = branch),
markdown files in a vault,
/api+ the admin SPA, an Anthropic-compatible/anthropic/v1/messages, MCP re-exposure at/mcp/<name>. - mcp/ - MCP servers a setup declares (stdio, http, python tools), aggregated in-process and handed to agents by name.
- vault/ - watching a directory of notes for the envelope.
- security/ - bearer tokens, the audit log, credential redaction.
- events/ - the in-process bus every frontend taps, and the stream event protocol backends emit.
- storage/ - SQLModel tables and the Postgres session store.
config.py defines Gateway and loads a setup; app.py builds the runtime
from it; cli.py is the entrypoint. Every string the gateway puts in front of
a model or a user has an English default and is overridable
(ConversationTexts, TelegramTexts).
Run
cd examples
CLAUDE_CODE_OAUTH_TOKEN=$(claude setup-token) docker compose up --build
examples/config.py is the smallest setup that starts: one agent, one
python tool, one cron job, the built-in frontends on port 8000; the compose
file next to it adds Postgres. Without Docker: uv sync, build the SPA with
cd ui && bun install && bun run build, then run uv run beaver-gateway with
DATABASE_URL and CONFIG_PATH set. A setup's own secrets come from .env
next to its config (load_dotenv runs before the config is executed).
Develop
make check # ruff format --check, ruff check, ty, pytest
make fix
No comments in code: modules carry a one-line docstring saying what they are for, public configuration fields carry a one-line docstring saying what they mean; everything else is the code.