@gotgenes/pi-subagents 13.2.1 → 13.2.2
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 +7 -0
- package/README.md +3 -1
- package/dist/public.d.ts +34 -35
- package/docs/architecture/architecture.md +50 -49
- package/docs/architecture/history/phase-16-invert-dependencies.md +2 -1
- package/docs/decisions/0003-publish-bundled-type-declarations.md +3 -1
- package/docs/plans/0051-update-adr-0001-hard-fork.md +8 -6
- package/docs/plans/0257-extract-child-session-factory.md +3 -1
- package/docs/plans/0262-add-workspace-provider-seam.md +41 -39
- package/docs/plans/0264-remove-extension-lifecycle-control.md +100 -98
- package/docs/plans/0265-born-complete-subagent-session.md +5 -2
- package/docs/plans/0270-type-consumable-public-surface.md +3 -1
- package/docs/plans/0280-rename-agent-to-subagent.md +197 -0
- package/docs/retro/0051-update-adr-0001-hard-fork.md +4 -2
- package/docs/retro/0257-extract-child-session-factory.md +3 -1
- package/docs/retro/0262-add-workspace-provider-seam.md +3 -1
- package/docs/retro/0264-remove-extension-lifecycle-control.md +3 -1
- package/docs/retro/0270-type-consumable-public-surface.md +4 -2
- package/docs/retro/0280-rename-agent-to-subagent.md +96 -0
- package/package.json +1 -1
- package/src/index.ts +9 -9
- package/src/lifecycle/create-subagent-session.ts +1 -1
- package/src/lifecycle/{agent-manager.ts → subagent-manager.ts} +27 -27
- package/src/lifecycle/subagent-session.ts +2 -2
- package/src/lifecycle/{agent.ts → subagent.ts} +28 -28
- package/src/lifecycle/turn-limits.ts +1 -1
- package/src/lifecycle/workspace.ts +2 -2
- package/src/observation/notification.ts +9 -9
- package/src/observation/record-observer.ts +9 -9
- package/src/runtime.ts +1 -1
- package/src/service/service-adapter.ts +10 -10
- package/src/service/service.ts +5 -9
- package/src/tools/agent-tool.ts +5 -5
- package/src/tools/background-spawner.ts +3 -3
- package/src/tools/foreground-runner.ts +5 -5
- package/src/tools/get-result-tool.ts +2 -2
- package/src/tools/steer-tool.ts +2 -2
- package/src/types.ts +1 -1
- package/src/ui/agent-creation-wizard.ts +2 -2
- package/src/ui/agent-menu.ts +5 -5
- package/src/ui/agent-widget.ts +2 -2
- package/src/ui/conversation-viewer.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [13.2.2](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v13.2.1...pi-subagents-v13.2.2) (2026-06-01)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Documentation
|
|
12
|
+
|
|
13
|
+
* use ADR-NNNN with links docs-wide ([c6b6431](https://github.com/gotgenes/pi-packages/commit/c6b6431c004f324931f23be46cf2e47e8fdac919))
|
|
14
|
+
|
|
8
15
|
## [13.2.1](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v13.2.0...pi-subagents-v13.2.1) (2026-05-30)
|
|
9
16
|
|
|
10
17
|
|
package/README.md
CHANGED
|
@@ -494,7 +494,7 @@ Each has a corresponding upstream PR:
|
|
|
494
494
|
Upstream PR: [tintinweb/pi-subagents#73](https://github.com/tintinweb/pi-subagents/pull/73).
|
|
495
495
|
4. **Child-execution lifecycle events** (`src/lifecycle/child-lifecycle.ts`) — the child-session execution lifecycle is published as ordered events on `pi.events` (`subagents:child:spawning`, `session-created`, `completed`, `disposed`).
|
|
496
496
|
`session-created` fires synchronously before `bindExtensions()` so consumers (e.g. `@gotgenes/pi-permission-system`) can register the child session before binding proceeds.
|
|
497
|
-
This inverts the former outbound `permission-bridge` pattern (ADR
|
|
497
|
+
This inverts the former outbound `permission-bridge` pattern ([ADR-0002] / [#261]) — the core publishes, consumers subscribe.
|
|
498
498
|
No upstream equivalent — this feature is specific to the `@gotgenes` fork.
|
|
499
499
|
|
|
500
500
|
The upstream `vitest` suite plus tests added for each patch all pass on every commit.
|
|
@@ -502,3 +502,5 @@ The upstream `vitest` suite plus tests added for each patch all pass on every co
|
|
|
502
502
|
## License
|
|
503
503
|
|
|
504
504
|
MIT — [tintinweb](https://github.com/tintinweb) (upstream) and [Chris Lasher](https://github.com/gotgenes) (fork)
|
|
505
|
+
|
|
506
|
+
[ADR-0002]: docs/decisions/0002-extensions-on-a-minimal-core.md
|
package/dist/public.d.ts
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import { ThinkingLevel } from '@earendil-works/pi-ai';
|
|
2
2
|
|
|
3
|
-
/** usage.ts — Token usage: shapes, accumulator operators, session-stats readers. */
|
|
4
|
-
/**
|
|
5
|
-
* Lifetime usage components, accumulated via `message_end` events. Survives
|
|
6
|
-
* compaction (which replaces session.state.messages and would reset any
|
|
7
|
-
* stats-derived sum). cacheRead is excluded because each turn's cacheRead is
|
|
8
|
-
* the cumulative cached prefix re-read on that one call — summing across
|
|
9
|
-
* turns counts the prefix N times. See issue #38.
|
|
10
|
-
*/
|
|
11
|
-
type LifetimeUsage = {
|
|
12
|
-
input: number;
|
|
13
|
-
output: number;
|
|
14
|
-
cacheWrite: number;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
3
|
/**
|
|
18
4
|
* types.ts — Type definitions for the subagent system.
|
|
19
5
|
*/
|
|
@@ -29,27 +15,19 @@ interface AgentInvocation {
|
|
|
29
15
|
runInBackground?: boolean;
|
|
30
16
|
}
|
|
31
17
|
|
|
18
|
+
/** usage.ts — Token usage: shapes, accumulator operators, session-stats readers. */
|
|
32
19
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* Stats (toolUses, lifetimeUsage, compactionCount) are owned by the class and
|
|
40
|
-
* accumulated via mutation methods (incrementToolUses, addUsage, incrementCompactions).
|
|
41
|
-
*
|
|
42
|
-
* Behavior (abort, steer buffering) lives on the agent rather than on
|
|
43
|
-
* AgentManager — each agent manages its own lifecycle concerns.
|
|
44
|
-
*
|
|
45
|
-
* The child's working directory is supplied by a registered WorkspaceProvider
|
|
46
|
-
* (the workspace seam); with no provider the child runs in the parent cwd.
|
|
47
|
-
*
|
|
48
|
-
* Phase-specific collaborators (subagentSession, notification) are attached
|
|
49
|
-
* after construction as lifecycle information becomes available.
|
|
20
|
+
* Lifetime usage components, accumulated via `message_end` events. Survives
|
|
21
|
+
* compaction (which replaces session.state.messages and would reset any
|
|
22
|
+
* stats-derived sum). cacheRead is excluded because each turn's cacheRead is
|
|
23
|
+
* the cumulative cached prefix re-read on that one call — summing across
|
|
24
|
+
* turns counts the prefix N times. See issue #38.
|
|
50
25
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
26
|
+
type LifetimeUsage = {
|
|
27
|
+
input: number;
|
|
28
|
+
output: number;
|
|
29
|
+
cacheWrite: number;
|
|
30
|
+
};
|
|
53
31
|
|
|
54
32
|
/**
|
|
55
33
|
* workspace.ts — The single generative extension seam (ADR 0002, Phase 16 Step 2).
|
|
@@ -73,7 +51,7 @@ interface WorkspacePrepareContext {
|
|
|
73
51
|
}
|
|
74
52
|
/** Outcome the core reports to a workspace when the run ends. */
|
|
75
53
|
interface WorkspaceDisposeOutcome {
|
|
76
|
-
status:
|
|
54
|
+
status: SubagentStatus;
|
|
77
55
|
description: string;
|
|
78
56
|
}
|
|
79
57
|
/** What dispose may hand back for the core to fold into the child result. */
|
|
@@ -92,6 +70,28 @@ interface WorkspaceProvider {
|
|
|
92
70
|
prepare(ctx: WorkspacePrepareContext): Promise<Workspace | undefined>;
|
|
93
71
|
}
|
|
94
72
|
|
|
73
|
+
/**
|
|
74
|
+
* subagent.ts — Subagent class with encapsulated status-transition logic and per-subagent behavior.
|
|
75
|
+
*
|
|
76
|
+
* Status transitions (status, result, error, startedAt, completedAt) are owned
|
|
77
|
+
* by the class and exposed via transition methods. External code reads these
|
|
78
|
+
* fields through public properties but cannot write them directly.
|
|
79
|
+
*
|
|
80
|
+
* Stats (toolUses, lifetimeUsage, compactionCount) are owned by the class and
|
|
81
|
+
* accumulated via mutation methods (incrementToolUses, addUsage, incrementCompactions).
|
|
82
|
+
*
|
|
83
|
+
* Behavior (abort, steer buffering) lives on the subagent rather than on
|
|
84
|
+
* SubagentManager — each subagent manages its own lifecycle concerns.
|
|
85
|
+
*
|
|
86
|
+
* The child's working directory is supplied by a registered WorkspaceProvider
|
|
87
|
+
* (the workspace seam); with no provider the child runs in the parent cwd.
|
|
88
|
+
*
|
|
89
|
+
* Phase-specific collaborators (subagentSession, notification) are attached
|
|
90
|
+
* after construction as lifecycle information becomes available.
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
type SubagentStatus = "queued" | "running" | "completed" | "steered" | "aborted" | "stopped" | "error";
|
|
94
|
+
|
|
95
95
|
/**
|
|
96
96
|
* service.ts — Public API surface for cross-extension access to subagents.
|
|
97
97
|
*
|
|
@@ -103,7 +103,6 @@ interface WorkspaceProvider {
|
|
|
103
103
|
* svc?.spawn("Explore", "Check for stale TODOs");
|
|
104
104
|
*/
|
|
105
105
|
|
|
106
|
-
type SubagentStatus = "queued" | "running" | "completed" | "steered" | "aborted" | "stopped" | "error";
|
|
107
106
|
/** Serializable snapshot of an agent's state — no live session objects. */
|
|
108
107
|
interface SubagentRecord {
|
|
109
108
|
id: string;
|
|
@@ -51,11 +51,11 @@ flowchart TB
|
|
|
51
51
|
|
|
52
52
|
subgraph lifecycle["Lifecycle domain"]
|
|
53
53
|
direction TB
|
|
54
|
-
|
|
54
|
+
SubagentManager["SubagentManager<br/>(spawn, abort, collection)"]
|
|
55
55
|
ConcurrencyQueue["ConcurrencyQueue<br/>(scheduling, drain)"]
|
|
56
56
|
CreateSubagentSession["createSubagentSession<br/>(assembly factory)"]
|
|
57
57
|
SubagentSession["SubagentSession<br/>(turn loop, steer, dispose)"]
|
|
58
|
-
|
|
58
|
+
Subagent["Subagent<br/>(status, behavior: abort/steer/run lifecycle)"]
|
|
59
59
|
ParentSnapshot["ParentSnapshot<br/>(frozen parent state)"]
|
|
60
60
|
Workspace["workspace<br/>(provider seam: child cwd + teardown)"]
|
|
61
61
|
end
|
|
@@ -85,9 +85,9 @@ flowchart TB
|
|
|
85
85
|
Menu["agent-menu<br/>(slash command)"]
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
AgentTool -->
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
AgentTool --> SubagentManager
|
|
89
|
+
SubagentManager --> Subagent
|
|
90
|
+
Subagent --> CreateSubagentSession & SubagentSession
|
|
91
91
|
CreateSubagentSession --> SubagentSession
|
|
92
92
|
CreateSubagentSession --> SessionConfig
|
|
93
93
|
SessionConfig --> AgentTypeRegistry
|
|
@@ -95,18 +95,18 @@ flowchart TB
|
|
|
95
95
|
AgentTypeRegistry --> DefaultAgents & CustomAgents
|
|
96
96
|
RecordObserver -.->|subscribes| SubagentSession
|
|
97
97
|
UIObserver -.->|subscribes| SubagentSession
|
|
98
|
-
Widget -.->|polls|
|
|
98
|
+
Widget -.->|polls| SubagentManager
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
### Key domain types
|
|
102
102
|
|
|
103
103
|
```mermaid
|
|
104
104
|
classDiagram
|
|
105
|
-
class
|
|
105
|
+
class Subagent {
|
|
106
106
|
+id: string
|
|
107
107
|
+type: SubagentType
|
|
108
108
|
+description: string
|
|
109
|
-
+status:
|
|
109
|
+
+status: SubagentStatus
|
|
110
110
|
+result?: string
|
|
111
111
|
+error?: string
|
|
112
112
|
+toolUses: number
|
|
@@ -123,7 +123,7 @@ classDiagram
|
|
|
123
123
|
+run()
|
|
124
124
|
+resume(prompt, signal)
|
|
125
125
|
+abort(): boolean
|
|
126
|
-
+steer(message): Promise
|
|
126
|
+
+steer(message): Promise~boolean~
|
|
127
127
|
+isSessionReady(): boolean
|
|
128
128
|
+getConversation(): string | undefined
|
|
129
129
|
+getContextPercent(): number | null
|
|
@@ -137,12 +137,12 @@ classDiagram
|
|
|
137
137
|
+releaseListeners()
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
class
|
|
140
|
+
class SubagentManager {
|
|
141
141
|
+spawn(snapshot, type, prompt, config)
|
|
142
142
|
+spawnAndWait(snapshot, type, prompt, config)
|
|
143
143
|
+resume(id, prompt, signal)
|
|
144
|
-
+getRecord(id):
|
|
145
|
-
+listAgents():
|
|
144
|
+
+getRecord(id): Subagent
|
|
145
|
+
+listAgents(): Subagent[]
|
|
146
146
|
+abort(id)
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -171,10 +171,10 @@ classDiagram
|
|
|
171
171
|
+hasRunning(): boolean
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
SubagentsService -->
|
|
177
|
-
|
|
174
|
+
SubagentManager --> Subagent : creates/manages
|
|
175
|
+
SubagentManager --> ParentSnapshot : receives at spawn
|
|
176
|
+
SubagentsService --> SubagentManager : wraps via adapter
|
|
177
|
+
SubagentManager --> AgentTypeRegistry : resolves types
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
## Agent lifecycle
|
|
@@ -216,8 +216,8 @@ sequenceDiagram
|
|
|
216
216
|
participant LLM as Parent LLM
|
|
217
217
|
participant Tool as subagent tool
|
|
218
218
|
participant Spawn as spawn-config
|
|
219
|
-
participant Mgr as
|
|
220
|
-
participant Ag as
|
|
219
|
+
participant Mgr as SubagentManager
|
|
220
|
+
participant Ag as Subagent
|
|
221
221
|
participant Factory as createSubagentSession
|
|
222
222
|
participant Asm as assembleSessionConfig
|
|
223
223
|
participant Sub as SubagentSession
|
|
@@ -238,8 +238,8 @@ sequenceDiagram
|
|
|
238
238
|
Sub->>Child: prompt + drive turn loop
|
|
239
239
|
Child-->>Sub: result text
|
|
240
240
|
Sub-->>Ag: TurnLoopResult
|
|
241
|
-
Ag-->>Mgr: update
|
|
242
|
-
Mgr-->>Tool:
|
|
241
|
+
Ag-->>Mgr: update Subagent
|
|
242
|
+
Mgr-->>Tool: Subagent
|
|
243
243
|
Tool-->>LLM: formatted result
|
|
244
244
|
Note over Mgr: disposeSession() fires `disposed` at cleanup (resume-detectable)
|
|
245
245
|
```
|
|
@@ -277,11 +277,11 @@ src/
|
|
|
277
277
|
│ └── session-dir.ts session directory derivation
|
|
278
278
|
│
|
|
279
279
|
├── lifecycle/ agent execution and state tracking
|
|
280
|
-
│ ├──
|
|
280
|
+
│ ├── subagent-manager.ts collection manager + observer wiring
|
|
281
281
|
│ ├── create-subagent-session.ts assembly factory: session creation, binding, tool filtering
|
|
282
282
|
│ ├── subagent-session.ts born-complete child session: turn loop, steer, dispose
|
|
283
283
|
│ ├── turn-limits.ts normalizeMaxTurns (turn-count policy)
|
|
284
|
-
│ ├──
|
|
284
|
+
│ ├── subagent.ts owns full execution lifecycle (run, abort, steer, workspace)
|
|
285
285
|
│ ├── concurrency-queue.ts background agent scheduling with configurable concurrency limit
|
|
286
286
|
│ ├── parent-snapshot.ts immutable spawn-time parent state
|
|
287
287
|
│ ├── child-lifecycle.ts child-execution lifecycle event publisher
|
|
@@ -296,7 +296,7 @@ src/
|
|
|
296
296
|
│
|
|
297
297
|
├── service/ cross-extension API boundary
|
|
298
298
|
│ ├── service.ts SubagentsService interface + Symbol.for() accessors
|
|
299
|
-
│ └── service-adapter.ts SubagentsServiceAdapter class wrapping
|
|
299
|
+
│ └── service-adapter.ts SubagentsServiceAdapter class wrapping SubagentManager
|
|
300
300
|
│
|
|
301
301
|
├── tools/ LLM-facing tool implementations
|
|
302
302
|
│ ├── agent-tool.ts subagent tool definition, validation, dispatch
|
|
@@ -334,7 +334,7 @@ Record statistics (tool uses, token usage, compaction counts) are updated by `re
|
|
|
334
334
|
UI streaming (active tools, response text, turn counts) is handled by `ui/ui-observer.ts`, which subscribes to the same session events independently.
|
|
335
335
|
Neither observer wraps or forwards the other — both subscribe directly to the session.
|
|
336
336
|
|
|
337
|
-
The widget reads agent state by polling a shared `Map<string, AgentActivityTracker>` on `SubagentRuntime` every 80 ms. The conversation viewer subscribes to session events via `
|
|
337
|
+
The widget reads agent state by polling a shared `Map<string, AgentActivityTracker>` on `SubagentRuntime` every 80 ms. The conversation viewer subscribes to session events via `Subagent.subscribeToUpdates()` and reads messages via `Subagent.messages` — no direct `AgentSession` reference (#277).
|
|
338
338
|
|
|
339
339
|
## Cross-extension architecture
|
|
340
340
|
|
|
@@ -343,7 +343,7 @@ flowchart TD
|
|
|
343
343
|
subgraph core["@gotgenes/pi-subagents"]
|
|
344
344
|
direction TB
|
|
345
345
|
exports["SubagentsService API<br/>publish / getSubagentsService<br/>SubagentRecord, SubagentStatus"]
|
|
346
|
-
engine["Tools: subagent, get_subagent_result,<br/>steer_subagent<br/>
|
|
346
|
+
engine["Tools: subagent, get_subagent_result,<br/>steer_subagent<br/>SubagentManager, createSubagentSession, SubagentSession"]
|
|
347
347
|
ui_int["Internal UI: widget, viewer,<br/>/agents menu"]
|
|
348
348
|
end
|
|
349
349
|
|
|
@@ -358,14 +358,14 @@ They declare this package as an optional peer dependency and use dynamic import
|
|
|
358
358
|
### What the core owns
|
|
359
359
|
|
|
360
360
|
- The three tools: `subagent` (née `Agent`), `get_subagent_result`, `steer_subagent`.
|
|
361
|
-
- `
|
|
361
|
+
- `SubagentManager` — spawn, abort, resume, collection management, observer wiring.
|
|
362
362
|
- `ConcurrencyQueue` — background agent scheduling with configurable concurrency limit.
|
|
363
363
|
- `createSubagentSession` — assembly factory: session creation and extension binding; returns a born-complete `SubagentSession`.
|
|
364
364
|
- `SubagentSession` — the born-complete child session: drives the turn loop (`runTurnLoop`/`resumeTurnLoop`), steers, and disposes (firing `disposed` at true session disposal, so resume executions are registry-detected).
|
|
365
365
|
- `child-lifecycle` — publishes the child-execution lifecycle (`spawning`, `session-created` before `bindExtensions()`, `completed`, `disposed`) on `pi.events`.
|
|
366
366
|
Reactive consumers subscribe: `@gotgenes/pi-permission-system` registers each child session on `session-created` and unregisters it on `disposed`.
|
|
367
|
-
This replaced the former outbound `permission-bridge` (#261, ADR
|
|
368
|
-
- `workspace` — the single generative seam (#262, ADR
|
|
367
|
+
This replaced the former outbound `permission-bridge` (#261, [ADR-0002]) — the core no longer looks up a named consumer.
|
|
368
|
+
- `workspace` — the single generative seam (#262, [ADR-0002]): a registered `WorkspaceProvider` supplies a child's cwd plus bracketed `dispose()` at run-start.
|
|
369
369
|
With no provider, children run in the parent cwd (default unchanged); the git worktree strategy lives behind this seam in `@gotgenes/pi-subagents-worktrees` (#263, the seam's first consumer).
|
|
370
370
|
- `session-config` — pure configuration assembler (called by `createSubagentSession`).
|
|
371
371
|
- `SubagentRuntime` — session-scoped state bag with methods.
|
|
@@ -373,7 +373,7 @@ They declare this package as an optional peer dependency and use dynamic import
|
|
|
373
373
|
- `record-observer` — session-event observer that updates record statistics without callback threading.
|
|
374
374
|
- Agent type registry — default agents, custom `.md` file loading.
|
|
375
375
|
- Prompt assembly, context extraction, skills, environment.
|
|
376
|
-
- Worktree isolation — evicted to `@gotgenes/pi-subagents-worktrees` via the workspace provider seam in Phase 16 (#263, ADR
|
|
376
|
+
- Worktree isolation — evicted to `@gotgenes/pi-subagents-worktrees` via the workspace provider seam in Phase 16 (#263, [ADR-0002]); `git` no longer appears in the core.
|
|
377
377
|
- Token usage tracking.
|
|
378
378
|
- Session directory derivation and persisted `SessionManager` for subagent transcripts.
|
|
379
379
|
- Settings persistence.
|
|
@@ -478,7 +478,7 @@ Extensions attach through exactly two surfaces, distinguished by the direction o
|
|
|
478
478
|
Reactive concerns live here: permission detection, telemetry, UI, notifications.
|
|
479
479
|
Adding a reactive concern never modifies the core.
|
|
480
480
|
2. **Provider seams (generative) — rationed.**
|
|
481
|
-
The rare concern that must
|
|
481
|
+
The rare concern that must _inject_ a value the core consumes synchronously registers a provider the core consults.
|
|
482
482
|
Today there is exactly one: the **workspace provider** (returns the child's working directory plus bracketed setup/teardown).
|
|
483
483
|
A provider seam is the only place the core is "open," so the list is kept as small as possible.
|
|
484
484
|
|
|
@@ -487,7 +487,7 @@ The discriminator when deciding how a concern attaches:
|
|
|
487
487
|
- It only needs to **know** what happened → subscribe to a lifecycle event (observational, unlimited).
|
|
488
488
|
- It must **return a value the core consumes** → register a provider (generative, rationed).
|
|
489
489
|
|
|
490
|
-
The governing rule — **no vacant hooks**: the architecture must
|
|
490
|
+
The governing rule — **no vacant hooks**: the architecture must _admit_ a seam without _shipping_ it until a concrete consumer exists.
|
|
491
491
|
A provider seam with no consumer is a speculative abstraction that taxes every reader and that `fallow` flags as dead.
|
|
492
492
|
Latent extensibility is the deliverable; a vacant hook is not.
|
|
493
493
|
|
|
@@ -509,11 +509,11 @@ Latent extensibility is the deliverable; a vacant hook is not.
|
|
|
509
509
|
- **Tool policy** (`disallowed_tools`) — access control belongs in pi-permission-system's `permission:` frontmatter.
|
|
510
510
|
- **Extension filtering** (`extensions: string[]` allowlist) — tool visibility is pi-permission-system's job.
|
|
511
511
|
- **Worktree isolation** (`worktree.ts`, `worktree-isolation.ts`, `GitWorktreeManager`, the `isolation: "worktree"` spawn mode) — environment policy, not core.
|
|
512
|
-
Git worktrees are one
|
|
512
|
+
Git worktrees are one _strategy_ for choosing the child's working directory; containers, throwaway tmpdirs, and remote sandboxes are others.
|
|
513
513
|
Evicted to `@gotgenes/pi-subagents-worktrees` (#263), the first consumer of the workspace provider seam.
|
|
514
514
|
- **Extension lifecycle control** (`extensions: false`, `isolated`, `noSkills`) — removed in #264.
|
|
515
515
|
Deny-at-use (the in-child permission layer blocking disallowed tool calls) covers what `isolated` pretended to do for tools.
|
|
516
|
-
Prevent-load (refusing to bind an extension because of load-time side effects, cost, or true sandboxing) is genuinely generative and is left as a
|
|
516
|
+
Prevent-load (refusing to bind an extension because of load-time side effects, cost, or true sandboxing) is genuinely generative and is left as a _latent_ (un-built) provider seam, added only if a real consumer needs it.
|
|
517
517
|
|
|
518
518
|
### Composition model
|
|
519
519
|
|
|
@@ -563,7 +563,7 @@ Bags with 10+ fields are the highest priority for decomposition.
|
|
|
563
563
|
| `AgentToolDeps` | 8 | agent-tool | ✓ done |
|
|
564
564
|
| `AgentMenuDeps` | 8 | agent-menu | ✓ done |
|
|
565
565
|
| `ConversationViewerOptions` | 8 | conversation-viewer | Low |
|
|
566
|
-
| `
|
|
566
|
+
| `SubagentInit` | 8 | subagent | Low |
|
|
567
567
|
|
|
568
568
|
### Complexity hotspots
|
|
569
569
|
|
|
@@ -595,19 +595,19 @@ One 11-line internal clone group remains within `agent-config-editor.ts` (lines
|
|
|
595
595
|
|
|
596
596
|
### Session encapsulation debt (Law of Demeter) — resolved by [#277] ✔️
|
|
597
597
|
|
|
598
|
-
All consumer reach-throughs to the raw SDK `AgentSession` via `
|
|
599
|
-
`
|
|
598
|
+
All consumer reach-throughs to the raw SDK `AgentSession` via `Subagent.session` have been eliminated.
|
|
599
|
+
`Subagent.session` is removed; `SubagentSession.session` is marked `@internal` (lifecycle use only).
|
|
600
600
|
The intent-revealing replacements added by [#277]:
|
|
601
601
|
|
|
602
|
-
| Reach-through | Sites | Replacement
|
|
603
|
-
| ---------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
604
|
-
| Steer buffer-or-deliver (was duplicated) | `service-adapter.ts`, `steer-tool.ts` | `
|
|
605
|
-
| Conversation viewing | `get-result-tool.ts`, `agent-menu.ts`, `conversation-viewer.ts` | `
|
|
606
|
-
| Session-readiness guard | `agent-tool.ts`, `
|
|
607
|
-
| Context-window stats | `steer-tool.ts`, `get-result-tool.ts`, `notification.ts`, `conversation-viewer.ts` | `
|
|
608
|
-
| Live updates (subscription) | `conversation-viewer.ts` | `
|
|
609
|
-
| Observer callback session param | `background-spawner.ts`, `foreground-runner.ts` | `
|
|
610
|
-
| Session disposal | `
|
|
602
|
+
| Reach-through | Sites | Replacement |
|
|
603
|
+
| ---------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
604
|
+
| Steer buffer-or-deliver (was duplicated) | `service-adapter.ts`, `steer-tool.ts` | `Subagent.steer(message)` |
|
|
605
|
+
| Conversation viewing | `get-result-tool.ts`, `agent-menu.ts`, `conversation-viewer.ts` | `Subagent.getConversation()` / `Subagent.messages` |
|
|
606
|
+
| Session-readiness guard | `agent-tool.ts`, `subagent-manager.ts` | `Subagent.isSessionReady()` |
|
|
607
|
+
| Context-window stats | `steer-tool.ts`, `get-result-tool.ts`, `notification.ts`, `conversation-viewer.ts` | `Subagent.getContextPercent()` |
|
|
608
|
+
| Live updates (subscription) | `conversation-viewer.ts` | `Subagent.subscribeToUpdates(fn)` |
|
|
609
|
+
| Observer callback session param | `background-spawner.ts`, `foreground-runner.ts` | `subagent.subagentSession` (narrowed callback) |
|
|
610
|
+
| Session disposal | `subagent-manager.ts` | `SubagentSession.dispose()` — resolved by [#265] |
|
|
611
611
|
|
|
612
612
|
### Proposed bag decompositions
|
|
613
613
|
|
|
@@ -757,10 +757,10 @@ See [phase-15-domain-model-evolution.md](history/phase-15-domain-model-evolution
|
|
|
757
757
|
|
|
758
758
|
## Phase 16 (complete)
|
|
759
759
|
|
|
760
|
-
Phase 16 inverted the core's outbound dependencies: worktree isolation joined permissions as an
|
|
760
|
+
Phase 16 inverted the core's outbound dependencies: worktree isolation joined permissions as an _extension_ on a minimal core, leaving pi-subagents a pure child-session orchestrator.
|
|
761
761
|
The core now attaches extensions through exactly two surfaces — observational lifecycle events (unlimited) and rationed generative provider seams (today only the workspace provider) — and has zero knowledge of its consumers.
|
|
762
|
-
The "runner" concept is gone: `createSubagentSession()` returns a born-complete `SubagentSession` that owns turn driving, steering, and disposal, and `
|
|
763
|
-
The decision and the full reasoning chain are recorded in [ADR
|
|
762
|
+
The "runner" concept is gone: `createSubagentSession()` returns a born-complete `SubagentSession` that owns turn driving, steering, and disposal, and `Subagent.run()` is coordination, not assembly.
|
|
763
|
+
The decision and the full reasoning chain are recorded in [ADR-0002]; the two-surface extension model is described under [Target architecture](#target-architecture).
|
|
764
764
|
All five steps are closed: [#261], [#262], [#263], [#264], [#265].
|
|
765
765
|
The earlier "agent collaborator architecture" framing (#256 superseded, #257 parked, #258 and #259 closed not-planned) was abandoned; its structural win was reached cleanly via the workspace seam.
|
|
766
766
|
See [phase-16-invert-dependencies.md](history/phase-16-invert-dependencies.md) for details.
|
|
@@ -816,7 +816,7 @@ Detailed records are preserved in per-phase history files:
|
|
|
816
816
|
| Phase 14 | #237, #238, #239, #242 | Remove disallowed_tools, remove extensions filtering, collapse filterActiveTools, rename Agent to subagent |
|
|
817
817
|
| Phase 15 | #227, #228, #231, #229, #230, #232 | Agent domain model, async startAgent, runner self-contained, Agent.run(), ConcurrencyQueue, Agent.resume() |
|
|
818
818
|
| Phase 16 | #261, #262, #263, #264, #265 | Lifecycle events (retire permission-bridge), WorkspaceProvider seam, extract worktrees package, remove isolated, born-complete execution / dissolve runner |
|
|
819
|
-
| Phase 16 (abandoned) | #256 (superseded), #257 (parked), #258, #259 (not planned) | Agent collaborator architecture — replaced by the inversion approach above (ADR
|
|
819
|
+
| Phase 16 (abandoned) | #256 (superseded), #257 (parked), #258, #259 (not planned) | Agent collaborator architecture — replaced by the inversion approach above ([ADR-0002]) |
|
|
820
820
|
|
|
821
821
|
The remaining open issue is #22 (parent-session resolution), a cross-extension track that does not gate the structural work.
|
|
822
822
|
|
|
@@ -861,3 +861,4 @@ The upstream test suite is run periodically as a regression canary for the sessi
|
|
|
861
861
|
[#264]: https://github.com/gotgenes/pi-packages/issues/264
|
|
862
862
|
[#265]: https://github.com/gotgenes/pi-packages/issues/265
|
|
863
863
|
[#277]: https://github.com/gotgenes/pi-packages/issues/277
|
|
864
|
+
[ADR-0002]: ../decisions/0002-extensions-on-a-minimal-core.md
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Summary
|
|
4
4
|
|
|
5
5
|
Phase 16 reclaimed its original intent — invert the core's outbound dependencies — and extended it: worktree isolation joined permissions as an *extension* on a minimal core, leaving pi-subagents a pure child-session orchestrator.
|
|
6
|
-
The decision and the full reasoning chain are recorded in [ADR
|
|
6
|
+
The decision and the full reasoning chain are recorded in [ADR-0002]; the two-surface extension model is described under [Target architecture](../architecture.md#target-architecture).
|
|
7
7
|
|
|
8
8
|
All five steps are closed: [#261], [#262], [#263], [#264], [#265].
|
|
9
9
|
|
|
@@ -141,3 +141,4 @@ Composition test: install neither extension, only permissions, only workspaces,
|
|
|
141
141
|
[#263]: https://github.com/gotgenes/pi-packages/issues/263
|
|
142
142
|
[#264]: https://github.com/gotgenes/pi-packages/issues/264
|
|
143
143
|
[#265]: https://github.com/gotgenes/pi-packages/issues/265
|
|
144
|
+
[ADR-0002]: ../../decisions/0002-extensions-on-a-minimal-core.md
|
|
@@ -27,7 +27,7 @@ A `tsc --traceResolution` of a sibling consuming the package surfaced two compou
|
|
|
27
27
|
The public entry's type closure is deeply entangled: `WorkspaceProvider` (in `lifecycle/workspace.ts`) reaches `AgentStatus` in the 510-line `lifecycle/agent.ts`, plus `SubagentType`/`AgentInvocation` from `types.ts` (which itself re-exports the `Agent` class).
|
|
28
28
|
A shallow alias-free entry is therefore not achievable without a substantial source restructure.
|
|
29
29
|
|
|
30
|
-
This collides with the ship-source model (ADR
|
|
30
|
+
This collides with the ship-source model ([ADR-0002]): every package ships raw `.ts` executed directly by Pi, with no build step.
|
|
31
31
|
|
|
32
32
|
## Decision
|
|
33
33
|
|
|
@@ -67,3 +67,5 @@ It is deliberately narrow: it produces type declarations only and changes nothin
|
|
|
67
67
|
- The `types` condition points at a build-time artifact; an in-repo workspace-linked consumer that imported the package would need `dist/public.d.ts` present.
|
|
68
68
|
This is acceptable because no in-repo package imports the surface yet; #263 consumes the built artifact from the published tarball.
|
|
69
69
|
- Sequencing: #270 must be published (its release-please PR merged) before #263 edits `pi-subagents` core, so #263's changes do not batch into the same `pi-subagents` release.
|
|
70
|
+
|
|
71
|
+
[ADR-0002]: ./0002-extensions-on-a-minimal-core.md
|
|
@@ -3,14 +3,14 @@ issue: 51
|
|
|
3
3
|
issue_title: "docs: update ADR 0001 to reflect hard-fork decision"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Update ADR
|
|
6
|
+
# Update ADR-0001 to reflect hard-fork decision
|
|
7
7
|
|
|
8
8
|
## Problem Statement
|
|
9
9
|
|
|
10
|
-
ADR
|
|
10
|
+
[ADR-0001] was written when the fork was a thin-patch layer over `tintinweb/pi-subagents`.
|
|
11
11
|
The new architecture document (`docs/architecture/architecture.md`) commits to a hard fork with material scope reduction — scheduling removal, a `SubagentsAPI` boundary, `index.ts` decomposition, and more.
|
|
12
12
|
|
|
13
|
-
Several claims in ADR
|
|
13
|
+
Several claims in [ADR-0001] are now outdated:
|
|
14
14
|
|
|
15
15
|
1. The status is "accepted" but the decision has been superseded by the architecture doc.
|
|
16
16
|
2. The Upstream PRs section states "the fork's divergence reduces to package naming and tooling," which is no longer true.
|
|
@@ -18,7 +18,7 @@ Several claims in ADR 0001 are now outdated:
|
|
|
18
18
|
|
|
19
19
|
## Goals
|
|
20
20
|
|
|
21
|
-
- Add a supersession note to ADR
|
|
21
|
+
- Add a supersession note to [ADR-0001] pointing to `docs/architecture/architecture.md`.
|
|
22
22
|
- Update the "Upstream PRs are open" subsection so the "divergence reduces to…" claim reflects reality.
|
|
23
23
|
- Update the Consequences → Operational section to note intentional divergence per the architecture document.
|
|
24
24
|
- Preserve all existing rationale — no information is removed.
|
|
@@ -31,7 +31,7 @@ Several claims in ADR 0001 are now outdated:
|
|
|
31
31
|
|
|
32
32
|
## Background
|
|
33
33
|
|
|
34
|
-
ADR
|
|
34
|
+
[ADR-0001] has YAML frontmatter (`status: accepted`, `date: 2026-05-11`) and follows a standard ADR structure: Status, Context, Decision, Consequences.
|
|
35
35
|
|
|
36
36
|
The architecture document (`docs/architecture/architecture.md`) describes a six-phase plan that materially diverges from upstream: scheduling removal, ad-hoc RPC replacement, group-join and output-file removal, a typed `SubagentsAPI` boundary, and `index.ts` decomposition.
|
|
37
37
|
|
|
@@ -60,7 +60,7 @@ No tests are affected — this is a docs-only change.
|
|
|
60
60
|
|
|
61
61
|
## TDD Order
|
|
62
62
|
|
|
63
|
-
1. Update ADR
|
|
63
|
+
1. Update [ADR-0001] with all four edits described above.
|
|
64
64
|
Commit: `docs: update ADR 0001 to reflect hard-fork decision (#51)`
|
|
65
65
|
|
|
66
66
|
## Risks and Mitigations
|
|
@@ -73,3 +73,5 @@ No tests are affected — this is a docs-only change.
|
|
|
73
73
|
## Open Questions
|
|
74
74
|
|
|
75
75
|
None — the issue's acceptance criteria are unambiguous.
|
|
76
|
+
|
|
77
|
+
[ADR-0001]: ../decisions/0001-deferred-patches.md
|
|
@@ -6,7 +6,7 @@ issue_title: "Extract ChildSessionFactory from runner"
|
|
|
6
6
|
# Extract ChildSessionFactory from runner
|
|
7
7
|
|
|
8
8
|
> Superseded — issue #257 was closed `not_planned`.
|
|
9
|
-
> Planning this extraction exposed that worktree isolation does not belong in the core; see [ADR
|
|
9
|
+
> Planning this extraction exposed that worktree isolation does not belong in the core; see [ADR-0002] and the reclaimed Phase 16 roadmap in [`docs/architecture/architecture.md`](../architecture/architecture.md).
|
|
10
10
|
> The structural goal is recovered by #265.
|
|
11
11
|
> This plan is retained for historical context only.
|
|
12
12
|
|
|
@@ -281,3 +281,5 @@ After all steps: `pnpm run check`, `pnpm run lint`, `pnpm -r run test`, `pnpm fa
|
|
|
281
281
|
Deferred to Step 4, when the runner dissolves and the natural home for these creation contracts is the factory module.
|
|
282
282
|
- Whether `ConcreteAgentRunner.createFactory()` lands in Step 3 (when `AgentManager` consumes it) exactly as the issue describes.
|
|
283
283
|
Deferred to Step 3 per the Design Overview rationale.
|
|
284
|
+
|
|
285
|
+
[ADR-0002]: ../decisions/0002-extensions-on-a-minimal-core.md
|