Browse documentation

Advanced

Subagents and automation

Spawn bounded helpers, pass only the context they need, and run durable jobs from queues, schedules, and webhooks.

Subagents are child executions, not a second storage system. A parent thread creates a child with an explicit role, model, tool allowlist, seed history, limits, and mailbox. The child reports events and a final result to the parent.

Define a bounded child task

const child = await coordinator.spawn({
  parentThreadId: trusted.threadId,
  role: "researcher",
  agentId: "research",
  model: {
    provider: "openai",
    model: "gpt-5.6-mini",
  },
  mode: "ask",
  seedTurns: [
    {
      role: "user",
      content: "Find the current refund policy in the approved sources.",
    },
  ],
  limits: {
    maxSteps: 8,
    maxToolCalls: 12,
    maxDurationMs: 90_000,
  },
});

Pass zero seed turns when the child needs only a task statement. Pass a small number of recent turns when context is necessary. Do not copy an entire conversation by default.

Parent and child communication

The parent can wait for a child, send a follow-up, or read the child result through the coordinator. Child tools use the same mode, capability, approval, tenant, and connection checks as a normal thread.

await coordinator.send(child.id, {
  type: "instruction",
  content: "Compare the two sources and return one recommendation.",
});

for await (const event of coordinator.observe(child.id)) {
  publishToParent(event);
}

Use bounded fan-out for independent research. Keep writes in the parent or serialize them by workspace resource. A child must not receive a stronger credential or tenant scope than its parent.

Tool and cost limits

Set limits on every child:

  • Maximum steps and model calls.
  • Maximum tool calls and parallel calls.
  • Maximum duration.
  • Maximum output or total tokens.
  • Maximum cost when the provider reports cost.
  • Allowed tools and mode.

The parent remains responsible for accepting a child result. Do not import untrusted child output into a write tool without validation and, when needed, approval.

Scheduled and webhook work

Flary exports Cloudflare adapters for scheduled jobs, webhooks, and queue workers. The host authenticates a webhook or schedule, creates a run with a stable idempotency key, and returns quickly.

export default {
  async scheduled(controller, env, execution) {
    const run = await env.RUNS.create({
      tenantId: "system",
      applicationId: "reports",
      agentId: "weekly-report",
      request: {
        requestId: "weekly:" + controller.scheduledTime,
        channelId: "weekly-report",
        input: { week: new Date(controller.scheduledTime).toISOString() },
        idempotencyKey: "weekly:" + controller.scheduledTime,
      },
    });

    execution.waitUntil(env.RUNS.execute(run.runId));
  },
};

For a long job, the accepted run is the durable record. The webhook response does not stay open while the model, tools, or child agents work.

Common patterns

Pattern Use
Fan-out research Several ask-mode children read independent sources
Review gate A review child checks a build result before the parent requests approval
Background sync A schedule starts a run with an idempotent timestamp key
Reactive support A signed webhook starts a support run for a new ticket
Build pipeline A build run invokes Sandbox only for explicit test or deploy jobs

Subagents share Flary’s event, usage, history, and tenant contracts. The host still decides retention, quotas, and whether a child is visible to the end user.