> ## Documentation Index
> Fetch the complete documentation index at: https://docs-stg.outerlayer.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Work commands

> Start, remove and read what the factory is working on.

These commands start, remove and read work items, the issues on the factory's Work page. None of them sends session content.

Every command takes `--json`, plus `--url` and `--app-id` when your config lacks them. A failed command prints the reason and exits `1`.

## outerlayer work build

Start work on an item. A runner builds it, or with `--local` you do.

```bash theme={"system"}
outerlayer work build --issue <n> [--repo <owner/name>] [--note <text>] [--instructions <text>]
outerlayer work build --issue ENG-123 [--tracker linear|jira] [--repo <owner/name>]
outerlayer work build --item <number> [--note <text>] [--instructions <text>]
outerlayer work build --issue <n> --local [--repo <owner/name>]
# every form also takes [--session-id <id>] [--retry <count>] [--json]
```

| Flag | Default | What it does |
| - | - | - |
| `--issue <n>` | none | Issue number, or a Linear or Jira key like `ENG-123`. Adds the item to Work if needed. |
| `--tracker <linear\|jira>` | none | The key's tracker. Needed only when both are connected. |
| `--item <number>` | none | An item already on Work. Not with `--local`. |
| `--local` | off | You build it. No runner takes it. |
| `--repo <owner/name>` | checkout's remote | The repository. A Linear or Jira key never uses the remote: pass `--repo` to attach one. |
| `--note <text>` | none | A note stored with the request for people to read. The agent never sees it. |
| `--instructions <text>` | none | Guidance for the build. The agent that runs the build receives it as guidance from you. At most 2000 characters: longer text is refused with a 400 naming `instructions`. `--local` refuses it. |
| `--session-id <id>` | detected | Session id to record as-is. |
| `--retry <count>` | `0` | Resend up to 4 times after a 5xx or 429, never after a network error. A non-integer means no retries. A build request is not idempotent, so a retry can record it twice. |

```bash theme={"system"}
outerlayer work build --issue 42           # a host builds it
outerlayer work build --issue 42 --local   # you build it
outerlayer work build --issue 42 --instructions "Skip the docs page; the release notes cover it."
```

Without `--local`, the command records a build request naming who asked. A runner takes the item when it has a free slot. Only a build request makes an item startable for a runner. The command never links your session or takes a claim. A failed build never retries itself: run `work build` again.

Instructions belong to the one build request they come with. A later request without instructions gives its build none. The agent treats them as guidance from you. The issue and its criteria win if the two disagree. Instructions never skip a check or change which issue is built. `--instructions` with `--local` exits non-zero and posts nothing, because you build that item in your own session and can say it there. The build skill reads them, so a repository whose `/build` skill predates this flag needs `outerlayer init --update` first.

It prints the item's own number, which is not the issue's, then the item's page:

```text theme={"system"}
✓ build requested · item #7 (issue github.com/acme/app#42) · by user:<your user id>
  https://app.outerlayer.ai/orgs/acme/factories/acme-factory/work/<item id>
```

The page line appears when the checkout is connected with `outerlayer connect` to the factory the request went to. Only that connection names the organization and factory.

With `--local`, the item goes on Work with no build request, so no runner takes it. The command prints:

```text theme={"system"}
✓ on Work for you to build · #7 · no host will take it
  start your session with: OUTERLAYER_WORK=7 claude
```

That session links itself and holds the item's claim. It works on a branch of its own choosing. With `--json`, the launch line is the `launchCommand` field, and `branch` is the branch a runner would build the item on. An item already on Work needs no `--local`: start a session with `OUTERLAYER_WORK=<number>`.

A Linear or Jira key must belong to a team or project the factory connected, and the tracker must be able to read it.

| Refusal | What to do |
| - | - |
| `--local takes --issue, not --item` | Start a session with `OUTERLAYER_WORK=<number>`. |
| `--instructions applies to host builds` | Drop `--local`, or give the instructions in your own session. |
| `repository_not_connected` | Connect the repository, or fix `--repo`. |
| `tracker_not_connected` | Connect the tracker, or check the key. |
| `tracker_ambiguous` | Pass `--tracker`. |
| `work_item_not_found` | Check the `--item` number. |
| Warning: a container host will fail this build | Ask again with a member's own key or login, not a host key. |

See also: [Work on an item locally](/launch-a-session), [Run work on your machines](/run-work-on-your-machines), [Connect a tracker](/connect-a-tracker).

## outerlayer work link-session

Link the calling session to an existing item. The session hooks run this for you.

```bash theme={"system"}
outerlayer work link-session <number> [--session-id <id>] [--retry <count>] [--no-lease] [--ended]
```

| Flag | Default | What it does |
| - | - | - |
| `<number>` | required | The item's number. |
| `--session-id <id>` | detected | The session to link. |
| `--retry <count>` | `0` | Resend up to 4 times after a network error, 5xx or 429. Linking is idempotent, so a retry is always safe. |
| `--no-lease` | off | Link only, with no claim. A runner's own build uses it. |
| `--ended` | off | Release the session's claim instead. |

```bash theme={"system"}
outerlayer work link-session 7
```

It also takes or renews the session's 20-minute [claim](/concepts) on the item. If a runner or another session holds one, the output names the holder and no claim is taken. Linking twice is a no-op.

| Refusal | What to do |
| - | - |
| `no session id detected` | Run it from a live session, or pass `--session-id`. |
| `work_item_not_found` | Check the number, or create the item with `work build --local`. |
| `work_item_withdrawn` | Add the issue again with `work build`. |

See also: [Work on an item locally](/launch-a-session).

## outerlayer work remove

Withdraw your own addition of an item, recording why. Nothing is deleted.

```bash theme={"system"}
outerlayer work remove (--item <number> | --issue <n> [--repo <owner/name>] | --issue ENG-123 [--tracker linear|jira]) --reason <text>
```

| Flag | Default | What it does |
| - | - | - |
| `--item <number>` | none | The item's number. |
| `--issue <n>` | none | The issue number in `--repo`, or a Linear or Jira key like `ENG-123`. |
| `--tracker <linear\|jira>` | none | The key's tracker. Needed only when both Linear and Jira hold the key. |
| `--repo <owner/name>` | checkout's remote | The repository for an issue number. |
| `--reason <text>` | required | Why. |

```bash theme={"system"}
outerlayer work remove --item 7 --reason "done"
```

The item leaves Work once no live addition remains. Removing again succeeds and changes nothing.

| Refusal | What to do |
| - | - |
| `not_your_addition` | Withdrawing someone else's addition needs **Withdraw others' work**. |
| `no live item for <repo>#<n>` or `for ENG-123` | Check `--issue` and `--repo`, or use `--item`. |
| `ENG-123 names an item in jira and linear` | Pass `--tracker`. |

## outerlayer work status

Print one item's stage, section, gate results, linked pull requests and sessions, additions, and recorded acceptance criteria, as JSON. The output is indented; with `--json` it is one line.

After the JSON, a Criteria section lists each criterion's id and text, with its required proof when it names one. It reads "drafted by the build" when the build wrote the list from the issue description instead of a person recording it. It reads "none recorded" when the item has no list. In `--json`, `criteria` is `null` when none are recorded. Otherwise it is `{ drafted, recordedAt, recordedBy, items: [{ id, text, proof }] }`. Only the current list appears.

`checks` lists every check open on the item: the newest result of each name, with `name`, `result`, `body`, `link`, `source` and `items`. `items` holds the check's [check items](/policy-and-validators#check-items), or `null` when it has none. After the Criteria section, a Failing checks section lists each failing check with its sentence. Under each one it lists the failing check items, with their reasons.

`issue` is the item's issue as OuterLayer last copied it from GitHub, Linear or Jira: `{ url, state, body, author, openedAt, labels, syncedAt, syncStatus }`. `body` is the description in Markdown. `syncStatus` is `ok`, `unreadable` when the last read failed and the copy is from the read before it, or `not_found` when the tracker says the issue is gone. A build reads the issue here, so it needs no tracker credential.

```bash theme={"system"}
outerlayer work status (--item <number> | --issue <n> [--repo <owner/name>] | --issue ENG-123 [--tracker linear|jira])
```

| Flag | Default | What it does |
| - | - | - |
| `--item <number>` | none | The item's number. |
| `--issue <n>` | none | The issue number in `--repo`, or a Linear or Jira key like `ENG-123`. |
| `--tracker <linear\|jira>` | none | The key's tracker. Needed only when both Linear and Jira hold the key. |
| `--repo <owner/name>` | checkout's remote | The repository for an issue number. |

```bash theme={"system"}
outerlayer work status --item 7
```

`no live item for <repo>#<n>` or `for ENG-123`: check `--issue` and `--repo`. `ENG-123 names an item in jira and linear`: pass `--tracker`.

## outerlayer work list

List live work items.

```bash theme={"system"}
outerlayer work list [--repo <owner/name>] [--stage spec|build|review]
                     [--section attention|waiting|flowing]
                     [--unclaimed] [--claimed] [--startable] [--needs amend]
```

| Flag | Default | What it does |
| - | - | - |
| `--repo <owner/name>` | checkout's remote, else all | The repository to list. A Linear or Jira item is in it when it was added with that repository. |
| `--stage` | all | `spec`, `build` or `review`. |
| `--section` | all | `attention`, `waiting` or `flowing`. |
| `--unclaimed` | off | No live claim, a runner's or a session's. |
| `--claimed` | off | A live claim. Each line names the claim's runner, kind, start time and expiry, or the member for a local session. With `--json`, each row carries the `claim` object. |
| `--startable` | off | An unused build request, no open pull request and no live claim. The [runner](/reference/cli-runner) takes work from this. |
| `--needs amend` | off | An open pull request, a person's unanswered `fail` on the general thread, and no live claim. Each row's `threads` names the thread waiting. |

```bash theme={"system"}
outerlayer work list --claimed
```

`--claimed` with `--unclaimed` is refused (`invalid_query`). Linked sessions and pull requests never block an item.

## outerlayer work comment

Post one comment on an item's general thread, or on one criterion's thread.

```bash theme={"system"}
outerlayer work comment --item <n> [--criterion <id>] --body <text>
                        [--artifact <id>] [--pass|--fail|--attach|--ready]
                        [--session-id <id>] [--json]
```

| Flag | Default | What it does |
| - | - | - |
| `--item <n>` | required | The item's number. |
| `--criterion <id>` | general thread | The criterion thread to post on. |
| `--body <text>` | empty | The text. |
| `--pass`, `--fail` | off | A person's verdict on the whole item, on the general thread. |
| `--attach` | off | Make `--artifact` the criterion's current proof. Needs `--criterion`. |
| `--artifact <id>` | none | The artifact to attach. Only with `--attach`. |
| `--ready` | off | An agent hands the thread back to a person after answering a fail or a sent note. |
| `--session-id <id>` | detected | The posting session. It only narrows what the comment may do. |

Give at most one of `--pass`, `--fail`, `--attach`, `--ready`.

```bash theme={"system"}
outerlayer work comment --item 7 --criterion AC-9-01 --body "fixed" --artifact 3f2a1c9d --attach
```

A verdict naming a criterion is refused with `verdict_on_criterion` and nothing is stored. A plain comment starts no agent: only a person's `fail` on the general thread does.

| Code | What to do |
| - | - |
| `verdict_on_criterion` | Drop `--criterion`. Note a criterion with a plain comment. |
| `verdict_needs_person` | An agent session or a factory key cannot record a verdict. Run it yourself, outside the session, with your own login, or record it on the work item page. |
| `not_reviewable` | Nothing is evaluated yet. Wait for the first evaluation. |
| `artifact_needs_attach` | Add `--attach`, or drop `--artifact`. |
| `attach_needs_criterion` | Name the criterion. |
| `artifact_not_found` | The artifact is unknown, superseded, or not on this item. Emit it for this item. |
| `artifact_criterion_mismatch` | Attach it on the criterion it was emitted for. |
| `ready_needs_agent` | Only an agent posts `--ready`. |
| `comment_conflict` | Post it again as a new comment. |

See also: [Review and merge](/review-the-work).

## outerlayer work threads

Print an item's general thread, then each criterion thread with proof or a comment, and who each waits on.

```bash theme={"system"}
outerlayer work threads --item <n>
```

| Flag | Default | What it does |
| - | - | - |
| `--item <n>` | required | The item's number. |

See also: [Review and merge](/review-the-work).

## outerlayer work logs

Print the runner's log for its attempt on an item: what the runner did around the agent, one line per event with its timestamp. Use it to find out why a build ended.

```bash theme={"system"}
outerlayer work logs --item <n>
outerlayer work logs --item <n> --attempt <claim id>
```

| Flag | Default | What it does |
| - | - | - |
| `--item <n>` | required | The item's number. |
| `--attempt <claim id>` | the newest attempt a runner made | An attempt's `id`, from `claims` in `outerlayer work status --item <n> --json`. |
| `--json` | off | Print the response: the item and attempt ids, when the attempt was released, when the log was stored, and the log. |

The runner sends its log when it releases the attempt, with secrets removed on the host. It keeps the last 64 KiB. When the attempt ended in provision, sync, cleanup or report, the log ends with the last 200 lines of that stage's log. It never holds the command's output.

The command exits with an error and prints no log in two cases. The attempt is still running, or a runner too old to send its log released it. See [Find out why a build ended](/troubleshoot-builds#find-out-why-a-build-ended).

## outerlayer work stop

Ask the runner that is building an item to stop. The gateway records who asked, when, and the note. The runner reads the request in the reply to its next heartbeat, ends the build, and releases the claim with outcome `stopped`.

```bash theme={"system"}
outerlayer work stop --item <n>
outerlayer work stop --item <n> --note "wrong branch"
```

| Flag | Default | What it does |
| - | - | - |
| `--item <n>` | required | The item's number. |
| `--note <text>` | none | Why the build is stopped, at most 500 characters. It is kept with the attempt and shown in its reason. |
| `--json` | off | Print the claim, including the runner and the stop request. |

The command prints that the stop is pending and which runner holds the build, then returns. It does not wait for the build to end. A second request while one is pending changes nothing.

A build stopped this way uses up its build request. The item is not claimed again until someone asks for another build, with `outerlayer work build` or **Rerun on a host**. A build ended by `outerlayer runner stop --now` on the host keeps its request, and the item stays available.

The command exits with an error when no host build is running for the item (`no_build_running`). A session's own lease cannot be stopped this way. The gateway records the request for a runner older than protocol 21, but that runner cannot act on it.

On the item page, a member with the same permission selects **Stop build** in the **Building now** block and confirms.

## outerlayer work pr

Declare that a pull request belongs to the work item this session was launched for. It declares onto the `OUTERLAYER_WORK` item or refuses: if the session is not on that item, nothing is stored. Running it twice is a no-op.

```bash theme={"system"}
outerlayer work pr <number> [--repo <owner/name>] [--session-id <id>]
outerlayer work pr <number> --withdraw --item <n> [--repo <owner/name>]
```

| Flag | Default | What it does |
| - | - | - |
| `<number>` | required | The pull request number. |
| `--repo <owner/name>` | checkout's remote | Its repository. |
| `--session-id <id>` | detected | The session declaring it. |
| `--withdraw` | off | Removes a declaration instead of making one. Needs `--item`. |
| `--item <n>` | required with `--withdraw` | The item to remove the declaration from. |

```bash theme={"system"}
outerlayer work pr 481
```

On success it prints the item's number and title, so you can see which item took the pull request.

| Refusal | What to do |
| - | - |
| `no repository` | Run it from a checkout with a git remote, or pass `--repo <owner/name>`. |
| `no active session detected` | Run it in the session that opened the pull request, or pass `--session-id`. |
| `this session is not launched on a work item` | Start the session with `OUTERLAYER_WORK=<number>`. |
| `session_not_on_item` (409) | The session is on other items than `OUTERLAYER_WORK`. The message names both numbers and the session. Pass `--session-id` for the right session. |
| `work_item_not_found` | `OUTERLAYER_WORK` names no item in this factory. |
| `<repo> is not a workpiece of this factory` | Connect the repository, or fix `--repo`. |

### Withdraw a declaration

`work pr <number> --withdraw --item <n>` removes that item's declaration of the pull request. Other items' declarations of it stay. It needs your own login: a factory key or an agent session is refused with `withdraw_needs_person`. Withdrawing a declaration that does not exist answers `declaration_not_found`.

See also: [Open and declare the pull request](/launch-a-session#open-and-declare-the-pull-request).

## outerlayer work open-pr

Open this session's pull request, or edit the one already open on its branch.

```bash theme={"system"}
outerlayer work open-pr --title <text> --body-file <path> [--repository <owner/name>] [--session-id <id>] [--json]
```

| Flag | Default | What it does |
| - | - | - |
| `--title <text>` | required | The title. |
| `--body-file <path>` | required | A file holding the description. |
| `--repository <owner/name>` | the claim's primary repository; on the `gh` path, the checkout's remote | The repository to open the pull request in. It must be one the build's claim names. `--repo` is the same flag. |
| `--session-id <id>` | detected | The declaring session, on the `gh` path. |
| `--json` | off | Prints `{ repository, number, url, created }`. `created` is `false` for an edit. |

```bash theme={"system"}
outerlayer work open-pr --title "Add the thing" --body-file pr.md
```

* **Host build** (an [item key](/concepts) is the credential): the gateway opens or edits it as the factory's GitHub App, from the branch the claim named in that repository. No `gh` runs. `OUTERLAYER_WORK` must be set. Refusals: [Opening the pull request](/reference/build-reference#opening-the-pull-request).
* **Your own session**: runs `gh pr create`, or `gh pr edit`, under your login, then declares it as [`work pr`](#outerlayer-work-pr) does: onto the `OUTERLAYER_WORK` item or refuses. If declaring fails, run `work pr <number>`.

Run it again after changing the title or description.

A build [checks out every repository of the factory](/container-builds#the-repositories-in-a-build). When it changes several, it opens one pull request per repository, naming each with `--repository`. Every pull request links to the same item:

```bash theme={"system"}
outerlayer work open-pr --repository acme/api --title "Add the endpoint" --body-file api-pr.md
outerlayer work open-pr --repository acme/web --title "Use the endpoint" --body-file web-pr.md
```

Use a `repository` from `OUTERLAYER_REPOSITORIES`. A repository the claim does not name is refused with `repository_not_in_claim`. A repository the build did not change gets no pull request.

See also: [Open and declare the pull request](/launch-a-session#open-and-declare-the-pull-request).

## outerlayer work claim, renew, release

Take, extend or give up a runner's [claim](/concepts) on an item, so two runners never build it at once. The [runner](/reference/cli-runner) makes these calls. `release` also gives up the calling session's own lease. Flags, help text and outcomes call a claim a *lease*.

```bash theme={"system"}
outerlayer work claim --item <n> --kind implement|amend [--host <name>] [--seconds <n>]
outerlayer work renew --item <n> [--host <name>] [--seconds <n>]
outerlayer work release --item <n> [--host <name>] [--session-id <id>] [--outcome <outcome>]
```

| Flag | Default | What it does |
| - | - | - |
| `--item <n>` or `--issue <n>` | one required | The item, or the issue in `--repo`, or a Linear or Jira key like `ENG-123`. |
| `--tracker <linear\|jira>` | none | The key's tracker. Needed only when both Linear and Jira hold the key. |
| `--repo <owner/name>` | checkout's remote | The repository for an issue number. |
| `--kind` | required on `claim` | `implement` or `amend`. |
| `--host <name>` | this machine's hostname | A label. The key that took the claim holds it. On `release`, giving it keeps the release to a runner's claim. |
| `--session-id <id>` | detected | On `release`: the session whose lease to release, when it cannot be detected. |
| `--seconds <n>` | `900` | Claim length, capped at 900. |
| `--outcome` | none | On `release`: `ok`, `incomplete`, `failed`, `timed_out`, `idle`, `lease_lost`, `interrupted` or `stopped`. |

```bash theme={"system"}
outerlayer work claim --item 7 --kind implement
```

Claiming again with the same key extends the claim. Releasing twice returns the recorded release time and outcome both times. A release with an outcome shows as an attempt on the item's page.

`outerlayer work release` also releases the calling session's own lease. A session that names an item holds a lease on it, and the item's review stays closed until that lease ends. Run inside a session with no `--host`, the command releases that session's lease, so review opens without closing the session. It never releases another session's lease, and `--outcome` applies only to a runner's claim. Releasing a session's lease needs `work.insert`, not `work.claim`. A later tool call in the same session takes the lease again. The `build` skill runs this as its last step in a local session.

```bash theme={"system"}
outerlayer work release --item 7
```

| Code | What to do |
| - | - |
| `work_item_claimed` | Another runner or session holds it. Wait for release or expiry. |
| `claim_not_held` | A different key holds it. Use the key that took it. |
| `work_item_not_requested` | `implement`: run `outerlayer work build` first. `amend`: no thread waits on an agent since the last attempt. |
| `claim_expired` | `renew` found no live claim. Claim again. |
| `work_item_withdrawn` | Add the issue again with `work build`. |
| `runner_upgrade_required` | Upgrade `@outerlayer/cli`. |

See also: [Run work on your machines](/run-work-on-your-machines).

## Permissions

| Command | Needs |
| - | - |
| `build`, `link-session`, `pr`, `open-pr` on your own login, `comment` (plain or `ready`) | Add work |
| `comment --attach` | Emit evidence |
| `status`, `list`, `threads`, `logs` | View the Work page |
| `pr --withdraw` | Withdraw others' work. A factory key or an agent session is refused with `withdraw_needs_person`. |
| `stop` | Update work, the permission the dashboard's **Stop build** button needs. |
| `remove` | Add work, plus View the Work page with `--issue`, plus Withdraw others' work for someone else's addition. |
| `claim`, `renew`, `release` of a runner's claim | Claim work items. No dashboard role has it: a claim belongs to a runner. |
| `release` of the calling session's own lease | Add work, the permission `link-session` needs. |
| `comment --pass`/`--fail` | Record a review. Your own login or dashboard session carries it. A factory key or an agent session is refused with `verdict_needs_person`. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.