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)
Privacybest — prompts, results, memory never leave your machinegood — your infra, but a cloud provider can see the box
Uptimewhile your machine is onalways-on (agents that act while you sleep)
Keysowner key can live in your normal wallet/keychainowner key should never touch the server (below)
Best forpersonal agents, development, privacy-sensitive dataschedulers, 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 / capabilityWhere it belongs
Paid public capability (search, feeds, models)marketplace service — pay per call
…with metadata privacyvia a bonded relay
Personal accounts (email, calendar, anything OAuth)private node only — never a third party
Agent context/memoryprivate node memory, or local DB
Sensitive datasets + analysislocal/your-hosted DB
Shared or encrypted-blob storagemarketplace 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.