Daimon

architecture

Four services, one loop.

The console is the thin face of a small fleet of Rust services. Each agent's life is a loop across them: bind a key, refill it from the Sui account, use it on OpenRouter, repeat.

Services

daimon-webNext.js

the console + marketing site. proxies every backend call so the service token never reaches the browser.

daimon-supervisorRust

spawns Sui agent objects and signs locally built Sui transactions. deposits treasury USDC into agent accounts, handles bounded refill requests, and runs the harness self-care loop that drives each agent tick.

daimon-issuerRust · SQLite

the ledger. mints keys, indexes Sui Charged events into API credit, records off-chain call debits, and serves the activity feed.

daimon-x402-proxyRust

OpenRouter forwarder. reachable at its public domain. it accepts either the service token plus X-Daimon-Key (internal callers) or an owner dk_ credential released through an OwnerCap challenge. a public key ID alone cannot authorize a call. usage is debited off-chain.

Request paths

browser ──► daimon-web ──► (service token)
   │            │
   │            ├──► daimon-supervisor   spawn agent · deposit USDC · treasury status
   │            └──► daimon-issuer       fleet by-owner · agent activity · pause/resume
   │
   │   the agent loop (harness inside the supervisor, no browser):
   │
   daimon-supervisor ──► daimon-issuer      mint key · index charges · debit
                     ├──► daimon-x402-proxy ──► OpenRouter   use key (per-call debit)
                     ├──► Sui mainnet   account::charge
                     └──► Sui mainnet   account::bind_key

The console only ever talks to daimon-web, which holds the service token and fans out to the supervisor and issuer. The agent's actual work happens in the harness, off the request path — the console just polls the issuer ledger to show what the agent did.

Trust boundary

  • service token — shared secret between web and the Rust services. Never sent to the browser; every privileged call is proxied through a web API route.
  • owner token— minted at spawn, stored in the browser's localStorage. Unlocks pause/resume for the agents you spawned. Never re-exposed by the issuer.
  • agent account— USDC lives inside the agent's Sui object. Anyone can deposit. Only its OwnerCap holder can withdraw; for Telegram agents, that holder is the operator. IssuerCap charges go only to the configured treasury, within per-charge and daily caps ($1 per charge, $5 per day), and stop when paused. Deposits are capped at 50 USDC per account.

State on chain

The agent's identity is a Move shared object minted by daimon::agent::new. Its USDC balance is a dynamic field managed by daimon::account. The active public key ID is bound by account::bind_key; private credentials stay off-chain. Refills emit Charged, deposits emit Deposited, and withdrawals emit Withdrawn. Each has a Sui transaction receipt. Model calls and walks are not recorded on chain; individual call debits stay in the issuer ledger.

Both objects below are on Sui mainnet. Check them on suiscan.