Operator configuration reference
A selling node, its adapters and a private node, plus the facilitator, bundler, relay, indexer,
billing, deposit service, staking node, agent runner and monitor that complete the stack, are
configured through environment variables. Each default is the one the code reads, with the reading file named, so you never
open the source to learn a setting. All are optional on the local development network: with
nothing set, the stack targets Anvil at http://127.0.0.1:8545 with deterministic test accounts.
offchain/.env.example is the copy-and-edit template.
Two files every runtime depends on are not environment variables. deployments.json holds
the contract addresses for your chain, loaded from the working directory (offchain/):
npm run deploy writes it for the local development network; a live chain uses that network's
addresses file (deploying, networks.json). A
runtime refuses to start without it; the Docker image mounts it read-only. services.json
is the multi-service runtime's catalogue (node quickstart); any
header or key written env:NAME resolves from the environment at load time and fails loudly if
missing (FAL_KEY for the fal.ai adapter, say).
Booleans are the literal string 1 (or 0 where noted). Durations are milliseconds unless the
name says otherwise. Token amounts are base units: USDC has 6 decimals, ZAI and ETH 18.
Chain, keys, and live-chain mode — src/config.ts
Settings every runtime shares: which chain it talks to, which key it signs with, and whether it may behave like a development network at all.
| Variable | Default | What it does |
|---|---|---|
RPC_URL | http://127.0.0.1:8545 | JSON-RPC endpoint every runtime talks to. |
CHAIN_ID | 31337 | Chain id used for EIP-712 domains and sanity checks. |
REAL_CHAIN | unset | 1 flips live-chain mode. Setting DEPLOYER_PRIVATE_KEY or USDC_ADDRESS flips it too. In this mode no mock tokens are deployed, nothing is minted, confirmation defaults rise to 2, and no runtime will fall back to the public Anvil mnemonic — it throws instead. |
OPERATOR_KEYSTORE_FILE | unset | Path to an encrypted JSON keystore holding the operator key. Preferred production form. |
OPERATOR_KEYSTORE_PASSWORD / OPERATOR_KEYSTORE_PASSWORD_FILE | unset | The keystore password, inline or read from a file (secret-manager friendly). Required with the keystore. |
OPERATOR_PRIVATE_KEY | unset | Raw hex operator key. Precedence: keystore, then this, then the local development network's Anvil index. |
AIOUM_DEPLOYMENTS | deployments.json | The manifest a runtime reads, relative to offchain/. deploy.ts writes to AIOUM_DEPLOYMENTS_OUT; point both elsewhere to run a throwaway chain beside a live one. |
RELAYER_PRIVATE_KEY | unset | Shared gas-paying key for the facilitator and bundler on a live chain. |
FACILITATOR_PRIVATE_KEY / BUNDLER_PRIVATE_KEY | unset | Per-service override of RELAYER_PRIVATE_KEY. |
FACILITATOR_RELAYER_INDEX / BUNDLER_RELAYER_INDEX | 3 / 21 | Local development network: which Anvil account each relayer uses, so they never fight the operator over nonces. |
FACILITATOR_URL / NODE_URL | http://127.0.0.1:8547 / http://127.0.0.1:8546 | Where the demo and SDK clients look for the facilitator and the node. |
LOG_LEVEL | info | debug, info, warn or error (src/logger.ts). |
Service node — src/node/server.ts (single service) and src/node/multinode.ts (catalogue)
Where the node listens, where it keeps receipts (vouchers, in the code) and transcripts, who may settle, how much load it accepts, and which environment names the adapters read upstream keys from.
| Variable | Default | What it does |
|---|---|---|
AIOUM_NODE_PORT | 8546 | Listen port of the single-service and multi-service runtimes. |
AIOUM_NODE_DIR | ~/.aioum-node | Durable state: accepted vouchers, transcripts, the instance lock, the shared SQLite store, the billing ledger. Wipe it after resetting the local development network (session ids restart). |
AIOUM_NODE_TOKEN | unset | Bearer token required on POST /settle and /metrics. Unset means those endpoints are open and the node prints a warning at boot. Set it before exposing a node. /mcp stays public; it is paid per call. |
AIOUM_NODE_RATE_MAX / AIOUM_NODE_RATE_WINDOW_MS | 120 / 60000 | Per-IP request budget per window before 429. |
AIOUM_NODE_MAX_INFLIGHT | 50 | Concurrent /mcp + /settle requests before the node sheds load with 503. |
AIOUM_NODE_BODY_LIMIT / AIOUM_NODE_MCP_BODY_LIMIT | 64kb / 16mb | Maximum request body, and the larger one a tool call may carry (a vision judge's frames ride inline). A body over the limit is answered as a JSON-RPC error naming it. |
AIOUM_NODE_TRUST_PROXY | unset | 1 behind a reverse proxy (see deploy/Caddyfile) so rate limiting keys on X-Forwarded-For. Never set it on a directly exposed node. |
AIOUM_HEALTH_RPC_TIMEOUT_MS | 3000 | How long /health waits on the RPC before reporting it down. |
AIOUM_SELF_STAKE | unset | ZAI of your own to stake at first boot (single-service runtime; a listing's stakeZai plays the role in services.json). Unset: 10,000 when the operator wallet holds that much, so the node is live at once; else 100, enough to list, live once backers bring the total to 10,000. |
AIOUM_SETUP_MAX_ATTEMPTS / AIOUM_SETUP_BACKOFF_MS | 5 / 1000 | Boot-time retries for stake and registration transactions (multi-service runtime). |
AIOUM_SETUP_CONCURRENCY | 8 | How many listings the multi-service runtime registers at once at boot, per operator. |
AIOUM_ADMIN_ALLOW_ADD | unset | 1 lets the admin API list new services on a live chain (POST /admin/services: the Earn page's Go live now, aioum sell add, aioum sell skill, the importer's go-live, a published agent); the local development network always allows it. |
AIOUM_ADMIN_OPERATOR_INDEX | 24 | Local development network: the Anvil account that signs for listings added through the admin API. |
AIOUM_PREVIEW_TIMEOUT_MS | 45000 | How long POST /admin/preview (the Earn page's test call, aioum sell preview) waits for the upstream. |
AIOUM_NODE_SKILLS_DIR / AIOUM_NODE_SKILL_BODY_LIMIT | <AIOUM_NODE_DIR>/skills / 24mb | Where POST /admin/skills writes an uploaded skill's folder (200 files, 1 MB each, 8 MB in all), and the largest upload it takes. |
AIOUM_DOCKER | docker | The docker binary a compute listing and the mcp verify check run. |
AIOUM_TEMPLATES_DIR | offchain/templates | Where npm run templates, the generators, the bootstrap and the runner's pipelines read the gallery (the OpenAPI importer writes its own set elsewhere and points this at it to verify). |
AIOUM_CATALOGUE_MCP | unset | npm run catalogue:bootstrap: remote lists the MCP templates whose servers run elsewhere (http: nothing of them runs on this machine), verified the ones whose check passed, all every keyless one; unset, none. A template with hostAccess is never in a bootstrap catalogue. |
AIOUM_MCP_SANDBOX | docker when docker answers | How the node serves a stdio MCP server, a stranger's code: docker runs it inside a container with nothing of the host mounted, host runs it on the machine on the operator's word. With neither, it is not served and the reason names both. AIOUM_DOCKER_BIN names the docker binary. |
AIOUM_HARDWARE_FILE | .deploy/hardware.json | Where npm run hardware:check writes the machine's report and the bootstrap reads it to gate local templates by their requires. |
HF_TOKEN | unset | Read when a model's size is looked up on the Hugging Face Hub (the optimizer and the private node's install check) and by train.export to Hugging Face. |
GITHUB_TOKEN / GH_TOKEN | unset, then gh auth token | The skills index generator's GitHub API token: without one, 60 calls an hour and no code search. |
SMITHERY_API_KEY | unset | Lets the MCP generator read Smithery's registry; without it that source is skipped and said so. |
AIOUM_PRICING_TICK_MS | 5000 | How often the multi-service runtime checks each listing with a pricing block for an elapsed window (below). |
AIOUM_NODE_PUBLIC_URL | http://127.0.0.1:<port> | The URL the node is reached at (behind TLS: https://node.<domain>, which scripts/deploy-network.sh sets). Media URLs use it, and the node announces it to the directory at boot and every AIOUM_ANNOUNCE_MS (POST <AIOUM_INDEXER_URL>/refresh { nodeUrl }); GET /identity?nonce=&url= answers with each operator's signature over the nonce and this URL, and only this URL. |
AIOUM_ANNOUNCE_MS | 600000 (10 min) | How often the node re-announces its public URL to the directory; 0 disables the timer (the boot-time announcement stays). |
AIOUM_SERVICES_CONFIG | unset | Path to services.json. Unset, the multi-service runtime serves the built-in demo catalogue. |
AIOUM_COMMIT_RESULTS | on | 0 stops the single-service runtime recording call transcripts and anchoring the Merkle results root before settlement. Leave it on: services flagged commitRequired cannot settle without a root. |
AIOUM_TRANSCRIPT_RETENTION_MS | 604800000 (7 days) | How long a session's transcript is kept after its last call. Keep it longer than settleChallengeWindow so evidence outlives the dispute window. |
FAL_KEY | unset | Read by the fal.ai adapter when services.json says "apiKeyEnv": "FAL_KEY" (the default). Any other env:NAME reference works the same way. |
APIFY_TOKEN | unset | Default token env for the apify adapter: an Apify API token or an x402-purchased prepaid token. |
BRIGHTDATA_API_KEY | unset | Default key env for the brightdata adapter (Web Unlocker, SERP and Web Scraper APIs). |
Three services.json fields per listing, beside priceUsdc and stakeZai:
| Field | Default | What it does |
|---|---|---|
template | the gallery template whose service key matches, else none | Names the template the listing runs. Shown in /services, the index and on the service page, where Run your own copy and the CLI/MCP one-liners come from. npm run templates -- add, aioum sell add --template, aioum_sell_add and the Earn page stamp it. |
pricing | unset (fixed price) | { "base", "max", "targetInflight", "window", "step" } in USDC, USDC, calls, seconds, fraction. Defaults: base = priceUsdc, targetInflight 2, window 300, step 0.25. Once per window the node compares the average calls in flight over the window with the target and moves the on-chain price one step up (at or above) or down toward base (below), never outside base–max, logged as [pricing] <key>: <old> → <new> (<reason>). /services reports pricing (current, base, max, last decision) and, for every listing, load (in flight, calls in the window, calls in the last hour). priceUsdc must sit between base and max; after a restart the chain's price is kept, clamped to the band. CLI --price-max, MCP pricingMax. |
provider | unset | { "domain": "api.example.com" }: the listing is the provider's own. The node reports it in /services; the indexer checks on every refresh that the domain names the listing's operator, by a DNS TXT record aioum-verify=<operator address> on the domain or https://<domain>/.well-known/aioum.json containing { "operators": ["0x…"] }, and marks the listing official. GET /admin/verify-domain?domain= on the node prints both records for its operator and what each check finds now (aioum sell verify-domain, aioum_sell_verify_domain). The OpenAPI importer sets it from the spec's server host. |
allowHost (on an mcp tool) | unset | An MCP server whose template carries hostAccess reads files, runs commands or drives a browser on the node it runs on. The node refuses to load it, "set "allowHost": true on the listing to run it here anyway", until the listing says so; never in a bootstrap catalogue. |
pricing (on a skill tool) | { "mode": "per-use" } | A skill listing's terms: { "mode": "per-use" | "one-time", "priceUsdc" }. Per use, every skill.get is a paid call; one-time, an agent pays once and keeps the files. /services reports mode and priceUsdc under pricing. |
Templates in the gallery (offchain/templates/*.json) add verified (set only by npm run templates -- verify), generated: { source, at } on generator-written ones, alsoOn (other templates serving the same model), local (needs Ollama or Docker on the box), requires: { gpu?, vramGb?, ramGb?, cpus? } (the bootstrap lists it only on a machine that meets it) and hostAccess (Ready-made listings).
Settlement loop — src/node/settle-loop.ts
A crash-safe background loop settles earned receipts on-chain and never drops an entry: past the deadline an entry is parked and retried at a slower cadence until it lands. These settings tune how eagerly it tries and how far fees may climb.
| Variable | Default | What it does |
|---|---|---|
AIOUM_SETTLE_INTERVAL_MS | 15000 | How often the loop scans for sessions to settle. |
AIOUM_SETTLE_JITTER_MS | 30000 | Privacy: random delay before an auto-settle's first attempt, so settle timing does not fingerprint call timing. 0 disables. Forced settles are never jittered. |
AIOUM_SETTLE_WAIT_MS | 60000 | How long one attempt waits for its transaction to mine before fee-bumping. |
AIOUM_SETTLE_FEE_BUMP_PCT | 125 | Fee multiplier per bump (125 = +25%, compounding). |
AIOUM_SETTLE_MAX_FEE_BUMPS | 10 | Caps how far fees escalate, not how many retries happen. |
AIOUM_SETTLE_DEADLINE_MS | 1800000 (30 min) | Fast-retry window per pending settlement. |
AIOUM_SETTLE_PARKED_RETRY_MS | 300000 (5 min) | Retry cadence for parked entries after the deadline. |
AIOUM_SETTLE_CONFIRMATIONS | 2 live chain, 1 local development network | Confirmations before a redeemed voucher is forgotten. A reorg keeps the entry queued. |
AIOUM_NODE_IDLE_SESSION_S | 120 | The idle close (catalogue node): a session the node holds a zero voucher for (the client handed it at open, POST /vouchers) and that served no call for this long is settled for 0 by the loop, so the client's deposit returns and the operator's session slot frees without waiting out the inactivity timeout. A session with a paid voucher is never closed this way. 0 turns it off. |
Multi-instance (single-box HA) — src/node/sqlite-store.ts
When one process is not enough, several instances serve the same operator key from one box, sharing state through SQLite and electing one to settle.
| Variable | Default | What it does |
|---|---|---|
AIOUM_STORE | unset | sqlite switches vouchers, transcripts and the settle queue to one shared SQLite database (WAL) under AIOUM_NODE_DIR, so N instances can run under one operator key. Unset, each instance keeps its own JSON files and the instance lock allows exactly one process per data dir. |
AIOUM_SETTLE_LEASE_MS | 20000 | TTL of the settle-leader lease. A killed leader is replaced within this time; followers accept /settle and enqueue. |
Privacy relay — src/relay/server.ts
A relay is an operator whose service is "proxy any other AIOUM service", so a buyer's calls never link on-chain to the node that served them. It shares the node's auth, rate and body settings.
| Variable | Default | What it does |
|---|---|---|
AIOUM_RELAY_PORT | 8553 | Listen port (8548 belongs to the bundler). |
AIOUM_RELAY_TARGETS | http://127.0.0.1:8546 | Comma-separated node URLs the relay is willing to proxy to. |
AIOUM_RELAY_MARGIN_BPS | 3000 | Per-call markup over the target's price. Break-even is about 1770 bps at the default 5% fee + 10% delegator split. |
AIOUM_RELAY_DEPOSIT | 50000000 (50 USDC) | Deposit per downstream session the relay opens on your behalf. |
AIOUM_RELAY_KEY_INDEX | 4 | Local development network: the Anvil account the relay operates from. |
AIOUM_RELAY_PRIVATE_KEY | unset | Live chain: the relay's own key, required there; it stakes and settles like a node, so it is never the catalogue node's key. |
AIOUM_RELAY_CATALOG_TTL_MS | 30000 | How long the relay caches each target's /services catalogue. |
Facilitator — src/facilitator/server.ts
The facilitator relays a buyer's signed payment authorization on-chain so the agent never needs gas of its own. It holds only a gas key; these settings are its guard rails.
| Variable | Default | What it does |
|---|---|---|
FACILITATOR_API_KEY | unset | If set, POST /open/eip3009 requires Authorization: Bearer <key> (or an X-API-Key: <key> header). |
FACILITATOR_ASSETS | unset | Extra comma-separated payment assets to relay; USDC is always allowed. |
FACILITATOR_MAX_AMOUNT | 1000000000000 (1,000,000 USDC) | Per-request ceiling in base units. |
FACILITATOR_MAX_INFLIGHT | 25 | Concurrent relays before 503. |
FACILITATOR_RATE_MAX / FACILITATOR_RATE_WINDOW_MS | 60 / 60000 | Per-IP request budget before 429. |
FACILITATOR_RELAYER_MIN_WEI | 100000000000000000 (0.1 ETH) | /health reports degraded below this relayer balance. |
FACILITATOR_REPLAY_TTL_MS | 3600000 (1 h) | How long a seen authorization is remembered for replay rejection. |
FACILITATOR_STUCK_TX_MS | 20000 | Wait before a same-nonce fee-bump replacement. |
FACILITATOR_MAX_FEE_BUMPS | 5 | Fee-bump replacements before giving up with 504. |
FACILITATOR_HEALTH_RPC_TIMEOUT_MS | 3000 | RPC timeout for /health. |
FACILITATOR_TRUST_PROXY | unset | 1 behind a reverse proxy, as for the node. |
Bundler (ERC-4337 relay) — src/bundler/server.ts
The bundler submits smart-account operations for agents that run on session keys, sponsoring their gas within a per-account budget.
| Variable | Default | What it does |
|---|---|---|
BUNDLER_PORT | 8548 | Listen port. |
BUNDLER_RATE_MAX / BUNDLER_RATE_WINDOW_MS | 120 / 60000 | Per-IP request budget before 429. |
BUNDLER_MAX_INFLIGHT | 25 | Concurrent handleOps submissions before 503. |
BUNDLER_EPOCH_MS / BUNDLER_EPOCH_GAS_CAP | 3600000 / 8000000 | Sponsored-gas budget per account per epoch, counted in gas used. A paid call from the command line opens a session, about 420,000 gas: 8 million is nineteen calls an hour. The local stack starts the bundler at 40 million. |
BUNDLER_BASEFEE_BUFFER_BPS | 10000 (1.00×) | Markup applied to the observed base fee when pricing an op. |
BUNDLER_RELAYER_MIN_WEI | 100000000000000000 (0.1 ETH) | Degraded-health threshold for the relayer balance. |
BUNDLER_PAYMASTER_MIN_DEPOSIT_WEI | 50000000000000000 (0.05 ETH) | Degraded-health threshold for the paymaster's EntryPoint deposit. |
BUNDLER_STUCK_TX_MS / BUNDLER_MAX_FEE_BUMPS | 20000 / 5 | Stuck-transaction replacement policy, as for the facilitator. |
BUNDLER_MAX_FEE_CAP_BPS | 20000 (2×) | Ceiling on fee escalation, as bps of the op's own maxFee. |
BUNDLER_CONFIRMATIONS | 2 live chain, 1 local development network | Confirmations before a handleOps success is reported. |
BUNDLER_REPLAY_TTL_MS | 900000 (15 min) | Replay-guard memory for submitted ops. |
BUNDLER_HEALTH_RPC_TIMEOUT_MS | 3000 | RPC timeout for /health. |
Discovery indexer — src/indexer/server.ts
The indexer is the directory behind discovery: it rescans the chain for listings, probes live
nodes for their catalogues, and is what an agent searches when it finds tools on its own mid-run.
It probes the nodes in its seed list and every node that announced itself: POST /refresh { "nodeUrl": "https://node.example.com" } makes it ask that URL for GET /identity and, when every
operator the node claims has signed the challenge, keep the node (nodes.json in its data dir),
probe it on every refresh and map to it only the listings of the operators it proved. GET /nodes
lists the seeds and the announced nodes. A listing on-chain whose node is neither a seed nor
announced has no endpoint in the directory, and no agent can call it.
| Variable | Default | What it does |
|---|---|---|
AIOUM_INDEXER_PORT | 8549 | Listen port. |
AIOUM_INDEXER_REFRESH_MS | 30000 | How often the chain is rescanned and seeds re-probed. |
AIOUM_INDEXER_SEEDS | http://127.0.0.1:8546,http://127.0.0.1:8553 | Node and relay URLs to probe for live catalogues; nodes that announce themselves with proof are probed as well (above). |
AIOUM_INDEXER_PROBE_TIMEOUT_MS | 4000 | Per-seed HTTP timeout. |
AIOUM_INDEXER_DIR | ~/.aioum-indexer | Holds demand.json: every listing's price history (from ServiceRegistered and ServiceUpdated events) and the sessions settled in the last seven days, kept across restarts; emptied when the chain resets. |
AIOUM_INDEXER_FROM_BLOCK | 0 on the local network, else the tip minus 50,000 | First block of the event scan on the first run; later runs continue from the last scanned block. |
AIOUM_INDEXER_SCAN_CHUNK | 5000 | Blocks per eth_getLogs request. |
AIOUM_INDEXER_EXPERIENCE_DAYS / AIOUM_INDEXER_EXPERIENCE_MAX | 30 / 20000 | How long, and how many, experience records are kept in experience.json (below). |
Each record in /services carries template (from the node, or the listing key when the node is unreachable), pricing and load as the node reports them, and demand: the price change over 24 h, calls per hour with its basis (node: the node's own count of calls served in the last hour; settled: sessions settled on-chain in the last hour, settled amount ÷ the price in force), and how many live listings run the same template. GET /services/:id/demand adds the price history, the last settled sessions and every live copy of the template, cheapest first. A listing whose node reports provider.domain carries provider (domain, verified, method: dns or well-known, checkedAt, detail in plain words) and official: true once the domain names its operator; a verified pair is rechecked after an hour, a failed one after ten minutes. Ranking puts official listings first among the live and reachable; ?official=1 filters to them.
Each record also carries experience: per need (the kind of job, data:crypto, image:gen), what agent runners' runs found with the listing: count (one record per session per tool), okRate (each record weighed by what it paid; a failed call one call at the listing's price), avgJudge (the judge's mean, 0-100, when judged), p50LatencyMs, avgCostUsdc and the latest five notes; GET /services/:id/experience has it per tool with the latest records. Runners post the records to POST /experience, signed with the wallet that paid; the indexer takes one only when the signature recovers to the client of that session on chain, the session is with that service and has settled (an error, which charges nothing, on the open session), the signer is not the listing's operator, and the session and tool are not recorded yet; it keeps them in experience.json, pruned by age and count.
Managed billing — src/billing/server.ts and src/billing/store.ts
Managed billing lets a person pay by card and have an agent's gas and deposits sponsored from that balance; these settings name its admin token, signers and price basis.
| Variable | Default | What it does |
|---|---|---|
AIOUM_BILLING_PORT | 8550 | Listen port. |
BILLING_ADMIN_TOKEN | unset | Bearer token for the admin API (accounts, grants, plans, renewals) and the top-up webhook. Unset disables admin routes. |
SPONSOR_SIGNER_KEY | local development signer | Key that signs AIOUMVerifyingPaymaster sponsorships. Must match the paymaster's sponsorSigner() on-chain. |
SPONSOR_VALID_SECONDS | 600 | Validity window stamped into each sponsorship signature. |
BILLING_TREASURY_KEY | local development account 0 | Key that funds user deposits from the treasury. Required on a live chain for /fund-deposit. |
ETH_USD_CENTS | 300000 ($3,000) | Price used to convert sponsored gas into credits. |
The ledger database lives under AIOUM_NODE_DIR. |
Deposit service — src/deposits/server.ts
The deposit service funds an AI wallet from any chain in any major asset: it quotes a route to
USDC on this network from the route provider, hands out the wallet's deposit address, keeps the
ledger and sweeps what arrives (the conversion fee to the treasury, the rest to the wallet). It
starts in one of two modes: route when the provider delivers to this chain, and direct on any
other chain, the local development network (chain 31337) among them, where it serves only the
deposit address and the sweep of USDC sent straight to it; there /chains, /tokens and /quote
answer 501 with "Routes from other chains deliver to Base; on this network send USDC to your
deposit address and it is swept to your AI wallet". The fee is depositFeeBps from
deployments.json (DEPOSIT_FEE_BPS at deploy).
| Variable | Default | What it does |
|---|---|---|
AIOUM_DEPOSITS_PORT / AIOUM_DEPOSITS_HOST | 8551 / 127.0.0.1 | Bind address. Loopback by default; bind elsewhere only behind TLS. |
AIOUM_DEPOSITS_DIR | ~/.aioum-deposits | The ledger (deposits.json): every deposit with its source, status, what was expected, credited and taken as fee, and the sweep transaction; and wallets.json, every wallet that asked for its deposit address, whose address the loop sweeps from then on. |
LIFI_API_URL | https://li.quest/v1 | The route provider's API. |
LIFI_API_KEY | unset | Sent as the provider's API key header on every request when set. |
AIOUM_DEPOSITS_SWEEP_MS | 30000 | How often the loop refreshes pending deposits against the provider and sweeps every known deposit address that holds USDC. |
DEPOSITS_PRIVATE_KEY | unset | Live chain: the sweeper, the key that pays gas for sweepFor, and required there. It holds no user funds; a forwarder pays only the treasury and the wallet. |
DEPOSITS_ACCOUNT_INDEX | 26 | Local development network: the Anvil account the sweeper uses. |
AIOUM_DEPOSITS_PUBLIC_URL | http://127.0.0.1:<port> | The address a card partner's webhook reaches the service at (/card/webhook/<partner>); GET /card/partners prints the URLs to register. |
CDP_API_KEY_ID (or CDP_API_KEY_NAME) / CDP_API_KEY_SECRET | unset | Pay by card through Coinbase Onramp. |
TRANSAK_API_KEY / TRANSAK_API_SECRET / AIOUM_CARD_RETURN_URL | unset | Pay by card through Transak; TRANSAK_ENV=staging for its test environment. |
MOONPAY_API_KEY / MOONPAY_SECRET_KEY | unset | Pay by card through MoonPay; MOONPAY_WEBHOOK_KEY verifies its webhooks. |
STRIPE_SECRET_KEY | unset | Pay by card through Stripe; STRIPE_WEBHOOK_SECRET verifies its webhooks. |
AIOUM_CARD_ABANDON_HOURS | 24 | A card deposit still pending after this long is marked abandoned. Card payments exist on Base (chain 8453) only; the partners deliver USDC there. |
Staking node — src/backer/server.ts
The network's staking node backs listings so a seller goes live with 100 ZAI of their own: POST /requests {serviceId} starts a review (the listing on-chain and on its node, the operator's own
floor, slashes and disputes, the price against the gallery, the pool's cap, a sample call through
the node, then a model against the rubric); on a yes the pool delegates the gap to minNodeStake
plus headroom, makes one paid call through the node, and the listing is live. A loop re-checks
every backed node and takes the ZAI back, with the reason, when the node stops answering, a
dispute is raised or the operator is slashed. GET /requests/:id, GET /requests?operator=,
GET /health (the pool's balance, what it holds behind operators, the reviewer) and GET /rubric.
| Variable | Default | What it does |
|---|---|---|
AIOUM_BACKER_PORT / AIOUM_BACKER_HOST | 8552 / 127.0.0.1 | Bind address. |
AIOUM_BACKER_DIR | ~/.aioum-backer | The ledger (requests.json): every request with its states and their times, checks, review, reasons, stake and transactions. |
BACKER_PRIVATE_KEY | unset | Live chain: the pool's wallet, required there. It holds the ZAI it delegates, a little USDC for the sample call it makes through each node, and gas. |
BACKER_ACCOUNT_INDEX / BACKER_POOL_ZAI | 25 / 100000 | Local development network: the Anvil account the pool uses, and the ZAI minted to it at boot. |
BACKER_MAX_PER_OPERATOR_ZAI | 20000 | The most the pool puts behind one operator, counting what it already holds there. |
BACKER_HEADROOM_SESSIONS | 2 | Sessions of capacity above the node floor, tokensPerSession each, added to the delegation when the cap allows. |
BACKER_RUBRIC | src/backer/rubric.md | What the review model reads. |
BACKER_REVIEW_SERVICE | unset | A judge listing's id (<id> or <id>:<tool>) to review through, paid per review. Without it the review uses ANTHROPIC_API_KEY (BACKER_REVIEW_MODEL, else AIOUM_AGENTS_MODEL), then AIOUM_AGENTS_OPENAI_BASE_URL with its key and model, then a local Ollama (BACKER_OLLAMA_MODEL, else its first model). No reviewer, no approvals. |
BACKER_REVIEW_MS | 60000 | How often the loop re-checks every backed node. |
BACKER_UNHEALTHY_STRIKES | 3 | Failed health checks in a row before the backing is withdrawn. |
BACKER_LOOKBACK_BLOCKS | 100000 | How far back the slash and dispute checks look at review time. |
BACKER_NODE_SEEDS | unset | Node URLs to ask for a listing when the directory (AIOUM_INDEXER_URL) has no endpoint for it. |
AIOUM_NODE_TOKEN | unset | Sent to a node's /admin/preview and /settle when its admin API is gated; a closed admin API leaves the sample to the paid call after backing. |
Monitor and paymaster tooling — src/monitor/watch.ts, src/tools/paymaster.ts
npm run monitor polls the chain and the services' /health endpoints, exposes Prometheus
metrics, and raises alerts. npm run paymaster reports the paymaster's EntryPoint deposit and
runway and can refill it.
| Variable | Default | What it does |
|---|---|---|
MONITOR_PORT | 8549 | Listen port. Same default as the indexer — set one of them when both run on one box. |
MONITOR_HOST | 127.0.0.1 | Loopback by default because /metrics and /health are unauthenticated. Bind elsewhere only with a scrape token. |
MONITOR_SCRAPE_TOKEN | unset | Required, and gates /metrics, whenever the monitor is bound off loopback. |
ALERT_WEBHOOK_URL | unset | Where alerts are POSTed. Unset means log-only. |
MONITOR_SLASH_ALERT_WEI | 1000000000000000000000 (1,000 ZAI) | Alert on any slash at least this large. |
MONITOR_SESSION_VOLUME_ALERT | 100 | Alert when more sessions than this open in one poll window. |
MONITOR_PAYMASTER_MIN_DEPOSIT_WEI | 100000000000000000 (0.1 ETH) | Alert when the paymaster's EntryPoint deposit drops below this. |
MONITOR_HEALTH_POLL_MS | 30000 | How often the services' /health endpoints are probed. |
MONITOR_CONFIRMATIONS | 2 live chain, 0 local development network | Reorg tolerance: a block is inspected for reverted settles only once it is buried this deep (the local development network inspects the tip). |
TIMELOCK_ADDRESS | unset | When set, the monitor also watches Timelock queue and execute events. |
AIOUM_PAYMASTER_MIN_ETH | 0 | npm run paymaster exits non-zero when the deposit is below this many ETH, so a cron job can alert. 0 disables. |
Deploy, handover, and the safety gate — src/deploy.ts, src/handover.ts, src/verify-deploy.ts
Read once, by the deploy and governance tools, not by the long-running services. You set them in order when deploying the stack.
| Variable | Used by | What it does |
|---|---|---|
DEPLOYER_PRIVATE_KEY | deploy | Funded EOA that deploys. Mandatory on a live chain; ownership moves to the Timelock afterwards. |
USDC_ADDRESS, ZAI_ADDRESS, PERMIT2_ADDRESS, ENTRYPOINT_ADDRESS | deploy | Canonical infrastructure to reuse instead of deploying mocks. ENTRYPOINT_ADDRESS is required on a live chain. Per-chain values are catalogued in networks.json. |
TREASURY_ADDRESS / ARBITRATOR_ADDRESS | deploy | Protocol-fee sink and the DisputeManager's arbitrator. Both required on a live chain. |
USE_VERIFYING_PAYMASTER / SPONSOR_SIGNER_ADDRESS | deploy | Deploy the signature-gated paymaster — set 1 to opt in on the local development network; a live chain deploys it when SPONSOR_SIGNER_ADDRESS is set and skips it otherwise — and the address allowed to sign sponsorships. Live-chain deploys ship it unfunded. |
ESCROW_CAP_USDC / SLASH_BPS | deploy | Deploy-time economics: escrow cap per staked ZAI, and the proportional slash in bps. See economics. |
MIN_SELF_STAKE | deploy | An operator's own stake floor in ZAI (100); the node floor of total stake, own + delegated, is 10,000. Both governance-settable afterwards (setParams). |
AIOUM_DEPLOYMENTS_OUT | deploy | Where deploy.ts writes the manifest (deployments.json in offchain/); point it elsewhere to try a deploy on a throwaway chain without touching the live one. |
DEPOSIT_FEE_BPS | deploy | The conversion fee on deposits from other chains and assets, in bps (100 = 1%, the default; at most 1000). Baked into the DepositForwarderFactory and written to deployments.json as depositFeeBps. |
DAO_OWNER, TIMELOCK_ADDRESS, CONFIRM_HANDOVER, ALLOW_EOA_OWNER | handover | Transfers every governance contract to the DAO. Irreversible, so the target is validated and CONFIRM_HANDOVER=1 is required; ALLOW_EOA_OWNER=1 is for test networks only. |
TIMELOCK_ADDRESS / DAO_OWNER | verify-deploy | The owner every contract must report for npm run verify-deploy to pass. TIMELOCK_ADDRESS wins when both are set. |
Private node — src/private-node/*.ts
The self-hosted personal runtime (Your private node) keeps secrets, a local context store and scheduled workflows on your own machine, and pays marketplace nodes from a budget-capped agent wallet.
| Variable | Default | What it does |
|---|---|---|
PRIVATE_NODE_PASSPHRASE | unset | scrypt key for the AES-256-GCM secret store. Unset, the node generates a 0600 keyfile under PRIVATE_NODE_DIR instead and warns you to back it up: losing it loses your secrets. |
PRIVATE_NODE_PORT / PRIVATE_NODE_HOST | 8770 / 127.0.0.1 | Bind address. 0.0.0.0 on a server the app reaches from another machine by address (every call carries the node's token; open the port to that machine alone, or put TLS in front with deploy/Caddyfile). Bound beyond loopback, the node answers to its own IP or PRIVATE_NODE_PUBLIC_HOST as host; bound to loopback it refuses every foreign host. |
PRIVATE_NODE_PUBLIC_HOST | unset | The name a server node is reached by, when it has one (an IP needs no setting). |
~/.aioum-private/env | written by install-node.sh | The node's own settings, one KEY=VALUE a line, read before the environment at every start: the chain (AIOUM_DEPLOYMENTS, REAL_CHAIN, CHAIN_ID, RPC_URL), the directory and the faucet (AIOUM_INDEXER_URL, AIOUM_FAUCET_URL), how it binds. The environment wins; a key, token or passphrase named in the file is ignored and said so. |
AIOUM_FAUCET_URL | unset | The testnet faucet the node claims from for its wallet (GET/POST /wallet/faucet): ZAI and the testnet dollar once per wallet, the proof of work solved on the node. |
PRIVATE_NODE_DIR | ~/.aioum-private | Where secrets.enc, the bearer token, jobs and the local brain live. |
PRIVATE_NODE_TOKEN | generated | Bearer token for the API; unset, one is generated and stored in PRIVATE_NODE_DIR. |
PRIVATE_NODE_TRUST_LOOPBACK | unset | 1 lets local non-browser callers (loopback requests that carry no Origin header) skip the bearer token; browser calls always need it. |
PRIVATE_NODE_ALLOWED_ORIGIN | http://localhost:3000 | CORS origin allowed to call the private node (the app). |
PRIVATE_NODE_RUNNER / PRIVATE_NODE_RUNNER_PORT | on / the port after the node's (8771) | Your own runner, a child of the node on 127.0.0.1: 0 starts the node without it. Its records are in <PRIVATE_NODE_DIR>/runner, its wallet is the one connected on the node. |
PRIVATE_NODE_SELLING_PORT / PRIVATE_NODE_SELLING_URL | the node's port + 10 (8780) / http://127.0.0.1:<port> | Your selling node, started by the private node when you go live with no other node to list on: its port, and the address buyers reach it at (the listing carries it). |
PRIVATE_NODE_OWNER | the wallet's address | The one owner of everything your own runner holds; a request that names another is refused. |
PRIVATE_NODE_MAX_EGRESS_BYTES | 4096 | Cap on private context bytes a workflow step may send to a paid external service per call; over the cap is refused, never truncated. |
MARKET_NODE_URL | http://127.0.0.1:8546 | The marketplace node the executor pays for external tools. |
AGENT_ACCOUNT_INDEX | 16 | Local development network: the Anvil account used as the scheduler's budget-capped agent wallet. |
SCHEDULER_LEASE_MS | 300000 (5 min) | Lease so exactly one runner executes recurring workflows. |
SCHEDULER_CATCHUP_GRACE_MS | 120000 (2 min) | Grace period in which runs missed during downtime are still executed. |
MEMORY_MAX_ITEMS | 5000 | Cap on local-brain items, bounding disk and memory growth. |
PRIVATE_NODE_URL / BACKUP_PASSPHRASE | http://<host>:<port> / unset | Used by npm run private-node:backup: which node to back up and the passphrase that encrypts the archive. |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | unset | OAuth client for connecting Gmail and Google Calendar; the connect flow is disabled without them. The ad, analytics and publishing accounts take their OAuth app's client id and secret on the card at connect time and keep them encrypted on the node. |
PRIVATE_NODE_PUBLIC_URL | http://<host>:<port> | The address the node is reached at: the OAuth callback (/oauth/<provider>/callback) and workspace file URLs (/workspace/<path>) are built on it. Set it behind TLS. |
PRIVATE_NODE_WORKSPACE | <PRIVATE_NODE_DIR>/workspace | The workspace root: ws.* refuses any path outside it. |
PRIVATE_NODE_MODELS / PRIVATE_NODE_TRAIN | <PRIVATE_NODE_DIR>/models / <PRIVATE_NODE_DIR>/train | Where Hugging Face installs (the Python venv, the model cache, the worker log) and training jobs keep their state. |
OLLAMA_HOST | 127.0.0.1:11434 | Where hf.install pulls an LLM to and hf.run runs it (a host:port or a URL). |
HF_WORKER_PORT / HF_WORKER_DEVICE | 8790 / auto | The pipeline worker's port on loopback (a free one when 8790 is taken) and the device it loads models on. |
TRAIN_IMAGE_<KIND> | pytorch/pytorch:2.4.0-cuda12.4-cudnn9-runtime | The trainer image for train.lora per kind (LLM, IMAGE, AUDIO, VIDEO). |
PLAYWRIGHT_MODULE | playwright | Where ws.screenshot and ws.browse resolve Playwright from, when it is not in offchain/node_modules. |
ZEROX_API_KEY / ZEROX_API_URL | unset / https://api.0x.org | wallet.swap's quote source. |
AIOUM_AGENTS_URL | the node's own runner | The runner skills.install fetches an index skill's files from when the agent did not hand them over. |
Runner — src/agents/server.ts
A runner keeps agents, runs and projects, plans an assistant's turns, pays their calls, streams runs live and keeps the spend rollups. Your own runs inside your private node, started with it, and pays from the wallet connected there. A shared runner is a listing people sign in to; their own accounts pay. It does not start without a mode.
| Variable | Default | What it does |
|---|---|---|
AIOUM_AGENTS_MODE | unset | own (one person's, behind a token; a private node sets it for its runner), shared (people sign in with their wallets), or open (tests only; refused on a real chain). |
AIOUM_AGENTS_TOKEN / AIOUM_AGENTS_TOKEN_FILE / AIOUM_AGENTS_OWNER | unset | An own runner's token, or a file only you read that holds it; the one owner whose requests it answers. |
AIOUM_AGENTS_KEYS_SECRET / AIOUM_AGENTS_KEYS_SECRET_FILE | unset | A shared runner's secret that seals people's spending keys at rest (16 characters or more). |
AIOUM_AGENTS_SESSION_TTL_S / AIOUM_AGENTS_FEE_SERVICE | 86400 / unset | How long a sign-in on a shared runner lasts; the listing its fee goes to. |
AIOUM_AGENTS_REVIEWER | unset | 1: the runner bonds ZAI and reviews the listings the chain draws it for (AIOUM_REVIEWER_PRIVATE_KEY or AIOUM_REVIEWER_KEY_INDEX, AIOUM_REVIEWER_BOND_ZAI, AIOUM_REVIEWER_POLL_S). |
AIOUM_AGENTS_PORT / AIOUM_AGENTS_URL | 8560 / http://127.0.0.1:<port> | Listen port when started by hand, and the address it gives a published agent's listing. A private node starts its own runner on 8771 and answers for it at /runner. |
AIOUM_AGENTS_HOST | every interface | The address the runner binds to. A private node starts its own runner on 127.0.0.1. |
AIOUM_AGENTS_REVIEW_WATCH | off | 1: the runner reviews the network's new listings unasked, from its own wallet. Off, a review is made on request only. |
AIOUM_AGENTS_DIR / AIOUM_AGENTS_MAX_RUNS | ~/.aioum-agents when started by hand; ~/.aioum-private/runner for your own; ~/.aioum-shared-runner for the local stack's shared one / 400 | Agents, runs, projects, the spend rollups (spend.json), the bought-skill cache (skill-cache/<agent>/) and the runner's copy of what its runs learned about tools (experience.json); how many runs are kept. |
AIOUM_AGENTS_EXPERIENCE_MAX | 2000 | Experience records kept on the runner, so a search ranks by what it learned when the directory is out of reach. |
AIOUM_AGENTS_PRIVATE_KEY / AIOUM_AGENTS_KEY_INDEX | unset / 30 | The runner's wallet. Your own runner gets the wallet connected on your node, handed over as it starts. A shared runner's own pays its gas and the reviews it makes, and nothing of a person's; required on a live chain; on the local development network an Anvil account of its own, so its session opens never share a nonce counter with a node's settles (the account map is in offchain/src/config.ts; the deploy funds its gas), which tops itself up with test USDC. |
AIOUM_INDEXER_URL / AIOUM_AGENTS_CATALOG_TTL_MS | http://127.0.0.1:8549 / 30000 | The directory the runner reads its tool catalogue from, and how long it keeps it. |
AIOUM_MULTINODE_URL / AIOUM_NODE_TOKEN | http://127.0.0.1:8556 / unset | The catalogue node that lists a published agent, and its admin token when it has one. |
AIOUM_PRIVATE_NODE_URL / AIOUM_PRIVATE_NODE_TOKEN | http://127.0.0.1:8770 / the file <PRIVATE_NODE_DIR>/token | Your private node, whose connected tools every agent gets as Your node (PRIVATE_NODE_TOKEN is read too). AIOUM_AGENTS_LOCAL_TTL_MS (15000) caches its tool list; AIOUM_AGENTS_LOCAL_CALL_TIMEOUT_MS (600000) bounds a local call. |
AIOUM_SKILLS_DIR / AIOUM_TEMPLATES_DIR | offchain/skills / offchain/templates | The skills index the runner serves and searches, and the gallery its pipelines count templates from. |
ANTHROPIC_API_KEY / AIOUM_AGENTS_MODEL | unset / claude-opus-5 | The runner's own planner; an agent's own pick under Model (plannerModel) comes first. |
AIOUM_CLAUDE_CLI | found | Where Claude Code is on the runner's machine, when the runner should not look for it itself (it looks on PATH, in the usual install folders and at the editor extension's bundled binary, and takes the newest). Your Claude plan plans through it once you are signed in (Settings, or claude auth login; Claude Code 2 or later). |
AIOUM_AGENTS_CLAUDE_MODEL | opus | The model your Claude plan is asked for: an alias Claude Code knows (opus, sonnet) or a Claude model id. An agent's own pick under Model comes first. |
AIOUM_AGENTS_MAX_TOKENS / AIOUM_AGENTS_CONTINUATIONS | 8192 / 3 | The longest reply one planning turn asks for (never past the model family's documented ceiling), and how many times a reply cut off at that length is continued before the run gives up. |
AIOUM_AGENTS_RENTAL_IDLE_MIN | 30 | How long a paused project keeps the GPU the setup rented for it before it is torn down by its id; a resume within that time finds it up, a later one rents again. |
AIOUM_AGENTS_RENTAL_WAIT_MIN | 6 | How long the setup waits for a rented GPU by the clock: this long for the provider to say it runs, three times it for a bootstrapped pod's job server to answer. Past it the pod is terminated by its id and the setup goes on without it. |
AIOUM_AGENTS_PLAN_PROBE_MS | 120000 | How often the runner reads your Claude plan's sign-in again: a new login on the machine, or a limit that passed, is seen without a restart, and a project that paused waiting for a planner starts itself. A key planner whose account is out of credit is set aside for an hour and the next planner is used. |
AIOUM_AGENTS_MAX_TURNS | 60 | Planning turns one run may take (a turn is one model call; its tool calls run together). The budget and the run's deadline are the caps that matter. |
AIOUM_AGENTS_SAMPLE_ROUNDS | 10 | How many times a project's sample stage is made (the stage as proposed, then sample rounds, each changing the approach when the last did not improve) before the project pauses rather than build anything long on a sample that did not reach the bar. |
AIOUM_AGENTS_TURN_RETRIES / AIOUM_AGENTS_TURN_BACKOFF_MS / AIOUM_AGENTS_STAGE_RETRIES | 5 / 5000 / 2 | A planning turn the model does not answer (a timeout, a dropped connection, an overloaded or rate-limited model) is asked again after a wait that doubles from the backoff up to a minute, this many times, each try a status line in the run; a project stage that still fails that way runs again by itself this many times before the project pauses for it. |
AIOUM_AGENTS_ASK | unset | The starting value of Ask me before continuing under Settings → Defaults, which overrides it once set there. A job never stops to ask you: a stage that fails for good is routed around (the stages after it read its error and deliver what they can, the project ends done naming what was lost), a sample nobody scored is taken as it is, and a job nothing live can serve ends with the answer (what is missing, the key that unlocks it). Set to 1 to bring the pauses back: edit the remaining stages and resume, add the key and press Continue. |
AIOUM_AGENTS_PARALLEL_CALLS / AIOUM_AGENTS_SESSIONS_PER_SERVICE | 8 / 3 | How many of one planning turn's tool calls run at once (calls that do not depend on each other go in one turn and run together), and how many sessions a run holds open with one service at once: one call at a time per session keeps each receipt's running total exact, so a second call in flight on a service takes another session, and past this many the call waits for one to free. |
AIOUM_AGENTS_TEST_INFLIGHT / AIOUM_AGENTS_TEST_INFLIGHT_NEED / AIOUM_AGENTS_TEST_INFLIGHT_FAMILY | 16 / 4 / 3 | How many of the setup's tool tests run at once: across every need, per need, per upstream (one provider's key). Every candidate starts as soon as a slot frees. |
AIOUM_AGENTS_TEST_AHEAD | 1 | How many candidates beyond what a need still needs may be in flight at once (a media need wants two at the bar): the next start waits for a verdict, so a need about to be met does not pay for tests it will not use. |
AIOUM_AGENTS_TEST_VARIANTS / AIOUM_AGENTS_TEST_VARIANT_MIN / AIOUM_AGENTS_TEST_VARIANTS_PER_NEED | 2 / 40 / 4 | Usage rewrites: how many ways to use a below-bar tool better the planner proposes from the judge's reasons (each tested at once as a variant), from what score up a rewrite is worth paying for, and how many variant tests a need may run in all. 0 turns them off. |
AIOUM_AGENTS_TEST_JUDGE_BATCH | 4 | How many landed results one judge call scores at once when they land while a judge call is busy. |
AIOUM_AGENTS_OPENAI_BASE_URL / AIOUM_AGENTS_OPENAI_MODEL / AIOUM_AGENTS_OPENAI_API_KEY | unset / gpt-4o-mini / unset | Any OpenAI-compatible planner. |
AIOUM_AGENTS_OLLAMA_URL / AIOUM_AGENTS_OLLAMA_MODEL | http://127.0.0.1:11434 / llama3.2, else the first local model | A local planner beside the runner. |
AIOUM_AGENTS_RUN_TIMEOUT_MS / AIOUM_AGENTS_CALL_TIMEOUT_MS / AIOUM_AGENTS_HIRE_TIMEOUT_MS | 1200000 / 90000 / 1500000 | A run (20 min, plus one hire's wait per part it may hire), one paid call (a listing that states its own timeout is waited on that long), one hire of another agent (25 min: a part whose single calls take minutes). |
AIOUM_AGENTS_TEST_MAX_MIN / AIOUM_AGENTS_TEST_WINDOW_S / AIOUM_AGENTS_ACCEPT_SCORE | 8 / 60 / 80 | The setup's tool tests: the most one test runs, how long one is waited on before the next candidate starts, and the judge's score a test output and the deliverable must reach. |
AIOUM_AGENTS_MAX_CALLS / AIOUM_AGENTS_MIN_DEPOSIT_USDC | 200 / 0.5 | Paid calls per run, and the least an agent sets aside for a session (twenty-five calls' worth otherwise, never past the budget). |
AIOUM_AGENTS_MAX_SERVICE_RUNS | 8 | Runs the published agents serve at once (a lead's turn hires its parts at the same time); past it a caller gets "this agent is busy serving other callers". |
AIOUM_AGENTS_PAY_FROM | native | Pay in any token: what the wallet on your node sells for USDC when a session needs more than the runner holds (on by default per agent, payAcross). On the local development network the runner tops itself up with test USDC instead. |
AIOUM_AGENTS_SSE_HEARTBEAT_MS | 15000 | The ping on GET /runs/:id/events and GET /projects/:id/events. |
Keys console — src/tools/keys-console.ts
Every key above and every listing key, as a checklist on your machine that writes .env at the repository root and reads what is live from the running services (Add your keys).
| Variable | Default | What it does |
|---|---|---|
AIOUM_KEYS_PORT | 8590 | Listen port, on 127.0.0.1 only (scripts/devstack.sh review starts it as keys; KEYS_PORT there). Requests whose Host or Origin is not this machine are refused; a value pasted on the page is written to .env with mode 0600 and never sent back. AIOUM_INDEXER_URL is where it reads which listings are live. |
Ports at a glance
| Service | Port | Variable |
|---|---|---|
| Anvil (local development chain) | 8545 | — |
| Service node | 8546 | AIOUM_NODE_PORT |
| Facilitator | 8547 | — |
| Bundler | 8548 | BUNDLER_PORT |
| Indexer | 8549 | AIOUM_INDEXER_PORT |
| Billing | 8550 | AIOUM_BILLING_PORT |
| Deposits | 8551 | AIOUM_DEPOSITS_PORT |
| Staking node | 8552 | AIOUM_BACKER_PORT |
| Relay | 8553 | AIOUM_RELAY_PORT |
| Your own runner, inside the private node | 8771 | PRIVATE_NODE_RUNNER_PORT |
| Your selling node, started by the private node | 8780 | PRIVATE_NODE_SELLING_PORT |
| Shared runner (local stack) | 8562 | SHARED_RUNNER_PORT |
| Paid reviewers (local stack) | 8661–8663 | REVIEWERS_PORT |
| A runner started by hand | 8560 | AIOUM_AGENTS_PORT |
| Private node | 8770 | PRIVATE_NODE_PORT |
| Keys console (loopback) | 8590 | AIOUM_KEYS_PORT |
| Hugging Face worker (private node, loopback) | 8790 | HF_WORKER_PORT |
| dApp (dev server) | 3000 | — |
All of it assumes a deployments.json that names the contracts on your chain. On the local
development network npm run deploy writes it for you. When the chain is your own, that file
comes from the deploy itself, the handover of ownership, and the verification gate that must pass
before anything is funded.
Next: Run every part yourself — every service the network runs on, started on your own machine and pointed at from the app, the command line and Claude.