@bastani/atomic 0.9.16-alpha.6 → 0.9.16-alpha.8
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/CHANGELOG.md +19 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +4 -4
- package/dist/builtin/intercom/broker/broker.ts +617 -22
- package/dist/builtin/intercom/broker/client-message-validation.ts +9 -0
- package/dist/builtin/intercom/broker/client.ts +200 -10
- package/dist/builtin/intercom/broker/pending-send-registry.ts +4 -0
- package/dist/builtin/intercom/broker/send-handler.ts +90 -36
- package/dist/builtin/intercom/broker/send-signature.ts +20 -8
- package/dist/builtin/intercom/group.ts +85 -0
- package/dist/builtin/intercom/index.bundle.mjs +680 -53
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/session-target.ts +54 -0
- package/dist/builtin/intercom/skills/intercom/SKILL.md +18 -3
- package/dist/builtin/intercom/source-ownership.ts +31 -0
- package/dist/builtin/intercom/types.ts +115 -0
- package/dist/builtin/mcp/index.bundle.mjs +109 -35
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/qlty/SKILL.md +123 -0
- package/dist/builtin/subagents/skills/qlty/references/coding-with-ai-agents.md +64 -0
- package/dist/builtin/subagents/skills/qlty/references/commands.md +291 -0
- package/dist/builtin/subagents/skills/qlty/references/plugins-and-extensions.md +228 -0
- package/dist/builtin/subagents/skills/qlty/references/quickstart.md +110 -0
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +173 -51
- package/dist/builtin/web-access/index.bundle.mjs +109 -35
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +23 -0
- package/dist/builtin/workflows/README.md +40 -37
- package/dist/builtin/workflows/builtin/adversarial-verification.js +13 -0
- package/dist/builtin/workflows/builtin/{shared-prompts.ts → chunk-0x6e303p.js} +137 -133
- package/dist/builtin/workflows/builtin/chunk-29wrp38a.js +199 -0
- package/dist/builtin/workflows/builtin/chunk-2dqb5s2q.js +602 -0
- package/dist/builtin/workflows/builtin/chunk-4febxsv4.js +264 -0
- package/dist/builtin/workflows/builtin/chunk-5n10x7j2.js +69730 -0
- package/dist/builtin/workflows/builtin/chunk-5wgwscd0.js +4 -0
- package/dist/builtin/workflows/builtin/chunk-6fqs7c01.js +155 -0
- package/dist/builtin/workflows/builtin/chunk-7430zyas.js +126 -0
- package/dist/builtin/workflows/builtin/chunk-7at6dnkr.js +33 -0
- package/dist/builtin/workflows/builtin/chunk-82ha8p41.js +175 -0
- package/dist/builtin/workflows/builtin/chunk-bfkmzv9h.js +156 -0
- package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
- package/dist/builtin/workflows/builtin/chunk-cdtd3m3w.js +529 -0
- package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
- package/dist/builtin/workflows/builtin/chunk-hdpj1dkw.js +2447 -0
- package/dist/builtin/workflows/builtin/chunk-hzzn6adg.js +221 -0
- package/dist/builtin/workflows/builtin/chunk-nqr34qp3.js +1061 -0
- package/dist/builtin/workflows/builtin/chunk-qwzvgxnq.js +404 -0
- package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
- package/dist/builtin/workflows/builtin/chunk-v04c5qmd.js +1207 -0
- package/dist/builtin/workflows/builtin/chunk-wpckd35c.js +12 -0
- package/dist/builtin/workflows/builtin/chunk-x2ghn0je.js +4110 -0
- package/dist/builtin/workflows/builtin/chunk-zf28603f.js +1080 -0
- package/dist/builtin/workflows/builtin/classify-and-act.js +12 -0
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +10 -0
- package/dist/builtin/workflows/builtin/generate-and-filter.js +12 -0
- package/dist/builtin/workflows/builtin/goal.js +16 -0
- package/dist/builtin/workflows/builtin/index.js +49 -0
- package/dist/builtin/workflows/builtin/loop-until-done.js +12 -0
- package/dist/builtin/workflows/builtin/open-claude-design.js +11 -0
- package/dist/builtin/workflows/builtin/ralph.js +16 -0
- package/dist/builtin/workflows/builtin/steering-context.d.ts +6 -0
- package/dist/builtin/workflows/builtin/steering-context.js +7 -0
- package/dist/builtin/workflows/builtin/tournament.js +13 -0
- package/dist/builtin/workflows/package.json +10 -7
- package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1250 -428
- package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +956 -427
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +403 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +327 -0
- package/dist/builtin/workflows/src/shared/budget.d.ts +67 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +60 -0
- package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.d.ts +21 -0
- package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +12 -5
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +2 -0
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/builtin-install-layout.d.ts +1 -1
- package/dist/core/builtin-install-layout.d.ts.map +1 -1
- package/dist/core/builtin-install-layout.js +1 -1
- package/dist/core/builtin-install-layout.js.map +1 -1
- package/dist/core/codex-fast-mode.d.ts +10 -7
- package/dist/core/codex-fast-mode.d.ts.map +1 -1
- package/dist/core/codex-fast-mode.js +31 -13
- package/dist/core/codex-fast-mode.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +35 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +6 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +4 -0
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +1 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +8 -0
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +2 -0
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +4 -2
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/workflow-stage-admission.d.ts +6 -1
- package/dist/core/workflow-stage-admission.d.ts.map +1 -1
- package/dist/core/workflow-stage-admission.js +8 -9
- package/dist/core/workflow-stage-admission.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +1 -1
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +4 -0
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +69 -10
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +18 -2
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +33 -5
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +8 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/intercom.md +15 -6
- package/docs/packages.md +2 -2
- package/docs/providers.md +8 -3
- package/docs/quickstart.md +3 -2
- package/docs/rpc.md +21 -4
- package/docs/settings.md +6 -4
- package/docs/skills.md +4 -0
- package/docs/subagents.md +1 -1
- package/docs/usage.md +1 -1
- package/docs/workflows.md +112 -239
- package/npm-shrinkwrap.json +32 -32
- package/package.json +9 -13
- package/dist/builtin/workflows/ambient.d.ts +0 -61
- package/dist/builtin/workflows/builtin/adversarial-verification-prompts.ts +0 -26
- package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +0 -391
- package/dist/builtin/workflows/builtin/adversarial-verification.ts +0 -34
- package/dist/builtin/workflows/builtin/classify-and-act-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/classify-and-act-runner.ts +0 -108
- package/dist/builtin/workflows/builtin/classify-and-act.ts +0 -40
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts +0 -96
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +0 -37
- package/dist/builtin/workflows/builtin/generate-and-filter-prompts.ts +0 -41
- package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +0 -90
- package/dist/builtin/workflows/builtin/generate-and-filter.ts +0 -31
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +0 -64
- package/dist/builtin/workflows/builtin/goal-convergence.ts +0 -87
- package/dist/builtin/workflows/builtin/goal-ledger.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-models.ts +0 -72
- package/dist/builtin/workflows/builtin/goal-orchestrator-prompts.ts +0 -94
- package/dist/builtin/workflows/builtin/goal-prompts.ts +0 -211
- package/dist/builtin/workflows/builtin/goal-reducer.ts +0 -176
- package/dist/builtin/workflows/builtin/goal-reports.ts +0 -76
- package/dist/builtin/workflows/builtin/goal-reverify.ts +0 -305
- package/dist/builtin/workflows/builtin/goal-review.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-runner.ts +0 -504
- package/dist/builtin/workflows/builtin/goal-schemas.ts +0 -89
- package/dist/builtin/workflows/builtin/goal-types.ts +0 -164
- package/dist/builtin/workflows/builtin/goal.ts +0 -78
- package/dist/builtin/workflows/builtin/index.ts +0 -16
- package/dist/builtin/workflows/builtin/loop-until-done-prompts.ts +0 -87
- package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +0 -282
- package/dist/builtin/workflows/builtin/loop-until-done.ts +0 -51
- package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +0 -305
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +0 -337
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +0 -347
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +0 -313
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -311
- package/dist/builtin/workflows/builtin/open-claude-design.ts +0 -57
- package/dist/builtin/workflows/builtin/pattern-artifact-root.ts +0 -28
- package/dist/builtin/workflows/builtin/progress-scoring.ts +0 -230
- package/dist/builtin/workflows/builtin/ralph-core.ts +0 -449
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +0 -100
- package/dist/builtin/workflows/builtin/ralph-models.ts +0 -183
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +0 -103
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +0 -100
- package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -455
- package/dist/builtin/workflows/builtin/ralph.ts +0 -82
- package/dist/builtin/workflows/builtin/review-convergence.ts +0 -229
- package/dist/builtin/workflows/builtin/selection-math.ts +0 -156
- package/dist/builtin/workflows/builtin/steering-context.ts +0 -51
- package/dist/builtin/workflows/builtin/tournament-prompts.ts +0 -70
- package/dist/builtin/workflows/builtin/tournament-runner.ts +0 -400
- package/dist/builtin/workflows/builtin/tournament.ts +0 -73
- package/dist/builtin/workflows/builtin/verification-criteria.ts +0 -330
- package/dist/builtin/workflows/builtin/verification-prompts.ts +0 -206
- package/dist/builtin/workflows/builtin/verification-usage.ts +0 -44
package/docs/workflows.md
CHANGED
|
@@ -36,7 +36,7 @@ Default to a workflow for non-trivial work with a verifiable objective — see [
|
|
|
36
36
|
- [Built-in Workflows](#built-in-workflows)
|
|
37
37
|
- [Writing a Workflow](#writing-a-workflow)
|
|
38
38
|
- [Scope-Guard Starter Pattern](#scope-guard-starter-pattern)
|
|
39
|
-
- [The `workflow()`
|
|
39
|
+
- [The `workflow()` definition](#the-workflow-definition)
|
|
40
40
|
- [WorkflowContext](#workflowcontext)
|
|
41
41
|
- [Task and Stage Options](#task-and-stage-options)
|
|
42
42
|
- [StageContext](#stagecontext)
|
|
@@ -51,10 +51,9 @@ Default to a workflow for non-trivial work with a verifiable objective — see [
|
|
|
51
51
|
- [Workflow Configuration](#workflow-configuration)
|
|
52
52
|
- [Settings](#settings)
|
|
53
53
|
- [Package Setup](#package-setup)
|
|
54
|
-
- [Programmatic
|
|
55
|
-
- [Fast
|
|
54
|
+
- [Programmatic usage](#programmatic-usage)
|
|
55
|
+
- [Fast inference for workflow stages](#fast-inference-for-workflow-stages)
|
|
56
56
|
- [Context Engineering](#context-engineering)
|
|
57
|
-
- [Migrating from the `defineWorkflow()` Builder API](#migrating-from-the-defineworkflow-builder-api)
|
|
58
57
|
- [Design Checklist](#design-checklist)
|
|
59
58
|
- [Common Mistakes](#common-mistakes)
|
|
60
59
|
- [Workflow Best Practices](#workflow-best-practices)
|
|
@@ -125,6 +124,26 @@ Workflow run identifiers are shown in full everywhere they are presented to user
|
|
|
125
124
|
|
|
126
125
|
Stage targeting is exact but not UUID-bound, because stage identifiers are not all bare UUIDs. A `stageId` resolves by exact stage id — a bare UUID at the root, the full `runId:stageId` composite for a stage inside a nested workflow, or `tool:<argsHash>` for a `ctx.tool` node — or by exact stage or tool name. Partial names no longer match, so `build` will not select `build-check`. Two stages that share an exact name are still reported as ambiguous, listing the full matching identifiers.
|
|
127
126
|
|
|
127
|
+
#### Intercom delivery to pending workflow stages
|
|
128
|
+
|
|
129
|
+
A known workflow stage whose session has not initialized is still addressable by the workflow run's full UUID and its exact authored stage key. From a sibling session in the same workflow Intercom group, use ordinary Intercom delivery:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
intercom({
|
|
133
|
+
action: "send",
|
|
134
|
+
to: "<runId>:reviewer",
|
|
135
|
+
message: "Scope changed: raw amendment text is now part of the oracle."
|
|
136
|
+
})
|
|
137
|
+
// queued — distinct from live-session delivered
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Send material updates through Intercom to every affected workflow stage, including stages that have not started. Atomic queues messages only for known pending stages and delivers them when their sessions initialize, before their first model turn. Live stage delivery is immediate. Use `ask` once the stage session is live and can reply. Unknown run/stage identities retain the ordinary unknown-target failure.
|
|
141
|
+
|
|
142
|
+
The workflows extension persists pending messages with run state across resume/replay and broker restart. Each exact run/stage key accepts 50 queued messages; the next send is refused without eviction. Only sessions in the run's Intercom group may queue them. When the stage session initializes, Atomic delivers its messages FIFO through the ordinary inbound Intercom path **before the first model turn**. The transcript labels them **Messages received before you started**, preserves sender identity and `Sent:` timestamps, and keeps them separate from the stage task prompt. Duplicate logical message IDs and stage-attempt restarts do not redeliver a message.
|
|
143
|
+
|
|
144
|
+
If the destination is skipped, the run is cancelled, or the stage becomes terminal before its session initializes, Atomic marks queued messages undeliverable rather than dropping them. Senders whose messages requested acknowledgment receive a correlated failure notification. Running and completed stages continue through their existing live, late, and post-mortem routes.
|
|
145
|
+
|
|
146
|
+
|
|
128
147
|
At 80 columns and wider, each `BACKGROUND` card uses two rows so the id is not squeezed beside the workflow name: the first row contains the status glyph and full UUID, and the second contains the workflow name followed by its mode, progress, live-tool total when more than one is active, pending/running `ctx.tool` node names and statuses as space permits, and elapsed/status metadata. Tool nodes are read-only durable graph nodes, not attachable stage chats. The panel renders every qualifying top-level run, so each card is two rows high (plus the existing spacing between cards). Below 80 columns, the panel keeps its collapsed form, omits ids and tool names, and includes a live-tool count when one or more tool nodes are pending or running.
|
|
129
148
|
|
|
130
149
|
For chat surfaces such as workflow status, run detail, dispatch confirmation, and the run picker, a full id wraps onto continuation rows when the card is narrower than the id. The renderer never ellipsizes the id and keeps the card border closed at its minimum layout width, while terminals below that floor — including sub-30-column terminals — can hard-clip the box. An awaiting-input attribution banner is titled `AWAITING INPUT` and contains the same two identity rows — `?` plus the full run id, then the workflow name and optional metadata — while the existing prompt question and options remain below it in the normal prompt UI.
|
|
@@ -148,7 +167,7 @@ Below the breakpoint the same run set is represented by the collapsed count line
|
|
|
148
167
|
Workflow files are plain TypeScript modules. Create `.atomic/workflows/explain-file.ts`:
|
|
149
168
|
|
|
150
169
|
```ts
|
|
151
|
-
import { workflow } from "@bastani/workflows";
|
|
170
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
152
171
|
import { Type } from "typebox";
|
|
153
172
|
|
|
154
173
|
export default workflow({
|
|
@@ -231,6 +250,8 @@ The shapes, cheapest first:
|
|
|
231
250
|
|
|
232
251
|
For every non-trivial workflow task, perform a short workflow-architecture pass before the first launch. Choose the execution shape before starting substantive work; reconnaissance already counts as inline execution. Derive the task's implementation lifecycle needs, whole-codebase research needs, independent work slices, competing strategies, exact API/type/build contracts, schema or generated-artifact contracts, state-transition/lifecycle behavior, deterministic stop conditions, and required evidence.
|
|
233
252
|
|
|
253
|
+
For coding tasks, that pass also infers repository intent from repo-level behavior before objectives and acceptance criteria freeze: mine git history (including `git log --show-signature`), merged PRs, issues, commits, and review comments for unwritten conventions — commit signing, message style and issue linking, changelog discipline, PR size and review norms — weighing the requesting user's own activity highest so the authored contract captures norms no doc states. Non-coding tasks mine their analogous available context sources (issue trackers, long-form docs, chat or comment threads, prior artifacts) the same way. Inferred conventions fill contract gaps; they never override the stated objective or explicit repository docs.
|
|
254
|
+
|
|
234
255
|
Use this compact coverage matrix internally (it may stay concise for a straightforward task), and let every unresolved material row change the graph choice:
|
|
235
256
|
|
|
236
257
|
```text
|
|
@@ -268,7 +289,7 @@ Ask these questions in order and stop at the cheapest shape that satisfies every
|
|
|
268
289
|
8. **Is it only specialist evidence-gathering?** If the parent keeps control, no completion gate is needed, and the work is bounded (a debug pass, a parallel research fanout, one noisy investigation), inline subagents are enough—and cheaper than a workflow.
|
|
269
290
|
9. **Is it truly tiny?** Deterministic, low-risk, single-file/no-test/no-review—answer or edit inline and stop.
|
|
270
291
|
|
|
271
|
-
A first named workflow launch commits the selected execution shape for the turn. For one task, end the turn after that launch. For an independent queue, the selected shape is a bounded launch wave: issue every planned per-item top-level launch up to the concurrency bound before ending the turn. Do not casually chain unplanned unrelated top-level workflow launches. When one task needs multiple workflow capabilities or dependent items need ordered handoffs, design composition **before** launch: author one custom parent, import project/package definitions or builtins from `@bastani/workflows/builtin`, and call `ctx.workflow(...)`. Nested children preserve their stages and guarantees within the expanded graph up to `maxDepth`, but they remain under the parent's root lifecycle and failure boundary.
|
|
292
|
+
A first named workflow launch commits the selected execution shape for the turn. For one task, end the turn after that launch. For an independent queue, the selected shape is a bounded launch wave: issue every planned per-item top-level launch up to the concurrency bound before ending the turn. Do not casually chain unplanned unrelated top-level workflow launches. When one task needs multiple workflow capabilities or dependent items need ordered handoffs, design composition **before** launch: author one custom parent, import project/package definitions or builtins from `@bastani/atomic/workflows/builtin`, and call `ctx.workflow(...)`. Nested children preserve their stages and guarantees within the expanded graph up to `maxDepth`, but they remain under the parent's root lifecycle and failure boundary.
|
|
272
293
|
|
|
273
294
|
Choose the cheapest complete graph. Routing cues are not a reason to add decorative stages: avoid duplicated research and review loops. Before launch, state the selected graph, why one broad builtin is sufficient or insufficient, the evidence each major stage produces, and the stop/repair conditions. A simple direct match can be one sentence; a composed graph should briefly name its children and task-specific gates.
|
|
274
295
|
|
|
@@ -386,7 +407,7 @@ A natural-language request for a worktree does not configure runner isolation. I
|
|
|
386
407
|
```ts
|
|
387
408
|
// .atomic/workflows/issue-to-pr.ts
|
|
388
409
|
import { spawnSync } from "node:child_process";
|
|
389
|
-
import { workflow } from "@bastani/workflows";
|
|
410
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
390
411
|
import { Type, type Static } from "typebox";
|
|
391
412
|
|
|
392
413
|
const reviewDecision = Type.Object(
|
|
@@ -634,7 +655,7 @@ So every builtin stage prompt carries a **steering propagation contract**:
|
|
|
634
655
|
Every bundled workflow wraps its run context once at the definition entry point, so each `ctx.task`, `ctx.chain`, and `ctx.parallel` prompt carries the contract automatically. Do the same in a custom workflow:
|
|
635
656
|
|
|
636
657
|
```ts
|
|
637
|
-
import { withSteeringPropagationContext } from "@bastani/workflows/builtin/steering-context";
|
|
658
|
+
import { withSteeringPropagationContext } from "@bastani/atomic/workflows/builtin/steering-context";
|
|
638
659
|
|
|
639
660
|
export default workflow({
|
|
640
661
|
name: "my-workflow",
|
|
@@ -669,7 +690,7 @@ A long-running stage gets compacted, and compaction ranks lines individually rat
|
|
|
669
690
|
Wrap contract text in `keepContext` so it survives verbatim regardless of the compression ratio:
|
|
670
691
|
|
|
671
692
|
```ts
|
|
672
|
-
import { keepContext, workflow } from "@bastani/workflows";
|
|
693
|
+
import { keepContext, workflow } from "@bastani/atomic/workflows";
|
|
673
694
|
|
|
674
695
|
const prompt = [
|
|
675
696
|
keepContext("Research only. Do not implement code changes."),
|
|
@@ -710,7 +731,7 @@ Note what is tagged and what is not: the constraint and the criteria are protect
|
|
|
710
731
|
**Steering.** A `send` amendment is authoritative and stages must carry it forward, but it is one short message arriving late into an already-long session, competing against the entire transcript for retention. Tagging it keeps it alive until the stage acts on it:
|
|
711
732
|
|
|
712
733
|
```
|
|
713
|
-
|
|
734
|
+
intercom({ action: "send", to: `${runId}:<stageKey>`, message:
|
|
714
735
|
"<keepContext>\nNew requirement: the fix must not change the public API.\n</keepContext>" })
|
|
715
736
|
```
|
|
716
737
|
|
|
@@ -743,7 +764,7 @@ Across these builtins, model-facing stages use compact, outcome-first contracts
|
|
|
743
764
|
|
|
744
765
|
### Six composable pattern builtins
|
|
745
766
|
|
|
746
|
-
The six common patterns are full definitions exported from `@bastani/workflows/builtin`:
|
|
767
|
+
The six common patterns are full definitions exported from `@bastani/atomic/workflows/builtin`:
|
|
747
768
|
|
|
748
769
|
| Workflow | Required input | Bounded/defaulted knobs | Principal declared outputs |
|
|
749
770
|
|---|---|---|---|
|
|
@@ -764,7 +785,7 @@ import {
|
|
|
764
785
|
loopUntilDone,
|
|
765
786
|
ralph,
|
|
766
787
|
tournament,
|
|
767
|
-
} from "@bastani/workflows/builtin";
|
|
788
|
+
} from "@bastani/atomic/workflows/builtin";
|
|
768
789
|
|
|
769
790
|
const research = await ctx.workflow(fanOutAndSynthesize, {
|
|
770
791
|
inputs: {
|
|
@@ -782,6 +803,8 @@ All six can run by name or as nested definitions. Prefer composition over copyin
|
|
|
782
803
|
Goal persists the literal objective and immutable acceptance criteria in a run ledger, delegates implementation through bounded orchestrator turns, records receipts, and asks independent reviewers to inspect the current delta. A TypeScript reducer returns `complete`, `blocked`, or `needs_human` rather than trusting free-form completion claims. The complete Goal artifact directory — both its owning run segment and unique `artifact-<id>` segment — is a durable checkpoint. A fresh-ID continuation therefore reuses the source ledger, receipts, and review paths without rerunning replayed producer stages; loading that ledger preserves its existing records without duplicating replayed receipts or reviews. The model-visible `goal-ledger.json` continues to omit internal turn numbers, while a sibling `goal-ledger-state.json` preserves the complete turn-bearing state for lossless continuation reloads. A live chain of continuations also protects that original owner from retention pruning.
|
|
783
804
|
|
|
784
805
|
Goal reviewers derive checks from the literal objective before consulting implementation receipts, inspect the actual checkout delta, and report commands, observed output, and file:line evidence rather than internal reasoning. Shared contracts cover acceptance-matrix traceability, contract-fidelity risks, end-to-end and QA-video evidence, and independent verification. `stop_review_loop` is the authoritative convergence signal: it remains `false` for P0–P2 findings, any `required_by_objective` finding, or unproven implementation/validation requirements; it becomes `true` only when independent evidence proves the objective and only non-blocking or authorized post-approval work remains. The deterministic reducer consumes that signal without reinterpreting free-form prose.
|
|
806
|
+
Goal and Ralph stage prompts — orchestrator, implementation, and reviewer alike — also carry shared code-quality verification guidance that points at the `qlty` skill for linting, auto-formatting, complexity and duplication metrics, and code smells, weighted higher when the objective asks for verifiers or high code quality. Repository-defined checks in `AGENTS.md`/`CLAUDE.md`, package scripts, and CI stay authoritative.
|
|
807
|
+
Both workflows also share repository-intent mining guidance: implementers and reviewers infer maintainer and requesting-user conventions from repository behavior — git history (including `git log --show-signature`), merged PRs, issues and their comments, review comments, commit subjects and trailers, and CI/branch-protection config — covering norms written docs rarely state, such as commit signing, message style and issue linking, changelog discipline, and review etiquette. The dominant, recent, intentional pattern wins over accidental drift, the requesting user's own activity weighs highest, implementers match the inferred conventions (an unsigned commit in a signed history is a miss, not a preference), and reviewers report deviations as convention findings. Behavioral evidence fills contract gaps; it never overrides the literal objective, acceptance criteria, or explicit `AGENTS.md`/`CLAUDE.md` guidance.
|
|
785
808
|
Goal and Ralph share the same low-confidence finding re-verification and per-round convergence evidence, documented under [`ralph`](#ralph).
|
|
786
809
|
|
|
787
810
|
| Input | Type | Required | Default | Description |
|
|
@@ -879,7 +902,7 @@ If required inputs are missing or ambiguous, Atomic asks for them or opens the i
|
|
|
879
902
|
Workflow files are TypeScript modules that export a workflow definition:
|
|
880
903
|
|
|
881
904
|
```ts
|
|
882
|
-
import { workflow } from "@bastani/workflows";
|
|
905
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
883
906
|
import { Type } from "typebox";
|
|
884
907
|
|
|
885
908
|
export default workflow({
|
|
@@ -954,7 +977,6 @@ Authoring basics:
|
|
|
954
977
|
- `outputs` declares typed outputs that parent workflows receive from `ctx.workflow(childWorkflow, ...)`.
|
|
955
978
|
- `run: async (ctx) => { ... }` defines the workflow body.
|
|
956
979
|
|
|
957
|
-
To migrate an existing file from the removed `defineWorkflow(...).compile()` builder, see [Migrating from the `defineWorkflow()` Builder API](#migrating-from-the-defineworkflow-builder-api) for the full method-to-key mapping, a before/after walkthrough, and a conversion checklist.
|
|
958
980
|
|
|
959
981
|
`prompt` and `task` are aliases for task text inside authored workflow primitives. Prefer `prompt` because it mirrors lower-level `stage.prompt(...)`; `task` remains useful in `ctx.chain(...)` examples.
|
|
960
982
|
|
|
@@ -1057,7 +1079,7 @@ Protect a stage's role constraints, acceptance criteria, and prohibitions with `
|
|
|
1057
1079
|
|
|
1058
1080
|
### Inputs
|
|
1059
1081
|
|
|
1060
|
-
Inputs are declared with TypeBox `Type.*` schemas in the `inputs` object. Import `Type` from `typebox` directly in workflow files. Workflow packages still declare `typebox` as a peer dependency so TypeBox schemas resolve under `tsc` — see [Programmatic
|
|
1082
|
+
Inputs are declared with TypeBox `Type.*` schemas in the `inputs` object. Import `Type` from `typebox` directly in workflow files. Workflow packages still declare `typebox` as a peer dependency so TypeBox schemas resolve under `tsc` — see [Programmatic usage](#programmatic-usage). Common input schemas map to picker kinds and accepted runtime values:
|
|
1061
1083
|
|
|
1062
1084
|
| TypeBox schema | Picker kind | Accepted runtime value |
|
|
1063
1085
|
|---|---|---|
|
|
@@ -1168,7 +1190,7 @@ The same rule applies to inputs: `inputs: { counts: Type.Array(Type.Number()) }`
|
|
|
1168
1190
|
When you already have a precise TypeScript type for a deeply-nested serializable value and don't want to hand-write the equivalent TypeBox schema, wrap a permissive runtime schema with `Type.Unsafe<MyType>(...)`. The **static** type becomes exactly `MyType` (so `ctx.inputs`, the `run` return, and `child.outputs` stay precise), while the **runtime** check stays as lenient as the wrapped schema. Use a `type` alias rather than an `interface` for the wrapped type — an `interface` has no implicit index signature, so it does not satisfy the serializable-output constraint:
|
|
1169
1191
|
|
|
1170
1192
|
```ts
|
|
1171
|
-
import { workflow } from "@bastani/workflows";
|
|
1193
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
1172
1194
|
import { Type } from "typebox";
|
|
1173
1195
|
|
|
1174
1196
|
type ResearchPacket = {
|
|
@@ -1205,7 +1227,7 @@ Tradeoff: `Type.Unsafe<T>()` does not deeply validate at runtime — it trusts t
|
|
|
1205
1227
|
- TypeScript checks the `run` return against your declared outputs at **compile time** (a missing required output or wrong value type is a TypeScript error), and TypeBox `Value` checks it at **runtime** (rejecting undeclared keys and enforcing the declared shape recursively).
|
|
1206
1228
|
- `ctx.workflow(child)` returns a discriminated child result. When `child.exited === false`, `child.outputs` is the child's full declared `outputs` contract; when `child.exited === true`, `child.outputs` is `Partial<TOutputs>` because child `ctx.exit({ outputs })` may intentionally provide only a subset.
|
|
1207
1229
|
|
|
1208
|
-
Use `Static<typeof schema>` (both `Static` and `TSchema` are re-exported from `@bastani/workflows`) when you need the inferred TypeScript type of a schema directly — for example to type a helper that builds an output value.
|
|
1230
|
+
Use `Static<typeof schema>` (both `Static` and `TSchema` are re-exported from `@bastani/atomic/workflows`) when you need the inferred TypeScript type of a schema directly — for example to type a helper that builds an output value.
|
|
1209
1231
|
|
|
1210
1232
|
### Stage follow-on user messages
|
|
1211
1233
|
|
|
@@ -1329,7 +1351,7 @@ User-defined workflows are ordinary TypeScript modules. Import the workflow defi
|
|
|
1329
1351
|
|
|
1330
1352
|
```ts
|
|
1331
1353
|
// .atomic/workflows/shared-research.ts
|
|
1332
|
-
import { workflow } from "@bastani/workflows";
|
|
1354
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
1333
1355
|
import { Type } from "typebox";
|
|
1334
1356
|
|
|
1335
1357
|
export default workflow({
|
|
@@ -1349,7 +1371,7 @@ export default workflow({
|
|
|
1349
1371
|
});
|
|
1350
1372
|
|
|
1351
1373
|
// .atomic/workflows/research-and-synthesize.ts
|
|
1352
|
-
import { workflow } from "@bastani/workflows";
|
|
1374
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
1353
1375
|
import { Type } from "typebox";
|
|
1354
1376
|
import sharedResearch from "./shared-research.js";
|
|
1355
1377
|
|
|
@@ -1395,22 +1417,22 @@ import {
|
|
|
1395
1417
|
openClaudeDesign,
|
|
1396
1418
|
ralph,
|
|
1397
1419
|
tournament,
|
|
1398
|
-
} from "@bastani/workflows/builtin";
|
|
1420
|
+
} from "@bastani/atomic/workflows/builtin";
|
|
1399
1421
|
```
|
|
1400
1422
|
|
|
1401
1423
|
Or import one individual module:
|
|
1402
1424
|
|
|
1403
1425
|
```ts
|
|
1404
|
-
import goal from "@bastani/workflows/builtin/goal";
|
|
1405
|
-
import ralph from "@bastani/workflows/builtin/ralph";
|
|
1426
|
+
import goal from "@bastani/atomic/workflows/builtin/goal";
|
|
1427
|
+
import ralph from "@bastani/atomic/workflows/builtin/ralph";
|
|
1406
1428
|
```
|
|
1407
1429
|
|
|
1408
1430
|
Example parent that maps a repository and verifies the synthesis:
|
|
1409
1431
|
|
|
1410
1432
|
```ts
|
|
1411
|
-
import { workflow } from "@bastani/workflows";
|
|
1433
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
1412
1434
|
import { Type } from "typebox";
|
|
1413
|
-
import { adversarialVerification, fanOutAndSynthesize } from "@bastani/workflows/builtin";
|
|
1435
|
+
import { adversarialVerification, fanOutAndSynthesize } from "@bastani/atomic/workflows/builtin";
|
|
1414
1436
|
|
|
1415
1437
|
export default workflow({
|
|
1416
1438
|
name: "research-and-verify",
|
|
@@ -1570,7 +1592,7 @@ Use a fresh task when one check at a material boundary is enough. This complete
|
|
|
1570
1592
|
|
|
1571
1593
|
```ts
|
|
1572
1594
|
// .atomic/workflows/scope-guard-boundary.ts
|
|
1573
|
-
import { workflow } from "@bastani/workflows";
|
|
1595
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
1574
1596
|
import { Type, type Static } from "typebox";
|
|
1575
1597
|
|
|
1576
1598
|
const decisionLogSchema = Type.Object(
|
|
@@ -1680,7 +1702,7 @@ Use `ctx.stage(...)` when one independent checker needs a retained conversation.
|
|
|
1680
1702
|
|
|
1681
1703
|
```ts
|
|
1682
1704
|
// .atomic/workflows/scope-guard-retained.ts
|
|
1683
|
-
import { workflow } from "@bastani/workflows";
|
|
1705
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
1684
1706
|
import { Type } from "typebox";
|
|
1685
1707
|
|
|
1686
1708
|
function continueWorker(sessionFile: string | undefined) {
|
|
@@ -1755,7 +1777,7 @@ Use a live peer only when steering during generation adds clear value. Both bran
|
|
|
1755
1777
|
|
|
1756
1778
|
```ts
|
|
1757
1779
|
// .atomic/workflows/scope-guard-live.ts
|
|
1758
|
-
import { workflow } from "@bastani/workflows";
|
|
1780
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
1759
1781
|
import { Type, type Static } from "typebox";
|
|
1760
1782
|
|
|
1761
1783
|
const coordinationSchema = Type.Object(
|
|
@@ -1902,9 +1924,9 @@ export default workflow({
|
|
|
1902
1924
|
|
|
1903
1925
|
The parallel fan-out has one shared parent frontier and downstream persistence waits for both branches. Blocking asks use the guard's retained conversation; the fresh persistence task turns the final transcript into the bounded artifact before correctness review. If Intercom is unavailable, `warn` runs that task as a boundary check, `block` requires `ctx.ui`, and `off` records that no guard approval exists.
|
|
1904
1926
|
|
|
1905
|
-
## The `workflow()`
|
|
1927
|
+
## The `workflow()` definition
|
|
1906
1928
|
|
|
1907
|
-
`workflow(spec)`
|
|
1929
|
+
Use `workflow(spec)` to author a workflow. It validates the schema maps, normalizes or infers the name, and returns a frozen `WorkflowDefinition` for export, discovery, and `ctx.workflow(...)` composition.
|
|
1908
1930
|
|
|
1909
1931
|
```typescript
|
|
1910
1932
|
function workflow<
|
|
@@ -1974,6 +1996,19 @@ A recoverable provider or rate-limit block is not the terminal `blocked` status:
|
|
|
1974
1996
|
|
|
1975
1997
|
A heartbeat the host has already accepted into the parent's queue is beyond that pass, because nothing withdraws a queued message. It is invalidated instead at the moment the parent reads it: the typed card's exact `runId + scheduledAt` identity must still be pending for a current nonterminal run. If the run has since reached a terminal state, this process no longer knows that run, or a durable resume has reused the run id with a later pending boundary, the old heartbeat is excluded from the model's context and cannot steer the parent. That covers all ways a stale card survives — one parked through a long turn while its run finished, one recovered from a previous process at startup, and one admitted before a same-ID durable resume. The card already rendered in your transcript is deliberately left alone: it is a true record that the heartbeat was raised, and rewriting scrollback after the fact would be worse than leaving it. Only the model-facing steer is invalidated.
|
|
1976
1998
|
|
|
1999
|
+
### `budget`
|
|
2000
|
+
|
|
2001
|
+
```typescript
|
|
2002
|
+
readonly budget?: {
|
|
2003
|
+
readonly maxDurationMs?: number;
|
|
2004
|
+
readonly maxTokens?: number;
|
|
2005
|
+
readonly maxCost?: number;
|
|
2006
|
+
readonly warnAtPercent?: number;
|
|
2007
|
+
};
|
|
2008
|
+
```
|
|
2009
|
+
|
|
2010
|
+
The optional budget sets duration, token, and cost limits for this workflow. Atomic freezes the declaration into the compiled definition and resolves each field over the extension default when the workflow runs. See [Run budgets](#run-budgets) for precedence and validation rules.
|
|
2011
|
+
|
|
1977
2012
|
### `inputs`
|
|
1978
2013
|
|
|
1979
2014
|
```typescript
|
|
@@ -2042,25 +2077,23 @@ interface WorkflowDefinition<
|
|
|
2042
2077
|
TInputs extends WorkflowInputValues = WorkflowInputValues,
|
|
2043
2078
|
TOutputs extends WorkflowOutputValues = WorkflowOutputValues,
|
|
2044
2079
|
TRunInputs extends WorkflowInputValues = TInputs,
|
|
2045
|
-
TDefinitionBrand extends object = {},
|
|
2046
2080
|
> {
|
|
2047
|
-
readonly __piWorkflow: true;
|
|
2048
|
-
readonly __runInputs?: TRunInputs;
|
|
2049
2081
|
readonly name: string;
|
|
2050
2082
|
readonly normalizedName: string;
|
|
2051
2083
|
readonly description: string;
|
|
2052
2084
|
readonly autoAttach?: true;
|
|
2053
2085
|
readonly heartbeatIntervalMinutes: number;
|
|
2086
|
+
readonly budget?: WorkflowBudget;
|
|
2054
2087
|
readonly inputs: WorkflowInputSchemaMap;
|
|
2055
2088
|
readonly outputs?: WorkflowOutputSchemaMap;
|
|
2056
2089
|
readonly inputBindings?: { readonly worktree?: WorkflowWorktreeInputBinding };
|
|
2057
|
-
run(
|
|
2058
|
-
ctx: WorkflowRunContext<TInputs, TDefinitionBrand, TOutputs>,
|
|
2059
|
-
): Promise<TOutputs> | TOutputs;
|
|
2090
|
+
run(ctx: WorkflowRunContext<TInputs, TOutputs>): Promise<TOutputs> | TOutputs;
|
|
2060
2091
|
}
|
|
2061
2092
|
```
|
|
2062
2093
|
|
|
2063
|
-
`
|
|
2094
|
+
`TRunInputs` describes the validated inputs accepted by `run(...)` and `ctx.workflow(...)`; it defaults to the workflow's resolved input values.
|
|
2095
|
+
|
|
2096
|
+
`workflow({...})` returns a `WorkflowDefinition` with the resolved name, normalized lookup name, description, runtime defaults, optional budget, schema maps, optional worktree input binding, and `run` function. Authors provide the fields documented above, and Atomic fills the normalized and defaulted values.
|
|
2064
2097
|
|
|
2065
2098
|
## WorkflowContext
|
|
2066
2099
|
|
|
@@ -2146,7 +2179,7 @@ ctx.workflow<
|
|
|
2146
2179
|
TChildOutputs extends WorkflowOutputValues,
|
|
2147
2180
|
TChildRunInputs extends WorkflowInputValues = TChildInputs,
|
|
2148
2181
|
>(
|
|
2149
|
-
definition: WorkflowDefinition<TChildInputs, TChildOutputs, TChildRunInputs
|
|
2182
|
+
definition: WorkflowDefinition<TChildInputs, TChildOutputs, TChildRunInputs>,
|
|
2150
2183
|
...args: WorkflowRunChildArgs<TChildRunInputs>
|
|
2151
2184
|
): Promise<WorkflowChildResult<TChildOutputs>>;
|
|
2152
2185
|
|
|
@@ -2176,7 +2209,7 @@ const child = await ctx.workflow(sharedResearch, {
|
|
|
2176
2209
|
});
|
|
2177
2210
|
```
|
|
2178
2211
|
|
|
2179
|
-
|
|
2212
|
+
Pass a definition returned by `workflow({...})`. See [Workflow Composition](#workflow-composition) for graph flattening, replay, failure, and parent-exit behavior, and [`WorkflowChildResult`](#workflowchildresult) for the discriminated result.
|
|
2180
2213
|
|
|
2181
2214
|
### `ctx.stage(name, options?)`
|
|
2182
2215
|
|
|
@@ -2996,7 +3029,7 @@ The workflow tool action surface is:
|
|
|
2996
3029
|
- discovery: `list`, `get`, `inputs`, plus `models` for the configured model catalog
|
|
2997
3030
|
- execution: named `run` with validated `workflow` and `inputs`
|
|
2998
3031
|
- inspection: `status`, `stages`, `stage`, `transcript`
|
|
2999
|
-
-
|
|
3032
|
+
- prompt response: `answer`; run control: `pause`, `interrupt`, `quit`, `resume`; free-form stage communication: ordinary Intercom `send`/`ask` to exact `<runId>:<stageKey>` targets
|
|
3000
3033
|
- rediscovery: `reload`
|
|
3001
3034
|
|
|
3002
3035
|
Every registered `workflow` tool call has one hard two-minute wall-clock deadline at the shared public tool boundary. The deadline covers request handling through the returned result; for background `run` and `resume`, it therefore covers startup/resume admission and acknowledgement only, not the workflow execution that continues after acknowledgement. A deadline returns one structured result:
|
|
@@ -3012,9 +3045,9 @@ Every registered `workflow` tool call has one hard two-minute wall-clock deadlin
|
|
|
3012
3045
|
}
|
|
3013
3046
|
```
|
|
3014
3047
|
|
|
3015
|
-
Expiry aborts the request operation signal so work that supports cancellation can stop, discards any later success or error, and never retries the action. The interactive engine remains available for the next command. For mutating actions (`reload`, `run`, `
|
|
3048
|
+
Expiry aborts the request operation signal so work that supports cancellation can stop, discards any later success or error, and never retries the action. The interactive engine remains available for the next command. For mutating actions (`reload`, `run`, `answer`, `pause`, `resume`, `interrupt`, and `quit`), the error additionally says that the outcome is unknown and instructs you to inspect workflow status before retrying; a timeout never claims that a mutation succeeded. When a timed-out `run` has already allocated its detached run, the structured result includes that exact full `runId`; inspect `status` with that id before any retry. A timeout before run allocation has no `runId`. Read-only actions (`models`, `list`, `get`, `inputs`, `status`, `stages`, `stage`, and `transcript`) omit that unknown-state guidance.
|
|
3016
3049
|
|
|
3017
|
-
From interactive chat, named workflow launches run in the background so the parent chat stays available. Run `/workflow connect <run>` to see agents working and chat with and steer each stage. Inspection and control calls (`status`, `stages`, `stage`, `transcript`, `
|
|
3050
|
+
From interactive chat, named workflow launches run in the background so the parent chat stays available. Run `/workflow connect <run>` to see agents working and chat with and steer each stage. Inspection, prompt-response, and control calls (`status`, `stages`, `stage`, `transcript`, `answer`, `pause`, `resume`, `interrupt`, `quit`) remain available while work runs.
|
|
3018
3051
|
|
|
3019
3052
|
`workflow({ action: "models" })` returns the registry's configured-auth catalog snapshot in registry order. Each entry includes `provider`, `id`, `fullId`, an `isCurrent` marker, and `availableThinkingLevels` derived from the real model's `reasoning` and `thinkingLevelMap` metadata. This is not proof of credentials, entitlements, OAuth freshness, or live provider access, and it exposes no authentication details.
|
|
3020
3053
|
|
|
@@ -3125,10 +3158,10 @@ workflow({ action: "transcript", runId: "<full-run-uuid>", stageId: "review" })
|
|
|
3125
3158
|
workflow({ action: "transcript", runId: "<full-run-uuid>", stageId: "review", tail: 40 })
|
|
3126
3159
|
workflow({ action: "transcript", runId: "<full-run-uuid>", stageId: "review", limit: 20, includeToolOutput: true })
|
|
3127
3160
|
|
|
3128
|
-
//
|
|
3129
|
-
|
|
3130
|
-
workflow({ action: "
|
|
3131
|
-
workflow({ action: "
|
|
3161
|
+
// Free-form stage communication uses Intercom; prompt responses use workflow answer.
|
|
3162
|
+
intercom({ action: "send", to: "<full-run-uuid>:review", message: "please focus on tests" })
|
|
3163
|
+
workflow({ action: "answer", runId: "<full-run-uuid>", stageId: "approval", promptId: "prompt-1", response: true })
|
|
3164
|
+
workflow({ action: "resume", runId: "<full-run-uuid>", stageId: "review", message: "continue with tests" })
|
|
3132
3165
|
|
|
3133
3166
|
workflow({ action: "pause", runId: "<full-run-uuid>" })
|
|
3134
3167
|
workflow({ action: "pause", runId: "<full-run-uuid>", stageId: "review" })
|
|
@@ -3153,25 +3186,15 @@ Control behavior:
|
|
|
3153
3186
|
|
|
3154
3187
|
- `runId` requires the full 36-character run UUID for every lifecycle and inspection action, including `status`. User-facing status surfaces print that exact value, so pass it back verbatim; typed prefixes are rejected with a distinct `Run id must be a full 36-character UUID` diagnostic rather than resolved. Because ids are matched exactly and are unique, no run target is ambiguous. Status lists and run pickers show top-level user-launched workflows; nested child runs are implementation details of the expanded parent graph.
|
|
3155
3188
|
- `status`, `stages`, `stage`, and `transcript` with an explicit full `runId` first use the current session store, then perform one exact DBOS hydration when that id is absent locally. This is inspection only: Atomic does not claim ownership, change status, run workflow code, or resume the workflow. A stale durable `running` root is shown as `crashed` with its resumability and an explicit `/workflow resume <id>` hint; fresh work owned by another Atomic process remains `running`, offers read-only status guidance, and stays protected from local control or resume. Deleted/tombstoned, absent, malformed, cyclic, orphaned, nonreciprocal, out-of-scope, and duplicate-node records report distinct failures instead of inventing a partial graph. `status` without `runId` remains current-session-only and never scans durable history.
|
|
3156
|
-
- `status` without `runId` lists every top-level run in the session with a concise per-run summary: the full run id, workflow name, run status, started/ended timing with pause-adjusted elapsed time, currently active stages, and awaiting-input details (count plus the stage, prompt id, kind, and message for each pending human prompt). In-flight runs are listed first. The summaries carry the exact identifiers that `pause
|
|
3189
|
+
- `status` without `runId` lists every top-level run in the session with a concise per-run summary: the full run id, workflow name, run status, started/ended timing with pause-adjusted elapsed time, currently active stages, and awaiting-input details (count plus the stage, prompt id, kind, and message for each pending human prompt). In-flight runs are listed first. The summaries carry the exact identifiers that `answer`, `pause`, `resume`, `interrupt`, and `quit` accept, so an orchestrating agent can list runs and act on them directly.
|
|
3157
3190
|
- `statusFilter` narrows the `status` run listing: run statuses (`pending`, `running`, `paused`, `blocked`, `completed`, `failed`, `skipped`, `cancelled`, `killed`) match runs directly, `awaiting_input` selects runs with at least one stage awaiting input or pending human prompt, and `all` (the default) includes everything.
|
|
3158
3191
|
- `format: "json"` on data-bearing inspection actions (`status`, `stages`, `stage`, `transcript`) returns the full structured result; the default text output for `status` is the concise per-run summary list.
|
|
3159
3192
|
- `status` / `status <runId>` show terminal `ctx.exit(...)` statuses (`completed`, `skipped`, `cancelled`, or `blocked`) and the optional exit reason when one was supplied.
|
|
3160
3193
|
- `stages` lists stage summaries, including flattened stages from nested `ctx.workflow(...)` imports and `sessionFile`/`transcriptPath` when a stage has a persisted session. Use `statusFilter: "all"` to include completed, failed, skipped, and pending stages.
|
|
3161
3194
|
- `stage` returns details for one stage by exact stage id or exact stage name, including nested child stages shown in the expanded graph and the persisted `sessionFile` when available. User-facing graph and control messages print full stage IDs; pass one back verbatim, or use the stage's exact name. Prefixes and partial names no longer resolve. Two stages sharing an exact name return an ambiguity diagnostic rather than selecting one.
|
|
3162
3195
|
- `transcript` is reference-first with a small preview by default: it returns metadata, transcript paths, and up to 5 recent entries. For targeted lookup, quote the exact `sessionFile`/`transcriptPath` value without changing platform separators (preserve Windows backslashes), search it with `rg` or `grep`, then read only small surrounding ranges. Text results include JSON-escaped `sessionFileJson`/`transcriptPathJson` lines for copy-safe path literals. Pass explicit `tail` or `limit` to override the 5-entry preview; `tail` overrides `limit`; `includeToolOutput` includes captured snapshot tool output in snapshot transcript results.
|
|
3163
|
-
- `
|
|
3164
|
-
|
|
3165
|
-
- Atomic checks an already-terminal root before stage resolution, nested-owner routing, prompt inspection, retained-session probing or revival, handle lookup, message admission, and delivery selection. That rejection creates no agent session or handle, appends no transcript, starts no model/tool/file work, answers no input, and mutates no workflow/stage snapshot. Missing or malformed retained sessions receive the same root-terminal error without being probed.
|
|
3166
|
-
- Atomic checks the same shared terminal authority again at the final synchronous SDK message-admission boundary. If a live root terminates while retained-session creation is pending, the send fails with `WORKFLOW_TERMINAL`, disposes its unclaimed provisional session/handle, and admits no prompt, model request, tool/file work, transcript append, or workflow-state mutation. A user-driven attach or Intercom claim remains independent and keeps the retained handle.
|
|
3167
|
-
- Prompt answers on a nonterminal root can include `promptId` and can carry answer content in `response`, `text`, or `message`; structured UI prompts usually prefer `response`.
|
|
3168
|
-
- Primitive HIL answers are normalized by prompt kind: `input` and `editor` require a text string; `confirm` accepts booleans or trimmed, case-insensitive `true`/`false`, `yes`/`y`, `no`/`n`, `approve`/`reject`, and `confirm`/`deny`; `select` accepts a trimmed, case-insensitive choice label or a 1-based numeric index.
|
|
3169
|
-
- An answer that does not match the pending primitive prompt stays pending. Atomic returns a `noop` explaining the expected shape and, for `select`, the available choices; it never silently chooses the first option. Prompt-card answers from the interactive graph keep their existing typed path.
|
|
3170
|
-
- For a live idle, non-paused stage, `prompt`, `followUp`, and eligible `auto` delivery all start a fresh prompt immediately; an actively streaming `followUp` remains queued and `steer` remains steering, so neither starts a concurrent prompt. During controlled pause, every context-bearing delivery remains held instead. The result's `delivery` and message describe the action actually taken (`prompt`, `followUp`, `steer`, `answer`, or `resume`), not merely the requested mode. Explicit `resume` against a stage that is not paused is a truthful no-op, and explicit message deliveries cannot bypass a paused stage; resume it first.
|
|
3171
|
-
- Delivery timing is mode-specific and deterministic. `steer` (and `auto` against a streaming stage) enters the steering queue and is consumed after the current assistant response finishes its whole tool batch, before the next model request — never between two tool calls of the same response. `followUp` enters the follow-up queue and is consumed only when the agent would otherwise stop. Sequential sends keep submission order *within* the queue they select; there is no global FIFO across the two queues, so a steer submitted after a follow-up is still consumed first. Ordering is promised relative to admission into the selected queue, not relative to when a caller started a request whose session setup or admission finishes later.
|
|
3172
|
-
- While the root remains nonterminal, follow-up messaging to an eligible completed child stage can reuse its retained `sessionFile`. After the root terminates, use explicit `/workflow attach <run-id> <stage>` post-mortem chat instead; `workflow send` never admits a retained-session turn after terminal publication.
|
|
3173
|
-
- Arbitrary `ctx.ui.custom<T>` widget prompts require the interactive workflow graph and return a clear unsupported message when targeted through `send`.
|
|
3174
|
-
- On a nonterminal root, `delivery: "auto"` first answers a pending prompt, then resumes paused work, then steers a streaming stage, and finally starts a fresh prompt when the live stage is idle.
|
|
3196
|
+
- `answer` responds only to a pending primitive or structured human-input prompt. It accepts `promptId` plus `response`, `text`, or `message`, preserves prompt-kind validation, and never sends stage chat, steers, resumes, or starts a model turn.
|
|
3197
|
+
- Send free-form updates through ordinary Intercom to `<runId>:<stageKey>`. Atomic delivers immediately to live stages and queues messages for known stages that have not started, delivering them before their first model turn; unknown stages remain unknown targets. Use `ask` once the target has a reply-capable live session. Use `workflow resume` only for paused workflow control.
|
|
3175
3198
|
- `pause`, `interrupt`, and `quit` can target one top-level run or `all: true`; `stageId` cannot be combined with `all: true`. Stage-scoped `pause` and `interrupt` controls can target a visible nested child stage from the expanded graph. Atomic routes stage controls to the owning nested run internally.
|
|
3176
3199
|
- `interrupt` and `quit` can also name one in-flight `ctx.tool` node with `stageId`, by expanded node id, local `tool:<argsHash>` id, or tool name. Both mean the same thing for a tool: abort that single call now. Tool nodes stay non-attachable — this is an abort control, not a chat target. Identifiers resolve exactly first and then uniquely; a name shared by two tool nodes (or by a stage and a tool) returns the same ambiguity diagnostic stages get, listing each match as `<name> (tool)`.
|
|
3177
3200
|
- Aborting one tool node leaves every sibling stage and sibling tool node running and does not pause the run. The node becomes `cancelled`, writes no replayable checkpoint, and re-runs on a later resume. Whether the run itself survives is ordinary author control flow: an awaited `ctx.tool` that is aborted rejects, exactly as it would for any other failure, unless the workflow catches it. A node that has already settled reports that it is not running rather than silently succeeding.
|
|
@@ -3208,7 +3231,7 @@ When a callback was abandoned, its executor stays alive but stops owning the run
|
|
|
3208
3231
|
|
|
3209
3232
|
When a paused stage interrupted an active model turn, Atomic preserves that turn's existing pause loop: a non-empty resume message is delivered exactly once through the resumed loop, and (if the stage has not finalized) Atomic injects `Continue where you left off. If you believe you are finished with your original task (or a redefined task if the user told you), stop.` before normal completion/readiness handling. A no-message interrupted-turn resume injects the same continuation directly. A different state applies when the stage was idle and waiting for a new stage-chat turn: resuming with a non-empty message starts exactly one fresh prompt containing the text, while an empty resume only releases the pause and does not fabricate a user turn or continuation.
|
|
3210
3233
|
|
|
3211
|
-
The same continuation applies to user messages queued into a live streaming stage. Steering a turn (Enter in an attached stage chat)
|
|
3234
|
+
The same continuation applies to user messages queued into a live streaming stage. Steering a turn (Enter in an attached stage chat) or queueing a follow-up (Ctrl+F) arms the identical continuation prompt, which Atomic injects once when the interrupted turn ends — even if several messages were queued during that turn — so a steered stage returns to its original (or user-redefined) objective instead of stopping after answering the queued message.
|
|
3212
3235
|
|
|
3213
3236
|
Messages delivered to an idle stage start a fresh user turn immediately and receive no continuation nudge; abort, kill, workflow exit, and finalized/fail-fast stage boundaries suppress late prompt creation and continuation injection.
|
|
3214
3237
|
|
|
@@ -3220,7 +3243,7 @@ These are distinct operations. *Resuming workflow execution* (`/workflow resume`
|
|
|
3220
3243
|
|
|
3221
3244
|
Any eligible terminal agent stage with a valid retained session opens as an interactive post-mortem chat through the explicit user-driven TUI path: completed-workflow inspection, `/workflow attach`, or `/workflow connect` followed by stage selection, including restored/replayed durable snapshots after a restart. Explicit `/workflow attach <root-run> <nested-stage>` targets are resolved through the expanded graph and routed to the child run that owns the stage while the overlay remains rooted on the requested graph; the resolved owner is preserved when sibling child workflows reuse the same local stage ID.
|
|
3222
3245
|
|
|
3223
|
-
|
|
3246
|
+
Intercom and explicit `/workflow attach` own stage communication. The workflow tool has no free-form message action; start a new workflow if tracked work remains after a terminal root.
|
|
3224
3247
|
|
|
3225
3248
|
When a nested stage is reopened after a restart or from another checkout through the explicit TUI path, its session cwd comes from the durable root workflow (resolved workflow cwd first, then original invocation cwd) while stage-control ownership remains with the actual child run. Follow-up turns are appended in place to the stage's retained session (no separate fork), so the agent may still invoke its ordinary tools and cause side effects; only the workflow DAG, run/stage status, results, timings, checkpoints, and topology are immutable. Post-mortem chat does not resume or modify workflow execution state.
|
|
3226
3249
|
|
|
@@ -3230,7 +3253,7 @@ Every host session replacement or shutdown invalidates post-mortem handles, incl
|
|
|
3230
3253
|
|
|
3231
3254
|
When a known stage cannot be reopened, the attached chat shows the complete `SESSION UNAVAILABLE` explanation down to the supported 40-column minimum instead of incorrectly labeling an invalid file as an archived transcript. Recoverably failed stages keep their execution-resume semantics and are not silently reopened as post-mortem chat.
|
|
3232
3255
|
|
|
3233
|
-
Completed stages also remain addressable by blocking `intercom.ask` calls from sibling workflow stages. If an ask reaches a completed target with a retained conversation, Atomic schedules one serialized post-mortem turn in that exact conversation
|
|
3256
|
+
Completed stages also remain addressable by blocking `intercom.ask` calls from sibling workflow stages. If an ask reaches a completed target with a retained conversation, Atomic schedules one serialized post-mortem turn in that exact conversation.
|
|
3234
3257
|
|
|
3235
3258
|
The target sees the original ask, and its normal `intercom.reply` remains correlated to the originating child session and message ID. The parent chat or another session cannot satisfy the waiter. Late-message routing uses single-owner claiming: after the workflow post-mortem router claims a completed-stage ask and assigns its completion promise, later listeners preserve that claim, making bundled extension registration order irrelevant.
|
|
3236
3259
|
|
|
@@ -3289,13 +3312,13 @@ When a workflow needs human input, answer in the graph viewer or attached stage
|
|
|
3289
3312
|
/workflow attach <run-id> <stage-id-or-name>
|
|
3290
3313
|
```
|
|
3291
3314
|
|
|
3292
|
-
Agents can answer primitive and structured pending prompts programmatically with `workflow({ action: "
|
|
3315
|
+
Agents can answer primitive and structured pending prompts programmatically with `workflow({ action: "answer", ... })` only while the root workflow is nonterminal; use `promptId` when it is present in the stage details, and provide answer content with `response`, `text`, or `message`. Arbitrary custom TUI widget prompts intentionally refuse this path in iteration 1 because a generic `T` cannot be reconstructed safely from a non-TUI payload.
|
|
3293
3316
|
|
|
3294
3317
|
`ctx.ui.custom<T>(factory, options?)` reuses Atomic's TUI component path: the factory receives the same real `(tui, theme, keybindings, done)` types as extension `ctx.ui.custom`, and the workflow resumes with the value passed to `done(value)`. Use `options.label` for a safe display-only graph/status label and `options.replayIdentity` when widget semantics can change without the callsite changing. Do not put secrets in labels or replay identities; only a hash of the identity is stored, and label text is not part of replay identity. Both inline connected rendering and `overlay: true` mount in the graph viewer's attached stage chat: overlay is a placement hint rather than a capability request, so an in-stage `ask_user_question` — which always asks for an overlay — mounts, takes focus, and resolves like any other custom prompt. There is no nested host overlay above the graph chrome; the widget occupies the stage-chat custom-UI slot and `overlayOptions` / `onHandle` are not consumed there.
|
|
3295
3318
|
|
|
3296
3319
|
Prompt answers are replayable only while the source run remains in the live in-memory store. `StageSnapshot.promptAnswerState` is snapshot-safe metadata for continuation: `available` means a matching live answer can be replayed, `unavailable` means the matching prompt node exists but its private answer was purged, and `ambiguous` means multiple matching prompt nodes exist so Atomic asks again. The raw answer lives in a private `PromptAnswerRecord` ledger, is never written to snapshots or persistence, and remains resident in memory until the answer is cleared, the run is removed, or the store is cleared.
|
|
3297
3320
|
|
|
3298
|
-
Prompt replay keys include the prompt kind, message text, select choices, input/editor initial value, custom prompt identity hash, and hashed author callsite, so changing any of those inputs may intentionally re-ask on continuation. An empty `ctx.ui.select(..., [])` has no answerable choices and throws before creating a prompt node. Arbitrary custom-widget answers cannot be supplied through `workflow
|
|
3321
|
+
Prompt replay keys include the prompt kind, message text, select choices, input/editor initial value, custom prompt identity hash, and hashed author callsite, so changing any of those inputs may intentionally re-ask on continuation. An empty `ctx.ui.select(..., [])` has no answerable choices and throws before creating a prompt node. Arbitrary custom-widget answers cannot be supplied through `workflow answer`; focus the `custom` awaiting-input node in the interactive graph instead.
|
|
3299
3322
|
|
|
3300
3323
|
If the user answers a human-in-the-loop prompt in the workflow UI or stage UI broker, the stage receives the answer directly and the active main chat receives a display-only notice (`triggerTurn: false`, `excludeFromContext: true`) containing a concise answer summary. The notice is rendered for the user and persisted for audit, but it does not wake the model, enter LLM context, or authorize answering any other workflow prompt. Prompt answers sent by the main-chat `workflow` tool are suppressed from this notice because the tool result already informs the current turn.
|
|
3301
3324
|
|
|
@@ -3303,7 +3326,7 @@ When an interactive, non-schema workflow stage calls `ask_user_question`, Atomic
|
|
|
3303
3326
|
|
|
3304
3327
|
In this chat-answer flow, choosing the ready option completes the stage and releases dependent stages. Choosing the not-ready option keeps the stage open for a genuine stage-chat turn and brokers readiness again after that turn. A chat answer is never treated as an invisible stay decision. On the readiness gate, **Type something.** sends the typed text as the next stage-chat message (empty or whitespace-only text cannot be submitted). **Chat about this** is a plain option — it does not open an inline editor — and stays by sending `The user would like to chat more about this`.
|
|
3305
3328
|
|
|
3306
|
-
The readiness prompt can be answered in the attached stage UI or with `workflow({ action: "
|
|
3329
|
+
The readiness prompt can be answered in the attached stage UI or with `workflow({ action: "answer", ... })`. Ordinary structured-option answers retain their existing readiness behavior. A schema-backed stage that has successfully finalized through `structured_output` is terminal and does not reopen this readiness gate.
|
|
3307
3330
|
|
|
3308
3331
|
|
|
3309
3332
|
## Durable Workflows and Cross-Session Resume
|
|
@@ -3427,7 +3450,7 @@ A run quit while a `ctx.tool` call was in flight resumes the same way: the unfin
|
|
|
3427
3450
|
|
|
3428
3451
|
Selecting a completed target—or a checkpointed failed target marked non-resumable—follows a separate read-only open path. Atomic reconstructs root and reciprocal nested child-run snapshots from authoritative checkpoints, remaps persisted source-stage, boundary, and tool references into a stable expanded hierarchy, and never calls the resume dispatcher or runs workflow code, tools, tasks, or prompts. These graphs remain inspectable even when no retained chat transcript survives, including tool-only graphs.
|
|
3429
3452
|
|
|
3430
|
-
A terminal child stage with a valid retained session may be reopened for detached post-mortem conversation through `/workflow attach` or completed graph inspection. Follow-up is routed to that real child `{runId, stageId}` and may append chat, but it cannot pause, resume, retry, mutate root or child execution state, write a terminal checkpoint, or emit a duplicate lifecycle notice.
|
|
3453
|
+
A terminal child stage with a valid retained session may be reopened for detached post-mortem conversation through `/workflow attach` or completed graph inspection. Follow-up is routed to that real child `{runId, stageId}` and may append chat, but it cannot pause, resume, retry, mutate root or child execution state, write a terminal checkpoint, or emit a duplicate lifecycle notice. Tool nodes never offer chat attachment.
|
|
3431
3454
|
|
|
3432
3455
|
New tool checkpoints persist topology. A current-format tool checkpoint created before that additive topology existed still replays safely: its cached output remains authoritative and its callback is never rerun. Root-level inspection derives deterministic fallback identity/order from checkpoint identity and record order. If a topology-less cached tool replays inside a child workflow, Atomic first appends awaited topology metadata with the current child/boundary ownership, without replacing the original output checkpoint. Foreign or malformed checkpoint formats remain excluded.
|
|
3433
3456
|
|
|
@@ -3490,7 +3513,7 @@ Atomic discovers workflow definitions in this order:
|
|
|
3490
3513
|
| `~/.atomic/agent/extensions/workflow/config.json` | Global | `workflows.<name>.path` for user-wide configured paths |
|
|
3491
3514
|
| `~/.atomic/agent/workflows/*.{ts,js,mjs,cjs}` | Global | Legacy `~/.pi/agent/workflows/` is also checked |
|
|
3492
3515
|
| Installed Atomic packages | Package | Uses package metadata or conventional `workflows/` directories |
|
|
3493
|
-
| Bundled workflows | Built-in | Shipped with `@bastani/workflows` |
|
|
3516
|
+
| Bundled workflows | Built-in | Shipped with `@bastani/atomic/workflows` |
|
|
3494
3517
|
|
|
3495
3518
|
A workflow module may export one default workflow definition and/or named workflow definitions. Discovery checks the default export first, then named exports.
|
|
3496
3519
|
|
|
@@ -3507,14 +3530,14 @@ To co-locate reusable helpers with your workflows — for example a `ctx.ui.cust
|
|
|
3507
3530
|
|
|
3508
3531
|
```ts
|
|
3509
3532
|
// .atomic/workflows/release-picker.ts
|
|
3510
|
-
import { workflow } from "@bastani/workflows";
|
|
3533
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
3511
3534
|
import { Type } from "typebox";
|
|
3512
3535
|
import { tableSelectorFactory } from "./lib/table-selector.js";
|
|
3513
3536
|
```
|
|
3514
3537
|
|
|
3515
3538
|
```ts
|
|
3516
3539
|
// .atomic/workflows/lib/table-selector.ts
|
|
3517
|
-
import type { WorkflowCustomUiFactory } from "@bastani/workflows";
|
|
3540
|
+
import type { WorkflowCustomUiFactory } from "@bastani/atomic/workflows";
|
|
3518
3541
|
|
|
3519
3542
|
export const tableSelectorFactory: WorkflowCustomUiFactory<{ id: string; name: string }> = (
|
|
3520
3543
|
tui,
|
|
@@ -3714,22 +3737,14 @@ atomic -e ./local-workflow-package
|
|
|
3714
3737
|
|
|
3715
3738
|
Workflow stage sessions inherit the same package and temporary `-e` resource discovery snapshot as the main chat. That means a workflow loaded from an external package or directory can start stages that see the package's extensions/tools, subagents and agent definitions, skills, prompt templates, themes, workflows, and trusted borrowed project-local resources without sharing the parent chat's resource-loader instance. Passing an explicit `resourceLoader` in stage options still opts that stage out of this inheritance.
|
|
3716
3739
|
|
|
3717
|
-
## Programmatic
|
|
3718
|
-
|
|
3719
|
-
`@bastani/workflows` is an Atomic package extension. It registers:
|
|
3740
|
+
## Programmatic usage
|
|
3720
3741
|
|
|
3721
|
-
|
|
3722
|
-
- `/workflow connect|attach|pause|interrupt|quit|resume|status|inputs|reload` for live control, inspection, and rediscovery
|
|
3723
|
-
- the `workflow` tool for named execution, discovery, inspection, messaging, run control, and reload
|
|
3742
|
+
`@bastani/atomic/workflows` is Atomic's published workflow SDK. Import `workflow` from that specifier, import `Type` from `typebox`, and export the definition returned by `workflow({...})`. Keep runtime helpers such as widget factories and shared utilities in a subdirectory outside the top-level discovery scan, such as `.atomic/workflows/lib/`; see [Workflow Locations](#workflow-locations).
|
|
3724
3743
|
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
Workflow definition files must export definitions produced by `workflow({...})`. Keep non-workflow runtime helpers (widget factories, shared utilities) in a subdirectory the discovery scan ignores, such as `.atomic/workflows/lib/` — see [Workflow Locations](#workflow-locations). The former imperative object-form runner is not part of the public SDK, and authored workflow files cannot use `runWorkflow` as a runner from `@bastani/workflows`.
|
|
3728
|
-
|
|
3729
|
-
Standalone TypeScript workflow packages type-check the SDK import without a hand-authored `.d.ts`, `declare module` shim, or `tsconfig` `paths` alias. The SDK types ship with `@bastani/atomic`, so a workflow package depends only on `@bastani/atomic` (plus a `typebox` peer):
|
|
3744
|
+
Package authors list both `@bastani/atomic` and `typebox` in `peerDependencies`. The `@bastani/atomic` package publishes compiled JavaScript and declarations for `@bastani/atomic/workflows`, `@bastani/atomic/workflows/builtin`, and each `@bastani/atomic/workflows/builtin/*` module. TypeScript resolves those exports directly under `moduleResolution: NodeNext`. When Atomic executes a workflow file, its runtime loader resolves the same published specifiers to Atomic's in-memory SDK.
|
|
3730
3745
|
|
|
3731
3746
|
```ts
|
|
3732
|
-
import { workflow } from "@bastani/workflows";
|
|
3747
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
3733
3748
|
import { Type } from "typebox";
|
|
3734
3749
|
|
|
3735
3750
|
export default workflow({
|
|
@@ -3746,29 +3761,7 @@ export default workflow({
|
|
|
3746
3761
|
});
|
|
3747
3762
|
```
|
|
3748
3763
|
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
- A package that imports `@bastani/atomic` anywhere (for example, an extension shipped in the same package) automatically resolves the workflow SDK types. `@bastani/atomic`'s root declarations reference the ambient bridge, so no extra configuration is needed.
|
|
3752
|
-
- A pure workflow-only package — one that imports nothing but `@bastani/workflows` — adds a single opt-in so TypeScript loads the ambient bridge. Set it once for the project in `tsconfig.json`:
|
|
3753
|
-
|
|
3754
|
-
```jsonc
|
|
3755
|
-
{
|
|
3756
|
-
"compilerOptions": {
|
|
3757
|
-
"module": "NodeNext",
|
|
3758
|
-
"moduleResolution": "NodeNext",
|
|
3759
|
-
"types": ["@bastani/atomic/workflows/ambient"]
|
|
3760
|
-
}
|
|
3761
|
-
}
|
|
3762
|
-
```
|
|
3763
|
-
|
|
3764
|
-
or add a single reference directive at the top of one workflow file:
|
|
3765
|
-
|
|
3766
|
-
```ts
|
|
3767
|
-
/// <reference types="@bastani/atomic/workflows/ambient" />
|
|
3768
|
-
```
|
|
3769
|
-
|
|
3770
|
-
Either form makes `import { workflow } from "@bastani/workflows"
|
|
3771
|
-
import { Type } from "typebox"` and the `@bastani/workflows/builtin/*` composition imports resolve under `tsc` (`moduleResolution: NodeNext`) with no hand-authored `.d.ts`, no `declare module` shim, and no `paths` alias. `@bastani/workflows` is not a separate npm package — its types ship with `@bastani/atomic` — so list both `@bastani/atomic` and `typebox` (workflow files import `Type` from `typebox`) in `peerDependencies`. Runtime discovery and loading via `atomic.workflows` are unchanged: Atomic's loader still supplies the SDK when workflow files execute.
|
|
3764
|
+
Programmatic callers import `run` and call `run(definition, inputs)` with an exported definition and validated inputs. Use `createRegistry()` when an integration needs to register, merge, or look up several definitions before selecting one to run. The extension also registers the `/workflow` commands and the `workflow` tool for named execution, discovery, inspection, messaging, run control, and reload.
|
|
3772
3765
|
|
|
3773
3766
|
|
|
3774
3767
|
### `workflow(spec)`
|
|
@@ -3783,7 +3776,7 @@ function workflow<
|
|
|
3783
3776
|
): AuthoredWorkflowDefinition<TInputs, TOutputs>;
|
|
3784
3777
|
```
|
|
3785
3778
|
|
|
3786
|
-
Creates the frozen
|
|
3779
|
+
Creates the frozen definition documented in [The `workflow()` definition](#the-workflow-definition). Export the returned definition or pass it to `ctx.workflow(...)`, `run(...)`, or a registry.
|
|
3787
3780
|
|
|
3788
3781
|
### `createRegistry(initial?)`
|
|
3789
3782
|
|
|
@@ -3808,7 +3801,7 @@ interface WorkflowRegistry {
|
|
|
3808
3801
|
Creates an immutable-style registry keyed by normalized workflow name. `register`, `merge`, and `remove` return registries rather than mutating the current registry.
|
|
3809
3802
|
|
|
3810
3803
|
```ts
|
|
3811
|
-
import { createRegistry, workflow } from "@bastani/workflows";
|
|
3804
|
+
import { createRegistry, workflow } from "@bastani/atomic/workflows";
|
|
3812
3805
|
import { Type } from "typebox";
|
|
3813
3806
|
|
|
3814
3807
|
const alpha = workflow({
|
|
@@ -4025,16 +4018,8 @@ The factory creates an isolated registry; `cancellationRegistry` is the default
|
|
|
4025
4018
|
export type { Static, TSchema } from "typebox";
|
|
4026
4019
|
```
|
|
4027
4020
|
|
|
4028
|
-
These TypeBox types are re-exported for authoring helpers.
|
|
4021
|
+
These TypeBox types are re-exported for authoring helpers. Import the runtime `Type` builder from `typebox`.
|
|
4029
4022
|
|
|
4030
|
-
### `runWorkflow` (removed)
|
|
4031
|
-
|
|
4032
|
-
```typescript
|
|
4033
|
-
/** @deprecated Always throws a migration error. */
|
|
4034
|
-
const runWorkflow: never;
|
|
4035
|
-
```
|
|
4036
|
-
|
|
4037
|
-
This runtime migration stub exists only so old modules fail at the callsite with a clear error. Use `workflow({...})` for authoring and `run(...)` for programmatic execution.
|
|
4038
4023
|
|
|
4039
4024
|
### Builtin workflow exports
|
|
4040
4025
|
|
|
@@ -4049,23 +4034,25 @@ import {
|
|
|
4049
4034
|
openClaudeDesign,
|
|
4050
4035
|
ralph,
|
|
4051
4036
|
tournament,
|
|
4052
|
-
} from "@bastani/workflows/builtin";
|
|
4037
|
+
} from "@bastani/atomic/workflows/builtin";
|
|
4053
4038
|
```
|
|
4054
4039
|
|
|
4055
4040
|
Each export is a workflow definition. All nine definitions are available through individual module paths. See [Compose with builtin workflows](#compose-with-builtin-workflows) for a parent workflow example.
|
|
4056
4041
|
|
|
4057
4042
|
|
|
4058
|
-
## Fast
|
|
4043
|
+
## Fast inference for workflow stages
|
|
4044
|
+
|
|
4045
|
+
Workflow stages can use faster inference on supported OpenAI and GitHub Copilot models so multi-stage runs finish sooner.
|
|
4059
4046
|
|
|
4060
|
-
|
|
4047
|
+
### Fast mode
|
|
4061
4048
|
|
|
4062
|
-
|
|
4049
|
+
Use `/fast` to manage fast mode separately for normal chat and workflow-stage sessions. The settings are `codexFastMode.chat` and `codexFastMode.workflow`; workflow stages use the workflow scope, not the chat scope. A stage inside a nested `ctx.workflow(...)` call keeps that workflow scope, and subagents launched by the stage inherit it.
|
|
4063
4050
|
|
|
4064
|
-
|
|
4051
|
+
Fast mode is eligible for supported `openai/*` and `openai-codex/*` providers, provider aliases that use the shared `openai-codex-responses` transport, and GitHub Copilot models whose OAuth account catalog advertises a fast variant. OpenAI requests use the priority service tier. GitHub Copilot requests use the account-supported fast variant without adding the OpenAI service-tier field. Azure OpenAI, OpenRouter, and generic OpenAI-compatible providers are not eligible.
|
|
4065
4052
|
|
|
4066
|
-
|
|
4053
|
+
Atomic resolves eligibility for the effective model on every fallback attempt. A supported fallback can use fast mode even when the primary failed, while an unsupported fallback keeps its normal request behavior. Workflow stage model labels and stage-launched subagent result labels keep the raw model ID and append a separate `fast` marker; graph node cards keep their dependency metadata focused on topology and do not repeat that marker.
|
|
4067
4054
|
|
|
4068
|
-
Enable workflow fast mode deliberately for broad workflows
|
|
4055
|
+
Enable workflow fast mode deliberately for broad workflows. Parallel fan-out and fallback attempts can multiply fast provider requests and usage.
|
|
4069
4056
|
|
|
4070
4057
|
## Context Engineering
|
|
4071
4058
|
|
|
@@ -4241,120 +4228,6 @@ Before turning a process into a workflow, confirm that it suits automation:
|
|
|
4241
4228
|
|
|
4242
4229
|
For complex workflows, structure the implementation as a pipeline: acquire context, prepare prompts/artifacts, process with LLM stages, parse or validate outputs, and render the final result.
|
|
4243
4230
|
|
|
4244
|
-
## Migrating from the `defineWorkflow()` Builder API
|
|
4245
|
-
|
|
4246
|
-
[#1457](https://github.com/bastani-inc/atomic/pull/1457) removed the chained builder API — `defineWorkflow(name).description(...).input(...).output(...).worktreeFromInputs(...).run(...).compile()` — and made the single `workflow({ name?, description, inputs, outputs, run })` object form the only authoring API. There is no shim and no deprecation period: workflow files that still call `defineWorkflow(...).compile()` fail discovery with a module-load error until authors migrate them.
|
|
4247
|
-
|
|
4248
|
-
Use this section for workflow files that use the previous API. If you are authoring a new workflow, skip it and start from [Writing a Workflow](#writing-a-workflow).
|
|
4249
|
-
|
|
4250
|
-
### What changed
|
|
4251
|
-
|
|
4252
|
-
- `import { defineWorkflow, Type } from "@bastani/workflows"` → `workflow` now comes from `@bastani/workflows`, and `Type` comes from the `typebox` package directly. `@bastani/workflows` no longer re-exports `Type`. The `Static` and `TSchema` *type* exports are still re-exported from `@bastani/workflows`, so `import type { Static } from "@bastani/workflows"` keeps working — only the runtime `Type` builder moved.
|
|
4253
|
-
- The fluent builder chain became one object literal passed to `workflow({ ... })`.
|
|
4254
|
-
- `name` moved from the `defineWorkflow(name)` argument into the object. It is now **optional** — omit it and discovery derives the name from the filename (the recommended style used by the builtins and most examples), or keep it when you want the name to differ from the file's basename.
|
|
4255
|
-
- `outputs` is now **required**. Workflows that declared no outputs before must now pass `outputs: {}`.
|
|
4256
|
-
- `.compile()` is gone. `workflow({ ... })` returns the frozen, branded definition directly; `export default` it.
|
|
4257
|
-
- The imperative object-form `runWorkflow(...)` runner is also removed (it is a `never` placeholder that throws on access). Programmatic execution uses the exported `run(def, inputs)` helper or a registry — see [Programmatic Usage](#programmatic-usage).
|
|
4258
|
-
|
|
4259
|
-
### Builder method → object key
|
|
4260
|
-
|
|
4261
|
-
| Removed builder API | New `workflow({ ... })` key |
|
|
4262
|
-
| --- | --- |
|
|
4263
|
-
| `defineWorkflow("name")` argument | `name: "name"` (optional; derived from the filename when omitted) |
|
|
4264
|
-
| `.description(text)` | `description: text` |
|
|
4265
|
-
| `.input(key, schema)` (repeatable) | `inputs: { key: schema, ... }` |
|
|
4266
|
-
| `.output(key, schema)` (repeatable) | `outputs: { key: schema, ... }` (required, even if `{}`) |
|
|
4267
|
-
| `.worktreeFromInputs(binding)` | `worktreeFromInputs: binding` (binding shape unchanged) |
|
|
4268
|
-
| `.run(fn)` callback | `run: fn` |
|
|
4269
|
-
| `.compile()` terminal | delete — `workflow({ ... })` returns the definition |
|
|
4270
|
-
|
|
4271
|
-
`ctx` and every primitive (`ctx.task`, `ctx.chain`, `ctx.parallel`, `ctx.stage`, `ctx.workflow`, `ctx.exit`, `ctx.ui`) are unchanged, so **you do not need to rewrite workflow bodies** — only the authoring wrapper changes.
|
|
4272
|
-
|
|
4273
|
-
### Full before / after
|
|
4274
|
-
|
|
4275
|
-
Before (removed API):
|
|
4276
|
-
|
|
4277
|
-
```ts
|
|
4278
|
-
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
4279
|
-
|
|
4280
|
-
export default defineWorkflow("review-changes")
|
|
4281
|
-
.description("Run two reviewers in parallel and synthesize a decision.")
|
|
4282
|
-
.input("target", Type.String({ description: "Path or change target to review." }))
|
|
4283
|
-
.input("base_branch", Type.String({ default: "origin/main" }))
|
|
4284
|
-
.output("decision", Type.String())
|
|
4285
|
-
.output("concerns", Type.Optional(Type.Array(Type.String())))
|
|
4286
|
-
.worktreeFromInputs({ baseBranch: "base_branch" })
|
|
4287
|
-
.run(async (ctx) => {
|
|
4288
|
-
const target = String(ctx.inputs.target);
|
|
4289
|
-
const [quality, runtime] = await ctx.parallel(
|
|
4290
|
-
[
|
|
4291
|
-
{ name: "quality", prompt: `Review quality of ${target}` },
|
|
4292
|
-
{ name: "runtime", prompt: `Review runtime behavior of ${target}` },
|
|
4293
|
-
],
|
|
4294
|
-
{ concurrency: 2 },
|
|
4295
|
-
);
|
|
4296
|
-
return { decision: `${quality.text}\n${runtime.text}`, concerns: [] };
|
|
4297
|
-
})
|
|
4298
|
-
.compile();
|
|
4299
|
-
```
|
|
4300
|
-
|
|
4301
|
-
After (current API):
|
|
4302
|
-
|
|
4303
|
-
```ts
|
|
4304
|
-
import { workflow } from "@bastani/workflows";
|
|
4305
|
-
import { Type } from "typebox";
|
|
4306
|
-
|
|
4307
|
-
export default workflow({
|
|
4308
|
-
name: "review-changes", // optional — omit to derive from filename
|
|
4309
|
-
description: "Run two reviewers in parallel and synthesize a decision.",
|
|
4310
|
-
inputs: {
|
|
4311
|
-
target: Type.String({ description: "Path or change target to review." }),
|
|
4312
|
-
base_branch: Type.String({ default: "origin/main" }),
|
|
4313
|
-
},
|
|
4314
|
-
outputs: {
|
|
4315
|
-
decision: Type.String(),
|
|
4316
|
-
concerns: Type.Optional(Type.Array(Type.String())),
|
|
4317
|
-
},
|
|
4318
|
-
worktreeFromInputs: { baseBranch: "base_branch" },
|
|
4319
|
-
run: async (ctx) => {
|
|
4320
|
-
const target = String(ctx.inputs.target);
|
|
4321
|
-
const [quality, runtime] = await ctx.parallel(
|
|
4322
|
-
[
|
|
4323
|
-
{ name: "quality", prompt: `Review quality of ${target}` },
|
|
4324
|
-
{ name: "runtime", prompt: `Review runtime behavior of ${target}` },
|
|
4325
|
-
],
|
|
4326
|
-
{ concurrency: 2 },
|
|
4327
|
-
);
|
|
4328
|
-
return { decision: `${quality.text}\n${runtime.text}`, concerns: [] };
|
|
4329
|
-
},
|
|
4330
|
-
});
|
|
4331
|
-
```
|
|
4332
|
-
|
|
4333
|
-
### Conversion checklist
|
|
4334
|
-
|
|
4335
|
-
For each `.atomic/workflows/*.ts` (or workflow-package) file:
|
|
4336
|
-
|
|
4337
|
-
1. Swap the import to `import { workflow } from "@bastani/workflows"` and add `import { Type } from "typebox"`. Drop `defineWorkflow` from the `@bastani/workflows` import. `import type { Static, TSchema }` can stay on the `@bastani/workflows` import if you use those types.
|
|
4338
|
-
2. Replace `defineWorkflow("<name>")` with `workflow({`. You may keep `name: "<name>"` or drop the key entirely to derive the name from the filename.
|
|
4339
|
-
3. Move `.description("<text>")` to a `description: "<text>",` property.
|
|
4340
|
-
4. Collect every `.input(key, schema)` into one `inputs: { key: schema, ... },` map.
|
|
4341
|
-
5. Collect every `.output(key, schema)` into one `outputs: { key: schema, ... },` map. If there were no `.output(...)` calls, add `outputs: {},` — it is now required.
|
|
4342
|
-
6. Move `.worktreeFromInputs(binding)` to a `worktreeFromInputs: binding,` property (same binding shape, unchanged).
|
|
4343
|
-
7. Move the `.run(fn)` callback to a `run: fn,` property; keep the body byte-for-byte identical.
|
|
4344
|
-
8. Delete the trailing `.compile()`, close the object with `})`, and keep `export default`.
|
|
4345
|
-
9. Run `/workflow reload` (or restart Atomic) and `/workflow list` to confirm the file loads. Because `ctx` and its primitives are unchanged, stage behavior, graph layout, resume/quit, and human-input prompts are unaffected.
|
|
4346
|
-
|
|
4347
|
-
### Gotchas
|
|
4348
|
-
|
|
4349
|
-
- **`outputs` is required.** The old `.output(...)` calls were optional, and a workflow without outputs compiled successfully. The new object form throws `workflow: outputs must be a schema map` when `outputs` is missing, so declare `outputs: {}` for outputless workflows.
|
|
4350
|
-
- **`Type` is no longer re-exported.** `import { Type } from "@bastani/workflows"` fails type-checking; import it from `typebox` instead. (`Static` and `TSchema` *types* are still re-exported from `@bastani/workflows`, so those imports do not need to change.)
|
|
4351
|
-
- **`.compile()` does not exist.** Leaving it produces a runtime `TypeError`; `workflow({ ... })` already returns the frozen, branded definition.
|
|
4352
|
-
- **`name` is derived from the filename when omitted.** Discovery derives the name from the filename: `review-changes.ts` becomes `review-changes`, so an explicit `name` is only needed when it should differ from the basename.
|
|
4353
|
-
- **Do not construct definitions manually.** Discovery rejects hand-built objects carrying `__piWorkflow: true`, and `ctx.workflow(...)` rejects them too. Both accept only definitions minted by `workflow({ ... })`.
|
|
4354
|
-
- **The imperative `runWorkflow` runner is gone.** It is now a `never` placeholder that throws on access; use the exported `run(def, inputs)` helper or a registry for programmatic execution.
|
|
4355
|
-
- **Keep `outputs` inline for the strictest type checking.** The old builder enforced no-extra-output keys through a `NoExtraOutputs` generic on `.run(fn)`; the object form re-creates that check for inline `outputs` maps, but cannot recover output keys when a schema map is widened or built up before being passed to `workflow({ ... })`. Keep the `outputs` literal inline so the declared-key check stays exact.
|
|
4356
|
-
|
|
4357
|
-
Everything else — stage primitives, `ctx.inputs` typing, runtime validation, DAG inference, MCP scoping, resume/quit, worktree binding, model fallback, and the `/workflow` tool contract — is unchanged.
|
|
4358
4231
|
|
|
4359
4232
|
## Design Checklist
|
|
4360
4233
|
|
|
@@ -4384,7 +4257,7 @@ Good workflows are information-flow systems, not just prompt sequences. Keep sta
|
|
|
4384
4257
|
- Do not guess input keys; inspect with `inputs` or `get` first.
|
|
4385
4258
|
- Do not call `create`, `update`, or `delete` on the workflow tool; definitions are code-authored.
|
|
4386
4259
|
- Do not use legacy workflow tool fields like `agent`, `stage`, or run-control `name`.
|
|
4387
|
-
- Do not pass strings or path objects to `ctx.workflow(...)`; import the workflow definition from `@bastani/workflows/builtin` or another TypeScript module first.
|
|
4260
|
+
- Do not pass strings or path objects to `ctx.workflow(...)`; import the workflow definition from `@bastani/atomic/workflows/builtin` or another TypeScript module first.
|
|
4388
4261
|
- Do not create a self-edge or a dependency edge from the current frontier to an existing ancestor. Cyclic workflow graphs are unsupported; redesign or stop before launch when a cycle cannot be removed.
|
|
4389
4262
|
- Do not model a bounded loop by reopening an earlier node beneath its downstream work. Create distinct tracked work per iteration and keep retained-session follow-up as non-topological activity when it adds no dependency work.
|
|
4390
4263
|
- Do not claim TypeScript or workflow discovery proves a dynamic workflow acyclic. Discovery diagnoses imports and definition shape; execution, replay, and DBOS hydration are the runtime topology boundary.
|
|
@@ -4849,7 +4722,7 @@ During the pre-launch architecture pass, enumerate the slices in the coverage ma
|
|
|
4849
4722
|
└─────────────────────────────────────────────────────────────┘
|
|
4850
4723
|
```
|
|
4851
4724
|
|
|
4852
|
-
Run each slice through a child workflow that owns its implement/review/repair lifecycle. Import `goal` or `ralph` from `@bastani/workflows/builtin`, or use a task-specific child when neither builtin matches. Before each child, use a durable `ctx.tool(...)` step to create or check out the slice's explicit branch in its worktree. `worktreeFromInputs` creates a missing target with a detached checkout and reuses an existing target as-is; `base_branch` and `git_worktree_dir` do not create or check out a feature branch by themselves. Create slice N+1's branch from slice N's verified branch, then pass that previous branch as `base_branch` and give the child a distinct `git_worktree_dir`.
|
|
4725
|
+
Run each slice through a child workflow that owns its implement/review/repair lifecycle. Import `goal` or `ralph` from `@bastani/atomic/workflows/builtin`, or use a task-specific child when neither builtin matches. Before each child, use a durable `ctx.tool(...)` step to create or check out the slice's explicit branch in its worktree. `worktreeFromInputs` creates a missing target with a detached checkout and reuses an existing target as-is; `base_branch` and `git_worktree_dir` do not create or check out a feature branch by themselves. Create slice N+1's branch from slice N's verified branch, then pass that previous branch as `base_branch` and give the child a distinct `git_worktree_dir`.
|
|
4853
4726
|
|
|
4854
4727
|
The parent should verify each child before creating the next boundary. If a gate fails, stop at the first failed gate, report that slice as unverified, and retain the earlier verified slices and their branch/worktree records. Do not roll earlier slices back and do not continue past the failure.
|
|
4855
4728
|
|
|
@@ -4859,8 +4732,8 @@ The calls below are deliberately unrolled. Repeat the downstream shape for the p
|
|
|
4859
4732
|
import { spawnSync } from "node:child_process";
|
|
4860
4733
|
import { resolve } from "node:path";
|
|
4861
4734
|
import { Type } from "typebox";
|
|
4862
|
-
import { workflow } from "@bastani/workflows";
|
|
4863
|
-
import { goal } from "@bastani/workflows/builtin";
|
|
4735
|
+
import { workflow } from "@bastani/atomic/workflows";
|
|
4736
|
+
import { goal } from "@bastani/atomic/workflows/builtin";
|
|
4864
4737
|
|
|
4865
4738
|
function spawnCommand(argv: readonly string[], cwd: string) {
|
|
4866
4739
|
const [command, ...args] = argv;
|