Orchestrating Multiple Agents in Flue: Task Sessions and Parent-Child Relationships Explained

Flue models every interaction as a session that can spawn isolated task sessions—detached child sessions running in parallel—that communicate through the parent's event stream, enabling complex multi-agent workflows without side effects.

Flue (from the withastro/flue repository) treats agent orchestration as a conversation tree where parent sessions delegate work to sandboxed children. By leveraging task sessions and explicit parent-child relationships, developers can build recursive agent workflows that maintain isolation while preserving a unified audit trail.

Core Architecture of Task Sessions

The FlueSession Interface

At the heart of the system lies the FlueSession interface, implemented by the Session class in packages/sdk/src/session.ts. Each session holds a harness (Agent), a sandboxed file system (FlueFs), and a SessionHistory that tracks the conversation state. This architecture ensures that every agent interaction is persistent, traceable, and capable of spawning independent sub-agents.

Session Hierarchy and Depth Limits

Flue enforces a strict maximum nesting depth of MAX_TASK_DEPTH = 4 (defined at line 78 of session.ts) to prevent runaway recursion. Each task session receives a unique storage key formatted as task:${parentSession}:${taskId}, constructed in the harness.session() implementation (lines 134‑150 of packages/sdk/src/harness.ts). The child inherits the parent’s environment variables, role, and current working directory, but runs in an isolated sandbox.

Task Session Lifecycle

The orchestration flow follows a six-step lifecycle managed by runTaskExclusive (lines 994‑1060):

  1. Invocation – The parent calls session.task(prompt, options) (lines 620‑630), which generates a task ID and enters the exclusive execution block.
  2. Depth validation – Flue checks the current nesting level against MAX_TASK_DEPTH, throwing if the limit is exceeded.
  3. Child construction – The createTaskSession factory (passed during parent initialization) builds a new Session instance with a depth counter incremented from the parent.
  4. Metadata bookkeepingrecordTaskSession (lines 2550‑2560) appends { session, taskId, storageKey } to the parent’s metadata.taskSessions array, creating a permanent record of the relationship.
  5. Prompt forwarding – The parent forwards the prompt via child.prompt (lines 1053‑1054), allowing the child to run its own harness and generate a fresh assistant turn.
  6. Result aggregation – Upon completion, the parent emits a task event (lines 1064‑1070), returns the child’s assistant text, and optionally persists the full PromptResultResponse when a schema is supplied.

All active children are tracked in Session.activeTasks (line 219), enabling bulk lifecycle operations.

Parent-Child Communication Patterns

Event Propagation

Child sessions report lifecycle events (task_start, task, operation_start) through the parent’s emit method. The parent decorates each event with its own session ID (line 1634) before forwarding it to listeners registered via init({ onAgentEvent }). This design provides a unified, ordered stream of sub-agent activity without requiring external message brokers.

History Isolation

Unlike shared-memory architectures, Flue keeps conversation branches isolated. The child’s messages are not automatically merged into the parent’s tree. Instead, the parent updates its own SessionHistory only after the child finishes, through recordTaskSession and subsequent save() calls. This preserves the full execution graph while preventing context contamination between agents.

Compaction Independence

Each task session manages its own token budget and compaction cycle. The parent’s checkCompaction logic (lines 1260‑1280) inspects only the parent’s messages, ensuring that a child’s summarization never interferes with the parent’s context window.

The Built-in Task Tool

The harness automatically exposes orchestration capabilities to the LLM through the task tool. During session construction, createBuiltinTools (line 556) registers this tool, which forwards LLM-generated calls to runTaskForTool (lines 908‑928). This allows models to initiate sub-tasks dynamically without explicit JavaScript invocation, bridging the gap between code-level orchestration and autonomous agent behavior.

Practical Implementation Examples

Basic Parent-to-Child Delegation

import { init } from '@flue/sdk';

const harness = init({ /* config */ });
const parent = await harness.session();

const result = await parent.task(
  'Summarize the following transcript:\n\n{{transcript}}',
  { role: 'summarizer' }
);

console.log('Child output:', result.text);

This creates a child session named task:default:<uuid> and returns the assistant’s generated text.

Monitoring Task Events

const harness = init({
  onAgentEvent: (ev) => {
    if (ev.type === 'task' && !ev.isError) {
      console.log(`[task ${ev.taskId}] completed in ${ev.durationMs}ms`);
    }
  },
});

const sess = await harness.session();
await sess.task('Write a short poem about cats');

All task_* events funnel through the onAgentEvent callback, providing a single observability surface.

Accessing Child Metadata

await sess.task('Analyze code complexity', { role: 'analyzer' });
const meta = sess.getMetadata();
const childInfo = meta.taskSessions?.find(t => t.taskId === taskId);

if (childInfo) {
  console.log('Child storage key:', childInfo.storageKey);
}

recordTaskSession guarantees that the child’s storageKey is persisted in the parent’s metadata.

Aborting All Children

// Aborts parent and every active child
await sess.abort();

The abort() implementation (lines 707‑711) walks Session.activeTasks and invokes abort() on each child session, ensuring clean teardown of distributed work.

Summary

  • Task sessions in Flue are isolated child sessions spawned via session.task(), running in parallel with depth-limited recursion (MAX_TASK_DEPTH = 4).
  • Parent-child relationships are tracked in metadata.taskSessions (populated by recordTaskSession at lines 2550‑2560), enabling persistent audit trails.
  • Communication occurs through the parent’s event stream, with children reporting to onAgentEvent while maintaining isolated conversation histories.
  • Built-in tooling exposes task creation to LLMs via the task tool (registered at line 556), enabling autonomous delegation.
  • Lifecycle management is centralized through Session.activeTasks (line 219), supporting bulk abort() operations and independent compaction cycles.

Frequently Asked Questions

What is the maximum nesting depth for task sessions in Flue?

Flue enforces a hard limit of four levels of nesting via MAX_TASK_DEPTH = 4 (line 78 of session.ts). This prevents runaway recursion when agents delegate to sub-agents that themselves spawn additional tasks.

How do parent and child sessions communicate in Flue?

Children emit lifecycle events (task_start, task, etc.) that propagate through the parent’s emit method (line 1634). The parent decorates these events with its own session ID and forwards them to the onAgentEvent callback registered in init(), creating a unified stream of sub-agent activity without shared memory.

Can child sessions modify the parent's working directory?

No. Each task session runs in its own sandboxed environment with an isolated FlueFs instance. Files written in a child’s sandbox never pollute the parent’s working directory, ensuring side-effect-free delegation according to the implementation in packages/sdk/src/session.ts.

How do I abort all running child sessions simultaneously?

Call await parent.abort() (lines 707‑711). This method walks the activeTasks array (line 219) and invokes abort() on each child session, terminating the parent and all descendants in a single operation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →