---
title: openBody
description: "Make an Open body: the actor slot that a Chart binds."
---

# `openBody`

Function, in `@jr2/orchestrator/src/open-body.ts`. It is an export of `@jr2/orchestrator`, on the [Authoring surface](../authoring-surface.md) page, in Charts.

```ts
function openBody(decl: OpenBodyDeclaration): OpenBodyLogic
```

Make an Open body: the actor slot that a Chart binds. Put it in `actors`, and invoke it from a
state with `{ chart, ...input }`. `chart` is the text of a Chart, or `{ name }` for a named
Chart of this wrapper. The other keys are the input of the Chart, which it reads as
`{{input.<key>}}`. A Machine with an Open body is a Chart wrapper.

Each Agent Turn of the Chart runs where the Open body runs: in the Sandbox of its `workspace()`,
or on the Instance Harness. The Open body ends with an [`OpenBodyOutput`](type-openbodyoutput.md).

It refuses a declaration that is not correct: `openBody: <problem>; <problem>`, for example
`ceilings.turns: missing; an Open body states every ceiling`. `createMachine` refuses a lent
name that the Machine does not have: `machine "<id>": Open body "<slot>": lends.agents: "<name>"
is no actor slot of this Machine; its actors: <slots>`.

**Parameters**

- `decl`: What a Chart can use, and its limits (see [`OpenBodyDeclaration`](type-openbodydeclaration.md)).

**Returns**: The actor logic of the slot.

**Example**

```ts
import { assign } from "xstate";
import { z } from "zod";
import { agent, chartSchema, fail, jr2Setup, openBody, type OpenBodyOutput } from "@jr2/orchestrator";

// `chart` is a Chart, so a run input can carry one, and Charts can have names.
const door = z.object({ topic: z.string(), chart: chartSchema });
type Input = z.infer<typeof door>;
type Context = Input & { result?: OpenBodyOutput };

export const machine = jr2Setup({
  types: {} as { context: Context; input: Input },
  actors: {
    writer: agent({
      model: "anthropic/claude-haiku-5-5",
      workspace: "none",
      instructions: "You write clear, short text for engineers.",
    }),
    body: openBody({
      lends: { agents: ["writer"] },
      allows: { models: [], workspace: [] },
      ceilings: { turns: 6, wallClock: "15m", transitions: 200, fanOut: 1, size: 65536 },
    }),
    fail: fail(),
  },
}).createMachine({
  id: "notes",
  input: door,
  context: ({ input }) => ({ ...input }),
  // The fault of `writer` when a Chart does not route it: the Open body sends it here.
  on: { "agent.fault": ".failed" },
  initial: "running",
  states: {
    running: {
      invoke: {
        src: "body",
        input: ({ context }: { context: Context }) => ({ chart: context.chart, topic: context.topic }),
        onDone: { target: "done", actions: assign({ result: ({ event }) => event.output as OpenBodyOutput }) },
      },
    },
    done: { type: "final" },
    failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
  },
});
```

**See also**

- [Charts](../../concepts/charts.md)
- [Run a Chart by name](../../guides/run-a-chart-by-name.md)
- [Let an Agent write a Chart](../../guides/let-an-agent-write-a-chart.md)
- [ADR-0070: A Machine lends its parts to a Chart](../decisions/0070-a-machine-lends-its-parts-to-a-chart.md)
