@bastani/atomic 0.9.18-alpha.2 → 0.9.18-alpha.4
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 +6 -0
- package/dist/builtin/intercom/CHANGELOG.md +8 -0
- package/dist/builtin/intercom/README.md +3 -3
- package/dist/builtin/intercom/broker/broker.ts +156 -12
- package/dist/builtin/intercom/broker/client.ts +89 -49
- package/dist/builtin/intercom/broker/pending-question-index.ts +10 -0
- package/dist/builtin/intercom/broker/send-handler.ts +32 -17
- package/dist/builtin/intercom/index.bundle.mjs +153 -50
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/skills/intercom/SKILL.md +1 -1
- package/dist/builtin/intercom/types.ts +30 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +18 -0
- package/dist/builtin/workflows/README.md +11 -2
- package/dist/builtin/workflows/builtin/{chunk-ngffz3y8.js → chunk-fghhy2a5.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-6v0yv8tj.js → chunk-h3r2vkzc.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-brerg33r.js → chunk-n58a7v26.js} +0 -1
- package/dist/builtin/workflows/builtin/goal.js +2 -2
- package/dist/builtin/workflows/builtin/index.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +2 -2
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +258 -49
- package/dist/builtin/workflows/src/index.js +35 -9
- package/docs/intercom.md +7 -5
- package/docs/models/artificial-analysis-index.md +2 -1
- package/docs/models/model-selection.md +19 -18
- package/docs/models/pareto-efficiency.md +36 -29
- package/docs/workflows.md +18 -9
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
|
@@ -1392,7 +1392,6 @@ function compactStage(stage) {
|
|
|
1392
1392
|
inputRequest,
|
|
1393
1393
|
notices,
|
|
1394
1394
|
mcpScope: _mcpScope,
|
|
1395
|
-
pendingStageDeliveryAvailable: _pendingStageDeliveryAvailable,
|
|
1396
1395
|
attemptedModels: _attemptedModels,
|
|
1397
1396
|
modelAttempts: _modelAttempts,
|
|
1398
1397
|
result: _result,
|
|
@@ -4459,6 +4458,7 @@ function durableStageCheckpointMetadata(stage, run, sourceOrder) {
|
|
|
4459
4458
|
version: DURABLE_STAGE_TOPOLOGY_VERSION,
|
|
4460
4459
|
stageId: stage.id,
|
|
4461
4460
|
parentIds: [...stage.parentIds],
|
|
4461
|
+
...stage.intercomGroup !== undefined ? { intercomGroup: stage.intercomGroup } : {},
|
|
4462
4462
|
...stage.executionOrder !== undefined ? { order: stage.executionOrder } : {},
|
|
4463
4463
|
...sourceOrder !== undefined && sourceOrder >= 0 ? { sourceOrder } : {},
|
|
4464
4464
|
...stage.promptFootprint !== undefined ? { occurrenceKey: stage.id } : {},
|
|
@@ -5191,11 +5191,13 @@ function createDurableStagePrimitive(input) {
|
|
|
5191
5191
|
const isMidSessionResume = session?.sessionFile !== undefined;
|
|
5192
5192
|
const topology = activeStageTopology(input.backend, input.workflowId, replayKey);
|
|
5193
5193
|
const durableStageId = topology?.stageId ?? pendingStageIdForReplay(input.backend, input.workflowId, replayKey, name);
|
|
5194
|
+
const durableIntercomGroup = topology?.intercomGroup ?? input.durableIntercomGroup?.(replayKey, durableStageId);
|
|
5194
5195
|
const liveOptions = {
|
|
5195
5196
|
...options ?? {},
|
|
5196
5197
|
durableReplayKey: replayKey,
|
|
5197
5198
|
...durableStageId !== undefined ? { durableStageId } : {},
|
|
5198
5199
|
...topology !== undefined ? { durableParentIds: [...topology.parentIds] } : {},
|
|
5200
|
+
...durableIntercomGroup !== undefined ? { durableIntercomGroup } : {},
|
|
5199
5201
|
...isMidSessionResume ? {
|
|
5200
5202
|
resumeFromSessionFile: session.sessionFile,
|
|
5201
5203
|
durableAccumulatedDurationMs: session.durationMs ?? 0
|
|
@@ -5224,6 +5226,7 @@ function createDurableTaskPrimitive(input) {
|
|
|
5224
5226
|
}
|
|
5225
5227
|
const session = input.backend.getStageSession(input.workflowId, replayKey);
|
|
5226
5228
|
const topology = activeStageTopology(input.backend, input.workflowId, replayKey);
|
|
5229
|
+
const durableIntercomGroup = topology?.intercomGroup ?? input.durableIntercomGroup?.(replayKey, topology?.stageId);
|
|
5227
5230
|
const taskOptions = {
|
|
5228
5231
|
...options,
|
|
5229
5232
|
durableReplayKey: replayKey,
|
|
@@ -5231,6 +5234,7 @@ function createDurableTaskPrimitive(input) {
|
|
|
5231
5234
|
durableStageId: topology.stageId,
|
|
5232
5235
|
durableParentIds: [...topology.parentIds]
|
|
5233
5236
|
} : {},
|
|
5237
|
+
...durableIntercomGroup !== undefined ? { durableIntercomGroup } : {},
|
|
5234
5238
|
...session?.sessionFile !== undefined ? {
|
|
5235
5239
|
resumeFromSessionFile: session.sessionFile,
|
|
5236
5240
|
durableAccumulatedDurationMs: session.durationMs ?? 0
|
|
@@ -8608,6 +8612,7 @@ function appendStageStart(api, payload) {
|
|
|
8608
8612
|
name: payload.name,
|
|
8609
8613
|
parentIds: [...payload.parentIds],
|
|
8610
8614
|
...payload.model !== undefined ? { model: payload.model } : {},
|
|
8615
|
+
...payload.intercomGroup !== undefined ? { intercomGroup: payload.intercomGroup } : {},
|
|
8611
8616
|
...payload.pendingStageDeliveryAvailable !== undefined ? { pendingStageDeliveryAvailable: payload.pendingStageDeliveryAvailable } : {},
|
|
8612
8617
|
...payload.replayKey !== undefined ? { replayKey: payload.replayKey } : {},
|
|
8613
8618
|
...payload.replayedFromStageId !== undefined ? { replayedFromStageId: payload.replayedFromStageId } : {},
|
|
@@ -10357,18 +10362,28 @@ function resolveStageGroup(stageOptions, workflowGroup) {
|
|
|
10357
10362
|
const group = stageOptions.group;
|
|
10358
10363
|
if (group === undefined)
|
|
10359
10364
|
return workflowGroup;
|
|
10360
|
-
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10365
|
+
const authored = group === true ? randomUUID2() : group.trim();
|
|
10366
|
+
if (authored.length === 0)
|
|
10367
|
+
return;
|
|
10368
|
+
if (workflowGroup === undefined || authored === DEFAULT_INTERCOM_GROUP)
|
|
10369
|
+
return authored;
|
|
10370
|
+
const owner2 = normalizeGroup(workflowGroup);
|
|
10371
|
+
if (authored === owner2 || authored.startsWith(`${owner2}/`))
|
|
10372
|
+
return authored;
|
|
10373
|
+
return `${owner2}/${authored}`;
|
|
10374
|
+
}
|
|
10375
|
+
function workflowInvocationOwnsGroup(workflowGroup, candidate) {
|
|
10376
|
+
if (workflowGroup === undefined || candidate === undefined)
|
|
10377
|
+
return false;
|
|
10378
|
+
const owner2 = normalizeGroup(workflowGroup);
|
|
10379
|
+
const group = normalizeGroup(candidate);
|
|
10380
|
+
return group === owner2 || group.startsWith(`${owner2}/`);
|
|
10364
10381
|
}
|
|
10365
10382
|
function stageHasIntercomAccess(_stageOptions) {
|
|
10366
10383
|
return true;
|
|
10367
10384
|
}
|
|
10368
10385
|
function stageCanUseWorkflowPendingStageRoute(stageOptions, workflowGroup) {
|
|
10369
|
-
|
|
10370
|
-
return false;
|
|
10371
|
-
return normalizeGroup(resolveStageGroup(stageOptions, workflowGroup)) === normalizeGroup(workflowGroup);
|
|
10386
|
+
return stageHasIntercomAccess(stageOptions) && workflowInvocationOwnsGroup(workflowGroup, resolveStageGroup(stageOptions, workflowGroup));
|
|
10372
10387
|
}
|
|
10373
10388
|
|
|
10374
10389
|
// dist/builtin/workflows/builtin/verification-usage.ts
|
|
@@ -14496,6 +14511,7 @@ function stripWorkflowOnlyOptions(options, defaultSessionDir, meta2, pendingStag
|
|
|
14496
14511
|
durableReplayKey: _durableReplayKey,
|
|
14497
14512
|
durableAccumulatedDurationMs: _durableAccumulatedDurationMs,
|
|
14498
14513
|
durableStageId: _durableStageId,
|
|
14514
|
+
durableIntercomGroup: _durableIntercomGroup,
|
|
14499
14515
|
durableParentIds: _durableParentIds,
|
|
14500
14516
|
sessionDir,
|
|
14501
14517
|
gitWorktreeDir: _gitWorktreeDir,
|
|
@@ -16618,15 +16634,18 @@ function createWorkflowStageFactory(input) {
|
|
|
16618
16634
|
const replaySource = replayDecision.kind === "replay" ? replayDecision.source : undefined;
|
|
16619
16635
|
const executeReplaySource = replayDecision.kind === "execute" ? replayDecision.source : undefined;
|
|
16620
16636
|
const shouldReplay = replaySource !== undefined;
|
|
16621
|
-
const
|
|
16637
|
+
const replayStageOptions = executeReplaySource?.sessionFile === undefined ? options : {
|
|
16622
16638
|
...options ?? {},
|
|
16623
16639
|
context: options?.context ?? "fork",
|
|
16624
16640
|
forkFromSessionFile: options?.forkFromSessionFile ?? executeReplaySource.sessionFile
|
|
16625
16641
|
};
|
|
16642
|
+
const intercomGroup = options?.durableIntercomGroup ?? resolveStageGroup(replayStageOptions, input.workflowIntercomGroup);
|
|
16643
|
+
const stageOptionsForContext = replayStageOptions?.group === undefined || intercomGroup === undefined ? replayStageOptions : { ...replayStageOptions, group: intercomGroup };
|
|
16626
16644
|
const pendingStageDeliveryAvailable = stageCanUseWorkflowPendingStageRoute(stageOptionsForContext, input.workflowIntercomGroup);
|
|
16627
16645
|
const stageSnapshot = {
|
|
16628
16646
|
id: stageId,
|
|
16629
16647
|
name,
|
|
16648
|
+
...intercomGroup === undefined ? {} : { intercomGroup },
|
|
16630
16649
|
replayKey,
|
|
16631
16650
|
status: shouldReplay ? "completed" : "pending",
|
|
16632
16651
|
parentIds: Object.freeze(parentIds),
|
|
@@ -16825,6 +16844,7 @@ function createWorkflowStageFactory(input) {
|
|
|
16825
16844
|
name,
|
|
16826
16845
|
parentIds: stageSnapshot.parentIds,
|
|
16827
16846
|
...stageReplayFields(stageSnapshot),
|
|
16847
|
+
...intercomGroup === undefined ? {} : { intercomGroup },
|
|
16828
16848
|
pendingStageDeliveryAvailable,
|
|
16829
16849
|
ts: stageSnapshot.startedAt ?? Date.now()
|
|
16830
16850
|
});
|
|
@@ -17506,11 +17526,16 @@ async function run(def, inputs, opts = {}) {
|
|
|
17506
17526
|
completedStageReplayKeys,
|
|
17507
17527
|
sourceToReplayedNodeIds: sourceToContinuationNodeIds
|
|
17508
17528
|
});
|
|
17529
|
+
const durableIntercomGroup = (replayKey, stageId) => {
|
|
17530
|
+
const stages = activeStore.runs().find((candidate) => candidate.id === runId)?.stages ?? [];
|
|
17531
|
+
return stages.find((stage) => stageId !== undefined && stage.id === stageId || stage.replayKey === replayKey)?.intercomGroup;
|
|
17532
|
+
};
|
|
17509
17533
|
let observedTaskTailQuit;
|
|
17510
17534
|
const durableTask = createDurableTaskPrimitive({
|
|
17511
17535
|
workflowId: runId,
|
|
17512
17536
|
backend: durableBackend,
|
|
17513
17537
|
nextReplayKey: (stageName) => stageReplayKeyGenerator(stageName),
|
|
17538
|
+
durableIntercomGroup,
|
|
17514
17539
|
task: taskRunners.task,
|
|
17515
17540
|
recordCachedTask: cachedStage.record,
|
|
17516
17541
|
signal: ownController.signal,
|
|
@@ -17559,6 +17584,7 @@ async function run(def, inputs, opts = {}) {
|
|
|
17559
17584
|
workflowId: runId,
|
|
17560
17585
|
backend: durableBackend,
|
|
17561
17586
|
nextReplayKey: (stageName) => stageReplayKeyGenerator(stageName),
|
|
17587
|
+
durableIntercomGroup,
|
|
17562
17588
|
recordCachedStage: cachedStage.record,
|
|
17563
17589
|
stage: (name, options, replayKey) => {
|
|
17564
17590
|
const stage = runtime.stage(name, options);
|
package/docs/intercom.md
CHANGED
|
@@ -153,7 +153,7 @@ Name sessions with `/name` so they can target each other (for example `/name pla
|
|
|
153
153
|
| `join` | Adds a trimmed named group membership and creates the group if needed. The action waits for broker acknowledgement and reports the complete resulting membership set. `default` is shared; `true` and `auto` are reserved for subagent auto-groups. |
|
|
154
154
|
| `leave` | With `group`, removes only that membership and keeps all others. Without `group`, resets the session to its resolved startup home group. Both forms report the resulting membership set. |
|
|
155
155
|
| `groups` | Lists every group represented by a connected session, with its session count and a marker for each group this session belongs to. Use it to discover names rather than guessing. |
|
|
156
|
-
| `list` |
|
|
156
|
+
| `list` | Returns the current session, every active session sharing at least one membership, and discoverable workflow stages. Workflow rows are explicitly labeled `PENDING` or `RUNNING` and include the canonical `<runId>:<stageId>` target. Pass `group` for a read-only view of one group. |
|
|
157
157
|
| `send` | Fire-and-forget delivery through ordinary Intercom. A live workflow-stage session receives the message immediately and returns `delivered`. A known workflow stage whose session has not initialized is addressed as `<runId>:<stageKey>`; Atomic persists the message and returns the distinct `queued` result with its FIFO position. Unknown stage identities retain the ordinary unknown-target failure. Requires `to` and `message`; cannot message the current session. |
|
|
158
158
|
| `ask` | Sends a message and blocks until a live recipient replies (10-minute timeout). An ask to a known workflow stage whose session has not initialized is refused with `pending_stage_ask_unsupported` and recommends ordinary `send`; holding a waiter until a stage eventually starts would be unbounded. A live recipient disconnect fails promptly. From a foreground child to its launching parent, the existing fresh-subagent handoff path remains unchanged. |
|
|
159
159
|
| `reply` | Replies to the intercom-triggered message of the current turn; otherwise falls back to the single unresolved inbound ask. With multiple pending asks, pass `to` or inspect with `pending` first. |
|
|
@@ -172,9 +172,9 @@ Sent and received messages are recorded in session history as `intercom_sent` /
|
|
|
172
172
|
|
|
173
173
|
### Targeting Sessions and Pending Workflow Stages
|
|
174
174
|
|
|
175
|
-
Live-session lookup accepts only an exact full session ID or an exact case-insensitive session name.
|
|
175
|
+
Live-session lookup accepts only an exact full Intercom session ID or an exact case-insensitive session name. Workflow stages use the canonical exact `<runId>:<stageId>` target printed by `intercom list` and workflow status surfaces; this target works while the row is `PENDING` and after it becomes `RUNNING`. Status surfaces label pending stages whose pre-start delivery capability is unavailable without presenting a usable target, and never advertise a retained pending stage after its run terminates. The `sessionId` shown by `workflow status` belongs to the workflow SDK and is **not** an Intercom target.
|
|
176
176
|
|
|
177
|
-
Before steering a stage,
|
|
177
|
+
Before steering a stage from the main chat, enter the workflow invocation context by joining `workflow:<rootRunId>` with `intercom({ action: "join", group: "workflow:<rootRunId>" })`; workflow-owned invocation sessions already start there. A member of that invocation group can list, `send` to, and live-`ask` exact stages in any invocation-owned subgroup (`workflow:<rootRunId>/<name>`), including intentionally isolated reviewer batches. This control is directional: a session registered as a subgroup stage cannot gain parent control by joining the invocation group, subgroup members cannot discover or reach sibling subgroups, and another workflow invocation remains refused. `PENDING` accepts queued `send` only; `RUNNING` accepts immediate `send` and correlated `ask`/`reply`.
|
|
178
178
|
|
|
179
179
|
### Deferred delivery to pending stages
|
|
180
180
|
|
|
@@ -182,7 +182,9 @@ Send material updates through Intercom to every affected workflow stage, includi
|
|
|
182
182
|
|
|
183
183
|
The workflows extension persists up to **50 queued messages per exact run/stage key** with workflow state. Messages survive resume/replay and broker restart, and logical message IDs prevent redelivery across stage-attempt restarts. When the stage session initializes, it receives the FIFO entries through the ordinary Intercom inbound path before its first model turn, under the heading **Messages received before you started**, with sender identity and `Sent:` timestamps visible separately from the task prompt.
|
|
184
184
|
|
|
185
|
-
Only a
|
|
185
|
+
Only a workflow invocation member with eligible invocation-control authority can queue to its invocation-owned stages; this includes a main-chat session that explicitly joined `workflow:<rootRunId>`. Subgroup peers and another root run remain refused even if they add that membership. An explicit stage `group: "default"` is a shared-group escape, is not workflow-owned, and does not receive pending invocation delivery. An ineligible attempt is refused with `Target workflow run is in a different intercom group`. The 51st queued message is refused with `Pending stage message queue is full (limit 50)` rather than evicting an earlier entry.
|
|
186
|
+
|
|
187
|
+
If the destination stage is skipped, the run terminates, or the stage becomes terminal before its session initializes, Atomic marks the queued message undeliverable and sends the correlated failure notification when acknowledgment was requested. Blocking `ask` is deliberately unsupported before initialization: use ordinary `send`, because a stage may start much later or never start.
|
|
186
188
|
|
|
187
189
|
### Groups
|
|
188
190
|
|
|
@@ -193,7 +195,7 @@ Every session belongs to a non-empty set of intercom **groups**. Sessions with n
|
|
|
193
195
|
- `join` adds one membership. `leave` removes the named membership, while bare `leave` resets the complete set to the startup home group.
|
|
194
196
|
- `status` reports the complete membership set. `session_joined`/`session_left`/`presence_update` events are delivered whenever a membership change affects visibility.
|
|
195
197
|
|
|
196
|
-
A session's home group is resolved with this precedence: explicit stage/task/subagent group > runtime-owned workflow invocation group or inherited launching-session group > env `ATOMIC_INTERCOM_GROUP` (legacy `PI_INTERCOM_GROUP`) > Intercom `config.json` `"group"` > `"default"`.
|
|
198
|
+
A session's home group is resolved with this precedence: explicit stage/task/subagent group > runtime-owned workflow invocation group or inherited launching-session group > env `ATOMIC_INTERCOM_GROUP` (legacy `PI_INTERCOM_GROUP`) > Intercom `config.json` `"group"` > `"default"`. Workflow stage named groups and `group: true` are namespaced under `workflow:<rootRunId>/...`, preventing cross-run collisions while preserving sibling isolation. `group: "default"` remains the explicit non-owned escape. The invocation group has asymmetric exact-target control over its owned subgroups; ownership does not grant reverse or lateral access.
|
|
197
199
|
|
|
198
200
|
The broker, not the client, marks validated supervisor traffic. Ordinary `send` frames remain membership-isolated even if a raw client forges a supervisor marker, and replies cross back only through an exact broker-recorded `replyTo` match. Parent-held authorization state is restored after reconnects. Before an Intercom-enabled foreground child first runs, the parent wrapper may lazy-load and connect the broker provider to mint that exact child's capability; queued children request no capability. The child still connects only when it uses an Intercom delivery path, and claimed decisions or interviews terminally hand off before child send or waiter admission. A claimed provider failure aborts launch, while runtimes with no provider omit supervisor metadata and do not expose a broken channel.
|
|
199
201
|
|
|
@@ -8,7 +8,7 @@ description: "The external benchmarks that inform Atomic model selection — Art
|
|
|
8
8
|
Atomic's model-selection docs are keyed to two live external benchmark sources rather than a hand-maintained table of scores. This page lists each benchmark, what it measures, and **when to reference it** for a given workflow role — so the docs stay useful as new models ship without a manual rewrite every time.
|
|
9
9
|
|
|
10
10
|
<Warning>
|
|
11
|
-
No single benchmark is the source of truth. Use these as inputs and validate against Atomic's own workflow evals — public suites test different task distributions than real engineering loops. When Atomic's numbers disagree with a public index, Atomic's evals win. **Last reviewed: 2026-
|
|
11
|
+
No single benchmark is the source of truth. Use these as inputs and validate against Atomic's own workflow evals — public suites test different task distributions than real engineering loops. When Atomic's numbers disagree with a public index, Atomic's evals win. The DeepSWE snapshot used by the linked model-selection pages was updated August 26, 2026. **Last reviewed: 2026-09-01.**
|
|
12
12
|
</Warning>
|
|
13
13
|
|
|
14
14
|
## The two sources at a glance
|
|
@@ -22,6 +22,7 @@ No single benchmark is the source of truth. Use these as inputs and validate aga
|
|
|
22
22
|
|
|
23
23
|
DeepSWE is the closest public proxy for what Atomic actually does. Tasks are written from scratch (not scraped from PRs), so no model has seen the solutions; solutions require substantially more code than SWE-bench-style suites; and verifiers test behavior rather than implementation.
|
|
24
24
|
|
|
25
|
+
- **Current snapshot:** DeepSWE v1.1, 113 tasks across 91 repositories and 5 languages, updated August 26, 2026. The site reports 26 measured models and displays 19 leaderboard rows.
|
|
25
26
|
- **Metric:** `pass@1`, plus average cost per task, output tokens, and agent steps.
|
|
26
27
|
- **When to reference:** default weighting for debugger, worker, and any code-writing role. This is the table that drives [Model Selection](/models/model-selection) and [Pareto Efficiency](/models/pareto-efficiency).
|
|
27
28
|
- **Watch:** cost and step count, not just score — a model that passes but takes 268 steps (e.g. sonnet-5) is a poor worker even at a good pass rate.
|
|
@@ -14,7 +14,7 @@ This page gives workflow authors and runtime policy code a practical way to answ
|
|
|
14
14
|
It is a **static reference**. It does not change runtime model routing — routing is configured elsewhere. Treat these recommendations as a starting point and validate against your own workflow evals.
|
|
15
15
|
|
|
16
16
|
<Note>
|
|
17
|
-
The table below is a snapshot of the [DeepSWE](https://deepswe.datacurve.ai/) leaderboard (v1.1, highest published thinking level per model), a long-horizon coding-agent benchmark reporting `pass@1` and average dollars per task. Benchmarks and pricing drift and new models ship constantly, so **treat the live leaderboards as authoritative** and refresh this page from them rather than hand-maintaining scores. See [Benchmark sources & when to reference each](/models/artificial-analysis-index). **Last compiled: 2026-
|
|
17
|
+
The table below is a snapshot of the [DeepSWE](https://deepswe.datacurve.ai/) leaderboard (v1.1, highest published thinking level per model), a long-horizon coding-agent benchmark reporting `pass@1` and average dollars per task. The source reports 113 tasks and was updated August 26, 2026. Benchmarks and pricing drift and new models ship constantly, so **treat the live leaderboards as authoritative** and refresh this page from them rather than hand-maintaining scores. See [Benchmark sources & when to reference each](/models/artificial-analysis-index). **Last compiled: 2026-09-01.**
|
|
18
18
|
</Note>
|
|
19
19
|
|
|
20
20
|
## Benchmark levels are measurement settings
|
|
@@ -30,38 +30,39 @@ reports the ambiguity. Use `--provider <provider> --model <id>` or `--model <pro
|
|
|
30
30
|
|
|
31
31
|
## Recommendation chart
|
|
32
32
|
|
|
33
|
-
The current highest-effort-config Pareto frontier is **claude-opus-5** (accuracy ceiling), **gpt-5.6-sol**, **glm-5.3**, **gpt-5.6-luna**,
|
|
33
|
+
The current highest-effort-config Pareto frontier is **claude-opus-5** (accuracy ceiling), **gpt-5.6-sol**, **glm-5.3**, **gpt-5.6-luna**, and **glm-5.3-flash** (cheapest point). Everything else displayed on the live DeepSWE leaderboard is dominated on cost and accuracy and earns a place only through role fit or provider diversity. For the frontier reasoning, see [Pareto Efficiency](/models/pareto-efficiency).
|
|
34
34
|
|
|
35
35
|
| Model [benchmark measurement level] | pass@1 | $/task | Verdict | Use it for |
|
|
36
36
|
| --- | --- | --- | --- | --- |
|
|
37
37
|
| claude-opus-5 [max] | 74% | $11.84 | Accuracy ceiling / frontier | Final approval and the hardest debugging when one more point can justify the cost |
|
|
38
|
-
| gpt-5.6-sol [max] | 73% | $
|
|
39
|
-
| gpt-5.6-terra [max] | 70% | $3.96 |
|
|
38
|
+
| gpt-5.6-sol [max] | 73% | $6.46 | Frontier | High-cost judgment gates; nearly the top score for about half the task cost of Opus 5 |
|
|
39
|
+
| gpt-5.6-terra [max] | 70% | $3.96 | Historical — off the live board | Last published measurement; not displayed on the August 26 leaderboard, so re-verify before relying on it |
|
|
40
40
|
| claude-fable-5 [max] | 70% | $21.63 | Drop | Sol matches or beats its score for much less |
|
|
41
|
-
| glm-5.3 [max] | 69% | $3.99 | Frontier — open-weights value | Best open-weights cost/accuracy point; matches Kimi K3's rounded score for less |
|
|
41
|
+
| glm-5.3 [max] | 69% | $3.99 | Frontier — open-weights value | Best open-weights mid-tier cost/accuracy point; matches Kimi K3's rounded score for less |
|
|
42
42
|
| kimi-k3 [max] | 69% | $4.65 | Dominated | GLM-5.3 matches its rounded score for $0.66 less; Moonshot-family diversity only |
|
|
43
43
|
| gpt-5.6-luna [max] | 67% | $0.61 | Frontier — best general value | Research, orchestration, workers, and code simplification |
|
|
44
44
|
| gpt-5.5 [xhigh] | 67% | $7.23 | Superseded | Luna matches its score for less than one tenth of the task cost |
|
|
45
45
|
| grok-4.6 [xhigh] | 67% | $5.50 | Provider fallback | xAI diversity; Luna has the same rounded score at lower DeepSWE task cost |
|
|
46
46
|
| gemini-3.7-flash [high] | 65% | $2.18 | Provider fallback | Strong Google-family result, but Luna is cheaper and more accurate |
|
|
47
|
-
|
|
|
47
|
+
| glm-5.3-flash [max] | 63% | $0.24 | Frontier — cheapest | Budget worker loops that can accept lower accuracy and 123 average steps |
|
|
48
|
+
| deepseek-v4-pro [max] | 63% | $1.67 | Dominated / provider fallback | DeepSeek diversity only; GLM-5.3 Flash has a higher unrounded score, fewer steps, and about one seventh of the cost |
|
|
48
49
|
| claude-opus-4.8 [max] | 59% | $13.22 | Fallback only | Anthropic diversity and long-context behavior, not cost efficiency |
|
|
49
|
-
| qwen3.8-max [xhigh] | 57% | $3.73 | Provider fallback | Qwen diversity only;
|
|
50
|
-
| muse-spark-1.2 [xhigh] | 55% | $3.70 | Drop |
|
|
50
|
+
| qwen3.8-max [xhigh] | 57% | $3.73 | Provider fallback | Qwen diversity only; GLM-5.3 Flash and Luna dominate it |
|
|
51
|
+
| muse-spark-1.2 [xhigh] | 55% | $3.70 | Drop | GLM-5.3 Flash is cheaper and more accurate |
|
|
51
52
|
| claude-sonnet-5 [max] | 54% | $26.40 | Drop everywhere | Highest task cost and 268 average steps for a mid-table score |
|
|
52
|
-
| grok-4.5 [high] | 54% | $2.42 |
|
|
53
|
-
| deepseek-v4-flash [max] | 53% | $0.
|
|
54
|
-
| muse-spark-1.1 [xhigh] | 53% | $2.36 |
|
|
55
|
-
| gpt-5.4 [xhigh] | 52% | $5.65 |
|
|
53
|
+
| grok-4.5 [high] | 54% | $2.42 | Historical — off the live board | Last published measurement; superseded by Grok 4.6 and dominated by current frontier models |
|
|
54
|
+
| deepseek-v4-flash [max] | 53% | $0.46 | Dominated / provider fallback | DeepSeek diversity only; GLM-5.3 Flash is ten points more accurate for about half the cost |
|
|
55
|
+
| muse-spark-1.1 [xhigh] | 53% | $2.36 | Historical — off the live board | Last published measurement; replaced by Muse Spark 1.2 and dominated by current frontier models |
|
|
56
|
+
| gpt-5.4 [xhigh] | 52% | $5.65 | Historical — off the live board | Last published measurement; Luna is cheaper and 15 points more accurate |
|
|
56
57
|
| gemini-3.6-flash [high] | 47% | $2.21 | Drop from reasoning | Superseded by Gemini 3.7 Flash |
|
|
57
58
|
| glm-5.2 [max] | 44% | $3.92 | Superseded | Measured predecessor only; do not relabel this as GLM-5.3 |
|
|
58
59
|
| gemini-3.5-flash [high] | 36% | $3.45 | Drop from reasoning | Retain only where a low-effort retrieval role has separate evidence |
|
|
59
|
-
| kimi-k2.7-code
|
|
60
|
-
| claude-sonnet-4.6 [high] | 30% | $5.52 |
|
|
61
|
-
| gemini-3.1-pro [high] | 12% | $2.14 |
|
|
60
|
+
| kimi-k2.7-code | 31% | $2.82 | Historical — off the live board | Last published measurement had no effort level; Kimi K3 is the current family fallback |
|
|
61
|
+
| claude-sonnet-4.6 [high] | 30% | $5.52 | Historical — off the live board | Last published measurement; removed from all chains |
|
|
62
|
+
| gemini-3.1-pro-preview [high] | 12% | $2.14 | Historical — off the live board | Last published measurement; removed from all chains |
|
|
62
63
|
|
|
63
64
|
<Note>
|
|
64
|
-
DeepSWE values above use the v1.1 results
|
|
65
|
+
DeepSWE values above use the v1.1 results displayed on the August 26, 2026 leaderboard, including the August 21 pricing corrections for GPT-5.6 Sol and DeepSeek V4. Sol's cost reflects OpenAI's promotional input and output price cut through at least November 21, 2026. DeepSWE uses DeepSeek's peak rates; its off-peak rates are half as much. `pass@1` is rounded as on the live leaderboard and confidence intervals are omitted here. The highest published thinking level is a measurement choice, not a production default. Seven historical configurations are retained with their last published values because they are no longer displayed: GPT-5.6 Terra, Grok 4.5, Muse Spark 1.1, GPT-5.4, Kimi K2.7 Code, Claude Sonnet 4.6, and Gemini 3.1 Pro Preview. See the live page for intervals, output tokens, steps, lower-effort configurations, and later corrections.
|
|
65
66
|
</Note>
|
|
66
67
|
|
|
67
68
|
## Role-based thinking effort
|
|
@@ -82,10 +83,10 @@ Reserve `max` for a high-cost-of-error role or an explicit user request. An expl
|
|
|
82
83
|
Pick by the cost of being wrong in each role, not by raw accuracy. Match the role to the benchmark that best measures it (see [Benchmark sources](/models/artificial-analysis-index)).
|
|
83
84
|
|
|
84
85
|
- **Reviewer / judgment gates** — use `max` when the reviewer makes a security, identity, adversarial, or final-approval decision whose wrong verdict discards an entire loop. `claude-opus-5` is the DeepSWE accuracy ceiling; `gpt-5.6-sol` is the lower-cost near-peer. Use another family when decorrelated errors matter.
|
|
85
|
-
- **Codebase mapping / planner** — start at `high` for repository mapping, lifecycle analysis, compatibility, and plans. `gpt-5.6-sol` is the strongest top-tier value at its measured `max` configuration, and `glm-5.3`
|
|
86
|
+
- **Codebase mapping / planner** — start at `high` for repository mapping, lifecycle analysis, compatibility, and plans. `gpt-5.6-sol` is the strongest top-tier value at its measured `max` configuration, and `glm-5.3` holds the open-weights mid tier; raise production effort to `max` only when the plan gates a high-cost loop or the user asks for it.
|
|
86
87
|
- **Debugger / triage / repair** — start at `high`; deep reasoning pays off when root-causing or repairing is costly. Weight DeepSWE and Terminal-Bench together rather than treating either as a complete measure.
|
|
87
88
|
- **Research / synthesis** — use `high` for demanding research and evidence reconciliation; use `medium` for routine synthesis when the evidence is already strong. `gpt-5.6-luna` remains the workhorse. Benchmark to weight: AA-LCR and AA-Omniscience.
|
|
88
|
-
- **Orchestrator / worker / cheap loops** — Luna offers the best broad cost/accuracy balance.
|
|
89
|
+
- **Orchestrator / worker / cheap loops** — Luna offers the best broad cost/accuracy balance. GLM-5.3 Flash is the cheapest live frontier point at 63% for $0.24 with 123 average steps. DeepSeek V4 Pro and Flash are provider-diversity options, not budget-frontier choices.
|
|
89
90
|
- **User-impact review / final reporting** — use `medium` for impact summaries and reports that preserve the evidence needed by the user. Do not spend `max` here unless the user explicitly requests it or the role has become a high-cost-of-error approval.
|
|
90
91
|
- **Design** — a quality-first, unbenchmarked domain; keep a top-tier model (`gpt-5.6-sol` or `claude-fable-5`) when the design decision has high failure cost, and choose effort by the review or approval role rather than by the benchmark row.
|
|
91
92
|
- **Interactive coding sessions** — use `high` for complex, multi-step coding and `medium` for routine edits; reserve `max` for a high-cost-of-error judgment or an explicit user request.
|
|
@@ -5,58 +5,65 @@ description: "Cost-vs-accuracy frontier for model selection: which models domina
|
|
|
5
5
|
|
|
6
6
|
# Pareto Efficiency
|
|
7
7
|
|
|
8
|
-
A model is **Pareto-efficient** (on the frontier) if no other model is both cheaper and more accurate. Everything not on the frontier is **dominated
|
|
8
|
+
A model is **Pareto-efficient** (on the frontier) if no other model is both cheaper and more accurate. Everything not on the frontier is **dominated**: some other option matches or beats it on accuracy for less money. Avoid a dominated model unless it earns a slot through a specific role fit or provider diversity.
|
|
9
9
|
|
|
10
10
|
The axes here are `pass@1` (accuracy) and `average dollars per task` (cost), taken from the [DeepSWE](https://deepswe.datacurve.ai/) coding-agent leaderboard. For the full table and role guidance, see [Model Selection](/models/model-selection).
|
|
11
11
|
|
|
12
12
|
<Note>
|
|
13
|
-
Figures are a snapshot of DeepSWE v1.1 using the highest published thinking level
|
|
13
|
+
Figures are a snapshot of DeepSWE v1.1 using the highest published thinking level for each of the 19 models displayed on the August 26, 2026 leaderboard. They include the August 21 pricing corrections for GPT-5.6 Sol and DeepSeek V4. DeepSWE publishes a live cost-vs-score scatter, so **read the frontier off the live chart** rather than trusting a static list. **Last compiled: 2026-09-01.**
|
|
14
14
|
</Note>
|
|
15
15
|
|
|
16
16
|
## The frontier
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Five displayed highest-effort model configurations sit on the frontier, from the cheapest measured task cost to the accuracy ceiling:
|
|
19
19
|
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **claude-opus-5 [max]** — 74% for $11.84. The current accuracy ceiling.
|
|
20
|
+
- **glm-5.3-flash [max]**: 63% for $0.24 with 123 average steps. This is the cheapest point.
|
|
21
|
+
- **gpt-5.6-luna [max]**: 67% for $0.61. This is the best broad value on the board.
|
|
22
|
+
- **glm-5.3 [max]**: 69% for $3.99 with 124 average steps. This is the open-weights mid-tier point and matches Kimi K3's rounded score for less.
|
|
23
|
+
- **gpt-5.6-sol [max]**: 73% for $6.46 with 61 average steps. This is the lower-cost near-peer to the accuracy leader.
|
|
24
|
+
- **claude-opus-5 [max]**: 74% for $11.84 with 99 average steps. This is the current accuracy ceiling.
|
|
26
25
|
|
|
27
|
-
## What changed
|
|
26
|
+
## What changed
|
|
28
27
|
|
|
29
|
-
The August
|
|
28
|
+
The August 26 snapshot moves the budget end of the frontier and lowers the cost of its upper end:
|
|
30
29
|
|
|
31
|
-
- **GLM-5.3 [max]**
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
30
|
+
- **GLM-5.3 Flash [max]** now appears at 63% for $0.24 with 123 average steps. It replaces both DeepSeek V4 configurations on the budget frontier.
|
|
31
|
+
- **DeepSeek V4 Pro [max]** now costs $1.67 per task after DeepSeek's August 16 price change. GLM-5.3 Flash has a higher unrounded score (63.4% versus 62.8%), costs about one seventh as much, and averages 32 fewer steps.
|
|
32
|
+
- **DeepSeek V4 Flash [max]** now costs $0.46 per task. GLM-5.3 Flash is ten rounded points more accurate and costs about half as much.
|
|
33
|
+
- **GPT-5.6 Sol [max]** now costs $6.46 per task after OpenAI's August 20 promotional price cut, down from $8.39 in the previous snapshot. The reduced input and output rates run through at least November 21, 2026.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
DeepSWE's August 21, 2026 changelog says these DeepSeek costs use peak rates and off-peak rates are half as much. DeepSeek V4 Pro remains dominated at either rate. At the off-peak rate, DeepSeek V4 Flash costs about $0.23, marginally less than GLM-5.3 Flash's $0.24, but remains ten rounded points less accurate; these pages report the frontier from DeepSWE's published peak-rate costs.
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- **
|
|
40
|
-
- **
|
|
41
|
-
- **
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
37
|
+
## Dominated models and why
|
|
38
|
+
|
|
39
|
+
- **deepseek-v4-pro [max]**: GLM-5.3 Flash has a higher unrounded score, costs $1.43 less, and averages 123 steps instead of 155.
|
|
40
|
+
- **deepseek-v4-flash [max]**: GLM-5.3 Flash is ten rounded points more accurate and costs $0.22 less.
|
|
41
|
+
- **claude-fable-5 [max]**: Sol is more accurate and much cheaper; GLM-5.3 comes within a point for less than one fifth of the task cost.
|
|
42
|
+
- **kimi-k3 [max]**: GLM-5.3 matches its rounded score and is $0.66 cheaper; Kimi remains useful for Moonshot-family diversity.
|
|
43
|
+
- **gpt-5.5 [xhigh]** and **grok-4.6 [xhigh]**: Luna matches their rounded 67% for $0.61.
|
|
44
|
+
- **gemini-3.7-flash [high]**: Luna is two points more accurate and costs less than one third as much.
|
|
45
|
+
- **muse-spark-1.2 [xhigh]**: GLM-5.3 Flash is eight points more accurate and costs $3.46 less.
|
|
46
|
+
- **claude-opus-4.8 [max]** and **claude-sonnet-5 [max]**: each is dominated on both cost and accuracy.
|
|
47
|
+
- **qwen3.8-max [xhigh]**, **gemini-3.6-flash [high]**, **gemini-3.5-flash [high]**, and **glm-5.2 [max]**: each has a cheaper, more accurate displayed alternative.
|
|
48
|
+
|
|
49
|
+
Seven measured configurations are no longer displayed on the live leaderboard and are excluded from this current frontier calculation. [Model Selection](/models/model-selection) keeps their last published values as clearly labeled history: GPT-5.6 Terra, Grok 4.5, Muse Spark 1.1, GPT-5.4, Kimi K2.7 Code, Claude Sonnet 4.6, and Gemini 3.1 Pro Preview.
|
|
44
50
|
|
|
45
51
|
## Diversity and role-fit exceptions
|
|
46
52
|
|
|
47
53
|
Efficiency is not the only axis. A dominated model can still earn a slot when it decorrelates errors or fills a niche:
|
|
48
54
|
|
|
49
|
-
- **
|
|
50
|
-
- **
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
53
|
-
- **claude-
|
|
54
|
-
- **
|
|
55
|
+
- **deepseek-v4-pro** and **deepseek-v4-flash** remain DeepSeek provider-diversity options, not budget-frontier choices.
|
|
56
|
+
- **grok-4.6** remains the operational xAI and OpenRouter provider-diversity fallback.
|
|
57
|
+
- **glm-5.2 [max]** remains only as a measured predecessor; its results are never relabeled as GLM-5.3 or GLM-5.3 Flash.
|
|
58
|
+
- **kimi-k3** remains a Moonshot-family provider-diversity option despite GLM-5.3's strict DeepSWE dominance.
|
|
59
|
+
- **claude-opus-4.8 [max]** remains useful where Anthropic diversity or its long-context behavior has separate value.
|
|
60
|
+
- **claude-fable-5** remains useful where Anthropic-family behavior is specifically wanted, such as the quality-first, unbenchmarked design chain.
|
|
61
|
+
- **Unmeasured models** may remain operational defaults when a family lacks current DeepSWE or Artificial Analysis coverage, but they should not inherit a predecessor's score.
|
|
55
62
|
|
|
56
63
|
## How to use this
|
|
57
64
|
|
|
58
65
|
1. Default to a frontier model for the role's accuracy needs (see [Model Selection](/models/model-selection)).
|
|
59
|
-
2. Only reach for a dominated model when you have an explicit reason
|
|
66
|
+
2. Only reach for a dominated model when you have an explicit reason, such as provider diversity, a long-context or token-price niche, or an unbenchmarked domain like design.
|
|
60
67
|
3. Re-read the frontier off the [DeepSWE live chart](https://deepswe.datacurve.ai/) when prices or benchmarks change, and update the timestamp on these pages.
|
|
61
68
|
|
|
62
69
|
## Related
|
package/docs/workflows.md
CHANGED
|
@@ -116,7 +116,7 @@ Named workflow runs execute in the background. By default, after launch expect a
|
|
|
116
116
|
|
|
117
117
|
For a request with several implementation items, do not turn list order into one serial workflow by default. Triage dependencies first, then launch independent items as a bounded wave of separate top-level runs; see [Task queues and software factories](#task-queues-and-software-factories).
|
|
118
118
|
|
|
119
|
-
While a workflow is running, the visible below-editor `BACKGROUND` panel advances its elapsed label every second from the moment the run starts; it does not require opening or switching to the orchestrator. Updates repaint the existing mounted panel in place, paused timers stay frozen, the panel renders every qualifying top-level run, and terminal or quit cards retain their brief recent-run expiry. A zero-stage workflow whose work consists only of `ctx.tool(...)` calls mounts the same panel without a synthetic stage: at normal widths its run metadata reports the live-tool total when more than one is active, followed by pending and running durable tool-node names and statuses as space permits; the collapsed narrow form reports only the number of live tools. Quit cards remain resumable and discoverable with `/workflow status` after they leave the panel. A run waiting for human input uses the blue `?` indicator in the BACKGROUND panel, the `/workflow connect` picker, and the `/workflow status` listing; answering or cancelling the prompt restores the run's current indicator.
|
|
119
|
+
While a workflow is running, the visible below-editor `BACKGROUND` panel advances its elapsed label every second from the moment the run starts; it does not require opening or switching to the orchestrator. Updates repaint the existing mounted panel in place, paused timers stay frozen, the panel renders every qualifying top-level run, and terminal or quit cards retain their brief recent-run expiry. At normal widths the panel names materialized pending stages with canonical stage IDs and exact Intercom targets when pre-start delivery is available; unavailable delivery is labeled instead of implying steerability. An exact target is never partially truncated: the panel uses only pending-stage forms that fit the metadata-row budget, and omits the pending label entirely when none fit so existing live-tool and elapsed/status metadata is not displaced. The narrow form remains aggregate-only. A zero-stage workflow whose work consists only of `ctx.tool(...)` calls mounts the same panel without a synthetic stage: at normal widths its run metadata reports the live-tool total when more than one is active, followed by pending and running durable tool-node names and statuses as space permits; the collapsed narrow form reports only the number of live tools. Quit cards remain resumable and discoverable with `/workflow status` after they leave the panel. A run waiting for human input uses the blue `?` indicator in the BACKGROUND panel, the `/workflow connect` picker, and the `/workflow status` listing; answering or cancelling the prompt restores the run's current indicator.
|
|
120
120
|
|
|
121
121
|
### Workflow run identifiers and the BACKGROUND panel
|
|
122
122
|
|
|
@@ -126,7 +126,7 @@ Stage targeting is exact but not UUID-bound, because stage identifiers are not a
|
|
|
126
126
|
|
|
127
127
|
#### Intercom delivery to pending workflow stages
|
|
128
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.
|
|
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 while that run can still reach the stage. Model-facing `workflow status` and interactive status list/detail surfaces proactively enumerate materialized pending stages by display name and canonical stage ID. They print the exact `<runId>:<stageId>` target only when `pendingStageDeliveryAvailable` is true and the stage's owning run is nonterminal, and label delivery unavailable otherwise; an ended root or nested child run never advertises a retained pending stage as steerable through a projected parent. Duplicate display names therefore remain independently identifiable without overstating capability. Run `intercom({ action: "list" })` from the invocation context to discover materialized stages: each live route appears as `PENDING` or `RUNNING` with its canonical target. Note that the `sessionId` reported by `workflow status` is an SDK session id and is **not** an Intercom target. From a session in the workflow invocation group — including a main chat that explicitly joined `workflow:<rootRunId>` — use ordinary Intercom delivery:
|
|
130
130
|
|
|
131
131
|
```ts
|
|
132
132
|
intercom({
|
|
@@ -141,12 +141,12 @@ Send material updates through Intercom to every affected workflow stage, includi
|
|
|
141
141
|
|
|
142
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
143
|
|
|
144
|
-
If the destination is skipped, the run
|
|
144
|
+
If the destination is skipped, the run terminates, 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
145
|
|
|
146
146
|
|
|
147
|
-
At 80 columns and wider, each `BACKGROUND` card
|
|
147
|
+
At 80 columns and wider, each `BACKGROUND` card keeps the full run identity and preserves its mode, progress, live-tool details, and elapsed/status metadata. When the remaining single-row budget permits, it adds bounded pending-stage details: a target is either shown exactly or replaced by a `stage`-labeled canonical ID, and `… N more` reports omitted pending stages. If no bounded pending-stage form fits, the pending label is omitted entirely rather than displacing the existing metadata. Tool nodes are read-only durable graph nodes, not attachable stage chats. Below 80 columns, the panel keeps its aggregate collapsed form and omits run IDs, stage identities, targets, and tool names.
|
|
148
148
|
|
|
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.
|
|
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. Pending-stage targets in run detail use the same rule: the exact address wraps instead of being ellipsized, and narrow status cards wrap the canonical stage ID or drop its display-name decoration rather than rendering a partial ID. The renderer 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.
|
|
150
150
|
|
|
151
151
|
The `/workflow connect` run picker shows five runs at a time; use the arrow keys or mouse wheel to scroll through additional retained runs.
|
|
152
152
|
|
|
@@ -984,7 +984,7 @@ Author workflows to create at least one tracked execution node by calling `ctx.t
|
|
|
984
984
|
|
|
985
985
|
### Source layout for authored workflows
|
|
986
986
|
|
|
987
|
-
Keep a small, readable workflow in one entry file.
|
|
987
|
+
Keep a small, readable workflow in one entry file and write it for human maintainers. Keep the graph and control flow visible in the top-level workflow entry file, use stage names that state each stage's responsibility, and make its inputs, outputs, evidence, and success contract explicit. A developer reading the entry file from top to bottom should be able to identify the graph, branches, gates, artifacts, and stop conditions. Avoid both monolithic prompt blobs and gratuitous fragmentation: do not split short one-use prompts, create one file per stage, add wrapper-only modules, hide the graph across files, or use line counts alone as a module boundary.
|
|
988
988
|
|
|
989
989
|
When a meaningful source boundary improves clarity, reuse, ownership, or testability, keep the graph and control flow in the top-level workflow entry file and extract cohesive concerns:
|
|
990
990
|
|
|
@@ -1007,6 +1007,12 @@ The repository uses this shape in `.atomic/workflows/release-docs.ts`: the entry
|
|
|
1007
1007
|
|
|
1008
1008
|
The subdirectory is for cohesive, reusable support code, not a requirement to give every prompt or stage its own file.
|
|
1009
1009
|
|
|
1010
|
+
### Workflow and extension responsibilities
|
|
1011
|
+
|
|
1012
|
+
Evaluate Atomic extension hooks when a workflow needs fine-grained, cross-cutting tool or session event control. Workflow TypeScript owns the inspectable DAG, stages, handoffs, durable `ctx.tool` side effects, and gates. Extension hooks own cross-cutting session and model-tool policy such as `tool_call` interception, input mutation, or blocking; `tool_result` transformation; context and provider hooks; lifecycle observation; or reusable custom tools. Use hooks only when cross-stage or cross-workflow event control is materially clearer than embedding the policy in each stage. Do not require a companion extension for ordinary workflow logic. See the authoritative [extension event documentation](/extensions#events) for hook contracts and ordering.
|
|
1013
|
+
|
|
1014
|
+
When a workflow depends on a companion extension, make that dependency explicit and package and document the extension with the workflow. If stages use `tools` allowlists, include any custom tools provided by the extension. Document the hook-driven behavior and keep the graph, stage contracts, artifacts, gates, and stop conditions visible in the workflow entry file so readers can distinguish inspectable workflow orchestration from event policy.
|
|
1015
|
+
|
|
1010
1016
|
### Dynamic topology must remain acyclic
|
|
1011
1017
|
|
|
1012
1018
|
Atomic `workflow({ run })` definitions are imperative, dynamic TypeScript. The final graph is materialized only while `run(ctx)` executes and may depend on runtime inputs, branches, loops, files or network data, model or human output, helpers, and nested workflows. Discovery can report module import and definition-shape diagnostics: it loads the module, checks its exports, schemas, and `run` function, and rejects failures observable at that point. It does not execute every control-flow path or compile `run` into a complete graph. TypeScript and discovery cannot prove arbitrary dynamic acyclicity.
|
|
@@ -1579,7 +1585,7 @@ Ordinary `intercom` is mandatory in every workflow model stage. `noTools: "all"`
|
|
|
1579
1585
|
- Never make a guard watch itself, recursively start another guard, reopen a terminal task, or add a dependency from the current frontier to an ancestor. Complete all turns on a retained guard before starting downstream dependency work.
|
|
1580
1586
|
- Messages admitted before a worker generation closes drain through that stage boundary. Late messages do not reopen or mutate its terminal workflow state. Give each live branch a bounded stop rule; `ctx.parallel(...)` releases downstream work only after all started branches settle, even when one finishes first.
|
|
1581
1587
|
- Persist decisions under stable keys. Pause/resume, model fallback, durable replay, and nested workflows then reread the artifact instead of sending duplicate interventions.
|
|
1582
|
-
- Omit `group` for ordinary use. The worker, guard, nested workflows, and delegated subagents inherit the top-level workflow invocation's stable Intercom group. Set an explicit group only for intentional isolation; an override
|
|
1588
|
+
- Omit `group` for ordinary use. The worker, guard, nested workflows, and delegated subagents inherit the top-level workflow invocation's stable Intercom group. Set an explicit group only for intentional isolation; an override isolates that stage from ordinary same-group peers while leaving it steerable from the invocation context, which retains directional list/send/live-ask control over the subgroups it owns.
|
|
1583
1589
|
- Use `context: "fresh"` for guards, reviewers, and judges. They should see only the contract, candidate, decision artifacts, and current files.
|
|
1584
1590
|
- Use `context: "fork"` plus `forkFromSessionFile` for implementation, debugging, and repair roles that need continuity with an owned earlier session. `context: "fork"` alone does not name a fork source; an initial worker with no prior lineage may start fresh. A later continuation should use the earlier worker's `sessionFile` when available. Do not fork an independent guard from the worker it judges.
|
|
1585
1591
|
- Send a forked continuation only the delta after the fork point: new evidence, the decision artifact, any human answer, and the next action. Keep the full shared contract in its canonical file.
|
|
@@ -2423,9 +2429,9 @@ readonly group?: string | true;
|
|
|
2423
2429
|
|
|
2424
2430
|
Sets the stage session's [Intercom](/intercom) home group. Every top-level workflow invocation receives a stable, non-`"default"` runtime group derived from its persistent run identity. Intercom-capable stages inherit that group when `group` is omitted, including stages in nested workflows. The group stays stable across model fallback, pause/resume, and durable replay, while separate top-level invocations receive different groups.
|
|
2425
2431
|
|
|
2426
|
-
`group` is accepted on `stage`/`task` options, on `ctx.parallel(...)` options, and per parallel step. Explicit values override the workflow invocation group; a step-level value also overrides its parallel-set value. A named string
|
|
2432
|
+
`group` is accepted on `stage`/`task` options, on `ctx.parallel(...)` options, and per parallel step. Explicit values override the workflow invocation group; a step-level value also overrides its parallel-set value. A named string becomes an **invocation-owned subgroup** resolved to `workflow:<rootRunId>/<name>`, so the same authored name in two concurrent runs never collides. Boolean `true` auto-generates one shared UUID group **per `ctx.parallel(...)` set** (minted once for every item in that set) and is namespaced the same way, while `true` on a non-parallel stage creates a fresh stage-only subgroup. The trimmed, case-insensitive string sentinels `"true"` and `"auto"` have the same automatic behavior and are reserved. `group: "default"` is the one exception: it opts into the shared default group, is **not** invocation-owned, and does not receive pending invocation delivery.
|
|
2427
2433
|
|
|
2428
|
-
The full precedence is: explicit stage/task/parallel group > workflow invocation group > `ATOMIC_INTERCOM_GROUP` (or legacy `PI_INTERCOM_GROUP`) > Intercom config > `"default"`. Every workflow model stage receives its workflow invocation group because ordinary Intercom is mandatory. Tool restrictions do not suppress that group; explicit `group` values retain their existing precedence. Subagents inherit their launching stage's resolved group by default (see [subagents.md](/subagents)). The subagent-only `contact_supervisor` channel keeps its broker-authorized cross-group route
|
|
2434
|
+
The full precedence is: explicit stage/task/parallel group > workflow invocation group > `ATOMIC_INTERCOM_GROUP` (or legacy `PI_INTERCOM_GROUP`) > Intercom config > `"default"`. Every workflow model stage receives its workflow invocation group because ordinary Intercom is mandatory. Tool restrictions do not suppress that group; explicit `group` values retain their existing precedence. Subagents inherit their launching stage's resolved group by default (see [subagents.md](/subagents)). The subagent-only `contact_supervisor` channel keeps its broker-authorized cross-group route. Ordinary client sends remain group-bound, with one deliberate exception: the workflow invocation group has directional list/send/live-ask control over the subgroups it owns, so an isolated stage stays steerable from the invocation context. That authority does not run in reverse or sideways — a subgroup stage cannot use it to reach a sibling subgroup, and another run cannot use it at all.
|
|
2429
2435
|
|
|
2430
2436
|
Authors do not need to generate or pass a group through ordinary stages, tasks, parallel steps, nested workflows, or delegated subagents. Use an explicit named group or `group: true` only to create an intentional subgroup, such as isolating one reviewer level from another.
|
|
2431
2437
|
|
|
@@ -3049,6 +3055,9 @@ Expiry aborts the request operation signal so work that supports cancellation ca
|
|
|
3049
3055
|
|
|
3050
3056
|
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.
|
|
3051
3057
|
|
|
3058
|
+
The no-`runId` status listing includes bounded pending-stage rows after each run summary. Each row gives the display name, canonical stage ID, literal `pending` lifecycle, `pendingStageDeliveryAvailable`, and either the exact usable Intercom target or `unavailable`. Interactive status cards and run detail show the same identity/availability distinction within their width budgets. Status cards wrap exact targets onto continuation rows instead of rendering a partially truncated address; bounded omissions retain an explicit remaining-stage count.
|
|
3059
|
+
|
|
3060
|
+
|
|
3052
3061
|
`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.
|
|
3053
3062
|
|
|
3054
3063
|
Named launches wait only for **startup admission**, not for workflow completion. Atomic returns `status: "running"` after durable registration, reusable-worktree setup, and other pre-body setup succeed, while the workflow body and stages continue in the background. If setup fails before the workflow body is admitted — for example, `git_worktree_dir` points inside the invoking checkout — the original `workflow` tool call instead returns a structured `status: "failed"` result with the allocated full run id and concrete setup error. No background-start claim or orphan run is retained, so the caller can correct the inputs and retry immediately. Failures after admission remain ordinary background lifecycle outcomes reported through status and lifecycle notices.
|