Skip to main content

What you’ll have at the end

A live oracle on localhost:3000 with:
  • The 15 bundled plugins resolved at boot.
  • A custom Weather plugin loading on demand.
  • A GET /weather/now?city=X public HTTP route.
  • A streaming chat endpoint over SSE.

Step 0 — prerequisites

  • Node.js 22+
  • pnpmnpm install -g pnpm
  • The IXO Mobile App or a 12/24-word mnemonic (for offline auth)
  • An OpenRouter API key — get one at openrouter.ai

Step 1 — install the CLI

If it prints the help text, the CLI is ready.

Step 2 — scaffold a project

The CLI walks through:
  1. Auth — pick SignX (QR code) or offline (mnemonic). Offline is faster for local dev.
  2. Network — pick devnet for development.
  3. Oracle profile — name, description, price, model. Defaults are fine.
  4. Entity creation — the CLI writes a transaction to register your oracle’s entity DID on chain. Confirm when prompted (SignX needs the mobile app; offline signs locally).
  5. Matrix bot — provisioned automatically.
Entity creation registers the oracle’s API URL as http://localhost:4000 by default, but the runtime boots on PORT=3000. To make your oracle reachable at its registered URL, either set PORT=4000 in .env to match, or change the registered URL later with qiforge-cli update-oracle-api-url.
The result is a plugin-runtime-shaped project:
The scaffold drops a Claude Code skill at .claude/skills/qiforge-oracle/. Open the project in Claude Code (or any agent that reads .claude/skills/) and the skill auto-loads — your AI helper now has dense, project-local references for adding plugins, adding tools, wiring env, and writing tests with createTestRuntime. Nothing to install separately.
Cloning instead of scaffolding — to study a finished plugin-based oracle, clone the boilerplate and run the example:
Then follow Step 3 onward against apps/qiforge-example/.

Step 3 — fill in .env

Open your project’s .env (my-oracle/.env from qiforge-cli new, or apps/qiforge-example/.env if you cloned the boilerplate). The CLI populated identity vars; you need to add the LLM key and any plugin vars:
Plugins whose env vars you leave blank simply don’t load — they’re skipped with a [boot] excluded: <plugin> (<env-var>) line. See Environment variables reference for the complete list.

Step 4 — install + boot

You should see something like:
The excluded plugins are normal — they need env vars you didn’t set. To enable one, fill its env vars and restart.

Step 5 — hit a public plugin endpoint

The Weather plugin exposes GET /weather/now. It’s marked auth-excluded via getAuthExcludedRoutes(), so no UCAN header needed:
You should get back JSON:
This proves: the plugin loaded, its Nest module mounted, the auth exclusion worked, and the upstream call to Open-Meteo succeeded.

Step 6 — send a chat message

For interactive chat, use the CLI’s streaming TUI:
Then type:
The agent walks this path:
  1. list_capabilities — sees weather is on-demand, not loaded yet.
  2. load_capability({ names: ['weather'] }) — gets the manifest back with whenToUse and the tool list. loadedPlugins state field now contains 'weather'.
  3. get_current_weather({ city: 'Berlin' }) — the actual tool fires.
  4. Final response — natural-language summary of the result.
Watch the server logs at the same time — you’ll see the weather middleware print model call started / model call complete (Xms) for each LLM step.

What you just verified

Where to go next

Build track

Task-by-task recipes — createOracleApp, plugin recipes, test, deploy.

Write a plugin

Recreate the Weather plugin from scratch.

createOracleApp options

Every option you can pass — config, plugins, features, hooks.

Bundled plugins

The 15 plugins shipped with the runtime.

For AI agents

Dense one-pager with every signature inlined.

Understand the model

Optional. The mental model, runtime layers, plugins vs skills.

Troubleshooting

Full coverage: Troubleshooting.