@bastani/atomic 0.5.34 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +329 -50
  2. package/dist/commands/cli/session.d.ts +67 -0
  3. package/dist/commands/cli/session.d.ts.map +1 -0
  4. package/dist/commands/cli/workflow-status.d.ts +63 -0
  5. package/dist/commands/cli/workflow-status.d.ts.map +1 -0
  6. package/dist/sdk/commander.d.ts +74 -0
  7. package/dist/sdk/commander.d.ts.map +1 -0
  8. package/dist/sdk/components/workflow-picker-panel.d.ts +14 -17
  9. package/dist/sdk/components/workflow-picker-panel.d.ts.map +1 -1
  10. package/dist/sdk/define-workflow.d.ts +18 -9
  11. package/dist/sdk/define-workflow.d.ts.map +1 -1
  12. package/dist/sdk/index.d.ts +4 -3
  13. package/dist/sdk/index.d.ts.map +1 -1
  14. package/dist/sdk/management-commands.d.ts +42 -0
  15. package/dist/sdk/management-commands.d.ts.map +1 -0
  16. package/dist/sdk/registry.d.ts +27 -0
  17. package/dist/sdk/registry.d.ts.map +1 -0
  18. package/dist/sdk/runtime/attached-footer.d.ts +1 -1
  19. package/dist/sdk/runtime/executor-env.d.ts +20 -0
  20. package/dist/sdk/runtime/executor-env.d.ts.map +1 -0
  21. package/dist/sdk/runtime/executor.d.ts +61 -10
  22. package/dist/sdk/runtime/executor.d.ts.map +1 -1
  23. package/dist/sdk/types.d.ts +147 -4
  24. package/dist/sdk/types.d.ts.map +1 -1
  25. package/dist/sdk/worker-shared.d.ts +42 -0
  26. package/dist/sdk/worker-shared.d.ts.map +1 -0
  27. package/dist/sdk/workflow-cli.d.ts +103 -0
  28. package/dist/sdk/workflow-cli.d.ts.map +1 -0
  29. package/dist/sdk/workflows/builtin-registry.d.ts +113 -0
  30. package/dist/sdk/workflows/builtin-registry.d.ts.map +1 -0
  31. package/dist/sdk/workflows/index.d.ts +5 -5
  32. package/dist/sdk/workflows/index.d.ts.map +1 -1
  33. package/package.json +12 -8
  34. package/src/cli.ts +85 -144
  35. package/src/commands/cli/chat/index.ts +10 -0
  36. package/src/commands/cli/workflow-command.test.ts +279 -938
  37. package/src/commands/cli/workflow-inputs.test.ts +41 -11
  38. package/src/commands/cli/workflow-inputs.ts +47 -12
  39. package/src/commands/cli/workflow-list.test.ts +234 -0
  40. package/src/commands/cli/workflow-list.ts +0 -0
  41. package/src/commands/cli/workflow.ts +11 -798
  42. package/src/scripts/constants.ts +2 -1
  43. package/src/sdk/commander.ts +161 -0
  44. package/src/sdk/components/workflow-picker-panel.tsx +78 -258
  45. package/src/sdk/define-workflow.test.ts +104 -11
  46. package/src/sdk/define-workflow.ts +47 -11
  47. package/src/sdk/errors.test.ts +16 -0
  48. package/src/sdk/index.ts +8 -8
  49. package/src/sdk/management-commands.ts +151 -0
  50. package/src/sdk/registry.ts +132 -0
  51. package/src/sdk/runtime/attached-footer.ts +1 -1
  52. package/src/sdk/runtime/executor-env.ts +45 -0
  53. package/src/sdk/runtime/executor.test.ts +37 -0
  54. package/src/sdk/runtime/executor.ts +147 -68
  55. package/src/sdk/types.ts +169 -4
  56. package/src/sdk/worker-shared.test.ts +163 -0
  57. package/src/sdk/worker-shared.ts +155 -0
  58. package/src/sdk/workflow-cli.ts +409 -0
  59. package/src/sdk/workflows/builtin/deep-research-codebase/claude/index.ts +1 -1
  60. package/src/sdk/workflows/builtin/deep-research-codebase/copilot/index.ts +1 -1
  61. package/src/sdk/workflows/builtin/deep-research-codebase/opencode/index.ts +1 -1
  62. package/src/sdk/workflows/builtin/open-claude-design/claude/index.ts +1 -1
  63. package/src/sdk/workflows/builtin/open-claude-design/copilot/index.ts +1 -1
  64. package/src/sdk/workflows/builtin/open-claude-design/opencode/index.ts +1 -1
  65. package/src/sdk/workflows/builtin/ralph/claude/index.ts +1 -1
  66. package/src/sdk/workflows/builtin/ralph/copilot/index.ts +1 -1
  67. package/src/sdk/workflows/builtin/ralph/opencode/index.ts +1 -1
  68. package/src/sdk/workflows/builtin-registry.ts +23 -0
  69. package/src/sdk/workflows/index.ts +10 -20
  70. package/src/services/system/auth.test.ts +63 -1
  71. package/.agents/skills/workflow-creator/SKILL.md +0 -334
  72. package/.agents/skills/workflow-creator/references/agent-sessions.md +0 -888
  73. package/.agents/skills/workflow-creator/references/computation-and-validation.md +0 -201
  74. package/.agents/skills/workflow-creator/references/control-flow.md +0 -470
  75. package/.agents/skills/workflow-creator/references/discovery-and-verification.md +0 -232
  76. package/.agents/skills/workflow-creator/references/failure-modes.md +0 -903
  77. package/.agents/skills/workflow-creator/references/getting-started.md +0 -275
  78. package/.agents/skills/workflow-creator/references/running-workflows.md +0 -235
  79. package/.agents/skills/workflow-creator/references/session-config.md +0 -384
  80. package/.agents/skills/workflow-creator/references/state-and-data-flow.md +0 -357
  81. package/.agents/skills/workflow-creator/references/user-input.md +0 -234
  82. package/.agents/skills/workflow-creator/references/workflow-inputs.md +0 -272
  83. package/dist/sdk/runtime/discovery.d.ts +0 -132
  84. package/dist/sdk/runtime/discovery.d.ts.map +0 -1
  85. package/dist/sdk/runtime/executor-entry.d.ts +0 -11
  86. package/dist/sdk/runtime/executor-entry.d.ts.map +0 -1
  87. package/dist/sdk/runtime/loader.d.ts +0 -70
  88. package/dist/sdk/runtime/loader.d.ts.map +0 -1
  89. package/dist/version.d.ts +0 -2
  90. package/dist/version.d.ts.map +0 -1
  91. package/src/commands/cli/workflow.test.ts +0 -317
  92. package/src/sdk/runtime/discovery.ts +0 -368
  93. package/src/sdk/runtime/executor-entry.ts +0 -18
  94. package/src/sdk/runtime/loader.ts +0 -267
@@ -1,275 +0,0 @@
1
- # Workflow Authors: Getting Started
2
-
3
- This guide covers the basics of creating workflows with the `defineWorkflow().run().compile()` API.
4
-
5
- ## Quick-start example
6
-
7
- Use `defineWorkflow({...}).for<"agent">().run(callback).compile()` to define your workflow. Inside the `.run()` callback, use `ctx.stage()` to spawn agent sessions dynamically. Each session gets its own tmux window and graph node. Use native TypeScript control flow (`for`, `if`, `Promise.all()`) for orchestration.
8
-
9
- The runtime manages the full session lifecycle automatically — it creates the client, creates the session, runs your callback, then cleans up. You never need to manually disconnect or stop anything.
10
-
11
- ### Claude
12
-
13
- ```ts
14
- // .atomic/workflows/my-workflow/claude/index.ts
15
- import { defineWorkflow, extractAssistantText } from "@bastani/atomic/workflows";
16
-
17
- export default defineWorkflow({
18
- name: "my-workflow",
19
- description: "A two-session pipeline",
20
- inputs: [
21
- { name: "prompt", type: "text", required: true, description: "task to perform" },
22
- ],
23
- })
24
- .for<"claude">()
25
- .run(async (ctx) => {
26
- const prompt = ctx.inputs.prompt ?? "";
27
-
28
- const describe = await ctx.stage(
29
- { name: "describe", description: "Ask Claude to describe the project" },
30
- {},
31
- {},
32
- async (s) => {
33
- await s.session.query(prompt);
34
- s.save(s.sessionId);
35
- },
36
- );
37
-
38
- await ctx.stage(
39
- { name: "summarize", description: "Summarize the previous session's output" },
40
- {},
41
- {},
42
- async (s) => {
43
- const research = await s.transcript(describe);
44
- await s.session.query(
45
- `Read ${research.path} and summarize it in 2-3 bullet points.`,
46
- );
47
- s.save(s.sessionId);
48
- },
49
- );
50
- })
51
- .compile();
52
- ```
53
-
54
- ### Copilot
55
-
56
- ```ts
57
- // .atomic/workflows/my-workflow/copilot/index.ts
58
- import { defineWorkflow } from "@bastani/atomic/workflows";
59
-
60
- export default defineWorkflow({
61
- name: "my-workflow",
62
- description: "A two-session pipeline",
63
- inputs: [
64
- { name: "prompt", type: "text", required: true, description: "task to perform" },
65
- ],
66
- })
67
- .for<"copilot">()
68
- .run(async (ctx) => {
69
- const prompt = ctx.inputs.prompt ?? "";
70
-
71
- const describe = await ctx.stage(
72
- { name: "describe", description: "Ask the agent to describe the project" },
73
- {},
74
- {},
75
- async (s) => {
76
- await s.session.send({ prompt });
77
- s.save(await s.session.getMessages());
78
- },
79
- );
80
-
81
- await ctx.stage(
82
- { name: "summarize", description: "Summarize the previous session's output" },
83
- {},
84
- {},
85
- async (s) => {
86
- const research = await s.transcript(describe);
87
- await s.session.send({
88
- prompt: `Summarize the following in 2-3 bullet points:\n\n${research.content}`,
89
- });
90
- s.save(await s.session.getMessages());
91
- },
92
- );
93
- })
94
- .compile();
95
- ```
96
-
97
- ### OpenCode
98
-
99
- ```ts
100
- // .atomic/workflows/my-workflow/opencode/index.ts
101
- import { defineWorkflow } from "@bastani/atomic/workflows";
102
-
103
- export default defineWorkflow({
104
- name: "my-workflow",
105
- description: "A two-session pipeline",
106
- inputs: [
107
- { name: "prompt", type: "text", required: true, description: "task to perform" },
108
- ],
109
- })
110
- .for<"opencode">()
111
- .run(async (ctx) => {
112
- const prompt = ctx.inputs.prompt ?? "";
113
-
114
- const describe = await ctx.stage(
115
- { name: "describe", description: "Ask the agent to describe the project" },
116
- {},
117
- { title: "describe" },
118
- async (s) => {
119
- const result = await s.client.session.prompt({
120
- sessionID: s.session.id,
121
- parts: [{ type: "text", text: prompt }],
122
- });
123
- s.save(result.data!);
124
- },
125
- );
126
-
127
- await ctx.stage(
128
- { name: "summarize", description: "Summarize the previous session's output" },
129
- {},
130
- { title: "summarize" },
131
- async (s) => {
132
- const research = await s.transcript(describe);
133
- const result = await s.client.session.prompt({
134
- sessionID: s.session.id,
135
- parts: [{ type: "text", text: `Summarize the following in 2-3 bullet points:\n\n${research.content}` }],
136
- });
137
- s.save(result.data!);
138
- },
139
- );
140
- })
141
- .compile();
142
- ```
143
-
144
- Reading top-to-bottom: `describe → summarize`. Each session spawns a graph node and tmux window.
145
-
146
- ## Native TypeScript control flow
147
-
148
- Sessions are spawned dynamically, so you can use loops, conditionals, and `Promise.all()`:
149
-
150
- ```ts
151
- // Parallel sessions
152
- const [a, b] = await Promise.all([
153
- ctx.stage({ name: "task-a" }, {}, {}, async (s) => { /* ... */ }),
154
- ctx.stage({ name: "task-b" }, {}, {}, async (s) => { /* ... */ }),
155
- ]);
156
-
157
- // Loop with dynamic sessions
158
- for (let i = 1; i <= maxIterations; i++) {
159
- const result = await ctx.stage({ name: `step-${i}` }, {}, {}, async (s) => {
160
- // ... do work ...
161
- return someValue; // available as result.result
162
- });
163
- if (result.result === "done") break;
164
- }
165
-
166
- // Conditional sessions
167
- if (needsReview) {
168
- await ctx.stage({ name: "review" }, {}, {}, async (s) => { /* ... */ });
169
- }
170
- ```
171
-
172
- ## Headless (background) stages
173
-
174
- Set `headless: true` in the stage options to run the provider SDK
175
- in-process instead of spawning a tmux window — invisible in the graph,
176
- identical callback API.
177
-
178
- ```ts
179
- const result = await ctx.stage(
180
- { name: "background-task", headless: true },
181
- {}, {},
182
- async (s) => {
183
- const result = await s.session.query("Analyze the codebase.");
184
- s.save(s.sessionId);
185
- return extractAssistantText(result, 0);
186
- },
187
- );
188
- ```
189
-
190
- For per-provider mechanics, the canonical fan-out pattern (visible seed →
191
- parallel headless → visible merge), and topology semantics, see
192
- `control-flow.md` §"Headless stages: transparent to graph topology" and the
193
- per-SDK "Headless mode" sections in `agent-sessions.md`. Failure visibility
194
- caveats live in `failure-modes.md` §F15.
195
-
196
- ## SDK exports
197
-
198
- The `@bastani/atomic/workflows` package exports the workflow authoring primitives. For native SDK types and utilities, install and import from the provider packages directly.
199
-
200
- **Builder:**
201
- - `defineWorkflow` — entry point; returns a chainable `WorkflowBuilder`. Use `.for<"agent">()` on the builder to narrow types to a specific provider.
202
- - `WorkflowBuilder` — the builder class (rarely needed directly)
203
-
204
- **Types** (import with `import type`):
205
- - `AgentType` — `"copilot" | "opencode" | "claude"`
206
- - `Transcript` — `{ path: string, content: string }` from `ctx.transcript()`
207
- - `SavedMessage` — union of provider-specific message types
208
- - `SaveTranscript` — overloaded save function type
209
- - `SessionContext` — the context object passed to `ctx.stage()` callbacks
210
- - `SessionHandle<T>` — returned by `ctx.stage()`, carries `{ name, id, result }`
211
- - `SessionRunOptions` — `{ name, description?, headless? }` for `ctx.stage()` first argument
212
- - `StageClientOptions<A>` — provider-specific client init options for `ctx.stage()` second argument
213
- - `StageSessionOptions<A>` — provider-specific session create options for `ctx.stage()` third argument
214
- - `ProviderClient<A>` — the `s.client` type, resolved by agent type
215
- - `ProviderSession<A>` — the `s.session` type, resolved by agent type
216
- - `ClaudeSessionWrapper` — Atomic wrapper for Claude sessions (exposes `s.session.query()`, which returns `SessionMessage[]`)
217
- - `SessionRef` — `string | SessionHandle<unknown>` for transcript/message lookups
218
- - `WorkflowContext` — top-level context passed to `.run()` callback
219
- - `WorkflowOptions` — `{ name, description? }` workflow metadata
220
- - `WorkflowDefinition` — sealed output of `.compile()`
221
-
222
- **Response utilities:**
223
- - `extractAssistantText(messages, afterIndex)` — extract plain text from the `SessionMessage[]` returned by `s.session.query()` for Claude; use `extractAssistantText(result, 0)` to get the full assistant response text
224
-
225
- **Validation helpers:**
226
- - `validateClaudeWorkflow` — static validation for Claude workflow source files; warns on direct `createClaudeSession` or `claudeQuery` usage
227
- - `validateCopilotWorkflow` — static validation for Copilot workflow source files; warns on manual `new CopilotClient` or `client.createSession()` usage
228
- - `validateOpenCodeWorkflow` — static validation for OpenCode workflow source files; warns on manual `createOpencodeClient()` or `client.session.create()` usage
229
-
230
- **Native SDK dependencies:**
231
-
232
- The Atomic runtime provides `s.client` and `s.session` with types resolved from the native SDKs. If you need to name those types in your own code, or use SDK utilities and advanced APIs, import them directly from the provider packages:
233
-
234
- | Provider | Package | Key imports |
235
- |----------|---------|-------------|
236
- | Copilot | `@github/copilot-sdk` | `SessionEvent`, `CopilotClient`, `CopilotSession`, `approveAll`, `defineTool` |
237
- | Claude | `@anthropic-ai/claude-agent-sdk` | `SessionMessage`, `query` |
238
- | OpenCode | `@opencode-ai/sdk/v2` | `SessionPromptResponse`, `OpencodeClient`, `Session` |
239
-
240
- ## `SessionContext` reference
241
-
242
- | Field | Type | Description |
243
- |-------|------|-------------|
244
- | `client` | `ProviderClient<A>` | Pre-created SDK client (auto-managed by runtime) |
245
- | `session` | `ProviderSession<A>` | Pre-created provider session (auto-managed by runtime) |
246
- | `inputs` | `{ [K in N]?: string }` | Typed inputs for this run — only declared field names are valid keys. Accessing an undeclared field is a compile-time error. See `workflow-inputs.md`. |
247
- | `agent` | `AgentType` | Which agent is running |
248
- | `transcript(ref)` | `(ref: SessionRef) => Promise<Transcript>` | Get prior session's transcript as `{ path, content }` |
249
- | `getMessages(ref)` | `(ref: SessionRef) => Promise<SavedMessage[]>` | Get prior session's raw native messages |
250
- | `save` | `SaveTranscript` | Save this session's output for downstream sessions |
251
- | `sessionDir` | `string` | Path to session storage directory |
252
- | `paneId` | `string` | tmux pane ID (or `headless-<name>-<id>` for headless stages) |
253
- | `sessionId` | `string` | Session UUID |
254
- | `stage(opts, clientOpts, sessionOpts, fn)` | `<T>(...) => Promise<SessionHandle<T>>` | Spawn a nested sub-session (child of this session in the graph) |
255
-
256
- ## Reference files
257
-
258
- The full table of references with load triggers lives in SKILL.md
259
- §"Reference Files". Pull `failure-modes.md` before shipping any
260
- multi-session workflow, and `agent-sessions.md` whenever writing SDK calls.
261
-
262
- ## Builtin reference implementations
263
-
264
- The SDK ships two builtin workflows that demonstrate production patterns for all three SDKs:
265
-
266
- - **`ralph`** (`src/sdk/workflows/builtin/ralph/`) — iterative plan → orchestrate → review → debug loop with consecutive clean-pass detection, shared helpers for prompts/parsing/git, and cross-SDK adaptation
267
- - **`deep-research-codebase`** (`src/sdk/workflows/builtin/deep-research-codebase/`) — deterministic codebase scout → LOC-based heuristic explorer partitioning → parallel explorers → aggregator with file-based handoffs and context-aware prompt engineering
268
-
269
- Both include `helpers/` directories with SDK-agnostic logic (prompt builders, parsers, heuristics) and per-agent `index.ts` files showing how the same workflow topology adapts to Claude, Copilot, and OpenCode.
270
-
271
- For a minimal headless example (not a builtin — it lives as a local workflow in this repo), see `.atomic/workflows/headless-test/` — demonstrates the visible → [parallel headless] → visible merge pattern for all three SDKs.
272
-
273
- ## Type safety
274
-
275
- The SDK avoids `any` and uses `unknown` only at well-defined boundaries (e.g., `SessionRef = string | SessionHandle<unknown>` for handle-erased lookups). `SessionContext` fields are precisely typed, and native provider types may appear inside Atomic generic aliases and runtime values — if you need to name those types in your own code, import them from the provider SDK directly. Use `import type` for type-only imports. Use `.for<"agent">()` to narrow `s.client` and `s.session` to the correct provider types. Declare `inputs` inline so TypeScript enforces typed access on `ctx.inputs`.
@@ -1,235 +0,0 @@
1
- # Running a Workflow on Behalf of the User
2
-
3
- When the user asks you to **run** (or "kick off" / "start" / "execute") a
4
- workflow — *not* author one — your job is to translate their request into a
5
- single `atomic workflow` invocation and run it. This is the playbook for that
6
- flow. It is different from the authoring playbook in `SKILL.md`: the workflow
7
- already exists on disk; you just need to invoke it correctly.
8
-
9
- ## You don't need to pass `-a` or `-d`
10
-
11
- When you (the agent) are running inside an atomic chat or workflow pane, the
12
- CLI reads `$ATOMIC_AGENT` from your environment and:
13
-
14
- - Fills in `-a <agent>` automatically if you don't pass it.
15
- - Forces detached mode on, so launching a workflow never takes over your pane.
16
-
17
- The practical result: your command is just `atomic workflow -n <name> <inputs>`.
18
- No provider flag, no detach flag, no chance of the orchestrator hijacking your
19
- terminal. The CLI prints the session name and returns immediately; you relay
20
- that name to the user.
21
-
22
- Override only when the user explicitly asks for a different provider (e.g.
23
- "run it on Copilot") — pass `-a copilot` and the CLI will honor it over the
24
- env var.
25
-
26
- ## Always list first
27
-
28
- **Before anything else, run `atomic workflow list`.** (Optionally filter with
29
- `-a <agent>` if the user's pinned to one — usually unnecessary.) This is a
30
- cheap, read-only call that tells you three things in one shot:
31
-
32
- - Whether the workflow the user named actually exists.
33
- - What other workflows are available (so you can suggest close matches on a typo).
34
- - Source + metadata for every discoverable workflow (local vs. global vs. builtin).
35
-
36
- Skipping this step is how you end up guessing a name, typing it into
37
- `atomic workflow -n <name>`, and getting a `workflow not found` error you
38
- could have predicted. List first, decide second, run third.
39
-
40
- If the user's request is ambiguous ("run the research one"), the list output
41
- is also how you show them the candidates so they can pick — present the
42
- matching names and ask with AskUserQuestion.
43
-
44
- ## If the workflow doesn't exist: offer to create it
45
-
46
- When the listed workflows don't include what the user asked for:
47
-
48
- 1. **Tell the user explicitly** — "I don't see a `<name>` workflow in
49
- `.atomic/workflows/` or `~/.atomic/workflows/`. Available: \<short list from
50
- `atomic workflow list`>."
51
- 2. **Check for typos first** — if one of the listed names is a close match,
52
- surface it via AskUserQuestion ("Did you mean `<close-match>`?") before
53
- offering to author anything.
54
- 3. **Offer to create it** — ask with AskUserQuestion: "Want me to create a
55
- `<name>` workflow first?" with choices `Yes, create it` / `No, pick from
56
- the list` / `No, cancel`.
57
- 4. **If yes → switch modes** — hand off to the authoring flow in SKILL.md
58
- (Steps 1-5). Interview the user for intent, write the file at
59
- `.atomic/workflows/<name>/<agent>/index.ts`, typecheck it, *then* come back
60
- here and invoke it. Do not skip the typecheck — an uncompiled workflow
61
- won't run.
62
- 5. **If no → stop** — don't fabricate a command that will fail. Let the user
63
- redirect you.
64
-
65
- Never invent a workflow name or silently fall back to a different workflow.
66
- If the thing the user asked for doesn't exist, the correct answer is to say
67
- so and offer concrete next steps.
68
-
69
- ## Collecting inputs with AskUserQuestion
70
-
71
- Once you've confirmed the workflow exists, you need to know two things about
72
- its invocation shape:
73
-
74
- 1. **Does it declare a `prompt` input?** If so, it's free-form — you pass a
75
- positional string.
76
- 2. **Does it declare structured inputs?** If so, you pass `--<field>=<value>`
77
- flags, one per required field.
78
-
79
- **Use `atomic workflow inputs <name> -a <agent>` to get the schema.** This
80
- prints a JSON envelope with every field's `name`, `type`, `required`,
81
- `default`, `description`, and (for enums) `values` — exactly what
82
- AskUserQuestion needs. The `freeform: true` flag tells you whether the
83
- workflow takes a positional prompt vs. structured flags, with a synthetic
84
- `prompt` field included so the JSON shape is uniform either way.
85
-
86
- ```bash
87
- atomic workflow inputs gen-spec -a claude
88
- # {"workflow":"gen-spec","agent":"claude","freeform":false,
89
- # "inputs":[{"name":"research_doc","type":"string","required":true,...},
90
- # {"name":"focus","type":"enum","values":["minimal","standard","exhaustive"],"default":"standard"}]}
91
- ```
92
-
93
- Why this command instead of reading the source file: `inputs` is the contract
94
- the CLI actually validates against. It survives refactors, handles built-in
95
- workflows that aren't in the project tree, and never falls out of sync with
96
- the runtime. Reading TypeScript source is a fallback for the rare case where
97
- the command can't resolve the workflow.
98
-
99
- Once you have the schema, use the **AskUserQuestion tool** to collect any
100
- values the user hasn't already provided in their message. One question per
101
- missing input field. For enum fields, pass the declared `values` as
102
- multiple-choice options so the user sees exactly what's allowed. Keep
103
- questions tight and purposeful — if the user's message already answers a
104
- question, don't ask it again.
105
-
106
- Skip AskUserQuestion entirely when:
107
- - The user already supplied every required value in their message
108
- ("run ralph on 'add OAuth to the API'" — the prompt is right there).
109
- - The workflow declares no required inputs and needs no prompt.
110
-
111
- ## End-to-end recipe
112
-
113
- 1. **List available workflows** — run `atomic workflow list`. Always. This is
114
- your ground truth.
115
- 2. **Resolve the target**:
116
- - Exact match in the list → continue.
117
- - Close match → confirm via AskUserQuestion before proceeding.
118
- - No match → tell the user what's available and offer to author it (see
119
- previous section). If they decline, stop.
120
- 3. **Discover the inputs schema** — run `atomic workflow inputs <name> -a <agent>`
121
- and parse the JSON.
122
- 4. **Ask for missing inputs** — use AskUserQuestion, one question per
123
- unanswered required field. Enums become multiple-choice.
124
- 5. **Invoke** — build one of these commands:
125
- - Free-form: `atomic workflow -n <name> "<prompt>"`
126
- - Structured: `atomic workflow -n <name> --<field1>=<value1> --<field2>=<value2>`
127
- 6. **Report the session name** the CLI printed and tell the user: "attach any
128
- time with `atomic workflow session connect <session>` — or
129
- `atomic workflow session list` to see what's running."
130
-
131
- ## Monitoring a running workflow
132
-
133
- Detached workflows return immediately with a session name; the actual work
134
- runs in the background on the atomic tmux socket. Use `atomic workflow status`
135
- to check whether the workflow is still running, has completed, errored out, or
136
- paused for human input — without attaching to its TUI.
137
-
138
- ```bash
139
- atomic workflow status atomic-wf-claude-gen-spec-a1b2c3d4
140
- # {"id":"atomic-wf-claude-gen-spec-a1b2c3d4","overall":"in_progress","alive":true,
141
- # "sessions":[{"name":"orchestrator","status":"running",...}],...}
142
- ```
143
-
144
- Four overall states the agent must handle distinctly:
145
-
146
- | Status | Meaning | What you should do |
147
- |---|---|---|
148
- | `in_progress` | The orchestrator is running and no stage is paused | Wait, or report progress to the user |
149
- | `needs_review` | At least one stage is paused for human input (HIL) — Copilot `ask_user`, OpenCode `question.asked`, Copilot/MCP elicitation | **Surface this to the user immediately** — they need to attach with `atomic workflow session connect <id>` to respond, otherwise the workflow stalls indefinitely |
150
- | `completed` | Workflow finished successfully | Report success and summarize the output |
151
- | `error` | Fatal error or a stage failed | Report the `fatalError` field and offer to investigate logs |
152
-
153
- `needs_review` outranks `completed` so a HIL pause near the end is never
154
- reported as done while still waiting on a human. A dead orchestrator with a
155
- stale snapshot is automatically downgraded to `error`.
156
-
157
- Omit the id to list every running workflow at once: `atomic workflow status`.
158
- Useful when checking on multiple parallel runs, or when the user just asks
159
- "what's running?".
160
-
161
- ## Cleaning up sessions
162
-
163
- When the user is done with a workflow — or you launched one detached and it's
164
- no longer needed — tear it down with `-y` so no confirmation prompt blocks you:
165
-
166
- ```bash
167
- atomic session kill atomic-wf-claude-gen-spec-a1b2c3d4 -y
168
- ```
169
-
170
- The `-y` flag is mandatory for agent use. Without it, the CLI calls
171
- `@clack/prompts confirm`, which expects a TTY and will hang indefinitely in a
172
- non-interactive context. Same flag works for `atomic workflow session kill`
173
- and `atomic chat session kill`. Without an id, `kill -y` tears down every
174
- in-scope session — only do that when the user has asked to stop everything.
175
-
176
- ## Worked examples
177
-
178
- **Example A — workflow exists, structured inputs**
179
-
180
- > **User:** "run gen-spec on research/docs/2026-04-11-auth.md"
181
-
182
- 1. Run `atomic workflow list`. Output includes `gen-spec` under local. Good.
183
- 2. Target resolved exactly: `gen-spec`.
184
- 3. Run `atomic workflow inputs gen-spec -a claude`. Parse the JSON:
185
- `research_doc` (required string — already given), `focus` (required enum
186
- of `minimal|standard|exhaustive`, default `standard`), `notes`
187
- (optional text).
188
- 4. Ask via AskUserQuestion once: "What focus level for the spec?" with
189
- choices `minimal`, `standard`, `exhaustive`. User picks `standard`. Skip
190
- `notes` since it's optional.
191
- 5. Run: `atomic workflow -n gen-spec --research_doc=research/docs/2026-04-11-auth.md --focus=standard`
192
- 6. The CLI prints a session name like `atomic-wf-claude-gen-spec-a1b2c3d4`.
193
- Tell the user: "Started in the background. Attach with
194
- `atomic workflow session connect atomic-wf-claude-gen-spec-a1b2c3d4`,
195
- check progress with `atomic workflow status atomic-wf-claude-gen-spec-a1b2c3d4`,
196
- or stop it with `atomic session kill atomic-wf-claude-gen-spec-a1b2c3d4 -y`."
197
-
198
- **Example B — workflow does not exist**
199
-
200
- > **User:** "run the security-audit workflow on src/auth"
201
-
202
- 1. Run `atomic workflow list`. Available: `ralph`, `deep-research-codebase`,
203
- `gen-spec`, `review-to-merge`. No `security-audit`.
204
- 2. Tell the user: "I don't see a `security-audit` workflow. Available:
205
- ralph, deep-research-codebase, gen-spec, review-to-merge."
206
- 3. Ask via AskUserQuestion: "Want me to create a `security-audit` workflow
207
- first?" with choices `Yes, create it`, `No, use one of the existing
208
- workflows`, `No, cancel`.
209
- 4. If **Yes**: switch to SKILL.md's Authoring Process — interview the user
210
- for what the workflow should do, draft it, typecheck, *then* return here
211
- and invoke it.
212
- 5. If **No, use existing**: ask which one via AskUserQuestion over the
213
- listed options, then continue from step 3 of the recipe.
214
- 6. If **Cancel**: stop, no command runs.
215
-
216
- ## Common mistakes to avoid
217
-
218
- - **Skipping `atomic workflow list`** — leads to guessing and
219
- `workflow not found` errors. It's a one-line command; always run it.
220
- - **Inventing a workflow name** — if it's not in the list, it doesn't exist.
221
- Say so and offer to author it.
222
- - **Reading the workflow source file to discover inputs** — use
223
- `atomic workflow inputs <name> -a <agent>` instead. JSON, no TS parsing
224
- required, always in sync with the runtime. Source-file reads are a
225
- fallback, not a default.
226
- - **Asking everything at once** — let AskUserQuestion drive one question per
227
- field. Enum fields are multiple-choice, not free text.
228
- - **Re-asking what the user already said** — read their message first.
229
- - **Forgetting to report the session name** — the user needs it to reattach
230
- and to query status later.
231
- - **Leaving `needs_review` unreported** — when `atomic workflow status`
232
- returns `needs_review`, surface it to the user right away. The workflow is
233
- blocked on human input and will sit forever otherwise.
234
- - **Calling `session kill` without `-y`** — the prompt hangs in a
235
- non-interactive context. Always pass `-y` from an agent.