@bastani/atomic 0.8.21 → 0.8.22-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -9
- package/dist/builtin/intercom/broker/broker.ts +3 -3
- package/dist/builtin/intercom/config.ts +3 -3
- package/dist/builtin/intercom/index.ts +1 -1
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/ui/compose.ts +2 -2
- package/dist/builtin/mcp/host-html-template.ts +0 -3
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +13 -4
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -9
- package/dist/builtin/subagents/agents/debugger.md +6 -6
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +1 -1
- package/dist/builtin/subagents/skills/browser-use/SKILL.md +234 -0
- package/dist/builtin/subagents/skills/browser-use/references/cdp-python.md +76 -0
- package/dist/builtin/subagents/skills/browser-use/references/multi-session.md +92 -0
- package/dist/builtin/subagents/skills/subagent/SKILL.md +4 -4
- package/dist/builtin/subagents/src/agents/skills.ts +19 -1
- package/dist/builtin/subagents/src/extension/index.ts +24 -22
- package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +7 -1
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +23 -7
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +98 -3
- package/dist/builtin/subagents/src/runs/background/async-status.ts +3 -1
- package/dist/builtin/subagents/src/runs/background/run-status.ts +1 -1
- package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +3 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +37 -12
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +15 -15
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +26 -2
- package/dist/builtin/subagents/src/runs/shared/nested-render.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +7 -0
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +28 -1
- package/dist/builtin/subagents/src/shared/fast-mode.ts +80 -0
- package/dist/builtin/subagents/src/shared/formatters.ts +4 -2
- package/dist/builtin/subagents/src/shared/types.ts +4 -2
- package/dist/builtin/subagents/src/shared/utils.ts +3 -61
- package/dist/builtin/subagents/src/tui/render.ts +303 -157
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +95 -35
- package/dist/builtin/workflows/README.md +228 -41
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +535 -541
- package/dist/builtin/workflows/builtin/goal.ts +39 -25
- package/dist/builtin/workflows/builtin/open-claude-design.ts +66 -69
- package/dist/builtin/workflows/builtin/ralph.ts +21 -21
- package/dist/builtin/workflows/package.json +6 -5
- package/dist/builtin/workflows/skills/research-codebase/SKILL.md +1 -1
- package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +2 -2
- package/dist/builtin/workflows/src/extension/discovery.ts +25 -146
- package/dist/builtin/workflows/src/extension/dispatcher.ts +72 -24
- package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +363 -0
- package/dist/builtin/workflows/src/extension/index.ts +690 -352
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +99 -62
- package/dist/builtin/workflows/src/extension/render-call.ts +2 -1
- package/dist/builtin/workflows/src/extension/render-result.ts +9 -3
- package/dist/builtin/workflows/src/extension/renderers.ts +5 -3
- package/dist/builtin/workflows/src/extension/runtime.ts +68 -33
- package/dist/builtin/workflows/src/extension/status-writer.ts +1 -1
- package/dist/builtin/workflows/src/extension/wiring.ts +34 -13
- package/dist/builtin/workflows/src/extension/workflow-module-loader.ts +142 -0
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +4 -4
- package/dist/builtin/workflows/src/index.ts +2 -0
- package/dist/builtin/workflows/src/intercom/result-intercom.ts +1 -1
- package/dist/builtin/workflows/src/runs/background/runner.ts +6 -4
- package/dist/builtin/workflows/src/runs/background/status.ts +45 -21
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +624 -52
- package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +80 -24
- package/dist/builtin/workflows/src/runs/shared/validate-inputs.ts +61 -24
- package/dist/builtin/workflows/src/runs/shared/workflow-runner.ts +32 -10
- package/dist/builtin/workflows/src/sdk-surface.ts +6 -0
- package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +178 -0
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +92 -12
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +21 -3
- package/dist/builtin/workflows/src/shared/render-inputs-schema.ts +1 -2
- package/dist/builtin/workflows/src/shared/run-visibility.ts +9 -0
- package/dist/builtin/workflows/src/shared/schema-introspection.ts +121 -0
- package/dist/builtin/workflows/src/shared/serializable.ts +132 -0
- package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +91 -9
- package/dist/builtin/workflows/src/shared/store-types.ts +31 -3
- package/dist/builtin/workflows/src/shared/store.ts +58 -14
- package/dist/builtin/workflows/src/shared/types.ts +105 -40
- package/dist/builtin/workflows/src/tui/chat-surface-message.ts +129 -13
- package/dist/builtin/workflows/src/tui/chat-surface.ts +6 -1
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +3 -2
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +1 -1
- package/dist/builtin/workflows/src/tui/graph-view.ts +91 -65
- package/dist/builtin/workflows/src/tui/inline-form-card.ts +1 -1
- package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +3 -2
- package/dist/builtin/workflows/src/tui/inputs-overlay.ts +3 -2
- package/dist/builtin/workflows/src/tui/inputs-picker.ts +8 -7
- package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +2 -0
- package/dist/builtin/workflows/src/tui/node-card.ts +34 -8
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -11
- package/dist/builtin/workflows/src/tui/prompt-card.ts +98 -50
- package/dist/builtin/workflows/src/tui/session-list.ts +7 -2
- package/dist/builtin/workflows/src/tui/session-picker.ts +2 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +226 -55
- package/dist/builtin/workflows/src/tui/status-helpers.ts +2 -0
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +37 -158
- package/dist/builtin/workflows/src/tui/toast.ts +2 -2
- package/dist/builtin/workflows/src/tui/widget.ts +53 -12
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +270 -19
- package/dist/builtin/workflows/src/tui/workflow-notice-card.ts +184 -0
- package/dist/builtin/workflows/src/workflows/define-workflow.ts +138 -43
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +45 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +27 -9
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +196 -17
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +2 -2
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/codex-fast-mode.d.ts +36 -0
- package/dist/core/codex-fast-mode.d.ts.map +1 -0
- package/dist/core/codex-fast-mode.js +117 -0
- package/dist/core/codex-fast-mode.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/index.d.ts +4 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -0
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +7 -2
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +23 -8
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/reactive-widget.d.ts +58 -0
- package/dist/core/extensions/reactive-widget.d.ts.map +1 -0
- package/dist/core/extensions/reactive-widget.js +182 -0
- package/dist/core/extensions/reactive-widget.js.map +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +26 -12
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +8 -2
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts +4 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +11 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/resource-loader.d.ts +9 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +49 -21
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +22 -13
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +7 -5
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +5 -3
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +16 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +64 -5
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +7 -4
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.js +2 -2
- package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +12 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
- package/dist/modes/interactive/chat-input-actions.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js +0 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/fast-mode-selector.d.ts +27 -0
- package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/fast-mode-selector.js +105 -0
- package/dist/modes/interactive/components/fast-mode-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +7 -12
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +132 -30
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +53 -6
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +2 -2
- package/docs/development.md +2 -2
- package/docs/docs.json +2 -2
- package/docs/extensions.md +18 -13
- package/docs/providers.md +5 -1
- package/docs/quickstart.md +5 -3
- package/docs/rpc.md +5 -5
- package/docs/sdk.md +12 -12
- package/docs/settings.md +18 -0
- package/docs/themes.md +6 -6
- package/docs/tui.md +20 -18
- package/docs/usage.md +2 -0
- package/docs/workflows.md +403 -39
- package/examples/extensions/qna.ts +2 -2
- package/package.json +4 -4
- package/dist/builtin/subagents/skills/playwright-cli/SKILL.md +0 -392
- package/dist/builtin/subagents/skills/playwright-cli/references/element-attributes.md +0 -23
- package/dist/builtin/subagents/skills/playwright-cli/references/playwright-tests.md +0 -39
- package/dist/builtin/subagents/skills/playwright-cli/references/request-mocking.md +0 -87
- package/dist/builtin/subagents/skills/playwright-cli/references/running-code.md +0 -241
- package/dist/builtin/subagents/skills/playwright-cli/references/session-management.md +0 -225
- package/dist/builtin/subagents/skills/playwright-cli/references/spec-driven-testing.md +0 -305
- package/dist/builtin/subagents/skills/playwright-cli/references/storage-state.md +0 -275
- package/dist/builtin/subagents/skills/playwright-cli/references/test-generation.md +0 -134
- package/dist/builtin/subagents/skills/playwright-cli/references/tracing.md +0 -139
- package/dist/builtin/subagents/skills/playwright-cli/references/video-recording.md +0 -143
|
@@ -29,7 +29,7 @@ Adding workflow files under `.atomic/workflows/` (project scope) or `~/.atomic/a
|
|
|
29
29
|
|
|
30
30
|
### Workflow lifecycle notifications
|
|
31
31
|
|
|
32
|
-
Workflow lifecycle notices are enabled by default. They send steer prompts into the main chat/model context when a run completes
|
|
32
|
+
Workflow lifecycle notices are enabled by default. They send steer prompts into the main chat/model context when a run completes or fails. Awaiting-input prompts are tracked for dedupe/restore, but they do not wake the main chat agent. Configure lifecycle tracking in the same extension config file:
|
|
33
33
|
|
|
34
34
|
```json
|
|
35
35
|
{
|
|
@@ -40,7 +40,9 @@ Workflow lifecycle notices are enabled by default. They send steer prompts into
|
|
|
40
40
|
}
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
Set `enabled` to `false` to disable all notices, or narrow `notifyOn` to a non-empty list of selected events.
|
|
43
|
+
Set `enabled` to `false` to disable all lifecycle notices, or narrow `notifyOn` to a non-empty list of selected events. Completion and failure lifecycle notices are emitted for top-level workflow runs, use steer delivery, and wake an idle model so the lifecycle update enters the model context when it happens. Nested child workflow completion/failure is reflected inside the expanded parent graph instead of producing separate top-level completion cards. Awaiting-input states are tracked for dedupe/restore, but workflows do not enqueue main-chat `/workflow connect` cards for them; prompt state remains visible through workflow status/connect surfaces, avoiding stale actionable cards if a prompt resolves while the main chat is streaming.
|
|
44
|
+
|
|
45
|
+
When a stage human-in-the-loop prompt is answered from the workflow TUI/stage chat, workflows also emits a separate display-only `workflows:hil-answer-notice` custom message. It records the answer for user-visible audit, but it does not wake the main agent, enter LLM context, or authorize answering later workflow prompts. Answers sent by the main-chat `workflow` tool do not emit this notice because the tool result already tells the main agent what happened.
|
|
44
46
|
|
|
45
47
|
---
|
|
46
48
|
|
|
@@ -49,15 +51,12 @@ Set `enabled` to `false` to disable all notices, or narrow `notifyOn` to a non-e
|
|
|
49
51
|
### Example 1 — Single task
|
|
50
52
|
|
|
51
53
|
```typescript
|
|
52
|
-
import { defineWorkflow } from "@bastani/workflows";
|
|
54
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
53
55
|
|
|
54
56
|
export default defineWorkflow("summarize-pr")
|
|
55
57
|
.description("Summarize a pull request in one task.")
|
|
56
|
-
.input("pr_url", {
|
|
57
|
-
|
|
58
|
-
required: true,
|
|
59
|
-
description: "URL of the pull request to summarize.",
|
|
60
|
-
})
|
|
58
|
+
.input("pr_url", Type.String({ description: "URL of the pull request to summarize." }))
|
|
59
|
+
.output("summary", Type.String({ description: "One-task summary of the pull request." }))
|
|
61
60
|
.run(async (ctx) => {
|
|
62
61
|
const summary = await ctx.task("summarize", {
|
|
63
62
|
prompt: `Summarize the pull request at ${String(ctx.inputs.pr_url)} clearly and concisely.`,
|
|
@@ -72,13 +71,14 @@ export default defineWorkflow("summarize-pr")
|
|
|
72
71
|
Use `ctx.parallel` for independent specialist work. The aggregator receives the specialist outputs through typed task results instead of manual stage/session plumbing.
|
|
73
72
|
|
|
74
73
|
```typescript
|
|
75
|
-
import { defineWorkflow } from "@bastani/workflows";
|
|
74
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
76
75
|
|
|
77
76
|
export default defineWorkflow("parallel-research")
|
|
78
77
|
.description("Scout → three parallel specialists → aggregator.")
|
|
79
|
-
.input("topic", {
|
|
78
|
+
.input("topic", Type.String({ description: "Research topic." }))
|
|
79
|
+
.output("summary", Type.String({ description: "Synthesized summary of the specialist reports." }))
|
|
80
80
|
.run(async (ctx) => {
|
|
81
|
-
const
|
|
81
|
+
const topic = ctx.inputs.topic;
|
|
82
82
|
|
|
83
83
|
const reports = await ctx.parallel([
|
|
84
84
|
{ name: "auth-specialist", task: `Research authentication patterns for: ${topic}` },
|
|
@@ -98,11 +98,13 @@ export default defineWorkflow("parallel-research")
|
|
|
98
98
|
### Example 3 — Human-in-the-loop (HIL)
|
|
99
99
|
|
|
100
100
|
```typescript
|
|
101
|
-
import { defineWorkflow } from "@bastani/workflows";
|
|
101
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
102
102
|
|
|
103
103
|
export default defineWorkflow("review-and-merge")
|
|
104
104
|
.description("Plan a change, ask for human approval, then execute.")
|
|
105
|
-
.input("task", {
|
|
105
|
+
.input("task", Type.String({ description: "What to implement." }))
|
|
106
|
+
.output("status", Type.Optional(Type.String({ description: "Set to \"cancelled\" when the human rejects the plan." })))
|
|
107
|
+
.output("result", Type.Optional(Type.String({ description: "Implementation result when the plan is approved." })))
|
|
106
108
|
.run(async (ctx) => {
|
|
107
109
|
const plan = await ctx.task("planner", {
|
|
108
110
|
prompt: `Create a concise implementation plan for: ${String(ctx.inputs.task)}`,
|
|
@@ -120,22 +122,87 @@ export default defineWorkflow("review-and-merge")
|
|
|
120
122
|
.compile();
|
|
121
123
|
```
|
|
122
124
|
|
|
125
|
+
Human input is runtime-only: call `ctx.ui.input`, `ctx.ui.confirm`, `ctx.ui.select`, or `ctx.ui.editor` at the point where the workflow actually needs a decision. No builder-level declaration is required or supported.
|
|
126
|
+
|
|
127
|
+
### Example 4 — Compose workflows
|
|
128
|
+
|
|
129
|
+
Prefer regular TypeScript module imports for reusable child workflows: import the compiled workflow definition, then pass it directly to `ctx.workflow(workflowDefinition, options)`.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
133
|
+
import goal from "@bastani/workflows/builtin/goal";
|
|
134
|
+
import sharedResearch from "./shared-research.js";
|
|
135
|
+
|
|
136
|
+
export default defineWorkflow("research-and-synthesize")
|
|
137
|
+
.input("topic", Type.String())
|
|
138
|
+
.output("final", Type.String({ description: "Synthesis of the child research and implementation." }))
|
|
139
|
+
.run(async (ctx) => {
|
|
140
|
+
const child = await ctx.workflow(sharedResearch, {
|
|
141
|
+
inputs: { topic: ctx.inputs.topic },
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const implementation = await ctx.workflow(goal, {
|
|
145
|
+
inputs: { objective: `Implement improvements based on: ${String(child.outputs.summary)}` },
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const final = await ctx.task("synthesize", {
|
|
149
|
+
prompt: `Synthesize this research and implementation:\n\n${String(child.outputs.summary)}\n\n${String(implementation.outputs.result)}`,
|
|
150
|
+
});
|
|
151
|
+
return { final: final.text };
|
|
152
|
+
})
|
|
153
|
+
.compile();
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The child executes as a nested workflow behind a parent boundary stage named `workflow:<workflow-name>` by default, but user-facing status and graph views flatten it into the parent run. In practice it should feel like inlining the child workflow code: child stages, HIL prompt nodes, and deeper imported children appear in one expanded parent graph, while implementation-owned child run ids stay hidden from top-level `/workflow status` lists. The child still has a run id internally so the graph can attach to, pause, interrupt, resume, or kill live child stages correctly. Inputs are strictly validated against the child workflow before it starts: unknown keys, missing required values, type mismatches, and invalid `select` choices fail before the child body runs. The parent receives the child's declared `.output(...)` outputs on `child.outputs` after those outputs pass their declared runtime type checks.
|
|
157
|
+
|
|
158
|
+
For workflows intended to be called as children, declare `.output(...)` for every non-default field a parent should rely on. `.output(...)` is only the schema/contract: use normal TypeScript in `.run()` to gather values from any stage/task/child workflow and return those keys.
|
|
159
|
+
|
|
160
|
+
**Return convention:** child outputs are return-object keys. Atomic never infers child workflow outputs from stage names, stage order, or the final assistant message. If a parent should read `child.outputs.summary`, the child workflow's `.run()` must both declare `.output("summary", schema)` and return `{ summary }`. `result` is not special and is never added for you: to expose `result`, declare `.output("result", schema)` and return `{ result }` like any other output. Returning a key that is not declared with `.output(...)` fails the run with `atomic-workflows: workflow "<name>" returned undeclared output "<key>"; declare it with .output("<key>", Type....) or remove it from the .run() return` (the child-call variant reports `... child "<alias>" returned undeclared output "<key>" from "<childName>"`).
|
|
161
|
+
|
|
162
|
+
A reusable child module can simply default-export a compiled workflow:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
166
|
+
|
|
167
|
+
export default defineWorkflow("shared-research")
|
|
168
|
+
.input("topic", Type.String())
|
|
169
|
+
.output("summary", Type.String())
|
|
170
|
+
.run(async (ctx) => {
|
|
171
|
+
const report = await ctx.task("research", {
|
|
172
|
+
prompt: `Research: ${String(ctx.inputs.topic)}`,
|
|
173
|
+
});
|
|
174
|
+
return { summary: report.text };
|
|
175
|
+
})
|
|
176
|
+
.compile();
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Builtin workflows are also callable as modules for reuse:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { deepResearchCodebase, goal, openClaudeDesign, ralph } from "@bastani/workflows/builtin";
|
|
183
|
+
import goalWorkflow from "@bastani/workflows/builtin/goal";
|
|
184
|
+
import openClaudeDesignWorkflow from "@bastani/workflows/builtin/open-claude-design";
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Only compiled workflow definitions can be passed to `ctx.workflow(...)`; registry names, strings, and path objects are intentionally not supported for child workflow calls. Missing or invalid module imports fail when the workflow file itself is loaded. A parent receives the child's declared `.output(...)` outputs from the child `.run()` return object. Missing required outputs, schema type mismatches, returning an undeclared output, and non-JSON-serializable returned child values fail the child call before the parent continues.
|
|
188
|
+
|
|
123
189
|
### Reusable Git worktrees
|
|
124
190
|
|
|
125
191
|
Use `gitWorktreeDir` when a workflow should run in a reusable Git worktree instead of the invoking checkout. The executor creates the worktree if it is missing, reuses it when it already exists as a same-repository worktree root, defaults workflow `ctx.cwd` to the matching path inside that worktree for `worktreeFromInputs`, and defaults stage/task `cwd` to that worktree path.
|
|
126
192
|
|
|
127
193
|
```typescript
|
|
128
|
-
import { defineWorkflow } from "@bastani/workflows";
|
|
194
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
129
195
|
|
|
130
196
|
export default defineWorkflow("safe-implementation")
|
|
131
197
|
.description("Run implementation stages in a reusable worktree.")
|
|
132
|
-
.input("task",
|
|
133
|
-
.input("worktree", {
|
|
134
|
-
.input("base_branch", {
|
|
198
|
+
.input("task", Type.String())
|
|
199
|
+
.input("worktree", Type.String({ default: "" }))
|
|
200
|
+
.input("base_branch", Type.String({ default: "origin/main" }))
|
|
135
201
|
.worktreeFromInputs({
|
|
136
202
|
gitWorktreeDir: "worktree",
|
|
137
203
|
baseBranch: "base_branch",
|
|
138
204
|
})
|
|
205
|
+
.output("result", Type.String({ description: "Implementation result text." }))
|
|
139
206
|
.run(async (ctx) => {
|
|
140
207
|
const result = await ctx.task("implement", {
|
|
141
208
|
task: String(ctx.inputs.task),
|
|
@@ -180,14 +247,18 @@ For advanced integrations, the SDK also exports `setupGitWorktree(options)`, whi
|
|
|
180
247
|
|
|
181
248
|
### Model fallbacks
|
|
182
249
|
|
|
183
|
-
Stages and high-level task helpers can retry transient provider/model failures with an ordered `fallbackModels` list. The primary `model` is tried first, then each fallback, and finally the current
|
|
250
|
+
Stages and high-level task helpers can retry transient provider/model failures with an ordered `fallbackModels` list. The primary `model` is tried first, then each fallback, and finally the current Atomic-selected model when available. Fallbacks are only used for retryable model/provider failures such as rate limits, quota/auth/provider outages, unavailable models, network timeouts, and 5xx errors — ordinary tool, shell, validation, cancellation, and workflow-code failures are not retried.
|
|
184
251
|
|
|
185
252
|
```typescript
|
|
186
|
-
import { defineWorkflow } from "@bastani/workflows";
|
|
253
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
187
254
|
|
|
188
255
|
export default defineWorkflow("fallback-review")
|
|
189
256
|
.description("Review with a model fallback chain.")
|
|
190
|
-
.input("topic",
|
|
257
|
+
.input("topic", Type.String())
|
|
258
|
+
.output("review", Type.String({ description: "Reviewer output text." }))
|
|
259
|
+
.output("model", Type.String({ description: "Model that produced the review." }))
|
|
260
|
+
.output("attemptedModels", Type.Array(Type.String(), { description: "Models tried, in fallback order." }))
|
|
261
|
+
.output("modelAttempts", Type.Array(Type.Unknown(), { description: "Per-attempt model fallback details." }))
|
|
191
262
|
.run(async (ctx) => {
|
|
192
263
|
const review = await ctx.task("reviewer", {
|
|
193
264
|
prompt: `Review this topic: ${String(ctx.inputs.topic)}`,
|
|
@@ -223,9 +294,9 @@ When pi exposes its model registry, workflow runs validate user-specified `model
|
|
|
223
294
|
```typescript
|
|
224
295
|
import { createRegistry, defineWorkflow } from "@bastani/workflows";
|
|
225
296
|
|
|
226
|
-
const alpha = defineWorkflow("alpha").run(async () => {}).compile();
|
|
227
|
-
const beta = defineWorkflow("beta").run(async () => {}).compile();
|
|
228
|
-
const gamma = defineWorkflow("gamma").run(async () => {}).compile();
|
|
297
|
+
const alpha = defineWorkflow("alpha").run(async () => ({})).compile();
|
|
298
|
+
const beta = defineWorkflow("beta").run(async () => ({})).compile();
|
|
299
|
+
const gamma = defineWorkflow("gamma").run(async () => ({})).compile();
|
|
229
300
|
|
|
230
301
|
const registry = createRegistry()
|
|
231
302
|
.register(alpha)
|
|
@@ -237,15 +308,115 @@ registry.all(); // compiled workflow definitions
|
|
|
237
308
|
registry.get("alpha"); // compiled workflow definition | undefined
|
|
238
309
|
```
|
|
239
310
|
|
|
240
|
-
###
|
|
311
|
+
### Declaring inputs and outputs with TypeBox
|
|
312
|
+
|
|
313
|
+
Inputs and outputs are declared with [TypeBox](https://github.com/sinclairzx81/typebox) schemas. Import `Type` from `@bastani/workflows` (alongside `defineWorkflow`) and pass a schema to `.input(key, schema)` / `.output(key, schema)`. The builder infers precise static types for `ctx.inputs`, the `.run()` return, and `child.outputs` from those schemas, and the runtime validates against them with TypeBox `Value`.
|
|
314
|
+
|
|
315
|
+
**Prefer precise schemas.** A precise schema (`Type.Object({ topic: Type.String(), score: Type.Number() })`, `Type.Array(Type.String())`) gives consumers a precise `Static<>` type and makes runtime validation enforce the real shape. Reserve `Type.Unknown()`, `Type.Any()`, `Type.Array(Type.Unknown())`, and `Type.Object({}, { additionalProperties: true })` for genuinely dynamic data whose shape you cannot know ahead of time.
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
319
|
+
|
|
320
|
+
defineWorkflow("example")
|
|
321
|
+
.input("prompt", Type.String({ description: "Required free-text input." })) // required key -> ctx.inputs.prompt: string
|
|
322
|
+
.input("ref", Type.Optional(Type.String())) // optional key -> string | undefined
|
|
323
|
+
.input("count", Type.Number({ default: 2 })) // defaulted -> required key, ctx.inputs.count: number
|
|
324
|
+
.input("flavor", Type.Union([Type.Literal("a"), Type.Literal("b")], { default: "a" })) // select
|
|
325
|
+
.output("packet", Type.Object({ topic: Type.String(), score: Type.Number() })) // required object output
|
|
326
|
+
.output("note", Type.Optional(Type.String())) // optional output
|
|
327
|
+
.run(async (ctx) => ({ packet: { topic: ctx.inputs.prompt, score: ctx.inputs.count } }))
|
|
328
|
+
.compile();
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
`Static` and `TSchema` are also re-exported from `@bastani/workflows` for advanced typing.
|
|
332
|
+
|
|
333
|
+
### Input schema reference
|
|
334
|
+
|
|
335
|
+
| Schema | Picker kind | Notes |
|
|
336
|
+
| ------------------------------------------------------------ | ----------- | ------------------------------------------------ |
|
|
337
|
+
| `Type.String({ default?, description? })` | `text` | Free-form string |
|
|
338
|
+
| `Type.Number({ default?, description? })` | `number` | Finite number |
|
|
339
|
+
| `Type.Integer({ default?, description? })` | `integer` | Integer |
|
|
340
|
+
| `Type.Boolean({ default?, description? })` | `boolean` | True/false toggle |
|
|
341
|
+
| `Type.Union([Type.Literal("a"), Type.Literal("b")], { default? })` | `select` | Enumerated string choices |
|
|
342
|
+
| `Type.Optional(schema)` | — | Makes the key optional (`T \| undefined`) |
|
|
343
|
+
|
|
344
|
+
A required input is any schema that is neither `Type.Optional(...)` nor carries a `default` (a defaulted input is a required key at the type level but optional for the caller to provide). Input validation is strict for named workflow runs and `ctx.workflow(...)` child calls: Atomic rejects unknown keys, missing required values, values whose runtime type does not match the declared schema, and `select` values outside the declared literals. It does not coerce strings like `"3"` into numbers; pass JSON numbers (`count=3`) for `Type.Number()`. `.input(...)` narrows `ctx.inputs` for intellisense: required/defaulted strings are `string`, numbers are `number`, booleans are `boolean`, selects are the literal union, and `Type.Optional(...)` inputs include `undefined`.
|
|
345
|
+
|
|
346
|
+
### Output types
|
|
347
|
+
|
|
348
|
+
Declare outputs with `.output(key, schema?)` when a workflow result should be part of its runtime contract, especially when another workflow will call it as a child. Lead with the most precise schema you can express — the loose rows at the bottom are last resorts for genuinely dynamic data.
|
|
349
|
+
|
|
350
|
+
| Schema | Runtime value accepted |
|
|
351
|
+
| --------------------------------------------------- | --------------------------------------------------- |
|
|
352
|
+
| `Type.String()` | string |
|
|
353
|
+
| `Type.Number()` | finite number (rejects `NaN`) |
|
|
354
|
+
| `Type.Integer()` | integer |
|
|
355
|
+
| `Type.Boolean()` | boolean |
|
|
356
|
+
| `Type.Union([Type.Literal(...)])` | one of the declared literal strings |
|
|
357
|
+
| `Type.Array(Type.String())` | array of the declared element type (use the real type) |
|
|
358
|
+
| `Type.Object({ topic: Type.String(), ... })` | object matching the declared shape |
|
|
359
|
+
| `Type.Unsafe<T>(runtimeSchema)` | precise static `T`, lenient runtime (escape hatch) |
|
|
360
|
+
| `Type.Array(Type.Unknown())` | any JSON array (last resort, dynamic only) |
|
|
361
|
+
| `Type.Object({}, { additionalProperties: true })` | any JSON object (last resort, dynamic only) |
|
|
362
|
+
| `Type.Unknown()` / `Type.Any()` | any JSON-serializable value (last resort) |
|
|
363
|
+
|
|
364
|
+
Wrap an output schema in `Type.Optional(...)` to make the key optional; an un-wrapped output schema is required. `.run()` must return a JSON-serializable object. Functions, symbols, `undefined` properties, `NaN`, infinite numbers, and non-plain objects (e.g. `Date`) fail validation. Declared outputs are validated before a workflow is marked completed. A required output that is missing fails with `missing output "<key>"`, and a type mismatch fails with `output "<key>" expected <kind>, got <actual>`. A workflow exposes exactly the outputs it declares with `.output(...)`: there is no automatic `result` output, and returning a key that was not declared fails the run with `atomic-workflows: workflow "<name>" returned undeclared output "<key>"; declare it with .output("<key>", Type....) or remove it from the .run() return`. To expose `result`, declare `.output("result", schema)` and return `{ result }`. Child output replay still performs a structured-clone safety check after JSON validation so completed child boundaries can be replayed.
|
|
365
|
+
|
|
366
|
+
#### Why precise schemas
|
|
367
|
+
|
|
368
|
+
A loose schema types the value as `unknown`/`Record<string, unknown>` everywhere it is read and only checks "is this JSON?" at runtime. A precise schema types it exactly and validates the real shape:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
// ❌ Loose: child.outputs.report is `unknown`; runtime only checks "is JSON".
|
|
372
|
+
.output("report", Type.Unknown())
|
|
373
|
+
|
|
374
|
+
// ✅ Precise: child.outputs.report is `{ topic: string; score: number; tags: string[] }`,
|
|
375
|
+
// and TypeBox rejects a returned value missing `score` or with a non-number `score`.
|
|
376
|
+
.output("report", Type.Object({
|
|
377
|
+
topic: Type.String(),
|
|
378
|
+
score: Type.Number(),
|
|
379
|
+
tags: Type.Array(Type.String()),
|
|
380
|
+
}))
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
#### `Type.Unsafe<T>()` escape hatch
|
|
384
|
+
|
|
385
|
+
When you already have a precise TypeScript interface for a deeply-nested serializable value and don't want to hand-write the full TypeBox schema, wrap a permissive runtime schema with `Type.Unsafe<MyInterface>(...)`. The **static** type becomes exactly `MyInterface` (so `ctx.inputs`, the `.run()` return, and `child.outputs` stay precise), while the **runtime** stays as lenient as the wrapped schema:
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
389
|
+
|
|
390
|
+
interface ResearchPacket {
|
|
391
|
+
readonly topic: string;
|
|
392
|
+
readonly score: number;
|
|
393
|
+
readonly sections: readonly { readonly heading: string; readonly body: string }[];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export default defineWorkflow("research-packet")
|
|
397
|
+
.input("topic", Type.String())
|
|
398
|
+
// Static type = ResearchPacket; runtime only checks "is a JSON object".
|
|
399
|
+
.output("packet", Type.Unsafe<ResearchPacket>(Type.Object({}, { additionalProperties: true })))
|
|
400
|
+
.run(async (ctx) => {
|
|
401
|
+
const packet: ResearchPacket = {
|
|
402
|
+
topic: ctx.inputs.topic,
|
|
403
|
+
score: 1,
|
|
404
|
+
sections: [{ heading: "overview", body: "…" }],
|
|
405
|
+
};
|
|
406
|
+
return { packet };
|
|
407
|
+
})
|
|
408
|
+
.compile();
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Tradeoff: `Type.Unsafe<T>()` does not deeply validate at runtime — it trusts the produced value matches `T`. Use it when the producing code already guarantees the shape; when you can express the shape directly, prefer a real `Type.Object(...)`/`Type.Array(...)` so runtime validation also catches drift. Keep bare `Type.Unknown()` and loose `additionalProperties` objects for genuinely dynamic data.
|
|
412
|
+
|
|
413
|
+
#### How types flow
|
|
241
414
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
| `boolean` | True/false toggle | `default`, `required` |
|
|
248
|
-
| `select` | Enumerated choices | `choices: string[]`, `default`, `required` |
|
|
415
|
+
- `ctx.inputs.x` is `Static<inputSchema>` — required/defaulted inputs are present, `Type.Optional(...)` adds `| undefined`.
|
|
416
|
+
- The `.run()` return is checked against declared outputs at compile time (missing-required and wrong-type are TypeScript errors) and at runtime via TypeBox `Value` (undeclared keys rejected, declared shape enforced recursively).
|
|
417
|
+
- `ctx.workflow(child).outputs` is typed from the child's declared `.output(...)` contract, so a parent reads precisely-typed child outputs without casting.
|
|
418
|
+
|
|
419
|
+
`Static` and `TSchema` are re-exported from `@bastani/workflows`; use `Static<typeof schema>` when you need a schema's inferred TypeScript type directly.
|
|
249
420
|
|
|
250
421
|
---
|
|
251
422
|
|
|
@@ -265,21 +436,25 @@ registry.get("alpha"); // compiled workflow definition | undefined
|
|
|
265
436
|
| `/workflow interrupt [run-id\|--all]` | Pause active/named/all active runs so they can resume |
|
|
266
437
|
| `/workflow kill [run-id\|--all]` | Kill in-flight workflow runs; killed runs are retained for inspection |
|
|
267
438
|
| `/workflow resume <run-id>` | Resume paused work or re-open a run snapshot |
|
|
268
|
-
| `/workflow reload` | Reload discovered workflow resources in-process
|
|
439
|
+
| `/workflow reload` | Reload discovered workflow resources and package-manifest entries in-process |
|
|
269
440
|
| `/workflow inputs <name>` | Print the input schema for a workflow |
|
|
270
441
|
|
|
271
|
-
Input overrides are bare `key=value` tokens (no leading `--`). Values are JSON-parsed when possible, so numbers, booleans, and quoted strings work as expected (e.g. `count=3`, `flag=true`, `prompt="multi word value"`). A whole-object override can be passed as a single JSON token (e.g. `{"prompt":"...","count":3}`).
|
|
442
|
+
Input overrides are bare `key=value` tokens (no leading `--`). Values are JSON-parsed when possible, so numbers, booleans, and quoted strings work as expected (e.g. `count=3`, `flag=true`, `prompt="multi word value"`). A whole-object override can be passed as a single JSON token (e.g. `{"prompt":"...","count":3}`). Runtime validation is strict: unknown input keys, missing required values, type mismatches, and invalid `select` choices fail before a named workflow run starts.
|
|
443
|
+
|
|
444
|
+
Workflows always run as **background tasks** in interactive sessions — the chat editor stays free while a run executes. Press **F2** (or `/workflow connect <run-id>`) to attach to the live graph viewer; HIL prompts (`ctx.ui.input/confirm/select/editor`) appear as awaiting-input graph nodes. Press Enter on the node to answer locally, never as a modal dialog over the chat. Human input is detected when those runtime `ctx.ui.*` calls execute; workflows no longer have a declaration-time HIL flag.
|
|
272
445
|
|
|
273
|
-
|
|
446
|
+
Nested `ctx.workflow(...)` calls are displayed as an expanded graph within the top-level run. `/workflow status` and run pickers list only top-level user-launched workflows, not implementation-owned child runs. `/workflow stages`, `/workflow stage`, `/workflow transcript`, `send`, `pause`, `interrupt`, and `resume` can still target visible child stage ids, prefixes, or names from the expanded graph; Atomic routes the control action to the owning nested run internally.
|
|
274
447
|
|
|
275
448
|
Prompt answer replay is live-memory only. `StageSnapshot.promptAnswerState` reports whether continuation can replay a prompt answer (`available`), must ask again because the private ledger entry is gone (`unavailable`), or must ask again because multiple matching prompt nodes are ambiguous (`ambiguous`). Raw answers stay in a private `PromptAnswerRecord` ledger, are never serialized to snapshots or persistence, and remain resident in memory until the answer is cleared, the run is removed, or the store is cleared. Replay keys include prompt kind, message text, select choices, input/editor initial value, and hashed author callsite, so changing any of those inputs may intentionally re-ask on continuation. Empty `ctx.ui.select(..., [])` calls throw before creating a prompt node.
|
|
276
449
|
|
|
277
450
|
### `workflow` tool (LLM-callable)
|
|
278
451
|
|
|
452
|
+
<!-- Keep the description below in sync with WORKFLOW_TOOL_DESCRIPTION in packages/workflows/src/extension/index.ts; integration tests assert this. -->
|
|
453
|
+
|
|
279
454
|
```json
|
|
280
455
|
{
|
|
281
456
|
"name": "workflow",
|
|
282
|
-
"description": "Run
|
|
457
|
+
"description": "Run named workflows or direct one-off task/tasks/chain workflows; discover with list/get/inputs, inspect status/stages/stage details, send prompt answers or steering, pause/resume/interrupt/kill runs, and reload workflow resources. For transcripts, prefer status/stages/stage to get sessionFile/transcriptPath, quote the exact path without rewriting separators (Windows backslashes are valid), search it with rg/grep, and read small ranges; transcript defaults to at most 5 recent entries and explicit tail/limit overrides that preview.",
|
|
283
458
|
"parameters": {
|
|
284
459
|
"workflow": "string (optional) — workflow ID or normalized name",
|
|
285
460
|
"inputs": "object (optional) — key/value map of workflow inputs",
|
|
@@ -288,9 +463,9 @@ Prompt answer replay is live-memory only. `StageSnapshot.promptAnswerState` repo
|
|
|
288
463
|
"stageId": "optional stage id, prefix, or name for stage-scoped actions; cannot be combined with all:true",
|
|
289
464
|
"statusFilter": "optional stages filter: pending/running/awaiting_input/paused/blocked/completed/failed/skipped/all",
|
|
290
465
|
"format": "optional agent-facing output format: text or json",
|
|
291
|
-
"limit": "transcript-only maximum number of
|
|
292
|
-
"tail": "transcript-only last-N entry count; overrides limit",
|
|
293
|
-
"includeToolOutput": "transcript-only flag for snapshot tool-event output;
|
|
466
|
+
"limit": "transcript-only explicit maximum number of recent entries; omitted with tail omitted uses the default 5-entry preview plus metadata/path",
|
|
467
|
+
"tail": "transcript-only explicit last-N entry count; overrides limit for quick recent-context checks",
|
|
468
|
+
"includeToolOutput": "transcript-only flag for explicit snapshot tool-event output; prefer rg/grep on the exact quoted sessionFile/transcriptPath for large outputs",
|
|
294
469
|
"text": "optional string payload for send/resume; explicit empty text answers pending prompts",
|
|
295
470
|
"response": "optional structured payload for answering pending prompts; explicit empty response is valid",
|
|
296
471
|
"message": "optional string payload for send/resume when text is not provided",
|
|
@@ -305,7 +480,7 @@ Prompt answer replay is live-memory only. `StageSnapshot.promptAnswerState` repo
|
|
|
305
480
|
|
|
306
481
|
- **`renderCall`** — renders a compact workflow call summary in the chat scroll.
|
|
307
482
|
- **`renderResult`** — renders the result or dispatch banner; live progress continues through the widget and graph viewer. Named workflow runs are background-oriented.
|
|
308
|
-
- **`transcript`** —
|
|
483
|
+
- **`transcript`** — reference-first with a small preview by default: use `status`, `stages`, or `stage` to identify the stage and its `sessionFile`/`transcriptPath`, quote the exact path without changing platform separators (for example, preserve Windows backslashes), then search that file with `rg`/`grep` for targeted terms and read only small surrounding ranges. Text results include JSON-escaped `sessionFileJson`/`transcriptPathJson` lines for copy-safe path literals plus up to 5 recent entries by default. Passing explicit `tail` or `limit` overrides that preview for quick context checks. A registered live stage handle is used when one exists, even before live messages arrive; otherwise the action falls back to stored stage snapshots. Snapshot entries are ordered chronologically before `tail`/`limit` is applied, with terminal result/error entries kept after tool entries when timestamps are missing or tied. `includeToolOutput` applies to snapshot tool-event results; live session transcripts may not expose tool output.
|
|
309
484
|
- **`send`** — answers pending stage prompts only when `text`, `response`, or `message` is present; an explicit empty string is a valid answer, while an omitted payload is a no-op. `delivery: "auto"` answers pending prompts first, then resumes paused stages, steers streaming stages, or queues a follow-up.
|
|
310
485
|
- **`reload`** — refreshes workflow resources directly in-process instead of queuing a literal `/workflow reload` chat follow-up.
|
|
311
486
|
|
|
@@ -317,7 +492,11 @@ Press **F2** while a workflow is running to open the DAG overlay for the active
|
|
|
317
492
|
|
|
318
493
|
`@bastani/workflows` follows pi's package/extension model: pi loads `src/extension/index.ts` from the package `pi.extensions` manifest, then the extension registers the `workflow` tool, `/workflow` slash command, renderers, widget, and lifecycle hooks in-process.
|
|
319
494
|
|
|
320
|
-
For interactive use, run workflows through `/workflow <name> [key=value ...]` or let the LLM call the `workflow` tool.
|
|
495
|
+
For interactive use, run workflows through `/workflow <name> [key=value ...]` or let the LLM call the `workflow` tool. In non-interactive (`-p` / `--print` / `--mode json`) sessions, `/workflow <name> key=value` and LLM calls to the `workflow` tool remain available for deterministic workflows. The input picker and graph picker are disabled, top-level `ctx.ui.*` is unavailable, and stage child sessions exclude `ask_user_question`. Named workflow dispatch waits for the terminal run snapshot before returning.
|
|
496
|
+
|
|
497
|
+
Because human input is runtime-only and workflows no longer carry a declaration-time HIL marker, headless dispatch does not reject a workflow just because its source contains `ctx.ui.*`. If you copy the HIL example above into a non-interactive session, it can pass dispatch and then fail when execution reaches the prompt with an error such as `atomic-workflows: HIL ctx.ui.confirm is unavailable because Atomic runtime did not provide a UI adapter` (the primitive name varies). Run those workflows interactively, or guard/remove runtime `ctx.ui.*` calls before using headless mode.
|
|
498
|
+
|
|
499
|
+
For library or scripted use, you can also call the explicit programmatic runner:
|
|
321
500
|
|
|
322
501
|
```ts
|
|
323
502
|
import { runWorkflow, type WorkflowOptions } from "@bastani/workflows";
|
|
@@ -375,10 +554,12 @@ Scout + research-history chain → two parallel specialist waves → aggregator.
|
|
|
375
554
|
| ----------------- | -------- | -------- | ------- | --------------------------------------------------------- |
|
|
376
555
|
| `prompt` | `text` | ✓ | — | Research question or topic to investigate. |
|
|
377
556
|
| `max_partitions` | `number` | — | `100` | Maximum number of codebase partitions to explore. |
|
|
378
|
-
| `max_concurrency` | `number` | — | `
|
|
557
|
+
| `max_concurrency` | `number` | — | `100` | Maximum number of workflow stages to run concurrently. |
|
|
379
558
|
|
|
380
559
|
Final Markdown research documents are written to dated `research/` paths relative to the current working directory, with a numeric suffix if needed to avoid overwriting an existing document. Hidden run artifacts are written under `research/.deep-research-<run-id>/`.
|
|
381
560
|
|
|
561
|
+
Child workflow outputs: `result`, `findings`, `research_doc_path`, `artifact_dir`, `manifest_path`, `partitions`, `explorer_count`, `specialist_count`, `max_concurrency`, and `history`.
|
|
562
|
+
|
|
382
563
|
### `goal`
|
|
383
564
|
|
|
384
565
|
Goal Runner workflow: initialize a persisted goal ledger with a per-run goal id and lifecycle events, render goal-continuation context, run bounded worker LM turns, append receipts, run three independent reviewers, and let a TypeScript reducer decide `complete`, `continue`, `blocked`, or `needs_human`. Token budget behavior is intentionally excluded.
|
|
@@ -395,6 +576,8 @@ Goal Runner workflow: initialize a persisted goal ledger with a per-run goal id
|
|
|
395
576
|
|
|
396
577
|
`goal` defaults to 10 worker/review turns. Reviewer quorum is fixed internally at 2 reviewer `complete` votes. The repeated-blocker threshold defaults to 3 consecutive same-blocker turns and is clamped to `max_turns` when you run fewer than 3 turns.
|
|
397
578
|
|
|
579
|
+
Child workflow outputs: `result`, `status`, `approved`, `goal_id`, `objective`, `ledger_path`, `turns_completed`, `iterations_completed`, `receipts`, `remaining_work`, and `review_report`.
|
|
580
|
+
|
|
398
581
|
### `ralph`
|
|
399
582
|
|
|
400
583
|
Plan → orchestrate → simplify → discover → review → PR-handoff workflow: write an RFC-style technical design document under `specs/`, delegate implementation through sub-agents, simplify recent changes, discover review infrastructure, run parallel reviewers, iterate until approval or the loop limit, then prepare a pull-request report.
|
|
@@ -410,6 +593,8 @@ Plan → orchestrate → simplify → discover → review → PR-handoff workflo
|
|
|
410
593
|
| `base_branch` | `string` | — | `origin/main` | Branch reviewers and PR-prep compare the current delta with; also used to create a missing worktree. |
|
|
411
594
|
| `git_worktree_dir` | `string` | — | `""` | Optional reusable Git worktree root. Empty runs in the invoking checkout; non-empty values run Ralph stages in the created/reused worktree. |
|
|
412
595
|
|
|
596
|
+
Child workflow outputs: `result`, `plan`, `plan_path`, `implementation_notes_path`, `pr_report`, `approved`, `iterations_completed`, and `review_report`.
|
|
597
|
+
|
|
413
598
|
### `open-claude-design`
|
|
414
599
|
|
|
415
600
|
Design-system onboarding → reference import → generation → refinement → export/handoff pipeline.
|
|
@@ -426,6 +611,8 @@ Design-system onboarding → reference import → generation → refinement →
|
|
|
426
611
|
| `design_system` | `text` | — | — | Existing design-system reference / Design.md path. |
|
|
427
612
|
| `max_refinements` | `number` | — | `3` | Maximum critique/apply refinement iterations. |
|
|
428
613
|
|
|
614
|
+
Child workflow outputs: `output_type`, `design_system`, `artifact`, `handoff`, `approved_for_export`, `refinements_completed`, `import_context`, `run_id`, `artifact_dir`, `preview_path`, `preview_file_url`, `spec_path`, and `spec_file_url`. `open-claude-design` has no `result` output; it exposes only the declared fields listed here.
|
|
615
|
+
|
|
429
616
|
---
|
|
430
617
|
|
|
431
618
|
## Custom workflow discovery
|