---
title: CommandOutput
description: "The output of a `command` Effect: what the `onDone` of its state gets as `event.output`."
---

# `CommandOutput`

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

```ts
type CommandOutput = (ExecOutcome & { dirty?: boolean }) | Unknown;
```

The output of a `command` Effect: what the `onDone` of its state gets as `event.output`. Every
outcome is output. A failed program is output too. Route on `outcome`:

- `exited`: the program ended. `code` is its exit code. A program that the container does not
  have is `exited` with code 127.
- `timeout`: the command ran past its `timeout`, and jr2 killed it.
- `killed`: a signal ended it. `signal` names the signal.
- `unknown`: jr2 cannot tell what the command did, for example because the Harness restarted
  while it ran. `reason` tells why. jr2 does not run it again.

`tail` is the end of what the command wrote, at most the `tail` option of `command` in
characters. `dirty` is `true` when a command that names an Effect secret ran against a commit,
and the Worktree held changes that it did not see.

**Forms**: it is one of these objects.

- Form 1: `outcome`, `code`, `tail`, `dirty`

  - `outcome`: `"exited"`
  - `code`: `number`
  - `tail`: `string`
  - `dirty` (optional): `boolean`
- Form 2: `outcome`, `tail`, `dirty`

  - `outcome`: `"timeout"`
  - `tail`: `string`
  - `dirty` (optional): `boolean`
- Form 3: `outcome`, `signal`, `tail`, `dirty`

  - `outcome`: `"killed"`
  - `signal`: `string`
  - `tail`: `string`
  - `dirty` (optional): `boolean`
- Form 4: `outcome`, `reason`

  - `outcome`: `"unknown"`
  - `reason`: `string`

**Example**

```ts
import {
  command,
  type CommandOutput,
  fail,
  jr2Setup,
  workspace,
  type Workspaced,
} from "@jr2/orchestrator";

type Input = Workspaced<{}, "app">;

const passed = (output: CommandOutput): boolean =>
  output.outcome === "exited" && output.code === 0;

const body = jr2Setup({
  types: {} as { context: Input; input: Input },
  actors: { tests: command(["npm", "test"], { timeout: "15m" }), fail: fail() },
}).createMachine({
  id: "tests",
  context: ({ input }) => input,
  on: { "workspace.lost": ".lost" },
  initial: "testing",
  states: {
    testing: {
      invoke: {
        src: "tests",
        onDone: [
          { guard: ({ event }) => passed(event.output), target: "green" },
          { target: "red" },
        ],
      },
    },
    green: { type: "final" },
    // Not a final state: a final state means `done`, and the run ends `failed` here.
    red: { invoke: { src: "fail", input: { reason: "npm test did not pass" } } },
    lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
  },
});

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

**See also**

- [Effects](../../concepts/effects.md)
- [Run a command or call a URL with an Effect](../../guides/run-a-command-or-call-a-url.md)
- [ADR-0067: An Effect is an actor slot, and runs at most once unless marked idempotent](../decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md)
