Quickstart

Provision an oracle, scaffold it as a Cloudflare Workers project, boot it locally and call a plugin route — in about ten minutes.

What you'll have at the end

An oracle on @ixo/oracle-runtime-workers running locally on http://localhost:8787, with:

  • Its own on-chain entity and DID (with its Ed25519 UCAN signing key), Matrix bot account and account room.
  • The bundled plugins resolved at boot.
  • The Weather plugin added, with its public GET /weather/now?city=X route answering.

Step 0 — prerequisites

  • Node.js 22+
  • pnpm 10+ — npm install -g pnpm
  • The IXO Mobile App or a 12/24-word mnemonic (for offline auth), with some IXO on the network you pick
  • An OpenRouter API key — get one at openrouter.ai
  • To deploy later: a Cloudflare account on the Workers Paid plan (local development needs no account)

Step 1 — install the CLI

pnpm add -g qiforge-cli           # npm package name
pnpm approve-builds -g            # approve protobufjs when prompted
qiforge-cli --version             # 2.0.0 or later

Step 2 — provision and scaffold

qiforge-cli new

The CLI walks through:

  1. Auth — pick SignX (QR code) or offline (mnemonic). Offline is faster for local dev.
  2. Oracle profile — name, description, organisation, avatar. Defaults are fine.
  3. Network — pick devnet for development.
  4. Install — let the CLI run pnpm install at the end, or run it yourself.
  5. Relayer node and Agent Card — keep the IXO relayer, and describe the services your oracle offers.
  6. Provisioning — enter a 6-digit PIN that encrypts the oracle's secrets, then confirm the transactions when prompted (SignX needs the mobile app; offline signs locally). The CLI creates the oracle's account and DID (with its UCAN signing key), its Matrix bot and account room, its entity, domain card, Agent Card and encryption key.

The result is a Cloudflare Workers project with the oracle's identity already in its wrangler configs:

my-oracle/
├── src/
│   ├── index.ts              # createOracleWorker({ config, plugins })
│   ├── gateway.ts            # the Matrix gateway as its own Worker script
│   ├── config.ts             # identity + prompt slots
│   └── plugins/              # your plugins go here
├── .claude/
│   └── skills/qiforge-oracle/  # Claude Code skill (project-local)
├── wrangler.jsonc            # oracle script ("minify": true, vars, Durable Objects)
├── wrangler.gateway.jsonc    # gateway script
├── .dev.vars                 # the Worker's secrets (gitignored)
├── oracle-credentials.env    # the oracle's wallet mnemonic + Matrix credentials (gitignored; back it up)
├── package.json              # @ixo/oracle-runtime-workers 0.37.0
└── CLAUDE.md

The full layout and every flag are in the CLI reference.

Step 3 — add your LLM key

qiforge-cli new wrote the Matrix secrets to .dev.vars. Add your OpenRouter key:

- OPEN_ROUTER_API_KEY=
+ OPEN_ROUTER_API_KEY=sk-or-v1-...

The non-secret configuration — the oracle's DIDs, Matrix user and account room, and the network's memory engine, sandbox, Firecrawl, domain indexer and VFS URLs — is already in the vars of wrangler.jsonc. Plugins whose variables are missing don't load; the boot log names them and why. See Environment variables for the complete list.

Step 4 — boot

cd my-oracle
pnpm dev                          # wrangler dev, both scripts

You should see something like:

[wrangler:info] Ready on http://localhost:8787
[my-oracle] [boot] oracle 'my-oracle' loaded plugins: [ixo-chain, memory, sandbox, firecrawl, domain-indexer, vfs, tasks, editor, user-preferences, portal, agui, attachments, matrix-group-chats, pod-creator] excluded: [action-proposals (...), hub-actions (...), composio (... (COMPOSIO_API_KEY))]

The excluded plugins are normal — they need configuration you didn't set. Check the oracle answers:

curl http://localhost:8787/health
# {"status":"ok", ...}

Every other route needs a UCAN invocation: curl http://localhost:8787/sessions answers 401.

Step 5 — add a plugin and call its public route

The runtime ships a demo WeatherPlugin that exercises every plugin hook. Add it in src/index.ts:

import {
  BUNDLED_WORKERS_PLUGINS,
  createOracleWorker,
  WeatherPlugin,
} from '@ixo/oracle-runtime-workers';
import { config } from './config';

const oracle = createOracleWorker({
  config,
  plugins: [...BUNDLED_WORKERS_PLUGINS, new WeatherPlugin()],
});

wrangler dev reloads. The boot line now lists weather. Its GET /weather/now route is excluded from UCAN auth through getAuthExcludedRoutes():

curl 'http://localhost:8787/weather/now?city=Berlin'
{
  "ok": true,
  "city": "Berlin",
  "temp_c": 5.3,
  "units": "celsius",
  "conditions": "partly cloudy",
  "latitude": 52.52437,
  "longitude": 13.41053
}

This proves the plugin loaded, its route mounted on the shell, the auth exclusion applied, and the call to Open-Meteo went out from the Worker. To write your own plugin, run qiforge-cli plugin new <name> — see Write a plugin.

Step 6 — deploy and chat

Chat clients (the Portal, Matrix) authenticate every request with a UCAN invocation addressed to the oracle, so you chat with the deployed oracle:

pnpm exec wrangler login
pnpm run deploy                   # the gateway script, then the oracle script
pnpm exec wrangler secret bulk .dev.vars
pnpm exec wrangler secret put MATRIX_ORACLE_ADMIN_PASSWORD -c wrangler.gateway.jsonc
pnpm exec wrangler secret put MATRIX_RECOVERY_PHRASE -c wrangler.gateway.jsonc
pnpm exec wrangler secret put MATRIX_VALUE_PIN -c wrangler.gateway.jsonc
qiforge-cli update-oracle-api-url # point the entity at https://my-oracle.<subdomain>.workers.dev

Both wrangler configs set "minify": true; keep it on. See Deploy → Cloudflare Workers runtime.

What you just verified

You sawWhat it proves
qiforge-cli new finishingThe oracle's DID, signing key, Matrix account and entity exist, and the project carries them.
Boot line listing pluginsPlugin loading, env validation and auto-detection worked.
excluded: with reasonsEnv-driven opt-in (autoDetect) is wired correctly.
/health 200, /sessions 401The shell runs and enforces UCAN auth.
GET /weather/now returning JSONA plugin's getRoutes and getAuthExcludedRoutes apply.

Where to go next

Troubleshooting

SymptomLikely fix
Boot fails naming an env keySet it in wrangler.jsonc vars (or .dev.vars for a secret), or turn the plugin off with features: { name: false } in createOracleWorker.
[matrix] ensureStarted failed in the logThe gateway cannot log the bot in: check MATRIX_BASE_URL, MATRIX_ORACLE_ADMIN_USER_ID and MATRIX_ORACLE_ADMIN_PASSWORD.
Memory, VFS or sandbox tools refuse with no signing keyThe oracle has no Ed25519 UCAN signing key: run qiforge-cli setup-signing-key --env oracle-credentials.env (oracles created before CLI 2.0.0).
Durable Object's isolate exceeded its memory limitKeep "minify": true and use runtime 0.37.0 or later — see Deploy.

Full coverage: Troubleshooting.