Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .agents/skills/repo-worktree/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ in the new tree.
- **Husky.Net:** When `.husky/pre-commit` sources `.husky/_/husky.sh` and the local .NET tool
manifest declares Husky.Net, run `dotnet tool restore`, then `dotnet husky install` from the
worktree root.
- **Python pre-commit:** When `.pre-commit-config.yaml` exists, install the repository's declared
Python environment, then run `pre-commit install` through that environment. A uv project runs
`uv sync --frozen`, then `uv run pre-commit install`.
- **Python pre-commit:** When `.pre-commit-config.yaml` exists, run `uv tool install pre-commit`
once per host if not already installed, then `pre-commit install` from the worktree root.
`pre-commit` is never a project dependency, so this is the same regardless of profile.
- **Repository override:** Follow a repository's explicit hook-setup instructions when they
differ from these standard cases. Do not infer a replacement command from the language alone.

Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/fleet-skills/.source-digest
Original file line number Diff line number Diff line change
@@ -1 +1 @@
309580363f245493
332c16d2c066383b
6 changes: 3 additions & 3 deletions .claude-plugin/fleet-skills/skills/repo-worktree/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ in the new tree.
- **Husky.Net:** When `.husky/pre-commit` sources `.husky/_/husky.sh` and the local .NET tool
manifest declares Husky.Net, run `dotnet tool restore`, then `dotnet husky install` from the
worktree root.
- **Python pre-commit:** When `.pre-commit-config.yaml` exists, install the repository's declared
Python environment, then run `pre-commit install` through that environment. A uv project runs
`uv sync --frozen`, then `uv run pre-commit install`.
- **Python pre-commit:** When `.pre-commit-config.yaml` exists, run `uv tool install pre-commit`
once per host if not already installed, then `pre-commit install` from the worktree root.
`pre-commit` is never a project dependency, so this is the same regardless of profile.
- **Repository override:** Follow a repository's explicit hook-setup instructions when they
differ from these standard cases. Do not infer a replacement command from the language alone.

Expand Down
6 changes: 3 additions & 3 deletions .github/skills/repo-worktree/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ in the new tree.
- **Husky.Net:** When `.husky/pre-commit` sources `.husky/_/husky.sh` and the local .NET tool
manifest declares Husky.Net, run `dotnet tool restore`, then `dotnet husky install` from the
worktree root.
- **Python pre-commit:** When `.pre-commit-config.yaml` exists, install the repository's declared
Python environment, then run `pre-commit install` through that environment. A uv project runs
`uv sync --frozen`, then `uv run pre-commit install`.
- **Python pre-commit:** When `.pre-commit-config.yaml` exists, run `uv tool install pre-commit`
once per host if not already installed, then `pre-commit install` from the worktree root.
`pre-commit` is never a project dependency, so this is the same regardless of profile.
- **Repository override:** Follow a repository's explicit hook-setup instructions when they
differ from these standard cases. Do not infer a replacement command from the language alone.

Expand Down
2 changes: 1 addition & 1 deletion AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ A check with `intentRef`/`workflowRef` points at the prose section that owns the
- **carried-scope** - the repo carries no file the hub hosts rather than carries. The set is derived, not listed: the hub's git-tracked paths minus the [`spec/files.json`][files] baseline, so a file dropped from the manifest starts being reported on the next run with no retirement list to remember to edit. The remedy is the opposite of every other file finding, a **deletion**, since the repo reaches the hub's copy per [GOVERNANCE.md "Hub-Hosted Tooling"][governance-hub-hosted-tooling]. The match is on path alone, so a hit is a candidate and not a verdict: a repo's own content at a path the hub also uses matches while carrying nothing of the hub's, which the first fleet run showed twice, a KiCad tooling doc at `scripts/README.md` and per-repo formatting hooks at `.husky/pre-commit`. A [`spec/divergences.json`][divergences] `gaps` disposition decides which case a hit is, so only `retire` asserts a deletion, `accepted` closes a collision or a repo-owned file, and an untriaged hit is read before it is acted on.
- **verbatim-tree** - every applicable `trees[]` declaration in [`spec/files.json`][files] owns its target tree. The audit reports missing files as letter findings, stale or modified bytes as drift, and extra files under a pruned target as drift. An unreadable or truncated repository tree is undecided and produces drift rather than a clean result.
- **repo-setup** - every required secret for the repo's publish mechanisms is configured, and no forbidden secret is present (per [`spec/secrets.json`][secrets]).
- **linter-parity** - one config per linter (`.markdownlint-cli2.jsonc`, `cspell.json`, ruff/pyright, editorconfig/csharpier, actionlint) drives the editor extension, the CLI, and CI, and CI runs each. A local hook exists and runs at minimum the diff-scoped prose gate and the eol check (`parity.hooks`, intent). A repo with none wired is a defect, and one mid-convergence on the language-formatting half stays operational.
- **linter-parity** - one config per linter (`.markdownlint-cli2.jsonc`, `cspell.json`, ruff/pyright, editorconfig/csharpier, actionlint) drives the editor extension, the CLI, and CI, and CI runs each. A local hook exists and runs at minimum the diff-scoped prose gate and the eol check via `hub-fetch-run.py`, or the hub's own local script copies for the hub repo itself (`parity.hooks`, intent). A repo with none wired is a defect, and one mid-convergence on the language-formatting half stays operational.
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
- **recurring-violations** - comments concise and non-narrative, ASCII only (no em-dash, no smart quotes), US spelling, line endings per `.editorconfig`. These are frequent regressions, so this dimension is high priority and always runs, and each check is grep-able (see below).
- **readme-structure** - the README follows [`spec/readme-structure.md`][readme-structure] (applicable sections, in order). Mechanically checked against the declared model in [`spec/readme-sections.json`][readme-sections]: required sections present, declared sections in their relative order, `License` last, the shields each deliverable implies, the license shield in the closing License section, and the tagline and its mirrors. A heading the model does not name is dropped before the order comparison, so a repo-specific section is never a finding.

Expand Down
2 changes: 1 addition & 1 deletion GOVERNANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ CI runs the full lint set, but run the linters locally before pushing to catch i
- **CI (authoritative)** runs **markdownlint-cli2**, **cspell**, and **actionlint** as pinned action wrappers (Dependabot bumps them), plus **editorconfig-checker** via Docker `:latest` (its action only installs the CLI, so the Docker one-liner is what actually runs the check), **shellcheck** and **shfmt** the same way for a repo that carries a shell script, and, **for a repo that carries `.ps1` files**, **PSScriptAnalyzer** the same way (none of the three has an action). markdownlint covers all `**/*.md`, and **cspell is scoped to `README.md` + `HISTORY.md`** (see [CODESTYLE.md](./CODESTYLE.md) "Markdown and Spelling" for why), matching the cspell one-liner below. A "shell script" here is a tracked `.sh` file, plus a tracked, extension-less file whose shebang names bash or sh, the shape a script meant to run as a bare command takes: a bare `*.sh` glob misses that second case, so both discovery paths run before either tool does. This whole block is the hub's `validate-task.yml` reusable workflow, so a fleet repo reaches it rather than carrying a copy of these steps.
- **A working local hook is strongly suggested fleet-wide, and its absence is a measured audit finding, not an invisible gap.** `spec/project-types.json`'s `parity.hooks` check reads this section for its rationale, judged by hand during an `AUDIT.md` run like every sibling check in its dimension, never mechanized by `spec/audit.py`: a repo with no local hook mechanism wired at all is a `linter-parity` defect, the same severity a missing markdownlint config already gets, while a repo mid-convergence (below) stays operational. CI remains the authoritative run regardless. Two catalog snippets carry the canonical shape, `catalog/snippets/husky/` (Husky.Net, for .NET or any project including Python) and `catalog/snippets/pre-commit/` (the Python `pre-commit` framework, for a repo with no `.husky/` tree), each carrying a copy of `catalog/snippets/hub-fetch-run.py` alongside it.
- **The hook** runs **language formatting** and the **diff-scoped doc gates**, never Docker, so it stays fast. The formatting half is whatever the repo's own language needs, CSharpier and `dotnet format` for .NET or ruff and the repo's type checker for Python, via native tooling. A repo adds each half once its tree passes that half, since a gate that fails on the corpus it guards blocks every commit from the moment it lands, so a hook running one half is a repo mid-convergence rather than a repo out of conformance. The doc half runs each gate at the scope that fits it. The prose gate is scoped to the working tree diff against `HEAD` rather than swept over the tree, which is the difference between about 2.2 seconds and about 0.13 and is what makes it affordable in a hook at all. That scope is the working tree rather than the staged index, so a partially staged file is judged on all of its edits, not only the staged ones, and CI re-checks the whole tree regardless, which is what makes that scope affordable in a hook. A whole-repo check belongs there too when it is already fast and takes no file list, which the line-ending consistency check is, so scope is a property of the gate rather than a rule the hook applies to all of them. `repo_gate.py --check sha-pin` stays out of the hook regardless, since it resolves a same-owner pin against the GitHub API.
- **The doc gates reach a downstream repo by fetching `.github/actions/prose-gate/prose_lint.py` and `.github/actions/repo-gate/repo_gate.py` fresh from `ptr727/ProjectTemplate`'s `main` branch, via `hub-fetch-run.py`, never vendored and never pinned.** Pinning anything Dependabot does not maintain goes stale by construction, and CI (this repo's own, and the hub's) is the backstop that catches a change landing broken on `main` before a locally fetched copy does real damage. These are the only network calls the hook makes, one per fetched script, the same category of dependency as the Docker pulls the VS Code Lint tasks already do routinely, not a new one. A fetch failure fails the commit, and it never silently skips the gate. The **hub's own** `.husky/pre-commit` is the one exception, staying local and offline, since it already carries `scripts/prose_lint.py` and `scripts/repo_gate.py` directly and has no hub to reach. A repo enables its hook per clone with `git config core.hooksPath .husky` or `uv run pre-commit install`, and CI remains the authoritative run either way.
- **The doc gates reach a downstream repo by fetching `.github/actions/prose-gate/prose_lint.py` and `.github/actions/repo-gate/repo_gate.py` fresh from `ptr727/ProjectTemplate`'s `main` branch, via `hub-fetch-run.py`, never vendored and never pinned.** Pinning anything Dependabot does not maintain goes stale by construction, and CI (this repo's own, and the hub's) is the backstop that catches a change landing broken on `main` before a locally fetched copy does real damage. These are the only network calls the doc gates make, one per fetched script. A Python repo's `uvx`-run ruff and type checker can also reach the network, to resolve `@latest` on a cache miss or refresh, the same category of dependency as the Docker pulls the VS Code Lint tasks already do routinely, not a new one. A fetch failure fails the commit, and it never silently skips the gate. The **hub's own** `.husky/pre-commit` is the one exception, staying local and offline, since it already carries `scripts/prose_lint.py` and `scripts/repo_gate.py` directly and has no hub to reach. A repo enables its hook per clone with `git config core.hooksPath .husky` or (`uv tool install pre-commit` once, then) `pre-commit install`, and CI remains the authoritative run either way.
- **The VS Code Lint tasks** run the full doc-lint set via Docker `:latest` on demand, the local surface for Markdown, spelling, workflow, and EditorConfig checks, plus `Lint: Prose` and `Lint: EOL`, the same two hook gates in whole-repo mode rather than diff-scoped, for on-demand full-tree validation.

The Docker invocations below run the same tools and configs as the VS Code tasks. Their headless form separates the image pull and minimizes repository exposure for an agent executor.
Expand Down
2 changes: 1 addition & 1 deletion STANDUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Carry `AGENTS.md`'s skill-dependency pointer paragraph, the one naming `scripts/

Choose the destination while scaffolding rather than after. Repo-specific content left in a carried file is drift, which the audit lists as an undeclared section to reconcile, and reconciling it later means moving prose that downstream readers have already started trusting in the wrong place.

**Wire a local commit hook here, not after the fact.** `.husky/pre-commit` and `.pre-commit-config.yaml` are deliberately excluded from the baseline above (each repo's own formatters make the content repo-owned, per [`spec/divergences.json`][divergences]), so nothing in the carry step above wires one. Copy and adapt the applicable catalog snippet, `catalog/snippets/husky/` for Husky.Net or `catalog/snippets/pre-commit/` for the Python `pre-commit` framework, each with `catalog/snippets/hub-fetch-run.py` alongside it, and enable it (`git config core.hooksPath .husky` or `uv run pre-commit install`) before the section 5 audit run. A freshly stood-up repo with nothing wired starts pre-failed on `parity.hooks`.
**Wire a local commit hook here, not after the fact.** `.husky/pre-commit` and `.pre-commit-config.yaml` are deliberately excluded from the baseline above (each repo's own formatters make the content repo-owned, per [`spec/divergences.json`][divergences]), so nothing in the carry step above wires one. Copy and adapt the applicable catalog snippet, `catalog/snippets/husky/` for Husky.Net or `catalog/snippets/pre-commit/` for the Python `pre-commit` framework, each with `catalog/snippets/hub-fetch-run.py` alongside it, and enable it (`git config core.hooksPath .husky`, or `uv tool install pre-commit` once then `pre-commit install`) before the section 5 audit run. A freshly stood-up repo with nothing wired starts pre-failed on `parity.hooks`.

## 3. Stand Up the Workflows

Expand Down
2 changes: 2 additions & 0 deletions catalog/snippets/configs/vscode-tasks-python.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@
// Lint: Prose and Lint: EOL below add the same two checks in whole-repo mode, for on-demand full-tree validation.
// Lint: EditorConfig/Workflows/Markdown/Spelling are language-agnostic, identical to the
// .NET snippet's Lint group.
// Lint: Prose and Lint: EOL assume the pre-commit-framework layout (hub-fetch-run.py at the workspace root).
// A repo using the Husky.Net snippet instead points these two tasks at .husky/hub-fetch-run.py.
{
"label": "Lint: EditorConfig",
"type": "process",
Expand Down
14 changes: 8 additions & 6 deletions catalog/snippets/pre-commit/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Reference pre-commit (pre-commit.com) config for a fleet Python repo with no .NET/Husky.Net tree.
# Copy into the repo root alongside ../hub-fetch-run.py.
# Adapt the type-check hook to match this repo's own CI checker (pyright or mypy, per python-codestyle).
# Enable with `uv run pre-commit install`.
# The type checker and ruff hooks are native/uv-run, no Docker.
# Install and enable with `uv tool install pre-commit` once, then `pre-commit install`.
# The type checker and ruff hooks run via uvx, native tooling, no Docker.
# That needs no project dependency, matching CI's own invocation for the lint-only profile.
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
# A repo on the build profile with a uv.lock may swap an entry for `uv run <tool>` to pin its own project version instead.
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
# The prose/EOL hooks fetch their scripts fresh from ptr727/ProjectTemplate's `main` branch via hub-fetch-run.py, rather than vendoring or pinning a copy.
# See that file's docstring for why.
# A fetch failure fails the commit, and it never silently skips the gate.
Expand All @@ -11,17 +13,17 @@ repos:
hooks:
- id: ruff-format
name: ruff format --check
entry: uv run ruff format --check
entry: uvx ruff@latest format --check
language: system
pass_filenames: false
- id: ruff-check
name: ruff check
entry: uv run ruff check
entry: uvx ruff@latest check
language: system
pass_filenames: false
- id: type-check
name: pyright (swap for "uv run mypy" if this repo's CI runs mypy instead)
entry: uv run pyright
name: pyright (swap for "uvx mypy@latest ." if this repo's CI runs mypy instead)
entry: uvx pyright@latest
language: system
pass_filenames: false
- id: prose-gate
Expand Down
30 changes: 20 additions & 10 deletions catalog/snippets/pre-commit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,30 @@

`.pre-commit-config.yaml` is the reference config for the Python `pre-commit` framework
(pre-commit.com), for a Python repo with no `.husky/` tree of its own. It runs `ruff format
--check`, `ruff check`, and this repo's declared type checker (`pyright` or `mypy`, match
whichever `python-codestyle` says this repo's CI runs) via `uv run`, native tooling, no
Docker, plus the same two shared doc gates the Husky.Net snippet carries: the diff-scoped
prose/comment-style gate and the whole-tree line-ending check.
--check` and `ruff check`. It also runs this repo's declared type checker, `pyright` or
`mypy`, matching whichever `python-codestyle` says this repo's CI runs. Each tool runs via
`uvx`, native tooling, never Docker. `uvx` needs no project dependency, matching CI's own
invocation for the lint-only profile (`CODESTYLE.md` "Two profiles"). A repo on the build
profile with a `uv.lock` may swap in `uv run <tool>` per entry to pin the project's own
version instead. The config also runs the same two shared doc gates the Husky.Net snippet
carries: the diff-scoped prose/comment-style gate and the whole-tree line-ending check.

Copy `../hub-fetch-run.py` alongside `.pre-commit-config.yaml` (repo root) for the doc gates
to run: it fetches those two checks fresh from `ptr727/ProjectTemplate`'s `main` branch and
runs them, rather than vendoring or pinning a copy. A pin nothing keeps current goes stale by
construction, and CI (this repo's own, and the hub's) is the backstop for a change that lands
broken on `main` before it does real damage locally. This is one more network fetch alongside
the Docker pulls the VS Code Lint tasks already do. A fetch failure fails the commit rather
than silently skipping the gate.
runs them, rather than vendoring or pinning a copy. A pin that no tool keeps current goes
stale by construction, and CI (this repo's own, and the hub's) is the backstop for a change
that lands broken on `main` before it does real damage locally. These are two more network
fetches alongside the Docker pulls the VS Code Lint tasks already do. A fetch failure fails
the commit rather than silently skipping the gate.

Enable the hook with `uv run pre-commit install`. Full linting (workflow YAML, Markdown,
Install and enable with `uv tool install pre-commit` once, then `pre-commit install`.
`pre-commit` itself is never added as a project dependency: the lint-only profile has no
project environment to add it to, and `uv tool install` gives a persistent, PATH-available
command independent of any project, the same footing `uvx` gives the tools the hooks run.
Comment thread
ptr727 marked this conversation as resolved.
If `pre-commit install` reports the command not found right after installing it, `uv tool
install`'s own bin directory is not yet on `PATH`: run `uv tool update-shell` and restart or
re-source the shell, or add the directory `uv tool dir --bin` prints directly.
Full linting (workflow YAML, Markdown,
spelling, EditorConfig) stays out of the hook: it runs in CI as pinned action wrappers, and on
demand via the VS Code **Lint** tasks in `catalog/snippets/configs/vscode-tasks-python.json`
(Docker at `:latest`), which also carries the same prose/EOL gates in whole-repo mode for
Expand Down
Loading