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.
$ 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 sEach 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#
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#
What counts as a project?#
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?#
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:
# 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?#
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), 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.
$ 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 sWith 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?#
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#
- What a clean check means — what one project's green validate covers
- Checking your app —
osy check: validate, lint and tests for one project - Checking a kit composes — osy kits check —
osy kits check: does a kit compose