> ## 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.

# Troubleshoot builds

> Fix a host before its first build, read the runner's log, find out why a build ended, look up its outcome, and fix refused signatures and items that come back.

Use this page when a host is not ready for its first build. Use it too when
a runner is running but a build did not go as expected.

## Before the first build

### `outerlayer doctor` says the installation "has not accepted" a permission

Builds need a permission the GitHub App installation has not accepted yet. An
owner of the installation accepts it on the settings page that doctor links.
If doctor says the App does not request it, the App's own settings must add
it first. See
[Check what each repository is missing](/github-app-and-build-tokens#check-what-each-repository-is-missing).

### `runner init` stops and asks for a runner key

A login cannot create a key, so `outerlayer runner init` asks you to paste
one, and prints the link to the factory's API keys page. When there is no
terminal to ask on, it stops and prints the same link. What to do in each
case is in [Give the runner its key](/set-up-a-host#give-the-runner-its-key).

### A runner key is refused on a new machine

A runner key is bound to the host key of the first machine that used it.
Elsewhere, the gateway refuses it as `runner_key_signature_invalid`, and the
runner says the key is "bound to another host's key". A member clears the
binding with **Clear host key** on **Settings → API keys**. The next claim
binds the new host. See
[Moving a runner to a new host](/run-a-host-as-a-service#moving-a-runner-to-a-new-host).

### A build fails with `agent_credential_missing` or `disk_limit_exceeded`

The runner has no Claude credential, or the build outgrew
`runner.build.disk`. What to do for each is in
[Outcomes and reasons](#outcomes-and-reasons).

## Read the runner's log

The runner prints one line per event, timestamp first. Failure lines also
go to standard error.

```text theme={"system"}
2026-09-22T14:46:22Z claimed implement #3 acme/api#5 (claim c39386da…) → jobs/implement-3-c39386da…
2026-09-22T14:46:25Z #3 provision ok (3s) · workdir jobs/implement-3-c39386da…/work
2026-09-22T14:58:40Z #3 command exited 0 (12m 15s)
2026-09-22T14:59:12Z #3 sync failed: gateway answered 503 · continuing
2026-09-22T14:59:13Z #3 released · outcome ok · 12m 51s
2026-09-22T15:02:00Z list failed: not authorized (401) · retrying next tick
```

`#3` is the item number. A line ending `continuing` or `retrying next tick`
is a failure the runner absorbed. `unexpected error: <message>` is one it
did not expect; it keeps going.

A repeating failure is logged once, then every tenth tick as
`still failing: <message> (N ticks)`, then `recovered:` when it stops. A drain says what it is waiting on, and
repeats it every thirty seconds.

To stop taking work, run `outerlayer runner stop`. It waits for running
builds to finish. `outerlayer runner stop --now` ends them as `stopped`.

## Find out why a build ended

Start from the work item, not the host. A host build records how it ended, the
session that ran in it, and what the runner did around the agent.

1. Run `outerlayer work status --item <n> --json`, or ask the MCP server for
   `get_work_item`. The item's `claims` list every attempt, newest first. Each
   has an `id`, an `outcome`, the `stage` it ended in, an `exitCode` and a
   `reason`. [Outcomes and reasons](#outcomes-and-reasons) says what they mean.
2. Find the attempt's session. Each session on the item has a `claimId`. The one
   that matches the attempt's `id` is the session that ran in it. It shows what
   the agent was doing when the attempt ended. A session linked by a person or a
   pull request has a `claimId` of `null`.
3. Print the runner's log for the attempt with `outerlayer work logs --item <n>`.
   It prints the newest attempt's log. Add `--attempt <id>` for another attempt.
   The MCP tool is `get_runner_log`. When the attempt ended in provision, sync,
   cleanup or report, the log ends with the last 200 lines of that stage's log.
4. Read the item's review threads with `outerlayer work threads --item <n>`, or
   `get_work_item_threads`, to see what a person asked for.

`outerlayer work logs` exits with an error when the attempt is still running,
because the runner sends its log when it releases the attempt. It also exits
with an error for an attempt that a runner older than this feature released.

Log in to the host only when these do not answer your question. Never signal a
build's processes by hand on a runner host. A build ended that way is lost, and
nothing on the item can show who did it.

### When the runner did not end the command

A command can die of a signal the runner never sent. An operator's `kill`, the
kernel's out-of-memory killer and a supervisor all do this. The runner then
records one of two reasons:

* `the command exited 137, the status of a process killed by SIGKILL; the runner did not end it`.
  The status is 128 plus the signal number. A process killed by a signal
  reports that status, and a program can exit with it on its own, so the runner
  cannot prove a kill.
* `the command was killed by SIGTERM on the host; the runner did not end it`. The
  command's process on the host died of a signal, and there is no exit code.

Either reason points to a cause outside the runner. A build the runner ended
itself keeps its own outcome and reason: `timed_out`, `idle`, `lease_lost` or
`stopped`. A build the kernel killed for memory keeps the
[out-of-memory reason](#when-a-build-runs-out-of-memory).

## Outcomes and reasons

Every build ends with an outcome. A failed build often also records a
`reason` naming the cause. `outerlayer runner logs <item>` prints the newest
build's log.

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/outerlayer-stg/vtkewxrpx_NzS0BQ/images/build-outcomes-light.svg?fit=max&auto=format&n=vtkewxrpx_NzS0BQ&q=85&s=e5a0bc69a49946260a6261a874a6b773" alt="Which stage of a build produces each outcome and reason. Claim: a claim refusal code, such as pull_request_from_fork, and no build runs. Provision: failed when the hook fails, agent_credential_missing, a gateway code when the read token is refused, the image codes recipe_ambiguous, recipe_needs_docker, recipe_context_outside, repository_unreadable, default_branch_unknown, invalid_repository, build_in_progress, build_failed and devcontainer_cli_missing, the six context codes, and no outcome when the hook exits 75. Command: failed on a non-zero exit, which skips the judge, host checks and verdict, disk_limit_exceeded, disk_check_failed, idle, interrupted and workflow_permission_required. Judge, host checks, sync, cleanup and report add no outcome code of their own. Verdict: ok or incomplete. Release sends the outcome. At any stage: timed_out, lease_lost or stopped." width="660" height="969" data-path="images/build-outcomes-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/outerlayer-stg/vtkewxrpx_NzS0BQ/images/build-outcomes-dark.svg?fit=max&auto=format&n=vtkewxrpx_NzS0BQ&q=85&s=4df772251926fb3396ee592090f96f72" alt="Which stage of a build produces each outcome and reason. Claim: a claim refusal code, such as pull_request_from_fork, and no build runs. Provision: failed when the hook fails, agent_credential_missing, a gateway code when the read token is refused, the image codes recipe_ambiguous, recipe_needs_docker, recipe_context_outside, repository_unreadable, default_branch_unknown, invalid_repository, build_in_progress, build_failed and devcontainer_cli_missing, the six context codes, and no outcome when the hook exits 75. Command: failed on a non-zero exit, which skips the judge, host checks and verdict, disk_limit_exceeded, disk_check_failed, idle, interrupted and workflow_permission_required. Judge, host checks, sync, cleanup and report add no outcome code of their own. Verdict: ok or incomplete. Release sends the outcome. At any stage: timed_out, lease_lost or stopped." width="660" height="969" data-path="images/build-outcomes-dark.svg" />
</Frame>

| Outcome or reason | Meaning | What to do |
| - | - | - |
| `ok` | The command exited zero and the item's checks pass. | Judge the work by the pull request. |
| `incomplete` | The command exited zero, but the item has no pull request, or its checks still fail or have no result. The reason says which. | If the build opened no pull request, it needs to open one with `outerlayer work open-pr`. Otherwise fix the checks on the pull request. Either way, you can run `outerlayer work build` again, or select **Rerun on a host** on the item page when no pull request is open. |
| `failed` | The command exited non-zero, or provision failed: the hook exited non-zero, wrote no `workdir=` line, or named a missing directory. | Read the log and reason, fix it, then run `outerlayer work build` again, or select **Rerun on a host** on the item page. |
| `timed_out` | The build ran past `runner.timeLimitMinutes` (480). | Raise it or split the item. |
| `idle` | No log output for `runner.idleLimitMinutes` (30) and, with a control group, under two seconds of CPU a minute. Usually a prompt. | Make the command non-interactive. |
| `lease_lost` | The runner lost its claim. For example, a token renewal got `claim_expired` or `401`, so the build stopped. | Nothing. The item stays available. |
| `interrupted` | The runner stopped mid-build. | Nothing. The item stays available. |
| `stopped` | Someone ended the build. When the reason says `stopped by <name> through OuterLayer`, they used **Stop build** or `outerlayer work stop`. Otherwise an operator ran `runner stop --now` or pressed Ctrl-C twice on the host. | Through OuterLayer, the item is not built again until someone asks for another build. On the host, the item stays available. |
| No outcome (exit 75) | The provision hook declined. | Nothing. The item stays queued. |
| `agent_credential_missing` | The runner has no Claude credential. | [Give the runner one](/set-up-a-host#set-it-up), and restart it. |
| `disk_limit_exceeded` | A container build's volume grew past [`runner.build.disk`](/container-builds#the-build-block). | Raise `disk`, or make the build write less. |
| `disk_check_failed` | The runner could not measure the build's volume on two disk checks in a row. A check fails when `du` prints no total, when it reports a directory it cannot read, or when it runs past 2 minutes. | Run `outerlayer work logs --item <n>` to print the runner's log for the attempt. The log shows what `du` reported. Make every directory under `/build` readable by the build's user, and use a build image that has `du`. |
| `workflow_permission_required` | A push changed a workflow file, and the token lacks `workflows` permission. | Allow it in `.outerlayer/policy.yaml`. See [Letting a build change workflows](/github-app-and-build-tokens#letting-a-build-change-workflows). |
| A gateway code, such as `repository_not_in_installation` | The gateway refused the read token. The build is `failed` at provision. | See [GitHub App permissions and build tokens](/github-app-and-build-tokens). |
| `github_request_failed` | GitHub refused the gateway's request to read the control plane, for a reason other than load, such as a rejected App credential. The attempt ends as `failed`, and the runner does not retry. | Check the GitHub App's credentials on the gateway. |
| `context_unavailable` | The runner could not get the control plane. The reason says why, and which credential the fetch used. | See [When the context is unavailable](#when-the-context-is-unavailable). |
| `no_control_plane` | The gateway answered that no control plane governs the repository. This is not a failure: the build starts with no governed context and fetches nothing. | Nothing. |
| `context_conflict` | The gateway named two control planes for the repository. Only an old gateway does this: one from before a factory's control plane governed all its linked repositories. | Upgrade the gateway. |
| `context_delivery_failed` | The control plane could not be copied into the build user's home. Or the `claude` program, or the record that names the directory, could not be written. The reason carries the first error line. | Fix what that line names, and start the build again. |
| `context_skill_conflict` | The repository has a skill with the same name as a shared skill, in `.claude/skills/` or `.agents/skills/`. The reason names the folder and both skills. | Rename or remove the repository's skill. |
| `context_layout_unsupported` | The control plane's `.outerlayer/config.json` declares a `layout` other than 1 or 2, or is not valid JSON. The reason names the layout. | For a layout newer than 2, upgrade the CLI on the runner host. Otherwise fix the file. Then start the build again. |
| `context_agent_too_old` | The build image's Claude Code is older than 2.1.284, the oldest version known to load the control plane's instructions for subagents. | Rebuild the build image with a current Claude Code. |
| `recipe_ambiguous` | The repository has only named dev container configurations. | Add `.devcontainer/devcontainer.json`. |
| `recipe_needs_docker` | The recipe uses `dockerComposeFile`, which no built-in hook runs. | Use a single-container recipe. A build that needs Docker can use `builtin:vm` with the docker-in-docker feature. Otherwise use [your own hooks](/write-your-own-hooks). See [why Compose recipes are refused](/build-image-from-devcontainer#why-compose-recipes-are-refused). |
| `recipe_context_outside` | The recipe reads outside `.devcontainer/`, or it is a symlink. | Commit a real directory and move the build files into it. |
| `repository_unreadable` | The host's git login cannot read the repository. `outerlayer runner image` reads it with that login. | Give the host's git login read access. |
| `default_branch_unknown` | The repository has no default branch the runner can read. | Set the repository's default branch on the git host. |
| `invalid_repository` | The item's repository is not `owner/name`. | Fix it. |
| `build_in_progress` | Another build of the same build image ran too long. | Retry when it finishes. |
| `build_failed` | The build image's build failed. | Read the image build log the runner names. |
| `devcontainer_cli_missing` | The devcontainer CLI that the runner uses is missing. | Reinstall `@outerlayer/cli`. |
| A claim refusal code, such as `pull_request_from_fork` | The gateway refused the claim. | See [Refusals](/reference/build-reference#refusals). |

A microVM build never ends with `disk_limit_exceeded` or `disk_check_failed`,
because its disk is a fixed size.

A read token that fails for a temporary reason, such as `github_unavailable`,
releases the claim with no outcome. The runner retries on its next poll. A
refused push token fails the push, and the build fails at its next health
check.

### When the context is unavailable

`context_unavailable` means the runner could not get the control plane. The
reason says which of these happened, and which credential the fetch used.

| The reason says | What to do |
| - | - |
| The gateway refused a token for the control plane, and names its code, such as `control_plane_not_in_installation`. | For `control_plane_not_in_installation`, give the GitHub App access to the control plane. |
| The token request failed before the gateway answered. The reason carries the network error. | Check the host's network path to the gateway. |
| The fetch failed with the token the gateway issued. | Check that the App's installation still includes the control plane. Check the host's network access to GitHub. |
| The gateway has no GitHub App, and the host's git login cannot read the control plane. | Give the host's git login read access to the named repository. |
| The gateway did not answer which repository governs this one: the lookup timed out after 10 seconds, twice, or carries the network error. | For a lookup that timed out or failed with a network error, check the host's network path to the gateway. |
| The lookup gives the HTTP status the gateway answered. | For a 5xx status, report it to the gateway's operator. |

Then run `outerlayer doctor`.

Other reasons are a sentence, or a line a hook wrote; see
[The cleanup hook](/write-your-own-hooks#the-cleanup-hook).

## When nothing is building an item

An item that is not being built can carry a `waiting` reason. The item page
shows it under **Not building**, and the item reads **Not picked up** when a
build request waits and no runner takes it. `outerlayer work status --item <n> --json`
and `get_work_item` return it as `waiting`. It is `null` while the item is
building, or queued with a runner to take it.

| `waiting` reason | What it means and what to do |
| - | - |
| `trigger-used` | A build already answered the latest request. For an item with an open pull request, no new review or build request has come since the amend build ended. Send changes, or ask for another build with `outerlayer work build` or **Rerun on a host**. |
| `no-host` | No runner that checked in recently takes the item's queue and repository. Check the runner's `queues` and `repos` filters in its config, and that it is running. `maybe: true` means a runner reported a repository list that was cut short, so one of them may take it after all. |
| `hosts-unavailable` | Runners take the item, but every one is draining, restarting, holding for an update, blocked or low on disk. The reason names each runner with its state. Wait for the state to clear, or see [When the runner is blocked](#when-the-runner-is-blocked) and [Let a restart through](/run-a-host-as-a-service#let-a-restart-through). |

A runner that has not heartbeated within three of its poll intervals is not
counted.

## When a lease expired

A host build can end without a release: the machine lost power, or the runner
was killed. Nothing writes the end, so the claim runs out. The item page lists
the attempt in **Last build** with the outcome **lease expired**, the runner's
name, and the time of the runner's last renewal. `claims` in
`outerlayer work status --item <n> --json` marks it with `leaseExpired: true` and
`lastRenewedAt`.

A claim that ran out uses up its build request like any other claim that was
not released as `interrupted` or `lease_lost`. To retry, run
`outerlayer work build` or select **Rerun on a host**.

## When the gateway refuses a signature

Each refusal is a `401`, logged to the organization audit log as
`runner_key_signature_refused`.

| Code | Meaning and what to do |
| - | - |
| `runner_key_signature_required` | No signature. Upgrade the CLI, and check that `<config dir>/runner/host-key.pem` exists. |
| `runner_key_signature_invalid` | Usually a runner key used from a second machine, or a body changed after signing. If the key moved on purpose, [clear its binding](/run-a-host-as-a-service#moving-a-runner-to-a-new-host); otherwise treat it as leaked: revoke it and make a new one. |
| `runner_key_signature_stale` | The host's clock is over five minutes off. Fix and synchronise it. |
| `runner_key_signature_replayed` | Something is resending the runner's requests. Restart the runner and find it. |

## When a call to the platform does not land

The runner retries the claim, renew and release for up to two minutes when
the gateway does not answer. Refusals are never retried.

A release that still fails is logged without `released`:

```text theme={"system"}
2026-09-22T15:02:41Z #16 release failed after 6 attempt(s): the store did not answer (503); the lease expires at 15:14 UTC
```

`runner status --recent` marks it `(release failed)`, and the next
`runner start` sends it again. The claim lapses fifteen minutes after the
last renewal, and the item returns to the queue.

If someone released the claim first, the runner logs
`lease was already released`, with the outcome the platform stored and the
outcome this attempt ended with. The platform keeps the outcome it stored
first.

## When the runner holds off for disk

A runner that takes no work and logs this has less free disk than it needs:

```text theme={"system"}
holding off new work: 2.0 GB free on the runner's file system, 40.0 GB needed (runner.housekeeping.minFreeDisk) · claiming again once there is room
```

The runner logs it once, keeps polling and keeps renewing the claims of
builds that already run. `outerlayer runner status` shows the same line, and
`outerlayer doctor` warns about it. `GET /v1/hosts` lists the runner with
`lowDisk`, the free and needed bytes. Its status is not changed by this.

The runner measures the file system that holds its own directory,
`<config dir>/runner`. Free space there, or lower
`runner.housekeeping.minFreeDisk`. When there is room the runner logs
`free disk is back above the minimum · taking work again` and claims on its
next poll, with no restart. By default the minimum equals
`runner.build.disk`: room for one more build.

Housekeeping removes what builds leave behind, which is usually enough. If
the disk is full of something else, such as Docker images a person pulled,
the runner does not remove it. See [Housekeeping](/run-a-host-as-a-service#housekeeping).

## When the runner is blocked

At start and on every poll, the runner checks itself, as its own account and
never as the person who set it up. It checks in this order:

1. No queue's command is still the placeholder `runner init` writes.
2. For container and microVM hooks, `concurrency` times `build.memory` fits
   in memory, as in [Memory limits](/run-a-host-as-a-service#memory-limits).
3. For `builtin:vm` hooks, `/dev/kvm` exists and the runner can open it.
4. For container and microVM hooks, its image builder exists and starts, as
   in [Image builds](/run-a-host-as-a-service#image-builds).
5. For any built-in hooks, it has a Claude credential.

When one fails, the runner claims nothing and logs `claiming nothing:`
followed by the reason, once. Its heartbeat carries `blocked` with the
reason, and `GET /v1/hosts` lists the runner as not taking work. A typical
line:

```text theme={"system"}
claiming nothing: the runner cannot open /dev/kvm, so builtin:vm cannot start a microVM. Add the runner's account to the kvm group, then restart the service, because a service reads its groups only when it starts
```

Once the check passes, the runner logs
`the runner can run its work again · taking work` and claims on its next
poll. Two fixes take effect only after a service restart, because the runner
reads them only when it starts: `/dev/kvm` access and a credential added to
`claude.env`. The others take effect on the next poll.

| The reason names | What to do |
| - | - |
| `/dev/kvm does not exist` | The machine has no KVM. Run microVM builds on a host with KVM enabled, or set `runner.hooks.provision` and `runner.hooks.cleanup` to `builtin:container`. |
| `/dev/kvm`, which the runner cannot open | Add the runner's account to the `kvm` group, then restart the service: `sudo usermod -aG kvm <account>` and `sudo systemctl restart outerlayer-runner`. A service reads its groups only when it starts, so a shell that shows the group says nothing about the service. Or set `runner.hooks.provision` and `runner.hooks.cleanup` to `builtin:container`. |
| Claude credential | Pipe a token or an API key to `outerlayer runner init --agent claude`. It stores the credential in the `claude.env` beside the config file. Then restart the service. The runner reads the file only when it starts. |
| `runner.commands.<queue>` is still the placeholder | Edit the command in the config file to start your agent. The runner reads the file again on its next poll. |
| The runner is still preparing its image builder | Nothing, at first. This is not a fault: the first start pulls the BuildKit image, and the runner takes work once the builder is ready. If the reason does not change, see [When the Image build limit check fails](#when-the-image-build-limit-check-fails). |
| Buildx, or an image builder that is not usable | Install Docker's Buildx plugin. See [When the Image build limit check fails](#when-the-image-build-limit-check-fails). |
| `concurrency` times `build.memory` | Lower `runner.concurrency` or `runner.build.memory`, or run the runner on a host with more memory. The reason names the memory the builds need and the memory available. See [Memory limits](/run-a-host-as-a-service#memory-limits). |

`outerlayer doctor` reports what the running service has, not your shell:
the groups of its main process, and the credential variables in its
`claude.env` and `runner.env`.

A runner short of disk also claims nothing; see
[When the runner holds off for disk](#when-the-runner-holds-off-for-disk).

## When the Image build limit check fails

The runner builds every build image in its own builder, a container with a memory
limit of `runner.build.memory`, which needs Docker's Buildx plugin. When
Buildx or its `docker-container` driver is missing, or older than 0.18,
`outerlayer doctor` fails the "Image build limit" check, and the runner
claims nothing. It logs `claiming nothing:` with the reason, and its heartbeat
carries the same reason.

Install the plugin: `docker-buildx-plugin` from Docker's apt repository, or
`docker-buildx` from Ubuntu's own packages. Then run `outerlayer doctor`
again. The runner takes work again by itself, with no restart.

A runner that has Buildx but is still starting its builder logs
`the runner is still preparing its image builder`. The first start pulls the
BuildKit image, which takes a moment. If the reason does not change, it
names why the builder did not start, for example that Docker Hub cannot be
reached. The builder container does not use a proxy on the host's loopback
address. So a daemon that reaches the network only through one needs a proxy
the container can reach.

## When an image build runs out of memory

A recipe step that uses more than `runner.build.memory` is stopped by the
kernel, in the runner's image builder. The build is released `failed` at the
`provision` stage with this reason:

```text theme={"system"}
the image build ran out of memory: the kernel stopped a build step at the limit of runner.build.memory (8g). Raise runner.build.memory, or lower what the recipe's build steps use; the build log is at <path>
```

Only that build ends. The builder and the other builds carry on. The log
named in the reason shows the step. Raise `runner.build.memory`, and check
that the builds still fit, as
[Memory limits](/run-a-host-as-a-service#memory-limits) says. When the limit changes, the runner replaces its builder once the image
builds it is running have ended. The next image build starts with an empty
cache.

## When a build runs out of memory

In a service that sets `Delegate=yes`, each microVM build's Firecracker
process runs in a cgroup of its own. When the kernel kills it at the cgroup's
limit, the build is released `failed` with this reason:

```text theme={"system"}
the build ran out of memory: the kernel killed its microVM at the limit of runner.build.memory (8g) plus 1 GiB for Firecracker and its disks' page cache. Raise runner.build.memory, or lower runner.concurrency
```

Only that build ends. The runner and the other builds carry on. Raise
`runner.build.memory`, and check that the builds still fit, as
[Memory limits](/run-a-host-as-a-service#memory-limits) says. A build killed below its limit means
this host needs more reserved memory. It needs more than the 1 GiB reserved
for Firecracker or the 2 GiB reserved for the system. Lower `runner.concurrency` to leave more room.

A service without `Delegate=yes` gives microVM builds no limit of their own,
and `outerlayer doctor` warns. Run `outerlayer runner install --service --replace` to write the unit this CLI generates. A container build's limit is
Docker's `--memory` at `build.memory`.

## When an item comes back

A build request is used up by any claim after it: a host build released
`ok`, `incomplete`, `failed`, `timed_out` or `idle`, a claim that lapsed, or a local
session. So a failed build is not claimed again. To retry, run
`outerlayer work build`, or select **Rerun on a host** in the **Last
build** block of the item page. The control is offered when no build is running
and no request is unused, and only to a member who can run
`outerlayer work build`. It also needs no open pull request on the item, or a
review that waits on an agent; see
[Rerun a Stuck item](/review-the-work#rerun-a-stuck-item).
`work build --local` does not queue the item.

`interrupted`, `lease_lost` and exit 75 leave the request unused, so the item
stays available. So does `stopped` when the operator ended the build on the
host. A build stopped through OuterLayer uses its request up.

An item that still needs work comes back through the amend queue when a
person sends notes or fails it, not through the implement queue. A failed
amend build is not retried until a person fails the item again, or a member
selects **Rerun on a host**.

While no session is linked, the item's **Sessions** list names who holds a
live claim. It names a runner by name, or a person's name followed by "(local session)". When nothing is
queued it names `outerlayer work build`. **Run it yourself** gives the
command that starts a session by hand.


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