diff --git a/README.md b/README.md
index 16c8817d..1b7394cc 100644
--- a/README.md
+++ b/README.md
@@ -65,34 +65,37 @@ Install the DevSpace CLI:
npm install -g @waishnav/devspace
```
-Then initialize and start the server:
+Then initialize DevSpace:
```bash
devspace init
-devspace serve
```
Or run it without a global install:
```bash
npx @waishnav/devspace init
-npx @waishnav/devspace serve
```
During setup, DevSpace asks for:
-- the local project folders ChatGPT is allowed to open through DevSpace
+- the local project folders DevSpace is allowed to open
- the local port, usually `7676`
-- your public HTTPS base URL from Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or
- another reverse proxy
+- whether ChatGPT or Claude will connect remotely; only remote MCP users need a public HTTPS URL
+- whether to enable subagents and Dynamic Workflows, and which available providers may run
-Use the public origin without `/mcp` during setup:
+Setup installs the `subagents` and `dynamic-workflows` skills in
+`~/.devspace/skills` when agent tooling is enabled. Coding harnesses can use the
+DevSpace CLI directly; MCP users invoke the same CLI through DevSpace's shell or
+process tools.
+
+For remote MCP use, enter the public origin without `/mcp` during setup:
```text
https://your-tunnel-host.example.com
```
-You will configure your MCP client with the public `/mcp` URL after setup.
+Then configure your MCP client with the public `/mcp` URL after setup.
When the client connects, DevSpace opens an Owner password approval page. Enter
the Owner password printed by `devspace init`. It is also stored in:
@@ -139,6 +142,7 @@ DevSpace gives ChatGPT tools to:
- use isolated Git worktrees for parallel coding sessions
- follow project instructions from `AGENTS.md` and `CLAUDE.md`
- discover local agent skills from your skill folders
+- delegate bounded work and run programmable multi-agent workflows through the DevSpace CLI
- show tool cards and optional change summaries in ChatGPT Apps-compatible hosts
## Mental Model
@@ -180,6 +184,7 @@ devspace doctor
- [Setup Guide](https://github.com/Waishnav/devspace/blob/main/docs/setup.md)
- [ChatGPT Coding Workflow](https://github.com/Waishnav/devspace/blob/main/docs/chatgpt-coding-workflow.md)
- [Configuration Reference](https://github.com/Waishnav/devspace/blob/main/docs/configuration.md)
+- [Subagents and Dynamic Workflows](https://github.com/Waishnav/devspace/blob/main/docs/dynamic-workflows.md)
- [Security Model](https://github.com/Waishnav/devspace/blob/main/docs/security.md)
- [Troubleshooting Gotchas](https://github.com/Waishnav/devspace/blob/main/docs/gotchas.md)
diff --git a/docs/chatgpt-coding-workflow.md b/docs/chatgpt-coding-workflow.md
index ad591163..93e7e418 100644
--- a/docs/chatgpt-coding-workflow.md
+++ b/docs/chatgpt-coding-workflow.md
@@ -85,18 +85,16 @@ DevSpace discovers standard Agent Skills from:
- project `.agents/skills`
- `~/.devspace/skills`
-It also includes:
+It also includes the managed `subagents` and `dynamic-workflows` skills that
+setup installs in `~/.devspace/skills` when agent tooling is enabled, plus:
-- the package-managed `subagents` skill when the Subagents capability is enabled
-- the package-managed `dynamic-workflows` skill when the Dynamic Workflows capability is enabled
- `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills`
- additional paths from `DEVSPACE_SKILL_PATHS`
-When Subagents are enabled, DevSpace discovers agent profiles
-from `~/.devspace/agents/*.md` and project `.devspace/agents/*.md`.
-`open_workspace` exposes a compact catalog with profile names, descriptions,
-providers, and optional models/effort levels so the model can choose a configured agent
-without seeing provider-specific launch details.
+When agent tooling is enabled, DevSpace discovers agent profiles from
+`~/.devspace/agents/*.md` and project `.devspace/agents/*.md`.
+`open_workspace` exposes only usable provider names and profile names with
+descriptions. Disabled or unavailable providers and their profiles are omitted.
Example profiles are packaged under `examples/agents/` for users who want
starter templates. Copy or adapt them into one of the active profile directories
@@ -113,16 +111,15 @@ Skill paths may be outside the workspace. DevSpace only permits reading:
- files under a skill directory after that skill's `SKILL.md` has been read
Set `DEVSPACE_SKILLS=0` to hide skills from workspace output. Set
-`DEVSPACE_SUBAGENTS=1` to expose the experimental subagent catalog and
-`subagents` skill. That skill can use target information already supplied by the
-host or discover it with `devspace agents targets`. `devspace agents ls` lists
-existing subagent sessions for the current workspace.
+`DEVSPACE_SUBAGENTS=1` to enable both direct subagents and Dynamic Workflows.
+The skills invoke the DevSpace CLI through `bash` or `exec_command`; DevSpace
+does not expose dedicated workflow-execution MCP tools. Models discover the
+usable execution catalog with `devspace agents targets --json`.
-Set `DEVSPACE_WORKFLOWS=1` to enable Dynamic Workflows independently. When the
-variable is omitted, Dynamic Workflows follows the effective Subagents setting,
-including persisted config and any environment override. Disabled features are
-omitted from the `open_workspace` schema and response rather than returned as
-empty capability arrays.
+`DEVSPACE_AGENT_PROVIDERS` can narrow the configured provider allowlist.
+`DEVSPACE_WORKFLOWS` remains an optional runtime override; normally workflows
+follow the agent-tooling setting. Disabled features are omitted from the
+`open_workspace` schema and response.
## Tool Names
@@ -158,16 +155,10 @@ a PTY, or send Ctrl-C. Set `tty: true` only for commands that need a terminal.
By default, `DEVSPACE_WIDGETS=full`.
-In that mode, DevSpace attaches widget UI to the exposed workspace, workflow,
-file, edit, and shell tools. The `open_workspace` dropdown presents the opened
-root, loaded skills and instructions, available agent providers/profiles, and
-currently active workflows for that workspace.
-
-Dynamic Workflow views are read-only. They refresh through app-only MCP tools
-and show observed phases, agent calls, replay state, worktree isolation, errors,
-and recent activity. When the host supports MCP Apps fullscreen display mode,
-the card offers an **Open dashboard** presentation control. It does not add
-cancel, resume, apply, or cleanup actions.
+In that mode, DevSpace attaches widget UI to the exposed workspace, file, edit,
+and shell tools. The `open_workspace` dropdown presents the opened root, loaded
+skills and instructions, usable agent provider/profile names, and a compact
+snapshot of active workflows with running, completed, and failed call counts.
The aggregate `show_changes` tool is not exposed by default.
diff --git a/docs/claude-code-dynamic-workflows.html b/docs/claude-code-dynamic-workflows.html
deleted file mode 100644
index d7fa34ac..00000000
--- a/docs/claude-code-dynamic-workflows.html
+++ /dev/null
@@ -1,1150 +0,0 @@
-
-
-
- Deterministic control flow.
- Stochastic workers. One orchestrator brain.
-
-
-
-
-
Problem
-
A single agent loop confuses what to do next with how to do the work. Fan-out, verification, and synthesis become ad-hoc tool calls that the model re-invents every turn.
-
-
-
Mechanism
-
Claude Code exposes a Workflow tool. The model authors a short plain-JS script. The harness runs that script: loops, conditionals, and fan-out are code — not free-form model decisions mid-orchestration.
-
-
-
Payoff
-
A stronger “orchestrator” model designs the graph once. Weaker/cheaper or specialized subagents execute units of work. Scale, confidence, and isolation become programmable.
-
-
-
- Key insight. Dynamic workflows are not “another agent.” They are a programmable multi-agent runtime the model can call. The script is the plan; agent() is the only way work escapes into a model.
-
Final text (or validated object) is the return value
-
-
-
-
-
-
Mental model
-
// Coordinator decides STRUCTURE
-Workflow({ script, args })
- → JS engine runs control flow
- → agent(prompt, opts) × N // workers decide CONTENT
- → script return value
-→ coordinator narrates to user
-
-
-
-
-
-
-
03 · Opt-in policy
-
When the model may call Workflow
-
-
- Workflows can spawn dozens of agents and burn large token budgets. Claude Code therefore gates the tool behind explicit user opt-in. A task that would “benefit from parallelism” is not enough.
-
-
-
-
Allowed triggers
-
-
User prompt contains the keyword ultracode (system-reminder confirms).
-
Session ultracode is on (standing opt-in for every substantive task).
-
User asks in their own words: “use a workflow”, “fan out agents”, “orchestrate with subagents”, etc.
-
A skill / slash command’s instructions tell the model to call Workflow.
-
User asks for a specific named / saved workflow.
-
-
-
-
Not enough
-
-
“This would be faster in parallel.”
-
The model silently deciding multi-agent is better.
-
Inferring opt-in from task complexity alone.
-
-
Fallback: use the single Agent tool, or describe the multi-agent plan + rough cost and ask.
-
-
-
-
-
Ultracode mode
-
When ultracode is on, opt-in is standing. The model should author and run a workflow for every substantive task. Token cost is not a constraint; the goal is the most exhaustive correct answer. Multi-phase work is often several workflows in sequence (understand → design → implement → review) so the coordinator stays in the loop between phases. Solo only for pure conversation or trivial mechanical edits.
-
-
-
- Hybrid default. Scout inline first (list files, scope the diff, discover the work-list), then call Workflow to pipeline over that list. You need the shape before the orchestration step, not before the whole task.
-
-
-
-
-
-
-
04 · Workflow tool API
-
Tool surface the model calls
-
-
Tool name: Workflow (alias RunWorkflow). Search hint: orchestrate subagents with deterministic JavaScript workflow. Runs in the background — returns immediately with a task ID; a <task-notification> arrives on completion. Live progress: /workflows.
-
-
Input fields
-
-
-
-
-
Field
-
Type
-
Role
-
-
-
-
-
script
-
string (optional, max-bounded)
-
Inline self-contained workflow script. Must start with pure-literal export const meta = {...}. Preferred first invocation — do not Write a file first.
-
-
-
name
-
string (optional)
-
Named workflow from built-ins or .claude/workflows/. Resolves to a script.
-
-
-
scriptPath
-
string (optional)
-
Path to a persisted script on disk. Every invocation writes one under the session dir and returns the path. Iterate with Write/Edit + re-invoke. Takes precedence over script / name.
-
-
-
args
-
any (optional)
-
Value exposed to the script as global args, verbatim. Pass real JSON arrays/objects — not stringified JSON (stringified lists break args.map).
-
-
-
resumeFromRunId
-
string matching ^wf_[a-z0-9-]{6,}$
-
Prior run ID. Unchanged prefix of agent() calls replays from cache; first changed/new call and after run live. Same-session only. Stop the prior run first.
-
-
-
description / title
-
ignored
-
Set display name/description in script meta, not these fields.
-
-
-
-
-
Validation: at least one of script, name, or scriptPath is required.
export const meta = {
- name: 'find-flaky-tests',
- description: 'Find flaky tests and propose fixes',
- phases: [
- { title: 'Scan', detail: 'grep test logs for retries' },
- { title: 'Fix', detail: 'one agent per flaky test', model: 'sonnet' },
- ],
- // optional: whenToUse (workflow list), model on a phase
-}
-
-// body runs in an async context — await freely
-phase('Scan')
-const flaky = awaitagent('…', { schema: FLAKY_SCHEMA })
-// …
-return { flaky }
-
-
-
-
-
meta rules
-
-
Must be the first statement.
-
Pure literal only — no variables, function calls, spreads, or template interpolation.
-
Required: name, description.
-
Optional: whenToUse, phases[] with title, detail, optional per-phase model.
-
Phase titles in meta.phases must match phase() calls exactly for UI grouping.
-
description is shown in the permission dialog.
-
-
-
-
Language & environment
-
-
Plain JavaScript only — not TypeScript. Type annotations, interfaces, generics fail to parse.
-
Standard built-ins: JSON, Math, Array, etc.
-
Forbidden for determinism:Date.now(), Math.random(), argless new Date() — they throw (would break resume).
-
No filesystem, no Node APIs, no network from the script.
-
Only escape hatch into models/tools: agent() (and nested workflow()).
-
Pass timestamps via args; stamp wall-clock after the workflow returns.
-
-
-
-
-
- Why non-determinism is banned. Resume replays the longest unchanged prefix of agent() calls by hashing prompt + opts. If the script could branch on time or random, cache identity would lie. Keep control flow pure; put entropy in agent prompts (vary by index) or in post-processing outside the script.
-
-
-
-
-
-
-
06 · Script primitives
-
Every hook the script can call
-
These are the only APIs injected into the script body. Together they form a small concurrent orchestration language.
- MCP access. Workflow subagents can reach session-connected MCP tools via ToolSearch (schemas load on demand). Interactively authenticated MCP servers may be missing in headless/cron runs.
-
-
-
-
-
-
- default multi-stage
-
pipeline()
-
-
pipeline(items: any[], stage1, stage2, ...): Promise<any[]>
-// each stage: (prevResult, originalItem, index) => Promise<any> | any
-
-
-
Semantics
-
-
Each item flows through all stages independently.
-
No barrier between stages: item A can be in stage 3 while item B is still in stage 1.
-
Wall-clock ≈ slowest single-item chain — not sum of per-stage slowest times.
-
Stage callbacks receive (prevResult, originalItem, index) so later stages can label work without stuffing identity into stage-1 returns.
-
A throwing stage drops that item to null and skips remaining stages for it.
-
-
-
-
When to use
-
Default for multi-stage work. Prefer over barrier-then-map whenever each item’s next stage does not need the full previous stage’s result set.
-
Smell test: if you wrote parallel → transform → parallel with no cross-item dependency, rewrite as pipeline with the transform inside a stage.
Starts a progress group. Subsequent agent() calls without explicit opts.phase group under this title in /workflows. Inside concurrent stages, prefer opts.phase to avoid races on the global phase state. Same string → same group box.
-
-
-
log(message)
-
Narrator line above the progress tree. Use for counts, dropped coverage, early-exit reasons — anything a silent cap would hide. “No silent caps” is a first-class quality rule.
-
-
-
-
-
-
-
- inputs & cost
-
args · budget
-
-
args: any
-// value of Workflow({ args }) — undefined if omitted
-
-budget: {
- total: number | null,
- spent(): number,
- remaining(): number // max(0, total - spent) or Infinity if no target
-}
-
-
-
args
-
-
Parameterize named workflows: research question, file list, config object.
-
Pass real JSON: args: ["a.ts", "b.ts"] — not a stringified list.
-
Only channel for non-deterministic / external inputs that must stay stable across resume (timestamps, seeds as fixed values).
-
-
-
-
budget
-
-
Turn token target from user “+500k”-style directives.
-
budget.total is null when no target was set.
-
spent() is shared across main loop + all workflows this turn.
-
Hard ceiling: further agent() calls throw once spent ≥ total.
-
Always guard loops with budget.total && — else remaining() is Infinity and you hit the 1000-agent cap.
Child agents appear under a nested group in /workflows.
-
Nesting is one level only — workflow() inside a child throws.
-
Throws on unknown name / unreadable path / child syntax error; catch to handle.
-
-
-
-
-
-
-
-
-
07 · Limits & sandbox
-
Hard bounds the engine enforces
-
-
-
-
-
-
Limit
-
Value
-
Notes
-
-
-
-
-
Concurrent agent() calls
-
min(16, cpu_cores - 2) per workflow
-
Excess queues; all items still complete.
-
-
-
Lifetime agent count
-
1000
-
Runaway-loop backstop.
-
-
-
Items per parallel/pipeline call
-
4096 max
-
More → explicit error, not silent truncate.
-
-
-
Workflow size guideline
-
user /config: small≈5, medium≈15, large≈50, unrestricted
-
Guideline, not hard engine cap (unless user configures otherwise).
-
-
-
Script determinism
-
no Date.now / Math.random / bare new Date
-
Required for resume cache identity.
-
-
-
Script I/O
-
none
-
No FS/network/Node; only agent/workflow escapes.
-
-
-
Worktree isolation
-
opt-in per agent
-
Expensive; auto-clean if unchanged.
-
-
-
-
-
-
-
-
-
-
08 · Resume & journal
-
Edit the plan without redoing finished work
-
-
- Every launch returns a runId and persists the script. After a pause, kill, or script edit: stop the prior run, then relaunch with Workflow({ scriptPath, resumeFromRunId }).
-
-
-
-
Cache hit rule
-
Longest unchanged prefix of agent() calls (same prompt + opts) returns cached results instantly. First edited/new call and everything after runs live.
-
-
-
Perfect replay
-
Same script + same args → 100% cache hit. Use this for pure post-processing edits after a completed run.
-
-
-
journal.jsonl
-
Under transcriptDir. Records each agent’s actual return value. Before diagnosing empty/weird results, read the journal — do not assume cached results are non-empty.
Distinct lenses (correctness, security, repro, perf) instead of N identical refuters. Diversity catches failure modes redundancy cannot.
-
-
-
Judge panel
-
N independent attempts from different angles (MVP-first, risk-first, user-first). Score in parallel; synthesize from winner while grafting runner-up ideas. Beats single-attempt iteration when the solution space is wide.
-
-
-
Loop-until-dry
-
Unknown-size discovery: keep finding until K consecutive rounds return nothing new. Dedup against all seen, not only confirmed — else rejected findings reappear forever.
-
-
-
Multi-modal sweep
-
Parallel agents each search a different way (by-container, by-content, by-entity, by-time). Each is blind to the others — covers angles one search cannot.
-
-
-
Completeness critic
-
Final agent asks: modality not run? claim unverified? source unread? Output becomes the next work round.
- Scale to the ask. “Find any bugs” → few finders, single-vote verify. “Thoroughly audit” → larger pool, 3–5 vote adversarial pass, synthesis stage. When unsure on research/review/audit: lean thorough; on quick checks: lean brief.
-
-
-
-
-
-
-
10 · Lifecycle & operator UX
-
How a run feels from the outside
-
-
-
Authoring. Coordinator scouts, then writes inline script (or picks name).
-
Permission. User sees meta.description (and size guideline if set).
-
Launch. Tool returns immediately with taskId, runId, scriptPath, transcriptDir.
Run several workflows in sequence across turns. The coordinator reads each result before choosing the next phase. Each workflow stays a well-scoped fan-out — not a giant forever-script.
-
-
-
-
-
-
-
-
11 · One level above agents
-
Bigger brain orchestrates smaller hands
-
-
- Classic multi-agent demos put several peers in a chat room and hope coordination emerges. Dynamic workflows invert that: coordination is a program written by a high-capability model; workers are replaceable execution units.
-
-
-
-
-
Orchestrator responsibilities
-
-
Understand user intent and constraints
-
Discover the work-list (files, bugs, APIs, modules)
-
Choose pattern (pipeline vs barrier, depth vs breadth)
-
Author the script + schemas + prompts
-
Allocate model/effort tiers per stage
-
Interpret structured returns; decide next phase
-
Talk to the human; own correctness narrative
-
-
-
-
Worker responsibilities
-
-
Execute one bounded prompt with tools
-
Return raw data or schema-validated objects
-
Stay isolated (optional worktree)
-
Do not redesign the global plan
-
May be cheaper/faster models for mechanical stages
-
May be specialized agentTypes (reviewer, explorer)
-
-
-
-
-
-
Why this is “one level above”
-
-
-
Control altitude
- The orchestrator reasons about graphs, budgets, and verification policy — not about every file read. Workers absorb token-heavy tool churn inside their own contexts.
-
-
-
Context isolation
- Each agent() gets a clean context for its unit of work. The script aggregates only return values. One agent’s rabbit hole cannot pollute another’s prompt.
-
-
-
Deterministic spine
- Loops, fan-out, early-exit, and majority votes are code. They do not “forget” to verify on a bad day. The model invents the harness once; the engine executes it faithfully.
-
-
-
-
-
- Model tiering pattern. Keep the session model strong for orchestration (authoring scripts, reading results, deciding phases). Inside the workflow, omit model for most calls (inherit), or pin effort: 'low' / smaller models for mechanical map stages and reserve high effort for adversarial judges. The orchestrator’s context stays small; total work scales with fleet size.
-
Fan out by dimension (security, correctness, tests, perf). Verify each finding adversarially. Merge only survivors. Scale vote count to thoroughness of the ask.
-
-
-
Large migrations / refactors
-
Discover call sites, pipeline each site through transform + verify with isolation: 'worktree' so parallel mutators do not clobber each other. Resume after fixing one stage’s prompt.
-
-
-
Research & multi-source synthesis
-
Multi-modal sweep (web, code, docs, git history), deep-read promising hits, completeness critic, then cited synthesis — with budget-bounded loops.
-
-
-
Design exploration
-
Judge panel: N independent designs from different angles, scored in parallel, grafted synthesis. Better than iterating one design in a single context.
-
-
-
Unknown-size bug hunts
-
Loop-until-dry finders + diverse-lens judges. Dedup against seen set. Stop when two dry rounds pass. Depth scales with budget.total.
-
-
-
Self-repair implementation loops
-
Implement → multi-reviewer parallel → repair from structured findings → verify gates. Same shape as real engineering process, encoded as a script the orchestrator can re-run with resume.
-
-
-
Heterogeneous agent fleets
-
Mix agentTypes and models: explorer for map, implementer for edit, reviewer for audit. Orchestrator stays vendor of truth; workers stay specialists.
-
-
-
Phased product delivery under ultracode
-
Standing multi-agent mode: every substantive step is a workflow. Human watches /workflows; orchestrator chains phases across turns without stuffing everything into one mega-context.
-
-
-
-
-
What it deliberately is not
-
-
Not a durable multi-day job system with external supervisors (that is a different control plane).
-
Not free-form multi-agent chat; workers do not negotiate plan changes with each other.
-
Not automatic: user must opt in (or enable ultracode).
-
Not a replacement for single-agent work on small tasks — overhead is real.
-
-
-
-
-
-
-
-
13 · Cheatsheet
-
Quick reference
-
-
-
// Tool
-Workflow({ script | name | scriptPath, args?, resumeFromRunId? })
-
-// Script header (pure literal)
-export const meta = { name, description, phases? }
-
-// Primitives
-agent(prompt, { label, phase, schema, model, effort, isolation, agentType })
-pipeline(items, stage1, stage2, …) // no barrier — default
-parallel([ () => …, … ]) // barrier — rare
-phase(title)
-log(message)
-args // Workflow args, verbatim
-budget.{ total, spent(), remaining() } // hard token ceiling
-workflow(name | { scriptPath }, args?) // one-level nest
-
-// Rules of thumb
-// 1. Default to pipeline; barrier only for cross-item merge.
-// 2. Always .filter(Boolean) on parallel/agent results.
-// 3. Prefer schema for structured returns.
-// 4. Guard budget loops with budget.total && …
-// 5. No Date.now / Math.random in scripts.
-// 6. isolation:'worktree' only for parallel mutators.
-// 7. log() anything a silent cap would hide.
-// 8. Hybrid: scout → Workflow → synthesize → maybe next phase.
script · name · scriptPath · args · resumeFromRunId
-
-
-
Design goal
-
Altitude
-
Strong model plans; many workers execute; engine enforces the graph
-
-
-
-
- Source of truth for this document: Claude Code binary tool description for the Workflow tool (v2.1.x family), observed script examples under session workflows/scripts/, and the runtime rules encoded in the tool prompt (opt-in, ultracode, resume, budget, concurrency). This is a model-facing API reference, not Anthropic product documentation.
-
-
-
-
-
-
-
diff --git a/docs/configuration.md b/docs/configuration.md
index a7b20b8d..bc5277d0 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -83,17 +83,18 @@ sessions.
| Value | Behavior |
| --- | --- |
-| `full` | Default. Widget UI is attached to exposed workspace, workflow, file, edit, and shell tools, including read-only live workflow dashboards. |
+| `full` | Default. Widget UI is attached to exposed workspace, file, edit, and shell tools. The workspace card includes a compact active-workflow summary. |
| `changes` | Enables the aggregate `show_changes` tool and attaches widget UI to `open_workspace` and `show_changes`. |
| `off` | Disables widget UI. |
-## Skills
+## Agent Tooling And Skills
| Variable | Purpose |
| --- | --- |
| `DEVSPACE_SKILLS` | Set to `0` to hide skills. Enabled by default. |
-| `DEVSPACE_SUBAGENTS` | Set to `1` to expose configured agent profiles as Subagents. Experimental and disabled by default. |
-| `DEVSPACE_WORKFLOWS` | Experimental Dynamic Workflows gate. When unset, it follows the effective Subagents setting, including persisted config and any environment override. |
+| `DEVSPACE_SUBAGENTS` | Enables direct subagents and, by default, Dynamic Workflows. |
+| `DEVSPACE_WORKFLOWS` | Optional runtime override for the workflow CLI. When unset, it follows `DEVSPACE_SUBAGENTS`. |
+| `DEVSPACE_AGENT_PROVIDERS` | Optional comma-separated provider allowlist: `codex`, `claude`, `opencode`, `pi`, `cursor`, or `copilot`. |
| `DEVSPACE_AGENT_DIR` | Defaults to `~/.codex`; its `skills` child is loaded for compatibility. |
| `DEVSPACE_SKILL_PATHS` | Optional comma-separated additional skill directories. |
@@ -105,33 +106,31 @@ DevSpace discovers standard Agent Skills from:
It also includes:
-- the package-managed `subagents` skill when the Subagents capability is enabled
-- the package-managed `dynamic-workflows` skill when the Dynamic Workflows capability is enabled
+- managed `subagents` and `dynamic-workflows` skills installed by setup in `~/.devspace/skills`
- `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills`
- additional paths from `DEVSPACE_SKILL_PATHS`
-User and project skills with the same name take precedence over bundled skills.
-DevSpace does not copy bundled skills into `~/.devspace/skills` during setup.
+User and project skills with the same name take precedence. Setup updates only
+copies marked as DevSpace-managed and preserves unmarked, user-owned skill
+directories.
-When Subagents are enabled, DevSpace discovers agent profiles
-from:
+When agent tooling is enabled, DevSpace discovers agent profiles from:
- `~/.devspace/agents/*.md`
- project `.devspace/agents/*.md`
-`open_workspace` returns a compact catalog containing profile names,
-descriptions, providers, and optional models/effort levels so the host model can choose an
-agent without reading provider-specific launch details. `devspace agents ls`
-lists existing subagent sessions for the current workspace, scoped by the
-workspace environment injected into shell commands. The `subagents`
-skill teaches the model to discover targets with `devspace agents targets`,
-then use the minimal `devspace agents run`, `devspace agents show`, and
-`devspace agents ls` workflow.
-
-Provider availability is detected at runtime. DevSpace does not persist probe
-timestamps, availability snapshots, or an experimental provider enable-list in
-`config.json`. Final provider policy and onboarding are deferred until the
-Subagents and Dynamic Workflows features are finalized.
+`open_workspace` returns only usable provider names and profile names with
+descriptions. `devspace agents ls` lists existing subagent sessions for the
+current workspace, scoped by the workspace environment injected into shell
+commands. The `subagents` skill teaches the model to discover targets with
+`devspace agents targets`, then use the minimal `devspace agents run`,
+`devspace agents show`, and `devspace agents ls` workflow.
+
+Provider availability is detected at runtime. Setup persists the selected
+provider names in `config.json`; unavailable and unselected providers and their
+profiles are omitted from model-facing results. `devspace agents targets --json`
+shows the complete usable CLI target catalog when a model needs provider,
+model, or effort defaults for execution.
Starter profile templates are available under `examples/agents/`. Copy or adapt
them into one of the active profile directories before use.
diff --git a/docs/dynamic-workflow/claude/README.md b/docs/dynamic-workflow/claude/README.md
deleted file mode 100644
index b9ddb350..00000000
--- a/docs/dynamic-workflow/claude/README.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# Claude Code Dynamic Workflows
-
-In-depth reference for Claude Code’s **dynamic workflow** system: the model-facing `Workflow` tool, the JavaScript script contract, every primitive injected into the script, resume/budget semantics, quality patterns, and how this enables a stronger model to orchestrate subagents one level above ordinary tool use.
-
-| Document | Contents |
-|---|---|
-| [Architecture](./architecture.md) | Three layers, control flow vs worker content, mental model |
-| [Opt-in & Ultracode](./opt-in.md) | When the model may call Workflow; standing multi-agent mode |
-| [Workflow tool API](./workflow-tool.md) | Tool inputs, return envelope, launch/iterate/named workflows |
-| [Script contract](./script-contract.md) | `export const meta`, language rules, determinism bans |
-| [Primitives overview](./primitives.md) | Map of all script hooks |
-| [agent()](./agent.md) | Spawn API, schema, model/effort, worktree, agentType |
-| [pipeline() & parallel()](./concurrency.md) | No-barrier default vs barrier; when each is correct |
-| [phase, log, args, budget, workflow()](./control-and-io.md) | Progress UX, parameterization, token ceiling, nesting |
-| [Limits & sandbox](./limits.md) | Concurrency caps, agent caps, script isolation |
-| [Resume & journal](./resume.md) | `resumeFromRunId`, cache identity, `journal.jsonl` |
-| [Quality patterns](./patterns.md) | Adversarial verify, judge panel, loop-until-dry, … |
-| [Lifecycle & UX](./lifecycle.md) | Permission, `/workflows`, notifications, multi-phase |
-| [One level above](./orchestration.md) | Bigger brain orchestrates smaller hands |
-| [Use cases](./usecases.md) | Review fleets, migrations, research, self-repair |
-| [Cheatsheet](./cheatsheet.md) | One-page API card |
-
-Related: standalone HTML overview at [`docs/claude-code-dynamic-workflows.html`](../../claude-code-dynamic-workflows.html).
-
----
-
-## One-sentence thesis
-
-**Deterministic control flow + stochastic workers + one orchestrator brain.**
-
-A single agent loop confuses *what to do next* with *how to do the work*. Dynamic workflows split them: the orchestrator model authors a short plain-JS script; the harness runs loops, conditionals, and fan-out as **code**; only `agent()` escapes into a model with tools.
-
-## Why it exists
-
-| Without workflows | With workflows |
-|---|---|
-| Fan-out is ad-hoc tool spam each turn | Fan-out is `parallel` / `pipeline` in a script |
-| Verification is optional and forgettable | Verification is a stage in the graph |
-| One context holds plan + all tool churn | Workers isolate tool churn; script aggregates returns |
-| Scale = longer single conversation | Scale = fleet size × stages under budget |
-
-## Scope of this doc set
-
-- **In scope:** model-facing API as exposed by Claude Code ~2.1.x (`Workflow` / `RunWorkflow` tool, script primitives, opt-in, resume, budget, patterns).
-- **Out of scope:** Anthropic product marketing, undocumented internal harness code, DevSpace’s separate durable workflow engine (see feature branches / other docs if present).
-
-Source basis: Claude Code Workflow tool description, session `workflows/scripts/*.js` examples, and engine rules encoded in the tool prompt (opt-in, ultracode, resume, concurrency).
diff --git a/docs/dynamic-workflow/claude/agent.md b/docs/dynamic-workflow/claude/agent.md
deleted file mode 100644
index 40fe3f97..00000000
--- a/docs/dynamic-workflow/claude/agent.md
+++ /dev/null
@@ -1,205 +0,0 @@
-# `agent()`
-
-The only primitive that spends model/tool budget on real work. Everything else in the script is control flow, UX, or nesting.
-
-## Signature
-
-```ts
-agent(
- prompt: string,
- opts?: {
- label?: string
- phase?: string
- schema?: object // JSON Schema
- model?: string // e.g. session model ids / 'sonnet' | 'opus' | 'haiku'
- effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max'
- isolation?: 'worktree'
- agentType?: string // registry name: 'general-purpose', 'code-reviewer', 'claude', …
- }
-): Promise
-```
-
-## Return value
-
-| Mode | Resolves to |
-|---|---|
-| No `schema` | Final assistant text (`string`) |
-| With `schema` | **Validated object** matching the JSON Schema (StructuredOutput tool; model retries on mismatch) |
-| User skip / terminal API death after retries | `null` |
-
-Always treat results as possibly null when fan-out is large:
-
-```js
-const rows = (await parallel(tasks)).filter(Boolean)
-```
-
-## Semantics
-
-1. Spawns a **subagent** with its own tool loop (Read, Bash, Edit, …).
-2. Subagents are instructed that their **final text/object is the return value** to the coordinator script — not a user-facing message.
-3. Prompt should be **self-contained**: workers do not inherit the full main-session transcript.
-4. Session-connected **MCP tools** are reachable via ToolSearch (on-demand schemas). Interactively authenticated MCP may be missing in headless/cron.
-5. Errors in the agent path surface as `null` for that call in combinators that swallow rejections; check journals if results look empty ([resume](./resume.md)).
-
-## Options
-
-### `label`
-
-Short string for `/workflows` progress UI (e.g. `review:security`, `verify:src/auth.ts`). Does not affect model behavior.
-
-### `phase`
-
-Explicit progress group assignment. **Prefer this inside `pipeline` / `parallel` stages** to avoid races on the global `phase()` state. Same string → same group box. Should match titles in `meta.phases` when you want tidy UI.
-
-### `schema`
-
-JSON Schema object. Forces structured output:
-
-- Validation at the tool-call layer.
-- `agent()` returns the object — no `JSON.parse` of prose.
-- Composes with `agentType` (StructuredOutput instruction is appended to that agent’s system prompt).
-
-Example:
-
-```js
-const FINDINGS = {
- type: 'object',
- properties: {
- findings: {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- file: { type: 'string' },
- line: { type: 'integer' },
- issue: { type: 'string' },
- severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },
- },
- required: ['file', 'line', 'issue', 'severity'],
- additionalProperties: false,
- },
- },
- summary: { type: 'string' },
- },
- required: ['findings', 'summary'],
- additionalProperties: false,
-}
-
-const result = await agent(
- 'Review auth changes for session fixation. Read-only. Cite file:line.',
- {
- label: 'review:auth',
- phase: 'Review',
- schema: FINDINGS,
- effort: 'medium',
- }
-)
-// result.findings is already shaped
-```
-
-### `model`
-
-Override the model for this call.
-
-- **Default: omit** — inherit the main-loop / session model (almost always correct).
-- Set only when you are confident a different tier fits (e.g. small model for mechanical map, large for hard judge).
-- When unsure, omit.
-
-### `effort`
-
-Reasoning effort for this call: `'low' | 'medium' | 'high' | 'xhigh' | 'max'`.
-
-- Omit → inherit session effort.
-- Use `'low'` for cheap mechanical stages (enumerate files, simple extract).
-- Reserve higher tiers for hard verify / judge / design stages.
-
-### `isolation: 'worktree'`
-
-Runs the agent in a **fresh git worktree**.
-
-| Property | Detail |
-|---|---|
-| Cost | Expensive (~200–500ms setup + disk) per agent |
-| When | **Only** when agents **mutate files in parallel** and would otherwise conflict |
-| Cleanup | Auto-removed if unchanged |
-| When not | Read-only review, single writer, sequential pipeline of mutators on one tree |
-
-### `agentType`
-
-Custom subagent from the **same registry as the Agent tool** (e.g. `general-purpose`, `code-reviewer`, `Explore`, project-defined types, or `claude` where configured).
-
-- Overrides the default workflow subagent personality/tools policy for that call.
-- Composes with `schema`.
-
-## Prompting workers well
-
-Workers start with **only** the prompt you pass (+ profile/system for `agentType`). Patterns:
-
-**Implementation**
-
-```text
-Goal: …
-Context: …
-Relevant files: …
-Acceptance criteria:
-- …
-Rules:
-- Keep changes focused
-- Do not unrelated-refactor
-- Report blockers clearly
-```
-
-**Read-only investigation**
-
-```text
-Question: …
-Scope: …
-Rules:
-- Do not modify files
-- Cite paths and symbols
-- Separate facts from guesses
-```
-
-**Structured judge / refuter**
-
-```text
-Try to REFUTE:
-Default to refuted=true if uncertain.
-Return only via the schema fields.
-```
-
-Pass prior stage data by **embedding it in the prompt** (stringified structured JSON), not by shared mutable state — scripts have no shared worker memory beyond what you thread through returns.
-
-## Cost & altitude tips
-
-| Stage kind | Typical opts |
-|---|---|
-| Enumerate / map / extract | `effort: 'low'`, maybe smaller `model` |
-| Implement / edit | inherit model; medium effort; `isolation: 'worktree'` if parallel |
-| Review dimension | schema + medium effort |
-| Adversarial judge | higher effort; schema; independent prompts |
-| Final verify gates | low/medium; focused prompt |
-
-The orchestrator stays high-altitude by keeping **structure** in the script and **content** in workers. See [orchestration](./orchestration.md).
-
-## Null and failure hygiene
-
-```js
-const reviews = await parallel([
- () => agent(p1, { schema: FINDINGS }),
- () => agent(p2, { schema: FINDINGS }),
- () => agent(p3, { schema: FINDINGS }),
-]).then(xs => xs.filter(Boolean))
-
-if (!reviews.length) {
- log('all reviewers failed or were skipped')
- return { confirmed: [], error: 'no_reviews' }
-}
-```
-
-Before claiming “workflow returned empty,” read `transcriptDir/journal.jsonl` — cached or failed agents may explain it ([resume](./resume.md)).
-
-## Next
-
-- [pipeline & parallel](./concurrency.md)
-- [Patterns](./patterns.md)
diff --git a/docs/dynamic-workflow/claude/architecture.md b/docs/dynamic-workflow/claude/architecture.md
deleted file mode 100644
index 180e2fb6..00000000
--- a/docs/dynamic-workflow/claude/architecture.md
+++ /dev/null
@@ -1,101 +0,0 @@
-# Architecture
-
-## Three layers
-
-```
-User intent
- │
- ▼
-┌──────────────────────────────────────────┐
-│ 1. Coordinator (main session model) │
-│ · talks to user · scouts work-list │
-│ · authors / selects script │
-│ · calls Workflow({ script, args }) │
-│ · synthesizes return value for user │
-└───────────────────┬──────────────────────┘
- │ Workflow tool (async)
- ▼
-┌──────────────────────────────────────────┐
-│ 2. Workflow engine (JS runtime) │
-│ · parses export const meta │
-│ · runs script in async context │
-│ · hosts agent/pipeline/parallel/… │
-│ · enforces concurrency & agent caps │
-│ · journals each agent() for resume │
-└───────────────────┬──────────────────────┘
- │ agent() × N
- ┌───────────┼───────────┐
- ▼ ▼ ▼
-┌────────────┐ ┌────────────┐ ┌────────────┐
-│ Subagent A │ │ Subagent B │ │ Subagent C │
-│ own tools │ │ own tools │ │ own tools │
-│ optional │ │ schema / │ │ worktree / │
-│ return │ │ model / │ │ agentType │
-│ text|obj │ │ effort │ │ │
-└────────────┘ └────────────┘ └────────────┘
-```
-
-### 1. Coordinator (main loop)
-
-- Owns the conversation with the human.
-- Scouts the repo / discovers the work-list *before* orchestration when possible (hybrid default).
-- Decides whether Workflow is allowed ([opt-in](./opt-in.md)).
-- Authors or selects the script and `args`.
-- Receives the script’s return value after completion and narrates / chains the next phase.
-
-The coordinator is the **only** place that should redesign the global plan. Workers execute units; they do not renegotiate the graph with each other.
-
-### 2. Workflow engine
-
-- Not another chat peer. It is a **small concurrent orchestration runtime**.
-- Script language: plain JavaScript (not TypeScript).
-- Injected APIs only: see [primitives](./primitives.md).
-- Progress UI: `/workflows` groups agents by `phase` / `label`.
-- Persistence: script path under session directory, `runId`, transcripts, `journal.jsonl`.
-
-### 3. Subagents
-
-- Full tool loops of their own (Read, Bash, Edit, MCP via ToolSearch, …).
-- Final text **is** the return value (or a schema-validated object) — not a user-facing essay unless the prompt asks for one.
-- Optional isolation (`isolation: 'worktree'`), model, effort, and `agentType` overrides per call.
-
-## Mental model
-
-```js
-// Coordinator decides STRUCTURE
-Workflow({ script, args })
- → JS engine runs control flow
- → agent(prompt, opts) × N // workers decide CONTENT
- → script return value
-→ coordinator narrates to user
-```
-
-| Concern | Who owns it |
-|---|---|
-| User intent, product judgment | Coordinator |
-| Graph shape (fan-out, verify, merge) | Script (authored by coordinator) |
-| Tool use, file reads, edits | Subagents |
-| Concurrency caps, resume cache, budget hard stop | Engine |
-| Permission to multi-agent at all | User (opt-in / ultracode) |
-
-## Hybrid default
-
-You do **not** need the full orchestration shape before starting the *task*. You need it before the *orchestration step*:
-
-1. Scout inline (list files, scope diff, find call sites).
-2. Build the work-list in the coordinator context.
-3. Call `Workflow` to pipeline over that list.
-4. Read the result; optionally chain another workflow for the next phase.
-
-For larger product work, prefer **several well-scoped workflows across turns** over one forever-script.
-
-## What is not a layer
-
-- Workers do not form a free-form multi-agent chat room.
-- The script has no filesystem or network — it cannot “just run shell.” Escape is only `agent()` / nested `workflow()`.
-- The Workflow tool returns **immediately** (async launch). Completion arrives via task notification; live progress is `/workflows`.
-
-## Next
-
-- [Opt-in & Ultracode](./opt-in.md)
-- [Workflow tool API](./workflow-tool.md)
diff --git a/docs/dynamic-workflow/claude/cheatsheet.md b/docs/dynamic-workflow/claude/cheatsheet.md
deleted file mode 100644
index 7604ac57..00000000
--- a/docs/dynamic-workflow/claude/cheatsheet.md
+++ /dev/null
@@ -1,154 +0,0 @@
-# Cheatsheet
-
-One-page API card. Details in the linked docs.
-
-## Tool
-
-```js
-Workflow({
- script?, // inline JS; must start with pure-literal meta
- name?, // built-in or .claude/workflows/
- scriptPath?, // persisted path; wins over script/name
- args?, // verbatim → global args (real JSON, not stringified)
- resumeFromRunId?, // ^wf_[a-z0-9-]{6,}$ stop prior run first
-})
-// need: script | name | scriptPath
-// returns async launch: taskId, runId, scriptPath, transcriptDir, …
-```
-
-[workflow-tool.md](./workflow-tool.md) · [opt-in.md](./opt-in.md)
-
-## Script header
-
-```js
-export const meta = {
- name: '…', // required, pure literal
- description: '…', // required — permission dialog
- phases: [ // optional
- { title: 'Scan', detail: '…', model: 'sonnet' },
- ],
- // whenToUse?: '…'
-}
-// plain JS only — no TS types
-// no Date.now / Math.random / bare new Date
-```
-
-[script-contract.md](./script-contract.md)
-
-## Primitives
-
-```ts
-agent(prompt, {
- label?, phase?, schema?, model?, effort?,
- isolation?: 'worktree', agentType?,
-}): Promise
-
-pipeline(items, stage1, stage2, …): Promise
-// stage(prev, originalItem, index) — NO barrier between stages
-
-parallel(thunks: Array<() => Promise>): Promise
-// BARRIER; slots null on error; never rejects
-
-phase(title: string): void
-log(message: string): void
-
-args: any
-budget: { total: number|null, spent(): number, remaining(): number }
-
-workflow(name | { scriptPath }, args?): Promise
-// nest depth 1 only
-```
-
-[primitives.md](./primitives.md) · [agent.md](./agent.md) · [concurrency.md](./concurrency.md) · [control-and-io.md](./control-and-io.md)
-
-## Rules of thumb
-
-1. Default multi-stage → **`pipeline`**; barrier only for cross-item merge.
-2. Always **`.filter(Boolean)`** on parallel / nullable agent results.
-3. Prefer **`schema`** for structured handoffs.
-4. Guard budget loops: **`budget.total && budget.remaining() > …`**.
-5. No entropy in scripts (resume safety).
-6. **`isolation: 'worktree'`** only for parallel mutators.
-7. **`log()`** anything a silent cap would hide.
-8. Hybrid: scout → Workflow → synthesize → maybe next phase.
-9. Omit **`model`** unless tier fit is clear.
-10. Dedup open-ended hunts against **`seen`**, not only confirmed.
-
-## Caps (engine)
-
-| Cap | Value |
-|---|---|
-| Concurrent agents | `min(16, cores-2)` / workflow (queue rest) |
-| Lifetime agents | 1000 / run |
-| Items / parallel|pipeline | 4096 |
-| Nested workflow | depth 1 |
-| Budget | hard throw when spent ≥ total |
-
-[limits.md](./limits.md)
-
-## Resume
-
-```js
-// stop prior run, then:
-Workflow({
- scriptPath,
- resumeFromRunId: runId,
- args: sameArgs,
-})
-// longest unchanged agent() prefix → cache
-// read transcriptDir/journal.jsonl if results look wrong
-```
-
-[resume.md](./resume.md)
-
-## Pattern stubs
-
-```js
-// adversarial verify
-const votes = await parallel(Array.from({ length: 3 }, () => () =>
- agent(`Refute: ${claim}. Default refuted=true if uncertain.`, { schema: V })
-))
-const ok = votes.filter(Boolean).filter(v => !v.refuted).length >= 2
-
-// loop-until-budget
-while (budget.total && budget.remaining() > 50_000) {
- const r = await agent('…', { schema: S })
- /* accumulate */ log(`${budget.remaining()} left`)
-}
-
-// canonical review pipeline
-await pipeline(
- DIMENSIONS,
- d => agent(d.prompt, { phase: 'Review', schema: F }),
- review => parallel(review.findings.map(f => () =>
- agent(`Verify: ${f.title}`, { phase: 'Verify', schema: V })
- .then(v => ({ ...f, verdict: v }))
- ))
-)
-```
-
-[patterns.md](./patterns.md)
-
-## Opt-in (must have one)
-
-- User said `ultracode` / session ultracode on
-- User asked for workflow / fan-out / multi-agent orchestration
-- Skill/command requires Workflow
-- Named workflow requested
-
-Else: single `Agent` or ask.
-
-## Altitude
-
-| Layer | Owns |
-|---|---|
-| Orchestrator | Intent, graph, schemas, synthesis, user |
-| Script | Loops, fan-out, votes, budget stops |
-| Workers | Tools, content, optional worktree |
-| Engine | Caps, journal, UI, permissions plumbing |
-
-[orchestration.md](./orchestration.md) · [usecases.md](./usecases.md)
-
-## Index
-
-[README](./README.md) · [Architecture](./architecture.md) · [Lifecycle](./lifecycle.md)
diff --git a/docs/dynamic-workflow/claude/concurrency.md b/docs/dynamic-workflow/claude/concurrency.md
deleted file mode 100644
index bf67020a..00000000
--- a/docs/dynamic-workflow/claude/concurrency.md
+++ /dev/null
@@ -1,191 +0,0 @@
-# `pipeline()` & `parallel()`
-
-These two combinators are the heart of multi-agent structure. Using the wrong one wastes wall-clock or forces incorrect synchronization.
-
-## Quick contrast
-
-| | `pipeline` | `parallel` |
-|---|---|---|
-| Input | `items[]` + stage functions | `thunks[]` of `() => Promise` |
-| Sync model | **No barrier** between stages | **Barrier** — wait for all thunks |
-| Wall-clock | ≈ slowest **item chain** | ≈ slowest **thunk** (then next barrier stage) |
-| Failure | Stage throw → that item becomes `null`, later stages skipped for it | Thunk throw / agent error → slot `null`; call never rejects |
-| Default for multi-stage? | **Yes** | No — only when you need all results together |
-
----
-
-## `pipeline`
-
-### Signature
-
-```ts
-pipeline(
- items: any[],
- stage1: (prev, originalItem, index) => any | Promise,
- stage2?: (prev, originalItem, index) => any | Promise,
- // ...
-): Promise
-```
-
-### Semantics
-
-- Each **item** flows through **all stages independently**.
-- Item A may be in stage 3 while item B is still in stage 1.
-- Every stage receives `(prevResult, originalItem, index)`:
- - Use `originalItem` / `index` to label work without stuffing identity only into stage-1 returns.
-- A stage that **throws** drops that item to `null` and skips remaining stages for that item.
-- Max items per call: **4096** (hard error if exceeded) — see [limits](./limits.md).
-
-### Canonical multi-stage pattern
-
-Review by dimension, then verify each finding **as soon as that dimension finishes** (not after all dimensions finish):
-
-```js
-export const meta = {
- name: 'review-changes',
- description: 'Review changed files across dimensions, verify each finding',
- phases: [{ title: 'Review' }, { title: 'Verify' }],
-}
-
-const DIMENSIONS = [
- { key: 'bugs', prompt: '…' },
- { key: 'perf', prompt: '…' },
-]
-
-const results = await pipeline(
- DIMENSIONS,
- d => agent(d.prompt, {
- label: `review:${d.key}`,
- phase: 'Review',
- schema: FINDINGS_SCHEMA,
- }),
- review => parallel(
- review.findings.map(f => () =>
- agent(`Adversarially verify: ${f.title}`, {
- label: `verify:${f.file}`,
- phase: 'Verify',
- schema: VERDICT_SCHEMA,
- }).then(v => ({ ...f, verdict: v }))
- )
- )
-)
-
-const confirmed = results
- .flat()
- .filter(Boolean)
- .filter(f => f.verdict?.isReal)
-
-return { confirmed }
-// Dimension "bugs" findings verify while "perf" is still reviewing.
-```
-
-### Transform inside a stage (no extra barrier)
-
-```js
-// ❌ Smell: barrier only to flatten
-const a = await parallel(items.map(i => () => agent(…)))
-const b = a.filter(Boolean).flatMap(x => x.findings)
-const c = await parallel(b.map(f => () => agent(verify(f))))
-
-// ✅ Pipeline with transform in a stage
-const c = await pipeline(
- items,
- i => agent(…),
- r => r.findings, // pure transform
- f => agent(verify(f), { schema: V }) // or map to parallel inside if many findings
-)
-```
-
-If one item produces many findings, a stage may return `parallel(findings.map(...))` as in the canonical example.
-
----
-
-## `parallel`
-
-### Signature
-
-```ts
-parallel(thunks: Array<() => Promise>): Promise
-```
-
-### Semantics
-
-- Runs thunks **concurrently**.
-- **Barrier:** does not resolve until every thunk settles.
-- A throwing thunk (or agent error) becomes **`null`** in that index — the `parallel` call **itself never rejects**.
-- Always `.filter(Boolean)` before treating results as data.
-- Same concurrency / item caps as overall engine ([limits](./limits.md)).
-
-### When a barrier is correct
-
-Use `parallel` (or a barrier between pipeline stages implemented via collecting all items) **only** when stage N needs **cross-item** context from **all** of stage N−1:
-
-1. **Dedup / merge** across the full set before expensive work.
-2. **Early-exit** if total count is zero (“0 bugs → skip verification”).
-3. Next prompt **references “the other findings”** for comparison.
-
-```js
-// Correct barrier: need ALL findings before expensive verification
-const all = await parallel(
- DIMENSIONS.map(d => () => agent(d.prompt, { schema: FINDINGS_SCHEMA }))
-)
-const deduped = dedupeByFileAndLine(
- all.filter(Boolean).flatMap(r => r.findings)
-)
-if (!deduped.length) {
- log('0 findings — skip verify')
- return { confirmed: [] }
-}
-const verified = await parallel(
- deduped.map(f => () => agent(verifyPrompt(f), { schema: VERDICT_SCHEMA }))
-)
-```
-
-### When a barrier is NOT justified
-
-| Bad reason | Do this instead |
-|---|---|
-| “I need to flatten/map/filter first” | Transform inside a `pipeline` stage |
-| “Stages are conceptually separate” | `pipeline` already models separate stages without sync |
-| “It’s cleaner code” | Barrier latency is real — if 5 finders run and the slowest is 3× the fastest, a barrier wastes most of the fast agents’ idle time |
-
-**Smell test:** if you wrote `parallel → transform → parallel` with no cross-item dependency, rewrite as `pipeline`.
-
----
-
-## Nested concurrency
-
-Stages of a `pipeline` may call `parallel` (per item). Outer `parallel` may launch whole pipelines. Nested `workflow()` shares the parent concurrency pool.
-
-```js
-// Per-item: many judges after one finder
-await pipeline(
- targets,
- t => agent(findPrompt(t), { schema: BUGS }),
- found => parallel(
- found.bugs.map(b => () => agent(judgePrompt(b), { schema: VERDICT }))
- )
-)
-```
-
-## Concurrency cap interaction
-
-Only ~`min(16, cpu_cores - 2)` agents run at once per workflow; the rest **queue**. You can still pass large arrays — they complete, they just don’t all run simultaneously. See [limits](./limits.md).
-
-## Decision flowchart
-
-```
-Need multi-stage over a list?
- │
- ├─ Does stage N need the FULL set from stage N-1?
- │ yes → parallel (barrier) then next stage
- │ no → pipeline(items, stage1, stage2, …)
- │
- └─ Single fan-out, one stage only?
- → parallel([() => agent…, …]) or pipeline(items, oneStage)
-```
-
-## Next
-
-- [phase, log, args, budget, workflow()](./control-and-io.md)
-- [Patterns](./patterns.md)
diff --git a/docs/dynamic-workflow/claude/control-and-io.md b/docs/dynamic-workflow/claude/control-and-io.md
deleted file mode 100644
index b347469d..00000000
--- a/docs/dynamic-workflow/claude/control-and-io.md
+++ /dev/null
@@ -1,179 +0,0 @@
-# `phase`, `log`, `args`, `budget`, `workflow()`
-
-Progress UX, parameterization, token ceilings, and one-level nesting.
-
----
-
-## `phase`
-
-```ts
-phase(title: string): void
-```
-
-- Starts a **progress group** in `/workflows`.
-- Subsequent `agent()` calls **without** `opts.phase` group under this title.
-- Titles should match `meta.phases[].title` exactly for clean UI; unmatched titles still get their own group.
-- Inside concurrent stages, prefer **`opts.phase`** on each `agent()` to avoid races on the global phase state:
-
-```js
-// Global phase — fine for sequential sections
-phase('Implement')
-await agent('…', { label: 'impl' })
-
-// Concurrent — set phase per agent
-await parallel([
- () => agent('…', { phase: 'Review', label: 'r1' }),
- () => agent('…', { phase: 'Review', label: 'r2' }),
-])
-```
-
-`phase` is UX only — it does not create isolation, budget buckets, or barriers.
-
----
-
-## `log`
-
-```ts
-log(message: string): void
-```
-
-- Emits a **narrator line** above the progress tree.
-- Use for counts, early exits, dropped coverage, loop progress.
-
-**Rule: no silent caps.** If the workflow bounds coverage (top-N, sampling, “first 20 files”), `log()` what was dropped. Silent truncation reads as “we covered everything.”
-
-```js
-if (files.length > 50) {
- log(`scoping to first 50 of ${files.length} files`)
- files = files.slice(0, 50)
-}
-```
-
----
-
-## `args`
-
-```ts
-args: any // Workflow({ args }) value, or undefined if omitted
-```
-
-### Rules
-
-1. Value is **verbatim** from the tool call.
-2. Pass **real** JSON arrays/objects in the tool invocation — **not** a stringified JSON blob.
-
-```js
-// ✅
-Workflow({ script, args: ['a.ts', 'b.ts'] })
-// in script: args.map(f => …)
-
-// ❌
-Workflow({ script, args: '["a.ts","b.ts"]' })
-// args is a string → args.map throws
-```
-
-3. Primary channel for **parameterizing** named workflows (research question, path list, config).
-4. Primary channel for values that must stay **stable across resume** (fixed timestamps, seeds) — see [script determinism](./script-contract.md).
-
-```js
-// script
-const topic = args?.topic ?? 'authentication'
-const files = args?.files ?? []
-await agent(`Review ${topic} in ${files.join(', ')}`, { schema: FINDINGS })
-```
-
----
-
-## `budget`
-
-```ts
-budget: {
- total: number | null
- spent(): number
- remaining(): number // max(0, total - spent) or Infinity if no target
-}
-```
-
-### Semantics
-
-| Field / method | Meaning |
-|---|---|
-| `total` | Turn token target from user “+500k”-style directives; `null` if unset |
-| `spent()` | Output tokens spent this turn across **main loop + all workflows** (shared pool) |
-| `remaining()` | `max(0, total - spent())`, or **`Infinity`** if no target |
-
-### Hard ceiling
-
-Once `spent()` reaches `total`, further **`agent()` calls throw**. This is not advisory.
-
-### Guard loops
-
-Without a target, `remaining()` is `Infinity` and a `while (budget.remaining() > …)` loop runs until the **1000-agent** lifetime cap. Always guard:
-
-```js
-const bugs = []
-while (budget.total && budget.remaining() > 50_000) {
- const result = await agent('Find bugs in this codebase.', { schema: BUGS_SCHEMA })
- bugs.push(...result.bugs)
- log(`${bugs.length} found, ${Math.round(budget.remaining() / 1000)}k remaining`)
-}
-```
-
-### Static fleet sizing
-
-```js
-const FLEET = budget.total
- ? Math.floor(budget.total / 100_000)
- : 5
-```
-
-### Loop-until-count (no budget)
-
-```js
-const bugs = []
-while (bugs.length < 10) {
- const result = await agent('Find bugs…', { schema: BUGS_SCHEMA })
- bugs.push(...result.bugs)
- log(`${bugs.length}/10 found`)
-}
-```
-
-Prefer budget-aware or dry-round stops for open-ended hunts ([patterns](./patterns.md)).
-
----
-
-## Nested `workflow()`
-
-```ts
-workflow(
- nameOrRef: string | { scriptPath: string },
- args?: any
-): Promise
-```
-
-### Semantics
-
-| Aspect | Detail |
-|---|---|
-| Purpose | Run another workflow **inline** as a sub-step; return its return value |
-| `string` | Name in saved/built-in registry (same as `Workflow({ name })`) |
-| `{ scriptPath }` | Script file on disk (e.g. previously persisted) |
-| Shared with parent | Concurrency cap, agent counter, abort signal, token `budget` |
-| UI | Child agents under a nested group in `/workflows` |
-| Nesting depth | **One level only** — `workflow()` inside a child **throws** |
-| Errors | Unknown name / unreadable path / child syntax error → throw (catch to handle) |
-
-```js
-const map = await workflow('understand-subsystem', { root: 'src/auth' })
-const plan = await workflow('design-panel', { context: map })
-return { map, plan }
-```
-
-Use nesting to compose **reusable** named workflows. Prefer sequential top-level `Workflow` tool calls across turns when the coordinator must read results and replan with the user.
-
----
-
-## Next
-
-- [Limits & sandbox](./limits.md)
-- [Resume & journal](./resume.md)
diff --git a/docs/dynamic-workflow/claude/lifecycle.md b/docs/dynamic-workflow/claude/lifecycle.md
deleted file mode 100644
index 4a2e41c6..00000000
--- a/docs/dynamic-workflow/claude/lifecycle.md
+++ /dev/null
@@ -1,108 +0,0 @@
-# Lifecycle & operator UX
-
-How a workflow run feels end-to-end.
-
-## Happy path
-
-```
-1. Authoring
- Coordinator scouts → builds work-list → writes inline script (or picks name)
-
-2. Permission
- User sees meta.description (+ size guideline if configured)
-
-3. Launch
- Workflow tool returns immediately:
- taskId, runId, scriptPath, transcriptDir, workflowName, status
-
-4. Progress
- /workflows shows:
- · phase groups
- · agent labels
- · nested child workflow groups
- · narrator log() lines
-
-5. Completion
- delivers script return value to coordinator
-
-6. Synthesis
- Coordinator may:
- · answer the user
- · edit scriptPath + resume
- · launch another Workflow for the next phase
-```
-
-## Multi-phase product work
-
-Prefer **several workflows across turns** over one mega-script:
-
-| Turn | Workflow | Coordinator does after |
-|---|---|---|
-| 1 | Understand | Read map; decide design scope |
-| 2 | Design panel | Pick approach with user if needed |
-| 3 | Implement + review repair | Inspect diff; request fixes |
-| 4 | Verify / audit | Ship narrative + residual risk |
-
-The coordinator **stays in the loop** between phases — that is a feature. Ultracode makes this the default for substantive work ([opt-in](./opt-in.md)).
-
-## Hybrid single-phase
-
-```
-scout (inline tools)
- → Workflow(pipeline over discovered items)
- → synthesize answer
-```
-
-You need the work-list shape before the orchestration step, not before any investigation.
-
-## Background vs blocking mental model
-
-From the model’s perspective:
-
-- The `Workflow` **tool call** returns once the run is **registered** (async launch).
-- The **result of the script** arrives later via notification / task completion channel.
-- Do not assume the tool return value is the script’s `return {…}` object.
-
-Operators watch `/workflows` for live structure.
-
-## Iteration loop
-
-```
-launch → observe → Edit(scriptPath) → stop if needed → resumeFromRunId
-```
-
-See [resume](./resume.md).
-
-## Failure / skip paths
-
-| Event | Typical handling |
-|---|---|
-| Syntax error in script | `error` on launch result; fix script, relaunch |
-| User denies permission | No run; ask or fall back to single Agent |
-| User skips individual agent | That `agent()` → `null`; filter and continue or abort in script |
-| Budget exhausted | Further `agent()` throws; catch / end loop; return partial |
-| Agent terminal API failure | `null`; log; optionally retry with new call (not automatic) |
-
-## Named vs inline scripts
-
-| Mode | When |
-|---|---|
-| Inline `script` | First design of a one-off harness |
-| `scriptPath` iterate | Evolving a run without re-pasting |
-| `name` / `.claude/workflows/` | Reusable team harnesses |
-| Nested `workflow(name)` | Compose reusable pieces inside a parent script |
-
-## Common single-phase catalog
-
-| Name | Intent |
-|---|---|
-| Understand | Parallel readers → structured map |
-| Design | Judge panel → scored synthesis |
-| Review | Dimensions → find → adversarially verify |
-| Research | Multi-modal sweep → deep-read → synthesize |
-| Migrate | Discover → transform (worktree) → verify |
-
-## Next
-
-- [One level above / orchestration](./orchestration.md)
-- [Use cases](./usecases.md)
diff --git a/docs/dynamic-workflow/claude/limits.md b/docs/dynamic-workflow/claude/limits.md
deleted file mode 100644
index 268dfb93..00000000
--- a/docs/dynamic-workflow/claude/limits.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Limits & sandbox
-
-Hard bounds and isolation properties of the Claude Code workflow engine (model-facing behavior).
-
-## Engine caps
-
-| Limit | Value | Behavior if exceeded |
-|---|---|---|
-| Concurrent `agent()` calls | `min(16, cpu_cores - 2)` **per workflow** | Excess **queue**; still complete |
-| Lifetime agent count | **1000** per workflow run | Runaway-loop backstop |
-| Items per `parallel` / `pipeline` call | **4096** | **Explicit error** (not silent truncate) |
-| Script non-determinism | `Date.now` / `Math.random` / bare `new Date` | **Throw** |
-| Nested `workflow()` depth | **1** | Nested call inside child **throws** |
-| Token budget | User “+N” target if set | Further `agent()` **throws** when spent ≥ total |
-
-Queued concurrency means you can pass large work-lists safely; wall-clock still stretches when the queue is deep.
-
-## Soft guidelines (not hard engine caps)
-
-| Guideline | Source |
-|---|---|
-| Workflow size: small ≈ 5, medium ≈ 15, large ≈ 50, unrestricted | User `/config` workflow size guideline |
-| Thoroughness vs brevity | Task wording (“any bugs” vs “thoroughly audit”) |
-
-The model should treat size guidelines as authoring policy unless the user explicitly overrides with scale language or ultracode.
-
-## Script sandbox
-
-| Available | Not available |
-|---|---|
-| Plain JS built-ins (`JSON`, `Math`, `Array`, …) | Node APIs, `require`, `process` |
-| Injected primitives | Filesystem, network, subprocess from script |
-| `agent` / nested `workflow` as escape hatches | Direct shell or edit from script |
-
-Side effects (file edits, network via tools, git) happen **inside subagents** under normal Claude Code tool permission policy — not as raw script I/O.
-
-## Worktree isolation (per agent)
-
-```js
-await agent(prompt, { isolation: 'worktree' })
-```
-
-| Property | Detail |
-|---|---|
-| Cost | ~200–500ms setup + disk **per agent** |
-| Use when | Parallel **mutators** would conflict on one checkout |
-| Cleanup | Auto-remove if worktree unchanged |
-| Avoid when | Read-only work, single writer, or sequential mutators |
-
-This is **opt-in per `agent()`**, not a default for all workers.
-
-## Permission / product gates
-
-Separate from engine caps:
-
-- User must [opt in](./opt-in.md) (or enable ultracode) before `Workflow` is called.
-- Script `meta.description` surfaces in the permission dialog.
-- Individual agents may still hit tool permission prompts per session policy.
-
-## MCP caveats
-
-Workflow agents can use session-connected MCP tools via ToolSearch. **Interactively authenticated** MCP servers (e.g. browser login flows) may be absent in headless or cron-style runs.
-
-## Practical sizing
-
-| Ask | Rough shape |
-|---|---|
-| “Find any bugs” | Few finders, single-vote verify |
-| “Thoroughly audit” | Larger finder pool, 3–5 vote adversarial pass, synthesis |
-| Open-ended hunt + budget | `while (budget.total && budget.remaining() > …)` |
-| Open-ended hunt, no budget | loop-until-dry with dry-round counter — not unbounded `while(true)` without exit |
-
-## Next
-
-- [Resume & journal](./resume.md)
-- [Patterns](./patterns.md)
diff --git a/docs/dynamic-workflow/claude/opt-in.md b/docs/dynamic-workflow/claude/opt-in.md
deleted file mode 100644
index 6a4b6b00..00000000
--- a/docs/dynamic-workflow/claude/opt-in.md
+++ /dev/null
@@ -1,67 +0,0 @@
-# Opt-in & Ultracode
-
-Workflows can spawn dozens of agents and consume large token budgets. Claude Code therefore gates the `Workflow` tool behind **explicit user opt-in**. A task that would merely “benefit from parallelism” is not enough.
-
-## When Workflow is allowed
-
-The model may call `Workflow` only when at least one of these holds:
-
-1. **Keyword `ultracode` in the user prompt**
- A system-reminder confirms it for that turn/session context.
-
-2. **Session ultracode is on**
- Standing opt-in for every substantive task (see below).
-
-3. **User asks in their own words** for multi-agent orchestration
- Examples: “use a workflow”, “run a workflow”, “fan out agents”, “orchestrate this with subagents”.
- The ask must be in the **user’s** words — not inferred from task complexity.
-
-4. **A skill / slash command’s instructions** tell the model to call Workflow.
-
-5. **User asks for a specific named / saved workflow.**
-
-## When Workflow is not allowed
-
-Even if multi-agent would clearly help:
-
-- Silent model decision that “parallel is better.”
-- Inferring opt-in from difficulty alone.
-- “This would be faster with more agents” without user request.
-
-**Fallback:**
-
-- Use the single `Agent` tool for one-off subagents, or
-- Briefly describe what a multi-agent workflow would do and rough cost, and ask. Mention the user can say “use a workflow” later to skip the ask.
-
-## Ultracode mode
-
-When a system-reminder confirms ultracode is **on**:
-
-| Rule | Behavior |
-|---|---|
-| Opt-in | Standing — every substantive task may/should use a workflow |
-| Goal | Most exhaustive correct answer; token cost is not a constraint |
-| Multi-phase | Often **several workflows in sequence** (understand → design → implement → review) so the coordinator stays in the loop between phases |
-| Patterns | Prefer adversarial verify, multi-modal sweep, completeness critic, loop-until-dry where they fit |
-| Solo exception | Pure conversation or trivial mechanical edits only |
-
-When ultracode is **off**, revert to the explicit opt-in list above.
-
-## Hybrid still applies
-
-Opt-in does not mean “dump the whole task into one script immediately.”
-
-1. Scout inline → discover work-list.
-2. Author workflow over that list.
-3. Synthesize; chain next phase if needed.
-
-## Cost and size guidelines
-
-Users may set a **workflow size guideline** in `/config` (e.g. small ≈ 5 agents, medium ≈ 15, large ≈ 50, unrestricted). This is a **guideline** for the model’s authoring behavior, not the same as the engine’s hard caps ([limits](./limits.md)).
-
-Budget directives (“+500k”-style) feed `budget.total` inside scripts — a **hard** ceiling on further `agent()` calls once spent. See [control-and-io](./control-and-io.md).
-
-## Next
-
-- [Workflow tool API](./workflow-tool.md)
-- [Orchestration altitude](./orchestration.md)
diff --git a/docs/dynamic-workflow/claude/orchestration.md b/docs/dynamic-workflow/claude/orchestration.md
deleted file mode 100644
index 39c75d34..00000000
--- a/docs/dynamic-workflow/claude/orchestration.md
+++ /dev/null
@@ -1,138 +0,0 @@
-# One level above agents
-
-Classic multi-agent demos put several peers in a chat room and hope coordination emerges. Dynamic workflows **invert** that:
-
-> **Coordination is a program** written by a high-capability model.
-> **Workers are replaceable execution units.**
-
-That is “one level above” ordinary agent tool use.
-
-## Split of responsibility
-
-### Orchestrator (main session)
-
-- Understand user intent and constraints
-- Discover the work-list (files, bugs, modules, APIs)
-- Choose pattern (pipeline vs barrier, depth vs breadth)
-- Author the script, schemas, and worker prompts
-- Allocate model / effort tiers per stage
-- Interpret structured returns; decide the next phase
-- Talk to the human; own the correctness narrative
-
-### Workers (`agent()`)
-
-- Execute one bounded prompt with tools
-- Return raw data or schema-validated objects
-- Stay isolated (optional worktree)
-- Do **not** redesign the global plan
-- May be cheaper/faster models for mechanical stages
-- May be specialized `agentType`s (reviewer, explorer, …)
-
-### Engine
-
-- Run control flow faithfully
-- Enforce concurrency, agent caps, budget hard stop
-- Journal for resume
-- Present progress UI
-
-## Why altitude matters
-
-| Problem in a flat agent loop | Workflow fix |
-|---|---|
-| Plan and tool churn share one context | Workers isolate tool churn; script aggregates returns only |
-| Model “forgets” to verify | Verify is a stage in code |
-| Fan-out is improvised each turn | Fan-out is `parallel` / `pipeline` |
-| Hard to scale thoroughness | Scale fleet size, votes, dry rounds, budget |
-| Parallel edits stomp each other | `isolation: 'worktree'` on mutators |
-
-```
-User intent
- │
- ▼
-┌──────────────────────────────────────────┐
-│ Orchestrator model (main session) │
-│ · plans · schemas · phase selection │
-│ · Workflow({ script, args }) │
-└───────────────────┬──────────────────────┘
- │ deterministic JS spine
- ┌───────────┼───────────┐
- ▼ ▼ ▼
- agent() agent() agent()
- worker A worker B worker C
- │ │ │
- └───────────┼───────────┘
- ▼
- structured returns
- │
- ▼
- orchestrator synthesizes
- │
- ▼
- user-facing answer
-```
-
-## Model tiering pattern
-
-Keep the **session model strong** for orchestration (authoring scripts, reading results, deciding phases).
-
-Inside the workflow:
-
-| Stage | Typical choice |
-|---|---|
-| Mechanical map / extract | `effort: 'low'`; optional smaller `model` |
-| Default work | **Omit `model`** — inherit session model |
-| Hard judges / design | higher `effort`; keep strong model |
-| Parallel mutators | same model + `isolation: 'worktree'` |
-
-When unsure about `model`, **omit**. Wrong downgrades are worse than paying full price on a small fleet.
-
-## Structured handoffs
-
-The interface between altitude layers is **data**, not chat:
-
-```js
-// worker → script
-{ findings: [{ file, line, issue, severity }] }
-
-// script → orchestrator
-{ confirmed, dropped, stats }
-
-// orchestrator → user
-narrative + residual risk + links to paths
-```
-
-Schemas make handoffs machine-checkable. Prefer them at every stage boundary that feeds another stage.
-
-## What the orchestrator must not outsource
-
-- Final user-facing judgment (“is this safe to merge?”) without reading key evidence
-- Opt-in / cost honesty
-- Choosing silent truncation
-- Replacing a missing verification stage with “the workers looked careful”
-
-Workers can be wrong in correlated ways; adversarial / diverse-lens patterns exist to fight that ([patterns](./patterns.md)).
-
-## Comparison: Agent tool vs Workflow altitude
-
-| | Single `Agent` | `Workflow` |
-|---|---|---|
-| Altitude | Peer subagent | Programmed fleet under orchestrator |
-| Coordination | Prompt prose | Code |
-| Resume multi-step graph | Weak | Prefix journal |
-| Best for | One bounded digression | Structured multi-agent jobs |
-
-## Enabling “bigger brain, many hands”
-
-Dynamic workflows let you:
-
-1. Put the **expensive reasoning** in graph design and synthesis.
-2. Put the **expensive tokens** in parallel worker contexts that do not pollute each other.
-3. Put the **reliability** in deterministic stages (verify, majority, dry-stop).
-4. Put the **human** at phase boundaries instead of inside every tool call.
-
-That is the product of the feature — not just “more agents.”
-
-## Next
-
-- [Use cases](./usecases.md)
-- [Cheatsheet](./cheatsheet.md)
diff --git a/docs/dynamic-workflow/claude/patterns.md b/docs/dynamic-workflow/claude/patterns.md
deleted file mode 100644
index 42dc59ec..00000000
--- a/docs/dynamic-workflow/claude/patterns.md
+++ /dev/null
@@ -1,254 +0,0 @@
-# Quality patterns
-
-These are **not** extra APIs. They are recipes composed from [`agent`](./agent.md), [`pipeline` / `parallel`](./concurrency.md), [`budget`](./control-and-io.md), and [`log`](./control-and-io.md). Pick by task; compose freely.
-
-## Scale to the ask
-
-| User language | Shape |
-|---|---|
-| “Find any bugs” | Few finders, single-vote verify |
-| “Thoroughly audit” / “be comprehensive” | Larger finder pool, 3–5 vote adversarial pass, synthesis |
-| Unsure on research/review/audit | Lean thorough |
-| Quick check | Lean brief |
-
----
-
-## Adversarial verify
-
-Spawn N independent skeptics per claim, each prompted to **REFUTE**. Kill if ≥ majority refute. Prevents plausible-but-wrong findings from surviving.
-
-```js
-const votes = await parallel(
- Array.from({ length: 3 }, () => () =>
- agent(
- `Try to refute: ${claim}. Default to refuted=true if uncertain.`,
- { schema: VERDICT, phase: 'Verify', effort: 'high' }
- )
- )
-)
-const survives =
- votes.filter(Boolean).filter(v => !v.refuted).length >= 2
-```
-
----
-
-## Perspective-diverse verify
-
-When a finding can fail in more than one way, give each verifier a **distinct lens** (correctness, security, perf, does-it-reproduce) instead of N identical refuters. Diversity catches failure modes redundancy cannot.
-
-```js
-const lenses = ['correctness', 'security', 'repro']
-const votes = await parallel(
- lenses.map(lens => () =>
- agent(`Judge "${desc}" via the ${lens} lens — real?`, {
- schema: VERDICT,
- phase: 'Verify',
- label: `judge:${lens}`,
- })
- )
-)
-const real = votes.filter(Boolean).filter(v => v.real).length >= 2
-```
-
----
-
-## Judge panel (design)
-
-Generate N independent attempts from different angles (MVP-first, risk-first, user-first). Score with parallel judges. Synthesize from the winner while grafting best ideas from runners-up. Beats single-attempt iteration when the solution space is wide.
-
-```js
-const ANGLES = ['mvp-first', 'risk-first', 'user-first']
-const drafts = await parallel(
- ANGLES.map(a => () =>
- agent(`Propose a design (${a}). Constraints: ${constraints}`, {
- schema: DESIGN_SCHEMA,
- phase: 'Design',
- label: `draft:${a}`,
- })
- )
-).then(xs => xs.filter(Boolean))
-
-const scored = await parallel(
- drafts.map(d => () =>
- agent(`Score this design vs criteria…\n${JSON.stringify(d)}`, {
- schema: SCORE_SCHEMA,
- phase: 'Score',
- })
- )
-).then(xs => xs.filter(Boolean))
-
-const winner = pickWinner(drafts, scored)
-const synthesis = await agent(
- `Synthesize final design from winner + graft runners-up…`,
- { schema: DESIGN_SCHEMA, phase: 'Synthesize', effort: 'high' }
-)
-return { winner, synthesis, runnersUp: drafts }
-```
-
----
-
-## Loop-until-dry
-
-Unknown-size discovery (bugs, issues, edge cases): keep spawning finders until **K consecutive rounds** return nothing new. Simple `while (count < N)` misses the tail.
-
-**Critical:** dedup against **all `seen`**, not only `confirmed`. If you only track confirmed, judge-rejected findings reappear every round and the loop never converges.
-
-```js
-const seen = new Set()
-const confirmed = []
-let dry = 0
-
-while (dry < 2) {
- const found = (
- await parallel(
- FINDERS.map(f => () =>
- agent(f.prompt, { phase: 'Find', schema: BUGS })
- )
- )
- )
- .filter(Boolean)
- .flatMap(r => r.bugs)
-
- const fresh = found.filter(b => !seen.has(key(b)))
- if (!fresh.length) {
- dry++
- log(`dry round ${dry}/2`)
- continue
- }
- dry = 0
- fresh.forEach(b => seen.add(key(b)))
- log(`${fresh.length} fresh findings (${seen.size} seen total)`)
-
- const judged = await parallel(
- fresh.map(b => () =>
- parallel(
- ['correctness', 'security', 'repro'].map(lens => () =>
- agent(`Judge "${b.desc}" via ${lens} — real?`, {
- phase: 'Verify',
- schema: VERDICT,
- })
- )
- ).then(vs => ({
- b,
- real: vs.filter(Boolean).filter(v => v.real).length >= 2,
- }))
- )
- )
-
- confirmed.push(...judged.filter(v => v.real).map(v => v.b))
-}
-
-return confirmed
-```
-
-Combine with [budget](./control-and-io.md#budget) for cost-bounded open-ended hunts:
-
-```js
-while (dry < 2 && budget.total && budget.remaining() > 50_000) {
- // …
-}
-```
-
----
-
-## Multi-modal sweep
-
-Parallel agents each search a **different way** (by-container, by-content, by-entity, by-time). Each is blind to what the others surface — covers angles one search cannot.
-
-```js
-const MODES = [
- { key: 'by-path', prompt: 'Find X by directory layout…' },
- { key: 'by-symbol', prompt: 'Find X by type/symbol names…' },
- { key: 'by-test', prompt: 'Find X by failing or related tests…' },
- { key: 'by-history', prompt: 'Find X by recent git history…' },
-]
-
-const sweeps = await parallel(
- MODES.map(m => () =>
- agent(m.prompt, {
- phase: 'Sweep',
- label: `sweep:${m.key}`,
- schema: HITS_SCHEMA,
- effort: 'low',
- })
- )
-).then(xs => xs.filter(Boolean))
-
-const merged = dedupe(sweeps.flatMap(s => s.hits))
-// then deep-read top hits, then synthesize
-```
-
----
-
-## Completeness critic
-
-A final agent asks what is missing — modality not run, claim unverified, source unread. Output becomes the next work round.
-
-```js
-const gaps = await agent(
- `Given work done:\n${JSON.stringify(summary)}\nWhat is missing?`,
- { schema: GAPS_SCHEMA, phase: 'Critic', effort: 'medium' }
-)
-if (gaps.items.length) {
- log(`critic found ${gaps.items.length} gaps`)
- // feed gaps into another pipeline / loop iteration
-}
-```
-
----
-
-## Self-repair implementation loop
-
-Encode a real engineering process as a script:
-
-```text
-Implement → multi-reviewer parallel → repair from structured findings → verify gates
-```
-
-See the implement/review/repair/verify example in [script contract](./script-contract.md).
-
-Tips:
-
-- Reviewers **read-only**; repair agent owns writes.
-- Structured `FINDINGS` schema forces actionable file/line/fix fields.
-- Final verify re-runs typecheck/tests and reports residual risk.
-- Resume after fixing only the repair prompt if implement+review were good.
-
----
-
-## Review pipeline (default multi-stage)
-
-Already detailed in [concurrency](./concurrency.md):
-
-```text
-dimensions → (per dimension) findings → (per finding) adversarial verify
-```
-
-Use barrier+dedup only when verification must see the global merged set first.
-
----
-
-## No silent caps
-
-If you bound coverage:
-
-```js
-const MAX = 40
-if (sites.length > MAX) {
- log(`transforming ${MAX}/${sites.length} sites; remainder skipped`)
-}
-const batch = sites.slice(0, MAX)
-```
-
-Silent truncation reads as full coverage.
-
----
-
-## Compose novel harnesses
-
-The list is not exhaustive. Valid compositions include tournament brackets, staged escalation (cheap finder → expensive judge only on survivors), and multi-phase product delivery under ultracode ([lifecycle](./lifecycle.md)).
-
-## Next
-
-- [Lifecycle & UX](./lifecycle.md)
-- [Orchestration altitude](./orchestration.md)
diff --git a/docs/dynamic-workflow/claude/primitives.md b/docs/dynamic-workflow/claude/primitives.md
deleted file mode 100644
index c30fa49b..00000000
--- a/docs/dynamic-workflow/claude/primitives.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Primitives overview
-
-The workflow script body is an async JS context with a **closed** API surface. Only these hooks are injected. Everything else is ordinary JavaScript (with [determinism bans](./script-contract.md)).
-
-## Inventory
-
-| Primitive | Kind | Role |
-|---|---|---|
-| [`agent`](./agent.md) | async call | Spawn one subagent; get string or schema-validated object |
-| [`pipeline`](./concurrency.md#pipeline) | combinator | Per-item multi-stage fan-out **without** barriers |
-| [`parallel`](./concurrency.md#parallel) | combinator | Concurrent thunks; **barrier** until all complete |
-| [`phase`](./control-and-io.md#phase) | side effect | Start a progress group for following agents |
-| [`log`](./control-and-io.md#log) | side effect | Narrator line in `/workflows` progress UI |
-| [`args`](./control-and-io.md#args) | binding | `Workflow({ args })` value, verbatim |
-| [`budget`](./control-and-io.md#budget) | binding | Shared turn token ceiling: `total`, `spent()`, `remaining()` |
-| [`workflow`](./control-and-io.md#nested-workflow) | async call | Run one nested named/path workflow (max depth 1) |
-
-## How they compose
-
-```
-meta (literal header)
- │
- ▼
-phase / log ─────────────────────────── UX only
- │
- ├── agent ─────────────────────────── unit of model work
- │
- ├── parallel([() => agent…, …]) ──── barrier fan-out
- │
- ├── pipeline(items, s1, s2, …) ───── streaming multi-stage
- │ └── stages may call agent / parallel
- │
- ├── budget.* ──────────────────────── scale / stop loops
- │
- └── workflow(name|path) ───────────── nested graph (1 level)
-```
-
-## Design rules (short)
-
-1. **Default multi-stage shape is `pipeline`**, not barrier-then-map.
-2. Use **`parallel` only** when stage N needs the **full** stage N−1 result set.
-3. Always **`.filter(Boolean)`** after `parallel` / nullable `agent` results.
-4. Prefer **`schema`** on `agent` for structured returns — no JSON parse roulette.
-5. **`log()`** anything a silent cap would hide (top-N, drops, early exit).
-6. Guard budget loops with **`budget.total &&`** (else `remaining()` is `Infinity`).
-7. Put identity for later stages in **`(prev, originalItem, index)`**, not only in stage-1 return blobs.
-
-## Not primitives (but matter)
-
-| Concern | Where documented |
-|---|---|
-| Tool launch API | [workflow-tool.md](./workflow-tool.md) |
-| Script / meta rules | [script-contract.md](./script-contract.md) |
-| Caps & isolation | [limits.md](./limits.md) |
-| Resume cache | [resume.md](./resume.md) |
-| Recipes | [patterns.md](./patterns.md) |
-
-## Next
-
-- [agent()](./agent.md)
-- [pipeline & parallel](./concurrency.md)
-- [phase, log, args, budget, workflow()](./control-and-io.md)
diff --git a/docs/dynamic-workflow/claude/resume.md b/docs/dynamic-workflow/claude/resume.md
deleted file mode 100644
index d0734b99..00000000
--- a/docs/dynamic-workflow/claude/resume.md
+++ /dev/null
@@ -1,94 +0,0 @@
-# Resume & journal
-
-Dynamic workflows are editable programs. Resume lets you change the plan mid-flight (or after a kill) without redoing finished `agent()` work.
-
-## Handles returned at launch
-
-| Field | Use |
-|---|---|
-| `runId` | Pass as `resumeFromRunId` on the next `Workflow` call |
-| `scriptPath` | Edit in place; re-invoke without resending full `script` |
-| `transcriptDir` | Subagent transcripts + `journal.jsonl` |
-| `taskId` | Stop / track the background task |
-
-## How to resume
-
-1. **Stop** the prior run if it is still running (background task stop / equivalent).
-2. Relaunch:
-
-```js
-Workflow({
- scriptPath: '/…/workflows/scripts/review-wf_abc.js',
- resumeFromRunId: 'wf_abc…',
- args: previousArgs, // keep identical for full cache when script unchanged
-})
-```
-
-Same-session only for `resumeFromRunId` (local runs).
-
-## Cache identity rule
-
-The engine finds the **longest unchanged prefix** of `agent()` calls:
-
-- Same **prompt** + same **opts** (as hashed for identity) → return **cached** result instantly.
-- First **edited or new** `agent()` call and **everything after it** run live.
-
-| Scenario | Result |
-|---|---|
-| Same script + same `args` | ~100% cache hit |
-| Edit only post-processing after the last `agent()` | Cache hit all agents; re-run pure JS tail |
-| Change prompt of agent #3 of 10 | Agents 1–2 cached; 3–10 live |
-| Insert a new `agent()` early | From that call onward live |
-
-## Why scripts ban entropy
-
-`Date.now()`, `Math.random()`, and bare `new Date()` throw in scripts so control flow and prompt construction cannot silently diverge between original run and resume. See [script contract](./script-contract.md).
-
-If you need wall-clock:
-
-- Pass a fixed ISO string via `args` at launch, or
-- Stamp times in the coordinator after the workflow returns.
-
-## `journal.jsonl`
-
-Path: `/journal.jsonl`
-
-- Records each agent’s **actual return value**.
-- Before diagnosing empty or surprising workflow results, **read the journal** — do not assume cached results are non-empty.
-- Fallback if no journal: read `agent-.jsonl` files in the transcript directory and hand-author a continuation script.
-
-## Operational patterns
-
-### Fix a bad verify stage after a long review
-
-1. Leave review `agent()` prompts unchanged.
-2. Edit only verify-stage prompts / schema in `scriptPath`.
-3. Resume with same `args` → review results cache; verify re-runs.
-
-### Add a completeness-critic pass
-
-1. Append a new phase + `agent()` at the end of the script.
-2. Resume → entire prior prefix caches; only the new agent runs.
-
-### Re-run pure aggregation
-
-1. Change only the `return` / merge logic (no `agent()` signature changes).
-2. Resume → full agent cache; new aggregation.
-
-## Failure modes to watch
-
-| Symptom | Check |
-|---|---|
-| Empty confirmed list | Journal: did judges return `null`? schema fail? |
-| Unexpected re-run of early agents | Prompt/opts drift (template changed, args differ) |
-| Resume rejected / no cache | Wrong session, missing `runId`, prior run not stopped |
-| Divergent args | Even with same script, different `args` can change prompts that embed `args` → cache miss from first embedded call |
-
-## Relation to durability
-
-Claude Code resume is **session-oriented prefix replay** of orchestration journals. It is not the same as a multi-day durable job supervisor with external leases (a different control plane). For long-lived external orchestration, see product-specific durable systems; this doc describes the model-facing Workflow resume API only.
-
-## Next
-
-- [Patterns](./patterns.md)
-- [Lifecycle](./lifecycle.md)
diff --git a/docs/dynamic-workflow/claude/script-contract.md b/docs/dynamic-workflow/claude/script-contract.md
deleted file mode 100644
index dfd64fbc..00000000
--- a/docs/dynamic-workflow/claude/script-contract.md
+++ /dev/null
@@ -1,145 +0,0 @@
-# Script contract
-
-A workflow script is plain JavaScript that starts with a pure-literal `meta` export, then runs in an async context with only the injected orchestration primitives available.
-
-## Minimal shape
-
-```js
-export const meta = {
- name: 'find-flaky-tests',
- description: 'Find flaky tests and propose fixes', // shown in permission dialog
- phases: [
- { title: 'Scan', detail: 'grep test logs for retries' },
- { title: 'Fix', detail: 'one agent per flaky test', model: 'sonnet' },
- ],
- // optional: whenToUse — shown in workflow lists
-}
-
-// body — async context; await freely
-phase('Scan')
-const flaky = await agent('grep CI logs for retry markers', { schema: FLAKY_SCHEMA })
-// ...
-return { flaky }
-```
-
-## `meta` rules
-
-| Rule | Detail |
-|---|---|
-| Position | Must be the **first statement** in the script |
-| Purity | **Pure literal only** — no variables, function calls, spreads, or template interpolation |
-| Required | `name`, `description` |
-| Optional | `whenToUse`, `phases` |
-| Phase entries | `{ title, detail?, model? }` |
-| Phase titles | Must match `phase('…')` call strings **exactly** for UI grouping; unmatched `phase()` still gets its own progress group |
-| Per-phase model | Optional override for agents in that phase’s UI group (agent-level `opts.model` still applies per call) |
-| Permission UX | `description` is what the user sees in the approval dialog |
-
-Invalid example (not pure literal):
-
-```js
-const n = 'review'
-export const meta = { name: n, description: `Review ${topic}` } // ❌
-```
-
-## Language
-
-| Allowed | Forbidden |
-|---|---|
-| Plain JavaScript | TypeScript annotations, interfaces, generics |
-| `async` body with top-level `await` | Node APIs (`fs`, `process`, `require`, …) |
-| `JSON`, `Math`, `Array`, `Object`, `Map`, `Set`, … | Filesystem, network, subprocess |
-| Template strings / normal expressions in the **body** | Non-determinism listed below |
-
-Type annotations like `: string[]` **fail to parse**. Keep types in comments or in JSON Schema objects as plain data.
-
-## Determinism bans (resume safety)
-
-These throw if called in the script (argless / pure entropy):
-
-- `Date.now()`
-- `Math.random()`
-- argless `new Date()`
-
-**Why:** [Resume](./resume.md) replays the longest unchanged prefix of `agent()` calls by hashing prompt + options. If the script branched on wall-clock or random, cache identity would lie and partial replay would be unsafe.
-
-**What to do instead:**
-
-- Pass fixed timestamps / seeds via `args`.
-- Stamp wall-clock **after** the workflow returns, in the coordinator.
-- For “random-like” diversity among agents, vary **prompt text or label by index** (deterministic in the script, different per worker).
-
-## Only escape hatches into models
-
-From the script you can only:
-
-1. Call **`agent()`** — spawn a subagent (tools, optional schema).
-2. Call **`workflow()`** — run one nested saved/path workflow (one level only).
-
-There is no raw shell, no write-file, no HTTP from the orchestration body. That is intentional: orchestration stays pure; side effects live inside agents under normal permission/tool policy.
-
-## Return value
-
-Whatever the script `return`s becomes the workflow result delivered to the coordinator (via task notification). Prefer structured objects:
-
-```js
-return { confirmed, dropped, stats: { found: seen.size } }
-```
-
-Subagents should return **raw data** (or schema objects), not user essays — the coordinator narrates.
-
-## Real-world example (implement → review → repair → verify)
-
-Condensed from a session script:
-
-```js
-export const meta = {
- name: 'implement-workflow-foundation',
- description: 'Implement and verify durable workflow foundation',
- phases: [
- { title: 'Implement', detail: 'build store and orchestrator', model: 'sonnet' },
- { title: 'Review', detail: 'audit correctness and tests' },
- { title: 'Repair', detail: 'apply verified fixes', model: 'sonnet' },
- { title: 'Verify', detail: 'run full validation' },
- ],
-}
-
-phase('Implement')
-const implementation = await agent(`…implementation prompt…`, {
- label: 'implement:durable-foundation',
- phase: 'Implement',
- effort: 'medium',
- agentType: 'claude',
-})
-
-phase('Review')
-const FINDINGS = { /* JSON Schema */ }
-const reviews = await parallel([
- () => agent(`…persistence audit…\n${implementation}`, {
- label: 'review:persistence', phase: 'Review', schema: FINDINGS, effort: 'medium', agentType: 'claude',
- }),
- () => agent(`…correctness audit…\n${implementation}`, {
- label: 'review:correctness', phase: 'Review', schema: FINDINGS, effort: 'medium', agentType: 'claude',
- }),
- () => agent(`…test quality audit…\n${implementation}`, {
- label: 'review:tests', phase: 'Review', schema: FINDINGS, effort: 'low', agentType: 'claude',
- }),
-]).then(xs => xs.filter(Boolean))
-
-phase('Repair')
-const repair = await agent(`…fix from ${JSON.stringify(reviews)}…`, {
- label: 'repair:review-findings', phase: 'Repair', effort: 'medium', agentType: 'claude',
-})
-
-phase('Verify')
-const verification = await agent(`…gates…`, {
- label: 'verify:full-gates', phase: 'Verify', effort: 'low', agentType: 'claude',
-})
-
-return { implementation, reviews, repair, verification }
-```
-
-## Next
-
-- [Primitives overview](./primitives.md)
-- [agent()](./agent.md)
diff --git a/docs/dynamic-workflow/claude/usecases.md b/docs/dynamic-workflow/claude/usecases.md
deleted file mode 100644
index c6735f5d..00000000
--- a/docs/dynamic-workflow/claude/usecases.md
+++ /dev/null
@@ -1,180 +0,0 @@
-# Use cases
-
-Workloads that were awkward or unreliable as a single flat agent loop, and how dynamic workflows fit them. Pair with [patterns](./patterns.md) and [orchestration](./orchestration.md).
-
-## Comprehensive code review
-
-**Goal:** High confidence that findings are real before the user acts.
-
-**Shape:**
-
-```text
-scout diff → dimensions (security, correctness, tests, perf)
- → (pipeline) per-dimension findings
- → adversarial / multi-lens verify per finding
- → return survivors only
-```
-
-**Why workflow:** Verification is not optional prose — it is stages. Vote count scales with “thoroughly audit” vs “any issues.”
-
-**Primitives:** `pipeline`, `parallel`, `schema`, higher `effort` on judges.
-
----
-
-## Large migrations / refactors
-
-**Goal:** Touch many call sites without stomping edits or losing progress.
-
-**Shape:**
-
-```text
-discover sites → pipeline(site → transform → local verify)
- isolation: 'worktree' on mutators
- resume after fixing one stage’s prompt
-```
-
-**Why workflow:** One context cannot hold hundreds of site-specific tool traces. Prefix resume avoids redoing finished sites when the transform prompt improves.
-
-**Primitives:** `pipeline`, `isolation: 'worktree'`, `resumeFromRunId`, `log` for skipped tails.
-
----
-
-## Research & multi-source synthesis
-
-**Goal:** Broad coverage then deep reading then a cited synthesis.
-
-**Shape:**
-
-```text
-multi-modal sweep (parallel angles)
- → merge/dedup hits
- → deep-read top sources (pipeline)
- → completeness critic
- → synthesize
-```
-
-**Why workflow:** Sweeps are embarrassingly parallel; synthesis needs the merged set (barrier). Budget bounds open-ended browsing.
-
-**Primitives:** `parallel`, barrier merge, `budget`, critic `agent`.
-
----
-
-## Design exploration
-
-**Goal:** Explore a wide solution space without anchoring on the first idea.
-
-**Shape:**
-
-```text
-N drafts from different angles (parallel)
- → score panel (parallel)
- → synthesize winner + graft runners-up
-```
-
-**Why workflow:** Single-thread iteration biases early. Independent drafts + structured scores beat one long chat.
-
-**Primitives:** judge panel pattern, `schema` for design objects, high effort on synthesis.
-
----
-
-## Unknown-size bug / issue hunts
-
-**Goal:** Keep finding until the map is dry, not until an arbitrary count.
-
-**Shape:**
-
-```text
-loop-until-dry:
- parallel finders → dedup vs seen → multi-lens judge → accumulate confirmed
-```
-
-**Why workflow:** `while (n < 10)` misses the tail; dry rounds + `seen` set converge. Budget optional hard stop.
-
-**Primitives:** loops, `parallel`, `Set` dedup, `budget.total && …`.
-
----
-
-## Self-repair implementation
-
-**Goal:** Ship a change with independent review pressure, not self-congratulation.
-
-**Shape:**
-
-```text
-implement → parallel reviewers (schema findings)
- → repair agent applies real issues
- → verify gates (typecheck/tests)
-```
-
-**Why workflow:** Separation of implementer and reviewers; structured findings; deterministic phase order.
-
-**Primitives:** sequential `phase`s, `parallel` reviewers, schema, medium/low effort mix.
-
-**Example skeleton:** [script contract](./script-contract.md).
-
----
-
-## Heterogeneous agent fleets
-
-**Goal:** Specialists for map / edit / audit under one plan.
-
-**Shape:**
-
-```text
-explorer agentType (read-only map)
- → implementer agentType (edits, maybe worktree)
- → reviewer agentType (schema audit)
-```
-
-**Why workflow:** `agentType` + model/effort per stage without the user manually jockeying three chats.
-
-**Primitives:** `agentType`, `model`/`effort` overrides, nested `workflow` for reusable specialist packs.
-
----
-
-## Phased product delivery under ultracode
-
-**Goal:** Maximum exhaustiveness for multi-day product work with human checkpoints.
-
-**Shape:**
-
-```text
-turn 1: Understand workflow
-turn 2: Design workflow
-turn 3: Implement+repair workflow
-turn 4: Review/audit workflow
-```
-
-**Why workflow:** Standing opt-in; each workflow is a well-scoped fan-out; coordinator synthesizes between turns.
-
-**Primitives:** full stack + [lifecycle](./lifecycle.md) multi-phase.
-
----
-
-## What this feature deliberately is not
-
-| Not | Because |
-|---|---|
-| Free-form multi-agent chat room | Workers do not negotiate the plan with each other |
-| Silent always-on multi-agent | Cost; requires [opt-in](./opt-in.md) / ultracode |
-| Multi-day durable external job system | Resume is session-oriented prefix replay, not external leases |
-| Replacement for small tasks | Overhead of scripting + fleet is real; use single Agent or inline tools |
-
----
-
-## Choosing a shape quickly
-
-| Symptom | Reach for |
-|---|---|
-| Many independent units | `pipeline` or `parallel` fan-out |
-| “I’m not sure we covered it” | multi-modal sweep + completeness critic |
-| “Findings feel flaky” | adversarial / multi-lens verify |
-| “Solution space is wide” | judge panel |
-| “Don’t know how many exist” | loop-until-dry |
-| “Parallel edits conflict” | `isolation: 'worktree'` |
-| “Reran everything after a prompt tweak” | `resumeFromRunId` + stable prefix |
-
-## Next
-
-- [Cheatsheet](./cheatsheet.md)
-- [README index](./README.md)
diff --git a/docs/dynamic-workflow/claude/workflow-tool.md b/docs/dynamic-workflow/claude/workflow-tool.md
deleted file mode 100644
index b43a40ee..00000000
--- a/docs/dynamic-workflow/claude/workflow-tool.md
+++ /dev/null
@@ -1,139 +0,0 @@
-# Workflow tool API
-
-The model-facing tool name is **`Workflow`** (alias **`RunWorkflow`**).
-
-- **Search hint:** orchestrate subagents with deterministic JavaScript workflow
-- **Execution:** background — tool returns immediately with a task id
-- **Completion:** `` when the script finishes
-- **Live progress:** `/workflows`
-
-## When to use the tool (product intent)
-
-A workflow structures work across many agents to be:
-
-- **Comprehensive** — decompose and cover in parallel
-- **Confident** — independent perspectives and adversarial checks before committing
-- **Scalable** — migrations, audits, broad sweeps that one context cannot hold
-
-The script encodes structure: what fans out, what verifies, what synthesizes.
-
-Control flow should be **deterministic** (loops, conditionals, fan-out in code) rather than re-decided free-form by the model mid-orchestration.
-
-Common single-phase shapes (chain across turns for larger work):
-
-| Phase | Pattern |
-|---|---|
-| Understand | parallel readers over subsystems → structured map |
-| Design | judge panel of N approaches → scored synthesis |
-| Review | dimensions → find → adversarially verify |
-| Research | multi-modal sweep → deep-read → synthesize |
-| Migrate | discover sites → transform (worktree) → verify |
-
-See [opt-in](./opt-in.md) for permission to call this tool.
-
-## Input fields
-
-At least one of `script`, `name`, or `scriptPath` is required.
-
-| Field | Type | Role |
-|---|---|---|
-| `script` | string (optional, length-bounded) | Inline self-contained workflow script. Must begin with pure-literal `export const meta = { name, description, phases }`. **Preferred on first invocation** — do not Write a file first. |
-| `name` | string (optional) | Predefined workflow: built-in or from `.claude/workflows/`. Resolves to a full script. |
-| `scriptPath` | string (optional) | Path to a script on disk. Every invocation **persists** its script under the session directory and returns the path. Iterate with Write/Edit + re-invoke. **Takes precedence** over `script` and `name`. |
-| `args` | any (optional) | Exposed to the script as global `args`, **verbatim**. Pass real JSON arrays/objects — **not** a JSON-encoded string (stringified lists break `args.map` / `args.filter`). |
-| `resumeFromRunId` | string `^wf_[a-z0-9-]{6,}$` (optional) | Prior run id. Unchanged prefix of `agent()` calls replays from cache; first edited/new call and everything after runs live. Same-session only. **Stop the prior run first** before resuming. |
-| `description` | string (optional) | **Ignored** — set description in script `meta`. |
-| `title` | string (optional) | **Ignored** — set title/name in script `meta`. |
-
-### First run
-
-```js
-Workflow({
- script: `
-export const meta = {
- name: 'review-changes',
- description: 'Review and adversarially verify findings',
- phases: [
- { title: 'Review' },
- { title: 'Verify' },
- ],
-}
-// ... body using agent/pipeline/parallel ...
-return { confirmed }
-`,
- args: { files: ['src/auth.ts', 'src/session.ts'] },
-})
-```
-
-### Iterate without resending the full script
-
-```js
-// Edit the returned scriptPath via Write/Edit, then:
-Workflow({
- scriptPath: returnedScriptPath,
- resumeFromRunId: runId, // optional: reuse cached agent() prefix
- args: { files: ['src/auth.ts', 'src/session.ts'] },
-})
-```
-
-### Named workflow
-
-```js
-Workflow({
- name: 'review-changes',
- args: { topic: 'authentication' },
-})
-```
-
-## Return envelope (conceptual)
-
-The tool launches asynchronously. A typical success-shaped result includes:
-
-```ts
-{
- status: 'async_launched' | 'remote_launched',
- taskId: string,
- taskType?: 'local_workflow' | 'remote_agent',
- workflowName?: string, // meta.name
- runId?: string, // for resumeFromRunId (local)
- transcriptDir?: string, // subagent transcripts + journal.jsonl
- scriptPath?: string, // persisted script for this invocation
- summary?: string,
- sessionUrl?: string, // when remote_launched
- warning?: string, // non-blocking heads-up
- error?: string, // e.g. syntax check failed
-}
-```
-
-Notes:
-
-- `runId` is the handle for [resume](./resume.md).
-- `scriptPath` is the handle for iteration without resending `script`.
-- `transcriptDir` holds per-agent logs and `journal.jsonl` (actual agent return values).
-- Remote launches may use `sessionUrl` instead of local `runId` as the resume handle.
-
-## Resolution order (engine behavior)
-
-Conceptually the engine resolves input as:
-
-1. If `scriptPath` → load (and optionally pair with inline `script` for built-in match checks).
-2. Else if `name` → resolve from built-ins / `.claude/workflows/`.
-3. Else if `script` → use inline body.
-4. Else → validation error: must provide script, name, or scriptPath.
-
-## Relationship to the single Agent tool
-
-| | `Agent` tool | `Workflow` tool |
-|---|---|---|
-| Count | One subagent (or a few manual launches) | Many, under a script graph |
-| Control flow | Model re-decides each turn | Script encodes loops/fan-out |
-| Structured multi-stage | Manual | `pipeline` / `parallel` + schema |
-| Cost risk | Lower | Higher — gated by opt-in |
-| Resume of a multi-step graph | Limited | Prefix-cached by agent call identity |
-
-Use `Agent` for isolated one-offs. Use `Workflow` when the **structure** of multi-agent work must be reliable.
-
-## Next
-
-- [Script contract](./script-contract.md)
-- [Primitives](./primitives.md)
diff --git a/docs/dynamic-workflow/devspace/plan.md b/docs/dynamic-workflow/devspace/plan.md
deleted file mode 100644
index 4a73627f..00000000
--- a/docs/dynamic-workflow/devspace/plan.md
+++ /dev/null
@@ -1,369 +0,0 @@
-# DevSpace Dynamic Workflow Engine — Plan
-
-Builds on the locked bigger-model plan. Scope = **this worktree only**.
-Subagents stay **CLI-only**. Workflows get **CLI + MCP** over shared primitives.
-
----
-
-## 0. Non-goals / locks
-
-| Lock | Meaning |
-|---|---|
-| No MCP `agent_run` / `agent_wait` / `agent_show` | Subagent feature surface remains `devspace agents *` (+ skill + shell). |
-| Workflow workers call adapters **in-process** | `runLocalAgentProvider` / same registry as CLI worker. No shell-out to `agents run` for `agent()`. |
-| No dashboard v1 | Events via store drain + CLI `--follow` / MCP status long-poll. |
-| CC script API parity | `meta`, `agent`, `parallel`, `pipeline`, `phase`, `log`, `args`, `budget`, `workflow` + determinism bans. |
-| Yolo sub-agents | Fixed write-capable adapter policy; **no** `writeMode` on `agent()`. |
-| `isolation: 'worktree'` | **Must-have** on `agent()` (CC-like); default shared checkout. |
-| `effort` (not `thinking`) | Profiles, CLI, store, adapters, `agent()` opts — rename across stack. |
-| `budget` stub v1 | `{ total: null, spent: () => 0, remaining: () => Infinity }`. |
-| Dual surface | `devspace workflow *` **and** MCP `run_workflow` / `workflow_status` / `workflow_cancel`. |
-| All 6 providers v1 | codex/claude/opencode/pi/cursor/copilot via existing adapters. |
-| Provider policy | Runtime uses currently available providers in stable product order. Durable provider policy and onboarding are deferred. |
-| Resume-by-replay right after engine core | Same milestone order as locked plan. |
-
----
-
-## 1. Control planes (do not conflate)
-
-```
-A) One-shot subagents (existing, unchanged API)
- host/shell → devspace agents run|show|ls
- → detached __worker → adapters → local_agent_sessions
-
-B) Dynamic workflows (new)
- host MCP / CLI → run row + spawn workflow __worker
- → sandboxed script
- → agent() → adapters (in-process)
- → workflow_* tables (not local_agent_sessions)
-```
-
-**Implication:** `devspace agents ls` does **not** list workflow-spawned agents. Observability = workflow events + `workflow_agent_calls`. Optional later dual-write — not v1.
-
----
-
-## 2. Architecture
-
-```
-┌─ CLI: workflow run|status|cancel|ls ─┐ ┌─ MCP: run_workflow|status|cancel ─┐
-│ parse / create run / spawn │ │ same primitives via workflow-tools │
-└──────────────────┬───────────────────┘ └──────────────────┬────────────────┘
- ▼ │
- WorkflowStore (SQLite WAL) ◄────────────────────────┘
- │
- │ detached: node cli.js workflow __worker
- ▼
- workflow-engine + sandbox + api
- │
- │ agent() [semaphore]
- ▼
- runLocalAgentProvider(provider, input) ← existing adapters
- │
- ▼
- journal: events + agent_calls (+ schema retries)
-```
-
-Server/CLI = **launcher + journal reader**. Worker owns execution, heartbeat, cancel watch, self group-kill.
-
----
-
-## 3. Accept bigger plan as-is (core)
-
-Keep their file split (flat `src/`):
-
-| Module | Role |
-|---|---|
-| `workflow-script.ts` | meta extract + wrap + `vm.Script` |
-| `workflow-sandbox.ts` | context, determinism bans, console→log |
-| `workflow-store.ts` | runs / events / agent_calls / cancel / reap |
-| `workflow-api.ts` | agent/parallel/pipeline/phase/log/args/budget/workflow + semaphore |
-| `workflow-engine.ts` | execute + `__worker` guts |
-| `workflow-replay.ts` | resume cache |
-| `workflow-schema.ts` | Ajv + retries |
-| `workflow-files.ts` | named + persist scriptPath |
-| `workflow-tools.ts` | MCP registration |
-| `skills/dynamic-workflows/SKILL.md` | teaching |
-
-DB migration **v4** (v3 = `local_agent_sessions` ✓).
-Tables: `workflow_runs`, `workflow_events`, `workflow_agent_calls` as specified.
-Spawn pattern copy `spawnAgentWorker` (detached, stdio ignore, unref).
-
-API semantics: keep their CC-parity table (throws vs parallel→null, pipeline stages, ALS for phase, nested workflow depth 1, budget stub).
-
-MCP contracts + yield windows: keep (status max ~110s matches `MAX_POLL_YIELD_MS`).
-
-Milestones 1→8: keep order and verifiability.
-
----
-
-## 4. Refinements / deltas on the bigger plan
-
-### 4.1 Explicit separation from subagent CLI
-
-In SKILL + serverInstructions + tool descriptions:
-
-- Workflows = multi-agent **graphs**.
-- One-off second opinions = still `devspace agents run` (CLI/skill).
-- Do **not** tell models to implement workflows by shelling many `agents run` when `run_workflow` exists.
-
-### 4.2 `agent()` backend = adapters, not CLI
-
-```ts
-// conceptual
-runProvider({ provider, prompt, workspace, model, effort, providerSessionId? })
- → runLocalAgentProvider(provider, { prompt, workspace, writeMode: "allowed", model, effort, providerSessionId? })
-```
-
-- Schema retries reuse `providerSessionId` when adapter returns it (codex/claude path).
-- Do not create `local_agent_sessions` rows per call (avoids polluting `agents ls`, simpler cancel).
-- If product later wants unified list, add a flag — not v1.
-- `workspace` is either shared `workspaceRoot` or a managed worktree path when `opts.isolation === 'worktree'`.
-
-### 4.3 Provider resolution now; policy later
-
-Current experimental runtime:
-
-- Probe provider availability at execution time.
-- Resolve `opts.provider` → `meta.defaultProvider` → first available provider
- in stable product order.
-- Keep probe timestamps and unavailable reasons in diagnostics only; do not
- persist them in user configuration.
-- Unknown or unavailable explicit providers fail that `agent()` call.
-
-The final onboarding release may add an ordered array of provider policy
-objects with `id`, `enabled`, `defaultModel`, and `defaultEffort`. That contract
-is deliberately deferred so the workflow stack does not publish an unfinished
-configuration shape.
-
-### 4.4 Skills gating fix (required, not optional)
-
-Bundled `subagents` and `dynamic-workflows` skills remain package-managed.
-User/project copies win on name collision. Setup does not copy bundled skills
-into `~/.devspace/skills`, which prevents generated copies from shadowing later
-package updates. The legacy `subagent-delegation` name is suppressed.
-
-### 4.5 MCP vs CLI symmetry
-
-| Op | CLI | MCP |
-|---|---|---|
-| Start | `workflow run --file\|--name\|--resume` | `run_workflow` |
-| Poll | `status --follow` | `workflow_status` long-poll |
-| Cancel | `cancel` | `workflow_cancel` |
-| List | `ls` | (optional later; status by id enough v1) |
-
-Same store. Detached worker survives MCP session death (critical acceptance test).
-
-### 4.6 Replay: document deliberate CC divergence
-
-CC: longest unchanged **call-index** prefix.
-v1: index+key, then **consume-once cacheKey** fallback (fan-out completion order).
-
-Document in SKILL under Resume. Do not pretend full CC resume identity.
-
-### 4.7 Sandbox choice
-
-Locked: `node:vm` + shadow Date/Math + no require/process/fetch/timers.
-Host wall-clock max (default 6h).
-Not SES (not in this tree; avoid new heavy dep). Accept vm is not a security boundary for hostile multi-tenant — DevSpace is single-user local.
-
-### 4.8 Cancel / kill
-
-1. `cancelRequested` flag.
-2. Worker heartbeat (5s) → AbortController + journal `run_cancelled` + group SIGTERM.
-3. Hard path after ≤5s: `terminateProcessTree` pid shim (existing `process-platform`).
-
-Known: in-flight adapter SDKs may not abort cleanly; group-kill is the backstop (already accepted).
-
-### 4.9 Pi timeout
-
-Document `PI_AGENT_TIMEOUT_MS = 120_000` in SKILL. Follow-up: make configurable — not milestone blocker.
-
-### 4.10 Script authoring feedback
-
-`run_workflow` / CLI parse **before** spawn. Syntax/meta errors return cheat-sheet snippet (tool desc + error). Line numbers preserved via export-strip + lineOffset.
-
-### 4.11 Concurrency
-
-`min(16, max(1, os.availableParallelism()-2))`, clamp by `meta.concurrency` if set. Semaphore gates **`agent()` only** (not pure JS stages).
-
-### 4.12 Named workflows paths
-
-1. `/.devspace/workflows/.js`
-2. `~/.devspace/workflows/.js` (via config dir helper used by profiles)
-
-Name: `[a-z0-9-]+`. Persist exact source to `/workflows/runs/.js` for resume/edit.
-
-### 4.13 `workflow()` nest
-
-Same run, shared journal/semaphore/call counter, depth ≤ 1. Resolve name via `workflow-files`. No new process.
-
-### 4.14 package.json
-
-- Direct dep: `ajv`
-- Tests: append new `*.test.ts` to existing per-file tsx chain
-- Node engines already `>=22.19` (ok for `availableParallelism`)
-
-### 4.15 Docs location
-
-Keep design notes under `docs/dynamic-workflow/devspace/` (this plan + later runtime notes). Claude reference stays under `docs/dynamic-workflow/claude/`.
-
-### 4.16 `effort` rename (profiles + agent stack)
-
-| Today | Target |
-|---|---|
-| Profile `thinking:` | `effort:` |
-| CLI `--thinking` | `--effort` (+ short deprecation alias optional) |
-| DB/store `thinking` | `effort` (rename column in new mig or dual-read) |
-| `LocalAgentRunInput.thinking` | `effort` |
-| Workflow `agent()` opts | `effort` only |
-| Replay cache key | includes `effort` |
-
-Provider-native strings pass through unchanged.
-
-### 4.17 `isolation: 'worktree'` (must-have)
-
-- Opt-in per call: `agent(prompt, { isolation: 'worktree', … })`.
-- Default: shared `workspaceRoot`.
-- Create under `config.worktreeRoot` / existing git-worktrees helpers; pin base SHA at run start.
-- Adapter `cwd` = worktree path.
-- Clean success → auto-remove; dirty/fail/cancel → preserve + journal `worktreePath`.
-- **No** auto-merge into source.
-- Non-git workspace → throw.
-- Cache key includes `isolation`.
-- Module touch: extend `workflow-api` + small worktree helper (wrap `git-worktrees.ts`).
-- Skill: use for parallel mutators only.
-
-### 4.18 Milestone impact
-
-| Milestone | Extra |
-|---|---|
-| **3 Engine** | `isolation` path with fake/temp git repos in tests |
-| **4 Worker+CLI** | real worktree create/cleanup; journal fields |
-| **5 Resume** | cache key includes isolation |
-| **8 Teach** | skill isolation + effort; document deferred provider policy |
-| Cross-cutting | rename `thinking`→`effort` in profile/CLI/store/adapters (can land with M3–4) |
-| Config | Keep provider availability runtime-only until final onboarding. |
-
----
-
-## 5. Script API (v1 contract — implement exactly)
-
-```js
-export const meta = {
- name: '…',
- description: '…',
- phases: [{ title: '…', detail?: '…' }],
- // devspace-only:
- defaultProvider?: 'codex'|'claude'|…,
- concurrency?: number,
-}
-
-phase('Review')
-const rows = await parallel([
- () => agent(p1, { provider: 'claude', label: 'r1', effort: 'high', schema: S }),
- () => agent(p2, { provider: 'codex', label: 'r2', schema: S }),
-])
-const mut = await agent(implPrompt, {
- provider: 'codex',
- isolation: 'worktree', // parallel-safe writes
- schema: DiffSummary,
-})
-const out = await pipeline(items, stage1, stage2)
-log('…')
-// args, budget (stub), workflow(name, args?)
-return { … }
-```
-
-Determinism bans: `Date.now`, `Math.random`, argless `new Date` → `WorkflowDeterminismError`.
-
----
-
-## 6. Milestones (same spine, sharper exit criteria)
-
-| # | Deliverable | Done when |
-|---|---|---|
-| **1 Journal** | schema + mig v4 + store + tests | create/append/drain/reap unit green |
-| **2 Script/sandbox** | parse + vm + bans | meta edge cases + line nos + bans green |
-| **3 Engine core** | api+engine, fake provider | semaphore, parallel null, pipeline no-barrier, phase ALS, nest depth |
-| **4 Worker+CLI** | router, spawn, heartbeat, cancel, files | `--follow` log-only + 1 real provider; kill -9 → reap; cancel → group empty |
-| **5 Resume** | replay + `--resume` | cancel mid-run; resume shows cached prefix events |
-| **6 Schema** | ajv enforce + retries | bad JSON → schema_retry → success/exhaust |
-| **7 MCP** | 3 tools + server wiring | Inspector: run+status; **kill MCP, worker still finishes** |
-| **8 Teach** | skill, seed, skills.ts fix, instructions | fresh + pre-seeded config both advertise skill |
-
-E2E: `npm test` + `npm run typecheck`; live fan-out 2 providers CLI; same MCP; cancel+resume.
-
----
-
-## 7. Mapping to existing code (touch list)
-
-| Existing | Use |
-|---|---|
-| `local-agent-adapters.ts` / `runLocalAgentProvider` | `agent()` backend |
-| `local-agent-availability.ts` | provider pick / error text |
-| `local-agent-store.ts` | **pattern only** (not dual-write) |
-| `cli.ts` `spawnAgentWorker` / `agents __worker` | copy for `workflow __worker` |
-| `process-platform.terminateProcessTree` | hard cancel |
-| `db/client` WAL + busy_timeout 5000 | multi-process journal |
-| `server.ts` `registerAppTool` + workflow capability gate | tools only if workflows are enabled |
-| `skills.ts` | independent package-managed skill gates |
-| `process-sessions` yield bounds | MCP status yield caps |
-
----
-
-## 8. Risk register (accepted + one process risk)
-
-| Risk | Mitigation |
-|---|---|
-| Adapter no abort | group-kill worker |
-| Daemonizing child escapes group | document; SIGTERM+adapter finally |
-| Pi 120s cap | SKILL note |
-| Replay key fallback ≠ CC | document |
-| Laptop sleep heartbeat false fail | `kill(pid,0)` before reap |
-| Host model still shells `agents run` for graphs | skill + tool cheat-sheet steer to `run_workflow` |
-| Long MCP poll vs proxy timeouts | yield ≤110s; client re-calls status |
-
----
-
-## 9. What we explicitly do **not** build in v1
-
-- MCP tools for raw subagents
-- Dashboard / live TUI
-- Real token `budget` tied to host
-- `writeMode` on `agent()` (isolation **is** in scope)
-- Auto-merge of agent worktrees into source checkout
-- Auto file-change / diff events per stage
-- Declaring DAG JSON alternate API (script is the API)
-- Dual-write to `local_agent_sessions`
-- SES lockdown
-
----
-
-## 10. Implementation order for a coding agent
-
-1. Mig + store (no behavior risk).
-2. Script + sandbox (pure).
-3. Engine against fakes (locks API).
-4. Wire CLI worker to real adapters.
-5. Replay.
-6. Schema.
-7. MCP.
-8. Skill/docs/gating.
-
-Do not open MCP before CLI smoke — debug path must work headless without a host.
-
----
-
-## Resolved questions (see also [primitives-spec.md](./primitives-spec.md))
-
-1. **Default provider:** `opts.provider` → `meta.defaultProvider` → first live provider in stable product order. Final provider defaults and enablement are deferred to onboarding finalization.
-2. **writeMode:** **not in v1 API**; skill teaches prompt-based RO/write.
-3. **Isolation:** **`isolation?: 'worktree'` is v1 must-have** on `agent()`; default shared; no auto-merge.
-4. **Effort rename:** `thinking` → **`effort`** across profiles, CLI, store, adapters, `agent()` opts, cache keys.
-5. **MCP list:** skip; **CLI** `workflow ls` yes.
-6. **Size caps:** transport/storage bounds (§8 of primitives-spec); not “coverage” truncation.
-7. **Nested workflow:** CC-like `name | { scriptPath }`, depth 1, shared journal/semaphore.
-8. **Cancel:** cooperative flag → then group-kill.
-
-**File-change tracking:** out of scope.
-**Schema:** `opts.schema` + Ajv + retries — in scope.
diff --git a/docs/dynamic-workflow/devspace/primitives-spec.md b/docs/dynamic-workflow/devspace/primitives-spec.md
deleted file mode 100644
index 219408f3..00000000
--- a/docs/dynamic-workflow/devspace/primitives-spec.md
+++ /dev/null
@@ -1,795 +0,0 @@
-# DevSpace Dynamic Workflow — Primitives & API Spec
-
-Implementation + contract spec for every surface, inspired by Claude Code’s Workflow environment.
-Pairs with [plan.md](./plan.md). Subagents remain CLI-only; this document is **workflow only**.
-
----
-
-## 0. Product goals (locks)
-
-| Goal | Surface |
-|---|---|
-| DW for coding agents that lack Workflow (pi, codex, opencode, cursor, …) | **CLI + skill** — host agent authors script, runs `devspace workflow *` |
-| ChatGPT as orchestrator, not implementer | **MCP workflow tools** behind the workflow capability gate — plan + `run_workflow` / status / cancel |
-| Ship both in dev | One engine; two entrypoints; converge later on performance/UX |
-
-```
-coding agent ── skill + CLI ──► engine ── agent() ──► adapters
-ChatGPT ── MCP tools ──► engine ── agent() ──► adapters
-```
-
----
-
-## 1. Resolved decisions
-
-| # | Topic | Decision |
-|---|---|---|
-| 1 | Default provider | Runtime: `opts.provider` → `meta.defaultProvider` → first currently available provider in stable product order. Final provider policy is deferred. |
-| 2 | Access / writeMode | **Not in v1 API.** No `writeMode`. Skill teaches **prompt-based** RO vs write. Isolation handles *where* writes land (see isolation). |
-| 3 | List runs | **No MCP list tool v1.** **CLI** `devspace workflow ls` yes. |
-| 4 | Size caps | Soft/hard bounds on journal + results (§8). |
-| 5 | Nested `workflow()` | CC-inspired: `name \| { scriptPath }`, depth 1, shared journal/semaphore (§7.8). |
-| 6 | Cancel | Cooperative flag → worker abort → hard `terminateProcessTree` (§9). |
-| 7 | **`effort` rename** | Profile frontmatter, CLI (`--effort`), store column, runtime input, and `agent()` opts use **`effort`** (not `thinking`). Adapters map `effort` → provider-native flags. |
-| 8 | **`isolation`** | **Must-have v1** on `agent()`: `opts.isolation?: 'worktree'`. Shared checkout default; worktree when set (§7.1, §7.1b). |
-| — | File-change tracking | Out of scope. Shared disk / worktree is truth; no auto per-stage diff. |
-| — | Structured output | **In scope:** `opts.schema` + Ajv + retries (§7.1). |
-
----
-
-## 2. Claude Code inspiration map
-
-| CC concept | CC behavior (model-facing) | DevSpace v1 |
-|---|---|---|
-| `Workflow` tool | Host tool; async; script/name/scriptPath/args/resume | CLI `workflow run` + MCP `run_workflow` |
-| `export const meta` | Pure literal; name, description, phases | Same + optional `defaultProvider`, `concurrency` |
-| `agent(prompt, opts)` | Spawn worker; string or schema object; null on skip/death in combinators | Same return contract; **throw** on failure; `parallel` → null |
-| `opts.schema` | StructuredOutput / validated object | Ajv enforce + retry in engine |
-| `opts.model` / `effort` | Tier/effort overrides | `model` + **`effort`** (renamed from `thinking`; provider passthrough) |
-| `opts.isolation: 'worktree'` | Per-agent worktree | **v1 must-have** — same semantics, DevSpace-managed worktrees |
-| Access / sandbox | Session permission mode; not `writeMode` on agent() | Prompt RO/write + **isolation for write containment** |
-| `pipeline` | No barrier; per-item chains | Same |
-| `parallel` | Barrier; null slots | Same |
-| `phase` / `log` | Progress UX | Journal events + CLI follow / MCP drain |
-| `args` | Verbatim tool args | Same |
-| `budget` | Shared host token hard ceiling | **Stub** `{ total: null, spent:0, remaining: Infinity }` |
-| `workflow()` | Nested name/scriptPath; depth 1; shared caps | Same spirit |
-| Determinism bans | Date.now / Math.random / bare new Date | Same |
-| Resume | Prefix cache by prompt+opts | Deterministic call-index prefix only (first miss closes replay) |
-| File diffs per stage | **Not a primitive** | Same — no auto-diff |
-
----
-
-## 3. Provider availability now; policy after finalization
-
-### Current experimental contract
-
-There is no user-facing `agentProviders` block and no
-`DEVSPACE_AGENT_PROVIDERS` environment variable. DevSpace probes implemented
-providers at runtime, keeps availability details in memory, and orders usable
-providers by `LOCAL_AGENT_PROVIDERS`:
-
-```text
-codex → claude → opencode → pi → cursor → copilot
-```
-
-`devspace init` does not configure providers. `devspace doctor` may report live
-availability but remains read-only. Probe timestamps and unavailable-provider
-reasons are diagnostics, not durable user intent.
-
-Default resolution is:
-
-```text
-explicit agent() provider
- → workflow meta.defaultProvider
- → first currently available provider
-```
-
-An explicit provider or profile whose harness is unavailable fails with a clear
-typed error. Direct `devspace agents` calls and workflow `agent()` calls use the
-same target resolver.
-
-### Deferred final provider policy
-
-When Subagents and Dynamic Workflows are finalized and incorporated into
-onboarding, the intended durable shape is an ordered array of user choices:
-
-```ts
-interface AgentProviderPolicy {
- id: AgentProviderId
- enabled: boolean
- defaultModel?: string
- defaultEffort?: string
-}
-
-interface DevspaceUserConfig {
- // ...existing fields...
- agentProviders?: AgentProviderPolicy[]
-}
-```
-
-Array order can define fallback preference. Resolution will then be:
-
-```text
-call model/effort override
- → profile model/effort
- → provider defaultModel/defaultEffort
- → provider-native defaults
-```
-
-Availability snapshots still must not be persisted inside this policy. The
-onboarding, config commands, documentation, and provider-management UI should
-land together rather than exposing another intermediate configuration shape.
----
-
-## 4. Entry surfaces
-
-### 4.1 CLI
-
-```
-devspace workflow run (--file | --name | --resume )
- [--arg key=value]... [--follow]
-devspace workflow status [--follow]
-devspace workflow cancel
-devspace workflow ls
-devspace workflow __worker # hidden
-```
-
-| Flag | Spec |
-|---|---|
-| `--file` | Read script from path (must be under allowed roots when policy applies). |
-| `--name` | Resolve via [§6 named files](#6-script-sources). |
-| `--resume` | New run row; replay journal from prior runId. |
-| `--arg k=v` | Build `args` object (values: JSON-parse if possible else string). |
-| `--follow` | Drain events until terminal; print log/phase/agent lines. |
-
-Spawn: same pattern as `agents __worker` (detached, stdio ignore, unref). Inputs only from run row.
-
-### 4.2 MCP (togglable with the workflow capability)
-
-| Tool | Input | Output (conceptual) |
-|---|---|---|
-| `run_workflow` | `workspaceId`, `script?` \| `name?` \| `resumeFromRunId?`, `args?`, `yieldTimeMs?` | `{ runId, status, events, nextSeq, result? }` after parse+spawn+short yield |
-| `workflow_status` | `runId`, `sinceSeq?`, `yieldTimeMs?` | long-poll events / terminal |
-| `workflow_cancel` | `runId` | `{ runId, status }` |
-
-**No** `workflow_ls` on MCP v1.
-**No** `agent_*` MCP tools.
-
-Tool description embeds ~25-line API cheat-sheet (CC-style education in-band).
-
-### 4.3 Skill
-
-`skills/dynamic-workflows/SKILL.md` (package-managed; not copied on init):
-
-- When to use CLI vs when host is ChatGPT (MCP).
-- Full primitive reference.
-- Prompt patterns for read-only vs write (instead of writeMode).
-- Provider list / default fallback.
-- Schema examples, resume, cancel, 3 worked examples.
-
----
-
-## 5. Script contract
-
-### 5.1 Shape
-
-```js
-export const meta = {
- name: 'review-auth',
- description: 'Fan-out review of auth changes',
- phases: [
- { title: 'Review', detail: 'parallel reviewers' },
- { title: 'Synthesize' },
- ],
- // DevSpace extensions (optional):
- defaultProvider: 'codex',
- concurrency: 4,
-}
-
-// body — async IIFE context
-phase('Review')
-// ...
-return { summary }
-```
-
-### 5.2 `meta` rules (CC + DS)
-
-| Rule | Spec |
-|---|---|
-| First statement | `export const meta = {…}` |
-| Pure literal | No vars, calls, spreads, templates in meta object |
-| Required | `name`, `description` |
-| Optional CC | `phases[]` `{ title, detail? }`, `whenToUse?` |
-| Optional DS | `defaultProvider?`, `concurrency?` (clamped to engine max) |
-| Validation | Zod `WorkflowMetaSchema` + JSON round-trip purity |
-| Extract | Regex start + balanced-brace scanner; `vm.runInNewContext('('+literal+')')` |
-
-### 5.3 Transform pipeline (`workflow-script.ts`)
-
-1. Extract/validate meta.
-2. Strip leading `export ` → 7 spaces (preserve line numbers).
-3. Reject stray `import` / top-level `export` after meta.
-4. Wrap:
-
-```js
-(async ({ agent, parallel, pipeline, phase, log, args, budget, workflow, meta, console }) => {
- // user body
-})
-```
-
-5. `new vm.Script(wrapped, { filename: 'workflow:'+name, lineOffset: -1 })`.
-6. Friendly errors: missing meta, syntax (with line), purity fail.
-
-### 5.4 Language bans (CC)
-
-| Banned in script | Behavior |
-|---|---|
-| `Date.now()` | `WorkflowDeterminismError` |
-| `Math.random()` | same |
-| argless `new Date()` | same |
-| `require` / `process` / `fetch` / timers | not in context |
-| TypeScript syntax | parse fail |
-
-Allowed: normal JS, `JSON`, `Array`, `Map`, `Set`, `Date.parse`, `new Date(isoString)`.
-
-`console.log/warn/error` → `log` events.
-
----
-
-## 6. Script sources
-
-| Source | Resolution |
-|---|---|
-| Inline (`--file` content / MCP `script`) | Persist to `/workflows/runs/.js` |
-| Named (`--name` / MCP `name`) | (1) `/.devspace/workflows/.js` (2) `~/.devspace/workflows/.js` |
-| Resume | Load persisted path on prior run (user may edit that copy) |
-
-Name sanitization: `^[a-z0-9-]+$`.
-Run row stores `scriptPath`, `scriptHash`, `source: inline|named`.
-
----
-
-## 7. Primitives (spec + implementation)
-
-All injected into the sandbox. Host deps: `{ journal, runProvider, availableProviders, replay?, concurrency, signal, workspaceRoot }`.
-
----
-
-### 7.1 `agent(prompt, opts?)`
-
-#### Spec (public)
-
-```ts
-type AgentOpts = {
- label?: string
- phase?: string // overrides current ALS phase for this call
- schema?: object // JSON Schema → validated object return
- model?: string
- effort?: string // was "thinking"; provider-native effort/reasoning level
- provider?: string // DevSpace; default via §3
- isolation?: "worktree" // must-have; omit = shared workspace root
- // NO writeMode in v1
-}
-
-function agent(prompt: string, opts?: AgentOpts): Promise
-// with schema → Promise