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.