Claude Code Dynamic Workflows vs oc-dw: Comprehensive Gap Analysis & Rebuild Roadmap
Executive Summary
After a thorough comparison between Claude Code's dynamic workflows (documented at https://code.claude.com/docs/en/workflows and https://claude.com/blog/introducing-dynamic-workflows-in-claude-code) and our oc-dw implementation, the conclusion is stark: our engine (planning, verification, adversarial review, synthesis pipeline) is a solid foundation, but we're missing almost every layer that makes workflows usable in practice. The core algorithms are comparable to what Claude Code describes — the Bun port example (750K lines of Rust, 11 days, 99.8% tests passing) is the kind of thing our architecture could theoretically handle. The missing pieces are entirely in the runtime and UX layer.
This issue documents every gap found, assesses severity, and proposes a prioritized roadmap.
Reference: What Claude Code Dynamic Workflows Provide
Core Runtime Model
- JavaScript orchestration script written by Claude for each task, executed by a runtime engine completely decoupled from the LLM's context window
- Intermediate results stored in script variables, not LLM context — enabling true fan-out to 100s of agents without context overflow
- Workflows are resumable within a session — completed agents return cached results, the rest continue live
- Scripts can be read, saved, and rerun — the orchestration itself is the reusable artifact
- "View raw script" lets users inspect and edit the script before approving execution
Bundled Workflows
/deep-research: Fans out web searches across several angles, fetches and cross-checks sources, votes on each claim, returns a cited report with claims that didn't survive cross-checking filtered out
- User-saved workflows appear in
/ autocomplete alongside bundled ones
/workflows TUI
Full interactive progress view (/workflows) showing:
- Each phase with its agent count, token total, and elapsed time
- Drill into any phase → any agent → see prompt, recent tool calls, and result
- Keyboard controls: ↑↓ select phase/agent, Enter/→ drill in, Esc back out, j/k scroll within agent detail, p pause/resume, x stop selected agent or whole workflow, r restart selected running agent, s save run's script as a command
- Task panel: one-line progress summary below input box, down arrow to focus, Enter to expand
Ultracode Mode
/effort ultracode combines xhigh reasoning effort with automatic workflow orchestration
- Claude decides when a task warrants a workflow without waiting for the user to ask
- A single request can become several workflows in a row: one to understand, one to make the change, one to verify it
- Resets when a new session starts; drop back with
/effort high for routine work
Approval Flow
- Per-run prompt shows planned phases with options: Yes, run it / Yes, and don't ask again for
<name> in <path> / View raw script / No
- Ctrl+G opens script in editor; Tab lets user adjust the prompt before run starts
- Permission modes: Default (every run), Auto (first launch only, then recorded), Bypass (never prompt — for
claude -p and Agent SDK)
- Subagents always run in
acceptEdits mode and inherit the user's tool allowlist
Save as Command
- Run
/workflows, select the run, press s
- Save dialog offers two locations:
.claude/workflows/ (project-shared) or ~/.claude/workflows/ (personal, all projects)
- Saved workflows run as
/<name> in future sessions
- Project workflows take precedence over personal ones with the same name
Constraints & Behavior
| Constraint |
Value |
| Max concurrent agents |
16 (fewer on low-CPU machines) |
| Total agents per run |
1,000 |
| Mid-run user input |
Only agent permission prompts can pause |
| No direct filesystem/shell from workflow |
Script coordinates agents; agents read/write/run |
Current oc-dw Architecture
What We Have (Engine Layer — Solid Foundation)
Our implementation in src/ includes:
planner.ts: LLM-driven planning with structured JSON schema output, scout-first mode, task decomposition into phases with dependency chains
runner.ts: Phase-by-phase execution loop, task concurrency via mapLimit(), verification rounds with structured output, consensus verification (multiple models vote + critic tiebreaker), adversarial review with convergence detection
adversarial.ts: Independent reviewer agents that attempt to refute findings before they're accepted
state.ts: File-based state store with atomic writes, locking, event log, progress reports, context offloading to disk
client.ts: SdkLikeWorkflowClient wrapping the OpenCode SDK client for plugin mode
- Quality gates: Shell command execution per phase with exit code checking
progress.ts: Periodic progress reports and synthesis reports written to artifacts
approval.ts: requestApproval() function for plan-phase approval gates
skills.ts: Skill constraint system applied to tasks
templates.ts: Built-in workflow templates (survey/execute/verify patterns)
worktree.ts: Git worktree creation for isolation during large changes
scheduler.ts: Cron/interval/once scheduling for automated workflow runs
What We Have (Plugin Layer)
plugin.ts: Registers dynamic_workflow_run tool inside OpenCode sessions
install.ts: oc-dw setup installs /workflow and /ultrawork custom commands
cli.ts: Minimal setup + version CLI
What's Missing (Everything Else)
See gap analysis below.
Comprehensive Gap Analysis
🔴 CRITICAL — Blocks Practical Use
1. No Workflow Progress UI (/workflows equivalent)
Claude Code: /workflows shows all running and completed workflows. Select one to see phase list, agent counts, token totals, elapsed time. Drill into any phase → any agent → see prompt, tool calls, result. Keyboard nav (↑↓ Enter p x r s j/k Esc).
oc-dw: User sees only "Started dynamic workflow <id>. Status and artifacts are under .opencode/dynamic-workflows/runs/<id>." — a single line of text. No TUI, no drill-down, no keyboard controls.
Impact: Users have zero visibility into what's happening. They can't tell if 1 task is running or 100. They can't see which phase is active. They can't identify a hung agent. The workflow appears to silently fail or silently succeed with no intermediate feedback.
Affected files: Would need a new src/ui.ts or similar, and integration into plugin.ts via a TUI hook or command.
2. Approval Flow is Non-Functional
Claude Code: "Yes, run it" / "Yes, don't ask again for X in Y" / "View raw script" (opens in editor with Ctrl+G) / "No". Per-mode behavior (Default/Auto/Bypass). Approval dialog shows phase list and token-usage caution.
oc-dw: require_approval: true in plugin.ts calls requestApproval() which creates a session and prompts the LLM — but there's no actual user-facing approval dialog. The tool just waits synchronously (or returns immediately in background mode). No "don't ask again", no "view plan", no per-mode behavior.
Impact: require_approval doesn't actually pause for human review. The planned approval UX from the docs doesn't exist.
Affected files: src/approval.ts, src/plugin.ts
3. Save-as-Command Doesn't Work as Described
Claude Code: After a run, press s in /workflows → saves to .claude/workflows/<name>.md → runs as /<name>. Appears in / autocomplete. Project-level or personal.
oc-dw: save_workflow: true with workflow_name saves the completed state as JSON to .opencode/dynamic-workflows/workflows/<name>.json. This is a state snapshot, not a rerunnable command. There's no way to replay it — it requires re-running the planner and re-executing the whole workflow. The saved file is not a command, doesn't appear in / autocomplete, and can't be invoked as /name.
Impact: The key value proposition of workflows — repeatable orchestration — is broken. Users can't save a successful workflow pattern and rerun it on new inputs.
Affected files: src/state.ts (saveWorkflowTemplate), src/plugin.ts, src/install.ts (custom command format)
4. Workflow Resume is Untested and Likely Broken
Claude Code: Stop a run → resume with cached results for completed agents, rest run live. Works within the same session. /workflows → select → p to resume.
oc-dw: runner.run() has a workflowId path: let state = options.workflowId ? await this.store.load(options.workflowId) : await this.store.create(options). If workflowId is passed and state has a plan, it should skip re-planning. However:
- No test coverage for this path
- The
workflowId must be explicitly passed from plugin.ts — there's no mechanism for the plugin to know "this is a resume"
- Session IDs in the saved state may be stale
- The approval gate would re-fire on resume if
requireApproval is set
Impact: Trying to resume a partially-completed workflow likely fails silently or restarts from scratch.
Affected files: src/runner.ts (run() method), src/plugin.ts (background run path), src/state.ts
🟠 MAJOR — Significant Feature Gaps
5. No Orchestration Script Runtime
Claude Code: The workflow runtime executes a JavaScript script that holds loop state, branching logic, and intermediate results in its own variables — completely outside the LLM's context window. The script is a first-class artifact: readable, editable, savable. The LLM writes the script and reads the final output.
oc-dw: The "plan" is a JSON object. The runner.ts has hard-coded orchestration logic (for loop over phases, mapLimit over tasks, etc.). There's no script — the plan is data, not code. The generateOrchestrationScript() function in planner.ts exists but produces a stub that doesn't generate real runnable code.
Impact: We can't show "here's the script that ran" (no script exists). We can't let users edit the script before running (no script to edit). We can't have conditional logic, loops, or event handlers in the plan (only hard-coded runner logic). We can't scale to truly complex orchestration scenarios with dynamic branching.
Affected files: src/planner.ts (generateOrchestrationScript), src/runner.ts, would need a new src/runtime.ts
6. No Ultracode / Auto-Workflow Mode
Claude Code: /effort ultracode auto-triggers a workflow for every substantive task. Claude decides when a task warrants a workflow without being asked. A single request can become several workflows in sequence.
oc-dw: Users must explicitly invoke the dynamic_workflow_run tool or use /workflow. There's no automatic detection of complex tasks, no effort-level integration that auto-upgrades to workflow mode, no multi-workflow sequencing.
Impact: Users have to know to ask for a workflow. Complex tasks don't automatically get the orchestration they need.
Affected files: src/plugin.ts (would need effort-level detection), src/install.ts (custom command templates)
7. No Bundled /deep-research Workflow
Claude Code: /deep-research <question> fans out web searches across multiple angles, fetches and cross-checks sources, votes on claims, returns a cited report with filtered claims.
oc-dw: No web search integration. No multi-angle research fan-out. No source cross-checking. No citation system. No voting on claims. The bundled /workflow and /ultrawork commands are generic — they just invoke dynamic_workflow_run with different defaults.
Impact: The easiest on-ramp to workflows (just run /deep-research) doesn't exist.
Affected files: src/templates.ts (would need a research template), src/plugin.ts (would need a web search integration), new research-specific planning logic
8. No Per-Agent Stop/Restart Controls
Claude Code: In /workflows, press x to stop the selected agent or the whole workflow. Press r to restart the selected running agent.
oc-dw: runner.abort(workflowId) and runner.pause(workflowId) exist but:
- No per-agent stop — only whole-workflow abort
- No per-agent restart
- No way to select a specific agent from a TUI
- State doesn't track which agent is "selected"
Impact: A single hung agent can block the entire workflow with no way to stop just that agent and restart it.
Affected files: src/runner.ts, src/state.ts (would need per-agent control state), new TUI layer
9. No CPU-Adaptive Concurrency
Claude Code: "Up to 16 concurrent agents, fewer on machines with limited CPU cores."
oc-dw: concurrency: 16 hard-coded in options.ts (defaultWorkflowOptions). No runtime CPU detection.
Impact: On a machine with many cores, we're under-utilizing resources. On a machine with few cores, we may be over-saturating and causing OOM or throttling.
Affected files: src/options.ts, src/runner.ts (would need os.cpus() check)
🟡 MODERATE — Usability Gaps
10. Custom Commands Have No State Persistence Across Runs
Claude Code: Saved workflows remember their configuration and can be re-invoked with different arguments.
oc-dw: The /workflow and /ultrawork custom commands are static template files in .opencode/commands/. They always invoke dynamic_workflow_run with the same arguments structure. There's no way to save a parameterized workflow as a reusable command with custom defaults.
Impact: Users can't create custom workflow commands with project-specific defaults or parameter patterns.
Affected files: src/install.ts (custom command templates)
11. No "Don't Ask Again" Persistence
Claude Code: "Yes, and don't ask again for <name> in <path>" records consent in user settings. Future runs start without prompting.
oc-dw: No approval persistence. Every run with require_approval: true would re-request approval (if the approval UI existed).
Impact: Users can't approve a trusted workflow once and have it auto-run thereafter.
Affected files: src/approval.ts, would need a settings file (e.g., ~/.config/opencode/oc-dw-approved-workflows.json)
12. No Token Cost Display in Progress
Claude Code: /workflows shows token totals per phase and per agent.
oc-dw: state.totalTokensUsed is tracked and available in the state file, but there's no UI to display it during execution. Only appears in the final formatWorkflowResult() output.
Impact: Users have no real-time token budget visibility during the run.
Affected files: Would need new UI layer to display
13. No Workflow Library / Command Discovery
Claude Code: Saved workflows appear in / autocomplete alongside built-in commands.
oc-dw: No command discovery. Custom commands (/workflow, /ultrawork) are always available but saved workflow templates are not exposed as commands.
Impact: Users don't know what custom workflows are available.
Affected files: src/install.ts, src/state.ts (listWorkflowTemplates)
14. Background Run Returns Immediately Without Real Tracking
Claude Code: Background runs are tracked in /workflows with live status updates.
oc-dw: Background run path in plugin.ts creates the state, fires runner.run() as fire-and-forget (.catch() for errors), and immediately returns "Started dynamic workflow <id>.". There's no mechanism for the plugin to surface ongoing updates to the user beyond the error logging.
Impact: Background runs feel like fire-and-forget with no accountability.
Affected files: src/plugin.ts
15. No Workflow Script Editing Before Run
Claude Code: "View raw script" with Ctrl+G opens the script in the user's editor before they approve the run. Tab lets them adjust the prompt.
oc-dw: No script exists to view or edit. The plan is a JSON object generated by the LLM. Users can't inspect or modify the plan before execution.
Impact: Power users can't tweak the orchestration logic before running.
Affected files: Would need orchestration script generation and pre-approval review UI
🟢 MINOR — Polish Gaps
16. Session Cleanup Strategy is Binary
oc-dw: cleanUpSessions: boolean is all-or-nothing. Sessions are either always deleted (true) or never deleted (false). There's no "delete after completion" strategy that keeps sessions available for debugging during execution.
Impact: For long-running workflows, session accumulation could be high. For debugging, you want sessions preserved until the workflow completes or fails.
Affected files: src/runner.ts
17. Quality Gates are Shell-Only
oc-dw: Quality gates in runner.ts (runQualityGates) are shell commands only. There's no way to run an LLM-based quality gate or a composite gate.
Impact: Complex verification scenarios require pre-combining into a single shell command.
Affected files: src/runner.ts
18. No Progress Report Suppression
oc-dw: progressReportIntervalMs controls report frequency, but there's no way to suppress progress entirely for non-interactive runs.
Impact: CI environments get unnecessary progress report output.
Affected files: src/runner.ts, src/options.ts
19. Effort Level Naming is Confusing
Claude Code: Effort levels: low, medium, high, ultracode.
oc-dw: Effort levels: low, medium, high, ultra. No "ultracode" equivalent. The naming doesn't communicate what triggers a workflow.
Impact: Users don't know what effort level to use or what the difference is.
Affected files: src/options.ts, src/planner.ts, src/install.ts
20. No Built-In Workflow Templates Beyond Survey/Execute/Verify
Claude Code: Templates are first-class: deep-research, codebase-audit, etc.
oc-dw: templates.ts has only a few patterns (survey/execute/verify). No equivalent to deep-research, large-migration, etc.
Impact: Users starting fresh have no guidance on workflow patterns.
Affected files: src/templates.ts
21. resolveVerifierModels Has Hard-Coded Fallback
oc-dw: In runner.ts:
return ["openai/gpt-5.1-codex"]
Hard-coded fallback to a model that likely doesn't exist in most OpenCode configurations.
Impact: Consensus verification fails with confusing errors when no verifier model is configured.
Affected files: src/runner.ts
Detailed File-by-File Assessment
src/plugin.ts
- ✅ Registers
dynamic_workflow_run tool correctly
- ✅ Args schema with
.describe() descriptions
- ✅
client.app.log() structured logging
- ✅ Background run path (fire-and-forget with error logging)
- ✅ Dry-run detection via
containsDryRunHint()
- ❌ No
/workflows TUI integration
- ❌ No approval interaction (just calls
requestApproval() which is non-functional)
- ❌ No save-as-command after completion
- ❌ No
workflowId resume path from plugin
- ❌ No ultrcode detection
- ❌ No way to surface live progress updates to the user
src/runner.ts
- ✅ Multi-phase execution with dependency chains
- ✅
mapLimit() concurrency control
- ✅ Verification rounds with JSON schema
- ✅ Consensus verification with critic tiebreaker
- ✅ Adversarial review with convergence detection
- ✅ Quality gates (shell commands)
- ✅ Token accumulation per task/phase
- ✅ Context offloading for large synthesis
- ✅ Worktree creation/cleanup
- ✅ Progress report timer
- ✅
abort() and pause() methods
- ❌ No per-agent stop/restart (only whole-workflow)
- ❌ Resume path (
workflowId) is untested
- ❌ No CPU-adaptive concurrency
- ❌ No script generation (only stub
orchestrationScript from planner)
- ❌
resolveVerifierModels has hard-coded openai/gpt-5.1-codex fallback
src/planner.ts
- ✅ Structured JSON plan output with Zod schema
- ✅ Scout-first planning for complex tasks
- ✅ Task decomposition into phases with dependencies
- ✅
generateOrchestrationScript() stub exists
- ❌ Orchestration script is a stub, not real runnable code
- ❌ No equivalent to Claude Code's JS script writer
src/state.ts
- ✅ File-based store with atomic writes and locking
- ✅ Event log (
appendEvent)
- ✅ Progress reports
- ✅ Context offloading
- ✅ Workflow template saving
- ✅
list() returns all runs sorted by date
- ❌ No
workflowId metadata for tracking which runs belong to which parent workflow
- ❌ No per-agent state visibility for UI
- ❌ Templates are state snapshots, not rerunnable commands
src/client.ts
- ✅
SdkLikeWorkflowClient wraps SDK client for plugin mode
- ✅ All core methods:
createSession, initSession, prompt, shell, deleteSession, abortSession, log
- ✅
health() fallback
- ✅
providers() for model config
- ❌ No session message history retrieval (
getSessionMessages is optional in interface but not implemented)
src/approval.ts
- ❌
requestApproval() is non-functional as actual user-facing UI — it prompts an LLM session but there's no real approval dialog
- ❌ No "don't ask again" persistence
- ❌ No per-mode behavior (Default/Auto/Bypass)
src/install.ts
- ✅
/workflow and /ultrawork custom commands created correctly
- ✅
setupOpenCodePlugin() adds oc-dw to plugin array
- ❌ Custom command templates don't support parameterized workflows
- ❌ No way to save a workflow as a reusable command
- ❌ No command discovery or autocomplete
src/options.ts
- ✅ Comprehensive options with sensible defaults
- ❌
concurrency: 16 hard-coded, no CPU awareness
- ❌
effortLevel has no ultrcode equivalent
- ❌ No option to disable progress reporting entirely
src/templates.ts
- ✅
BUILT_IN_TEMPLATES with survey/execute/verify pattern
- ❌ Only 1-2 templates, no deep-research equivalent
- ❌ Templates are applied as plan overrides, not as runnable workflow scripts
Architectural Root Cause
The fundamental gap is this:
Claude Code's workflow runtime is a JavaScript interpreter. Our workflow runner is a "smart pipeline."
Claude Code's runtime executes an orchestration script — JavaScript code that can contain loops, conditionals, event handlers, and variable state. The script is decoupled from the LLM's context window. The LLM writes the script (prompted with the task), and reads the final report when the runtime finishes. All intermediate state (agent results, partial conclusions, loop counters) lives in the script's variables.
Our runner.ts is a pipeline: LLM plans → runner executes plan → runner coordinates agents → runner synthesizes. The orchestration logic is hard-coded in TypeScript (for loops, mapLimit, phase dependency checks). The "plan" is a JSON object — data, not code. There's no script to read, edit, save, or branch.
This matters because:
- A script can have
if conditions and for loops — a plan JSON cannot express conditional logic
- We can't show "here's the script that ran" because no script exists
- We can't let users edit the script before running because there's nothing to edit
- We can't resume from a script's variable state — only from the serialized
WorkflowState
- The LLM's context window fills up as more agents run because orchestration state lives in context, not in a script
The fix is not to "add more features to the runner." The fix is to generate actual JavaScript orchestration scripts and build a runtime that executes them — shifting orchestration out of the LLM's context and into a first-class code artifact.
Prioritized Rebuild Roadmap
Phase 1: Fix Critical UX (Weeks 1-2)
-
Build /workflows TUI — Show running and completed workflow runs with phase/task progress. Make it accessible as a custom command that renders a progress view. Use OpenCode's client.tui.* methods or render to a temp file.
-
Fix workflow resume — Add test coverage for workflowId resume path. Ensure sessions are properly tracked, approval gates don't re-fire, and partial state is handled correctly.
-
Implement real approval interaction — Replace requestApproval() LLM prompt with a proper approval file workflow: write the plan to a file, show the user the path, wait for them to approve/reject via file edit or a dedicated approval command.
-
Add save-as-command — After a workflow completes, save its plan as a custom command file in .opencode/commands/<name>.md with proper frontmatter. Ensure these appear in command discovery.
Phase 2: Major Feature Gaps (Weeks 3-6)
-
Generate orchestration scripts — Replace JSON plan with JavaScript module generation in planner.ts. Build a runtime in src/runtime.ts that executes scripts with loops, conditionals, and event handlers. Script state lives in the runtime, not in LLM context.
-
Add ultrcode equivalent — Detect when a user's task is complex enough to warrant a workflow. Add a custom command /auto-workflow or detect effort: ultra in the session and auto-suggest workflow mode.
-
Build /deep-research bundled workflow — Implement web search fan-out, source cross-checking, and claim voting. Add a deep-research template to templates.ts.
-
Add per-agent controls — Track per-agent status in TaskRunState. Add stopAgent() and restartAgent() to runner. Wire up to TUI with x and r keys.
-
CPU-adaptive concurrency — Detect os.cpus().length and set smarter concurrency defaults. Add as a plugin initialization option.
Phase 3: Polish & Completeness (Weeks 7-10)
-
"Don't ask again" persistence — Store approved workflow hashes in a settings file. Check on every require_approval run.
-
Token cost per phase display — Track and surface in TUI and final report.
-
Fix hard-coded verifier fallback — Remove openai/gpt-5.1-codex fallback. Require explicit model configuration or fail loudly.
-
Workflow library discovery — Surface saved templates as commands. Add /workflows list subcommand.
-
Parameterizable custom commands — Allow saved workflows to accept parameters via $ARGUMENTS substitution.
-
Better effort level UX — Rename ultra to ultracode, add clear descriptions of what triggers automatic workflow mode.
Verification Against Claude Code Feature List
| Feature |
Claude Code |
oc-dw |
Status |
| JS orchestration script |
✅ |
❌ |
Missing |
| /workflows progress TUI |
✅ |
❌ |
Missing |
| Phase/agent drill-down |
✅ |
❌ |
Missing |
| Per-agent stop/restart |
✅ |
❌ |
Missing |
| Pause/resume controls |
✅ |
❌ |
Partial (methods exist, UI missing) |
| Save as command |
✅ |
❌ |
Broken |
| Approval flow |
✅ |
❌ |
Non-functional |
| Ultracode auto-trigger |
✅ |
❌ |
Missing |
| /deep-research bundled |
✅ |
❌ |
Missing |
| Token cost display |
✅ |
❌ |
Missing |
| Context offloading |
✅ |
✅ |
Present |
| Verification rounds |
✅ |
✅ |
Present |
| Consensus verification |
✅ |
✅ |
Present |
| Adversarial review |
✅ |
✅ |
Present |
| Quality gates |
✅ |
✅ |
Present |
| Multi-phase execution |
✅ |
✅ |
Present |
| Scout-first planning |
✅ |
✅ |
Present |
| Template system |
✅ |
❌ |
Partial |
| CPU-adaptive concurrency |
✅ |
❌ |
Missing |
| "Don't ask again" |
✅ |
❌ |
Missing |
| Script editing before run |
✅ |
❌ |
Missing |
What Works Well (Keep)
- Verification and adversarial review pipeline — This is the strongest part of our implementation. The consensus mechanism (vote + critic tiebreaker) is more sophisticated than what Claude Code describes.
- File-based state with atomic writes — Solid foundation for resumability.
- Context offloading — The
contextOffloadThreshold mechanism is ahead of Claude Code's description.
- Quality gates — Shell command execution per phase is practical and powerful.
- Scout-first planning — The
scoutFirst option with structured scout findings is a good pattern.
- Plugin architecture — Being inside OpenCode as a plugin is the right model. We inherit all the SDK client infrastructure.
Related Documentation
Generated from a thorough analysis of the oc-dw codebase (src/) against the official Claude Code dynamic workflows documentation. The engine is solid; the missing pieces are entirely in the runtime and UX layer.
Claude Code Dynamic Workflows vs oc-dw: Comprehensive Gap Analysis & Rebuild Roadmap
Executive Summary
After a thorough comparison between Claude Code's dynamic workflows (documented at https://code.claude.com/docs/en/workflows and https://claude.com/blog/introducing-dynamic-workflows-in-claude-code) and our
oc-dwimplementation, the conclusion is stark: our engine (planning, verification, adversarial review, synthesis pipeline) is a solid foundation, but we're missing almost every layer that makes workflows usable in practice. The core algorithms are comparable to what Claude Code describes — the Bun port example (750K lines of Rust, 11 days, 99.8% tests passing) is the kind of thing our architecture could theoretically handle. The missing pieces are entirely in the runtime and UX layer.This issue documents every gap found, assesses severity, and proposes a prioritized roadmap.
Reference: What Claude Code Dynamic Workflows Provide
Core Runtime Model
Bundled Workflows
/deep-research: Fans out web searches across several angles, fetches and cross-checks sources, votes on each claim, returns a cited report with claims that didn't survive cross-checking filtered out/autocomplete alongside bundled ones/workflows TUI
Full interactive progress view (
/workflows) showing:Ultracode Mode
/effort ultracodecombines xhigh reasoning effort with automatic workflow orchestration/effort highfor routine workApproval Flow
<name>in<path>/ View raw script / Noclaude -pand Agent SDK)acceptEditsmode and inherit the user's tool allowlistSave as Command
/workflows, select the run, press s.claude/workflows/(project-shared) or~/.claude/workflows/(personal, all projects)/<name>in future sessionsConstraints & Behavior
Current oc-dw Architecture
What We Have (Engine Layer — Solid Foundation)
Our implementation in
src/includes:planner.ts: LLM-driven planning with structured JSON schema output, scout-first mode, task decomposition into phases with dependency chainsrunner.ts: Phase-by-phase execution loop, task concurrency viamapLimit(), verification rounds with structured output, consensus verification (multiple models vote + critic tiebreaker), adversarial review with convergence detectionadversarial.ts: Independent reviewer agents that attempt to refute findings before they're acceptedstate.ts: File-based state store with atomic writes, locking, event log, progress reports, context offloading to diskclient.ts:SdkLikeWorkflowClientwrapping the OpenCode SDK client for plugin modeprogress.ts: Periodic progress reports and synthesis reports written to artifactsapproval.ts:requestApproval()function for plan-phase approval gatesskills.ts: Skill constraint system applied to taskstemplates.ts: Built-in workflow templates (survey/execute/verify patterns)worktree.ts: Git worktree creation for isolation during large changesscheduler.ts: Cron/interval/once scheduling for automated workflow runsWhat We Have (Plugin Layer)
plugin.ts: Registersdynamic_workflow_runtool inside OpenCode sessionsinstall.ts:oc-dw setupinstalls/workflowand/ultraworkcustom commandscli.ts: Minimal setup + version CLIWhat's Missing (Everything Else)
See gap analysis below.
Comprehensive Gap Analysis
🔴 CRITICAL — Blocks Practical Use
1. No Workflow Progress UI (
/workflowsequivalent)Claude Code:
/workflowsshows all running and completed workflows. Select one to see phase list, agent counts, token totals, elapsed time. Drill into any phase → any agent → see prompt, tool calls, result. Keyboard nav (↑↓ Enter p x r s j/k Esc).oc-dw: User sees only
"Started dynamic workflow <id>. Status and artifacts are under .opencode/dynamic-workflows/runs/<id>."— a single line of text. No TUI, no drill-down, no keyboard controls.Impact: Users have zero visibility into what's happening. They can't tell if 1 task is running or 100. They can't see which phase is active. They can't identify a hung agent. The workflow appears to silently fail or silently succeed with no intermediate feedback.
Affected files: Would need a new
src/ui.tsor similar, and integration intoplugin.tsvia a TUI hook or command.2. Approval Flow is Non-Functional
Claude Code: "Yes, run it" / "Yes, don't ask again for X in Y" / "View raw script" (opens in editor with Ctrl+G) / "No". Per-mode behavior (Default/Auto/Bypass). Approval dialog shows phase list and token-usage caution.
oc-dw:
require_approval: trueinplugin.tscallsrequestApproval()which creates a session and prompts the LLM — but there's no actual user-facing approval dialog. The tool just waits synchronously (or returns immediately in background mode). No "don't ask again", no "view plan", no per-mode behavior.Impact:
require_approvaldoesn't actually pause for human review. The planned approval UX from the docs doesn't exist.Affected files:
src/approval.ts,src/plugin.ts3. Save-as-Command Doesn't Work as Described
Claude Code: After a run, press
sin/workflows→ saves to.claude/workflows/<name>.md→ runs as/<name>. Appears in/autocomplete. Project-level or personal.oc-dw:
save_workflow: truewithworkflow_namesaves the completed state as JSON to.opencode/dynamic-workflows/workflows/<name>.json. This is a state snapshot, not a rerunnable command. There's no way to replay it — it requires re-running the planner and re-executing the whole workflow. The saved file is not a command, doesn't appear in/autocomplete, and can't be invoked as/name.Impact: The key value proposition of workflows — repeatable orchestration — is broken. Users can't save a successful workflow pattern and rerun it on new inputs.
Affected files:
src/state.ts(saveWorkflowTemplate),src/plugin.ts,src/install.ts(custom command format)4. Workflow Resume is Untested and Likely Broken
Claude Code: Stop a run → resume with cached results for completed agents, rest run live. Works within the same session.
/workflows→ select → p to resume.oc-dw:
runner.run()has aworkflowIdpath:let state = options.workflowId ? await this.store.load(options.workflowId) : await this.store.create(options). IfworkflowIdis passed and state has a plan, it should skip re-planning. However:workflowIdmust be explicitly passed fromplugin.ts— there's no mechanism for the plugin to know "this is a resume"requireApprovalis setImpact: Trying to resume a partially-completed workflow likely fails silently or restarts from scratch.
Affected files:
src/runner.ts(run()method),src/plugin.ts(background run path),src/state.ts🟠 MAJOR — Significant Feature Gaps
5. No Orchestration Script Runtime
Claude Code: The workflow runtime executes a JavaScript script that holds loop state, branching logic, and intermediate results in its own variables — completely outside the LLM's context window. The script is a first-class artifact: readable, editable, savable. The LLM writes the script and reads the final output.
oc-dw: The "plan" is a JSON object. The
runner.tshas hard-coded orchestration logic (for loop over phases, mapLimit over tasks, etc.). There's no script — the plan is data, not code. ThegenerateOrchestrationScript()function inplanner.tsexists but produces a stub that doesn't generate real runnable code.Impact: We can't show "here's the script that ran" (no script exists). We can't let users edit the script before running (no script to edit). We can't have conditional logic, loops, or event handlers in the plan (only hard-coded runner logic). We can't scale to truly complex orchestration scenarios with dynamic branching.
Affected files:
src/planner.ts(generateOrchestrationScript),src/runner.ts, would need a newsrc/runtime.ts6. No Ultracode / Auto-Workflow Mode
Claude Code:
/effort ultracodeauto-triggers a workflow for every substantive task. Claude decides when a task warrants a workflow without being asked. A single request can become several workflows in sequence.oc-dw: Users must explicitly invoke the
dynamic_workflow_runtool or use/workflow. There's no automatic detection of complex tasks, no effort-level integration that auto-upgrades to workflow mode, no multi-workflow sequencing.Impact: Users have to know to ask for a workflow. Complex tasks don't automatically get the orchestration they need.
Affected files:
src/plugin.ts(would need effort-level detection),src/install.ts(custom command templates)7. No Bundled
/deep-researchWorkflowClaude Code:
/deep-research <question>fans out web searches across multiple angles, fetches and cross-checks sources, votes on claims, returns a cited report with filtered claims.oc-dw: No web search integration. No multi-angle research fan-out. No source cross-checking. No citation system. No voting on claims. The bundled
/workflowand/ultraworkcommands are generic — they just invokedynamic_workflow_runwith different defaults.Impact: The easiest on-ramp to workflows (just run
/deep-research) doesn't exist.Affected files:
src/templates.ts(would need a research template),src/plugin.ts(would need a web search integration), new research-specific planning logic8. No Per-Agent Stop/Restart Controls
Claude Code: In
/workflows, pressxto stop the selected agent or the whole workflow. Pressrto restart the selected running agent.oc-dw:
runner.abort(workflowId)andrunner.pause(workflowId)exist but:Impact: A single hung agent can block the entire workflow with no way to stop just that agent and restart it.
Affected files:
src/runner.ts,src/state.ts(would need per-agent control state), new TUI layer9. No CPU-Adaptive Concurrency
Claude Code: "Up to 16 concurrent agents, fewer on machines with limited CPU cores."
oc-dw:
concurrency: 16hard-coded inoptions.ts(defaultWorkflowOptions). No runtime CPU detection.Impact: On a machine with many cores, we're under-utilizing resources. On a machine with few cores, we may be over-saturating and causing OOM or throttling.
Affected files:
src/options.ts,src/runner.ts(would needos.cpus()check)🟡 MODERATE — Usability Gaps
10. Custom Commands Have No State Persistence Across Runs
Claude Code: Saved workflows remember their configuration and can be re-invoked with different arguments.
oc-dw: The
/workflowand/ultraworkcustom commands are static template files in.opencode/commands/. They always invokedynamic_workflow_runwith the same arguments structure. There's no way to save a parameterized workflow as a reusable command with custom defaults.Impact: Users can't create custom workflow commands with project-specific defaults or parameter patterns.
Affected files:
src/install.ts(custom command templates)11. No "Don't Ask Again" Persistence
Claude Code: "Yes, and don't ask again for
<name>in<path>" records consent in user settings. Future runs start without prompting.oc-dw: No approval persistence. Every run with
require_approval: truewould re-request approval (if the approval UI existed).Impact: Users can't approve a trusted workflow once and have it auto-run thereafter.
Affected files:
src/approval.ts, would need a settings file (e.g.,~/.config/opencode/oc-dw-approved-workflows.json)12. No Token Cost Display in Progress
Claude Code:
/workflowsshows token totals per phase and per agent.oc-dw:
state.totalTokensUsedis tracked and available in the state file, but there's no UI to display it during execution. Only appears in the finalformatWorkflowResult()output.Impact: Users have no real-time token budget visibility during the run.
Affected files: Would need new UI layer to display
13. No Workflow Library / Command Discovery
Claude Code: Saved workflows appear in
/autocomplete alongside built-in commands.oc-dw: No command discovery. Custom commands (
/workflow,/ultrawork) are always available but saved workflow templates are not exposed as commands.Impact: Users don't know what custom workflows are available.
Affected files:
src/install.ts,src/state.ts(listWorkflowTemplates)14. Background Run Returns Immediately Without Real Tracking
Claude Code: Background runs are tracked in
/workflowswith live status updates.oc-dw: Background run path in
plugin.tscreates the state, firesrunner.run()as fire-and-forget (.catch()for errors), and immediately returns"Started dynamic workflow <id>.". There's no mechanism for the plugin to surface ongoing updates to the user beyond the error logging.Impact: Background runs feel like fire-and-forget with no accountability.
Affected files:
src/plugin.ts15. No Workflow Script Editing Before Run
Claude Code: "View raw script" with Ctrl+G opens the script in the user's editor before they approve the run. Tab lets them adjust the prompt.
oc-dw: No script exists to view or edit. The plan is a JSON object generated by the LLM. Users can't inspect or modify the plan before execution.
Impact: Power users can't tweak the orchestration logic before running.
Affected files: Would need orchestration script generation and pre-approval review UI
🟢 MINOR — Polish Gaps
16. Session Cleanup Strategy is Binary
oc-dw:
cleanUpSessions: booleanis all-or-nothing. Sessions are either always deleted (true) or never deleted (false). There's no "delete after completion" strategy that keeps sessions available for debugging during execution.Impact: For long-running workflows, session accumulation could be high. For debugging, you want sessions preserved until the workflow completes or fails.
Affected files:
src/runner.ts17. Quality Gates are Shell-Only
oc-dw: Quality gates in
runner.ts(runQualityGates) are shell commands only. There's no way to run an LLM-based quality gate or a composite gate.Impact: Complex verification scenarios require pre-combining into a single shell command.
Affected files:
src/runner.ts18. No Progress Report Suppression
oc-dw:
progressReportIntervalMscontrols report frequency, but there's no way to suppress progress entirely for non-interactive runs.Impact: CI environments get unnecessary progress report output.
Affected files:
src/runner.ts,src/options.ts19. Effort Level Naming is Confusing
Claude Code: Effort levels:
low,medium,high,ultracode.oc-dw: Effort levels:
low,medium,high,ultra. No "ultracode" equivalent. The naming doesn't communicate what triggers a workflow.Impact: Users don't know what effort level to use or what the difference is.
Affected files:
src/options.ts,src/planner.ts,src/install.ts20. No Built-In Workflow Templates Beyond Survey/Execute/Verify
Claude Code: Templates are first-class:
deep-research,codebase-audit, etc.oc-dw:
templates.tshas only a few patterns (survey/execute/verify). No equivalent todeep-research,large-migration, etc.Impact: Users starting fresh have no guidance on workflow patterns.
Affected files:
src/templates.ts21.
resolveVerifierModelsHas Hard-Coded Fallbackoc-dw: In
runner.ts:Hard-coded fallback to a model that likely doesn't exist in most OpenCode configurations.
Impact: Consensus verification fails with confusing errors when no verifier model is configured.
Affected files:
src/runner.tsDetailed File-by-File Assessment
src/plugin.tsdynamic_workflow_runtool correctly.describe()descriptionsclient.app.log()structured loggingcontainsDryRunHint()/workflowsTUI integrationrequestApproval()which is non-functional)workflowIdresume path from pluginsrc/runner.tsmapLimit()concurrency controlabort()andpause()methodsworkflowId) is untestedorchestrationScriptfrom planner)resolveVerifierModelshas hard-codedopenai/gpt-5.1-codexfallbacksrc/planner.tsgenerateOrchestrationScript()stub existssrc/state.tsappendEvent)list()returns all runs sorted by dateworkflowIdmetadata for tracking which runs belong to which parent workflowsrc/client.tsSdkLikeWorkflowClientwraps SDK client for plugin modecreateSession,initSession,prompt,shell,deleteSession,abortSession,loghealth()fallbackproviders()for model configgetSessionMessagesis optional in interface but not implemented)src/approval.tsrequestApproval()is non-functional as actual user-facing UI — it prompts an LLM session but there's no real approval dialogsrc/install.ts/workflowand/ultraworkcustom commands created correctlysetupOpenCodePlugin()addsoc-dwto plugin arraysrc/options.tsconcurrency: 16hard-coded, no CPU awarenesseffortLevelhas no ultrcode equivalentsrc/templates.tsBUILT_IN_TEMPLATESwith survey/execute/verify patternArchitectural Root Cause
The fundamental gap is this:
Claude Code's runtime executes an orchestration script — JavaScript code that can contain loops, conditionals, event handlers, and variable state. The script is decoupled from the LLM's context window. The LLM writes the script (prompted with the task), and reads the final report when the runtime finishes. All intermediate state (agent results, partial conclusions, loop counters) lives in the script's variables.
Our
runner.tsis a pipeline: LLM plans → runner executes plan → runner coordinates agents → runner synthesizes. The orchestration logic is hard-coded in TypeScript (forloops,mapLimit, phase dependency checks). The "plan" is a JSON object — data, not code. There's no script to read, edit, save, or branch.This matters because:
ifconditions andforloops — a plan JSON cannot express conditional logicWorkflowStateThe fix is not to "add more features to the runner." The fix is to generate actual JavaScript orchestration scripts and build a runtime that executes them — shifting orchestration out of the LLM's context and into a first-class code artifact.
Prioritized Rebuild Roadmap
Phase 1: Fix Critical UX (Weeks 1-2)
Build
/workflowsTUI — Show running and completed workflow runs with phase/task progress. Make it accessible as a custom command that renders a progress view. Use OpenCode'sclient.tui.*methods or render to a temp file.Fix workflow resume — Add test coverage for
workflowIdresume path. Ensure sessions are properly tracked, approval gates don't re-fire, and partial state is handled correctly.Implement real approval interaction — Replace
requestApproval()LLM prompt with a proper approval file workflow: write the plan to a file, show the user the path, wait for them to approve/reject via file edit or a dedicated approval command.Add save-as-command — After a workflow completes, save its plan as a custom command file in
.opencode/commands/<name>.mdwith proper frontmatter. Ensure these appear in command discovery.Phase 2: Major Feature Gaps (Weeks 3-6)
Generate orchestration scripts — Replace JSON plan with JavaScript module generation in
planner.ts. Build a runtime insrc/runtime.tsthat executes scripts with loops, conditionals, and event handlers. Script state lives in the runtime, not in LLM context.Add ultrcode equivalent — Detect when a user's task is complex enough to warrant a workflow. Add a custom command
/auto-workflowor detecteffort: ultrain the session and auto-suggest workflow mode.Build
/deep-researchbundled workflow — Implement web search fan-out, source cross-checking, and claim voting. Add adeep-researchtemplate totemplates.ts.Add per-agent controls — Track per-agent status in
TaskRunState. AddstopAgent()andrestartAgent()to runner. Wire up to TUI withxandrkeys.CPU-adaptive concurrency — Detect
os.cpus().lengthand set smarterconcurrencydefaults. Add as a plugin initialization option.Phase 3: Polish & Completeness (Weeks 7-10)
"Don't ask again" persistence — Store approved workflow hashes in a settings file. Check on every
require_approvalrun.Token cost per phase display — Track and surface in TUI and final report.
Fix hard-coded verifier fallback — Remove
openai/gpt-5.1-codexfallback. Require explicit model configuration or fail loudly.Workflow library discovery — Surface saved templates as commands. Add
/workflows listsubcommand.Parameterizable custom commands — Allow saved workflows to accept parameters via
$ARGUMENTSsubstitution.Better effort level UX — Rename
ultratoultracode, add clear descriptions of what triggers automatic workflow mode.Verification Against Claude Code Feature List
What Works Well (Keep)
contextOffloadThresholdmechanism is ahead of Claude Code's description.scoutFirstoption with structured scout findings is a good pattern.Related Documentation
Generated from a thorough analysis of the oc-dw codebase (src/) against the official Claude Code dynamic workflows documentation. The engine is solid; the missing pieces are entirely in the runtime and UX layer.