13 KiB
13 KiB
Task: Implement PI-080 child workers and subagent runtime
Identity
- Task ID: 20260823-pi-child-workers-5c8e2a71
- Mode: Feature
- Branch: codex/20260823-pi-child-workers-5c8e2a71-pi-child-workers
- Worktree: D:\Datas\OthersProjects\makelore-pi-child-workers-5c8e2a71
- Base commit:
b806c78139 - Owner: codex
- Status: Ready for integration
Scope
- Implement
PI-080 — Subagent scheduler and nested protocolon top of the cumulative PI-070 baselineb806c78139aa11e338c680d4c3fa92e076901aa2. - Own the Main-private child scheduler/supervisor, managed ephemeral child Pi
opener, parent-child lifecycle registry, global child concurrency limit, and
strict
subagent.v1validation/projection. - Extend the single managed Makelore Pi extension and its authenticated Main
bridge only as needed to dispatch
single,parallel, andchainchild work and stream stable product details back to the parent tool. - Add fake scheduler integration coverage, real Pi child process smoke, process/semaphore leak coverage, bridge identity/abort coverage, and same-project parent/child write-lease coverage. Renderer/Host product routes and final nested UI remain owned by later tickets.
Intent And Constraints
- Follow planner task
20260822-pi-runtime-spec-b6e2c9a4, ticketPI-080, SpecUX-041throughUX-044,EXT-001throughEXT-006, and section 9.4. - A dispatch accepts exactly one mode, contains at most eight bounded tasks,
and resolves only through Makelore-owned
subagent.v1; unknown schema or raw Pi/example details never enter product state or diagnostics. - Every child owns an independent ephemeral Pi process/context and uses an
enabled project Agent's managed prompt, skills, model, credentials, and one
exact
read-onlyorcodingtool profile. Child sessions are not persisted as recoverable user Conversations and children cannot recursively dispatch more subagents. - Reuse the same application
PiProcessBudgetas parent workers for the locked parent/child soft cap of eight and enforce one global FIFO maximum of four running children across all parents. Do not add a competing process counter. - Reuse PI-070's single project mutation lease. A coding child loads the same managed extension lease hooks as its parent; read-only children receive no mutation tools. Do not introduce child worktrees or a second mutation lock.
- Parent abort/crash/recover/dispose, stale generation/run identity, bridge disconnect, and host shutdown cancel unfinished children and release every child/process permit. Parallel failures preserve sibling results; chain failure marks the remaining tasks skipped.
- Keep Provider credentials in the child environment/redaction set only. Real
external Provider validation remains Explicitly Waived / Accepted Risk
with
realTurnVerified=false; macOS x64/arm64 remains deferred to mandatory PI-150. Neither is a Pass. - Keep the change surgical: no dual runtime, generic plugin/permission system, project/user Pi discovery, Renderer wire changes, Host product routes, OpenCode refactor, or canonical project-memory edits.
Outcome
- Added the Main-private
PiSubagentSchedulerwith strict one-to-eight task validation, single/parallel/chain execution, one FIFO four-child semaphore, a parent/run dispatch registry, sharedPiProcessBudgetacquisition, idle parent reclamation when the eight-process budget is full, and deterministic abort/error/skipped projection without raw child errors. - Planner review of
f1c7cd8found that a previously queued parent process budget waiter could take a reclaimed idle permit before the child. The corrected budget keeps normal waiters FIFO, keeps child waiters FIFO, and prioritizes child reservations so a running parent cannot deadlock while waiting on its own child. The child enters the priority queue before idle reclamation releases capacity. - Planner re-review of
3de85d6confirmed the original three findings closed, then reproduced two further supported failure paths: a child reservation could wait forever when no parent was idle during the one-time reclaim but a spawning/running parent became reclaimable later; and reclaim/worker-stop failure could leave an unowned process lease. The pool now wakes pending reclaimers onready/idlestate transitions without polling. Scheduler reservations race direct capacity against this cancellable event-driven reclaim and always settle/release on reclaim rejection, parent abort, or any other early exit. Parentstop()now releases its process lease infinally. - Planner re-review of
a10b98econfirmed both lease-lifecycle findings closed, then reproduced the production-capacity shape4 running + 4 queued: queued parent workers retained all eight process leases, leaving no ready/idle worker for four children to reclaim. The pool now prefers ready/idle eviction, then suspends the oldest queued parent process while retaining its top-level FIFO entry, Conversation state, and session binding. When its turn arrives, the same queue entry reopens that session as a new worker generation before sending the original prompt. This closes the deadlock without dropping queued work, reordering it, adding another queue, or exceeding the shared eight-process cap. - Planner re-review of
1727b75confirmed the 4+4 deadlock closed, then reproduced a supported stop/dispatch overlap: a queued worker could be selected while its suspensionstop()was still pending, soensureFreshsaw the not-yet-released old lease and sent the prompt to a stopping generation.ensureFreshnow awaits any existingprocessStopFlight, rechecks record ownership/rebuild state, and only then reopens a lease-less worker. The old generation never receives the queued prompt. - Final planner review of
30c8bfdpassed with zero Standards findings and zero Spec findings. Independent reproduction confirmed the exact stop/slot overlap and the production-defaultmaxRunning=4,maxIdle=4,maxProcesses=84+4 path; PI-080 is Done and the ready frontier advances to PI-090 and PI-100. - Added the managed ephemeral child opener. It resolves only enabled,
unarchived project Agents from
.niancode/project.json, materializes their exact model/prompt/skills, keeps credentials in the child environment and redaction set, selects the exact read-only or coding tools, uses--no-session, and returns bounded public summary/usage data. - Upgraded the single materialized Makelore extension bundle to v2. Parent
workers expose
ask_userandsubagent; child workers expose neither and retain only the shared mutation-lease hooks required by coding tools. The authenticated loopback bridge streams only NDJSONsubagent.v1details and rejects recursive child dispatch and stale identities. - Planner review of
f1c7cd8also found that Pi 0.84.2 treats--toolsas a strict whitelist across built-in and extension tools. The managed parent default now explicitly includessubagent; child read-only/coding lists remain exact and exclude bothsubagentandask_user. - Connected subagent dispatches to PI-070 generation resource cancellation so parent abort/crash/recover/dispose and bridge disconnect stop unfinished children and release child/process permits. Coding children join the same project write lease as their parent.
- Added vendor-neutral strict
subagent.v1projection for live events, durable session hydration, and reducer validation. Unknown versions render one fixed unavailable message and never copy their raw payload into product state. PiConversationRuntimenow configures the scheduler/bridge against the existing pool generation tracker. Final product cutover and nested Renderer presentation remain outside this ticket.
Verification
- Focused scheduler, managed-child, bridge, bundle, projector, session, process
and contract tests passed, including: 1/4/8 task coverage and ninth-task
rejection; two-parent global child concurrency of four; full-budget idle
parent reclamation; parallel sibling preservation; chain skip/abort rules;
parent generation cancellation with no orphan and zero leaked permits;
recursive child rejection; parent/child same-project write-lease queuing;
unknown schema/version raw-payload suppression; first reclaim finding no
idle followed by delayed parent readiness and automatic child execution;
reclaim rejection/abort with zero queued lease; and stop rejection with zero
active/waiting lease. A production-scale regression also covers four running
plus four queued parents dispatching four parallel children: all four queued
workers suspend, all children complete, and the queued parents then resume
FIFO with unchanged session bindings and generation 2. Their
stop()calls are deliberately held behind a gate while an earlier parent settles; the test confirms no prompt reaches the stopping generation before the gate and the original prompt reaches only the reopened generation. - Locked real Pi 0.84.2 workspace smoke passed for both the parent worker and
an ephemeral read-only child launched through Electron Node with the child
extension role and
--no-session. A probe extension reads Pi's actual active-tool list atsession_start: the parent includessubagent, while the child is exactlyread,grep,find,ls. pnpm run test:pi-subagent:packagedpassed 3/3. The dedicated runner uses PI-030's production bundler to create and validate a temporary staged production closure/manifest, then starts the staged Pi CLI as an ephemeral read-only child, verifiesget_state, the exact active tools and child extension role, and clean stdin shutdown. The normal suite skips only this staging case so it does not perform a productionnpm cion every unit run.- The real materialized extension bundle test executes
subagentthrough the authenticated Main bridge; the active-tool process probes and bridge execute test jointly cover visibility and tool invocation without an external Provider. - All cumulative Pi tests passed: 22 files, 111 passed and 1 staged-only skipped; the staged-only command passed separately as described above.
pnpm run typecheck: passed.pnpm run lint:check: passed with 0 errors and 6 pre-existing frontend warnings outside this task.pnpm run build:vite: passed for Renderer, Main, Preload, and utility worker bundles; existing chunk-size/dynamic-import warnings remain.- The final full-suite first pass hit the known Windows temporary JSON
renameEPERMin the unchanged conversation store while the other 2213 tests passed. The failing runtime test passed 1/1 in isolation and the single full rerun passed: 202 files, 2214 passed and 1 staged-only skipped. - Real external Provider validation remains Explicitly Waived / Accepted
Risk with
realTurnVerified=false. Provider concurrency, credential isolation, protocol compatibility, and image-path risk are accepted rather than marked Pass. macOS x64/arm64 validation was not run and remains deferred to mandatory PI-150; it is not marked Pass.
Follow-ups
- PI-130 owns the final nested Renderer execution graph and user-facing child error/abort presentation.
- PI-150 owns final packaged provider-shaped subagent smoke and mandatory macOS x64/arm64 validation.
Promotion Candidates
- Target canonical document: Pi runtime process/concurrency architecture.
Proposal: record that child budget acquisition must reclaim an idle parent
worker when the shared eight-process budget is full; otherwise the supported
shape of four running parents plus four warm-idle parents can deadlock while
the running parents wait on children. Evidence: the focused full-budget
scheduler regression test and the shared-budget implementation in PI-080.
Future impact: any final Main composition must pass one
PiProcessBudgetto both the parent pool and child scheduler, preserve child-priority budget reservations ahead of normal parent-start waiters, and wire the scheduler's cancellable capacity reclaimer toPiWorkerPool.reclaimIdleWorker. The pool must notify an already waiting child when a spawning/running parent becomesready/idle, and stop/reclaim failure must never retain a lease. If the cap consists only of running and queued parents, it must suspend queued parent processes in FIFO-safe/LRU order, retain their queue entries and session bindings, and reopen them as a new generation when scheduled. A queued run selected while suspension is still stopping must await that stop flight and recheck ownership before it can reopen or send the prompt. Semantic conflicts: none with the accepted PI runtime specification; this makes its parent/child cap executable. Human confirmation required: no, unless integration changes the accepted process-cap policy.