Skip to content

Claude Code Dynamic Workflows vs oc-dw: Comprehensive Gap Analysis & Rebuild Roadmap #1

@Timmy6942025

Description

@Timmy6942025

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:

  1. A script can have if conditions and for loops — a plan JSON cannot express conditional logic
  2. We can't show "here's the script that ran" because no script exists
  3. We can't let users edit the script before running because there's nothing to edit
  4. We can't resume from a script's variable state — only from the serialized WorkflowState
  5. 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)

  1. 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.

  2. 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.

  3. 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.

  4. 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)

  1. 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.

  2. 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.

  3. Build /deep-research bundled workflow — Implement web search fan-out, source cross-checking, and claim voting. Add a deep-research template to templates.ts.

  4. 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.

  5. 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)

  1. "Don't ask again" persistence — Store approved workflow hashes in a settings file. Check on every require_approval run.

  2. Token cost per phase display — Track and surface in TUI and final report.

  3. Fix hard-coded verifier fallback — Remove openai/gpt-5.1-codex fallback. Require explicit model configuration or fail loudly.

  4. Workflow library discovery — Surface saved templates as commands. Add /workflows list subcommand.

  5. Parameterizable custom commands — Allow saved workflows to accept parameters via $ARGUMENTS substitution.

  6. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions