feat(workflow): run and resume workflows from the CLI - #97
Conversation
Named/file script resolve, agent worktree factory, resume matcher (index+key then consume-once), and Ajv schema enforcement wired into agent(). Adds ajv dependency. Co-Authored-By: Claude <noreply@anthropic.com>
Detached __worker with heartbeat/cancel, real adapters via runLocalAgentProvider, worktree isolation, and resume wiring. setScriptPath persists script after run create. Co-Authored-By: Claude <noreply@anthropic.com>
Always include bundled skills root when subagents enabled so seeding subagent-delegation no longer hides later skills. Seed dynamic-workflows alongside subagent-delegation on init. Co-Authored-By: Claude <noreply@anthropic.com>
Load ordered enable-list from config/env, probe available providers on init and doctor, and filter workflow CLI providers by enabled∩live. Co-Authored-By: Claude <noreply@anthropic.com>
Gate on config.subagents. run_workflow spawns the same detached worker as CLI; status long-polls journal events; cancel requests cooperative stop. Co-Authored-By: Claude <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| }); | ||
|
|
||
| const persisted = | ||
| priorScriptPath ?? |
There was a problem hiding this comment.
[P0] Resume reuses the prior mutable script path and does not verify that the new run is in the same repository/workspace/base SHA. This can replay repository A in B, and prior.scriptHash can disagree with edited bytes executed later. Snapshot the exact validated source under the new run ID and require a matching repository identity/base revision (or an explicit override) before replay.
There was a problem hiding this comment.
Partially addressed by stacked PR #108 (c8f0b65). Resume now reads the selected source, recomputes its hash, persists a fresh per-run script snapshot, updates the new run to that snapshot path, and the worker executes those exact bytes. That fixes the mutable prior-path / stale scriptHash half of this finding. The repository identity half is still open: resume does not require matching workspaceId/workspaceRoot/baseSha, so cross-workspace replay is still possible. Keeping this thread unresolved for that remaining check.
There was a problem hiding this comment.
The mutable-source/hash half was addressed in #108, and PR #116 completes the replay contract with exact return-value persistence plus deterministic same-index prefix reuse. Mandatory workspace/repository identity matching is intentionally not added: runId and resume are designed to remain usable from Cursor, Pi, OpenCode, CLI, and other harnesses that do not own a DevSpace workspace ID. Project-local workflow path confinement is handled separately in the next follow-up rather than through workspace-ID authorization.
| console.log(formatRunLine(run)); | ||
| if (run.pid && (run.status === "running" || run.status === "starting")) { | ||
| try { | ||
| process.kill(run.pid, "SIGTERM"); |
There was a problem hiding this comment.
[P0] Sending SIGTERM immediately after setting the cooperative flag usually kills the worker before it can observe cancellation, clean up worktrees, or write terminal events. Please centralize CLI/MCP cancellation in a supervisor: request cancel, wait a grace period, then use the cross-platform terminateProcessTree fallback and atomically mark the run cancelled. The supervisor should also schedule reapStale().
There was a problem hiding this comment.
Addressed by follow-up PR #115 (15be40e, 5a7a3db). CLI cancellation now uses the shared lifecycle supervisor: set the cooperative flag, wait a grace period, terminate the detached process tree through the cross-platform helper, escalate to SIGKILL when necessary, and atomically mark the run cancelled as a fallback. The server also schedules stale-worker reaping.
| } | ||
| } | ||
|
|
||
| store.completeRun(runId, { resultJson }); |
There was a problem hiding this comment.
[P1] The run becomes completed before run_completed is appended. A status poll can observe terminal state and stop before the terminal event exists. Please update terminal status and append the corresponding terminal event in one SQLite transaction; use the same path for failed and cancelled runs.
There was a problem hiding this comment.
Addressed by follow-up PR #115 (dfbf5a1). Completed, failed, and cancelled transitions now update the run row and append the matching terminal event inside one immediate SQLite transaction. Pollers can no longer observe terminal status before its terminal event exists.
| function toHit(call: WorkflowAgentCallRecord): WorkflowReplayHit { | ||
| if (call.structuredJson) { | ||
| try { | ||
| return { |
There was a problem hiding this comment.
[P0] Replay restores only the previous return value; it does not recreate filesystem side effects or reconnect the preserved worktree. A cached mutating agent can report success while the new run contains none of its changes. Please make mutating calls non-cacheable by default, or persist/apply a patch or resume the exact worktree as part of the replay contract.
There was a problem hiding this comment.
Addressed by follow-up PR #116 (57229cb, d12fc43). Resume now reuses only the longest unchanged same-index call prefix. The first mismatch closes replay for every later call. Worktree-isolated calls are explicitly non-replayable until DevSpace can restore their exact worktree, so a cached success can no longer stand in for absent worktree changes. Shared-checkout calls retain Claude Code-like prefix behavior and assume their filesystem effects remain in the checkout.
Wire LocalAgentRunInput.schema through CodexSdkLocalAgentRuntime to thread.run turn options, and surface parsed structured output.
Pass JSON Schema via outputFormat on query options and prefer structured_output from result messages. OpenCode stays prompt-path only.
Hardcode NATIVE_SCHEMA_PROVIDERS; attempt 0 uses adapter schema without prompt bloat, then prompt-repair retries with Ajv. Wire schema through runProvider / CLI worker. Document in skill.
refactor(agents): unify provider resolution and subagent guidance
feat(workflow): support agent profiles and project workflows
fix(workflow): replay deterministic call prefixes
fix(workflow): supervise cancellation and terminal lifecycle
feat(workflow): isolate workflow script execution
feat(ui): live workspace and workflow dashboards
feat(workflow): read-only project workflow TUI
feat(workflow): script iteration, replay provenance, and call inspection
refactor(workflow): model operational failures with better-result
refactor(workflow): strengthen contracts and zod boundaries
feat(agents): native schema for codex/claude agent({ schema })
feat(workflow): MCP tools, skill, agentProviders
The engine from #96 was only an in-process API. Users still needed a durable way to resolve scripts, launch runs independently of the initiating shell, inspect or cancel them later, isolate agent changes, resume prior work, and request structured output.
Add named and file-based script resolution, per-call workflow worktrees, the initial replay implementation, and JSON Schema enforcement for
agent()results. A detached CLI worker now owns run execution and heartbeat state, whileworkflow run,status,cancel, andlsprovide the first user-facing lifecycle controls.Stack
Based on #96 and merged into #94 before the MCP and skill integration in #98.