Self-hosted agent runtime in TypeScript. A port of Aegra's
server layer to Node — it speaks Agent Protocol v2, so the official
@langchain/langgraph-sdk client, Agent Chat UI and LangGraph Studio talk to it unmodified.
Graph execution itself is @langchain/langgraph; checkpointing is
@langchain/langgraph-checkpoint-postgres. What lives here is the server:
HTTP protocol, persistence, run orchestration, streaming, auth, crons.
| Concern | Choice |
|---|---|
| HTTP | Hono + @hono/node-server |
| DB | Postgres (pgvector) via Drizzle ORM |
| Graphs | @langchain/langgraph |
| Checkpoints | PostgresSaver |
| Validation | Zod |
| Auth | pluggable — noop / jwt (jose) / custom |
Unlike Aegra there is no Redis dependency: the queue and cross-instance fan-out
are planned on Postgres (FOR UPDATE SKIP LOCKED + LISTEN/NOTIFY).
git clone https://github.com/volt-eq/volt.git
cd volt
pnpm install
cp .env.example .env
pnpm volt devvolt dev starts Postgres if it is not running, applies migrations, then boots
the runtime with reload on change. Talk to a graph without leaving the terminal:
pnpm volt chat echovolt · chat · echo
Thread 6895d1e4-0127-42dc-bd6f-f721ee1efa45
Commands /state /history /new /exit
you › hola
bot › echo: hola
volt chat speaks to the HTTP API through the official SDK, so what you see is
what any other client sees. An interrupt() pauses the session and asks:
⏸ Approve "delete the staging bucket"?
options: approve, reject
resume › approve
bot › Approved. Executed: delete the staging bucket
| Command | Does |
|---|---|
volt dev |
Preflight, then the runtime with reload on change |
volt serve |
The runtime without a watcher |
volt chat [graph] |
Interactive session against a running runtime |
volt graphs |
The graphs this project declares, and what is being served |
volt up / volt down |
Docker services; down --volumes erases the database |
A project is any directory with a volt.json. It needs the graph dependencies,
nothing else — the runtime and its migrations come from wherever the CLI was
installed.
mkdir my-agent && cd my-agent
pnpm init
pnpm add @langchain/core @langchain/langgraph// volt.json
{ "graphs": { "agent": "./agent.ts:graph" } }volt dev # in one terminal
volt chat agent # in anothervolt dev runs the Compose service only when the project ships a
docker-compose.yml. Elsewhere, point DATABASE_URL at a Postgres you already
have.
Smoke test:
curl localhost:2026/info
curl -X POST localhost:2026/assistants \
-H 'content-type: application/json' \
-d '{"graph_id":"echo","name":"echo"}'volt.json maps a protocol graph_id to a module export:
{
"graphs": {
"echo": "./examples/echo-agent/src/graph.ts:graph",
"agent": "./examples/react-agent/src/graph.ts:graph"
}
}The export may be a compiled graph or a factory returning one. Prefer the
factory: it keeps provider credentials out of module import time.
POST /assistants resolves the graph before writing the row, so a bad
graph_id — or a graph whose provider key is missing — fails at create time
rather than on the first run.
Detailed status lives in context/plan/02-roadmap.md;
the endpoint-by-endpoint table is in
context/plan/03-agent-protocol.md.
| Phase | Scope | Status |
|---|---|---|
| 0 | Scaffold, Postgres, migrations | done |
| 1 | Schema: assistants, threads, runs, crons | done |
| 2 | Graph registry + manifest | done |
| 3 | Assistants + threads CRUD, /info, /health |
done |
| 3b | Assistant versions, thread state + history | partial (state + history done) |
| 4 | Run executor, SSE, cancel, join, stateless runs | done |
| 5 | Human-in-the-loop interrupts and resume | done |
| 6 | JWT / OAuth / custom auth handlers | partial (noop, jwt) |
| 7 | Cron scheduler, worker leases, crash recovery | todo |
| 8 | Store: KV + pgvector semantic search | todo |
| 9 | CLI (volt dev/serve/up), Docker, OpenTelemetry |
todo |
pnpm db:up # the suite uses a real Postgres, in a volt_test database
pnpm test129 tests, around 13 seconds. They call app.fetch directly rather than binding
a port, and run against real Postgres rather than a mock — jsonb containment,
the conditional-update claim, cascade deletes and the checkpointer are the parts
most worth exercising for real.
pnpm test:unit # serialisation, event broker, graph registry
pnpm test:integration # protocol endpoints, streaming, human-in-the-loop, auth
pnpm typecheckThe acceptance criterion is that the official client works unmodified. With the server running:
pnpm tsx scripts/sdk-smoke.tsdrives a real @langchain/langgraph-sdk through assistants, threads, runs,
streaming, and an approval gate with resume.
volt.json graph manifest
docker-compose.yml Postgres + pgvector
context/ plan and progress notes
tests/ unit and integration suites
scripts/sdk-smoke.ts compatibility check against the real SDK
packages/cli/ the `volt` command
packages/server/
src/
app.ts Hono app, error mapping, route mounting
index.ts entrypoint, graceful shutdown
config.ts env parsing (Zod)
api/ protocol routes (the only snake_case in the codebase)
auth/ pluggable identity middleware
db/ Drizzle schema, pool, checkpointer
graphs/registry.ts graph_id -> compiled graph
runs/ executor, event broker, message serialisation
drizzle/ generated migrations
examples/
echo-agent/ credential-free graphs for tests (echo, slow)
approval-agent/ human-in-the-loop approval gate
react-agent/ ReAct agent (needs ANTHROPIC_API_KEY)