Drive your private node
Your private node holds your own accounts: Gmail, your calendar, any keyed API, and a memory of
facts and preferences. It runs where you put it, its secrets are encrypted at rest, and calling
it costs nothing because you own it. With the aioum_node_* tools, Claude connects accounts,
calls its tools, keeps and recalls memory, runs scheduled workflows and backs it all up. You set
the node up in Your private node; the server reaches it at
AIOUM_PRIVATE_NODE_URL (default http://127.0.0.1:8770) with AIOUM_PRIVATE_NODE_TOKEN, or
the token file the node wrote at ~/.aioum-private/token.
Is it up
You: "Is my private node running? What is connected?"
Claude calls aioum_node_status with {}
You see: the node's health (ok, kind: "private-node") and its providers, each with its
label, authType (none, oauth or apikey), whether it is connected, and the names of
its tools: workspace, hf (Hugging Face models), hardware, train, skills and
memory, always connected; gmail, gcal, apikey, wallet, exchange, the OAuth accounts
(googleads, youtube, ga, gsc, tiktokads, redditads, snapads, hootsuite, xads)
and ghost, connected when you say so. Names only; the node never returns a secret.
Connect an account
Two kinds of connection. A key-only API:
You: "Connect my weather API: key abc123, base URL https://api.example.com."
Claude calls aioum_node_connect with
{ "provider": "apikey", "apiKey": "abc123", "baseUrl": "https://api.example.com" }
You see: ok, connected: "apikey" and the baseUrl that was fixed. The key is stored
encrypted on the node; the call tool resolves every path against that base URL and refuses any
that lands on another origin. Optional header names the header the key goes in, prefix what
precedes it (for example Bearer ). The key you paste is in the conversation; Claude passes it
to the node and nowhere else.
An OAuth account:
You: "Connect my Gmail."
Claude calls aioum_node_connect with { "provider": "gmail" }
You see: an authUrl. Open it in a browser, approve, and Google redirects to the node, which
stores the tokens encrypted and refreshes them when they expire. gcal works the same way. The
node needs GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in its own environment; without them the
answer is "OAuth not configured", with what to set.
You: "Disconnect the weather API."
Claude calls aioum_node_disconnect with { "provider": "apikey" }
Its tools, and calling one
You: "What can the node do?"
Claude calls aioum_node_tools with {}
You see: the tools of every connected provider, each with its args and which of them are
required: the workspace's ws.list, ws.read, ws.write, ws.run, ws.fetch,
ws.screenshot, ws.browse and ws.ffmpeg; hf.install, hf.status, hf.list, hf.remove
and hf.run; hardware.check and hardware.optimize; train.lora, train.distill,
train.status, train.list and train.export; skills.install and skills.list; remember
and recall from memory; sendGmail, readGmail and createGcalEvent; call for a connected
key-only API; and, once connected, the wallet's, the exchange's and each account's own tools
(Your node).
You: "What can this machine run? Write the answer to hardware.md in the workspace."
Claude calls aioum_node_call with { "tool": "hardware.check" }, then aioum_node_call
with { "tool": "ws.write", "args": { "path": "hardware.md", "content": "…" } }
You see: the machine's report (CPU, RAM, GPUs and their memory, disk, Docker and the NVIDIA
runtime, Ollama, ffmpeg's encoders, python3) and then the file's workspace path and URL. A wallet
or an exchange connects through the Your node cards on the marketplace page with the caps you
set; aioum_node_connect covers API keys and the OAuth sign-in link.
You: "Email me the gas price we just looked up."
Claude calls aioum_node_call with { "tool": "sendGmail", "args": { "to": "you@example.com", "subject": "Gas right now", "body": "…" } }
You see: sendGmail returned: and the tool's text result. No receipt, no payment: the call
runs on your node, through your token.
Memory
You: "Remember that I prefer answers in metric units."
Claude calls aioum_node_memory_add with
{ "text": "Prefers metric units.", "kind": "preference", "tags": "units,style" }
You see: the stored item: its id, kind, text, tags and at. Kinds are fact,
preference, result and note; tags is a comma-separated string.
aioum_node_memory_list with {} returns every item; aioum_node_memory_delete with
{ "id": "…" } forgets one. aioum_node_memory_forget_all with {} wipes the store, in memory
and on disk, and answers with how many items were forgotten; secrets and schedules are
untouched. The store is capped, encrypted with the node's own key, and never leaves the node:
only the slice a step needs is ever sent to a paid service.
Schedules
The node runs workflows of its own on a timer, paying marketplace steps from its budget-capped wallet and calling its own connectors for personal steps.
You: "What is scheduled?"
Claude calls aioum_node_schedules with {}
You see: each job's id, name, steps, intervalSeconds, budgetUsdc (per run, in USDC
base units), enabled, nextRun, lastRun and its runs, each with at, ok, spent,
outputs and any error.
You: "Every hour, fetch the ETH gas price with at most 10 cents a run."
Claude calls aioum_node_schedule_create with:
{
"job": {
"name": "Hourly gas",
"intervalSeconds": 3600,
"budgetUsd": 0.1,
"steps": [
{ "id": "gas", "category": "chain:eth-gas", "tool": "gasPrice", "inputs": {} }
]
}
}
You see: the job, enabled, with its first nextRun. A step names a category and a tool;
its inputs are literals ({ "kind": "literal", "value": "…" }) or references to an earlier
step's output ({ "kind": "ref", "fromStep": 0, "extract": "text" }, where extract is text
for the whole output, number or price for the first figure in it, or ticker). A step may pin
a serviceId, cap maxPricePerCall, and must set allowContextEgress before a paid step may
receive anything derived from memory. The app's workflow page builds the same steps by hand, and
the node runs both the same way
(How a workflow uses it).
aioum_node_schedule_run with { "id": "job_…" } fires a job now, waits, and returns it with
the new run appended; aioum_node_schedule_toggle pauses or resumes it;
aioum_node_schedule_delete removes it. A job that comes due while the node is off for hours is
skipped, not fired in a burst.
Backups
You: "Back up the node to ~/aioum-backup.bin."
Claude calls aioum_node_backup_export with
{ "path": "/Users/you/aioum-backup.bin", "passphrase": "…" }
You see: confirmation that the file was written. The node bundles its secrets, memory and
jobs into one blob encrypted under the passphrase you gave (twelve characters at least); the
server writes it to path on the machine it runs on. The bearer token is never included.
You: "Restore it on this machine."
Claude calls aioum_node_backup_restore with
{ "path": "/Users/you/aioum-backup.bin", "passphrase": "…" }
You see: ok, the files restored, and the note to restart the node: restored state loads on
the next start. The secrets inside the blob stay encrypted under the node's own at-rest key, so
restoring on another machine needs the same PRIVATE_NODE_PASSPHRASE or a copy of its keyfile.
Next: Watch the network — every probe in the status check, recent activity, balances, a run as it happens, and an operator who went dark.