System overview
In short: Frank is a handful of small services. The one that runs the AI never holds a key; the one that holds the key can only do a few narrow things.
The services
| Service | Holds | Job |
|---|---|---|
frank | model API keys, database | Runs the room, the agent, the pricing service, the ops bot and the website |
signer | Frank's key, nothing else | Signs a short list of allowed calls, never moves money |
sandbox | the Docker socket | Starts Frank's isolated machines, which carry a browser and a page reader |
egress | credentials Frank may use but never see | The only way Frank's machines reach the internet |
search | nothing | A self-hosted search engine, one of several Frank can use |
postgres | room, users, memory, markets, intents | Durable state |
| self-update deployer | runs on the host, outside the app | Tests, trials and installs changes Frank proposes to its own code, and rolls them back if they fail |
The signer and the sandbox runner are pinned: only a human deploy changes them, never one of Frank's own updates.
Each service holds as few secrets as possible, so a problem in one doesn't hand over everything. The detail of this split is on Signing and safety.
Read next
- Agent loop and tools — how a turn runs and what Frank can call.
- Jev, the second opinion — the independent classifier.
- Signing and safety — how keys stay away from the model, and where the gaps are.
Users and payments
- Sign-in uses Privy. The browser swaps Privy's token for Frank's own session cookie, tied to one wallet.
- Credits: a USDG transfer to the collector. The sender is credited exactly once, even if they paid before signing up.
- Bond, claim, redeem are built in the browser and signed by the user's wallet, approving only the exact amount needed.
Operators
New markets are approved by human operators in a private chat with a bot. The bot holds no keys: approving names the exact terms, and the backend re-checks them before signing. Operators can also list open markets, change a market's discount or close it. The pricing service posts its reprices, closes and anything that needs a person there.
Data and API
Postgres tables: users, sessions, payments, faucet claims, events, turns, transcript, tool calls, summaries, notes, skills, extensions, sources, jobs, schedules, topics, proposals, bond markets, price samples, intents, self-updates, usage log, key-value.
Public API: /api/health, /api/chain, /api/session, /api/treasury, /api/room, /api/jobs, /api/events (live stream), /api/bonds, /api/wallet, sign-in, messages, credits, faucet, and /rpc (a read-mostly chain proxy). Frank's own machines get a separate read-only chain endpoint behind a secret token: reads only, no transactions. Admin routes need a bearer token.