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

# Spec commands

> Find, file and edit the issue a spec lives in, through OuterLayer.

These commands find, file and edit the issue a spec lives in, in your factory's issue tracker. You need only an OuterLayer credential. OuterLayer holds the tracker's credential, so the same four commands work for GitHub, Linear and Jira.

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

Filing works for GitHub, Linear and Jira. A Linear or Jira connection made without write access is refused with `tracker_write_not_permitted`. `spec target` and `spec search` work for all three.

The starter `/spec` skill runs these commands for you. See [Connect an issue tracker](/connect-a-tracker).

## `outerlayer spec target`

Say where a spec would be filed, and whether the factory can file there.

```bash theme={"system"}
outerlayer spec target [--tracker <name>]
```

```text theme={"system"}
tracker: github
trackers: github
scopes: none
repositories: acme/api, acme/web
can file: yes
```

| Line | Meaning |
| - | - |
| `tracker` | The tracker a spec goes to. `none chosen` when the factory has several and you named none, or has none. |
| `trackers` | Every tracker the factory can file in. |
| `scopes` | The Linear teams or Jira projects the connection covers. `none` for GitHub. |
| `repositories` | The repositories linked to the factory. |
| `can file` | `yes` when the tracker can take a write now. |

A factory with a stored Linear or Jira connection files there. A factory with only linked repositories files in GitHub.

It needs `work.read`.

## `outerlayer spec search`

Find open and closed issues that match a query, so a spec is not filed twice.

```bash theme={"system"}
outerlayer spec search "<query>" [--tracker <name>] [--json]
```

```text theme={"system"}
open   acme/api#3  Retry storms
       https://github.com/acme/api/issues/3
closed acme/api#2  Retry budget
       https://github.com/acme/api/issues/2
```

A closed issue is a match too, because it may already hold the decision. With `--json`, each issue also carries its tracker, `updatedAt` and URL. It needs `work.read`.

## `outerlayer spec file`

File a spec as a new issue.

```bash theme={"system"}
outerlayer spec file --title "<title>" --body-file <path> [--repo <owner/name>] [--tracker <name>] [--scope <key>]
```

| Flag | Default | What it does |
| - | - | - |
| `--title <text>` | required | The issue title. |
| `--body-file <path>` | required | The spec as Markdown. `-` reads standard input. |
| `--repo <owner/name>` | the only linked repository | The repository to file in for GitHub. Optional for Linear or Jira, where it names the repository the work lands in. |
| `--tracker <name>` | the only connected tracker | Needed when the factory can file in more than one. |
| `--scope <key>` | the only team or project | The Linear team or Jira project. Needed when the connection covers several. |

It prints the key, the URL, the issue's `updatedAt` and the command that builds the issue:

```text theme={"system"}
✓ filed acme/api#12
  https://github.com/acme/api/issues/12
  updatedAt: 2026-10-12T10:00:00Z
  build it with: outerlayer work build --issue 12 --repo acme/api
```

**What filing needs.** The key must hold `spec.insert`. The Agent preset carries it, but keys made before it existed do not, so make a new key or edit the old one. For GitHub, an organization admin must also approve the OuterLayer App's **Issues: Read and write** permission (`issues: write`) once. Until then `spec target` prints `can file: no`, and `spec file` refuses with `tracker_write_not_permitted` and sends GitHub nothing.

Every attempt that reaches a tracker is recorded in a log that cannot be edited or deleted.

## `outerlayer spec edit`

Replace the body of an issue that holds a spec.

```bash theme={"system"}
outerlayer spec edit <key> --body-file <path> [--updated-at <timestamp>]
```

`<key>` is the issue key, such as `acme/api#12`. `--body-file` is the whole new body. Pass the `updatedAt` that `spec file` printed, or that your last `spec edit` of the issue printed, as `--updated-at`, and the edit is refused with `conflict` if the issue has changed since. On Linear any change to the issue counts, not only to its description. Without `--updated-at`, the edit is not checked for someone else's change. `spec search` matches words in titles and descriptions, not keys, so it cannot supply `updatedAt` for a given key. The tracker offers no conditional update, so a small window for a race remains.

It prints the key, the URL and the issue's new `updatedAt`, which is the value to pass to the next edit. With `--json`, the output carries the same `updatedAt`.

```text theme={"system"}
✓ edited acme/api#12
  https://github.com/acme/api/issues/12
  updatedAt: 2026-10-12T11:30:00Z
```

It needs `spec.update`, held on its own so a key can file without being able to rewrite.

## Refusals

A refused command prints the reason and exits `1`. The message names the choices when there are any.

| Code | Meaning | What to do |
| - | - | - |
| `tracker_required` | The factory has no tracker to file in, or can file in more than one and you named none. | Link a repository or connect Linear or Jira, or pass `--tracker`. |
| `tracker_invalid` | The named tracker is not connected, or the tracker refused the issue. | Check `spec target` for the connected trackers, or read the tracker's message. |
| `repository_required` | You filed in GitHub with no repository named and several linked, or you named one the factory never linked. A Linear or Jira spec needs no repository. | Pass `--repo` with one of the repositories listed. |
| `scope_required` | The connection covers several teams or projects and you named none, or a wrong one. | Pass `--scope` with one of the keys listed. |
| `tracker_cannot_file` | OuterLayer cannot file in this tracker. No supported tracker answers this today. | File the issue in the tracker by hand. |
| `tracker_write_not_permitted` | The credential may not write, such as a GitHub App installation without `issues: write`, a Linear connection without write access, a Jira connection whose credential lacks `write:jira-work`, or a Jira credential whose account Jira refuses with a 401 or 403 on a write. | Disconnect Linear or Jira and connect it again with write access, or accept the App's Issues permission on GitHub. For a Jira connection that has `write:jira-work` but whose write Jira refused, give the credential's account permission to create and edit issues in that project. See [Connect an issue tracker](/connect-a-tracker). |
| `item_key_out_of_scope` | A build's own item key called a spec command. A build may not file or edit specs. | Use a key you made, or a login. |
| `conflict` | The issue changed after the `--updated-at` you gave. Nothing was written. | Read the issue again and redo the edit. |
| `issue_not_found` | The key is not an issue in a source the factory connected. | Check the key with `spec search`. |
| `issue_key_malformed` | The key is not in the tracker's form. The message shows an example. | Fix the key. |
| `tracker_ambiguous` | A key could belong to more than one connected tracker. `work build` reports this. | Pass `--tracker`. |
| `tracker_unavailable` | The tracker could not be reached, or refused a search because its connection lost access. The message says which. | Try again, or reconnect the tracker. |
| `spec_service_unavailable` | The gateway could not reach OuterLayer's dashboard. | Try again. |

A key without the permission gets `403` and no tracker request is made.


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