Operations
Nave's commands fall into three phases — read (fleet), validate (schemas), and write (pens).
Only the write phase (pens) mutates the fleet.
Fleet reading
| Command | What it produces |
|---|---|
scan |
Repo index in the cache |
pull |
Tracked files, sparse-checked-out |
search |
Repos/files/hole-addresses matching a query |
build |
Templates + hole reports for a file kind |
They may update the local cache as a local projection, not a remote effect.
Schema validation
| Command | What it produces |
|---|---|
check |
Parse/round-trip outcomes per tracked file |
schemas validate |
Per-file schema errors; per-step action errors |
Validation is derived from the cache, and still doesn't have any effect on the fleet.
It's part of preparation for write operations: a failing check or validate is a signal
that a bulk edit will land on shaky ground.
Pen writing
| Command subtree | What it does |
|---|---|
pen create / sync / clean / revert / reinit / rm |
Pen lifecycle |
pen rewrite |
Apply declarative transforms to working trees |
pen exec |
Run an arbitrary command per repo |
pen run |
(Planned) Rewrite + commit + push |
Pens are the only thing in Nave that can mutate remote state, and every write goes through the pen lifecycle. There is no "just push this one commit" shortcut.
Composition
Naturally, the phases build on one another:
write (pen) ──► reads (search, build) ──► cache (scan, pull) ──► fleet
A pen uses search internally to select repos; search reads the cache; the cache
was built by scan and pull. You can run any phase standalone, but you can't skip
a lower one.
Safety consequences
The read/validate/write split has two safety properties:
- Local analysis is free.
search,build, andschemas validatehave no network dependency after the cache is populated. Iterating a codemod design is fast and cheap because you're not round-tripping to GitHub. - Writes are audited by construction. Every pen write leaves a trail: first a pen workspace on disk (on a branch whose name matches the pen name), then as a branch on the remote (pushed on nave pen run), and eventually a PR (on nave pen open), merged with nave pen merge. You can revert or clean up at any stage without touching your default branch.
Failure modes
Each phase is conscious of the potential issues and care is taken so the fleet moves without leaving any individual repo in an inconsistent state.
Several commands will halt if the workspace has untracked/uncommitted files (what git calls a "dirty" state), and repos are checked for freshness by nave scan to avoid commits being rejected upon push (where the local git state was not updated to reflect the remote's).
Additionally, since editing config files can produce invalid config,
schema validation is performed wherever possible (including for GitHub Actions
based on the declared inputs from the remote action.yml).
There is a "four dimensional" model of the state of each repo that can be tracked using the
status/show/list commands:
- Working tree cleanliness (vs. the git state), which can be ensured by nave pen clean
- Local repo freshness (vs. the remote), which can be ensured by nave pen revert
- Completion of a rewrite operation (committing and pushing to the remote) from nave pen run
- PR state, modified upon nave pen open, nave pen merge and nave pen close