Skip to content

Support forked agents (fan-out from a shared parent context) #10

Description

@Michaelliv

Problem

Every agent() call today spawns a fresh in-memory Pi session with no prior context. For fan-out patterns where N subagents need the same expensive setup — reading a large file, walking a directory, building a mental model of a codebase — each one redoes the work from scratch.

A fork() primitive would let one subagent do the setup once, then branch N children that inherit its full state (messages, tools, cwd, model) and diverge from there.

Proposed shape

const base = await agent('Read src/ and build a mental model of the architecture.', {
  label: 'baseline',
  fork: true, // keep session alive so it can be forked
})

const reviews = await parallel(
  ['security', 'performance', 'API design'].map(angle => () =>
    base.fork(`Now review the codebase from a ${angle} perspective.`, {
      label: `${angle} review`,
    })
  )
)

Each base.fork(prompt) call:

  1. Deep-clones the parent session (messages, tool state, settings).
  2. Appends the new user prompt.
  3. Runs to completion independently. Children do not see each other.
  4. Returns text or structured output, same contract as agent().

The parent session is disposed once no live forks remain (or explicitly via base.dispose()).

Why

  • Cache reuse. Anthropic/OpenAI prompt caching keys off message prefix; forks share the prefix verbatim, so the expensive setup is paid once.
  • Less token waste. No need to serialize parent output back into N child prompts as context.
  • Cleaner scripts. The pattern "do setup, then fan out N variations" stops requiring manual prompt stitching.

Open questions

  • API surface: agent(..., { fork: true }) returning a handle vs. a dedicated fork() global. Handle feels more natural but is a bigger departure from the current "results are plain values" model.
  • Determinism: forking is deterministic w.r.t. the parent's final state, but parent + N forks running concurrently is not. Probably require the parent to settle before fork() can be called.
  • Abort: aborting the workflow should cascade to all live forks.
  • Memory: deep-cloning sessions could get heavy; may need to share immutable message arrays by reference.

Implementation sketch

WorkflowAgent.run currently disposes the session in finally. A fork-capable variant would keep the session object alive and expose a fork(prompt, opts) method that:

  1. Snapshots session.messages and settings.
  2. Calls createAgentSession with those as initial state (or clones the underlying session if pi-coding-agent exposes that).
  3. Runs as today.

Depends on what @mariozechner/pi-coding-agent exposes for session cloning — may need an upstream affordance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions