@bastani/atomic 0.6.4 → 0.6.5
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.
- package/.agents/skills/create-spec/SKILL.md +6 -3
- package/.agents/skills/tdd/SKILL.md +107 -0
- package/.agents/skills/tdd/deep-modules.md +33 -0
- package/.agents/skills/tdd/interface-design.md +31 -0
- package/.agents/skills/tdd/mocking.md +59 -0
- package/.agents/skills/tdd/refactoring.md +10 -0
- package/.agents/skills/tdd/tests.md +61 -0
- package/.agents/skills/workflow-creator/SKILL.md +550 -0
- package/.agents/skills/workflow-creator/references/agent-sessions.md +891 -0
- package/.agents/skills/workflow-creator/references/agent-setup-recipe.md +266 -0
- package/.agents/skills/workflow-creator/references/computation-and-validation.md +201 -0
- package/.agents/skills/workflow-creator/references/control-flow.md +470 -0
- package/.agents/skills/workflow-creator/references/failure-modes.md +1014 -0
- package/.agents/skills/workflow-creator/references/getting-started.md +392 -0
- package/.agents/skills/workflow-creator/references/registry-and-validation.md +141 -0
- package/.agents/skills/workflow-creator/references/running-workflows.md +418 -0
- package/.agents/skills/workflow-creator/references/session-config.md +384 -0
- package/.agents/skills/workflow-creator/references/state-and-data-flow.md +356 -0
- package/.agents/skills/workflow-creator/references/user-input.md +234 -0
- package/.agents/skills/workflow-creator/references/workflow-inputs.md +392 -0
- package/.claude/agents/debugger.md +2 -2
- package/.claude/agents/reviewer.md +1 -1
- package/.claude/agents/worker.md +2 -2
- package/.github/agents/debugger.md +1 -1
- package/.github/agents/worker.md +1 -1
- package/.mcp.json +5 -1
- package/.opencode/agents/debugger.md +1 -1
- package/.opencode/agents/worker.md +1 -1
- package/README.md +236 -201
- package/dist/sdk/define-workflow.d.ts +11 -6
- package/dist/sdk/define-workflow.d.ts.map +1 -1
- package/dist/sdk/errors.d.ts +10 -0
- package/dist/sdk/errors.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +21 -9
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/primitives/inputs.d.ts +36 -0
- package/dist/sdk/primitives/inputs.d.ts.map +1 -0
- package/dist/sdk/primitives/metadata.d.ts +40 -0
- package/dist/sdk/primitives/metadata.d.ts.map +1 -0
- package/dist/sdk/primitives/run.d.ts +57 -0
- package/dist/sdk/primitives/run.d.ts.map +1 -0
- package/dist/sdk/primitives/sessions.d.ts +128 -0
- package/dist/sdk/primitives/sessions.d.ts.map +1 -0
- package/dist/sdk/runtime/executor.d.ts +24 -56
- package/dist/sdk/runtime/executor.d.ts.map +1 -1
- package/dist/sdk/runtime/orchestrator-entry.d.ts +26 -0
- package/dist/sdk/runtime/orchestrator-entry.d.ts.map +1 -0
- package/dist/sdk/runtime/tmux.d.ts +20 -0
- package/dist/sdk/runtime/tmux.d.ts.map +1 -1
- package/dist/sdk/types.d.ts +26 -86
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/claude/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/copilot/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/open-claude-design/claude/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/open-claude-design/copilot/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/open-claude-design/opencode/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/ralph/claude/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/ralph/copilot/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/ralph/opencode/index.d.ts.map +1 -1
- package/dist/sdk/workflows/index.d.ts +20 -12
- package/dist/sdk/workflows/index.d.ts.map +1 -1
- package/dist/services/config/additional-instructions.d.ts +1 -1
- package/dist/services/config/additional-instructions.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/cli.ts +39 -56
- package/src/commands/builtin-registry.ts +37 -0
- package/src/commands/cli/chat/index.ts +1 -3
- package/src/{sdk → commands/cli}/management-commands.ts +15 -55
- package/src/commands/cli/session.ts +1 -1
- package/src/commands/cli/workflow-command.test.ts +250 -16
- package/src/commands/cli/workflow-inputs.test.ts +1 -0
- package/src/commands/cli/workflow-inputs.ts +13 -3
- package/src/commands/cli/workflow-list.test.ts +1 -0
- package/src/commands/cli/workflow-list.ts +0 -0
- package/src/commands/cli/workflow-status.ts +1 -1
- package/src/commands/cli/workflow.ts +191 -11
- package/src/sdk/define-workflow.test.ts +47 -16
- package/src/sdk/define-workflow.ts +24 -6
- package/src/sdk/errors.test.ts +11 -0
- package/src/sdk/errors.ts +13 -0
- package/src/sdk/index.test.ts +92 -0
- package/src/sdk/index.ts +71 -15
- package/src/sdk/primitives/inputs.ts +48 -0
- package/src/sdk/primitives/metadata.ts +63 -0
- package/src/sdk/primitives/run.ts +81 -0
- package/src/sdk/primitives/sessions.test.ts +594 -0
- package/src/sdk/primitives/sessions.ts +328 -0
- package/src/sdk/runtime/executor.ts +36 -115
- package/src/sdk/runtime/orchestrator-entry.ts +110 -0
- package/src/sdk/runtime/tmux.ts +33 -0
- package/src/sdk/types.ts +26 -91
- package/src/sdk/workflows/builtin/deep-research-codebase/claude/index.ts +1 -0
- package/src/sdk/workflows/builtin/deep-research-codebase/copilot/index.ts +1 -0
- package/src/sdk/workflows/builtin/deep-research-codebase/opencode/index.ts +1 -0
- package/src/sdk/workflows/builtin/open-claude-design/claude/index.ts +1 -0
- package/src/sdk/workflows/builtin/open-claude-design/copilot/index.ts +1 -0
- package/src/sdk/workflows/builtin/open-claude-design/opencode/index.ts +1 -0
- package/src/sdk/workflows/builtin/ralph/claude/index.ts +1 -0
- package/src/sdk/workflows/builtin/ralph/copilot/index.ts +1 -0
- package/src/sdk/workflows/builtin/ralph/opencode/index.ts +1 -0
- package/src/sdk/workflows/index.ts +68 -51
- package/src/services/config/additional-instructions.ts +1 -1
- package/.agents/skills/test-driven-development/SKILL.md +0 -371
- package/.agents/skills/test-driven-development/testing-anti-patterns.md +0 -299
- package/dist/commands/cli/session.d.ts +0 -67
- package/dist/commands/cli/session.d.ts.map +0 -1
- package/dist/commands/cli/workflow-status.d.ts +0 -63
- package/dist/commands/cli/workflow-status.d.ts.map +0 -1
- package/dist/sdk/commander.d.ts +0 -74
- package/dist/sdk/commander.d.ts.map +0 -1
- package/dist/sdk/management-commands.d.ts +0 -42
- package/dist/sdk/management-commands.d.ts.map +0 -1
- package/dist/sdk/workflow-cli.d.ts +0 -103
- package/dist/sdk/workflow-cli.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin-registry.d.ts +0 -113
- package/dist/sdk/workflows/builtin-registry.d.ts.map +0 -1
- package/src/sdk/commander.ts +0 -161
- package/src/sdk/workflow-cli.ts +0 -409
- package/src/sdk/workflows/builtin-registry.ts +0 -23
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
# Workflow Inputs
|
|
2
|
+
|
|
3
|
+
Workflows collect structured data from the user at invocation time through
|
|
4
|
+
a single uniform API: `ctx.inputs` (and `s.inputs` inside stage
|
|
5
|
+
callbacks). This reference covers how the inputs pipe works, how to
|
|
6
|
+
declare input schemas, and how values reach the workflow from the CLI
|
|
7
|
+
and the interactive picker.
|
|
8
|
+
|
|
9
|
+
## The inputs pipe
|
|
10
|
+
|
|
11
|
+
Every workflow run receives a typed inputs object. When the workflow
|
|
12
|
+
declares an `inputs` schema, only the declared field names are valid
|
|
13
|
+
keys — accessing undeclared fields is a compile-time error. The
|
|
14
|
+
runtime populates it from whichever invocation surface the user chose.
|
|
15
|
+
|
|
16
|
+
### Input precedence (highest → lowest)
|
|
17
|
+
|
|
18
|
+
CLI flags always win. Under them, the order depends on the composition shape:
|
|
19
|
+
|
|
20
|
+
- **Single-workflow worker** (`runWorkflow({ workflow })`):
|
|
21
|
+
```
|
|
22
|
+
CLI flags > runWorkflow({ workflow, inputs }) > defineWorkflow defaults
|
|
23
|
+
```
|
|
24
|
+
- **Multi-workflow cli** (`iterating registry, with inputs })`):
|
|
25
|
+
```
|
|
26
|
+
CLI flags > runWorkflow({ workflow, inputs }) > runWorkflow({ inputs }) > defineWorkflow defaults
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
With ``, the CLI-flags layer is skipped entirely — `inputs`
|
|
30
|
+
become the top-of-chain value. Use this from tests or any programmatic
|
|
31
|
+
caller that doesn't want its host process argv parsed.
|
|
32
|
+
|
|
33
|
+
`defineWorkflow` field `default` is always the final fallback if no
|
|
34
|
+
higher-precedence value supplies one.
|
|
35
|
+
|
|
36
|
+
### Invocation surfaces
|
|
37
|
+
|
|
38
|
+
| Surface | How values are supplied | How they land in `ctx.inputs` |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| **Single-worker, positional** — `bun run src/claude-worker.ts "fix the bug"` | The dev wires a `[prompt...]` Commander argument; the collected string is passed as `prompt` | `{ prompt: "fix the bug" }` |
|
|
41
|
+
| **Single-worker, structured** — `bun run src/claude-worker.ts --research_doc=notes.md --focus=standard` | The dev registers one `--<field> <value>` option per declared input via `getInputSchema(wf)` | `{ research_doc: "notes.md", focus: "standard" }` |
|
|
42
|
+
| **Multi-workflow CLI** — `bun run src/cli.ts gen-spec --research_doc=notes.md` | The dev registers one Commander subcommand per workflow; the subcommand's `--<field>` options match the workflow's declared inputs | Same as above |
|
|
43
|
+
| **Interactive picker** — `atomic workflow -a claude` (atomic builtins only) | User fills in a form rendered from the declared schema | Whatever the user typed, keyed by field name |
|
|
44
|
+
| **Picker in user app** — dev mounts `WorkflowPickerPanel` from `@bastani/atomic/workflows/components` | Same form-based collection, against the dev's own registry | Same as above |
|
|
45
|
+
| **Programmatic** — `runWorkflow({ workflow, inputs })` | Plain `Record<string, string>` passed directly — no argv parsing | Top-of-chain value; falls back to `defineWorkflow` defaults |
|
|
46
|
+
|
|
47
|
+
Workflow code is the same either way — it always reads
|
|
48
|
+
`ctx.inputs.<name>`. The invocation surface is a CLI concern, not a
|
|
49
|
+
workflow concern.
|
|
50
|
+
|
|
51
|
+
### CLI flags in user-app CLIs
|
|
52
|
+
|
|
53
|
+
`runWorkflow` and `createRegistry`/`listWorkflows` are pure SDK primitives —
|
|
54
|
+
they do not auto-register CLI flags. It is the developer's responsibility to
|
|
55
|
+
wire flags using whatever CLI library they prefer. The canonical pattern is to
|
|
56
|
+
iterate `getInputSchema(wf)` and call `.option(--<name> <value>)` for each
|
|
57
|
+
declared input. See §"Scaffold a new workflow from scratch" in `SKILL.md` for
|
|
58
|
+
the full template.
|
|
59
|
+
|
|
60
|
+
The atomic CLI builds its own per-input flags internally by iterating
|
|
61
|
+
`getInputSchema(wf)` when the user passes `-n <name> -a <agent>`. That is
|
|
62
|
+
atomic's own implementation, not an SDK feature.
|
|
63
|
+
|
|
64
|
+
## Reading inputs
|
|
65
|
+
|
|
66
|
+
Workflows that accept a user prompt should declare it explicitly as an
|
|
67
|
+
input. Destructure it once at the top of `.run()` so every stage can
|
|
68
|
+
close over a bare string:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
defineWorkflow({
|
|
72
|
+
name: "answer",
|
|
73
|
+
source: import.meta.path,
|
|
74
|
+
description: "Single-turn answer",
|
|
75
|
+
inputs: [
|
|
76
|
+
{ name: "prompt", type: "text", required: true, description: "question to answer" },
|
|
77
|
+
],
|
|
78
|
+
})
|
|
79
|
+
.for("claude")
|
|
80
|
+
.run(async (ctx) => {
|
|
81
|
+
const prompt = ctx.inputs.prompt ?? "";
|
|
82
|
+
|
|
83
|
+
await ctx.stage({ name: "answer" }, {}, {}, async (s) => {
|
|
84
|
+
await s.session.query(prompt);
|
|
85
|
+
s.save(s.sessionId);
|
|
86
|
+
});
|
|
87
|
+
})
|
|
88
|
+
.compile();
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For structured workflows, read each declared field by name. Pull them
|
|
92
|
+
out of `ctx.inputs` once for readability and so downstream stages can
|
|
93
|
+
close over locals:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
defineWorkflow({
|
|
97
|
+
name: "gen-spec",
|
|
98
|
+
source: import.meta.path,
|
|
99
|
+
description: "Convert a research doc into a detailed execution spec",
|
|
100
|
+
inputs: [
|
|
101
|
+
{ name: "research_doc", type: "string", required: true },
|
|
102
|
+
{
|
|
103
|
+
name: "focus",
|
|
104
|
+
type: "enum",
|
|
105
|
+
required: true,
|
|
106
|
+
values: ["minimal", "standard", "exhaustive"],
|
|
107
|
+
default: "standard",
|
|
108
|
+
},
|
|
109
|
+
{ name: "notes", type: "text" },
|
|
110
|
+
],
|
|
111
|
+
})
|
|
112
|
+
.for("claude")
|
|
113
|
+
.run(async (ctx) => {
|
|
114
|
+
const { research_doc, focus } = ctx.inputs;
|
|
115
|
+
const notes = ctx.inputs.notes ?? "";
|
|
116
|
+
|
|
117
|
+
await ctx.stage({ name: "write-spec" }, {}, {}, async (s) => {
|
|
118
|
+
await s.session.query(
|
|
119
|
+
`Read ${research_doc} and produce a ${focus} spec.` +
|
|
120
|
+
(notes ? `\n\nExtra guidance:\n${notes}` : ""),
|
|
121
|
+
);
|
|
122
|
+
s.save(s.sessionId);
|
|
123
|
+
});
|
|
124
|
+
})
|
|
125
|
+
.compile();
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The nullish coalescing on `notes` handles the optional field case —
|
|
129
|
+
declared-but-unset inputs resolve to `undefined` unless they have a
|
|
130
|
+
`default`.
|
|
131
|
+
|
|
132
|
+
**Style convention.** Inside a stage callback, both `s.inputs.<name>` and
|
|
133
|
+
`ctx.inputs.<name>` resolve to the same value. Either of these patterns
|
|
134
|
+
works:
|
|
135
|
+
|
|
136
|
+
- **Destructure once at the top of `.run()`** so each stage closes over a
|
|
137
|
+
bare local. Best when many stages reference the same input.
|
|
138
|
+
- **Inline access** with `(s.inputs.<name> ?? "")` at each call site. Best
|
|
139
|
+
for short workflows or when each stage uses a different field.
|
|
140
|
+
|
|
141
|
+
Pick whichever reads cleaner for your workflow. Examples in other reference
|
|
142
|
+
files use the inline form for brevity in focused snippets.
|
|
143
|
+
|
|
144
|
+
## Declaring an input schema
|
|
145
|
+
|
|
146
|
+
Pass an `inputs` array to `defineWorkflow({ ... })`. Each entry is a
|
|
147
|
+
`WorkflowInput`:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
interface WorkflowInput {
|
|
151
|
+
/** Field name — becomes the CLI flag (`--<name>`) and form label. */
|
|
152
|
+
name: string;
|
|
153
|
+
/** Input kind: string | text | enum */
|
|
154
|
+
type: "string" | "text" | "enum";
|
|
155
|
+
/** Whether the field must be non-empty before the workflow can run. */
|
|
156
|
+
required?: boolean;
|
|
157
|
+
/** Short description shown as the field caption. */
|
|
158
|
+
description?: string;
|
|
159
|
+
/** Placeholder shown when the field is empty. */
|
|
160
|
+
placeholder?: string;
|
|
161
|
+
/** Default value — enums use this to pick their initial value. */
|
|
162
|
+
default?: string;
|
|
163
|
+
/** Allowed values — required when `type` is `"enum"`. */
|
|
164
|
+
values?: readonly string[];
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Picking a field type
|
|
169
|
+
|
|
170
|
+
| Type | Use when | Picker renders as | Example |
|
|
171
|
+
|---|---|---|---|
|
|
172
|
+
| `string` | Short single-line values — identifiers, file paths, branch names | Single-row text input | `research_doc: "notes.md"` |
|
|
173
|
+
| `text` | Longer free-form prose — specs, prompts, extra context | Multi-row text area | `spec: "Build a..."` |
|
|
174
|
+
| `enum` | A fixed set of allowed values | Radio-button row | `focus: "standard" \| "minimal" \| "exhaustive"` |
|
|
175
|
+
|
|
176
|
+
Rule of thumb: use `enum` whenever there's a closed set of options — it
|
|
177
|
+
gives users discoverable choices instead of making them remember magic
|
|
178
|
+
strings, and the CLI will reject invalid values at parse time.
|
|
179
|
+
|
|
180
|
+
### Validation enforced by the runtime
|
|
181
|
+
|
|
182
|
+
The `defineWorkflow` builder validates the schema at compile time and
|
|
183
|
+
rejects authoring mistakes immediately — you won't discover them in
|
|
184
|
+
production:
|
|
185
|
+
|
|
186
|
+
- **Input names must be valid CLI flag tails** — start with a letter,
|
|
187
|
+
then letters/digits/underscores/dashes. `1bad` is rejected because
|
|
188
|
+
`--1bad` isn't a parseable flag.
|
|
189
|
+
- **Enum inputs must declare `values`** — an enum with no choices is
|
|
190
|
+
always invalid.
|
|
191
|
+
- **Enum `default` must be in `values`** — prevents drift between the
|
|
192
|
+
default and the allowed set.
|
|
193
|
+
- **No duplicate names** — two inputs with the same `name` shadow each
|
|
194
|
+
other and are rejected.
|
|
195
|
+
|
|
196
|
+
At invocation time, the CLI does a second pass to catch runtime errors
|
|
197
|
+
before spinning up any tmux session:
|
|
198
|
+
|
|
199
|
+
- **Required fields must be non-empty** (whitespace-only strings are
|
|
200
|
+
treated as empty). Missing required fields produce a clear
|
|
201
|
+
`Missing required input --<name>` error and exit non-zero.
|
|
202
|
+
- **Enum values must be in the allowed list.** `--focus=bogus` produces
|
|
203
|
+
`Invalid value for --focus: "bogus". Expected one of: minimal, standard, exhaustive.`
|
|
204
|
+
- **Unknown flags are rejected.** A `--random_flag=value` that isn't in
|
|
205
|
+
the schema produces `Unknown input --random_flag` with the valid
|
|
206
|
+
flag list appended.
|
|
207
|
+
|
|
208
|
+
This validation runs before any workflow code, so a malformed
|
|
209
|
+
invocation can never reach your `.run()` callback in a half-filled
|
|
210
|
+
state.
|
|
211
|
+
|
|
212
|
+
## Declaring a prompt input
|
|
213
|
+
|
|
214
|
+
Workflows that accept a user prompt should declare it explicitly in their
|
|
215
|
+
`inputs` array rather than relying on an implicit key:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
inputs: [
|
|
219
|
+
{ name: "prompt", type: "text", required: true, description: "task to perform" },
|
|
220
|
+
]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Declaring `prompt` explicitly gives compile-time safety — `ctx.inputs.prompt` is typed and accessing an undeclared key is a type error. For atomic builtins you can still pass a positional string (`atomic workflow -n ralph -a claude "fix the bug"`); user-app workers handle positional args however the dev wired their Commander entrypoint (e.g., `program.argument("[prompt...]", ...)`), and the collected string is passed as the `prompt` input value.
|
|
224
|
+
|
|
225
|
+
For workflows that need both a free-form prompt AND structured parameters,
|
|
226
|
+
declare all fields in the schema:
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
inputs: [
|
|
230
|
+
{ name: "prompt", type: "text", required: true, description: "what to build" },
|
|
231
|
+
{ name: "focus", type: "enum", required: true, values: ["minimal", "standard", "exhaustive"], default: "standard" },
|
|
232
|
+
{ name: "notes", type: "text", description: "extra context" },
|
|
233
|
+
]
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Reserved input names
|
|
237
|
+
|
|
238
|
+
The following input names are rejected by `defineWorkflow` because they
|
|
239
|
+
collide with the atomic CLI's `workflow` subcommand flags and management
|
|
240
|
+
subcommands:
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
name, agent, detach, list, help, version, session, status
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The first six (`name`, `agent`, `detach`, `list`, `help`, `version`) collide
|
|
247
|
+
with the atomic CLI's `workflow` subcommand flags (`-n/--name`,
|
|
248
|
+
`-a/--agent`, `-d/--detach`, `-l/--list`, `-h/--help`, `-v/--version`).
|
|
249
|
+
The last two (`session`, `status`) collide with the atomic CLI's management
|
|
250
|
+
subcommands (`atomic workflow session …`, `atomic workflow status`).
|
|
251
|
+
|
|
252
|
+
Declaring an input with any of these names throws at `defineWorkflow` time
|
|
253
|
+
(before the workflow can be registered into any registry):
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
[atomic] defineWorkflow: input name "name" is reserved by the worker CLI.
|
|
257
|
+
Rename it. Reserved names: name, agent, detach, list, help, version, session, status.
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
This is enforced in `defineWorkflow`, not at runtime, so the error surfaces
|
|
261
|
+
at workflow authoring time — the workflow cannot be registered.
|
|
262
|
+
|
|
263
|
+
User-app CLIs built on the SDK primitives are **not** bound by these
|
|
264
|
+
reservations at runtime. The check exists only to keep workflows portable
|
|
265
|
+
to the atomic CLI without needing to rename inputs later.
|
|
266
|
+
|
|
267
|
+
## The interactive picker
|
|
268
|
+
|
|
269
|
+
### Atomic builtins — `atomic workflow -a <agent>`
|
|
270
|
+
|
|
271
|
+
`atomic workflow -a <agent>` (no `-n`) launches the interactive picker for
|
|
272
|
+
atomic builtins (TTY only — non-interactive contexts skip straight to
|
|
273
|
+
`--help`). All direct attached or detached builtin runs should include
|
|
274
|
+
`-n <workflow-name>` explicitly; omitting `-n` is the intentional
|
|
275
|
+
picker-discovery path.
|
|
276
|
+
|
|
277
|
+
The picker is the `WorkflowPickerPanel` component from
|
|
278
|
+
`@bastani/atomic/workflows/components`. It:
|
|
279
|
+
|
|
280
|
+
1. Calls `registry.list()` and filters to workflows whose `agent` field
|
|
281
|
+
matches `<agent>`. No source labels — registry entries are just
|
|
282
|
+
workflows someone registered; where they came from is irrelevant.
|
|
283
|
+
2. Shows a Telescope-style fuzzy list. The user types to filter,
|
|
284
|
+
arrows (or ⌃j/⌃k) to navigate, ↵ to lock in a selection.
|
|
285
|
+
3. Renders the selected workflow's form. One field per declared input,
|
|
286
|
+
type-specific rendering (`string` → single-row input, `text` →
|
|
287
|
+
multi-row textarea, `enum` → radio row). Free-form workflows
|
|
288
|
+
(no declared inputs) fall back to a single `prompt` text field.
|
|
289
|
+
4. Validates required fields on ⌃d. If any are empty, focus jumps to
|
|
290
|
+
the first invalid field.
|
|
291
|
+
5. Confirms with a y/n modal, then tears down the picker and hands
|
|
292
|
+
off to the workflow executor — same live-run surface users see
|
|
293
|
+
when they invoke the workflow with `-n` directly.
|
|
294
|
+
|
|
295
|
+
The picker is the preferred discovery path for users who don't remember
|
|
296
|
+
flag names. Structured workflows benefit the most from it because the
|
|
297
|
+
form teaches the schema as the user fills it in.
|
|
298
|
+
|
|
299
|
+
### User apps — mount `WorkflowPickerPanel` yourself
|
|
300
|
+
|
|
301
|
+
`runWorkflow` does **not** auto-launch a picker. If a user app wants a
|
|
302
|
+
picker UX, the developer mounts `WorkflowPickerPanel` from
|
|
303
|
+
`@bastani/atomic/workflows/components` against their own registry:
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
import { WorkflowPickerPanel } from "@bastani/atomic/workflows/components";
|
|
307
|
+
|
|
308
|
+
const panel = await WorkflowPickerPanel.create({ agent: "claude", registry });
|
|
309
|
+
const result = await panel.waitForSelection();
|
|
310
|
+
panel.destroy();
|
|
311
|
+
if (result) {
|
|
312
|
+
await runWorkflow({ workflow: result.workflow, inputs: result.inputs });
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Single-workflow workers have no picker — the file already identifies the
|
|
317
|
+
workflow, so the user just passes the declared `--<input>` flags directly.
|
|
318
|
+
|
|
319
|
+
## Duplicate registration
|
|
320
|
+
|
|
321
|
+
Registering the same `${agent}/${name}` key twice throws at composition-root
|
|
322
|
+
time (before any workflow runs):
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
[atomic] Duplicate workflow registration: "claude/my-workflow" is already registered.
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
There is no silent shadowing. Pick distinct `(agent, name)` pairs across all
|
|
329
|
+
workflows in the registry. For the full key-scheme and validate-on-register
|
|
330
|
+
contract see `registry-and-validation.md`.
|
|
331
|
+
|
|
332
|
+
## Invocation details
|
|
333
|
+
|
|
334
|
+
See SKILL.md §"Invocation surfaces" for the full table. This section covers
|
|
335
|
+
flag-parsing nuances specific to structured inputs.
|
|
336
|
+
|
|
337
|
+
Both `--flag=value` and `--flag value` forms are accepted by Commander. Short
|
|
338
|
+
flags (`-x value`) are NOT parsed as structured inputs — only long-form
|
|
339
|
+
`--<name>` flags resolve against the schema.
|
|
340
|
+
|
|
341
|
+
For user-app CLIs, the dev wires the flags via `getInputSchema(wf)` and
|
|
342
|
+
Commander; there is no `-n`/`-a`/`-d` built into user-app workers. If the
|
|
343
|
+
dev wants detached runs, they pass `detach: true` to `runWorkflow` or wire
|
|
344
|
+
their own `--detach` Commander option.
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# User's own app — single-workflow worker
|
|
348
|
+
bun run src/claude-worker.ts --focus=standard --research_doc=notes.md
|
|
349
|
+
bun run src/claude-worker.ts --focus standard --research_doc notes.md
|
|
350
|
+
|
|
351
|
+
# User's own app — multi-workflow CLI
|
|
352
|
+
bun run src/cli.ts gen-spec --focus=standard --research_doc=notes.md
|
|
353
|
+
|
|
354
|
+
# Atomic builtins — use atomic CLI's -n/-a/-d flags
|
|
355
|
+
atomic workflow -n gen-spec -a claude --focus=standard --research_doc=notes.md
|
|
356
|
+
atomic workflow -n gen-spec -a claude -d --focus=standard # detached
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Pitfalls
|
|
360
|
+
|
|
361
|
+
### Declare every field you access
|
|
362
|
+
|
|
363
|
+
With typed inputs, accessing `ctx.inputs.foo` when `foo` is not declared
|
|
364
|
+
in the workflow's `inputs` array is a compile-time error. If your workflow
|
|
365
|
+
needs a prompt field, declare it:
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
inputs: [
|
|
369
|
+
{ name: "prompt", type: "text", required: true, description: "task prompt" },
|
|
370
|
+
]
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
If the developer has wired a `[prompt...]` Commander argument in their
|
|
374
|
+
entrypoint, the collected string is passed as the `prompt` input value —
|
|
375
|
+
but only if the workflow actually declares a `prompt` input. Accessing
|
|
376
|
+
`ctx.inputs.prompt` without declaring it is a compile-time error. The
|
|
377
|
+
atomic CLI applies the same rule for builtins: a positional string is
|
|
378
|
+
rejected if the builtin workflow does not declare a `prompt` input.
|
|
379
|
+
|
|
380
|
+
### Don't rename inputs across workflow versions
|
|
381
|
+
|
|
382
|
+
Declared input names are part of the workflow's public API — they map
|
|
383
|
+
directly to `--<name>` flags and field identifiers in the picker.
|
|
384
|
+
Renaming a field is a breaking change for any script that invokes the
|
|
385
|
+
workflow. If you need to rename, add the new name alongside the old,
|
|
386
|
+
migrate callers, then remove the old name in a later change.
|
|
387
|
+
|
|
388
|
+
### Don't put secrets in `default`
|
|
389
|
+
|
|
390
|
+
Defaults are visible in the picker and printed in CLI errors. They're
|
|
391
|
+
fine for values like `"standard"` but not for API keys or auth tokens.
|
|
392
|
+
Read those from environment variables inside the workflow instead.
|
|
@@ -3,7 +3,7 @@ name: debugger
|
|
|
3
3
|
description: Debug errors, test failures, and unexpected behavior. Use PROACTIVELY when encountering issues, analyzing stack traces, or investigating system problems.
|
|
4
4
|
tools: Bash, Agent, Edit, Grep, Glob, Read, TaskCreate, TaskList, TaskGet, TaskUpdate, LSP, WebFetch, WebSearch
|
|
5
5
|
skills:
|
|
6
|
-
-
|
|
6
|
+
- tdd
|
|
7
7
|
- playwright-cli
|
|
8
8
|
model: opus
|
|
9
9
|
---
|
|
@@ -18,7 +18,7 @@ Available tools:
|
|
|
18
18
|
- PREFER to use the playwright-cli (refer to playwright-cli skill) OVER web fetch/search tools
|
|
19
19
|
- ALWAYS load the playwright-cli skill before usage with the Skill tool.
|
|
20
20
|
- ALWAYS ASSUME you have the playwright-cli tool installed (if the `playwright-cli` command fails, fallback to `npx playwright-cli`).
|
|
21
|
-
- ALWAYS invoke your
|
|
21
|
+
- ALWAYS invoke your tdd skill BEFORE creating or modifying any tests.
|
|
22
22
|
</EXTREMELY_IMPORTANT>
|
|
23
23
|
|
|
24
24
|
## Search Strategy
|
|
@@ -3,7 +3,7 @@ name: reviewer
|
|
|
3
3
|
description: Code reviewer for proposed code changes.
|
|
4
4
|
tools: Bash, Agent, Glob, Grep, Read, TodoWrite, TaskCreate, TaskList, TaskGet, TaskUpdate, WebFetch, WebSearch
|
|
5
5
|
skills:
|
|
6
|
-
-
|
|
6
|
+
- tdd
|
|
7
7
|
- playwright-cli
|
|
8
8
|
model: opus
|
|
9
9
|
---
|
package/.claude/agents/worker.md
CHANGED
|
@@ -3,7 +3,7 @@ name: worker
|
|
|
3
3
|
description: Implement a SINGLE task from a task list.
|
|
4
4
|
tools: Bash, Agent, Edit, Grep, Glob, Read, LSP, TaskCreate, TaskList, TaskGet, TaskUpdate
|
|
5
5
|
skills:
|
|
6
|
-
-
|
|
6
|
+
- tdd
|
|
7
7
|
model: sonnet
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -82,7 +82,7 @@ Frequently use unit tests, integration tests, and end-to-end tests to verify you
|
|
|
82
82
|
|
|
83
83
|
### Testing Anti-Patterns
|
|
84
84
|
|
|
85
|
-
Use your
|
|
85
|
+
Use your tdd skill to avoid common pitfalls when writing tests.
|
|
86
86
|
|
|
87
87
|
## Design Principles
|
|
88
88
|
|
|
@@ -25,7 +25,7 @@ Available tools:
|
|
|
25
25
|
- PREFER to use the playwright-cli (refer to playwright-cli skill) OVER web fetch/search tools
|
|
26
26
|
- ALWAYS load the playwright-cli skill before usage with the Skill tool.
|
|
27
27
|
- ALWAYS ASSUME you have the playwright-cli tool installed (if the `playwright-cli` command fails, fallback to `npx playwright-cli`).
|
|
28
|
-
- ALWAYS invoke your
|
|
28
|
+
- ALWAYS invoke your tdd skill BEFORE creating or modifying any tests.
|
|
29
29
|
</EXTREMELY_IMPORTANT>
|
|
30
30
|
|
|
31
31
|
## Search Strategy
|
package/.github/agents/worker.md
CHANGED
|
@@ -143,7 +143,7 @@ Frequently use unit tests, integration tests, and end-to-end tests to verify you
|
|
|
143
143
|
|
|
144
144
|
### Testing Anti-Patterns
|
|
145
145
|
|
|
146
|
-
Use your
|
|
146
|
+
Use your tdd skill to avoid common pitfalls when writing tests.
|
|
147
147
|
|
|
148
148
|
## Design Principles
|
|
149
149
|
|
package/.mcp.json
CHANGED
|
@@ -26,7 +26,7 @@ Available tools:
|
|
|
26
26
|
- PREFER to use the playwright-cli (refer to playwright-cli skill) OVER web fetch/search tools
|
|
27
27
|
- ALWAYS load the playwright-cli skill before usage with the Skill tool.
|
|
28
28
|
- ALWAYS ASSUME you have the playwright-cli tool installed (if the `playwright-cli` command fails, fallback to `npx playwright-cli`).
|
|
29
|
-
- ALWAYS invoke your
|
|
29
|
+
- ALWAYS invoke your tdd skill BEFORE creating or modifying any tests.
|
|
30
30
|
</EXTREMELY_IMPORTANT>
|
|
31
31
|
|
|
32
32
|
## Search Strategy
|
|
@@ -83,7 +83,7 @@ Frequently use unit tests, integration tests, and end-to-end tests to verify you
|
|
|
83
83
|
|
|
84
84
|
### Testing Anti-Patterns
|
|
85
85
|
|
|
86
|
-
Use your
|
|
86
|
+
Use your tdd skill to avoid common pitfalls when writing tests.
|
|
87
87
|
|
|
88
88
|
## Design Principles
|
|
89
89
|
|