---
title: Workspaced
description: "The input of a `workspace()` body: the run input, plus `workspace`, the handles that the Workspace adds (`workspace.repos`, `workspace.branch`, `workspace.review`)."
---

# `Workspaced`

Type, in `@jr2/orchestrator/src/workspace.ts`. It is an export of `@jr2/orchestrator`, on the [Authoring surface](../authoring-surface.md) page, in Workspaces and Repos.

```ts
type Workspaced<TInput, TSlots extends string> = WithoutEmptyIndex<TInput> & {
  workspace: WorkspaceHandles<TSlots>;
};
```

The input of a `workspace()` body: the run input, plus `workspace`, the handles that the
Workspace adds (`workspace.repos`, `workspace.branch`, `workspace.review`). Use it as the type of
the body's input.

The first argument is the run input: the `input` schema of the `workspace()`. The second is the
Repo Slots that the body reads, by name (`"app"` or `"app" | "docs"`). Under `repos: open`, write
`string`: the body cannot know the names, so it reads the slots in order. For a `workspace()`
with no `repos`, write `never`. The second argument has no default.

A body under a root `workspace()` also gets the fields of `HostInjectedInput`. Add them when the
body reads them: `Workspaced<HostInjectedInput & RunInput, "app">`.

Its fields are the fields of the run input, and `workspace`. The run input can have no fields:
`Workspaced<z.infer<typeof door>, "app">` for the door `z.object({})` holds only `workspace`.

**Fields**: each field of [`WithoutEmptyIndex`](type-withoutemptyindex.md), and these:

- `workspace`: `WorkspaceHandles<TSlots>`

**Example**

```ts
import { z } from "zod";
import { agent, defineEvent, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";

const done = defineEvent({
  name: "done",
  description: "Call this when REVIEW.md is written.",
  input: z.object({}),
});
const runInput = z.object({ branch: z.string(), sha: z.string() });
type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;

const body = jr2Setup({
  types: {} as { input: BodyInput; context: BodyInput },
  events: [done],
  actors: {
    reviewer: agent({
      model: "anthropic/claude-haiku-5-5",
      instructions: "You review one commit and write REVIEW.md.",
      workspace: "read",
    }),
    fail: fail(),
  },
}).createMachine({
  id: "review",
  context: ({ input }) => input,
  on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
  initial: "reviewing",
  states: {
    reviewing: {
      invoke: {
        src: "reviewer",
        input: ({ context }) => ({
          prompt: `Review commit ${context.sha} on ${context.workspace.branch}.`,
          cwd: context.workspace.review?.app ?? context.workspace.repos.app,
        }),
      },
      on: { done: "finished" },
    },
    finished: { type: "final" },
    failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
    lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
  },
});

export const machine = workspace(body, {
  input: runInput,
  repos: { app: "https://github.com/you/app.git" },
  spec: ({ input }) => ({ branch: input.branch, reviewSha: input.sha }),
});
```

**See also**

- [Workspaces](../../concepts/workspaces.md)
- [Write a Workflow](../../guides/write-a-workflow.md)
- [ADR-0012: `workspace()` wraps a body Machine and owns only Sandbox lifecycle](../decisions/0012-workspace-wrapper-machine.md)
- [ADR-0051: A Repo is a slot on the `workspace()` and a cache on the node](../decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md)
