Summary
@Blankeos, I would like to propose adding a native dynamic workflow runtime to CrabCode.
The main reference is travisliu/open-dynamic-workflow, which demonstrates useful orchestration concepts such as agent steps, pipelines, parallel execution, loops, retries, cancellation, artifacts, and resumable runs.
CrabCode is a better place for this capability than a model gateway such as Joocode because CrabCode already owns the agent loop, tool execution, permissions, subagents, sessions, cancellation, and persistence. Joocode should remain responsible for provider discovery, authentication, model routing, and protocol translation.
Motivation
Complex coding tasks increasingly require more than a single agent loop. Examples include:
- Inspect a pull request, then run security, correctness, and test reviews in parallel.
- Implement a change, run tests, ask a verifier to inspect the result, and retry until verification succeeds.
- Process multiple files concurrently with bounded concurrency.
- Pause before a destructive action and request user approval.
- Resume an interrupted workflow without rerunning successful independent steps.
- Assign different agents, models, tools, and permission policies to different stages.
CrabCode already has most of the low-level primitives required to implement this natively. A workflow engine would orchestrate those primitives rather than spawning external coding-agent CLIs.
Proposed architecture
Workflow definition
│
▼
┌─────────────────────────────┐
│ CrabCode Workflow Runtime │
│ │
│ DAG / loops / conditions │
│ agents / tools / approvals │
│ persistence / resume │
└──────────────┬──────────────┘
│ model request
▼
┌─────────────────────────────┐
│ Provider layer / Joocode │
│ model routing and auth │
└──────────────┬──────────────┘
▼
Model providers
Suggested module layout:
src/workflow/
├── mod.rs
├── definition.rs
├── parser.rs
├── validator.rs
├── graph.rs
├── expression.rs
├── engine.rs
├── scheduler.rs
├── context.rs
├── events.rs
├── persistence.rs
├── fingerprint.rs
├── approval.rs
├── report.rs
└── steps/
├── agent.rs
├── tool.rs
├── parallel.rs
├── foreach.rs
├── condition.rs
├── loop.rs
└── workflow.rs
A possible execution interface:
#[async_trait]
pub trait WorkflowStepExecutor {
async fn execute(
&self,
step: &ResolvedStep,
context: &StepContext,
cancellation: CancellationToken,
) -> Result<StepResult>;
}
The engine should reuse CrabCode's existing agent loop, tool registry, permission system, subagents, cancellation tokens, and session storage.
Proposed workflow format
For the first version, I suggest a declarative YAML format rather than executing arbitrary JavaScript inside the process.
name: review-and-fix
version: 1
inputs:
pull_request:
type: integer
steps:
- id: inspect
agent: explore
prompt: Inspect pull request {{ inputs.pull_request }}
- id: review
parallel:
max_concurrency: 3
steps:
- agent: security
- agent: correctness
- agent: tests
- id: fix
when: "{{ steps.review.output.needs_fix }}"
agent: builder
- id: verify
loop:
max_rounds: 3
until: "{{ steps.verify.output.success }}"
steps:
- tool: test
- agent: verifier
A restricted expression language can be introduced for conditions and references. More dynamic scripting could later use Starlark, Rhai, or WASM rather than treating a Node VM as a security boundary.
Initial workflow primitives
- Agent step — run a CrabCode agent with an optional model, tool set, permission policy, and step limit.
- Tool step — invoke a registered CrabCode tool directly.
- Condition — execute a step only when an expression is true.
- Parallel — execute independent steps with a concurrency limit.
- For-each — execute a pipeline for each item in a resolved collection.
- Loop — repeat bounded steps until a condition succeeds.
- Approval — suspend execution until the user approves or rejects an action.
- Child workflow — compose reusable workflows.
Events and observability
The runtime should emit structured events such as:
workflow.started
workflow.completed
workflow.failed
step.queued
step.started
step.completed
step.failed
agent.started
agent.completed
tool.started
tool.completed
approval.requested
approval.resolved
loop.iteration
These events could feed the CrabCode TUI, ACP clients, logs, and future external integrations.
Persistence and resume
I suggest using SQLite as the authoritative state store and filesystem artifacts for large outputs.
SQLite records could include:
- workflow runs and status;
- resolved nodes and dependencies;
- attempts and retries;
- approvals;
- event indexes;
- fingerprints and checkpoints.
Filesystem artifacts could include:
~/.local/share/crabcode/workflows/runs/<run-id>/
├── workflow.yaml
├── inputs.json
├── resolved.json
├── events.jsonl
├── report.json
└── artifacts/
Each successful step should have a dependency-aware fingerprint based on its definition, resolved input, prompt, model, tools, permissions, and dependency outputs. Resume should reuse unchanged successful steps while rerunning invalidated steps and their dependents.
Safety requirements
- Bounded loops and maximum workflow steps.
- Per-step timeout and retry policy.
- Hierarchical cancellation.
- Workflow and per-step concurrency limits.
- Existing CrabCode workspace and sensitive-path protections.
- Existing permission prompts for risky tools.
- No arbitrary JavaScript execution for the MVP.
- Immutable step outputs rather than unsynchronized global mutable context.
Proposed delivery phases
Phase 1: MVP
crabcode workflow validate workflow.yaml
crabcode workflow run workflow.yaml --input pull_request=123
crabcode workflow list
crabcode workflow status <run-id>
Phase 2: concurrency and control flow
Phase 3: resume and approvals
Phase 4: composition and integration
CrabCode and Joocode boundary
CrabCode should own:
- workflow execution and state;
- agents and subagents;
- tools and permissions;
- approvals;
- retries, cancellation, and resume;
- workflow events and artifacts.
Joocode should only optionally provide:
- provider/model discovery;
- authentication and protocol translation;
- a local OpenAI-compatible gateway;
- read-only workflow visibility or forwarding to CrabCode in the future.
Joocode should not become the workflow execution engine.
Relationship to the plugin proposal
This is related to #24, but it is not the same feature. A future plugin system could provide custom workflow step types, parsers, or triggers. The workflow runtime itself should remain a first-class CrabCode subsystem with stable execution, persistence, permission, and event contracts.
Open questions
- Should the initial definition format be YAML, TOML, or both?
- Should expressions use a small custom evaluator, Rhai, or Starlark?
- Should workflow runs share normal CrabCode sessions or use dedicated child sessions?
- Which workflow events should be exposed through ACP initially?
- Should scheduled workflows be part of the core runtime or a later trigger/plugin layer?
I would be interested in helping design or implement an MVP if this direction fits CrabCode's roadmap.
Summary
@Blankeos, I would like to propose adding a native dynamic workflow runtime to CrabCode.
The main reference is
travisliu/open-dynamic-workflow, which demonstrates useful orchestration concepts such as agent steps, pipelines, parallel execution, loops, retries, cancellation, artifacts, and resumable runs.CrabCode is a better place for this capability than a model gateway such as Joocode because CrabCode already owns the agent loop, tool execution, permissions, subagents, sessions, cancellation, and persistence. Joocode should remain responsible for provider discovery, authentication, model routing, and protocol translation.
Motivation
Complex coding tasks increasingly require more than a single agent loop. Examples include:
CrabCode already has most of the low-level primitives required to implement this natively. A workflow engine would orchestrate those primitives rather than spawning external coding-agent CLIs.
Proposed architecture
Suggested module layout:
A possible execution interface:
The engine should reuse CrabCode's existing agent loop, tool registry, permission system, subagents, cancellation tokens, and session storage.
Proposed workflow format
For the first version, I suggest a declarative YAML format rather than executing arbitrary JavaScript inside the process.
A restricted expression language can be introduced for conditions and references. More dynamic scripting could later use Starlark, Rhai, or WASM rather than treating a Node VM as a security boundary.
Initial workflow primitives
Events and observability
The runtime should emit structured events such as:
These events could feed the CrabCode TUI, ACP clients, logs, and future external integrations.
Persistence and resume
I suggest using SQLite as the authoritative state store and filesystem artifacts for large outputs.
SQLite records could include:
Filesystem artifacts could include:
Each successful step should have a dependency-aware fingerprint based on its definition, resolved input, prompt, model, tools, permissions, and dependency outputs. Resume should reuse unchanged successful steps while rerunning invalidated steps and their dependents.
Safety requirements
Proposed delivery phases
Phase 1: MVP
Phase 2: concurrency and control flow
Phase 3: resume and approvals
Phase 4: composition and integration
CrabCode and Joocode boundary
CrabCode should own:
Joocode should only optionally provide:
Joocode should not become the workflow execution engine.
Relationship to the plugin proposal
This is related to #24, but it is not the same feature. A future plugin system could provide custom workflow step types, parsers, or triggers. The workflow runtime itself should remain a first-class CrabCode subsystem with stable execution, persistence, permission, and event contracts.
Open questions
I would be interested in helping design or implement an MVP if this direction fits CrabCode's roadmap.