taskflow

Using taskflow on OpenCode

Register taskflow as an MCP server on OpenCode and orchestrate multi-phase workflows.

OpenCode is a natural home for taskflow: it already thinks in terms of subagents, and taskflow gives those subagents a declarative graph to run inside. On OpenCode, taskflow is exposed as a dependency-free MCP server, so the taskflow_* tools appear inside the session and each phase's subagent runs as an isolated opencode run process.

This page walks through the whole arc: register the MCP server, confirm it's live, run a flow through a tool call, and understand the permission and model-resolution model.

Install

OpenCode has no git-based plugin marketplace, so you register the MCP server directly — either with the CLI or by editing your opencode.json.

Option A: the CLI

Register the MCP server via the CLI
opencode mcp add taskflow -- npx -y -p opencode-taskflow opencode-taskflow-mcp

Option B: edit opencode.json

opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "taskflow": {
      "type": "local",
      "command": ["npx", "-y", "-p", "opencode-taskflow", "opencode-taskflow-mcp"],
      "enabled": true
    }
  },
  "skills": {
    "paths": ["./node_modules/opencode-taskflow/plugin/skills"]
  }
}

The command runs via npx (a version-pinned opencode-taskflow), so the server is fetched and launched on demand — nothing else to install globally, and the pin binds the exact code that runs.

The skills.paths entry is optional. OpenCode auto-discovers **/SKILL.md skills (including Claude Code .claude/skills), and the taskflow tools are self-describing, so the routing skill just helps OpenCode reach for them at the right time. A ready-to-copy opencode.json ships in the package's plugin/ directory.

Verify the install

Before running anything, confirm the MCP server registered cleanly:

Verify the MCP server
opencode mcp list   # taskflow should appear, enabled

If it's missing, the mcp add step didn't complete — re-run it and check for errors.

Run your first flow

On OpenCode, you don't invoke taskflow through a slash command — you invoke it through an MCP tool. The model decides when to call it, guided by the routing skill. So the most natural way to start is to just describe the work.

Just ask

Try one of these in an OpenCode session:

Describe the work in plain language
> List my saved taskflows.
> Verify this flow, then run it: {name:"review-changes", phases:[...]}
> Run the "review-changes" taskflow with dir set to src.

The skill routes the request to the right tool. If a flow is saved in the current project, the model calls taskflow_run with the saved name; if you pasted an inline definition, it passes that instead.

Call the tool directly

If you want to be explicit — useful in scripts or when you know the exact shape — the tool is taskflow_run. It accepts either a saved flow name or an inline define:

Run a saved flow via taskflow_run
{
  "name": "review-changes",
  "args": { "dir": "src" }
}
Run an inline flow via taskflow_run
{
  "define": {
    "name": "quick-review",
    "phases": [
      {
        "id": "discover",
        "type": "agent",
        "agent": "scout",
        "task": "List changed source files under src/. Output ONLY a JSON array of {path} objects.",
        "output": "json"
      },
      {
        "id": "review-each",
        "type": "map",
        "over": "{steps.discover.json}",
        "as": "file",
        "agent": "security-reviewer",
        "task": "Review {file.path} for security risks. Return one paragraph.",
        "dependsOn": ["discover"],
        "concurrency": 4
      },
      {
        "id": "summarize",
        "type": "reduce",
        "from": ["review-each"],
        "agent": "writer",
        "task": "Combine these reviews into one prioritized summary:\n{steps.review-each.output}",
        "dependsOn": ["review-each"],
        "final": true
      }
    ]
  }
}

Either form runs the same DAG. The tool returns only the final output — the intermediate transcripts from discover, review-each, and summarize stay inside the runtime and never enter your context.

Only the phase marked final: true is returned. Everything else is context-isolated by design.

Check a flow before spending tokens

Before running a DAG, you can ask OpenCode to verify it statically. This catches cycles, dangling dependsOn, unknown phase references, and malformed configs — all at zero token cost:

Verify a flow via taskflow_verify
{
  "name": "review-changes"
}

Or render the DAG as a diagram to eyeball its shape:

Compile a flow to a diagram via taskflow_compile
{
  "name": "review-changes"
}

taskflow_compile returns the DAG grouped into topological layers as a text outline, plus an inline SVG image for clients that render images.

How subagents run

Each phase's subagent runs as an isolated opencode run process — a real OpenCode session, not a pi process. The server discovers saved flows and agents from its launch cwd, so the project you start it in determines which flows are visible.

Permission mapping

OpenCode has no per-run tool-whitelist flag, but it honours a per-process config injected via the OPENCODE_CONFIG_CONTENT env var. The runner maps each phase's tool whitelist to a permission policy:

Phase toolsPermission policyWhat it means
Read-only (no write/edit/bash)Injected policy that denies bash/write/editA denied tool call is genuinely rejected (not merely un-approved). This is real enforcement, closer to a read-only OS sandbox than an advisory whitelist.
Mutating (or no whitelist)opencode run --autoAuto-approves every permission — the workspace-write analogue. Run flows you trust, ideally in a throwaway worktree (cwd: "worktree").

Mutating phases run with --auto and auto-approve every permission. Prefer a throwaway worktree (cwd: "worktree") for flows that touch the filesystem, and only run flows you trust.

Model resolution

OpenCode model ids are provider/model (e.g. anthropic/claude-sonnet-4-5). Because a valid OpenCode id contains a slash, the runner does not reuse the codex/claude "contains / ⇒ drop" rule. It drops only ids that clearly aren't OpenCode models:

  • An unresolved role placeholder ({{fast}})
  • A pi thinking suffix (…:xhigh)
  • A multi-segment openrouter path (openrouter/vendor/model, ≥ 2 slashes)

A dropped id falls back to OpenCode's configured default model.

Long-running flows

Here's the one thing to know about running taskflow on OpenCode: taskflow_run is synchronous. The tool call doesn't return until the entire DAG finishes — every phase, every subagent. For a three-phase review that's fine; for a fan-out over fifty files with a tournament at the end, it can take a while.

If a flow is genuinely huge, consider splitting it into a few smaller taskflow_run calls so each returns promptly, or run it in the background from a plain shell:

Run a flow in the background
opencode run "run the nightly-audit taskflow" &

Then inspect the run afterward with taskflow_peek:

Peek at a phase's stored output via taskflow_peek
{
  "runId": "run_2026-07-04_abc123",
  "phaseId": "summarize"
}

Omit phaseId to list every phase with its status and output size. Output is hard-truncated (default 4000 chars) so a peek never floods your context.

taskflow_peek is the one intentional exception to taskflow's context isolation. It pulls intermediate output into your conversation — use it for debugging, not as part of your normal flow.

Approvals in MCP mode

MCP-driven runs are non-interactive, so an approval phase auto-rejects (fail-open). Prefer a gate (agent review) in flows you run through the taskflow_* tools; use approval only in flows a human runs interactively.

Tool reference

Here's the full MCP surface the server exposes:

ToolPurpose
taskflow_runRun a saved flow (by name) or an inline definition (by define). Returns the final output + a runId.
taskflow_listList saved flows discoverable from the cwd, with library metadata when available.
taskflow_showShow a saved flow's definition plus its library sidecar metadata.
taskflow_saveSave a flow to the library with optional purpose, tags, and notes.
taskflow_searchSearch the library before authoring. Returns ranked reusable flows.
taskflow_verifyStatically verify a flow (cycles, refs, configs) at zero cost.
taskflow_compileRender the DAG as a text outline + inline SVG.
taskflow_peekInspect a stored phase's output for post-hoc debugging.

You rarely need to memorize these. The bundled skill tells OpenCode which tool fits the request — "verify this flow", "show me the diagram", "run it" all route correctly on their own.

Alternative: run from a repo checkout

If you'd rather not install the package, build from a checkout of this repo and point OpenCode at the built bin:

Register from a checkout
pnpm run build
opencode mcp add taskflow -- node /abs/path/to/taskflow/packages/opencode-taskflow/dist/mcp/bin.js

The server behaves identically to the npx version.

Remove

If you need to take taskflow off a machine:

Remove the taskflow MCP server
opencode mcp remove taskflow    # or delete the mcp.taskflow entry from opencode.json

Any saved flow definitions on disk are left untouched.

Next

Last updated on

Was this helpful?

Help us improve the docs or ask a question in the community.

On this page