Files
makelore/.project-docs/30-worklog/tasks/20260823-pi-child-workers-5c8e2a71.md
T

9.4 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: Planner corrections complete; re-review pending

Scope

  • Implement PI-080 — Subagent scheduler and nested protocol on top of the cumulative PI-070 baseline b806c78139aa11e338c680d4c3fa92e076901aa2.
  • Own the Main-private child scheduler/supervisor, managed ephemeral child Pi opener, parent-child lifecycle registry, global child concurrency limit, and strict subagent.v1 validation/projection.
  • Extend the single managed Makelore Pi extension and its authenticated Main bridge only as needed to dispatch single, parallel, and chain child 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, ticket PI-080, Spec UX-041 through UX-044, EXT-001 through EXT-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-only or coding tool profile. Child sessions are not persisted as recoverable user Conversations and children cannot recursively dispatch more subagents.
  • Reuse the same application PiProcessBudget as 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 PiSubagentScheduler with strict one-to-eight task validation, single/parallel/chain execution, one FIFO four-child semaphore, a parent/run dispatch registry, shared PiProcessBudget acquisition, idle parent reclamation when the eight-process budget is full, and deterministic abort/error/skipped projection without raw child errors.
  • Planner review of f1c7cd8 found 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.
  • 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_user and subagent; child workers expose neither and retain only the shared mutation-lease hooks required by coding tools. The authenticated loopback bridge streams only NDJSON subagent.v1 details and rejects recursive child dispatch and stale identities.
  • Planner review of f1c7cd8 also found that Pi 0.84.2 treats --tools as a strict whitelist across built-in and extension tools. The managed parent default now explicitly includes subagent; child read-only/coding lists remain exact and exclude both subagent and ask_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.v1 projection 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.
  • PiConversationRuntime now 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; and unknown schema/version raw-payload suppression.
  • 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 at session_start: the parent includes subagent, while the child is exactly read,grep,find,ls.
  • pnpm run test:pi-subagent:packaged passed 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, verifies get_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 production npm ci on every unit run.
  • The real materialized extension bundle test executes subagent through 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, 106 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.
  • First full-suite run, executed concurrently with the build, passed 2208/2209 and hit the known Windows temporary JSON rename EPERM in the unchanged conversation store. The failing test passed in isolation, then the serial full-suite rerun passed. After planner corrections the final serial full suite passed: 202 files, 2209 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 PiProcessBudget to both the parent pool and child scheduler, preserve child-priority budget reservations ahead of normal parent-start waiters, and wire the scheduler's capacity reclaimer to PiWorkerPool.reclaimIdleWorker. 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.