# Configuration file

Most repositories need no configuration. Add `.github/upseam.yml` to the
default branch only when you want one of these things:

- **`internal`**: watch your own OpenAPI or GraphQL contract and send pull
  requests to the repositories that consume it.
- **`ignore`**: skip providers or paths.
- **`agent`**: have your own coding agent write the fixes in your GitHub
  Actions, see [Bring your own agent](own-agent.md).
- **`pull_requests`** and **`slack`**: choose who reviews Upseam's pull
  requests and who is mentioned in Slack.

The delivery mode, the model and the Slack connection live on the settings
page, not in this file. Reviewers, assignees, labels, draft and Slack mentions
can be set in both places; this file wins.

```yaml
internal:
  - spec: api/openapi.yaml
    consumers: [acme/web, acme/mobile]
ignore:
  providers: [twilio]
  paths: [legacy/**, "**/*.test.ts", scripts]
```

An empty file gives the defaults: no internal contracts and nothing ignored.
Upseam rescans a repository when a push to its default branch changes this
file.

## internal

A list of contracts that this repository publishes.

| Field       | Type             | Rules                                                                                      |
| ----------- | ---------------- | ------------------------------------------------------------------------------------------ |
| `spec`      | string, required | Path to the OpenAPI (JSON or YAML) or GraphQL SDL file, relative to the repository root, without patterns. Each path once. |
| `consumers` | list, required   | 1 to 10 repositories as `owner/repo`. Names that differ only in case count once.            |

Consumers must be in the same Upseam installation as the backend. When a push
to the default branch changes `spec`, each affected consumer gets a pull
request. See [How it works](how-it-works.md#internal-contracts).

## ignore

| Field       | Type | Rules                                                                        |
| ----------- | ---- | ---------------------------------------------------------------------------- |
| `providers` | list | Provider ids from the [provider list](providers.md), for example `twilio`.   |
| `paths`     | list | Up to 20 patterns. Files under these paths are not scanned.                  |

Patterns in `ignore.paths` are matched against paths relative to the
repository root, with `/` as the separator:

- `*` matches within one path segment, `?` matches one character within a
  segment, and `**` as a whole segment matches any number of segments.
- `*` and `?` also match names that start with a dot, as in `.gitignore`.
- A path is ignored when the pattern matches it or one of its parent
  directories, so `scripts` ignores everything under `scripts/`.
- A pattern without `/` matches at the root only: `scripts` does not ignore
  `src/scripts`. Use `**/scripts` for that.

Patterns are kept small on purpose: at most 128 characters, 16 segments of at
most 32 characters, two `**` segments, and four `*` per segment. Negation with
`!`, `[]`, `{}`, a leading or trailing `/`, and `.` or `..` segments are
errors.

## agent

| Field    | Type   | Rules                                                                                             |
| -------- | ------ | ------------------------------------------------------------------------------------------------- |
| `runner` | string | `upseam` (default: the model from the settings page), `claude-code`, `codex`, `opencode`, `hermes` or `openclaw`. |

`hermes` and `openclaw` run in a Docker sandbox, see
[Hermes Agent](own-agent.md#hermes-agent) and [OpenClaw](own-agent.md#openclaw).

## pull_requests

Applies to every pull request Upseam opens in this repository.

| Field       | Type    | Rules                                                                                           |
| ----------- | ------- | ----------------------------------------------------------------------------------------------- |
| `reviewers` | list    | Up to 10 GitHub logins or teams as `org/team-slug`. A team must belong to the repository owner. |
| `assignees` | list    | Up to 10 GitHub logins. GitHub assigns only people with push access.                             |
| `labels`    | list    | Up to 10 labels of at most 50 characters, not only dots. A missing label is created. `[]` adds no labels.      |
| `draft`     | boolean | `true` opens the pull request as a draft. Default `false`.                                       |

```yaml
pull_requests:
  reviewers: [alice, acme/api-team]
  assignees: [alice]
  labels: [dependencies, upseam]
  draft: false
slack:
  mention: ["U0123ABCD", "S0456EFGH"]
```

Without any setting, pull requests get the labels `dependencies` and `upseam`
and no reviewers or assignees.

Each field is chosen on its own: a field in this file wins over the same field
on the settings page for this repository, which wins over the setting for the
whole installation. A field you leave out falls through to the next level.
Changes take effect after the next scan, which runs when a push to the
default branch changes this file.

GitHub offers draft pull requests in private repositories only on the Team
and Enterprise Cloud plans. When GitHub refuses a draft, Upseam opens the
pull request ready for review and notes this on the settings page.

A reviewer, assignee or label that GitHub refuses does not stop the pull
request: Upseam opens it, requests the others, and shows what failed for the
last pull request of the repository on the settings page.

## slack

| Field     | Type | Rules                                                                                   |
| --------- | ---- | --------------------------------------------------------------------------------------- |
| `mention` | list | Up to 10 Slack member ids (`U…` or `W…`) or user group ids (`S…`). Names are not looked up. |

Upseam mentions these people and groups in its Slack messages about a finding
and when the pull request opens. When someone approves in Slack, the pull
request link is posted in the message thread and mentions them. A member id
is under "Copy member ID" in the menu of the member's Slack profile.

## Errors

An invalid file stops the scan of that repository until the file is fixed.

- Unknown fields and unknown providers are errors. When the name is close to
  a known one, the error suggests it ("did you mean"); otherwise it lists the
  allowed names.
- Errors in a field name that field, for example `internal[0].consumers[2]`.
- Duplicate keys, non-scalar keys and unknown YAML tags are errors; YAML
  syntax errors give the line instead of a field.
- The file may be at most 64 KiB (an oversized file is an error without a
  field), and lists other than `ignore.paths` at most 100 items.
