Crux
API Reference@use-crux/core

Backgroundable Agent Work

Exact process-local backgroundable(), Work reference, automatic work Tool, and safe status contracts.

import { backgroundable } from "@use-crux/core/agent";
import type { BackgroundableAgent } from "@use-crux/core/agent";

backgroundable(agent) returns a frozen, inert BackgroundableAgent<TAgent>. It becomes executable only when used as a child entry in an Agent tools map:

const coordinator = agent({
  id: "coordinator",
  prompt: coordinatorPrompt,
  tools: { research: backgroundable(researchAgent) },
});

The export belongs to @use-crux/core/agent. Provider packages do not re-export it.

Child Tool input

The wrapper adds one reserved optional field:

Child Prompt inputProvider Tool inputChild receives
Object schemaOriginal fields plus run_in_background?: booleanOriginal validated object without the control field
Scalar or mixed-root schema{ input, run_in_background? }Validated input value
No input schema{ run_in_background? }{}

An object input schema cannot author run_in_background; preparation throws. The normal Tool validation path runs before Work acceptance.

When the field is absent or false, the call is foreground and returns the exact child output. When it is true, the Tool returns immediately without awaiting the child result:

interface WorkRef {
  readonly kind: "work.ref";
  readonly id: string;
  readonly targetId: string;
  readonly guarantees: {
    readonly execution: "process-local";
    readonly rejoin: "process-local";
  };
}

The returned object and nested guarantees are immutable.

Automatic work Tool

Exactly one automatic model-facing Tool named work is added when an Agent has at least one backgroundable child. Agents with only ordinary Tools or direct foreground child Agents do not receive it. An authored work Tool collision in the Agent or its resolved Prompt fails preparation.

Its exact input is:

interface WorkToolInput {
  readonly action: "list" | "status" | "result" | "cancel" | "detach" | "send";
  readonly id?: string;
  readonly timeout?: string;
  readonly message?: string;
}

status, result, cancel, detach, and send require id. timeout is a Crux duration string used by result. send requires a non-empty message string and is available only for Agent children retained by this owner. The schema remains stable for a backgroundable run; status remains ephemeral. This Tool is not exported for application code; it is an automatic capability for the parent model.

list and status

list returns at most 50 owner-visible entries. status returns one. Both use the same immutable, result-free projection:

interface WorkStatus {
  readonly work: WorkRef;
  readonly targetLabel: string;
  readonly state:
    | "queued"
    | "running"
    | "completed"
    | "failed"
    | "cancel-requested"
    | "cancelled";
  readonly attachment: "attached";
  readonly attempt: 1;
  readonly createdAt: string;
  readonly startedAt?: string;
  readonly finishedAt?: string;
  readonly resultAvailable: boolean;
}

Timestamps are ISO strings and appear only when applicable. targetLabel is the authored child Tool map key. No result or failure payload is included.

For any id action, an unknown id or one owned by another Agent returns:

{ status: "not_found" }

result

If Work is complete, result returns the exact child output. Otherwise it waits for the requested timeout, capped at 30 seconds; omitting timeout uses the 30-second cap. If no result becomes available, it returns the safe status projection. A rejection is represented only by lifecycle status—failure content is never returned.

cancel

Cancellation returns:

interface CancelReceipt {
  readonly workId: string;
  readonly accepted: boolean;
  readonly state: WorkStatus["state"];
  readonly acceptedAt: string;
}

Queued Work can be cancelled before it runs. Running Work first enters cancel-requested and cancellation remains cooperative. A failure unrelated to that request stays failed, and normal completion may win the race. Requests against already terminal Work are not accepted.

send

send accepts ordered supervisor guidance for a non-terminal Agent child:

interface SendReceipt {
  readonly workId: string;
  readonly id: string;
  readonly cursor: string;
  readonly acceptedAt: string;
  readonly outcome: "accepted";
}

Acceptance is immediate and idempotent for the same model tool-call identity. Raw message content is not stored in command identity records—only a payload digest. Delivery happens only at the child's next semantic provider-step boundary; the active provider call, tools, and guardrails are never mutated. Terminal or non-Agent targets reject.

detach

Detach removes the Work from the owner's visible inbox without cancelling it:

{ id: string, detached: true }

Later lookup by that owner returns { status: "not_found" }, even if the underlying execution continues.

Provider-boundary status context

Before each new semantic provider request is sealed, Core samples the owner's inbox. If Work exists, the next request can receive a non-cacheable, capped status block. At most 12 prioritized rows are included. The active provider request is immutable and is never patched after dispatch.

This automatic context contains only Work id, target label, state, elapsed time, and result availability. Child output and failure content are never injected. A result reaches the model only through an explicit result action.

Execution isolation and lifetime

The child runs only its own prompt, use, tools, and declared input. It does not inherit parent prompt/history, sibling tools, request details, or control authority.

All execution, registry, result, and control state is process-local. Process exit loses it. There is no crash recovery, remote transport, API route, cross-process or Session rejoin, durable replay, or public application Work handle. Use Flows, the Runtime Engine, or Signals when those guarantees are required; no integration is implied.

On this page