Skip to content

What a worker reads of the repository is declared once in .ai/repo/scope.yaml, out wins over in, and the Rust executable discovers, indexes and serves nothing outside it

A repository says, in one tracked file, which paths a worker reads (in: pathspecs such

guaranteed Deterministic and blocking. Implemented, and a behavioural test proves it.

The declaration is typed and schema-validated (share/schemas/majordomus/scope/scope.v1.schema.json; share/allow/scope.txt is generated from it for the shell tool); a repository declaring none is read under the distribution's default and says so; a discovered file outside the scope is an out_of_scope diagnostic naming the rule; a tracked secret is a tracked_secret warning; repository.scope and repository.scope_classify are projected to MCP, HTTP and `majordomus scope`. The crate's tests/scope.rs covers every branch at the library, socket and process level. The doctrine is project.scope-is-declared.

What it means

A repository says, in one tracked file, which paths a worker reads (in: pathspecs such as src/**, docs/**, .ai/repo/**) and what it never reads (out: version control, the local half of the layer, dependencies and build outputs, secrets, generated assets, archives, images, video, PDF, database dumps, fixtures over a size, any file over a size, binary content). out wins over in, and a path that matches nothing is out with the reason undeclared. The executable reads that file once when it starts, and from then on a file outside the scope is not an object of the index: it is not listed, not read, not searched and not served, through MCP, HTTP or the command line alike. Any path can be asked about: majordomus scope <path> answers in or out, the reason, and the pattern or limit that decided. A repository that declares no scope is read under the distribution's default, the same file majordomus init seeds, and the answer says so.

How it works

apps/majordomus-cli/src/scope.rs types the declaration (deny_unknown_fields, and the scope JSON Schema under share/schemas/, from which the shell tool's allow-list is generated), validates every pattern, and compiles it into ordered rules: out.paths and each category's paths against the repository-relative path, each category's names against the file name alone, then the in pathspecs, then size against fixtures.max_bytes and max_bytes, then the first bytes of content. Index::build judges every discovered file before reading it and records out_of_scope with the reason; it also tallies every tracked file by name and size once, so repository.scope answers from memory, and reports a tracked secret. Scope::load reads the manifest's scope section or the distribution's share/skeleton/ai/repo/scope.yaml. The shell tool's doctor checks the file's version and keys against share/allow/scope.txt, and init seeds it.

How to see it

just build
B=apps/majordomus-cli/target/debug/majordomus
$B scope                                   # origin, the tally, every tracked file that is out and why
$B scope docs/CLI.md .env target/x site/data/generated/plan.json
$B scope --check --format json docs/CLI.md .env; echo "exit $?"    # 10: a path is out
# in an MCP client: majordomus_scope_classify {"path": "priv/dump.sql.gz"}
curl -s 'http://127.0.0.1:8741/api/v1/scope/classify?path=.ai/local/state/current.yaml'

What it does not cover

The scope governs what the executable reads and serves; it does not stop a person or a provider from opening a file themselves, and it does not scan content for secrets beyond the names the declaration lists. The tally judges names and sizes, not content: a binary with an innocent name is caught when it is read, not counted in advance. Task scopes (majordomus start --scope) are a different thing: the paths a task may touch.

Why it exists

The operator gave the boundary as a list: in .ai/repo/**, source, tests, configuration, the root manifests; out .git/, .ai/local/, dependencies, build outputs, binaries, archives, images, video, PDF, database dumps, fixtures over a limit, generated assets, secrets. Until then the boundary was three unrelated mechanisms: the local half skipped in discovery, a size limit compiled into the reader, and whatever a source class happened to match. One declaration, read by the executable and checked by the shell tool, replaces them, and test/cases/93_scope_policy.sh proves the executable honours it.

Detail rendered from docs/claims/scope-declared.md.

Provenance

defined in
read it on this site · docs/SCOPE.md
implemented in
apps/majordomus-cli/src/scope.rs
proved by
test/cases/93_scope_policy.sh
claim id
scope-declared

Verify it yourself

The test runs in a disposable temporary repository and asserts the behaviour, not a string in the source.

from a clone of the repository
bash test/run.sh 93_scope_policy