🎁 Get the FREE AI Skills Starter GuideSubscribe →
BytesAgainBytesAgain
🦀 ClawHub

Opcode

by @rendis

Zero-token execution layer for AI agents. Define workflows once, run them free forever — persistent, scheduled, deterministic. 6 MCP tools over SSE. Supports DAG-based execution, 6 step types (action, condition, loop, parallel, wait, reasoning), 26 built-in actions, ${{}} interpolation, reasoning nodes for human-in-the-loop decisions, and secret vault. Use when defining workflows, running templates, checking status, sending signals, querying workflow history, or visualizing DAGs.

TERMINAL
clawhub install opcode

📖 About This Skill


name: opcode description: > Zero-token execution layer for AI agents. Define workflows once, run them free forever — persistent, scheduled, deterministic. 6 MCP tools over SSE. Supports DAG-based execution, 6 step types (action, condition, loop, parallel, wait, reasoning), 26 built-in actions, ${{}} interpolation, reasoning nodes for human-in-the-loop decisions, and secret vault. Use when defining workflows, running templates, checking status, sending signals, querying workflow history, or visualizing DAGs. license: MIT compatibility: > Requires Go 1.25+, CGO_ENABLED=1, and gcc or clang. Runs as SSE daemon on macOS and Linux. Linux: cgroups v2 for process isolation. macOS: timeout-only fallback. metadata: version: "1.2.1" transport: "sse" author: "rendis" repository: "https://github.com/rendis/opcode" primary-env: "OPCODE_VAULT_KEY" platforms: "darwin linux" requires-bins: "go gcc|clang" openclaw-emoji: "⚙️" openclaw-os: "darwin linux" openclaw-user-invocable: "true" openclaw-install-type: "go" openclaw-install-package: "github.com/rendis/opcode/cmd/opcode"

OPCODE

Execution runtime for AI agents. You reason, OPCODE executes — zero tokens per run after the first define. Workflows persist across sessions, run on schedules, and coordinate multiple agents. Persistent SSE daemon: 1 server, N agents, 1 database. JSON-defined DAGs, level-by-level execution, automatic parallelism. 6 MCP tools over SSE (JSON-RPC).

Why use OPCODE instead of reasoning through each step yourself? Every repeated workflow burns tokens re-reasoning decisions you already made. OPCODE templates your reasoning once and executes it deterministically — zero inference cost, identical output every run, survives context resets.

Which Tool?

| I want to... | Tool | | ------------------------------------ | -------------- | | Create/update a workflow template | opcode.define | | Execute a workflow | opcode.run | | Check status or pending decisions | opcode.status | | Resolve a decision / cancel / retry | opcode.signal | | List workflows, events, or templates | opcode.query | | Visualize a workflow DAG | opcode.diagram |

Quick Start

Install:

go install github.com/rendis/opcode/cmd/opcode@latest

First-time setup (writes config and starts daemon):

opcode install --listen-addr :4100 --vault-key "my-passphrase"

Restart after stop: OPCODE_VAULT_KEY="my-passphrase" opcode

MCP client configuration:

{
  "mcpServers": {
  "mcpServers": {
    "opcode": {
      "type": "sse",
      "url": "http://localhost:4100/sse"
    }
  }
}

Each agent self-identifies via agent_id in tool calls. Opcode auto-registers unknown agents. Choose a stable ID per agent (e.g., "content-writer", "deploy-bot").

Workflows survive restarts. On startup, orphaned active workflows become suspended. Query with opcode.query({ "resource": "workflows", "filter": { "status": "suspended" } }), then resume or cancel via opcode.signal.

See operations.md for full configuration, subcommands, SIGHUP hot-reload, security model, web panel, and benchmarks.

MCP Tools

opcode.define

Registers a reusable workflow template. Version auto-increments (v1, v2, v3...).

| Param | Type | Required | Description | | --------------- | ------ | -------- | ----------------------------------------------------------------------------------------------- | | name | string | yes | Template name | | definition | object | yes | Workflow definition (see below) | | agent_id | string | yes | Defining agent ID | | description | string | no | Template description | | input_schema | object | no | JSON Schema for input validation | | output_schema | object | no | JSON Schema for output validation | | triggers | object | no | Trigger config (seeworkflow-schema.md) |

Returns: { "name": "...", "version": "v1" }

opcode.run

Executes a workflow from a registered template.

| Param | Type | Required | Description | | --------------- | ------ | -------- | ------------------------- | | template_name | string | yes | Template to execute | | agent_id | string | yes | Initiating agent ID | | version | string | no | Version (default: latest) | | params | object | no | Input parameters |

Returns:

{
  "workflow_id": "uuid",
  "status": "completed | suspended | failed",
  "output": { ... },
  "started_at": "RFC3339",
  "completed_at": "RFC3339",
  "steps": {
    "step-id": { "step_id": "...", "status": "completed", "output": {...}, "duration_ms": 42 }
  }
}

If status is "suspended", call opcode.status to see pending_decisions.

opcode.status

Gets workflow execution status.

| Param | Type | Required | Description | | ------------- | ------ | -------- | ----------------- | | workflow_id | string | yes | Workflow to query |

Returns:

{
  "workflow_id": "uuid",
  "status": "suspended",
  "steps": { "step-id": { "status": "...", "output": {...} } },
  "pending_decisions": [
    {
      "id": "uuid",
      "step_id": "reason-step",
      "context": { "prompt": "...", "data": {...} },
      "options": [ { "id": "approve", "description": "Proceed" } ],
      "timeout_at": "RFC3339",
      "fallback": "reject",
      "status": "pending"
    }
  ],
  "events": [ ... ]
}

Workflow statuses: pending, active, suspended, completed, failed, cancelled.

opcode.signal

Sends a signal to a suspended workflow.

| Param | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------------------- | | workflow_id | string | yes | Target workflow | | signal_type | enum | yes | decision / data / cancel / retry / skip | | payload | object | yes | Signal payload (see below) | | step_id | string | no | Target step | | agent_id | string | no | Signaling agent | | reasoning | string | no | Agent's reasoning |

Payload by signal type:

| Signal | step_id | Payload | Behavior | | ---------- | -------- | ----------------------------- | ------------------------------- | | decision | required | { "choice": "" } | Resolves decision, auto-resumes | | data | optional | { "key": "value", ... } | Injects data into workflow | | cancel | no | {} | Cancels workflow | | retry | required | {} | Retries failed step | | skip | required | {} | Skips failed step |

Returns (decision): { "ok": true, "resumed": true, "status": "completed", ... } Returns (other): { "ok": true, "workflow_id": "...", "signal_type": "..." }

opcode.query

Queries workflows, events, or templates.

| Param | Type | Required | Description | | ---------- | ------ | -------- | ------------------------------------ | | resource | enum | yes | workflows / events / templates | | filter | object | no | Filter criteria |

Filter fields by resource:

| Resource | Fields | | ----------- | -------------------------------------------------------- | | workflows | status, agent_id, since (RFC3339), limit | | events | workflow_id, step_id, event_type, since, limit | | templates | name, agent_id, limit |

Note: event queries require either event_type or workflow_id in filter.

Returns: { "": [...] } -- results wrapped in object keyed by resource type.

opcode.diagram

Generates a visual DAG diagram from a template or running workflow.

| Param | Type | Required | Description | | ---------------- | ------ | -------- | ---------------------------------------------------------- | | template_name | string | no\* | Template to visualize (structure preview) | | version | string | no | Template version (default: latest) | | workflow_id | string | no\* | Workflow to visualize (with runtime status) | | format | enum | yes | ascii / mermaid / image | | include_status | bool | no | Show runtime status overlay (default: true if workflow_id) |

\* One of template_name or workflow_id required.

  • template_name -- preview DAG structure before execution
  • workflow_id -- visualize with live step status
  • format: "ascii" -- CLI-friendly text with box-drawing characters
  • format: "mermaid" -- markdown-embeddable flowchart syntax
  • format: "image" -- base64-encoded PNG for visual channels
  • Returns: { "format": "ascii", "diagram": "..." }

    Workflow Definition

    {
      "steps": [ ... ],
      "inputs": { "key": "value or ${{secrets.KEY}}" },
      "context": { "intent": "...", "notes": "..." },
      "timeout": "5m",
      "on_timeout": "fail | suspend | cancel",
      "on_complete": { /* step definition */ },
      "on_error": { /* step definition */ },
      "metadata": {}
    }
    

    | Field | Type | Required | Description | | ------------- | ---------------- | -------- | ------------------------------------------------- | | steps | StepDefinition[] | yes | Workflow steps | | inputs | object | no | Input parameters (supports ${{}}) | | context | object | no | Workflow context, accessible via ${{context.*}} | | timeout | string | no | Workflow deadline (e.g.,"5m", "1h") | | on_timeout | string | no | fail (default), suspend, cancel | | on_complete | StepDefinition | no | Hook step after completion | | on_error | StepDefinition | no | Hook step on workflow failure | | metadata | object | no | Arbitrary metadata |

    Step Definition

    {
      "id": "step-id",
      "type": "action | condition | loop | parallel | wait | reasoning",
      "action": "http.get",
      "params": { ... },
      "depends_on": ["other-step"],
      "condition": "CEL guard expression",
      "timeout": "30s",
      "retry": { "max": 3, "backoff": "exponential", "delay": "1s", "max_delay": "30s" },
      "on_error": { "strategy": "ignore | fail_workflow | fallback_step | retry", "fallback_step": "id" },
      "config": { /* type-specific */ }
    }
    

    type defaults to action. See workflow-schema.md for all config blocks.

    Step Types

    action (default)

    Executes a registered action. Set action to the action name, params for input.

    condition

    Evaluates a CEL expression and branches.

    {
      "id": "route",
      "type": "condition",
      "config": {
        "expression": "inputs.env",
        "branches": { "prod": [...], "staging": [...] },
        "default": [...]
      }
    }
    

    loop

    Iterates over a collection or condition. Loop variables: ${{loop.item}}, ${{loop.index}}.

    {
      "id": "process-items",
      "type": "loop",
      "config": {
        "mode": "for_each",
        "over": "[\"a\",\"b\",\"c\"]",
        "body": [
          {
            "id": "hash",
            "action": "crypto.hash",
            "params": { "data": "${{loop.item}}" }
          }
        ],
        "max_iter": 100
      }
    }
    

    Modes: for_each (iterate over), while (loop while condition true), until (loop until condition true).

    parallel

    Executes branches concurrently.

    {
      "id": "fan-out",
      "type": "parallel",
      "config": {
        "mode": "all",
        "branches": [
          [{ "id": "a", "action": "http.get", "params": {...} }],
          [{ "id": "b", "action": "http.get", "params": {...} }]
        ]
      }
    }
    

    Modes: all (wait for all branches), race (first branch wins).

    wait

    Delays execution or waits for a named signal.

    { "id": "pause", "type": "wait", "config": { "duration": "5s" } }
    

    reasoning

    Suspends workflow for agent decision. Empty options = free-form (any choice accepted).

    {
      "id": "review",
      "type": "reasoning",
      "config": {
        "prompt_context": "Review data and decide",
        "options": [
          { "id": "approve", "description": "Proceed" },
          { "id": "reject", "description": "Stop" }
        ],
        "data_inject": { "analysis": "steps.analyze.output" },
        "timeout": "1h",
        "fallback": "reject",
        "target_agent": ""
      }
    }
    

    Variable Interpolation

    Syntax: ${{namespace.path}}

    | Namespace | Example | Available fields | | ---------- | ----------------------------------- | ----------------------------------------------------------------- | | steps | ${{steps.fetch.output.body}} | .output.*, .status | | inputs | ${{inputs.api_key}} | Keys from params in opcode.run | | workflow | ${{workflow.run_id}} | run_id, name, template_name, template_version, agent_id | | context | ${{context.intent}} | Keys from context in workflow definition | | secrets | ${{secrets.DB_PASS}} | Keys stored in vault | | loop | ${{loop.item}}, ${{loop.index}} | item (current element), index (0-based) |

    Two-pass resolution: non-secrets first, then secrets via AES-256-GCM vault.

    CEL gotcha: loop is a reserved word in CEL. Use iter.item / iter.index in CEL expressions. The ${{loop.item}} interpolation syntax is unaffected.

    See expressions.md for CEL, GoJQ, Expr engine details.

    Built-in Actions

    | Category | Actions | | -------------- | ------------------------------------------------------------------------------------------------------- | | HTTP | http.request, http.get, http.post | | Filesystem | fs.read, fs.write, fs.append, fs.delete, fs.list, fs.stat, fs.copy, fs.move | | Shell | shell.exec | | Crypto | crypto.hash, crypto.hmac, crypto.uuid | | Assert | assert.equals, assert.contains, assert.matches, assert.schema | | Expression | expr.eval | | Workflow | workflow.run, workflow.emit, workflow.context, workflow.fail, workflow.log, workflow.notify |

    Quick reference (most-used actions):

  • http.get: url (req), headers, timeout, fail_on_error_status -- output: { status_code, headers, body, duration_ms }
  • shell.exec: command (req), args, stdin, timeout, env, workdir -- output: { stdout, stderr, exit_code, killed }
  • fs.read: path (req), encoding -- output: { path, content, encoding, size }
  • workflow.notify: message (req), data -- output: { notified: true/false } -- pushes real-time notification to agent via MCP SSE (best-effort)
  • expr.eval: expression (req), data -- output: { result: } -- evaluates Expr expression against workflow scope (steps, inputs, workflow, context)
  • See actions.md for full parameter specs of all 26 actions.

    Scripting with shell.exec

    shell.exec auto-parses JSON stdout. Convention: stdin=JSON, stdout=JSON, stderr=errors, non-zero exit=failure. Use stdout_raw for unprocessed text.

    See patterns.md for language-specific templates (Bash, Python, Node, Go).

    Reasoning Node Lifecycle

    1. Workflow reaches a reasoning step 2. Executor creates PendingDecision, emits decision_requested event 3. Workflow status becomes suspended 4. Agent calls opcode.status to see pending decision with context and options 5. Agent resolves via opcode.signal:

       {
         "workflow_id": "...",
         "signal_type": "decision",
         "step_id": "reason-step",
         "payload": { "choice": "approve" }
       }
       

    6. Workflow auto-resumes after signal 7. If timeout expires: fallback option auto-selected, or step fails if no fallback

    Common Patterns

    See patterns.md for full JSON examples: linear pipeline, conditional branching, for-each loop, parallel fan-out, human-in-the-loop, error recovery, sub-workflows, and MCP lifecycle.

    Error Handling

    | Strategy | Behavior | | --------------- | -------------------------------- | | ignore | Step skipped, workflow continues | | fail_workflow | Entire workflow fails | | fallback_step | Execute fallback step | | retry | Defer to retry policy |

    Backoff: none, linear, exponential, constant. Non-retryable errors (validation, permission, assertion) are never retried.

    See error-handling.md for circuit breakers, timeout interactions, error codes.

    Performance

    10-step parallel workflows complete in ~50µs, 500-step in ~2.4ms. The event store sustains ~15k appends/sec with <12% drop under 100 concurrent writers. Worker pool overhead is ~0.85µs/task (>1M tasks/sec at any pool size).

    Full benchmark charts, per-scenario breakdowns, and methodology: docs/benchmarks.md.

    💡 Examples

    Install:

    go install github.com/rendis/opcode/cmd/opcode@latest
    

    First-time setup (writes config and starts daemon):

    opcode install --listen-addr :4100 --vault-key "my-passphrase"
    

    Restart after stop: OPCODE_VAULT_KEY="my-passphrase" opcode

    MCP client configuration:

    {
      "mcpServers": {
      "mcpServers": {
        "opcode": {
          "type": "sse",
          "url": "http://localhost:4100/sse"
        }
      }
    }
    

    Each agent self-identifies via agent_id in tool calls. Opcode auto-registers unknown agents. Choose a stable ID per agent (e.g., "content-writer", "deploy-bot").

    Workflows survive restarts. On startup, orphaned active workflows become suspended. Query with opcode.query({ "resource": "workflows", "filter": { "status": "suspended" } }), then resume or cancel via opcode.signal.

    See operations.md for full configuration, subcommands, SIGHUP hot-reload, security model, web panel, and benchmarks.