# Several projects in one repository

By default, [what hushrun compares](https://hushrun.com/docs/run.md#same-code) covers every file in the repository, so a change anywhere runs every check again. This guide narrows it with `hushrun.yaml` at the repository's root.

## Leave out files that change no result

List the files no check depends on, such as docs, under `digest.exclude`:

```yaml title="hushrun.yaml"
version: 1
repository: github.com/acme/shop
digest:
  exclude: ["**/*.md"]
```

A change to a file it leaves out no longer runs any check again.

## Split into scopes

A scope is the set of files one project's checks depend on. Declare one per project:

```yaml title="hushrun.yaml"
version: 1
repository: github.com/acme/shop
scopes:
  web:
    include: ["web/**", "package.json", "pnpm-lock.yaml"]
  api:
    include: ["api/**", "go.mod", "go.sum"]
```

Then give each check its scope with `--scope`:

```json title="web/package.json"
"scripts": {
  "test": "hushrun run --scope web -- vitest run"
}
```

A change under `api/` no longer runs `web`'s checks again.

Once `hushrun.yaml` has more than one scope, every `hushrun run` needs `--scope`. Without it, hushrun can't tell which files the check covers, so the check runs every time, and hushrun says why:

```text
hushrun: test running without skipping: can't tell which code this is (this policy has several scopes (api, web); pass --scope NAME or --all-scopes)
```

### Let init write them

`npx hushrun init` writes the scopes for you when CI runs checks in subdirectories. Each project's scope holds:

- the root's files, dotfiles included, but not the root's `*.md`, `LICENSE*` or `NOTICE*`;
- CI's files;
- what its manifests name;
- what its files name in a `../` path, quoted or not, such as a test that opens `../landing/lib/pricing.json`;
- where a link it tracks leads.

A wrong guess only widens a scope. Where init can't be sure, it keeps one scope and says why, since a scope that left something out would skip a check that should run.

init can't see a path built at run time, such as `path.join(__dirname, "..", "..", "landing")`. If a check reads one, add it to the scope's `include`.

## Declare code outside the repository

A check can build against something beside the repository, such as a sibling checkout. Nothing in the repository changes when that code does, so declare it in the scope under `external`:

```yaml title="hushrun.yaml"
scopes:
  back:
    include: ["back/**"]
    external:
      - path: ../cli
        include: ["crates/**", "Cargo.lock"]
```

A change there then runs the check again, uncommitted changes included.

- `path` is the top of a git checkout, relative to the repository's root.
- When `path` is missing, hushrun can't tell which code this is. The check runs, and records nothing.
- If `hushrun.yaml` also sets up [promotion](https://hushrun.com/docs/promotion.md) (`stages:`), a scope can't use `external`: a stage's evidence covers the repository's own files.

## Next

- [Where a check counts](https://hushrun.com/docs/where-a-check-counts.md): a rule per scope for the machine a check needs.
- [Configuration](https://hushrun.com/docs/reference/configuration.md#hushrun-yaml): all of `hushrun.yaml`.
- [Set up CI](https://hushrun.com/docs/ci.md): jobs that run each project's checks.
