Build an agent — locally or on a server
An agent of your own, in code: where it runs, how it holds its keys, how it gets personal tools (email, calendar) without handing your accounts to strangers, where its data lives. Running everything locally is a first-class path, not a degraded one.
What an "agent" is here
An agent is your code plus three things it did not have to build. The code is any Node/TS
process: a script, a LangChain-style loop, an MCP client. Behind it, an owner wallet that
funds and authorizes. In its hands, a budget-capped, expiring session key on an ERC-4337 smart
account: the only key it holds, and one that can never spend past the cap. In its toolbox,
@aioum/sdk (or @aioum/mcp for Claude-family clients) to discover services, open escrow
sessions and pay per call with signed vouchers. Finding is its own work, when its owner allows it:
it asks the marketplace for what it needs, opens a session with what comes back, tries one service
against another when two offer the same thing, and rates each operator on-chain at settlement.
(Python? pip install aioum gives the same flow — EOA sessions, per-call vouchers,
evidence capture — see packages/python-sdk.)
import { AIOUMClient, devnet } from "@aioum/sdk";
const client = new AIOUMClient(await devnet("./deployments.json")); // local development network; fromDeployments(...) for the AIOUM network
const agent = await client.createAgent({
ownerKey: process.env.OWNER_KEY as `0x${string}`, // funds + authorizes, then can go offline
budget: "10 USDC", // hard cap; the agent can never exceed it
expiresIn: "24h", // session key self-destructs
});
const session = await agent.openSession("web-search"); // one on-chain tx
const r = await session.call({ query: "solar eclipse 2027" }); // signed voucher, no tx
await session.close(); // one settle; unspent deposit refunds
That is the whole payment story from the agent's side: one owner action sets the budget (then the owner can go offline), one transaction opens a session, each call costs a signature and no transaction, one settle returns whatever was not spent.
The same agent on the runner
An agent built in the app or from a shell is the runner's job to pay for, and its shape is one
JSON object, the eight builder steps as fields (POST /agents, aioum agent create --file,
aioum_agent_create):
{
"name": "Art director", "instructions": "…", "mode": "assistant",
"planner": "marketplace", "plannerService": { "serviceId": "12", "tool": "plan" },
"tools": [{ "serviceId": "local", "tool": "ws.write" }, { "serviceId": "44", "tool": "generate" }],
"access": "prefer", "deny": ["12"],
"data": { "memory": ["mem_…"], "files": ["brief.md"] }, "dataAccess": "prefer",
"skills": ["anthropics-skills-skills-pdf", "svc:216"], "skillsAccess": "prefer",
"budget": { "capUsdc": 5, "perRunMaxUsdc": 0.5 }, "payAcross": true,
"schedule": { "everyMinutes": 60, "input": "Run the next round", "enabled": false }
}
access, dataAccess and skillsAccess are each only, prefer or open: what you ticked
and nothing else, your picks first and then whatever it discovers, or fully loose. Tools on your
node carry serviceId: "local" and cost nothing. skills are index ids or svc:<serviceId> for
one listed on a node; the runner adds learnedSkills (kept by the agent itself after a run that
went well) and boughtSkills (one-time skills it paid for, loaded again free). payAcross, on
by default, lets the wallet on your node swap for the USDC a session needs
(pay in any token). Every run streams over GET /runs/:id/events
with a doing line and costUsdc per step and spendByService at the end (Watch it
work); a project, one brief and several stages on the same agent, is POST /projects; a pipeline, a network of such agents with a project, is POST /starters/:id/create
(Pipelines).
Where to run it
The same code runs on a laptop or a server; what changes is who can see the machine and how keys are handled.
| Local (laptop/desktop) | Your server (VPS/homelab) | |
|---|---|---|
| Privacy | best — prompts, results, memory never leave your machine | good — your infra, but a cloud provider can see the box |
| Uptime | while your machine is on | always-on (agents that act while you sleep) |
| Keys | owner key can live in your normal wallet/keychain | owner key should never touch the server (below) |
| Best for | personal agents, development, privacy-sensitive data | schedulers, monitors, long-running workflows |
Local setup
npm install @aioum/sdk
OWNER_KEY=0x... node agent.mjs
Use a dedicated owner wallet holding only what agents need, never your main key in an env var. Arguments, results and reasoning stay on your machine; the chain sees only escrow opens and settles, and with Layer-1 hygiene + a relay even that metadata blurs.
Server setup — the key trick that makes it safe
The server never holds the owner key. On your local machine, run createAgent(...) against
the same chain: it deploys and funds the smart account and authorizes a fresh session key. Ship
only the session key (and config) to the server, via a secret manager or the environment; the
agent there builds its session from that key and pays autonomously.
A compromised server yields a key that can spend at most the remaining budget, only on AIOUM
sessions, only until expiry, and the owner can revoke() it on-chain at any moment.
Re-authorize on a cadence (daily budget = daily key), not long-lived credentials. Standard
hygiene: non-root, systemd/Docker restart policy, outbound-only networking unless serving.
Personal tools: what the marketplace can never host — and the answer
Payment signatures authorize money; they cannot authorize your Gmail. Tools that act as you, email, calendar, personal accounts, need OAuth tokens or API keys, and a marketplace operator holding those could read everything, un-slashably: stake compensates monetary harm, but nothing un-reads your inbox. Personal-credential tools are structurally client-side.
The private node is that client side: a small runtime you deploy
(same tools/call shape as a marketplace node, but personal, free and unmetered) holding your
secrets AES-256-GCM-encrypted, exposing your accounts (Gmail, Calendar, the ad and analytics
platforms, any keyed API), a workspace, locally installed models, a wallet and an exchange with
caps, and a local memory store for your agent's context (Your node):
cd offchain
PRIVATE_NODE_PASSPHRASE=strong npm run private-node # local: binds 127.0.0.1 only
# or on your VPS: docker compose up -d # bearer-token + put TLS in front
A workflow spans both worlds: public paid steps → marketplace nodes; personal steps → your private node. The private node's egress gates and taint tracking stop untrusted marketplace output exfiltrating personal data through a personal tool.
Databases: where your agent's data lives
Where the agent's results, transcripts and memory go: three patterns, ordered by privacy posture; the data itself decides.
1. Local DB (max privacy). SQLite/DuckDB next to the agent: results, transcripts and analysis
stay on disk you control, and DuckDB gives real analytics for free. The private node's
memory connector (remember/recall) already holds the "agent context" slice, encrypted at
rest. Choose this whenever the data is sensitive.
2. Your hosted DB. Postgres on your VPS/cloud beside a server-deployed agent: your infra, your access control, private from the marketplace, visible to your cloud provider. The default for always-on agents with real data volume. Never expose it publicly; same-box or private networking.
3. Marketplace storage-as-a-service. An operator can sell store/query tools per call like
any other service, for shared, public, or client-side-encrypted data. The operator sees
whatever you store, so encrypt first (keys stay with you) and treat it as durable, public-ish
storage with payment rails, not a private database. Anchored transcripts prove what the service
returned; a dispute cannot un-leak data. Storage (action:storage) is in
example-services.md; listing one is run-a-node.md.
The privacy decision table
The rule is short: anything public and paid goes to the marketplace; anything that is you stays with you.
| Data / capability | Where it belongs |
|---|---|
| Paid public capability (search, feeds, models) | marketplace service — pay per call |
| …with metadata privacy | via a bonded relay |
| Personal accounts (email, calendar, anything OAuth) | private node only — never a third party |
| Agent context/memory | private node memory, or local DB |
| Sensitive datasets + analysis | local/your-hosted DB |
| Shared or encrypted-blob storage | marketplace storage service (encrypt client-side) |
See also
Bring your own agent · Launch an agent workflow · payments · budgets & session keys · MCP for Claude · private node · privacy design
Next: Launch an agent workflow — the same loop run end to end on the local development network, one HTTP message at a time, with the money flow printed at the end.