Monorepo scopes
How PatchArc maps a change to the packages it touched, the ten workspace layouts it detects, and how to declare scopes yourself.
validated against patcharc 0.2.0 · 2026-08-22
A scope is a unit of ownership inside a repository: a package, a service, a module. The review's "Affected scopes" section groups every changed file by scope, with additions, deletions, and a severity band, so a reviewer reads "the auth service and the shared client" instead of a flat list of 40 paths.
Automatic detection
Run patcharc scopes in any repository:
$ patcharc scopes
Scopes (4):
- scope_apps_web [package] Web
apps/web/**
- scope_packages_client [package] Client
packages/client/**
- scope_packages_server [package] Server
packages/server/**
- scope_tools [package] Tools
tools/**
Detection runs in this order and stops collecting from a detector only if it errors; results are merged:
| Detector | Reads |
|---|---|
| pnpm | pnpm-workspace.yaml packages: |
| npm / yarn | package.json workspaces (array or workspaces.packages) |
| Nx | nx.json plus every project.json |
| Rush | rush.json projects[] |
| Bazel | every BUILD / BUILD.bazel |
| Go | go.work use entries |
| Cargo | Cargo.toml [workspace] members |
| Maven | every non-root pom.xml |
| Gradle | settings.gradle(.kts) plus every build.gradle(.kts) |
| .NET | every *.csproj |
That is ten working detectors. A turbo.json is recognised but contributes no scopes on its own (Turborepo projects are usually pnpm or npm workspaces, which are detected). There is no Python detector in 0.2.0.
Scope ids are derived from the path (packages/server becomes scope_packages_server); titles are the last path segment, title-cased.
Declaring scopes
Explicit scopes in .patcharc/config.yaml always win over detection:
scopes:
- id: auth
title: Auth service
kind: service
paths: ["services/auth/**"]
owners: ["@platform"]
depends_on: ["shared"]
- id: shared
title: Shared client
kind: package
paths: ["packages/client/**"]
cross_cutting:
- ".github/**"
- "pnpm-lock.yaml"
idmust match[a-z0-9_-]+and be unique;titleand at least onepathsglob are required.- Globs support
**,*, and?. cross_cuttingglobs are matched first; files that match land in across_cuttingbucket rather than any scope.depends_onis the only source of edges in the scope graph.
patcharc scopes:configure prints a pointer to the config file in 0.2.0; edit the YAML directly.
Classification order
For each changed file: graph cross-cutting globs, then config cross_cutting, then scope paths in declaration order, then unclassified. Unclassified files appear in the review under their own heading so nothing is silently dropped.
The dependency graph
$ patcharc scopes:graph
digraph scopes {
"auth";
"shared";
"auth" -> "shared";
}
Edges come only from depends_on. Detectors do not infer dependencies in 0.2.0, so on an unconfigured repository the graph has nodes and no edges. Pipe the output to dot -Tsvg to draw it.
How scopes appear in the review
Each scope summary carries the commits and files that touched it (computed per commit with git diff-tree), additions and deletions, and a severity band: major at 500 or more changed lines, moderate at 100, minor below that, none for untouched scopes (which are omitted). See The six review sections.