# Checking every project at once — osy validate --all / --affected

> One command, one verdict, for a repository that holds many projects: `osy validate --all` finds every app and package under the workspace root and validates them in one process, several at a time, printing only the ones that fail and one summary line. `--affected` checks only the projects a change can reach — a changed project, and every project that uses a changed package. Exit 0 when all pass, 1 when any fails.

<!-- id: local-checking-every-project · area: local · stability: stable · html: https://osysharp.com/reference/local/checking-every-project/ -->

## Summary        {#summary}

`osy validate` answers for one project. A repository with kits, their test apps and the apps that use them holds many,
and "does everything here still compile?" used to mean running it once per project — paying the start-up each time.
`--all` asks the question once: every project is found, validated inside one process with the platform loaded once,
and only failures are printed.

```console
$ osy validate --all

✗ apps/storefront  (1 error)
  apps/storefront/model/cart.osy:14:20  RESOLVE_ERROR  unknown function or member 'Twice'

✗ 412 projects, 1 failed, 231.4 s
```

Each project's answer is the one `osy validate <project> --json` gives on its own; nothing about validating is
different, and one project's failure never changes another's.

## Signature      {#signature}

```console
osy validate --all [PATH…]       # every project under PATH (default: the workspace root)
osy validate --affected [RANGE]  # only the projects a change can reach
  --jobs <N>                     # how many projects to check at once (default: half the cores)
  --list                         # print what WOULD be checked, and why, and validate nothing
  --no-emit                      # parse + resolve only, as for a single project
  --json                         # { success, projects, failed, seconds, results: [{ project, success, seconds, errors }], skipped, affected }
```

Exit code: `0` every project passed · `1` at least one failed · `2` the run could not start (no project found, a path
that is not a directory, no change set for `--affected`).

## Description    {#description}

### What counts as a project?    {#projects}

What a lone `osy validate` in that directory reads as one: a directory whose `app.osy` declares an `app { }` block, or
— with no `app.osy` — one holding a `package.osy`. A kit and the test app in its `tests/` directory are two projects.
A model file that happens to be called `app.osy` is not a manifest and makes no project.

The search starts at the nearest directory, at or above where you run it, that holds an `osy.workspace`; with none,
at the root of the git repository; with neither, at the current directory. Directories whose name starts with a dot,
and `node_modules`, `bin` and `obj`, are never searched.

### How do I say a folder is not meant to compile?    {#skip}

Put a file named `osy.skip` in it. Nothing under that directory is searched, and the file's first line of text is the
reason, shown with the summary and carried in `--json`:

```text
# sketches/osy.skip
Design sketches written ahead of the language. They are not meant to compile yet.
```

It is for a tree that is a record or a question rather than source someone keeps green — recorded output, a probe
whose refusals are its answers, a sketch written ahead of the language. Naming the folder on the command line does not
reopen it.

### What does --affected select?    {#affected}

It reads the files that changed from git and applies these rules, first match first, printing the rule behind each
part of the selection:

| a changed file that is… | selects |
|---|---|
| under a directory with an `osy.skip` | nothing |
| a `.md` file | nothing |
| inside a C# project that is not a test project | every project — that is the compiler and the platform's own model |
| inside a project | that project; if it is a package, every project that uses it, directly or through other packages; and any project whose directory encloses it |
| a build file every C# project reads, or `osy.workspace` | every project |
| anything else — a script, a design page, a platform test, client TypeScript | nothing |

"Uses" is the workspace's own graph: `use` lines in apps and packages, a bridge reaching whoever uses every package it
`completes` ([Bridges — a package that arrives when an app uses the two it completes](https://osysharp.com/reference/project/bridges/)), a kit's test app reaching its kit, and an app reaching the kits in its own `kits/`.
A project whose manifest cannot be read is selected by any package change.

```console
$ osy validate --affected
affected (changes since origin/main at 753cee10d9, uncommitted work included):
  [project] kits/chart — theme.osy  → 1 selected
  [encloses] kits/chart is inside 0 other project(s)  → 0 selected
  [uses] 41 project(s) use Osysharp.Chart, directly or through another package  → 41 selected
  [nothing] 2 file(s): prose (.md)
✓ 42 projects, 0 failed, 38.0 s
```

With no value, the change is everything since the branch left `origin/main`, uncommitted and untracked files included.
`--affected HEAD~3` measures from that commit (working tree included); `--affected a..b` is exactly those commits.
A change that reaches no project is a pass and says so. It errs toward more: a project a change could not break costs
seconds, and one it did break is what the command exists to catch.

### What is shared, and what is not?    {#sharing}

The process, the platform's own baseline (compiled once for the run and copied into each project's check), the
workspace's member list and each package's packed bytes are computed once and handed to every project that asks.

Each project's own composition — parsing, resolving and emitting it with the packages it uses — is done per project,
so a large kit used by thirty projects is compiled thirty times, and that is what the remaining time is made of. It is
not one compile repeated: what a kit compiles to depends on the app composing it — which of its components that app's
pages reach, the policies and slots the app supplies for it, the theme its tokens resolve against, which of its texts
are words a reader sees — so the same kit is a different compile in each app that uses it.

## See also       {#see-also}

- [What a clean check means](https://osysharp.com/reference/local/what-a-clean-check-means/) — what one project's green validate covers
- [Checking your app](https://osysharp.com/reference/local/checking-your-app/) — `osy check`: validate, lint and tests for one project
- [Checking a kit composes — osy kits check](https://osysharp.com/reference/local/checking-a-kit/) — `osy kits check`: does a kit compose
