Skip to content

Commit 8ce8274

Browse files
authored
Merge pull request #116 from pr/dw-14-prefix-replay-integrity
fix(workflow): replay deterministic call prefixes
2 parents 0b52e5e + b677c3e commit 8ce8274

57 files changed

Lines changed: 2133 additions & 987 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/chatgpt-coding-workflow.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,17 @@ DevSpace discovers standard Agent Skills from:
8585
- project `.agents/skills`
8686
- `~/.devspace/skills`
8787

88-
It also keeps compatibility with:
88+
It also includes:
8989

90-
- the bundled `subagent-delegation` skill when `DEVSPACE_SUBAGENTS=1`, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists
90+
- the package-managed `subagents` skill when the Subagents capability is enabled
91+
- the package-managed `dynamic-workflows` skill when the Dynamic Workflows capability is enabled
9192
- `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills`
9293
- additional paths from `DEVSPACE_SKILL_PATHS`
9394

9495
When Subagents are enabled, DevSpace discovers agent profiles
9596
from `~/.devspace/agents/*.md` and project `.devspace/agents/*.md`.
9697
`open_workspace` exposes a compact catalog with profile names, descriptions,
97-
providers, and optional models/thinking levels so the model can choose a configured agent
98+
providers, and optional models/effort levels so the model can choose a configured agent
9899
without seeing provider-specific launch details.
99100

100101
Example profiles are packaged under `examples/agents/` for users who want
@@ -113,10 +114,15 @@ Skill paths may be outside the workspace. DevSpace only permits reading:
113114

114115
Set `DEVSPACE_SKILLS=0` to hide skills from workspace output. Set
115116
`DEVSPACE_SUBAGENTS=1` to expose the experimental subagent catalog and
116-
`subagent-delegation` skill. That skill teaches the minimal
117-
`devspace agents ls`, `devspace agents run`, and `devspace agents show`
118-
workflow. The catalog comes from `open_workspace`; `devspace agents ls` lists
119-
existing subagent sessions for that workspace.
117+
`subagents` skill. That skill can use target information already supplied by the
118+
host or discover it with `devspace agents targets`. `devspace agents ls` lists
119+
existing subagent sessions for the current workspace.
120+
121+
Set `DEVSPACE_WORKFLOWS=1` to enable Dynamic Workflows independently. When the
122+
variable is omitted, Dynamic Workflows follows the effective Subagents setting,
123+
including persisted config and any environment override. Disabled features are
124+
omitted from the `open_workspace` schema and response rather than returned as
125+
empty capability arrays.
120126

121127
## Tool Names
122128

docs/configuration.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ sessions.
9393
| --- | --- |
9494
| `DEVSPACE_SKILLS` | Set to `0` to hide skills. Enabled by default. |
9595
| `DEVSPACE_SUBAGENTS` | Set to `1` to expose configured agent profiles as Subagents. Experimental and disabled by default. |
96+
| `DEVSPACE_WORKFLOWS` | Experimental Dynamic Workflows gate. When unset, it follows the effective Subagents setting, including persisted config and any environment override. |
9697
| `DEVSPACE_AGENT_DIR` | Defaults to `~/.codex`; its `skills` child is loaded for compatibility. |
9798
| `DEVSPACE_SKILL_PATHS` | Optional comma-separated additional skill directories. |
9899

@@ -102,25 +103,35 @@ DevSpace discovers standard Agent Skills from:
102103
- project `.agents/skills`
103104
- `~/.devspace/skills`
104105

105-
It also keeps compatibility with:
106+
It also includes:
106107

107-
- the bundled `subagent-delegation` skill when `DEVSPACE_SUBAGENTS=1`, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists
108+
- the package-managed `subagents` skill when the Subagents capability is enabled
109+
- the package-managed `dynamic-workflows` skill when the Dynamic Workflows capability is enabled
108110
- `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills`
109111
- additional paths from `DEVSPACE_SKILL_PATHS`
110112

113+
User and project skills with the same name take precedence over bundled skills.
114+
DevSpace does not copy bundled skills into `~/.devspace/skills` during setup.
115+
111116
When Subagents are enabled, DevSpace discovers agent profiles
112117
from:
113118

114119
- `~/.devspace/agents/*.md`
115120
- project `.devspace/agents/*.md`
116121

117122
`open_workspace` returns a compact catalog containing profile names,
118-
descriptions, providers, and optional models/thinking levels so the host model can choose an
123+
descriptions, providers, and optional models/effort levels so the host model can choose an
119124
agent without reading provider-specific launch details. `devspace agents ls`
120125
lists existing subagent sessions for the current workspace, scoped by the
121-
workspace environment injected into shell commands. The `subagent-delegation`
122-
skill teaches the model to use only the minimal `devspace agents ls`,
123-
`devspace agents run`, and `devspace agents show` workflow.
126+
workspace environment injected into shell commands. The `subagents`
127+
skill teaches the model to discover targets with `devspace agents targets`,
128+
then use the minimal `devspace agents run`, `devspace agents show`, and
129+
`devspace agents ls` workflow.
130+
131+
Provider availability is detected at runtime. DevSpace does not persist probe
132+
timestamps, availability snapshots, or an experimental provider enable-list in
133+
`config.json`. Final provider policy and onboarding are deferred until the
134+
Subagents and Dynamic Workflows features are finalized.
124135

125136
Starter profile templates are available under `examples/agents/`. Copy or adapt
126137
them into one of the active profile directories before use.

docs/dynamic-workflow/devspace/plan.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Subagents stay **CLI-only**. Workflows get **CLI + MCP** over shared primitives.
1919
| `budget` stub v1 | `{ total: null, spent: () => 0, remaining: () => Infinity }`. |
2020
| Dual surface | `devspace workflow *` **and** MCP `run_workflow` / `workflow_status` / `workflow_cancel`. |
2121
| All 6 providers v1 | codex/claude/opencode/pi/cursor/copilot via existing adapters. |
22-
| `agentProviders.enabled` | Ordered config from onboarding; default provider = first enabled ∩ live. |
22+
| Provider policy | Runtime uses currently available providers in stable product order. Durable provider policy and onboarding are deferred. |
2323
| Resume-by-replay right after engine core | Same milestone order as locked plan. |
2424

2525
---
@@ -119,28 +119,28 @@ runProvider({ provider, prompt, workspace, model, effort, providerSessionId? })
119119
- If product later wants unified list, add a flag — not v1.
120120
- `workspace` is either shared `workspaceRoot` or a managed worktree path when `opts.isolation === 'worktree'`.
121121

122-
### 4.3 Provider resolution + config
122+
### 4.3 Provider resolution now; policy later
123123

124-
Config add (see primitives-spec §3):
124+
Current experimental runtime:
125125

126-
```ts
127-
agentProviders?: {
128-
enabled: AgentProviderId[] // order = preference; [0] = default
129-
detectedAt?: string
130-
lastProbe?: Array<{ id, available, detail? }>
131-
}
132-
```
126+
- Probe provider availability at execution time.
127+
- Resolve `opts.provider``meta.defaultProvider` → first available provider
128+
in stable product order.
129+
- Keep probe timestamps and unavailable reasons in diagnostics only; do not
130+
persist them in user configuration.
131+
- Unknown or unavailable explicit providers fail that `agent()` call.
133132

134-
Algorithm: `opts.provider``meta.defaultProvider` → first of `enabled ∩ liveAvailable`.
135-
Missing `agentProviders` → compat all-available in code order.
136-
Onboarding (`init`/`doctor`) probes PATH and writes `enabled`.
137-
Unknown/unavailable: fail that `agent()` (throw → parallel null).
133+
The final onboarding release may add an ordered array of provider policy
134+
objects with `id`, `enabled`, `defaultModel`, and `defaultEffort`. That contract
135+
is deliberately deferred so the workflow stack does not publish an unfinished
136+
configuration shape.
138137

139138
### 4.4 Skills gating fix (required, not optional)
140139

141-
Today `effectiveSkillPaths` drops **entire** bundled dir if user has seeded `subagent-delegation` — hides any new bundled skill.
142-
143-
v1: include bundled **per-skill** (user copy wins on name collision). Seed `dynamic-workflows` in `user-config` next to subagent skill.
140+
Bundled `subagents` and `dynamic-workflows` skills remain package-managed.
141+
User/project copies win on name collision. Setup does not copy bundled skills
142+
into `~/.devspace/skills`, which prevents generated copies from shadowing later
143+
package updates. The legacy `subagent-delegation` name is suppressed.
144144

145145
### 4.5 MCP vs CLI symmetry
146146

@@ -240,9 +240,9 @@ Provider-native strings pass through unchanged.
240240
| **3 Engine** | `isolation` path with fake/temp git repos in tests |
241241
| **4 Worker+CLI** | real worktree create/cleanup; journal fields |
242242
| **5 Resume** | cache key includes isolation |
243-
| **8 Teach** | skill isolation + effort; seed `agentProviders` docs |
243+
| **8 Teach** | skill isolation + effort; document deferred provider policy |
244244
| Cross-cutting | rename `thinking``effort` in profile/CLI/store/adapters (can land with M3–4) |
245-
| Config | `agentProviders` on user-config + init probe (with M4 or M8) |
245+
| Config | Keep provider availability runtime-only until final onboarding. |
246246

247247
---
248248

@@ -305,8 +305,8 @@ E2E: `npm test` + `npm run typecheck`; live fan-out 2 providers CLI; same MCP; c
305305
| `cli.ts` `spawnAgentWorker` / `agents __worker` | copy for `workflow __worker` |
306306
| `process-platform.terminateProcessTree` | hard cancel |
307307
| `db/client` WAL + busy_timeout 5000 | multi-process journal |
308-
| `server.ts` `registerAppTool` + `config.subagents` gate | tools only if subagents on |
309-
| `skills.ts` / `user-config.ts` | gate fix + seed |
308+
| `server.ts` `registerAppTool` + workflow capability gate | tools only if workflows are enabled |
309+
| `skills.ts` | independent package-managed skill gates |
310310
| `process-sessions` yield bounds | MCP status yield caps |
311311

312312
---
@@ -356,7 +356,7 @@ Do not open MCP before CLI smoke — debug path must work headless without a hos
356356

357357
## Resolved questions (see also [primitives-spec.md](./primitives-spec.md))
358358

359-
1. **Default provider:** `opts.provider``meta.defaultProvider` → first of **onboarding-configured** `agentProviders.enabled` ∩ live available. Full config schema in primitives-spec §3.
359+
1. **Default provider:** `opts.provider``meta.defaultProvider` → first live provider in stable product order. Final provider defaults and enablement are deferred to onboarding finalization.
360360
2. **writeMode:** **not in v1 API**; skill teaches prompt-based RO/write.
361361
3. **Isolation:** **`isolation?: 'worktree'` is v1 must-have** on `agent()`; default shared; no auto-merge.
362362
4. **Effort rename:** `thinking`**`effort`** across profiles, CLI, store, adapters, `agent()` opts, cache keys.
@@ -366,4 +366,4 @@ Do not open MCP before CLI smoke — debug path must work headless without a hos
366366
8. **Cancel:** cooperative flag → then group-kill.
367367

368368
**File-change tracking:** out of scope.
369-
**Schema:** `opts.schema` + Ajv + retries — in scope.
369+
**Schema:** `opts.schema` + Ajv + retries — in scope.

docs/dynamic-workflow/devspace/primitives-spec.md

Lines changed: 47 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Pairs with [plan.md](./plan.md). Subagents remain CLI-only; this document is **w
1010
| Goal | Surface |
1111
|---|---|
1212
| DW for coding agents that lack Workflow (pi, codex, opencode, cursor, …) | **CLI + skill** — host agent authors script, runs `devspace workflow *` |
13-
| ChatGPT as orchestrator, not implementer | **MCP workflow tools** (togglable with subagents) — plan + `run_workflow` / status / cancel |
13+
| ChatGPT as orchestrator, not implementer | **MCP workflow tools** behind the workflow capability gate — plan + `run_workflow` / status / cancel |
1414
| Ship both in dev | One engine; two entrypoints; converge later on performance/UX |
1515

1616
```
@@ -24,7 +24,7 @@ ChatGPT ── MCP tools ──► engine ── agent() ──► adapter
2424

2525
| # | Topic | Decision |
2626
|---|---|---|
27-
| 1 | Default provider | **Configured enabled provider list** (onboarding auto-detect CLIs → `config.json`). Runtime: `opts.provider``meta.defaultProvider`**first entry of enabled+available list**. |
27+
| 1 | Default provider | Runtime: `opts.provider``meta.defaultProvider` → first currently available provider in stable product order. Final provider policy is deferred. |
2828
| 2 | Access / writeMode | **Not in v1 API.** No `writeMode`. Skill teaches **prompt-based** RO vs write. Isolation handles *where* writes land (see isolation). |
2929
| 3 | List runs | **No MCP list tool v1.** **CLI** `devspace workflow ls` yes. |
3030
| 4 | Size caps | Soft/hard bounds on journal + results (§8). |
@@ -60,136 +60,66 @@ ChatGPT ── MCP tools ──► engine ── agent() ──► adapter
6060

6161
---
6262

63-
## 3. Config: agent providers (what to add)
63+
## 3. Provider availability now; policy after finalization
6464

65-
### Today (`DevspaceUserConfig` / `.devspace/config.json`)
65+
### Current experimental contract
6666

67-
Existing fields (unchanged conceptually):
67+
There is no user-facing `agentProviders` block and no
68+
`DEVSPACE_AGENT_PROVIDERS` environment variable. DevSpace probes implemented
69+
providers at runtime, keeps availability details in memory, and orders usable
70+
providers by `LOCAL_AGENT_PROVIDERS`:
6871

69-
```ts
70-
// src/user-config.ts — today
71-
interface DevspaceUserConfig {
72-
host?: string
73-
port?: number
74-
allowedRoots?: string[]
75-
publicBaseUrl?: string | null
76-
allowedHosts?: string[]
77-
stateDir?: string
78-
worktreeRoot?: string
79-
agentDir?: string
80-
subagents?: boolean // master switch only
81-
}
72+
```text
73+
codex → claude → opencode → pi → cursor → copilot
74+
```
75+
76+
`devspace init` does not configure providers. `devspace doctor` may report live
77+
availability but remains read-only. Probe timestamps and unavailable-provider
78+
reasons are diagnostics, not durable user intent.
79+
80+
Default resolution is:
81+
82+
```text
83+
explicit agent() provider
84+
→ workflow meta.defaultProvider
85+
→ first currently available provider
8286
```
8387

84-
There is **no** persisted enable-list. Runtime exposes every implemented provider that is **currently on PATH** (`getLocalAgentProviderAvailabilitySnapshot`). Order is code order of `LOCAL_AGENT_PROVIDERS`, not user preference. No onboarding write-back.
88+
An explicit provider or profile whose harness is unavailable fails with a clear
89+
typed error. Direct `devspace agents` calls and workflow `agent()` calls use the
90+
same target resolver.
8591

86-
### Add: `agentProviders` on user config
92+
### Deferred final provider policy
93+
94+
When Subagents and Dynamic Workflows are finalized and incorporated into
95+
onboarding, the intended durable shape is an ordered array of user choices:
8796

8897
```ts
89-
/** Known built-in ids — keep in sync with LocalAgentProvider */
90-
type AgentProviderId =
91-
| "codex"
92-
| "claude"
93-
| "opencode"
94-
| "pi"
95-
| "cursor"
96-
| "copilot"
97-
98-
interface AgentProvidersConfig {
99-
/**
100-
* Ordered enable-list. Order = preference.
101-
* index 0 = default fallback for agent() when provider omitted.
102-
* Only ids in this list may be used by workflows/subagents (if present).
103-
* Missing/empty → fall back to "all currently available" (compat) OR
104-
* require init (prefer: treat missing as "auto = all available in code order").
105-
*/
106-
enabled: AgentProviderId[]
107-
108-
/** ISO time of last successful probe (init/doctor). Optional. */
109-
detectedAt?: string
110-
111-
/**
112-
* Optional last probe snapshot for doctor UI (not required at runtime).
113-
* Do not use as source of truth for enablement — `enabled` is.
114-
*/
115-
lastProbe?: Array<{
116-
id: AgentProviderId
117-
available: boolean
118-
detail?: string // path or error
119-
}>
98+
interface AgentProviderPolicy {
99+
id: AgentProviderId
100+
enabled: boolean
101+
defaultModel?: string
102+
defaultEffort?: string
120103
}
121104

122105
interface DevspaceUserConfig {
123-
// ...existing...
124-
subagents?: boolean
125-
agentProviders?: AgentProvidersConfig // NEW
126-
}
127-
```
128-
129-
### Example `~/.devspace/config.json`
130-
131-
```json
132-
{
133-
"host": "127.0.0.1",
134-
"port": 7676,
135-
"allowedRoots": ["/home/you/work"],
136-
"subagents": true,
137-
"agentProviders": {
138-
"enabled": ["codex", "claude", "opencode", "pi"],
139-
"detectedAt": "2026-07-21T12:00:00.000Z",
140-
"lastProbe": [
141-
{ "id": "codex", "available": true, "detail": "/usr/bin/codex" },
142-
{ "id": "claude", "available": true, "detail": "/home/you/.local/bin/claude" },
143-
{ "id": "opencode", "available": true },
144-
{ "id": "pi", "available": true },
145-
{ "id": "cursor", "available": false, "detail": "not found" },
146-
{ "id": "copilot", "available": false, "detail": "not found" }
147-
]
148-
}
106+
// ...existing fields...
107+
agentProviders?: AgentProviderPolicy[]
149108
}
150109
```
151110

152-
### Semantics
111+
Array order can define fallback preference. Resolution will then be:
153112

154-
| Concern | Spec |
155-
|---|---|
156-
| **Master switch** | `subagents: true` still required for workflow tools + agent CLI + skills. |
157-
| **Enable-list** | `agentProviders.enabled` is the only user-facing allowlist. |
158-
| **Order** | First entry = default `agent()` provider after availability filter. |
159-
| **Live ∩ config** | `candidates = enabled.filter(id => currentlyAvailable(id))`. Stale enable of uninstalled CLI → skipped with doctor warning, not hard-fail until no candidates. |
160-
| **Unknown ids** | Reject on write/init; ignore-with-warn at read if config hand-edited. |
161-
| **Missing `agentProviders`** | Compat: `enabled` effective = all available in built-in order (today’s behavior). Init should still write the block. |
162-
| **Empty `enabled: []`** | Error at first `agent()` / `agents run`: “no providers enabled”. |
163-
| **Env override (optional)** | `DEVSPACE_AGENT_PROVIDERS=codex,claude` replaces `enabled` for process (ops/debug). |
164-
| **ServerConfig** | Load into `ServerConfig.agentProviders: { enabled: AgentProviderId[] }` resolved at boot. |
165-
166-
### Onboarding (`devspace init` / `doctor`)
167-
168-
1. Probe all six providers (reuse `local-agent-availability`).
169-
2. Set `enabled` = available ids in **stable product order**:
170-
`codex → claude → opencode → pi → cursor → copilot` (only those available).
171-
3. Write `detectedAt` + optional `lastProbe`.
172-
4. `doctor` re-probes; offers to refresh `enabled` (add newly installed; optionally keep user-disabled by not auto-re-adding removed ids — v1: refresh = rewrite available set, document that).
173-
174-
### Default provider algorithm
175-
176-
```
177-
resolveProvider(opts, meta, config):
178-
enabled = config.agentProviders?.enabled
179-
?? ALL_IMPLEMENTED_IN_CODE_ORDER
180-
candidates = enabled ∩ liveAvailable(PATH)
181-
if opts.provider:
182-
if opts.provider ∉ enabled → throw (disabled in config)
183-
if opts.provider ∉ liveAvailable → throw (not installed)
184-
return opts.provider
185-
if meta.defaultProvider:
186-
same checks against candidates
187-
return meta.defaultProvider
188-
if candidates[0] → return candidates[0]
189-
throw NoProviderError
113+
```text
114+
call model/effort override
115+
→ profile model/effort
116+
→ provider defaultModel/defaultEffort
117+
→ provider-native defaults
190118
```
191119

192-
Skill: “Pass `provider` when you care; else first enabled+available provider.”
120+
Availability snapshots still must not be persisted inside this policy. The
121+
onboarding, config commands, documentation, and provider-management UI should
122+
land together rather than exposing another intermediate configuration shape.
193123
---
194124

195125
## 4. Entry surfaces
@@ -215,7 +145,7 @@ devspace workflow __worker <runId> # hidden
215145

216146
Spawn: same pattern as `agents __worker` (detached, stdio ignore, unref). Inputs only from run row.
217147

218-
### 4.2 MCP (togglable with `config.subagents`)
148+
### 4.2 MCP (togglable with the workflow capability)
219149

220150
| Tool | Input | Output (conceptual) |
221151
|---|---|---|
@@ -230,7 +160,7 @@ Tool description embeds ~25-line API cheat-sheet (CC-style education in-band).
230160

231161
### 4.3 Skill
232162

233-
`skills/dynamic-workflows/SKILL.md` (+ seed on init):
163+
`skills/dynamic-workflows/SKILL.md` (package-managed; not copied on init):
234164

235165
- When to use CLI vs when host is ChatGPT (MCP).
236166
- Full primitive reference.

0 commit comments

Comments
 (0)