|
1 | 1 | # EPIC-09 Tasks: Orchestras — Dynamic Workflow Orchestration |
2 | 2 |
|
3 | | -> Status: NOT STARTED — created 2026-03-19 |
| 3 | +> Status: ~90% — backend implemented, frontend dashboard partial — updated 2026-03-19 |
4 | 4 |
|
5 | 5 | ## Phase 1: Foundation (Result + Secrets + Artifacts) |
6 | 6 |
|
7 | 7 | ### T09.1 Run Result (JSONB) |
8 | | -- [ ] Add `result JSONB` column to runs table (migration) |
9 | | -- [ ] `PATCH /runs/{id}/result` — set result (max 1MB, validates JSON) |
10 | | -- [ ] `GET /runs/{id}/result` — get result |
11 | | -- [ ] SDK: `set_result(run_id, data)` and `get_result(run_id)` in all 5 SDKs |
12 | | -- [ ] `CRONCONTROL_TRIGGERED_BY` env var injected when run is triggered by another run |
| 8 | +- [x] Add `result JSONB` column to runs table (migration) |
| 9 | +- [x] `PATCH /runs/{id}/result` — set result (max 1MB, validates JSON) |
| 10 | +- [x] `GET /runs/{id}/result` — get result |
| 11 | +- [x] SDK: `set_result(run_id, data)` and `get_result(run_id)` in all 5 SDKs |
| 12 | +- [x] `CRONCONTROL_TRIGGERED_BY` env var injected when run is triggered by another run |
13 | 13 |
|
14 | 14 | ### T09.2 Workspace Secrets Vault |
15 | | -- [ ] `workspace_secrets` table: id, workspace_id, name, value_enc (AES-256-GCM), created_at |
16 | | -- [ ] `GET /secrets` — list names only, never values |
17 | | -- [ ] `POST /secrets` — create (name + value, encrypted at rest) |
18 | | -- [ ] `PUT /secrets/{name}` — update value |
19 | | -- [ ] `DELETE /secrets/{name}` — delete |
| 15 | +- [x] `workspace_secrets` table: id, workspace_id, name, value_enc (AES-256-GCM), created_at |
| 16 | +- [x] `GET /secrets` — list names only, never values |
| 17 | +- [x] `POST /secrets` — create (name + value, encrypted at rest) |
| 18 | +- [x] `PUT /secrets/{name}` — update value |
| 19 | +- [x] `DELETE /secrets/{name}` — delete |
20 | 20 | - [ ] Dashboard: Settings > Secrets tab (list, create, delete, warning about one-time visibility) |
21 | | -- [ ] SDK: `create_secret`, `list_secrets`, `delete_secret` in all 5 SDKs |
| 21 | +- [x] SDK: `create_secret`, `list_secrets`, `delete_secret` in all 5 SDKs |
22 | 22 |
|
23 | 23 | ### T09.3 Run Artifacts (S3/MinIO + Local) |
24 | | -- [ ] `run_artifacts` table: id, run_id, workspace_id, name, content_type, size_bytes, storage_key |
25 | | -- [ ] Artifact storage backend interface: `Upload`, `Download`, `Delete`, `GetURL` |
26 | | -- [ ] S3/MinIO backend implementation |
27 | | -- [ ] Local filesystem backend (fallback) |
28 | | -- [ ] `POST /runs/{id}/artifacts` — upload (multipart) |
29 | | -- [ ] `GET /runs/{id}/artifacts` — list |
30 | | -- [ ] `GET /runs/{id}/artifacts/{name}` — download |
31 | | -- [ ] Config: `CC_ARTIFACTS_BACKEND`, `CC_ARTIFACTS_S3_ENDPOINT`, `CC_ARTIFACTS_S3_BUCKET`, etc. |
32 | | -- [ ] SDK: `upload_artifact`, `get_artifact_url`, `list_artifacts` in all 5 SDKs |
| 24 | +- [x] `run_artifacts` table: id, run_id, workspace_id, name, content_type, size_bytes, storage_key |
| 25 | +- [x] Artifact storage backend interface: `Upload`, `Download`, `Delete`, `GetURL` |
| 26 | +- [x] S3/MinIO backend implementation |
| 27 | +- [x] Local filesystem backend (fallback) |
| 28 | +- [x] `POST /runs/{id}/artifacts` — upload (multipart) |
| 29 | +- [x] `GET /runs/{id}/artifacts` — list |
| 30 | +- [x] `GET /runs/{id}/artifacts/{name}` — download |
| 31 | +- [x] Config: `CC_ARTIFACTS_BACKEND`, `CC_ARTIFACTS_S3_ENDPOINT`, `CC_ARTIFACTS_S3_BUCKET`, etc. |
| 32 | +- [x] SDK: `upload_artifact`, `get_artifact_url`, `list_artifacts` in all 5 SDKs |
33 | 33 |
|
34 | 34 | ## Phase 2: Orchestra Core |
35 | 35 |
|
36 | 36 | ### T09.4 Orchestra Table & Lifecycle |
37 | | -- [ ] `orchestras` table: id, workspace_id, name, director_type, director_process_id, ai_config, state, movement_count, secrets, summary, parent_orchestra_id, wait_for_parent, budget, budget_used, timeout, timeout_at, created_at, updated_at |
38 | | -- [ ] Orchestra states: active, waiting_for_choice, paused, completed, cancelled, failed |
39 | | -- [ ] `POST /orchestras` — create (name, director, first_musician, secrets, timeout, budget) |
40 | | -- [ ] `GET /orchestras` — list (filter by state) |
41 | | -- [ ] `GET /orchestras/{id}` — get metadata |
42 | | -- [ ] `GET /orchestras/{id}/score` — full score (all movements with results) |
43 | | -- [ ] `POST /orchestras/{id}/cancel` — cancel active orchestra |
44 | | -- [ ] Add `orchestra_id`, `orchestra_step` columns to runs table (migration) |
45 | | -- [ ] SDK: `create_orchestra`, `get_score`, `cancel_orchestra` in all 5 SDKs |
| 37 | +- [x] `orchestras` table: id, workspace_id, name, director_type, director_process_id, ai_config, state, movement_count, secrets, summary, parent_orchestra_id, wait_for_parent, budget, budget_used, timeout, timeout_at, created_at, updated_at |
| 38 | +- [x] Orchestra states: active, waiting_for_choice, paused, completed, cancelled, failed |
| 39 | +- [x] `POST /orchestras` — create (name, director, first_musician, secrets, timeout, budget) |
| 40 | +- [x] `GET /orchestras` — list (filter by state) |
| 41 | +- [x] `GET /orchestras/{id}` — get metadata |
| 42 | +- [x] `GET /orchestras/{id}/score` — full score (all movements with results) |
| 43 | +- [x] `POST /orchestras/{id}/cancel` — cancel active orchestra |
| 44 | +- [x] Add `orchestra_id`, `orchestra_step` columns to runs table (migration) |
| 45 | +- [x] SDK: `create_orchestra`, `get_score`, `cancel_orchestra` in all 5 SDKs |
46 | 46 |
|
47 | 47 | ### T09.5 Next Movement (Dynamic Trigger) |
48 | | -- [ ] `POST /runs/{id}/next` — trigger next movement (process_id, payload, message) |
49 | | -- [ ] Creates new run with: orchestra_id, orchestra_step+1, triggered_by_run_id |
50 | | -- [ ] Inherits orchestra secrets as env vars |
51 | | -- [ ] Injects: `CRONCONTROL_ORCHESTRA_ID`, `CRONCONTROL_ORCHESTRA_STEP`, `CRONCONTROL_TRIGGERED_BY` |
52 | | -- [ ] Increments orchestra movement_count |
53 | | -- [ ] SDK: `next_movement(process_id, payload, message)` in all 5 SDKs |
| 48 | +- [x] `POST /runs/{id}/next` — trigger next movement (process_id, payload, message) |
| 49 | +- [x] Creates new run with: orchestra_id, orchestra_step+1, triggered_by_run_id |
| 50 | +- [x] Inherits orchestra secrets as env vars |
| 51 | +- [x] Injects: `CRONCONTROL_ORCHESTRA_ID`, `CRONCONTROL_ORCHESTRA_STEP`, `CRONCONTROL_TRIGGERED_BY` |
| 52 | +- [x] Increments orchestra movement_count |
| 53 | +- [x] SDK: `next_movement(process_id, payload, message)` in all 5 SDKs |
54 | 54 |
|
55 | 55 | ### T09.6 Director Auto-Trigger |
56 | | -- [ ] After movement completes/fails: if orchestra has a director, trigger it automatically |
57 | | -- [ ] Inject event env vars: `CRONCONTROL_EVENT_TYPE`, `CRONCONTROL_EVENT_RUN_ID`, `CRONCONTROL_EVENT_RESULT` |
58 | | -- [ ] Director process runs, reads event via `cc.get_event()`, decides next action |
59 | | -- [ ] SDK: `get_event()` (reads env vars, returns structured event) in all 5 SDKs |
60 | | -- [ ] If director_type=none: no auto-trigger (musicians chain directly) |
| 56 | +- [x] After movement completes/fails: if orchestra has a director, trigger it automatically |
| 57 | +- [x] Inject event env vars: `CRONCONTROL_EVENT_TYPE`, `CRONCONTROL_EVENT_RUN_ID`, `CRONCONTROL_EVENT_RESULT` |
| 58 | +- [x] Director process runs, reads event via `cc.get_event()`, decides next action |
| 59 | +- [x] SDK: `get_event()` (reads env vars, returns structured event) in all 5 SDKs |
| 60 | +- [x] If director_type=none: no auto-trigger (musicians chain directly) |
61 | 61 |
|
62 | 62 | ### T09.7 Ask Choice (Human-in-the-Loop) |
63 | | -- [ ] Add `choice_config JSONB`, `chosen_index INTEGER` columns to runs table |
64 | | -- [ ] Add `waiting_for_choice` run state + state machine transitions |
65 | | -- [ ] `POST /runs/{id}/choice` — set choice config (message + choices array) |
66 | | -- [ ] `POST /runs/{id}/choose` — human selects a choice (choice_index) |
67 | | -- [ ] On choose: if choice has process_id → trigger next movement; if null → finish/cancel |
68 | | -- [ ] Update orchestra state: active ↔ waiting_for_choice |
69 | | -- [ ] SDK: `ask_choice(run_id, message, choices)` and `ask_confirm(run_id, message, on_approve, on_reject)` in all 5 SDKs |
70 | | -- [ ] Dashboard RunDetail: show choice buttons when waiting_for_choice |
| 63 | +- [x] Add `choice_config JSONB`, `chosen_index INTEGER` columns to runs table |
| 64 | +- [x] Add `waiting_for_choice` run state + state machine transitions |
| 65 | +- [x] `POST /runs/{id}/choice` — set choice config (message + choices array) |
| 66 | +- [x] `POST /runs/{id}/choose` — human selects a choice (choice_index) |
| 67 | +- [x] On choose: if choice has process_id → trigger next movement; if null → finish/cancel |
| 68 | +- [x] Update orchestra state: active ↔ waiting_for_choice |
| 69 | +- [x] SDK: `ask_choice(run_id, message, choices)` and `ask_confirm(run_id, message, on_approve, on_reject)` in all 5 SDKs |
| 70 | +- [x] Dashboard RunDetail: show choice buttons when waiting_for_choice |
71 | 71 |
|
72 | 72 | ### T09.8 Finish Orchestra |
73 | | -- [ ] `POST /orchestras/{id}/finish` — set state=completed, summary |
74 | | -- [ ] SDK: `finish_orchestra(orchestra_id, summary)` in all 5 SDKs |
75 | | -- [ ] Webhook event: `orchestra.completed` |
| 73 | +- [x] `POST /orchestras/{id}/finish` — set state=completed, summary |
| 74 | +- [x] SDK: `finish_orchestra(orchestra_id, summary)` in all 5 SDKs |
| 75 | +- [x] Webhook event: `orchestra.completed` |
76 | 76 |
|
77 | 77 | ## Phase 3: Chat System |
78 | 78 |
|
79 | 79 | ### T09.9 Orchestra Chat Table & API |
80 | | -- [ ] `orchestra_chat` table: id, orchestra_id, sender_type (system/director/musician/human), sender_id, message_type (text/result/request_help/action/choice/choice_response/file/status/warning), content, data JSONB, created_at |
81 | | -- [ ] `POST /orchestras/{id}/chat` — post message |
82 | | -- [ ] `GET /orchestras/{id}/chat` — list messages (pagination, since=timestamp) |
83 | | -- [ ] System messages auto-posted: movement started/completed/failed, budget warnings |
84 | | -- [ ] SDK: `post_chat(orchestra_id, message, type, data)` and `get_chat(orchestra_id, since)` in all 5 SDKs |
| 80 | +- [x] `orchestra_chat` table: id, orchestra_id, sender_type (system/director/musician/human), sender_id, message_type (text/result/request_help/action/choice/choice_response/file/status/warning), content, data JSONB, created_at |
| 81 | +- [x] `POST /orchestras/{id}/chat` — post message |
| 82 | +- [x] `GET /orchestras/{id}/chat` — list messages (pagination, since=timestamp) |
| 83 | +- [x] System messages auto-posted: movement started/completed/failed, budget warnings |
| 84 | +- [x] SDK: `post_chat(orchestra_id, message, type, data)` and `get_chat(orchestra_id, since)` in all 5 SDKs |
85 | 85 |
|
86 | 86 | ### T09.10 Chat Actions |
87 | | -- [ ] Actions field in chat messages: array of {label, action_name, params, style} |
88 | | -- [ ] `POST /orchestras/{id}/chat/{message_id}/action` — trigger an action |
89 | | -- [ ] When action triggered: creates a new run for the action handler OR triggers director with event |
90 | | -- [ ] SDK: `register_action(name, handler)` and `post_chat(..., actions=[...])` in all 5 SDKs |
| 87 | +- [x] Actions field in chat messages: array of {label, action_name, params, style} |
| 88 | +- [x] `POST /orchestras/{id}/chat/{message_id}/action` — trigger an action |
| 89 | +- [x] When action triggered: creates a new run for the action handler OR triggers director with event |
| 90 | +- [x] SDK: `register_action(name, handler)` and `post_chat(..., actions=[...])` in all 5 SDKs |
91 | 91 |
|
92 | 92 | ### T09.11 Real-Time Chat (SSE) |
93 | | -- [ ] `GET /orchestras/{id}/stream` — SSE endpoint |
94 | | -- [ ] Events: chat, movement, choice, state, budget_warning |
95 | | -- [ ] Dashboard: real-time chat panel on Score page |
96 | | -- [ ] Human input box: post text messages and click action buttons |
| 93 | +- [x] `GET /orchestras/{id}/stream` — SSE endpoint |
| 94 | +- [x] Events: chat, movement, choice, state, budget_warning |
| 95 | +- [x] Dashboard: real-time chat panel on Score page |
| 96 | +- [x] Human input box: post text messages and click action buttons |
97 | 97 |
|
98 | 98 | ## Phase 4: AI Director |
99 | 99 |
|
100 | 100 | ### T09.12 Multi-Model AI Director |
101 | | -- [ ] Built-in Go component: `internal/orchestra/ai_director.go` |
102 | | -- [ ] Provider interface: `CallLLM(model, system, messages, tools) → response` |
103 | | -- [ ] Anthropic provider (Claude API with tool_use) |
104 | | -- [ ] OpenAI provider (GPT API with function_calling) |
105 | | -- [ ] Google provider (Gemini API with function_calling) |
106 | | -- [ ] Tools: next_movement, ask_choice, post_chat, launch_sub_orchestra, finish_orchestra, get_score, list_musicians |
107 | | -- [ ] System prompt includes: orchestra name, available musicians, budget remaining |
108 | | -- [ ] Context includes: full score, last event, chat history |
109 | | -- [ ] Fallback: 3 retries, then ask_choice to human with available options |
| 101 | +- [x] Built-in Go component: `internal/orchestra/ai_director.go` |
| 102 | +- [x] Provider interface: `CallLLM(model, system, messages, tools) → response` |
| 103 | +- [x] Anthropic provider (Claude API with tool_use) |
| 104 | +- [x] OpenAI provider (GPT API with function_calling) |
| 105 | +- [x] Google provider (Gemini API with function_calling) |
| 106 | +- [x] Tools: next_movement, ask_choice, post_chat, launch_sub_orchestra, finish_orchestra, get_score, list_musicians |
| 107 | +- [x] System prompt includes: orchestra name, available musicians, budget remaining |
| 108 | +- [x] Context includes: full score, last event, chat history |
| 109 | +- [x] Fallback: 3 retries, then ask_choice to human with available options |
110 | 110 |
|
111 | 111 | ### T09.13 AI Director Budget Tracking |
112 | | -- [ ] Count AI calls per orchestra in budget_used |
113 | | -- [ ] Warning at 80% in chat |
114 | | -- [ ] Fail orchestra at 100% |
115 | | -- [ ] Webhook events: `orchestra.budget_warning`, `orchestra.budget_exceeded` |
| 112 | +- [x] Count AI calls per orchestra in budget_used |
| 113 | +- [x] Warning at 80% in chat |
| 114 | +- [x] Fail orchestra at 100% |
| 115 | +- [x] Webhook events: `orchestra.budget_warning`, `orchestra.budget_exceeded` |
116 | 116 |
|
117 | 117 | ## ~~Phase 5: Sub-Orchestras~~ DEFERRED |
118 | 118 | > Moved to future epic. Orchestras are flat for now — no nesting. |
|
121 | 121 |
|
122 | 122 |
|
123 | 123 | ### T09.16 Container Executor |
124 | | -- [ ] `internal/executor/container/container.go`: implements Method interface |
125 | | -- [ ] Docker SDK client (`github.com/docker/docker/client`) |
126 | | -- [ ] `Execute()`: create Swarm service → poll tasks → collect logs → remove service |
127 | | -- [ ] `Kill()`: remove service |
128 | | -- [ ] Resource limits: cpu, memory from method_config |
129 | | -- [ ] Env var injection: all standard vars + orchestra secrets |
130 | | -- [ ] Config: `CC_CONTAINER_SWARM_ENDPOINT`, `CC_CONTAINER_DEFAULT_CPU`, `CC_CONTAINER_DEFAULT_MEMORY` |
| 124 | +- [x] `internal/executor/container/container.go`: implements Method interface |
| 125 | +- [x] Docker SDK client (`github.com/docker/docker/client`) |
| 126 | +- [x] `Execute()`: create Swarm service → poll tasks → collect logs → remove service |
| 127 | +- [x] `Kill()`: remove service |
| 128 | +- [x] Resource limits: cpu, memory from method_config |
| 129 | +- [x] Env var injection: all standard vars + orchestra secrets |
| 130 | +- [x] Config: `CC_CONTAINER_SWARM_ENDPOINT`, `CC_CONTAINER_DEFAULT_CPU`, `CC_CONTAINER_DEFAULT_MEMORY` |
131 | 131 |
|
132 | 132 | ### T09.17 Registry Authentication |
133 | | -- [ ] method_config.registry_auth references a workspace secret |
134 | | -- [ ] Container executor decrypts and passes to `docker service create --with-registry-auth` |
135 | | -- [ ] Support: Docker Hub, ghcr.io, AWS ECR, custom registries |
| 133 | +- [x] method_config.registry_auth references a workspace secret |
| 134 | +- [x] Container executor decrypts and passes to `docker service create --with-registry-auth` |
| 135 | +- [x] Support: Docker Hub, ghcr.io, AWS ECR, custom registries |
136 | 136 |
|
137 | 137 | ### T09.18 Container Pool Dashboard |
138 | | -- [ ] `GET /admin/container-pool` — list Swarm nodes (platform admin) |
| 138 | +- [x] `GET /admin/container-pool` — list Swarm nodes (platform admin) |
139 | 139 | - [ ] Dashboard: Settings > Container Pool (node list, CPU/memory usage, containers running) |
140 | 140 | - [ ] Health status per node |
141 | 141 |
|
142 | 142 | ## Phase 7: Timeout, Budget & Pause |
143 | 143 |
|
144 | 144 | ### T09.19 Orchestra Timeout |
145 | | -- [ ] `timeout` and `timeout_at` fields on orchestras table |
146 | | -- [ ] Monitor goroutine checks active orchestras for timeout |
147 | | -- [ ] On timeout: kill running movements, state=failed, chat message, webhook `orchestra.timeout` |
| 145 | +- [x] `timeout` and `timeout_at` fields on orchestras table |
| 146 | +- [x] Monitor goroutine checks active orchestras for timeout |
| 147 | +- [x] On timeout: kill running movements, state=failed, chat message, webhook `orchestra.timeout` |
148 | 148 |
|
149 | 149 | ### T09.20 Orchestra Budget |
150 | | -- [ ] `budget` and `budget_used` JSONB fields on orchestras table |
151 | | -- [ ] Counters: movements, ai_calls, duration_minutes |
152 | | -- [ ] Check before each movement/AI call |
153 | | -- [ ] 80% warning: chat + webhook |
154 | | -- [ ] 100% exceeded: fail orchestra + webhook |
| 150 | +- [x] `budget` and `budget_used` JSONB fields on orchestras table |
| 151 | +- [x] Counters: movements, ai_calls, duration_minutes |
| 152 | +- [x] Check before each movement/AI call |
| 153 | +- [x] 80% warning: chat + webhook |
| 154 | +- [x] 100% exceeded: fail orchestra + webhook |
155 | 155 |
|
156 | 156 | ### T09.21 Pause / Resume |
157 | | -- [ ] `POST /orchestras/{id}/pause` — state=paused, no new movements triggered |
158 | | -- [ ] `POST /orchestras/{id}/resume` — state=active, process queued events |
159 | | -- [ ] Running movements continue to completion during pause |
160 | | -- [ ] Completed events queued (stored in orchestra_events table or chat) |
161 | | -- [ ] On resume: director triggered with accumulated events |
162 | | -- [ ] SDK: `pause_orchestra(id)` and `resume_orchestra(id)` in all 5 SDKs |
| 157 | +- [x] `POST /orchestras/{id}/pause` — state=paused, no new movements triggered |
| 158 | +- [x] `POST /orchestras/{id}/resume` — state=active, process queued events |
| 159 | +- [x] Running movements continue to completion during pause |
| 160 | +- [x] Completed events queued (stored in orchestra_events table or chat) |
| 161 | +- [x] On resume: director triggered with accumulated events |
| 162 | +- [x] SDK: `pause_orchestra(id)` and `resume_orchestra(id)` in all 5 SDKs |
163 | 163 |
|
164 | 164 | ## Phase 8: Dashboard |
165 | 165 |
|
166 | 166 | ### T09.22 Orchestra List Page |
167 | | -- [ ] New sidebar item: "Orchestras" (between Queue and Infrastructure sections) |
168 | | -- [ ] List: name, director type badge, state badge, movement count, duration, budget used |
169 | | -- [ ] Filters: state, date range |
170 | | -- [ ] Click → Score view |
| 167 | +- [x] New sidebar item: "Orchestras" (between Queue and Infrastructure sections) |
| 168 | +- [x] List: name, director type badge, state badge, movement count, duration, budget used |
| 169 | +- [x] Filters: state, date range |
| 170 | +- [x] Click → Score view |
171 | 171 |
|
172 | 172 | ### T09.23 Score View Page |
173 | | -- [ ] `/orchestras/{id}` route |
174 | | -- [ ] Vertical timeline of movements: process name, state, duration, result preview |
175 | | -- [ ] Choice buttons inline when waiting_for_choice |
176 | | -- [ ] Orchestra metadata header: name, director, state, budget, timeout |
| 173 | +- [x] `/orchestras/{id}` route |
| 174 | +- [x] Vertical timeline of movements: process name, state, duration, result preview |
| 175 | +- [x] Choice buttons inline when waiting_for_choice |
| 176 | +- [x] Orchestra metadata header: name, director, state, budget, timeout |
177 | 177 | - [ ] Sub-orchestras expandable tree |
178 | 178 |
|
179 | 179 | ### T09.24 Chat Panel |
180 | | -- [ ] Real-time chat panel (SSE) on Score page |
181 | | -- [ ] Message types rendered differently: text, status (gray), warning (amber), file (link), action (buttons) |
182 | | -- [ ] Human input box at bottom |
183 | | -- [ ] Action buttons clickable |
| 180 | +- [x] Real-time chat panel (SSE) on Score page |
| 181 | +- [x] Message types rendered differently: text, status (gray), warning (amber), file (link), action (buttons) |
| 182 | +- [x] Human input box at bottom |
| 183 | +- [x] Action buttons clickable |
184 | 184 |
|
185 | 185 | ### T09.25 RunDetail Orchestra Integration |
186 | | -- [ ] Show result JSON (collapsible section) |
187 | | -- [ ] Show artifacts with download links |
188 | | -- [ ] Orchestra breadcrumb: Orchestra "name" → Movement N |
189 | | -- [ ] Choice buttons when waiting_for_choice |
| 186 | +- [x] Show result JSON (collapsible section) |
| 187 | +- [x] Show artifacts with download links |
| 188 | +- [x] Orchestra breadcrumb: Orchestra "name" → Movement N |
| 189 | +- [x] Choice buttons when waiting_for_choice |
190 | 190 |
|
191 | 191 | ## Phase 9: Storage Isolation |
192 | 192 |
|
|
198 | 198 | - [ ] Access control: only runs within same orchestra can read each other's artifacts |
199 | 199 |
|
200 | 200 | ## Acceptance Checklist |
201 | | -- [ ] Phase 1: Result, secrets, artifacts all working with SDK support |
202 | | -- [ ] Phase 2: Orchestra lifecycle, movements, director trigger, human choices |
203 | | -- [ ] Phase 3: Chat with actions, real-time SSE |
204 | | -- [ ] Phase 4: AI Director multi-model with fallback |
205 | | -- [ ] Phase 5: Sub-orchestras with wait/parallel |
206 | | -- [ ] Phase 6: Container executor on Docker Swarm |
207 | | -- [ ] Phase 7: Timeout, budget, pause/resume |
208 | | -- [ ] Phase 8: Full dashboard with score view and chat |
| 201 | +- [x] Phase 1: Result, secrets, artifacts all working with SDK support |
| 202 | +- [x] Phase 2: Orchestra lifecycle, movements, director trigger, human choices |
| 203 | +- [x] Phase 3: Chat with actions, real-time SSE |
| 204 | +- [x] Phase 4: AI Director multi-model with fallback |
| 205 | +- [x] Phase 5: Container executor on Docker Swarm |
| 206 | +- [x] Phase 7: Timeout, budget, pause/resume |
| 207 | +- [ ] Phase 8: Full dashboard with score view and chat (partial — secrets UI and infrastructure dashboard pending) |
209 | 208 | - [ ] Phase 9: Storage isolation per orchestra/run |
0 commit comments