@bastani/atomic 0.8.29-alpha.2 → 0.8.29-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.
Files changed (73) hide show
  1. package/CHANGELOG.md +14 -6
  2. package/dist/builtin/cursor/package.json +2 -2
  3. package/dist/builtin/intercom/CHANGELOG.md +1 -1
  4. package/dist/builtin/intercom/package.json +1 -1
  5. package/dist/builtin/mcp/CHANGELOG.md +1 -1
  6. package/dist/builtin/mcp/package.json +1 -1
  7. package/dist/builtin/subagents/CHANGELOG.md +4 -4
  8. package/dist/builtin/subagents/README.md +4 -4
  9. package/dist/builtin/subagents/package.json +1 -1
  10. package/dist/builtin/subagents/src/extension/index.ts +14 -0
  11. package/dist/builtin/subagents/src/extension/schemas.ts +1 -1
  12. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +1 -6
  13. package/dist/builtin/subagents/src/runs/foreground/execution.ts +1 -6
  14. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +0 -1
  15. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -1
  16. package/dist/builtin/subagents/src/runs/shared/structured-output.ts +16 -285
  17. package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
  18. package/dist/builtin/subagents/src/shared/types.ts +4 -4
  19. package/dist/builtin/subagents/src/slash/saved-chain-mapping.ts +3 -18
  20. package/dist/builtin/web-access/CHANGELOG.md +1 -1
  21. package/dist/builtin/web-access/package.json +1 -1
  22. package/dist/builtin/workflows/CHANGELOG.md +12 -5
  23. package/dist/builtin/workflows/README.md +10 -8
  24. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +9 -49
  25. package/dist/builtin/workflows/builtin/goal.ts +68 -155
  26. package/dist/builtin/workflows/builtin/index.d.ts +2 -0
  27. package/dist/builtin/workflows/builtin/open-claude-design.ts +42 -110
  28. package/dist/builtin/workflows/builtin/ralph.d.ts +2 -0
  29. package/dist/builtin/workflows/builtin/ralph.ts +235 -565
  30. package/dist/builtin/workflows/builtin/shared-prompts.ts +7 -0
  31. package/dist/builtin/workflows/package.json +1 -1
  32. package/dist/builtin/workflows/src/extension/index.ts +17 -0
  33. package/dist/builtin/workflows/src/extension/wiring.ts +55 -8
  34. package/dist/builtin/workflows/src/extension/workflow-schema.ts +2 -29
  35. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +1 -5
  36. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +1 -1
  37. package/dist/builtin/workflows/src/shared/types.ts +1 -1
  38. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  39. package/dist/core/atomic-guide-command.js +7 -7
  40. package/dist/core/atomic-guide-command.js.map +1 -1
  41. package/dist/core/resource-loader.d.ts +2 -2
  42. package/dist/core/resource-loader.d.ts.map +1 -1
  43. package/dist/core/resource-loader.js.map +1 -1
  44. package/dist/core/sdk.d.ts +3 -3
  45. package/dist/core/sdk.d.ts.map +1 -1
  46. package/dist/core/sdk.js +2 -2
  47. package/dist/core/sdk.js.map +1 -1
  48. package/dist/core/system-prompt.d.ts.map +1 -1
  49. package/dist/core/system-prompt.js +0 -36
  50. package/dist/core/system-prompt.js.map +1 -1
  51. package/dist/core/tools/index.d.ts +1 -1
  52. package/dist/core/tools/index.d.ts.map +1 -1
  53. package/dist/core/tools/index.js +1 -1
  54. package/dist/core/tools/index.js.map +1 -1
  55. package/dist/core/tools/structured-output.d.ts +7 -18
  56. package/dist/core/tools/structured-output.d.ts.map +1 -1
  57. package/dist/core/tools/structured-output.js +9 -89
  58. package/dist/core/tools/structured-output.js.map +1 -1
  59. package/dist/core/tools/todos.d.ts +1 -0
  60. package/dist/core/tools/todos.d.ts.map +1 -1
  61. package/dist/core/tools/todos.js +4 -0
  62. package/dist/core/tools/todos.js.map +1 -1
  63. package/dist/index.d.ts +1 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +1 -1
  66. package/dist/index.js.map +1 -1
  67. package/docs/extensions.md +1 -1
  68. package/docs/quickstart.md +3 -3
  69. package/docs/sdk.md +1 -1
  70. package/docs/subagents.md +4 -6
  71. package/docs/usage.md +1 -1
  72. package/docs/workflows.md +23 -19
  73. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,26 +7,34 @@
7
7
  - Added support for local `-e <dir>` extension sources to borrow project-local Atomic resources from `<dir>/.atomic`, legacy `<dir>/.pi`, and `<dir>/.agents/skills` after resolving trust for that extension source, preserving package-manager provenance and explicit-path workflow forwarding while avoiding untrusted borrowed resources ([#1354](https://github.com/bastani-inc/atomic/issues/1354)).
8
8
  - Added a prototype Rust/N-API Cursor HTTP/2 native transport binding through the generated `@bastani/atomic-natives` NAPI-RS package, so Atomic can use an in-process native HTTP/2 client without requiring Node.js on `PATH`.
9
9
  - Added the experimental bundled `@bastani/cursor` provider scaffold so `/login` can offer Cursor OAuth, estimated fallback exposes `cursor/composer-2`, and Cursor model mapping/streaming hooks are available behind an isolated HTTP/2 Connect transport boundary with production-default protobuf decoding, buffered Connect frames, write-before-headers Run streaming, stable Cursor conversation ids, schema-correct Cursor MCP tool advertisement, Cursor MCP tool-call decoding with protobuf `Value` or raw UTF-8/JSON arguments and exec-id metadata, same-stream MCP tool-result resume, abort/idle cleanup for paused tool streams, Connect end-stream error classification, exact live model id fidelity without static default injection, fast/thinking catalog grouping, and usage-delta accumulation.
10
- - Added the opt-in `createStructuredOutputTool({ schema, capture, output, name })` factory for terminating machine-readable final answers with schema-as-parameters validation, flat `details`, in-process capture, flat private `output.json` capture plus `output.meta.json` sidecar metadata, and prompt guidance for exact-once use without registering `structured_output` in normal agent sessions by default ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
10
+ - Added the opt-in `createStructuredOutputTool({ schema, capture, output, name })` factory for terminating machine-readable final answers with direct schema-as-parameters capture, flat `details`, in-process capture, configurable private file capture via `output.outputPath`, and the concise two-line `structured_output` prompt guidance from `pi-dynamic-workflows` without registering `structured_output` in normal agent sessions by default ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
11
11
 
12
12
  ### Changed
13
13
 
14
+ - Changed the bundled builtin `ralph` workflow to run `/skill:prompt-engineer` prompt-engineering and `/skill:research-codebase` research before orchestration instead of starting with an RFC/planner stage, pass the research artifact as primary implementation context, reuse prior research session data on follow-up loops, and feed unresolved reviewer findings into later research passes ([#1371](https://github.com/bastani-inc/atomic/issues/1371)).
15
+ - Changed bundled `goal`, `ralph`, and `open-claude-design` decision gates to use schema-backed workflow `structured_output` stages instead of registering bespoke terminating custom tools.
16
+ - Changed bundled `goal` worker/reviewer prompts and `ralph` orchestrator/reviewer prompts to request end-to-end verification when practical, using browser-skilled subagents for web/frontend flows that may depend on backend/API behavior and tmux-skilled subagents for TUI or terminal-app scenarios.
14
17
  - Bumped the bundled upstream pi runtime libraries `@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and `@earendil-works/pi-tui` from `^0.79.1` to `^0.79.3`, bringing the latest upstream provider, model, agent-core, and TUI compatibility fixes into `@bastani/atomic`.
15
- - Updated the structured-output extension example and SDK/workflow/extension docs to use the canonical factory instead of hand-rolled `terminate: true` wrappers, and documented that schema-specific calls pass fields directly rather than through `{ value: ... }` ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
16
- - Enforced top-level object schemas for `structured_output` factory registration, with guidance to wrap array or primitive final values in object fields, made custom-named factory tools advertise the configured name in prompt metadata, and documented that text print mode recognizes factory-created custom structured-output tools without treating every terminating tool as printable ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
18
+ - Updated the structured-output extension example and SDK/workflow/extension docs to use the canonical factory instead of hand-rolled `terminate: true` wrappers, and documented that Atomic passes the supplied schema directly to the tool without additional structured-output parsing, object-root restrictions, or sidecar validation ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
19
+ - Made custom-named factory tools advertise the configured name in concise prompt metadata, and documented that text print mode recognizes factory-created custom structured-output tools without treating every terminating tool as printable ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
20
+ - Changed factory-created structured-output tool descriptions and prompt guidance to use context-neutral final-result wording for SDK, extension, workflow, and subagent registrations ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
17
21
  - Clarified SDK, extension, and workflow guidance that structured-output tools are opt-in custom tools, with workflow stages/tasks/chains/parallel items receiving `structured_output` only when they declare a `schema` and subagent children receiving it only when `outputSchema` is enabled ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
18
22
 
19
23
  ### Fixed
20
24
 
21
25
  - Fixed the root `@bastani/atomic` package export to include a `default` condition alongside the ESM import target, improving compatibility with loaders that select default export conditions.
22
26
  - Fixed extension custom UI focus deferral so full-screen overlays can keep keyboard focus while a parent/main-chat inline custom UI is pending, then focus that pending UI when the overlay is hidden; already-aborted custom UI calls no longer invoke factories or emit host custom-UI state changes ([#1353](https://github.com/bastani-inc/atomic/issues/1353)).
23
- - Fixed text print mode to emit trailing terminating JSON from factory-created structured-output tools, including custom tool names such as `final_decision`, instead of only recognizing the canonical `structured_output` name ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
24
- - Fixed terminating `structured_output` results to opt out of oversized-result persistence so large final JSON stays inline instead of being replaced by a `<persisted-output>` pointer ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
25
- - Fixed cross-process structured-output file capture to preserve flat schema-valid params in `output.json` and write call metadata to an `output.meta.json` sidecar so parent readback can reject stale or non-final captures instead of accepting any schema-valid `output.json` payload by existence alone ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
27
+ - Fixed text print mode to emit trailing terminating JSON from factory-created structured-output tools, including custom tool names such as `final_decision`, instead of only recognizing the canonical `structured_output` name; the same structured value remains available through `details`, capture sinks, and workflow/subagent structured result fields ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
28
+ - Fixed terminating `structured_output` results to opt out of oversized-result persistence ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
29
+ - Fixed cross-process structured-output file capture to preserve flat tool arguments in `output.json` without sidecar metadata or transcript-finality parsing ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
26
30
  - Fixed bundled subagent handling so explicit empty `tools: []` plus `outputSchema` grants only the schema-backed `structured_output` runtime tool instead of restoring default tools ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
27
31
  - Fixed prerelease publishing for native Atomic artifacts by allowing the `@bastani/atomic-natives` package metadata in release-preparation verification, running native artifact builds on architecture-matched Blacksmith and macOS runners, and documenting the two-package publish flow while keeping npm provenance publishing on GitHub-hosted Ubuntu.
28
32
  - Fixed the bundled experimental Cursor provider to honor per-request stream deadlines across open/read/resume writes, reset timed-out or aborted streams, clean up replaced paused turns safely, catch cleanup cancellation failures, tolerate non-MCP Cursor exec protocol messages without ending assistant turns, and align Run requests with Cursor's private CLI protocol by using blob/KV conversation state plus request-context tool-definition responses without the unsupported custom system-prompt field ([#1286](https://github.com/bastani-inc/atomic/issues/1286)).
29
33
  - Fixed release archive startup for the bundled experimental Cursor provider by declaring `@bufbuild/protobuf` as an `@bastani/atomic` runtime dependency, covering Cursor in the bundled-package dependency metadata guard, and smoke-checking Cursor/protobuf assets in native archives ([#1286](https://github.com/bastani-inc/atomic/issues/1286)).
34
+ - Fixed bundled `ralph` skill-prompt stages to invoke bundled skills through `/skill:<name>` expansion so prompt engineering and research stages receive the intended skill instructions.
35
+ - Fixed concurrent bundled workflow stage resource reloads to serialize temporary subagent child environment isolation so parallel stage startup cannot leave parent process child flags accidentally cleared.
36
+ - Fixed bundled workflow stage sessions to keep workflow package skills (`create-spec`, `impeccable`, `prompt-engineer`, `research-codebase`, and `skill-creator`) available while disabling only the recursive workflows extension in child sessions.
37
+ - Fixed bundled workflow stage resource discovery so bundled subagent definitions stay available, `subagent` is active by default with the same two-hop nesting budget as main chat, and explicitly allowlisted bundled extension tools such as `subagent`, `web_search`, `fetch_content`, and `intercom` remain visible even when a workflow is launched from a subagent child process.
30
38
 
31
39
  ### Security
32
40
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/cursor",
3
- "version": "0.8.29-alpha.2",
3
+ "version": "0.8.29-alpha.4",
4
4
  "private": true,
5
5
  "description": "Experimental first-party Atomic extension for Cursor OAuth, model discovery, and streaming provider registration.",
6
6
  "contributors": [
@@ -40,7 +40,7 @@
40
40
  }
41
41
  },
42
42
  "dependencies": {
43
- "@bastani/atomic-natives": "0.8.29-alpha.2",
43
+ "@bastani/atomic-natives": "0.8.29-alpha.4",
44
44
  "@bufbuild/protobuf": "^2.0.0"
45
45
  }
46
46
  }
@@ -6,7 +6,7 @@ All notable changes to the `pi-intercom` extension will be documented in this fi
6
6
 
7
7
  ### Changed
8
8
 
9
- - Published a synchronized Atomic 0.8.29-alpha.1 prerelease with the upstream pi TUI dependency aligned to `^0.79.3`; no functional changes were made in the intercom extension.
9
+ - Published a synchronized Atomic 0.8.29-alpha.4 prerelease with the upstream pi TUI dependency aligned to `^0.79.3`; no functional changes were made in the intercom extension.
10
10
 
11
11
  ## [0.8.28] - 2026-06-11
12
12
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.8.29-alpha.2",
3
+ "version": "0.8.29-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
- - Published a synchronized Atomic 0.8.29-alpha.1 prerelease with upstream pi AI/TUI dependencies aligned to `^0.79.3`; no functional changes were made in the MCP extension.
12
+ - Published a synchronized Atomic 0.8.29-alpha.4 prerelease with upstream pi AI/TUI dependencies aligned to `^0.79.3`; no functional changes were made in the MCP extension.
13
13
 
14
14
  ## [0.8.28] - 2026-06-11
15
15
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.8.29-alpha.2",
3
+ "version": "0.8.29-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic extension that adapts MCP (Model Context Protocol) servers into the coding agent. Fork of: https://github.com/nicobailon/pi-mcp-adapter",
6
6
  "contributors": [
@@ -5,14 +5,14 @@
5
5
  ### Changed
6
6
 
7
7
  - Aligned the subagents extension with upstream pi `^0.79.3` runtime packages (`@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and `@earendil-works/pi-tui`) so child sessions inherit the latest shared agent, provider, and TUI compatibility fixes.
8
- - Changed `outputSchema` child runs to use Atomic's shared `structured_output` factory with flat schema parameters, preserving parent-side `structuredOutput` capture while removing the old child-facing `{ value: ... }` envelope, auto-allowing the required tool for explicit child tool allowlists, and documenting that the prompt-runtime extension is loaded before user/tool extensions so the allowlist sees the runtime-registered tool ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
9
- - Enforced parent-side fail-fast validation that subagent child `outputSchema` roots are top-level object tool-argument schemas; array or primitive handoff values must now be wrapped in object fields such as `{ items: [...] }` or `{ value: ... }` ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
10
- - Kept dynamic fanout `collect.outputSchema` as a general JSON Schema validator so saved chains and direct runs can validate aggregate arrays with array-root schemas while child `outputSchema` tool contracts remain object-rooted ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
8
+ - Changed `outputSchema` child runs to use Atomic's shared `structured_output` factory with direct schema parameters, concise two-line prompt guidance, parent-side `structuredOutput` capture from `output.json`, and auto-allowing the required tool for explicit child tool allowlists ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
9
+ - Removed parent-side top-level-object restrictions from child `outputSchema`; any plain JSON Schema object can be passed directly to the `structured_output` tool ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
11
10
 
12
11
  ### Fixed
13
12
 
14
- - Fixed subagent `outputSchema` readback to accept cross-process captures only when flat `output.json` params validate against the schema and `output.meta.json` sidecar metadata matches the final successful terminating `structured_output` transcript action, rejecting missing metadata, stale captures with later assistant/tool-result messages, sibling tool calls, duplicate structured-output calls, mismatched call IDs/names, and error tool results while ignoring benign `custom` host annotations around the final tool result ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
13
+ - Fixed subagent `outputSchema` readback to use the captured `output.json` directly without sidecar metadata, transcript-finality parsing, duplicate-call checks, or parent-side schema revalidation ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
15
14
  - Fixed explicit empty child `tools: []` allowlists with `outputSchema` to pass only `--tools structured_output`, keeping the restricted child from regaining default tools while still enabling the required final-answer channel ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
15
+ - Fixed workflow-stage subagent depth handling so bundled workflow stages inherit the main-chat two-hop subagent nesting budget while preserving stricter configured limits, and updated the nested-depth rejection message to describe the maximum-depth condition ([#1372](https://github.com/bastani-inc/atomic/pull/1372)).
16
16
 
17
17
  ## [0.8.28] - 2026-06-11
18
18
 
@@ -531,15 +531,15 @@ Create an implementation plan based on {outputs.context}
531
531
 
532
532
  Each `.chain.md` `## agent-name` section is a step. Config lines such as `phase`, `label`, `as`, `outputSchema`, `output`, `outputMode`, `reads`, `model`, `skills`, and `progress` go immediately after the header. A blank line separates config from task text. In saved `.chain.md` files, `outputSchema` is a path to a JSON Schema file; direct tool calls and `.chain.json` files can pass the schema object inline.
533
533
 
534
- When `outputSchema` is present, the child receives a schema-specific `structured_output` tool backed by Atomic's shared factory. The schema must be a top-level object tool-argument schema; wrap array or primitive handoff values in explicit object fields such as `{ items: [...] }` or `{ value: ... }`. The child must call `structured_output` exactly once with the schema fields directly, for example `structured_output({ files: [...], risks: [...] })`; do not use the old `structured_output({ value: ... })` wrapper unless your schema explicitly defines a top-level `value` property. The child writes flat params to `output.json` and call metadata (`toolName`, `toolCallId`, `success`, `terminate`) to the `output.meta.json` sidecar. Missing calls, missing sidecar metadata, invalid values, duplicate calls, stale output-file captures, sibling tool calls in the same assistant batch, and later assistant/custom/tool-result messages after the successful tool result fail the step. The parent accepts the cross-process capture only when the flat `output.json` validates and sidecar metadata plus transcript finality prove the same `structured_output` call was the final successful terminating action, then exposes the validated flat value as `structuredOutput`.
534
+ When `outputSchema` is present, the child receives a schema-specific `structured_output` tool backed by Atomic's shared factory. The schema is passed directly to the tool. The child writes the tool arguments to `output.json`, and the parent reads that JSON back as `structuredOutput`; Atomic no longer adds object-root restrictions, sidecar metadata, transcript-finality checks, or duplicate-call guards.
535
535
 
536
- Children without `outputSchema` do not receive `structured_output` from Atomic's default tool registry. They can still use a custom extension-provided terminating tool if you explicitly add one, but validated `result.structuredOutput` remains reserved for schema-backed captures.
536
+ Children without `outputSchema` do not receive `structured_output` from Atomic's default tool registry. They can still use a custom extension-provided terminating tool if you explicitly add one.
537
537
 
538
538
  For `output`, `reads`, `skills`, and `progress`, chain behavior is three-state: omitted inherits from the agent, a value overrides, and `false` disables.
539
539
 
540
540
  Use `phase` to group related work in status output, `label` for a readable step name, and `as` to store a successful step or parallel task result for later `{outputs.name}` references. Duplicate `as` names, invalid identifiers, and unknown output references fail before child execution.
541
541
 
542
- Dynamic fanout is available only through direct `subagent({ chain: [...] })` JSON or saved `.chain.json` files. It expands an array from a prior structured named output, runs one child template per item, and stores the ordered collection under `collect.as`. The source must be structured output; prose is never parsed. `expand.maxItems` is required, over-limit arrays fail, nested fanout and arbitrary expressions are not supported, and `.chain.md` has no dynamic syntax in this release. `collect.outputSchema` validates the collected array after child execution and remains a general JSON Schema, so array-root schemas such as `{ "type": "array", "minItems": 1 }` are allowed there even though child `outputSchema` tool schemas must be top-level objects.
542
+ Dynamic fanout is available only through direct `subagent({ chain: [...] })` JSON or saved `.chain.json` files. It expands an array from a prior structured named output, runs one child template per item, and stores the ordered collection under `collect.as`. The source must be structured output; prose is never parsed. `expand.maxItems` is required, over-limit arrays fail, nested fanout and arbitrary expressions are not supported, and `.chain.md` has no dynamic syntax in this release. `collect.outputSchema` validates the collected array after child execution.
543
543
 
544
544
  ```json
545
545
  {
@@ -820,7 +820,7 @@ Agent definitions are not loaded into context by default. Management actions let
820
820
 
821
821
  Use `outputMode: "file-only"` when a saved output may be large and the parent only needs a pointer. The returned text is a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` Failed runs and save errors still return normal inline output for debugging. In chains, later `{previous}` steps receive the same compact reference when the prior step used file-only mode.
822
822
 
823
- Sequential and parallel chain tasks accept `agent`, `task`, `phase`, `label`, `as`, `outputSchema`, `cwd`, `output`, `outputMode`, `reads`, `progress`, `skill`, and `model`. Parallel tasks also accept `count`. Parallel step groups accept `parallel`, `concurrency`, `failFast`, and `worktree`. If child `outputSchema` is present, it must be a top-level object schema and the child must call `structured_output` with schema-valid flat JSON arguments; prose-only completion, missing `output.meta.json` sidecar metadata, invalid JSON, top-level arrays/primitives, or an obsolete `{ value: ... }` envelope fails unless the schema itself allows that shape. Validated structured values are preserved on the step result, and `as` also exposes a compact text representation through `{outputs.name}`. Without `outputSchema`, Atomic does not inject `structured_output` into the child. Dynamic fanout `collect.outputSchema` is looser because it validates the aggregate collection rather than a tool call; array-root collection schemas remain valid.
823
+ Sequential and parallel chain tasks accept `agent`, `task`, `phase`, `label`, `as`, `outputSchema`, `cwd`, `output`, `outputMode`, `reads`, `progress`, `skill`, and `model`. Parallel tasks also accept `count`. Parallel step groups accept `parallel`, `concurrency`, `failFast`, and `worktree`. If child `outputSchema` is present, Atomic injects `structured_output`, writes the child tool arguments to `output.json`, and preserves the parsed value on the step result; `as` also exposes a compact text representation through `{outputs.name}`. Without `outputSchema`, Atomic does not inject `structured_output` into the child.
824
824
 
825
825
  Status and control actions:
826
826
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.8.29-alpha.2",
3
+ "version": "0.8.29-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic extension for delegating tasks to subagents with chains, parallel execution, and TUI clarification. Fork of: https://github.com/nicobailon/pi-subagents",
6
6
  "contributors": [
@@ -213,6 +213,19 @@ class SubagentControlNoticeComponent implements Component {
213
213
  }
214
214
  }
215
215
 
216
+ export const DEFAULT_PROMPT_GUIDANCE: string[] = [
217
+ `**Subagent Orchestration**:
218
+ - To avoid draining your context window, prefer to use subagents for complex tasks all non-trivial operations should be delegated to subagents.
219
+ - You should delegate running bash commands (particularly ones that are likely to produce lots of output) such as investigating with the \`aws\` CLI, using the \`gh\` CLI, digging through logs to \`bash\` subagents.
220
+ - You should use separate subagents for separate tasks, and you may launch them in parallel, but do not delegate multiple tasks that are likely to have significant overlap to separate subagents.
221
+ - Sometimes subagents will take a long time. DO NOT attempt to do the job yourself while waiting for the subagent to respond Instead, use the time to plan out your next steps.
222
+ - **Debugging**: When a user asks about debugging, spawn a debugger subagent first.
223
+ - Do not attempt to debug or analyze code yourself without first consulting the debugger subagent.
224
+ - Explain the debugger's insights to the user clearly and concisely.
225
+ - Once the user confirms, implement the necessary code changes based on those insights.
226
+ - If the user has follow-up questions, spawn additional debugger and research subagents as needed.`,
227
+ ];
228
+
216
229
  export default function registerSubagentExtension(pi: ExtensionAPI): void {
217
230
  if (getEnvValue(SUBAGENT_CHILD_ENV) === "1") {
218
231
  if (getEnvValue(SUBAGENT_FANOUT_CHILD_ENV) === "1") registerFanoutChildSubagentExtension(pi);
@@ -431,6 +444,7 @@ CONTROL:
431
444
  DIAGNOSTICS:
432
445
  • { action: "doctor" } - read-only report for runtime paths, discovery, sessions, and intercom`,
433
446
  parameters: SubagentParams,
447
+ promptGuidelines: DEFAULT_PROMPT_GUIDANCE,
434
448
 
435
449
  execute(id, params, signal, onUpdate, ctx) {
436
450
  return executeSubagentCollapsed(id, params, signal, onUpdate, ctx);
@@ -38,7 +38,7 @@ const ReadsOverride = Type.Unsafe({
38
38
  const JsonSchemaObject = Type.Unsafe({
39
39
  type: "object",
40
40
  additionalProperties: true,
41
- description: "JSON Schema object for strict structured output. Non-object roots are rejected.",
41
+ description: "Plain JSON Schema object for structured output.",
42
42
  });
43
43
 
44
44
  const AcceptanceEvidenceKind = Type.String({
@@ -748,12 +748,7 @@ async function runSingleStep(
748
748
  let structuredOutput: unknown;
749
749
  let structuredError: string | undefined;
750
750
  if (effectiveStructuredOutput && run.exitCode === 0 && !run.error && !hiddenError?.hasError) {
751
- const structured = readStructuredOutput({
752
- schema: effectiveStructuredOutput.schema,
753
- schemaPath: effectiveStructuredOutput.schemaPath,
754
- outputPath: effectiveStructuredOutput.outputPath,
755
- metadataPath: effectiveStructuredOutput.metadataPath,
756
- }, { messages: run.messages });
751
+ const structured = readStructuredOutput(effectiveStructuredOutput);
757
752
  if (structured.error) structuredError = structured.error;
758
753
  else structuredOutput = structured.value;
759
754
  }
@@ -748,12 +748,7 @@ async function runSingleAttempt(
748
748
  }
749
749
  }
750
750
  if (options.structuredOutput && result.exitCode === 0 && !result.error) {
751
- const structured = readStructuredOutput({
752
- schema: options.structuredOutput.schema,
753
- schemaPath: options.structuredOutput.schemaPath,
754
- outputPath: options.structuredOutput.outputPath,
755
- metadataPath: options.structuredOutput.metadataPath,
756
- }, { messages: result.messages ?? [] });
751
+ const structured = readStructuredOutput(options.structuredOutput);
757
752
  result.structuredOutputSchemaPath = options.structuredOutput.schemaPath;
758
753
  result.structuredOutputPath = options.structuredOutput.outputPath;
759
754
  if (structured.error) {
@@ -33,7 +33,6 @@ export interface RunnerSubagentStep {
33
33
  schema: import("../../shared/types.ts").JsonSchemaObject;
34
34
  schemaPath: string;
35
35
  outputPath: string;
36
- metadataPath: string;
37
36
  };
38
37
  structuredOutputSchema?: import("../../shared/types.ts").JsonSchemaObject;
39
38
  effectiveAcceptance?: import("../../shared/types.ts").ResolvedAcceptanceConfig;
@@ -75,7 +75,6 @@ interface BuildPiArgsInput {
75
75
  schema: JsonSchemaObject;
76
76
  schemaPath: string;
77
77
  outputPath: string;
78
- metadataPath: string;
79
78
  };
80
79
  }
81
80
 
@@ -1,7 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as os from "node:os";
3
3
  import * as path from "node:path";
4
- import { APP_NAME, STRUCTURED_OUTPUT_TOOL_NAME, getStructuredOutputMetadataPath } from "@bastani/atomic";
4
+ import { APP_NAME } from "@bastani/atomic";
5
5
  import { Compile } from "typebox/compile";
6
6
  import type { JsonSchemaObject } from "../../shared/types.ts";
7
7
 
@@ -9,239 +9,10 @@ const ENV_PREFIX = APP_NAME.toUpperCase();
9
9
  export const STRUCTURED_OUTPUT_SCHEMA_ENV = `${ENV_PREFIX}_SUBAGENT_STRUCTURED_OUTPUT_SCHEMA`;
10
10
  export const STRUCTURED_OUTPUT_CAPTURE_ENV = `${ENV_PREFIX}_SUBAGENT_STRUCTURED_OUTPUT_CAPTURE`;
11
11
 
12
- type JsonPrimitive = string | number | boolean | null;
13
- type JsonArray = readonly JsonValue[];
14
- type JsonRecord = { readonly [key: string]: JsonValue };
15
- type JsonValue = JsonPrimitive | JsonArray | JsonRecord;
16
-
17
12
  export interface StructuredOutputRuntime {
18
13
  schema: JsonSchemaObject;
19
14
  schemaPath: string;
20
15
  outputPath: string;
21
- metadataPath: string;
22
- }
23
-
24
- export interface StructuredOutputCaptureMetadata {
25
- toolName: string;
26
- toolCallId: string;
27
- success: true;
28
- terminate: true;
29
- capturedAt?: string;
30
- }
31
-
32
- export interface StructuredOutputTranscriptContent {
33
- readonly type?: string;
34
- readonly id?: string;
35
- readonly name?: string;
36
- }
37
-
38
- export interface StructuredOutputTranscriptMessage {
39
- readonly role: string;
40
- readonly content?: string | readonly StructuredOutputTranscriptContent[];
41
- readonly toolCallId?: string;
42
- readonly toolName?: string;
43
- readonly isError?: boolean;
44
- }
45
-
46
- export interface ReadStructuredOutputOptions {
47
- messages?: readonly StructuredOutputTranscriptMessage[];
48
- toolName?: string;
49
- }
50
-
51
- interface CompiledJsonSchema {
52
- Check(value: unknown): boolean;
53
- Errors(value: unknown): Iterable<{ instancePath?: string; message?: string }>;
54
- }
55
-
56
- type JsonSchemaRootDescriptor = {
57
- readonly type?: string | readonly string[];
58
- readonly anyOf?: readonly JsonSchemaObject[];
59
- readonly oneOf?: readonly JsonSchemaObject[];
60
- readonly allOf?: readonly JsonSchemaObject[];
61
- };
62
-
63
- type ToolCallBlock = {
64
- readonly type: "toolCall";
65
- readonly id?: string;
66
- readonly name?: string;
67
- };
68
-
69
- function schemaTypeIsObjectOnly(type: JsonSchemaRootDescriptor["type"]): boolean {
70
- if (type === "object") return true;
71
- return Array.isArray(type) && type.length === 1 && type[0] === "object";
72
- }
73
-
74
- function isTopLevelObjectOutputSchema(schema: JsonSchemaObject): boolean {
75
- const descriptor = schema as JsonSchemaRootDescriptor;
76
- if (schemaTypeIsObjectOnly(descriptor.type)) return true;
77
- if (descriptor.type !== undefined) return false;
78
- if (Array.isArray(descriptor.anyOf) || Array.isArray(descriptor.oneOf)) return false;
79
- if (Array.isArray(descriptor.allOf)) {
80
- return descriptor.allOf.length > 0 && descriptor.allOf.every((member) => isTopLevelObjectOutputSchema(member));
81
- }
82
- return false;
83
- }
84
-
85
- function isJsonRecord(value: JsonValue): value is JsonRecord {
86
- return typeof value === "object" && value !== null && !Array.isArray(value);
87
- }
88
-
89
- function stringField(record: JsonRecord, key: string): string | undefined {
90
- const value = record[key];
91
- return typeof value === "string" && value.length > 0 ? value : undefined;
92
- }
93
-
94
- function booleanField(record: JsonRecord, key: string): boolean | undefined {
95
- const value = record[key];
96
- return typeof value === "boolean" ? value : undefined;
97
- }
98
-
99
- function roleOf(message: StructuredOutputTranscriptMessage): string {
100
- return message.role;
101
- }
102
-
103
- function toolCallBlocks(message: StructuredOutputTranscriptMessage): ToolCallBlock[] {
104
- if (roleOf(message) !== "assistant" || !Array.isArray(message.content)) return [];
105
- return message.content
106
- .filter((block): block is ToolCallBlock => block.type === "toolCall")
107
- .map((block) => ({ type: "toolCall", id: block.id, name: block.name }));
108
- }
109
-
110
- function isFinalityRelevantMessage(message: StructuredOutputTranscriptMessage): boolean {
111
- const role = roleOf(message);
112
- // `custom` entries are host/runtime annotations (for example display/status
113
- // messages) rather than additional child model output, so they should not make
114
- // an otherwise-final structured_output capture look stale.
115
- return role === "assistant" || role === "toolResult";
116
- }
117
-
118
- function finalityInvalid(message: string): { status: "invalid"; message: string } {
119
- return { status: "invalid", message };
120
- }
121
-
122
- function parseCaptureMetadata(value: JsonValue): { metadata?: StructuredOutputCaptureMetadata; error?: string } {
123
- if (!isJsonRecord(value)) {
124
- return { error: "Structured output metadata sidecar must contain an object with call metadata." };
125
- }
126
- const toolName = stringField(value, "toolName");
127
- const toolCallId = stringField(value, "toolCallId");
128
- if (!toolName || !toolCallId) {
129
- return { error: "Structured output metadata sidecar is missing toolName or toolCallId metadata." };
130
- }
131
- if (booleanField(value, "success") !== true) {
132
- return { error: "Structured output capture was not marked successful." };
133
- }
134
- if (booleanField(value, "terminate") !== true) {
135
- return { error: "Structured output capture was not marked as a terminating action." };
136
- }
137
- return {
138
- metadata: {
139
- toolName,
140
- toolCallId,
141
- success: true,
142
- terminate: true,
143
- ...(typeof value.capturedAt === "string" ? { capturedAt: value.capturedAt } : {}),
144
- },
145
- };
146
- }
147
-
148
- function verifyStructuredOutputFinality(
149
- messages: readonly StructuredOutputTranscriptMessage[],
150
- metadata: StructuredOutputCaptureMetadata,
151
- expectedToolName: string,
152
- ): { status: "valid" } | { status: "invalid"; message: string } {
153
- if (metadata.toolName !== expectedToolName) {
154
- return finalityInvalid(
155
- `Captured structured output tool name ${JSON.stringify(metadata.toolName)} did not match expected ${JSON.stringify(expectedToolName)}.`,
156
- );
157
- }
158
- if (messages.length === 0) {
159
- return finalityInvalid("Structured output finality could not be verified because the child transcript is empty.");
160
- }
161
-
162
- let structuredOutputCallCount = 0;
163
- let assistantIndex = -1;
164
- let matchingAssistantToolCalls: ToolCallBlock[] = [];
165
- for (let index = 0; index < messages.length; index++) {
166
- const calls = toolCallBlocks(messages[index]);
167
- if (calls.length === 0) continue;
168
- for (const call of calls) {
169
- if (call.name === metadata.toolName) {
170
- structuredOutputCallCount += 1;
171
- }
172
- }
173
- const idMatch = calls.find((call) => call.id === metadata.toolCallId);
174
- if (!idMatch) continue;
175
- if (idMatch.name !== metadata.toolName) {
176
- return finalityInvalid(
177
- `Captured structured output tool call ${JSON.stringify(metadata.toolCallId)} used tool name ${JSON.stringify(idMatch.name)} instead of ${JSON.stringify(metadata.toolName)}.`,
178
- );
179
- }
180
- assistantIndex = index;
181
- matchingAssistantToolCalls = calls;
182
- }
183
-
184
- if (structuredOutputCallCount > 1) {
185
- return finalityInvalid(
186
- `Captured structured output call ${JSON.stringify(metadata.toolCallId)} was not exactly once; another ${metadata.toolName} tool call appeared in the child transcript.`,
187
- );
188
- }
189
- if (assistantIndex === -1) {
190
- return finalityInvalid(
191
- `No assistant tool call matched captured structured output toolCallId ${JSON.stringify(metadata.toolCallId)}.`,
192
- );
193
- }
194
- if (matchingAssistantToolCalls.length !== 1) {
195
- return finalityInvalid(
196
- `Captured structured output call ${JSON.stringify(metadata.toolCallId)} was accompanied by sibling tool calls in the same assistant message.`,
197
- );
198
- }
199
-
200
- let resultIndex = -1;
201
- let resultMessage: StructuredOutputTranscriptMessage | undefined;
202
- for (let index = assistantIndex + 1; index < messages.length; index++) {
203
- const message = messages[index];
204
- if (roleOf(message) !== "toolResult") continue;
205
- if (message.toolCallId !== metadata.toolCallId) continue;
206
- resultIndex = index;
207
- resultMessage = message;
208
- break;
209
- }
210
-
211
- if (!resultMessage) {
212
- return finalityInvalid(
213
- `No tool result matched captured structured output toolCallId ${JSON.stringify(metadata.toolCallId)}.`,
214
- );
215
- }
216
- if (resultMessage.toolName !== metadata.toolName) {
217
- return finalityInvalid(
218
- `Structured output tool result for ${JSON.stringify(metadata.toolCallId)} used tool name ${JSON.stringify(resultMessage.toolName)} instead of ${JSON.stringify(metadata.toolName)}.`,
219
- );
220
- }
221
- if (resultMessage.isError !== false) {
222
- return finalityInvalid(
223
- `Structured output tool result for ${JSON.stringify(metadata.toolCallId)} was an error or did not prove success.`,
224
- );
225
- }
226
-
227
- for (let index = assistantIndex + 1; index < resultIndex; index++) {
228
- const message = messages[index];
229
- if (isFinalityRelevantMessage(message)) {
230
- return finalityInvalid(
231
- `Structured output call ${JSON.stringify(metadata.toolCallId)} was not final; another ${roleOf(message)} message appeared before its matching tool result.`,
232
- );
233
- }
234
- }
235
- for (let index = resultIndex + 1; index < messages.length; index++) {
236
- const message = messages[index];
237
- if (isFinalityRelevantMessage(message)) {
238
- return finalityInvalid(
239
- `Structured output call ${JSON.stringify(metadata.toolCallId)} was not final; a later ${roleOf(message)} message followed the successful tool result.`,
240
- );
241
- }
242
- }
243
-
244
- return { status: "valid" };
245
16
  }
246
17
 
247
18
  export function assertJsonSchemaDescriptor(schema: unknown, label = "outputSchema"): asserts schema is JsonSchemaObject {
@@ -250,84 +21,44 @@ export function assertJsonSchemaDescriptor(schema: unknown, label = "outputSchem
250
21
  }
251
22
  }
252
23
 
253
- export function assertStructuredOutputParameterSchema(schema: unknown, label = "outputSchema"): asserts schema is JsonSchemaObject {
254
- assertJsonSchemaDescriptor(schema, label);
255
- if (!isTopLevelObjectOutputSchema(schema)) {
256
- throw new Error(
257
- `${label} must be a top-level object tool-argument schema. `
258
- + "Wrap array or primitive outputs in an object field, for example `{ items: [...] }` or `{ value: ... }`.",
259
- );
260
- }
261
- }
262
-
263
24
  export function createStructuredOutputRuntime(schema: JsonSchemaObject, baseDir?: string): StructuredOutputRuntime {
264
- assertStructuredOutputParameterSchema(schema);
265
25
  const rootDir = baseDir ?? os.tmpdir();
266
26
  fs.mkdirSync(rootDir, { recursive: true });
267
27
  const dir = fs.mkdtempSync(path.join(rootDir, "pi-subagent-structured-"));
268
28
  const schemaPath = path.join(dir, "schema.json");
269
29
  const outputPath = path.join(dir, "output.json");
270
- const metadataPath = path.join(dir, "output.meta.json");
271
30
  fs.writeFileSync(schemaPath, JSON.stringify(schema), { mode: 0o600 });
272
- return { schema, schemaPath, outputPath, metadataPath };
31
+ return { schema, schemaPath, outputPath };
273
32
  }
274
33
 
275
34
  export function validateStructuredOutputValue(schema: JsonSchemaObject, value: unknown): { status: "valid" } | { status: "invalid"; message: string } {
276
- let validator: CompiledJsonSchema;
277
35
  try {
278
- validator = (Compile as (schema: unknown) => CompiledJsonSchema)(schema);
36
+ const validator = (Compile as (schema: unknown) => {
37
+ Check(value: unknown): boolean;
38
+ Errors(value: unknown): Iterable<{ instancePath?: string; message?: string }>;
39
+ })(schema);
40
+ if (validator.Check(value)) return { status: "valid" };
41
+ const errors = [...validator.Errors(value)]
42
+ .slice(0, 8)
43
+ .map((error) => {
44
+ const pathText = error.instancePath ? error.instancePath.replace(/^\//, "").replace(/\//g, ".") : "root";
45
+ return `${pathText}: ${error.message}`;
46
+ });
47
+ return { status: "invalid", message: errors.join("; ") || "schema validation failed" };
279
48
  } catch (error) {
280
49
  return { status: "invalid", message: `invalid outputSchema: ${error instanceof Error ? error.message : String(error)}` };
281
50
  }
282
- if (validator.Check(value)) return { status: "valid" };
283
- const errors = [...validator.Errors(value)]
284
- .slice(0, 8)
285
- .map((error) => {
286
- const pathText = error.instancePath ? error.instancePath.replace(/^\//, "").replace(/\//g, ".") : "root";
287
- return `${pathText}: ${error.message}`;
288
- });
289
- return { status: "invalid", message: errors.join("; ") || "schema validation failed" };
290
51
  }
291
52
 
292
- export function readStructuredOutput(
293
- runtime: StructuredOutputRuntime,
294
- options: ReadStructuredOutputOptions = {},
295
- ): { value?: unknown; error?: string } {
53
+ export function readStructuredOutput(runtime: StructuredOutputRuntime): { value?: unknown; error?: string } {
296
54
  if (!fs.existsSync(runtime.outputPath)) {
297
55
  return { error: "Missing structured_output call; this step has outputSchema and must finish by calling structured_output." };
298
56
  }
299
- const metadataPath = runtime.metadataPath ?? getStructuredOutputMetadataPath(runtime.outputPath);
300
- if (!fs.existsSync(metadataPath)) {
301
- return { error: "Missing structured_output metadata sidecar; this step must finish with a verified structured_output call." };
302
- }
303
- let payload: JsonValue;
304
57
  try {
305
- payload = JSON.parse(fs.readFileSync(runtime.outputPath, "utf-8")) as JsonValue;
58
+ return { value: JSON.parse(fs.readFileSync(runtime.outputPath, "utf-8")) as unknown };
306
59
  } catch (error) {
307
60
  return { error: `Failed to read structured output: ${error instanceof Error ? error.message : String(error)}` };
308
61
  }
309
- let rawMetadata: JsonValue;
310
- try {
311
- rawMetadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8")) as JsonValue;
312
- } catch (error) {
313
- return { error: `Failed to read structured output metadata: ${error instanceof Error ? error.message : String(error)}` };
314
- }
315
- const parsed = parseCaptureMetadata(rawMetadata);
316
- if (parsed.error || !parsed.metadata) {
317
- return { error: parsed.error ?? "Structured output metadata sidecar is invalid." };
318
- }
319
- const validation = validateStructuredOutputValue(runtime.schema, payload);
320
- if (validation.status === "invalid") return { error: `Structured output validation failed: ${validation.message}` };
321
- const expectedToolName = options.toolName ?? STRUCTURED_OUTPUT_TOOL_NAME;
322
- if (options.messages) {
323
- const finality = verifyStructuredOutputFinality(options.messages, parsed.metadata, expectedToolName);
324
- if (finality.status === "invalid") return { error: finality.message };
325
- } else if (parsed.metadata.toolName !== expectedToolName) {
326
- return {
327
- error: `Captured structured output tool name ${JSON.stringify(parsed.metadata.toolName)} did not match expected ${JSON.stringify(expectedToolName)}.`,
328
- };
329
- }
330
- return { value: payload };
331
62
  }
332
63
 
333
64
  export function cleanupStructuredOutputRuntime(runtime: StructuredOutputRuntime | undefined): void {
@@ -11,13 +11,6 @@ import type { JsonSchemaObject } from "../../shared/types.ts";
11
11
 
12
12
  export { SUBAGENT_INTERCOM_SESSION_NAME_ENV } from "./pi-args.ts";
13
13
 
14
- const STRUCTURED_OUTPUT_INSTRUCTIONS = [
15
- "This subagent step has a strict structured output contract.",
16
- "Your final action must be to call the `structured_output` tool with JSON matching the provided schema.",
17
- "Pass the schema fields directly as the tool arguments; do not wrap them in `{ value: ... }` unless the schema explicitly defines a top-level `value` field.",
18
- "Do not rely on prose-only completion; if you do not call `structured_output`, the parent will fail this step.",
19
- ].join("\n");
20
-
21
14
  export const CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS = [
22
15
  "You are a child subagent, not the parent orchestrator.",
23
16
  "The parent session owns delegation, orchestration, review fanout, and follow-up worker launches.",
@@ -107,8 +100,7 @@ export function rewriteSubagentPrompt(
107
100
  rewritten = stripSubagentOrchestrationSkill(rewritten);
108
101
  rewritten = stripChildBoundaryInstructions(rewritten);
109
102
  const boundary = options.fanoutChild ? CHILD_FANOUT_BOUNDARY_INSTRUCTIONS : CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS;
110
- const structured = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV] ? `\n\n${STRUCTURED_OUTPUT_INSTRUCTIONS}` : "";
111
- return `${boundary}${structured}\n\n${rewritten}`;
103
+ return `${boundary}\n\n${rewritten}`;
112
104
  }
113
105
 
114
106
  function isParentOnlySubagentMessage(message: unknown): boolean {