Specialized suites: CanonWorks, Manus & nodes
Serial-fiction canon management, Manus web research, image generation, live canvas rendering, and remote IoT nodes.
Beyond core orchestration, the Operator MCP ships several purpose-built tool suites that turn Revka into a domain platform: a serial-fiction canon manager, a live web-research bridge, image generation, a real-time dashboard canvas, and a registry for remote hardware. Each is exposed as Operator MCP tools your agent can call directly from chat or wire into a workflow step. This page is the reference for all five.
All of the tools below live in the Operator MCP server, so they require the operator to be installed and running. See Operator MCP for setup and Install the Python MCP sidecars for the prerequisites.
CanonWorks: serial-fiction canon management
Section titled “CanonWorks: serial-fiction canon management”CanonWorks manages serialized fiction — characters, timelines, relationships, storylines, and foreshadow threads — as a Kumiho graph project. Once a series is initialized, you run an episode-factory workflow to draft new episodes and a state-sync workflow to keep canon consistent as the story grows. It is built primarily for Korean web-serial production, so the default language is ko-KR and the default cadence is web_serial.
Set up a series
Section titled “Set up a series”There are two paths: a one-shot programmatic init, or an interactive interview that previews the graph before committing.
canonworks_init builds the full project in a single call: it creates Kumiho spaces, canon bundles, the initial series/character/relationship/timeline items, artifacts, and graph edges, then returns the generated project_config_yaml the workflows consume.
{ "title": "Quantum Soul", "project": "quantum-soul", "story_slug": "quantum-soul", "premise": "A courier discovers her implant hosts a dead AI.", "language": "ko-KR", "cadence": "web_serial", "target_length": "6000", "characters": [ { "id": "rin", "name": "Rin", "role": "protagonist", "summary": "..." } ], "relationships": [ { "from": "rin", "to": "the-ai", "type": "hosts", "label": "..." } ]}Only title is required. Everything else (project, story_slug) defaults to a slug of the title.
For a guided setup, use the interview tools in sequence:
-
canonworks_start(seed?, answers?, project_name?)— start or continue the setup interview. It scaffolds the Kumiho project and spaces (passdefer_kumiho_scaffold: truefor a dry run), collects story-seed answers, and asks the next questions. -
canonworks_preview(session_id?, seed?, answers?)— preview the spaces, bundles, items, artifacts, and relationship edges without mutating Kumiho. -
canonworks_commit(session_id?, allow_incomplete?)— commit the draft by callingcanonworks_initunder the hood, and store the resultingproject_config_artifact_pathso later run tools don’t need internal config paths.
Run the production workflows
Section titled “Run the production workflows”With a committed project, two tools drive ongoing production. Both hide the project_config_yaml plumbing — pass the session_id (or project + story_slug) and they resolve the rest.
| Tool | Runs workflow | Key inputs |
|---|---|---|
canonworks_run_episode | canonworks-serial-episode-factory | episode_goal, target_length, must_include, avoid, continuity_context, pacing_mode, initial_episode_number |
canonworks_sync_state | canonworks-serial-canon-state-sync | apply_mode, review_focus, target_episode_number, target_episode_kref, bootstrap_mode |
These map to the builtin workflows of the same names. See Built-in workflows & orchestration patterns for the full catalog and how builtin workflows are structured.
Manus web research integration
Section titled “Manus web research integration”manus_create_task runs an ad-hoc research task on the Manus hosted web agent, which has real browser access for live research and structured data extraction. Use it mid-conversation when a question benefits from live web browsing rather than the model’s training data. It mirrors the manus: workflow step type and shares its auth precedence.
{ "prompt": "Find the three most-cited papers on graph memory published in 2025, with links.", "structured_output_schema": { "type": "object", "properties": { "papers": { "type": "array" } } }, "agent_profile": "manus-1.6", "timeout_seconds": 600, "credentials_ref": "manus:work"}| Field | Type | Default | Meaning |
|---|---|---|---|
prompt | string | (required) | The research prompt for Manus. |
structured_output_schema | object | — | JSON schema for Manus to populate; when set, the result includes structured_output. |
connectors | string[] | — | Manus connector ids to attach (e.g. google_drive). |
agent_profile | string | manus-1.6 | Manus agent profile id. |
timeout_seconds | integer | 600 | Max seconds to poll the task. |
poll_interval_seconds | integer | 5 | Seconds between poll calls. |
credentials_ref | string | — | Auth-profile id (e.g. manus:work). When unset, falls back to the MANUS_API_KEY environment variable. |
Authentication resolves in this order: the credentials_ref auth profile first, then the MANUS_API_KEY env var. The task returns task_id, task_url, final_state, the assistant message, attachments, and the optional structured_output.
Image generation (via Codex CLI)
Section titled “Image generation (via Codex CLI)”generate_image_codex generates PNG images using the OpenAI Codex CLI’s built-in image_generation tool. It can produce up to 5 images in parallel in one call (independent Codex sessions via asyncio.gather); for more, call it repeatedly in batches. Optionally it pushes a gallery frame to the Live Canvas and registers each PNG as a Kumiho artifact.
{ "prompt": "A fox in a forest, cinematic lighting", "output_path": "fox.png", "count": 3, "canvas": true, "space": "Marketing/Logos"}| Field | Type | Default | Meaning |
|---|---|---|---|
prompt | string | (required) | Description of the image to generate. |
output_path | string | (required) | Target PNG path, relative to cwd unless absolute. With count > 1 and no output_pattern, expanded as <stem>-N.<ext>. |
cwd | string | ~/.revka/workspace | Working directory for Codex. |
count | integer (1–5) | 1 | Images to generate in parallel. |
output_pattern | string | — | Filename template with a {n} placeholder, e.g. logo-{n}.png. |
input_images | string | string[] | — | Local image path(s) passed to codex exec --image as references. [IMAGE:/path] markers in the prompt are also extracted automatically. |
canvas | bool | string | false | true pushes a gallery frame to the default canvas; a string uses that canvas_id. |
register_artifact | bool | true | Create a Kumiho item + revision under <harness>/<space> and attach each PNG. |
space | string | Images | Kumiho space (relative to the harness project). Multi-segment paths like Marketing/Logos are supported. |
item_name | string | (filename stem) | Name for the Kumiho item. |
sandbox | enum | (auto) | Codex --sandbox mode: read-only, workspace-write, or danger-full-access. |
Reading the result
Section titled “Reading the result”The response includes a urls[] array of signed /workspace/... URLs the dashboard can load, and a files[] array of absolute filesystem paths. When composing your own HTML or canvas output, reference urls[] — the browser sandbox can’t read raw filesystem paths. The signed URLs are produced by the gateway’s workspace asset serving, so they work through tunnels.
See Code agents, delegation & pipelines for more on the Codex CLI integration.
Live Canvas rendering
Section titled “Live Canvas rendering”The Live Canvas pushes agent-rendered content (HTML, SVG, Markdown, or plain text) to the dashboard’s Canvas page in real time. Multiple named canvases are supported; the dashboard shows the latest frame and every WebSocket subscriber receives new frames instantly.
Operator tools
Section titled “Operator tools”| Tool | Parameters | Purpose |
|---|---|---|
render_canvas | content (required), content_type (html | svg | markdown | text, default html), canvas_id (default default) | Push a frame to a canvas. |
clear_canvas | canvas_id (default default) | Clear a canvas and its frame history. |
{ "content": "<svg viewBox='0 0 100 100'><circle cx='50' cy='50' r='40'/></svg>", "content_type": "svg", "canvas_id": "default"}Gateway endpoints and live updates
Section titled “Gateway endpoints and live updates”The same canvas system is exposed over the gateway for subscribing browsers and external callers. The dashboard subscribes over WebSocket; you can also drive a canvas from REST.
ws://host:port/ws/canvas/<canvas_id>?token=<bearer>On connect, the gateway sends the current snapshot (if any), then {"type":"connected","canvas_id":"..."}. New content arrives as {"type":"frame","canvas_id":"...","frame":{}}. A slow subscriber that falls behind the broadcast ring buffer receives {"type":"lagged","missed_frames":N}.
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/canvas | Bearer | List active canvas IDs |
GET | /api/canvas/:id | Bearer | Get the current snapshot |
GET | /api/canvas/:id/history | Bearer | Get frame history |
POST | /api/canvas/:id | Loopback: none / external: Bearer | Push a frame |
DELETE | /api/canvas/:id | Loopback: none / external: Bearer | Clear the canvas |
A POST body matches the tool shape:
{ "content_type": "html", "content": "<h1>Live status</h1>" }For the full realtime surface, see Realtime: WebSocket, SSE & Live Canvas. On the dashboard side, see Agents, teams & canvas.
Remote nodes (hardware / IoT)
Section titled “Remote nodes (hardware / IoT)”Remote nodes are external processes — phones, sensors, IoT devices, or remote machines — that connect to the gateway over WebSocket and advertise capabilities (for example camera.snap or shell.exec). Each advertised capability becomes a dynamically available agent tool, and the gateway dispatches invocations back to the originating node.
Operator tools
Section titled “Operator tools”| Tool | Parameters | Purpose |
|---|---|---|
list_nodes | (none) | List connected nodes and their capabilities. |
invoke_node | node_id (required), capability (required), args (default {}) | Invoke a capability on a node. |
Always call list_nodes first to discover what capabilities a node exposes, then invoke one:
{ "node_id": "phone-1", "capability": "camera.snap", "args": {} }Connecting a node
Section titled “Connecting a node”A node connects to the gateway’s dynamic node registry over WebSocket and registers its capabilities:
ws://host:port/ws/nodes?token=<bearer>Sub-protocol: revka.nodes.v1. The node sends a register frame; the gateway acks with registered:
{ "type": "register", "node_id": "phone-1", "capabilities": [ { "name": "camera.snap", "description": "Capture a photo from the rear camera", "parameters": { "type": "object", "properties": {} } } ]}When the agent invokes a capability, the gateway sends the node an invoke frame with a call_id, capability, and args; the node replies with a result frame (call_id, success, output, optional error). Capability parameters are a JSON Schema object, defaulting to {"type":"object","properties":{}}.
Auth and lifecycle:
- A node-specific
auth_tokenfrom config takes precedence; if no node token is configured, the gateway falls back to the standard pairing guard. node_idmust be 1–128 characters. Re-registering the samenode_idupdates the existing entry.- The registry has a configurable
max_nodescapacity. On WebSocket close, the node is automatically unregistered.
For the full node protocol and how capability names become agent tools, see Realtime: WebSocket, SSE & Live Canvas and the Hardware quickstart.