Skip to content

feat(workflow): add dynamic workflows - #94

Draft
Waishnav wants to merge 83 commits into
mainfrom
pr/dw-1-types-effort
Draft

feat(workflow): add dynamic workflows#94
Waishnav wants to merge 83 commits into
mainfrom
pr/dw-1-types-effort

Conversation

@Waishnav

@Waishnav Waishnav commented Jul 21, 2026

Copy link
Copy Markdown
Owner

DevSpace can invoke local agents one call at a time, but it has no durable orchestration layer for work that needs concurrency, nested calls, resumability, inspection, or cancellation. Long-running multi-agent tasks therefore depend on the chat session staying alive, and recovery after interruption or script edits is difficult to reason about.

This draft adds opt-in Dynamic Workflows: typed public contracts and limits; a SQLite journal for runs, events, and agent calls; restricted child-process script execution; CLI and MCP run, status, cancellation, and inspection surfaces; deterministic prefix replay with provenance; worktree isolation; lifecycle supervision; provider and profile selection; schema-aware outputs; and read-only TUI and MCP App dashboards. It also standardizes local-agent effort across profiles, adapters, storage, and CLI so workflows and direct subagent execution use the same provider model.

Stack

This PR is the merge vehicle for Dynamic Workflows. Review and land the remaining refinements in order: #119#120#121. Each PR is based on the previous one and should be merged into this branch before this PR targets main.

Dynamic Workflows remain experimental and opt-in through the existing agent capability gates.

Waishnav and others added 15 commits July 21, 2026 12:10
Add workflow-types contract module (statuses, AgentOpts, journal shapes,
cache key helper, budget stub, concurrency). Wire test into package.json.
Fix primitives-spec §13: isolation worktree is v1 must-have.

Co-Authored-By: Claude <noreply@anthropic.com>
Normalize LocalAgentRunInput, profiles, CLI, store, and adapters on
effort. CLI accepts --thinking as a one-release alias; profile YAML
thinking: still maps to effort. DB migration v4 renames the column.

Co-Authored-By: Claude <noreply@anthropic.com>
Update profile schema, examples, and subagent skill for effort. Note
legacy thinking alias and provider-native pi --thinking flag.

Co-Authored-By: Claude <noreply@anthropic.com>
Create workflow_runs, workflow_events, and workflow_agent_calls with
indexes. Effort rename remains v4; journal schema is v5.

Co-Authored-By: Claude <noreply@anthropic.com>
Create/claim/cancel/complete runs, monotonic event append+drain,
agent call lifecycle, and stale-worker reaping. Wire unit tests.

Co-Authored-By: Claude <noreply@anthropic.com>
Parse export const meta (pure literal), compile scripts as vm.Script,
and run them with banned Date.now/Math.random/bare new Date plus no
process/require/fetch. Rehydrate results into the host realm.

Co-Authored-By: Claude <noreply@anthropic.com>
agent/parallel/pipeline/phase/log/workflow primitives, semaphore,
ALS phase, isolation worktree hook, nest depth 1, and executeWorkflow
against injectable runProvider for unit tests.

Co-Authored-By: Claude <noreply@anthropic.com>
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>
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db17baaa-c984-4b64-a375-885709e92379

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr/dw-1-types-effort

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread src/workflow-types.ts Outdated
@Waishnav

Copy link
Copy Markdown
Owner Author

The primitive set is a strong read-oriented MVP, but I do not think the public contract should be called frozen yet. agent() -> string | object cannot represent reusable provider sessions, isolated workspace/worktree handoff, usage metadata, or typed failures. At minimum, please keep room for: configured profile/agentType, a settled-error mode, enforceable read-only/tool policy, per-call timeout, and a total workflow call cap. Reusable agent/workspace handles can be staged, but the v1 return contract should not foreclose them.

Waishnav and others added 12 commits July 21, 2026 22:55
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.
Waishnav added 9 commits July 27, 2026 20:34
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
feat(workflow): CLI worker, worktrees, resume, schema
feat(workflow): engine API with fakes
feat(workflow): journal store + script sandbox
Comment thread src/workflow-tools.ts
Comment on lines +166 to +167
} else if (scriptPath) {
const resolvedResult = await readWorkflowScriptFileResult(scriptPath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Unchecked workflow script path

When an authenticated MCP client supplies a scriptPath outside the selected workspace, the handler reads, persists, and executes that file without validating it against the workspace or allowed roots, allowing external workflow logic to run agents with write access to the selected workspace.

How this was verified: The caller-controlled path flows directly through readWorkflowScriptFileResult, whose generic reader resolves and reads it without a root or canonical-path check.

Comment thread src/workflow-tools.ts
Comment on lines +242 to +256
async ({ runId, sinceSeq, yieldTimeMs }) => {
const store = createWorkflowStore(config);
try {
const runResult = store.getRunResult(runId);
if (runResult.isErr()) throw runResult.error;
if (!runResult.value) throw new WorkflowNotFoundError(runId);
const page = await yieldEvents(store, runId, sinceSeq ?? 0, yieldTimeMs ?? 0);
return toolResult(page, "workflow_status");
} catch (error) {
if (isWorkflowOperationError(error)) return workflowToolError(error);
throw error;
} finally {
store.close();
}
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Unscoped workflow run access

When a client supplies a run ID created for another workspace, workflow_status retrieves that global record and workflow_cancel can cancel it without verifying workspace ownership, exposing the other run's status, result, or error and allowing cross-workspace cancellation.

How this was verified: Both handlers address the shared workflow store solely by runId and perform no comparison with the run's workspaceId or workspaceRoot.

@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces the Dynamic Workflow contracts and runtime while renaming local-agent reasoning configuration from thinking to effort.

  • Adds workflow parsing, sandbox execution, agent orchestration, replay, persistence, lifecycle management, CLI/MCP tools, worktree isolation, and UI views.
  • Adds workflow database migrations and freezes the public workflow types and limits.
  • Migrates agent profiles, adapters, sessions, CLI options, documentation, and examples to effort while retaining selected legacy aliases.
  • Adds package-managed subagent and dynamic-workflow skills plus provider capability discovery.

Confidence Score: 3/5

The PR should not merge until workflow script loading and run operations are constrained to the caller's authorized workspace.

The new MCP workflow surface permits unchecked filesystem paths to supply executable workflow source and uses globally addressable run identifiers for status and cancellation without workspace ownership validation.

Files Needing Attention: src/workflow-tools.ts, src/workflow-files.ts, src/workflow-store.ts

Security Review

Two workspace-boundary issues were identified: run_workflow can load scripts from unchecked filesystem paths, and status/cancel operations can address another workspace's run by its global identifier.

Important Files Changed

Filename Overview
src/workflow-tools.ts Adds the MCP workflow surface, but script paths and run-level operations are not consistently constrained to the selected workspace.
src/workflow-files.ts Adds source persistence and named/project workflow resolution; specialized project readers are scoped, while the generic script reader accepts unrestricted paths.
src/workflow-api.ts Implements workflow primitives, concurrency, replay journaling, profile resolution, schema enforcement, and worktree finalization with coherent lifecycle handling.
src/workflow-store.ts Adds the global SQLite workflow journal and state transitions; consumers must enforce workspace ownership when accessing runs.
src/workflow-cli.ts Adds detached workflow execution, lifecycle commands, provider invocation, replay, and follow-mode output.
src/db/migrations.ts Renames the local-agent thinking column to effort and adds the workflow run, event, call, replay, and profile-provenance schema.
src/workflow-types.ts Freezes workflow limits, records, options, event contracts, cache identity, and public runtime types.
src/server.ts Gates and registers workflow capabilities, exposes active workflow summaries, and integrates the workflow reaper and UI.
src/local-agent-resolution.ts Centralizes provider/profile selection and effort/model precedence for direct agents and workflows.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Client[MCP client] --> Tools[Workflow MCP tools]
  Tools --> Files[Script resolution and persistence]
  Files --> Worker[Detached workflow worker]
  Worker --> Sandbox[Workflow sandbox]
  Sandbox --> Agents[Local agent providers]
  Agents --> Workspace[Workspace or isolated worktree]
  Worker <--> Store[(Global workflow journal)]
  Tools <--> Store
Loading

Reviews (1): Last reviewed commit: "Merge pull request #95 from pr/dw-2-stor..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant