Task Primitive
Status: Design landing Reference epic: INK-825 ADRs: ADR-016, ADR-022
task() is the unified work-dispatch primitive inside the Python sidecar. It is the single entry point for dispatching a unit of agent work on LangGraph: given a shape and parameters, task() runs the work and returns a typed result. Every form of subagent dispatch — subgraph execution, persistent-sandbox investigation, and compact-result compaction — passes through task().
The primitive
Section titled “The primitive”task() takes two required arguments:
- Shape. A string key that names the kind of work to run. The sidecar maintains a shape registry — a small mapping from shape key to the LangGraph subgraph or callable that handles it.
- Params. A typed dict matching the shape’s declared parameter schema.
It returns a typed result whose shape is determined by the registered handler. The return type is never Any; every shape declares its output schema at registration time.
The caller is always a planner node or a dispatch node inside the main graph. task() is not called from outside the sidecar.
Shape registry
Section titled “Shape registry”The shape registry is the only extensibility surface. Registering a new shape means providing:
- A unique string key.
- A parameter schema (a DSPy Signature input specification, or a Pydantic model).
- An output schema.
- A handler callable — typically a LangGraph subgraph entry point.
The registry is populated at sidecar startup. It is not user-configurable and not accessible through MCP. The shapes that ship are:
| Shape key | What it does | Described on |
|---|---|---|
subagent-subgraph | Dispatches a named subagent subgraph via LangGraph Send. Default shape. | Agent Core System |
investigation | Opens a persistent Wasmtime CPython sandbox session, runs an iterative code-and-prose loop, returns a FINAL answer. | Investigation Pattern |
compaction | Wraps an inner action in checkpoint-expand-compact-rewind; returns the compact form as the canonical history record. | Checkpoint Rewind and Compaction |
Additional shapes may be registered as new composition patterns are introduced. The primitive itself does not change.
Subagent-subgraph: the default shape
Section titled “Subagent-subgraph: the default shape”The default shape is subagent-subgraph. It wraps LangGraph’s Send mechanism for dispatching named subgraphs: a subgraph name, an input payload, and an optional sub-thread ID for checkpointing. The planner node uses this shape whenever it decides a piece of work should be scoped to a subagent.
The subgraph runs inside the sidecar — there is no new process, no new OS-level agent. The subgraph gets its own sub-thread for checkpointing purposes (via thread_id + sub-thread suffix), but it shares the sidecar’s LLM clients, tool surface, and memory client. When the subgraph reaches END, task() returns its terminal state as the typed result.
Roles attach at the task() boundary
Section titled “Roles attach at the task() boundary”Roles (see Role Primitive) are call-scoped prompt overlays. They do not modify DSPy Signature instructions globally; they attach as a typed input field on the node’s Signature at the point where task() is invoked. The planner-prompt builder resolves the precedence chain (call → thread → channel → workspace → account) before the dispatch; the resolved role value is passed into the dispatched subgraph’s entry Signature as a named input field.
This means the role’s prompt content is present inside the subgraph’s first planner node but is never written into thread history and never present in the calling graph’s state.
What task() is not
Section titled “What task() is not”It is not a job queue. There is no enqueue, no worker pool, no deferred execution. task() dispatches synchronously within the LangGraph run — the caller awaits the result before the graph continues. The only caller-visible latency is the time the shape handler takes to complete.
It is not a process spawn. The sidecar runs one Python process. task() does not fork, exec, or spawn threads. Concurrency is cooperative async inside LangGraph’s event loop.
It is not an agent-harness replacement. The old Rust harness (infrastructure-agent-harness) drove a Python optimizer and made subagent dispatch a cross-process concern. task() operates entirely inside the sidecar; the only process boundary it crosses is the MCP call any tool makes into the Rust host.
It is not directly callable from MCP. External MCP clients cannot invoke task() as a tool. task() is an internal sidecar primitive. External callers dispatch work by sending a message on a conversation thread through IPC; the planner node then decides whether to call task().
Interaction with checkpointing
Section titled “Interaction with checkpointing”Each task() call that dispatches a subgraph produces a sub-thread in the LangGraph checkpointer. Sub-threads are keyed under the parent thread_id with a deterministic suffix. If the parent turn is interrupted or cancelled while a subgraph is running, the subgraph’s sub-thread retains its checkpoint; the parent’s checkpoint records the in-flight sub-thread ID. On resume, the parent can re-attach to the sub-thread or start fresh, depending on the shape handler’s recovery semantics.
Investigation and compaction shapes have additional checkpoint semantics described on their respective pages.
Where this fits
Section titled “Where this fits”task() is the dispatch layer between the main planner graph and the specialized subgraphs and patterns that implement scoped work. Without it, each new form of dispatch (investigation, compaction, future shapes) would need its own direct wiring into the planner — its own Send variant, its own result-handling node, its own role-attachment path. task() centralizes that wiring. Adding a new composition pattern means registering a shape, not modifying the planner.
What this page does not do
Section titled “What this page does not do”- It does not describe the LangGraph runtime or the main graph shape. See Agent Core System.
- It does not describe how roles are defined, stored, or resolved. See Role Primitive.
- It does not describe the investigation shape in detail. See Investigation Pattern.
- It does not describe the compaction shape in detail. See Checkpoint Rewind and Compaction.
- It does not describe the MCP tool surface or how Rust-backed capabilities are called from inside a subgraph. See MCP System.
- It does not describe how scheduled tasks dispatch work. See Scheduling System.
Was this page helpful?
Thanks for your feedback!