Skip to content

Promote the Fleet Skills, the Windows and Docker Host Setup, and the Python CI Gates - #718

Merged
ptr727 merged 30 commits into
mainfrom
develop
Aug 15, 2026
Merged

Promote the Fleet Skills, the Windows and Docker Host Setup, and the Python CI Gates#718
ptr727 merged 30 commits into
mainfrom
develop

Conversation

@ptr727

@ptr727 ptr727 commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Thirty-one squashes, 56f4d7d..d54862a. 115 files, +20436/-5298.

Merge with a merge commit, never a squash, and never with --delete-branch. This pull request's head is develop itself.

What lands

Fleet Skills. The .agents/skills/ source tree, the generated .claude-plugin/ distribution, scripts/build_dist.py with its --check gate, and scripts/skills_install.py with its host stamp (#676). Packaged as skills on top of the scaffold: PR review conduct and Copilot instructions upkeep (#677), comment and doc style (#678), resync-a-repo and fleet-conformance-check (#679), the per-language codestyles (#680), git commit conventions and operational vs release workflow (#681), stand up a repo (#683), and repo-worktree (#717). Coverage gaps closed in three passes (#690, #691, #692) plus the P4 sentence-length opt-in (#697).

Host setup. The Windows host-setup tooling and its PowerShell gate (#674), the Windows bootstrap loader (#682), Docker install and upgrade on Linux and Windows with a version floor (#701, #705), a uv floor in spec/host-tools.json (#698), self-healing of a shadowing uv, jq, or git-restore-mtime copy (#689), node's real winget package id (#696), and a README for the Linux host-setup nuances (#710).

Python and CI. Python tooling in CI with the script tests moved to scripts/tests (#704), ruff format adopted and gated (#709), and the PSScriptAnalyzer claim conditioned on repos that carry .ps1 files (#686).

Conduct rules. Triage-order and scope guardrails in pr-review-conduct (#684), pr_review.py wait requesting a review rather than only polling for one (#685), a tech-agnostic signed-commit verification (#708), execution rather than analogy to verify platform-specific code (#715), and a unique worktree for every task (#717).

Docs. The fleet map and gap register with peer messaging declared (#687), mermaid flow diagrams in the kept-authority docs (#702), and the map pointed at the shipped diagrams and current tooling (#703).

Issues this promotion closes

Each landed on develop on its own pull request. The keyword fires only on a merge into main, so it sits here rather than on the feature pull requests.

Closes #700
Closes #707
Closes #711
Closes #712
Closes #714
Closes #688

#699 stays open on purpose: #717 shipped the layout convention and the skill, and the physical migration of existing checkouts is still tracked there.

Review record

Every squash closed its own Copilot loop on its own pull request before merging to develop. This promotion carries no new content of its own, so its review is the merged tree as a whole.

Consequence worth stating

The GOVERNANCE.md and AGENTS.md sections these squashes changed become the canonical the moment this reaches main, and every carrying repository reads as drifted from that point until it resyncs. That is the ordinary consequence of a canonical moving rather than a defect. The Skills installer added here is also how a machine picks the new skills up, so a session that keeps restating a rule already packaged as a skill is the signal to run it.

ptr727 and others added 30 commits August 11, 2026 08:57
…#674)

`host-setup/` carried Linux tooling only, so every Windows setup step
was a manual read of the matrix in #483. This makes that column
executable, and it was written and run on a Windows host rather than
translated.

## What Lands

`host-setup/windows/`, four scripts and a README, mirroring the Linux
design where it applies and diverging where Windows genuinely differs.

| Script | Does |
| --- | --- |
| `install-tools.ps1` | Installs and upgrades the eight managed tools,
and reports version, source, scope and status |
| `upgrade-host.ps1` | Upgrades the winget packages, and updates the WSL
platform behind a Docker guard |
| `setup-github.ps1` | The SSH key, git identity, commit signing, the
agent, and `gh` |
| `setup-wsl.ps1` | Installs a distribution, and reports the Docker
Desktop integration |

Plus `PSScriptAnalyzerSettings.psd1` and a CI step, per-platform
coverage in `scripts/test_bootstrap.py`, and the documentation.

## Three Decisions Worth Reviewing

**winget is the only source.** Every tool in the contract has a winget
package, measured, so the three-source machinery the Linux script needs
for feeds that trail upstream has nothing to do here. A tool that ever
lacks one is a finding to raise rather than a second source to add
quietly.

**Nothing elevates, and no scope is passed unless one is named.**
Forcing user scope installs a second copy beside a machine wide one
rather than upgrading it, some installers fail when launched from an
already elevated process, and a user scope install made from an elevated
process lands in the administrator's profile. Letting each installer
raise its own prompt is the path with the fewest failures. Scope drift
is reported instead, with a `SCOPE` column, and `-Reinstall` is the only
action that removes anything.

**A package winget will not move is reported apart, with no command
beside it.** Its manifest asks for that because the application updates
itself, so the version winget shows is the installer's rather than the
one it runs. `MSYS2` is the worked example: it upgrades through
`pacman`, and printing `winget upgrade --id MSYS2.MSYS2` beside a
permanently stale number invites a reinstall over a working copy.

## The PowerShell Gate

Built as the peer of the shellcheck step, per the same model: the file
list comes from `git ls-files`, the checker runs as a container, and the
same invocation is documented in `GOVERNANCE.md` and `OPERATIONS.md` so
a local run and CI are the same check.

The module version is pinned beside the image, because the image alone
does not fix it. `1.23.0` rather than the newest, since `1.24.0` needs a
newer `System.Management.Automation` than the image carries and fails to
import after installing cleanly, which reads as a broken gate rather
than a version mismatch.

**The file count is printed because this gate lied on its first
invocation.** It reported `no findings` while analyzing zero files,
since the argument list never reached the container. That is the failure
mode the repository is built against, and the count is what caught it.

Two rules are excluded with their reasons in the settings file:
`PSAvoidUsingWriteHost`, since these scripts write their report to the
console as their whole purpose and returning exit codes through the
pipeline makes `Write-Output` wrong rather than merely different, and
`PSUseShouldProcessForStateChangingFunctions`, since every script
already carries `-DryRun` and a confirm prompt and adding `-WhatIf`
beside them would give a reader two spellings of preview.

## test_bootstrap.py

Coverage now asserts per platform, since the two installers do not
manage the same set and the difference is a decision:
`git-restore-mtime` is not applicable on Windows, and `docker` is one
winget package there where the Linux answer differs by host role.
`NOT_MANAGED['windows']` is empty rather than absent, which is itself
the assertion.

The executability check now reads the mode **git** records rather than
the filesystem's. NTFS carries no exec bit, so `st_mode` reported every
file as non-executable and the check failed on Windows against a correct
tree. What the loader depends on is the mode a Linux checkout gets,
which is the one git stores.

The loader invariant is deliberately unchanged. No `bootstrap.ps1`
lands, so `bootstrap.sh` still reads exactly one path, and widening that
set before a Windows loader exists would retire the invariant ahead of
the thing it protects.

## Documentation

`docs/host-setup.md` gains the PowerShell verification block #483
deferred until somebody had run it on a Windows host, and the real
reason for `py -3` over `python`: an activated virtual environment
shadows `python`, so the host gate would grade the environment rather
than the host. The Store alias stub rules out `python3` and chooses
nothing between the other two, which is a weaker argument than the doc
previously carried.

## Verified on This Host

Windows 11 Pro 10.0.26200, PowerShell 7.6.4, winget v1.29.280, WSL
2.7.10.0, unelevated.

Every repository gate passes: `prose_lint`, `repo_gate`, `markdownlint`,
`actionlint`, `editorconfig-checker`, `PSScriptAnalyzer` over 5 files,
and all seven script self-tests. `git ls-files --eol` confirms CRLF on
every new file, and no `.ps1` opens with a shebang.

Both guards were proven to fire under `-DryRun` rather than printing a
command: `upgrade-host.ps1 -Wsl` refuses while Docker Desktop runs, and
an `-Upgrade` whose `-Scope` disagrees with the installed copy refuses
and names `-Reinstall`. The coverage assertion was proven to bite by
deleting `docker` from the registry and watching the test fail.

The apply path ran for real: `install-tools.ps1 -Upgrade uv -Yes` moved
`uv` from `0.11.32` to `0.12.2` and the re-report reads `current`. Its
first attempt failed because a running process held `uv.exe`, which is
why the failure path now names the holding process instead of leaving
winget's bare access denial.

## Raised, Not Fixed Here

Three findings about the Linux side or the fleet, none blocking this:
#671 the linter category is an undocumented decision rather than a
missing feature, #672 `gh` uses https where the contract prescribes ssh
and neither script checks it, and #673 the Linux scripts should refuse
two actions instead of letting the last one win. All three are recorded
in `TODO.md`.

Closing keywords are deliberately absent, per the branching model: they
belong on the `develop -> main` promotion.
)

## What

Phase 0 and Phase 1 of a multi-phase plan to convert the hub's
instruction-heavy docs (comment
style, PR-review conduct, resync safety) into Claude Code / opencode /
Codex Skills, so the rules
surface automatically instead of needing to be re-read every session.
Opening now, early, to get a
read on the foundation (the distribution mechanism, the installer)
before building the remaining
~6 phases on top of it. Expect further commits landing on this same PR
as later phases ship.

**Phase 0 (scaffolding, no skill content yet):**
- `.agents/skills/` — canonical, hand-authored home for fleet skills.
Codex and opencode read this
  path natively, zero config.
- `scripts/build_dist.py` — generates a Claude-plugin-compatible copy at
`.claude-plugin/fleet-skills/` (Claude Code does not scan
`.agents/skills/` directly), with
  `--check` for CI staleness gating.
- `scripts/skills_install.py` (+ `skills_install.sh`/`.ps1` thin
wrappers, mirroring
`host-setup/agent-safety/install.py`'s shape) — materializes
`~/.agents/skills` for Codex/opencode
and registers the marketplace with Claude Code via the real `claude
plugin marketplace add`/
  `install` CLI, with `--report` for staleness checks.
- `.claude-plugin/marketplace.json` — the Claude Code entry point.
- `AGENTS.md` pointer (in "Where the Rules Live", verbatim/carried)
naming the dependency.

**Phase 1: `carried-instruction-file-guard` skill.** Encodes
`spec/section-model.md`'s
"Migrating a repo onto the split" procedure (the distinctive-phrase
probe) as an active pre-flight
check before any
`AGENTS.md`/`GOVERNANCE.md`/`CODESTYLE.md`/`WORKFLOW.md` overwrite,
rather than
the prose-only advisory it was before. This is the highest-leverage
skill in the plan: it directly
targets the bug class that once silently deleted a downstream repo's
local `AGENTS.md` additions
during a resync.

## Why nested under `.claude-plugin/` instead of a top-level `dist/`

First draft generated output at `dist/claude/`, which collided with this
repo's existing
Python-build-artifact `dist/` gitignore entry. Moved to
`.claude-plugin/fleet-skills/` instead,
avoiding the name clash entirely rather than punching a hole in a
blanket ignore.

## Verification

- Ran the real install against a scratch `AGENTS_HOME`, confirmed via
`claude plugin marketplace
list` / `plugin list` that registration and install actually worked,
then cleaned up.
- `claude plugin validate` passes clean on both manifests.
- 13 new unit tests, all passing.
- `repo_gate.py` (`eol`, `eol-coverage`), `prose_lint.py` (diff),
`spec/validate.py` all clean.
- **Live triggering test for the guard skill**: loaded it via `claude
--plugin-dir`, prompted a
session to blindly copy a canonical `AGENTS.md` over a scratch repo's
`AGENTS.md` carrying a
local addition. It triggered, identified the local section, refused the
overwrite, and proposed
relocating the content before carrying the rest — the exact procedure it
specifies.

Also logs a `TODO.md` cluster (unrelated to this PR's diff otherwise)
for defaulting `.py` to LF
fleet-wide, found while pinning the two new scripts individually.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…677)

Phase 2 of the hub-docs-to-Skills conversion (Phase 0/1 shipped in
#676).

## What this adds

- **`pr-review-conduct`** — the merge gate, expected review loop, the
five finding-outcomes, triage, and suppressed-finding answering rules,
extracted from `GOVERNANCE.md` "PR Review Etiquette".
- **`copilot-instructions-keeper`** — new content (not derived from
existing prose) for keeping a downstream repo's
`.github/copilot-instructions.md` in sync with the hub canonical without
losing that repo's own "Disproved Claims" ledger entries, which the
file's own rules say are never carried between repos.

## What changed in existing files

- `GOVERNANCE.md` "PR Review Etiquette" shrinks from the full contract
text to a two-paragraph pointer at the `pr-review-conduct` skill, per
this project's standing decision that a skill becomes the sole canonical
content for its topic once one exists (see #676's plan doc).
- `.github/copilot-instructions.md` is **untouched** — the Copilot
review bot reads it directly and cannot read a Skill, so its runbook
content stays fully intact by design.
- `AGENTS.md` "Where the Rules Live" table and closing paragraph updated
to route to both new skills.
- `.claude-plugin/fleet-skills/` regenerated via `scripts/build_dist.py`
to carry the two new skills alongside `carried-instruction-file-guard`
from Phase 1.

## Verification performed

- `scripts/prose_lint.py`, CRLF byte-integrity, `editorconfig-checker`
(docker), `spec/validate.py`, `scripts/test_build_dist.py` +
`scripts/test_skills_install.py` (46 tests) all clean.
- `scripts/build_dist.py --check` confirms the generated plugin is
current relative to `.agents/skills/`.
- Live-triggered both skills via `claude --plugin-dir
.claude-plugin/fleet-skills -p "..."` against realistic prompts ("it's
all green, go ahead and merge" for `pr-review-conduct`; "just a routine
copy-over, right?" for `copilot-instructions-keeper`) — both fired
correctly and produced accurate, grounded answers without the rule being
restated manually.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Package Comment and Doc Style as a Skill

Phase 3 of the hub-docs-to-Skills conversion (Phase 0/1 shipped in #676,
Phase 2 in #677).

## What this adds

- comment-and-doc-style, extracted from CODESTYLE.md's General section
  (Tooling Names and Casing, Markdown and Spelling) plus GOVERNANCE.md's
  Documentation Style Conventions and Pull Request Title and Commit
  Message Conventions sections: naming tools in prose, Markdown linting
  and spelling, Markdown formatting, comment philosophy, the ASCII
  character-set tiers, line endings, the carried-file coordination
  reference ban, and PR title/commit message conventions.
- Three references/ files for progressive disclosure: line-endings.md
  (the full CRLF/LF policy), carried-doc-references.md (the full
  coordination-reference rule and its two exceptions), and
  markdown-links.md (the full reference-style-link convention).

## What changed in existing files

- CODESTYLE.md's General section: Tooling Names and Casing and Markdown
  and Spelling shrink to pointers at the skill. Clean-Compile
  Verification and Analyzer Diagnostics and Suppressions are untouched,
  they are build-gate topics, not comment or doc style.
- GOVERNANCE.md's Pull Request Title and Commit Message Conventions and
  Documentation Style Conventions sections shrink to pointers, per this
  project's standing decision that a skill becomes the sole canonical
  content for its topic once one exists. The Comments, Character Set,
  and Line Endings headings stay in place (spec/files.json and
  spec/project-types.json anchor to them by name), their content is now
  a one-line pointer each.
- AGENTS.md's Where the Rules Live table routes both rows to the new
  skill.
- .claude-plugin/fleet-skills/ regenerated via scripts/build_dist.py to
  carry the new skill alongside the three from Phases 1 and 2.

## Verification performed

- scripts/prose_lint.py, CRLF byte-integrity (all touched files remain
  100% CRLF), editorconfig-checker (docker), spec/validate.py,
  markdownlint-cli2, scripts/test_build_dist.py +
  scripts/test_skills_install.py (46 tests) all clean.
- scripts/build_dist.py --check confirms the generated plugin is
  current relative to .agents/skills/.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Phase 4 of the hub-docs-to-Skills conversion (see #676, #677, #678 for
Phases 0-3).

## What this adds

- **`resync-a-repo`** (hub-only): packages `RESYNC.md` section 3's apply
order for a hub-context session driving a named repo's resync. The
`carried-instruction-file-guard` skill's distinctive-phrase probe is now
a mandatory, non-skippable step before any verbatim re-vendor of an
instruction file, the direct structural fix for the AGENTS.md-overwrite
bug class rather than a rewording of existing advisory language.
- **`fleet-conformance-check`** (fleet-wide, `appliesTo: "*"`, new
content): the downstream-facing counterpart. Runs from inside a repo's
own session with no hub checkout and no named target other than the repo
itself. Confirms the local Skills install is current, confirms
`AGENTS.md`'s pointer text matches the hub, self-applies what is safe
(re-running the installer), and escalates anything ambiguous (a genuine
local addition, a settings/workflow drift) to a hub-driven
`resync-a-repo` run rather than touching it.

## Supporting changes

- `RESYNC.md` section 3 step 1 gains the mandatory probe requirement and
the `AGENTS.md` skill-dependency pointer as one more verbatim-carried
unit in the same step.
- `AGENTS.md`'s "Where the Rules Live" table and pointer paragraph route
to both new skills.
- `.claude-plugin/fleet-skills/` rebuilt via `build_dist.py` (now 6
skills).

## Verification

- `python3 -m unittest discover -s scripts -p "test_*.py"`: 628 tests,
all pass.
- `python3 scripts/prose_lint.py` on all touched files: clean.
- `python3 spec/validate.py`: clean.
- `docker run ... mstruebing/editorconfig-checker:latest`: clean.
- CRLF preserved on all touched Markdown.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Phase 5 of the hub-docs-to-Skills conversion (Phase 0/1 shipped in #676,
Phase 2 in #677, Phase 3 in #678, Phase 4 in #679).

## What this adds

- `dotnet-codestyle` (appliesTo csharp), `python-codestyle` (appliesTo
python), and `shell-codestyle` (appliesTo *, since a shell script can
appear in any repo), extracted from CODESTYLE.md's .NET, Python, and
Shell sections respectively: build/analyzer requirements, language and
naming conventions, logging and testing conventions, the Python
build-versus-lint-only profile split and toolchain, and the shell `set
-Eeuo pipefail` / pipefail-early-reader / shellcheck rules.
- This is the first phase gating a skill by `appliesTo` rather than
fleet-wide `*`, expressed through each skill's own trigger wording (file
extensions and project shape) rather than a mechanical field, since
SKILL.md frontmatter carries no such field.

## What changed in existing files

- CODESTYLE.md's .NET, Python, and Shell sections shrink to pointers,
per this project's standing decision that a skill becomes the sole
canonical content for its topic once one exists. No spec file or test
references any subheading inside these three sections, so each collapses
fully rather than keeping empty subheadings. Six now-orphaned link
reference definitions (MD053) are removed with them.
- CODESTYLE.md's and AGENTS.md's own descriptions of the file's
structure are corrected to mention the pre-existing Shell section, which
neither previously named.
- `.claude-plugin/fleet-skills/` regenerated via `scripts/build_dist.py`
to carry the three new skills alongside the six from Phases 1-4.

## Dropped

- `docker-codestyle` (Phase 5b): a content-discovery pass found no
dedicated Docker style section in CODESTYLE.md, only scattered
linter-invocation mentions in OPERATIONS.md and release mechanics in
GOVERNANCE.md, neither of which is Docker coding style. Not authored,
per the plan's own don't-invent-content instruction.

## Verification performed

- `scripts/prose_lint.py`, CRLF byte-integrity (all touched/new files
100% CRLF), `editorconfig-checker` (docker), `markdownlint-cli2`
(docker, 72 files, 0 issues), `spec/validate.py`,
`scripts/test_prose_lint.py` (223 tests), `scripts/test_build_dist.py`
(19 tests), and `scripts/test_skills_install.py` all clean.
- `scripts/build_dist.py --check` confirms the generated plugin is
current relative to `.agents/skills/`.
- Grepped `scripts/test_*.py` and `spec/*.json` for any coupling to the
trimmed CODESTYLE.md subheadings before trimming: none found.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
… Skills (#681)

## Summary

Phase 6 of the hub-docs-to-Skills conversion project (see #676-#680 for
prior phases).

Adds three fleet-wide Claude Code / opencode / Codex Skills, all
`appliesTo: "*"`:

- **`git-commit-conventions`**, derived from `GOVERNANCE.md` "Git and
Commit Rules": staging vs.
committing, commit-means-commit-and-push, signing verified not
configured, identity verified
not set, never force push, careful history rewrites, no destructive git
commands.
- **`operational-vs-release-workflow`**, derived from `GOVERNANCE.md`
"Branching Model",
"Release Model", and "Operational Repositories". One skill serves both
workflow models: its
own trigger description reads the registry's `workflowModel` field per
repo rather than gating
by repo type. Two `references/` files hold the deep CI-wiring detail
(branch protection and
promotion mechanics; release build and publish mechanics) via
progressive disclosure.
- **`upstream-contribution-workflow`** (new content, not derived from
any `GOVERNANCE.md`
section): the maintainer's own third-party-contribution workflow, a
dirty work branch on his
own fork for the actual work and review iteration, squashed once clean
to a second branch that
carries only the intended minimal history, that clean branch opened as
the PR against the
upstream repo, reviewer feedback applied to the dirty branch first and
then re-squashed.
  Triggers independent of the target repo's own type or workflow model.

`GOVERNANCE.md`'s four source sections are trimmed to short pointers,
per the standing "skill
becomes sole canonical content" decision. Their `## ` headings stay in
place, since
`spec/files.json` carries all four at `verbatim` fidelity by heading
name, only the body content
under each shrank. Checked before trimming: no `scripts/test_*.py`
couples to any of the four
sections' content or subheadings (the Phase 3 gotcha).

`AGENTS.md`'s "Where the Rules Live" table gains "packaged as the `X`
Skill" annotations on the
four affected rows, and `upstream-contribution-workflow` is added to the
explanatory paragraph
below the table (new content goes there, not a new table row, per the
Phase 2/4 precedent, since
that table pairs a task with a real `GOVERNANCE.md` section name).

## Verification

- `python3 scripts/build_dist.py`: regenerated
`.claude-plugin/fleet-skills/` from 12 skills clean.
- `python3 scripts/test_build_dist.py`, `python3
scripts/test_skills_install.py`: pass.
- `python3 scripts/prose_lint.py . --diff HEAD`: 0 violations (after
fixing one `dupword` false
  positive caused by awkward phrasing).
- `python3 scripts/repo_gate.py --check eol`: 0 issues (also re-verified
by the pre-commit hook).
- `npx markdownlint-cli2` against every new/changed Markdown file: 0
issues.
- Verified no `scripts/test_*.py` couples to any of the four trimmed
`GOVERNANCE.md` sections'
  content before trimming.
- Verified CRLF preserved on every touched file after every edit
(byte-level check, not visual).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
## What

Adds `host-setup/bootstrap.ps1`, a Windows counterpart to
`host-setup/bootstrap.sh`, so a Windows host with nothing can be stood
up from a copy-paste console snippet the same way a Linux host already
can.

## Why

Windows previously carried no loader, by a documented decision
(`host-setup/README.md`, `docs/host-setup.md`,
`host-setup/windows/README.md`'s "Why There Is No bootstrap.ps1"): *"the
Windows form of that problem has no one-liner anybody here has run, and
an unverified loader is worse than none."* This PR supersedes that
decision rather than ignoring it — the reasoning is kept and repurposed
as the reason `bootstrap.ps1` does more defensive work than its Linux
peer (TLS pinning, a tree-ownership marker, execution-policy handling,
self-installing its own prerequisite) rather than as the reason none
exists.

## How

- `bootstrap.ps1` runs under Windows PowerShell 5.1, the one shell a
fresh Windows host guarantees. It finds or installs PowerShell 7 via
`winget`, then hands the rest of the run to itself under `pwsh`.
- From there it mirrors `bootstrap.sh`: resolves the ref to a commit,
fetches/extracts the tarball with an ownership marker guarding cleanup,
and drives `upgrade-host.ps1` → `install-tools.ps1` → `setup-github.ps1`
in the same fixed order (packages first, GitHub last since it's the only
step waiting on a human in a browser).
- Adds a new `-Wsl` action (report-only — `setup-wsl.ps1` has no Linux
peer, and no flag here collects a distribution name to install one
unattended).
- Sits beside `bootstrap.sh` at `host-setup/` rather than inside
`host-setup/windows/`, the same one-concern-two-platforms shape
`agent-safety/install.sh` + `install.ps1` already uses.
- Docs (`host-setup/README.md`, `docs/host-setup.md`,
`host-setup/windows/README.md`) updated to describe the new loader and
its Windows one-liner, replacing the "no bootstrap.ps1" sections.
- `scripts/test_bootstrap.py` extended: the loader-invariant tests
(fetched-tree-path, no-Python) now run against both loaders, plus a new
presence/no-shebang test for `bootstrap.ps1`.

## What this does not verify

Neither loader (the existing `bootstrap.sh` nor this new
`bootstrap.ps1`) has ever been run against a genuinely fresh host — only
dry runs and reads against an already-configured checkout. `TODO.md` now
tracks that as its own work cluster ("Neither Host Bootstrap Has Run
Against a Truly Fresh Host"), since closing it needs a human watching a
real run on a real fresh VM image, not more code.

## Verification performed

- `PSScriptAnalyzer` (pinned 1.23.0, matching CI): clean.
- `scripts/test_bootstrap.py`: passing.
- `scripts/prose_lint.py . --diff HEAD` and `scripts/repo_gate.py
--check eol`: clean (the local pre-commit gate).
- Parsed and ran `-Help` under actual Windows PowerShell 5.1.
- Full `-DryRun` runs against `develop` under `pwsh` for `-Report`,
`-Host -Yes`, `-Wsl`, and the PS5.1→pwsh7 reinvocation handoff forced
via `powershell.exe` — all completed cleanly, correctly drove the real
tool scripts, and left no orphaned trees afterward.
- Confirmed two-actions-given correctly refuses, matching the sibling
scripts' convention.
Phase 7 of the hub-docs-to-skills conversion project.

## What
- New `standup-a-repo` Skill at
`.agents/skills/standup-a-repo/SKILL.md`: a
hub-only driver over `STANDUP.md`'s create-to-conformance procedure, run
from a hub checkout for a named target repo the maintainer is standing
up.
- Same non-trimming pattern Phase 4 (`resync-a-repo`) used: `STANDUP.md`
is
  hub-only and never carried downstream, so there's no duplicate-copy
  problem to solve by pointer-izing it. The source file stays the full
  authoritative procedure; the skill is a driver layered on top.
- `STANDUP.md` section "2. Carry the Baseline Files" gains an explicit
step
  to carry `AGENTS.md`'s skill-dependency pointer paragraph (naming
`scripts/skills_install.py` and where the fleet's Skills live) as one
more
  verbatim unit, the identical requirement Phase 4 added to `RESYNC.md`
  section 3 for a repo already stood up.
- `AGENTS.md`'s "Onboarding a repo or running a conformance sweep" table
row
  now names both `standup-a-repo` and `resync-a-repo`.
- `.claude-plugin/fleet-skills/` regenerated via
`scripts/build_dist.py`.

## Checks done before pushing
- `spec/files.json`, `spec/project-types.json`, `scripts/test_*.py`
grepped
for `STANDUP.md` coupling before editing: none found, safe to edit
freely.
- `python3 scripts/prose_lint.py` clean on the whole tree.
- No inline Markdown links in the new skill file
(reference-style/backtick
  convention only).
- No semicolons or em-dashes introduced (verified against the
pre-existing
  baseline in each touched file).
- CRLF preserved byte-for-byte in every touched/created file, no stray
LF.
- No mid-span code-span line wraps (`` `python3 scripts/host_gate.py` ``
and
  `` `repo-config/configure.sh apply owner/repo release|operational` ``
  each stay on one line).
- `python3 scripts/build_dist.py --check` reports the plugin current.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
## Why

A real mis-triage this session, on a downstream PR
([HomeAutomation-Config#50](ptr727/HomeAutomation-Config#50)):
two findings were factually real but structurally out of that repo's
scope to fix (verbatim-fidelity-locked GOVERNANCE.md content owned by
this hub). Neither of the skill's five outcomes named that shape
cleanly, so I reached for outcome 3 ("the maintainer's call") and left
the threads open with a plan to ask later — which never happened once
attention moved to other in-flight work in the same session. That's an
unresolved thread with no closing mechanism, exactly what outcome 3's
own "never resolve this one by silence" line exists to prevent, just
from the other direction (never *leave* it unresolved by silence
either).

## What changed

- **Outcome 2** broadened from "not real" only to also cover "real but
structurally out of scope, provable" — either shape closes the thread on
cited evidence (a command's output, a code path, or now also a governing
rule/manifest entry establishing the boundary), rather than needing
outcome 3's maintainer consultation at all.
- **Outcome 3** tightened to apply only once outcome 2 is ruled out (a
fix genuinely possible here, the question is value not scope), and now
requires the maintainer's answer in the same turn rather than deferred —
a plan to ask later is treated explicitly as resolution by silence.
- New closing line: a disposition decided on one PR does not carry to a
sibling PR or repo in the same batch, even when the finding shape is
identical — each instance needs its own close.

`.claude-plugin/fleet-skills/skills/pr-review-conduct/SKILL.md`
regenerated via `scripts/build_dist.py` to match.

## Verification

```
python3 scripts/prose_lint.py .agents/skills/pr-review-conduct/SKILL.md   # scope: 1 file(s) read, whole tree
python3 scripts/build_dist.py --check                                     # is current
```
No `scripts/test_*.py` coupling to this file's content (checked before
editing, per the Phase 3 gotcha).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
## Why

Twice in one session, `wait` polled the full 45-minute timeout for a
review nothing had asked for: once after a push superseded the prior
request, once after a re-request attempt that never actually issued a
mutation. `wait` never requested anything itself, contrary to what a
caller reasonably expects from a command named `wait` — the manual
`requestReviews` recipe documented in `.github/copilot-instructions.md`
is a separate step every caller has to remember on every push, and
forgetting it fails silently (a full timeout, not an error) rather than
loudly.

## What changed

`wait` now issues the request itself, once, before its first poll,
whenever nothing is already outstanding and the head isn't already
covered. The bot id is read fresh from the repository's own last 20 PRs
every time (never fabricated, never cached), and requests are additive
(`union:true`) so a human reviewer requested alongside Copilot is never
dropped. A repository with no Copilot review anywhere to read the id
from falls back to plain polling rather than crashing or guessing.

**This is a deliberate second write path**, not an oversight fixed in
passing: it was previously excluded by name in a guard test
(`test_the_only_writes_are_the_two_the_reply_path_owns`) asserting an
explicit prior design decision, itself consistent with
`.github/copilot-instructions.md`'s own text describing `requestReviews`
as a manual mutation this script doesn't issue. Renamed that test and
updated its assertions for the third deliberate write (now
`test_the_only_writes_are_the_three_named_here`), added the mutation and
runbook-mention checks alongside the existing two, and added an explicit
ban on `union:false` (the destructive clear-and-recover form stays a
manual runbook step, never automatic).

Added targeted tests for all three auto-request shapes: bot id resolved
and the request fires, no bot id found anywhere and it falls back to
polling, already requested and it is not re-requested. Each was verified
to fail against the pre-fix code before trusting it (reverted
`pr_review.py` alone, ran the three new tests, confirmed 3 of 4 failed
as expected — the fourth, "already requested," passed even pre-fix since
that no-op case existed by coincidence of no request-issuing code
existing yet, not something this PR broke).

## Verification

```
cd scripts && python3 -m unittest test_pr_review   # 231 tests, all pass
python3 scripts/prose_lint.py scripts/pr_review.py scripts/test_pr_review.py   # clean
uvx ruff check scripts/pr_review.py scripts/test_pr_review.py   # 23 pre-existing errors, unchanged by this diff, none in new code
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
GOVERNANCE.md's "Running the Linters Locally" bullet unconditionally
claimed CI runs PSScriptAnalyzer and linked
`PSScriptAnalyzerSettings.psd1`, true for the hub itself but not for
every downstream repo.

Hit as a real Copilot finding on both
[Blog#94](ptr727/Blog#94) (a stale carried
`validate-task.yml` never wired the step) and
[HomeAutomation-Config#50](ptr727/HomeAutomation-Config#50)
(the repo carries no `.ps1` files at all, so the link 404s). Neither was
fixable per-repo without either breaking byte-parity on the verbatim
bullet or inventing content the repo does not need, so both were
replied-and-deferred as the maintainer's call.

This conditions both bullets on a repo carrying `.ps1` files instead,
closing the recurring gap at its source rather than continuing to defer
it repo by repo through the rest of the Phase 8 rollout.

Not manifest-tracked ("Running the Linters Locally" is not a declared
verbatim section in `spec/files.json`), so this is a hub-only prose fix
with no spec/audit coupling to update.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
## Why

The skill-based fleet system has defined procedures but undefined seams
between them. The skills install has no home in the cold-start flow, a
failed tool floor names no install remedy, session entry never checks
skill staleness, and WORKFLOW.md, AUDIT.md, and the conduct rules carry
no skill. Each gap was real but recorded nowhere, so each session
rediscovered them.

## What

- `docs/fleet-map.md` (hub-only): maps the five entry points into the
fleet system with a flowchart each, registers twelve gaps (G1-G12) with
a defined handoff and a closing test per gap, resolves the skills
install model as global with its wiring gaps enumerated, proposes four
new skills (`audit-a-repo`, `workflow-ci-contract`, `skill-lifecycle`,
`agent-conduct`) with scope and overlap settled, evaluates ASD-STE100
against a constrained house style, and phases the closure work P0-P4.
Carries its own maintenance rule: a PR closing a gap edits its register
row in the same change.
- `docs/peer-messaging.md` (hub-only): declares the live agent-to-agent
messaging method and its four safety rules, resolving the TODO.md
location decision to a hub-only doc until cross-host is verified. Closes
register gap G11.
- `TODO.md`: the peer-messaging cluster's two open bullets resolve by
pointer to the new docs, and one added line establishes the fleet-map
register as the home for adoption gaps so the two files do not fork.

## Verification

- `prose_lint.py --diff HEAD`, `repo_gate.py --check eol`, and
`markdownlint-cli2` all pass on the three files.
- All seven mermaid blocks parse as `flowchart-v2` via `mermaid.parse`
(mermaid 11).
- All three files are CRLF, verified with `git ls-files --eol`.

Generated with [Claude Code](https://claude.com/claude-code)
)

## Why

`install-tools.sh` already detected a copy of `uv`, `jq`, or
`git-restore-mtime` earlier on `PATH` than `$BIN_DIR` (`tool_note`'s
report note), but nothing acted on it. `--install`/`--upgrade` only ever
touched `$BIN_DIR`, so a `--report` run right after still repeated the
same note, unchanged.

Worse: `apply_tool()` reads a tool's version via `command -v`, so a
shadow that already happened to be current made the tool report as
`current` and return before ever reaching its own install function. That
is exactly how `uv` installed per #483's own documented method (`curl
-LsSf https://astral.sh/uv/install.sh | sh`, into `~/.local/bin`, ahead
of `/usr/local/bin` on a stock Debian `PATH`) never converged on
repeated `--upgrade` runs, per the repro in #688.

## What changed

Went with option (b) from the issue (detect and self-heal), since option
(a) (ride the vendor's own install path, the pattern already used for
`gh`/`node`'s apt repos) doesn't fit `uv` the way it fits those two: the
astral installer's own path is a per-user `~/.local/bin`, where this
script installs shared tools system-wide as root into `/usr/local/bin`.

- `tool_shadow_path()` factors the existing PATH-vs-`$BIN_DIR` check out
of `tool_note()`, so the report and the fix below share one answer. Uses
`type -P` rather than `command -v`, so an alias or shell function
shadowing the name (no file behind it) is never mistaken for a shadow.
- `tool_unshadow()` acts on it, looping per tool name until nothing
shadows `$BIN_DIR` any more (PATH can stack more than one copy ahead of
it), prompting before each removal and respecting `--yes`/`--dry-run`
the same way `apt_install_displacing`'s confirm already does. A distro
package's own file is never removed this way (`dpkg-query -S`), since
`rm -f`-ing it would desync dpkg's database from the filesystem,
matching `jq_install`'s own design note that the distro `jq` package
stays installed. Covers `uv`'s `uvx` companion from the same archive
too, since it would otherwise stay shadowed while `uv` itself got fixed.
- `apply_tool()` only unshadows *ahead of* the version read under
`--upgrade` (which brings `$BIN_DIR` current regardless of what gets
removed) or when the managed copy at `$BIN_DIR` does not exist yet
(nothing there to protect). `--install` with a managed copy already
present leaves a shadow alone rather than risk removing a newer copy
with nothing to replace it, and logs an explicit note pointing at
`--upgrade` instead of going silent.

Fixes #688.

## Verification

- `bash -n host-setup/linux/install-tools.sh` and `--help`/`--list`
still run.
- `shellcheck` clean via the pinned `koalaman/shellcheck:stable` image.
- `scripts/prose_lint.py --diff HEAD` clean.
- Functional harnesses sourced the script's functions against simulated
`PATH` states and confirmed: `tool_shadow_path` finds a real shadow and
ignores a same-named alias/function with no file behind it;
`tool_unshadow` removes a single shadow, removes two stacked shadows in
one call, leaves a distro-package-owned path alone with a warning,
leaves a declined path alone with a warning, and performs one simulated
pass under `--dry-run` rather than looping forever; and `apply_tool`
leaves a newer shadow untouched (with an explicit note) under
`--install` when an older managed copy already exists, but removes it
under `--upgrade`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
## Why

The fleet map's P1 phase closes the skills install model. A bootstrapped
host ended with every tool and no fleet skills, a failed tool floor
named no runnable remedy, a bare `host_gate.py` run silently skipped an
enclosing repo's overlay, nothing stated the skills staleness cadence,
and the register's G8 row described a CI gap that #676 had already
closed before the register merged.

## What

One commit per register row, each editing its row in `docs/fleet-map.md`
per the maintenance rule:

- **G8, recorded closed.** `validate-task.yml` has run `build_dist.py
--check` since #676, which predates the register's merge, so the row's
`Checked` claim was stale on arrival and the row now records the
resolution and its provenance.
- **G2, bare-run overlay warning.** `host_gate.py` warns when a bare
run's working directory sits inside a repo carrying a `host-tools.json`
overlay it did not read, naming the `--repo` re-run that counts it. An
explicit `--repo` and `--no-local` stay silent. STANDUP section 0 states
the residual case the warning cannot cover, a target that does not exist
yet.
- **G3, runnable remedy.** Each floored `spec/host-tools.json` entry
carries a per-platform `remedy` command beside its `source`, printed as
a `REMEDY:` line under a below-floor failure, with `host-setup/` paths
resolved against the checkout so the command is runnable as printed. The
schema and `spec/validate.py` require it on every hub floor, and
`test_bootstrap.py` keeps the mapping total per platform
(git-restore-mtime/windows is the recorded not-applicable exception) and
pointing at tools the installers actually manage.
- **G1, skills in the cold start.** The bootstrap host mode ends with an
`install-skills` step on both platforms, a `--skills` action runs it
alone, and the report mode reads the stamp beside the other status
lines. The loaders hand their resolved commit to the installer via
`SKILLS_SOURCE_COMMIT`, since a tarball tree has no `.git`, so the stamp
stays checkable and `--report` can exit zero on a fresh host.
`docs/host-setup.md` gains the "Fleet Skills Install" section and verify
lines, and `README.md` "Using This Repo" names four deployed things. The
`claude` CLI stays out of the tool catalog: the installer degrades
without it, lands the overlay half, and records the partial install. The
new drivers keep the loader single-path and no-Python invariants intact,
and the two recorded exceptions (Python last-in-line, independent
fetchability) are stated in `host-setup/README.md`. Cross-links #671 and
#673, which touch the same scripts and stay open on their own tracks.
- **G6, staleness cadence.** Stated at both trigger surfaces:
`docs/host-setup.md` and the `fleet-conformance-check` skill's new
"Refresh cadence" section (plugin regenerated via `build_dist.py`),
routing the restated-rule symptom to `skills_install.py --report`.

## Verification

Every `validate-task.yml` gate run locally and green: the ten script and
spec self-tests, including new cases for the warning, the remedy
mapping, and the handed-in commit, plus `repo_gate.py`, `prose_lint.py`
with CI's check list, `spec/validate.py`, `build_dist.py --check`,
markdownlint, cspell on README and HISTORY, shellcheck and
PSScriptAnalyzer via the same pinned containers CI uses, and all seven
fleet-map mermaid blocks parse.
Implements phase 2 of the docs/fleet-map.md adoption roadmap: the four
proposed skills ship, the AGENTS.md rule map carries a disposition per
doc-only GOVERNANCE section, and the G9, G10, and G12 register rows
close.

## What ships

- **skill-lifecycle** (G10, authored first so the other three follow its
procedure): the .agents/skills/ source-versus-generated split,
build_dist.py regenerate and --check semantics, skills_install.py
install and stamp semantics, the doc-packaging pattern, and
trigger-description conventions. .agents/skills/README.md defers to it
for procedure, which is the row's closing test.
- **audit-a-repo** (G9): packages AUDIT.md in the kept-authority shape,
completing the standup/resync/measure triangle, with
fleet-conformance-check remaining the in-repo self-check.
- **workflow-ci-contract** (G9): packages the WORKFLOW.md contract, with
references/ splits for the D-guarantee catalog and the 5A/5B/5C test
methodology. The git half stays with operational-vs-release-workflow,
and the two descriptions state the split.
- **agent-conduct** (G12): narrow decision-moment triggers only (about
to claim done, about to assume, a failure just surfaced a lesson), per
the proposal's deliberately-not-always-on decision. Its three GOVERNANCE
sections keep the full rules and carry the surfacing pointer.
- **G9 disposition sweep**: the four surfaced rule-map rows are
annotated, and a paragraph after the table states why each remaining
unannotated section is doc-only by decision.

## Deviation from the doc, recorded in the doc

fleet-map.md said each skill ships as its own pull request. All four
ship here in one at the maintainer's direction, recorded in the G9
provenance note, since skill-lifecycle only needed to be authored (not
merged) before the others follow it.

## Verification

- python3 scripts/build_dist.py run and committed together with the
source, --check passes.
- python3 scripts/prose_lint.py . clean whole-tree, repo_gate.py --check
eol clean, all 644 script tests pass, markdownlint-cli2 0 issues over 98
files.
- New files are CRLF, verified by byte scan.

Generated with [Claude Code](https://claude.com/claude-code)
Closes the three P3 audit-depth register rows in `docs/fleet-map.md`,
each per the maintainer's recorded disposition.

## G4: deletion sweeps miss prose

Split by what a pattern can reach. The named-path half is mechanized: a
`dead-path` rule in `scripts/prose_lint.py` reports a Markdown mention
(backtick span, inline link target, or reference definition) of a path
git once tracked and the tree no longer holds. Keying on deletion
history is what scopes it: proposed files a backlog names, another
repository's layout, and refs like `origin/develop` have no history here
and stay silent, and manifest-declared carried paths are exempt since
the hub's own instances retire to catalog snippets. The rule joins the
default set and the CI prose step, the CI checkout fetches full history
(`fetch-depth: 0`) because the rule stands down loudly in a shallow
clone rather than pass blind. The name-shaped half (a description naming
no path) stays the manual RESYNC section 4 read, `accepted` as manual:
no pattern reaches it.

The rule's first tree-wide run caught a real instance:
`docs/host-setup.md` still described bind-mounts in the deleted
`.devcontainer/` definitions, fixed here by re-pointing at
`catalog/snippets/devcontainer/`.

## G5: intent-fidelity drift is invisible

The advisory ships in `spec/audit.py`: per applicable intent unit, the
audit compares when the hub canonical and the repo copy each last
changed, and a canonical changing later reports the copy as possibly
trailing, at DRIFT and never failing. A copy content-identical to the
canonical is skipped (current, and the `fidelity_honesty.py` promotion
candidate). No reconciliation record exists anywhere, so last-modified
is the implementable proxy, and the blind spot (a copy touched without
reconciling reads current) is stated in RESYNC section 5, AUDIT.md, and
`spec/fidelity-model.md` rather than papered over. Verified read-only
against a fleet repo: carried intent files reported as trailing hub
changes made weeks earlier, findings no prior check produced.

## G7: operational develop PR-only is prose-enforced

Closed `accepted`, mirroring the `spec/divergences.json` vocabulary,
recorded in STANDUP.md section 0B beside its uneven-protection warning.
The allowance is the operational model's foundation per WORKFLOW.md
"Branch Model", and the considered standup-time tightening (apply the
release payload, swap after the closing audit) was declined: it adds a
forgettable swap step and a window where the live ruleset contradicts
the registry's declared model.

Also retires the stale G11 phase cell (`P0` -> `closed`), which trailed
its own closure, per the register's maintenance rule.

## Verification

- All seven `scripts/test_*.py` suites pass, including the new
`TestDeadPath` (deletion signature, shallow stand-down, manifest
exemption, tree-clean assertion).
- `prose_lint.py` full default sweep clean with `dead-path` enabled,
`charset-unknown` clean, `build_dist.py --check` current.
- markdownlint and editorconfig-checker clean on every changed file,
CRLF preserved, all 7 `fleet-map.md` mermaid blocks parse.
- mypy and pyright report zero deltas against the develop baseline.
Addresses #695.

`uv` carried a null minimum with no floor measured. The issue offered
Windows winget versions (0.12.2, with winget already offering 0.12.4) as
an unverified starting point, explicitly asking for someone with broader
fleet data to firm it up into a real measured or target floor.

Cross-checked against this Linux host (uv 0.12.4, via
`host-setup/linux/install-tools.sh`'s always-fetch-latest install), the
lower of the two independently observed versions becomes a **target**
floor (`0.12.2`) in the same style `jq`'s floor already uses: anchored
to what an independently set-up host already provides rather than to a
measured breakage, with real `source`/`remedy` entries per platform.

`docker` is deliberately left at `null`. Unlike `uv`, it has no remedy
anchor anywhere in this repo (it isn't in either host-setup tool list,
so there's no install/upgrade command to cite), and its existing `why`
already argues the daemon version has never been what broke a run since
the linters run as pinned images. Per this file's own stated philosophy
("a floor nobody can justify becomes a host failure nobody can act on"),
adding a floor there would be unfounded.

Also fixes a latent bug in `scripts/test_host_gate.py`'s
`test_the_contract_table_carries_every_declared_floor`: the compound ``
`uv` / `uvx` `` table cell normalized to a key (`uvuvx`) that neither
tool name matched, which only surfaced now that `uv` actually carries a
floor to check.

Verified locally:
- `python3 scripts/host_gate.py` reports `uv 0.12.4 meets the 0.12.2
floor`
- `python3 -m unittest scripts.test_host_gate` — 72 passed
- `python3 scripts/test_bootstrap.py` — OK
- `python3 scripts/prose_lint.py spec/host-tools.json
docs/host-setup.md` — clean
- `python3 scripts/repo_gate.py --check eol` — clean
Closes out the actionable half of the fleet-map P4 roadmap item on STE
structural checks.

## What

- **`sentence-length` rule in `scripts/prose_lint.py`**: flags a
Markdown prose sentence over 25 words, ASD-STE100's descriptive cap.
Opt-in like `sentence-split` (not in `DEFAULT_RULES`, not in CI),
because the rule counts 1686 over-cap sentences in the corpus at
landing, so a default gate would fail whole files nobody is editing. A
table row, a heading, a link definition, and a blockquote are exempt, an
inline code span and a double-quoted quotation each count as one word.
Eight new cases in `scripts/test_prose_lint.py`, including one pinning
the opt-in status.
- **Decision recording**, per the fleet-map hook that the decision lands
when the first structural check ships: a `Sentence Structure` subsection
in GOVERNANCE.md `Documentation Style Conventions`, the full house-style
rules in the `comment-and-doc-style` skill (plugin regenerated), and a
`Decision` paragraph plus P4 row edit in `docs/fleet-map.md` per the
maintenance rule.
- **OPERATIONS.md staleness fix**: the runbook's mirrored prose gate
omitted `--check dead-path` after #692 added it to CI, and its rule
counts predated the rule. Both now match CI, and the opt-in note names
both unlinted rules.

## Why opt-in

The corpus measures 26 percent of sentences over 20 words and 1686 over
the 25-word cap, so the house style is adopted for new prose while the
check stays reachable by name and by `--diff` scoping. Promotion into
`DEFAULT_RULES` or CI is a separate decision, taken if and when the
corpus converges. The changed lines of this PR lint clean under the new
rule.

## Verification

- `python3 scripts/test_prose_lint.py` (243 tests), `test_repo_gate.py`,
`test_pr_review.py`, `test_build_dist.py`, `spec/audit.py --selftest`,
`gh-write-guard.py --selftest`: all pass
- `repo_gate.py`, `build_dist.py --check`, the CI prose gate including
`dead-path`, `charset-unknown` summary (0 findings), `spec/validate.py`,
`jq` sweep, `markdownlint-cli2` on the changed files: all clean
- `ruff` at latest adds no new finding over develop's pre-existing nine,
`mypy` passes
- Line endings byte-verified, CRLF Markdown and LF Python unchanged

Generated with [Claude Code](https://claude.com/claude-code)
…696)

## Summary

Fixes #693.

`winget list --id OpenJS.NodeJS.LTS --exact` echoes back the queried id
for a package that only shares a publisher and name with what's actually
installed. On a host running `OpenJS.NodeJS` (the Current channel), that
made every report and action believe `OpenJS.NodeJS.LTS` was installed,
and `-Upgrade`/`-Reinstall` would have targeted that wrong id.

Node also ships under many more ids than Current/LTS — one per pinned
major back to 4 (`OpenJS.NodeJS.4` … `.23`) — any of which is fine on a
host as long as its version clears the LTS floor.

## Fix

- Added a `Family` field to the tools registry in `install-tools.ps1`
(empty for every tool but `node`, which gets `'OpenJS.NodeJS'`).
- Added `Resolve-ToolPackage`, which cross-references the
already-correctly-read installed version against a `winget search
--query <family>` catalog listing. A version that uniquely matches one
of the sibling ids identifies which one is truly installed, without ever
trusting winget's id-scoped `list --id --exact` correlation.
- That resolved id (`$state.Package`) now flows through status, notes,
the report's SOURCE column, and every install/upgrade/remove action
instead of the hardcoded default.
- Other 7 managed tools are untouched (`Family = ''` short-circuits
before any extra winget call).

## Verification (done on a live host)

Host had `OpenJS.NodeJS` (Current, 26.7.0) installed, not
`OpenJS.NodeJS.LTS`.

- `-Report node` → now shows `SOURCE=OpenJS.NodeJS` (was misleadingly
`OpenJS.NodeJS.LTS`), status still correctly `current` (26.7.0 ≥ LTS
floor 24.19.0).
- `-Upgrade node -DryRun` → correctly no-ops (already current).
- `-Reinstall node -DryRun` → now issues `winget uninstall --id
OpenJS.NodeJS` / `winget install --id OpenJS.NodeJS`, i.e. it reinstalls
the package that's actually there instead of silently swapping to LTS.
- Full `-Report` across all 8 tools → other 7 unchanged, no regressions.
- Script parses clean; PSScriptAnalyzer shows only pre-existing,
unrelated `Write-Host` warnings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…on floor (#701)

Closes the docker gaps tracked in #695: no version floor was declared,
and `host-setup/linux/install-tools.sh` carried no install path for
docker at all.

- `spec/host-tools.json`: docker now carries a target floor of 29.6.2,
anchored to the Windows host issue #695 recorded (Docker Desktop 4.85.0,
Engine 29.6.2), plus source and remedy for linux, macos and windows.
- `host-setup/linux/install-tools.sh`: a real docker install/upgrade
path, the same apt-repository shape `gh` and `node` already use here -
removes old conflicting packages, registers download.docker.com's own
repo with a verified signing key, installs `docker-ce docker-ce-cli
containerd.io docker-buildx-plugin docker-compose-plugin`. Inside a
detected WSL distribution it refuses the native install outright, with
no override, and points at Docker Desktop's own WSL integration instead.
- `host-setup/windows/install-tools.ps1`: before installing or upgrading
docker, checks that `wsl.exe` is present and WSL is at or above 2.1.5
(Docker Desktop's own documented floor), and skips with a named remedy
otherwise. It never runs `wsl --install`/`wsl --update` itself - those
stay `upgrade-host.ps1 -Wsl` and `setup-wsl.ps1`, a person's own action.
- `scripts/test_bootstrap.py`, `docs/host-setup.md`,
`host-setup/windows/README.md` updated to match: the now-stale
`NOT_MANAGED['linux']['docker']` exception is removed, the floor table
and comparison table are brought current.

## Verification

On this machine (Linux, docker 29.7.1 already installed):
`spec/validate.py`, `scripts/host_gate.py`, `scripts/test_bootstrap.py`
all pass; `shellcheck` and `PSScriptAnalyzer` via the pinned CI images
are clean on both modified scripts; `markdownlint-cli2` and
`editorconfig-checker` are clean. Exercised `--report`,
`--install`/`--upgrade --dry-run`, and a simulated-WSL run
(`WSL_DISTRO_NAME` set) against the real download.docker.com repository
- the GPG key fetch and verification succeeded and the WSL path
correctly refused with no apt commands attempted.

A real install/upgrade on a native Windows host and inside an actual WSL
distribution has not been run in this session - the maintainer is
following up with both separately.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Gives README.md, STANDUP.md, RESYNC.md, and AUDIT.md the same
at-a-glance
mermaid diagrams `docs/fleet-map.md` already uses, so a reader gets the
shape of the flow inside the procedure doc itself instead of only in the
hub-only summary map. Also adds a small matching diagram to
`AGENTS.md`'s
Fleet Bootstrap section, and appends the governing `D`-guarantee number
to 3 already-existing `WORKFLOW.md` diagram labels (no new diagrams
there, no structural change).

**What changed**

- `README.md`: entry-doors flowchart in "How This Repo Operates",
  matching the "Getting Started" table's rows.
- `STANDUP.md`: full section-by-section procedure map (0 through 5).
- `RESYNC.md`: primary route/measure/apply/ship flow, plus a detail
  diagram for the section 4 deletion remedy.
- `AUDIT.md`: primary measurement-pipeline map (0 through 8), plus a
  section 9/10 escalate-vs-converge diagram.
- `AGENTS.md`: a small Fleet Bootstrap diagram reusing README's door
  names, so the agent-entry and human-entry views are the same graph.
- `WORKFLOW.md`: 3 existing diagram node labels get a `(D#)` tag
  appended; label text only, no graph-shape change.

**Design principle**: every new node label opens with the section
number or name it maps to, so each diagram doubles as a navigable
index of its own document and a renamed/renumbered section shows up
as a mismatched node rather than drifting silently.

**Scope note**: `docs/fleet-map.md` itself is intentionally untouched
(no register gap is closing, no disagreement with a procedure doc to
fix). `AUDIT.md` and `AGENTS.md` were added to scope beyond the three
files first requested, since they complete the same triangle
`fleet-map.md` names and close a real divergence risk (`AGENTS.md`'s
Fleet Bootstrap and README's Getting Started table already described
the same routing in two independent prose blocks).

**Verification**: markdownlint-cli2, cspell, and editorconfig-checker
all ran clean via Docker over the six changed files. Every diagram's
node set was cross-checked against its source doc's actual headings
and table rows for completeness, order, and no invented door.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
## Why

A re-analysis of `docs/fleet-map.md`, applying the same gap-finding
method that created it, after the P0-P4 closures, the #689/#701
install-model changes, and the #702 procedure-doc diagrams.

## What

- **Diagram authority**: #702 put authoritative flow diagrams into
STANDUP.md, RESYNC.md, AUDIT.md, and AGENTS.md. The map's own copies of
the STANDUP and RESYNC flows were coarser duplicates with no
cross-reference in either direction, and by the map's own rule the
procedure doc wins. The two derivative diagrams are replaced with
pointer sentences, and the Entry Points intro states the ownership rule.
The five diagrams no procedure doc draws (System Map, Pre-Agent Cold
Start, Daily Development, Hub-Side Operations, G3 remedy loop) stay.
- **Maintenance rule extended**: it covered register rows but not drawn
flows, which is exactly the class this batch fixes. It also cited G4 for
register staleness, which is at best an analogy, so the sentence states
the class directly.
- **Stale content**: the vestigial `Checked` evidence-anchor sentence
(the shipped register has no such cells, and the `ba392f9` pin is
historical) is removed, the cold-start tool node points at
`spec/host-tools.json` instead of an enumeration that drifted twice in
two weeks (#689, #701), and the dead "dashed arrows mark a gap" clause
(zero dashed arrows exist) is removed.
- **Unmapped entry points surfaced**: OPERATIONS.md is named as the
runnable form of the Hub-Side Operations door and of the daily-dev gates
node, and `scripts/repo_gate.py`, `scripts/pr_review.py`, and
`spec/audit.py` get reference links.
- **Cross-links**: #699 and #700 join the Decision Ledger
Cross-References per the #671-cluster precedent, and the #689 PATH
self-heal is noted in the cold-start prose.
- **Discoverability**: README links the map from the doors diagram it
sits behind. AGENTS.md is deliberately untouched (byte-locked Fleet
Bootstrap, and a carried file must not reference a hub-only doc).
- `worktree` joins `cspell.json` words (used by the #699 cross-link).

## Flag, not a task

`docs/fleet-map.md` and the #702 diagrams exist only on `develop` (main
is 22 commits behind and lacks the file entirely). A `develop` to `main`
promotion is a maintainer decision and is not part of this change.

## Verification

All nine CI prose_lint checks pass tree-wide and `--diff develop` is
clean, markdownlint reports 0 issues on both edited files, cspell is
clean on README and leaves only the six pre-existing fleet-map findings
(the file is not CI spell-gated), editorconfig-checker passes (CRLF
preserved, diff is line-scoped), `spec/validate.py` and `jq` pass, all 6
remaining mermaid fences (5 in fleet-map, README doors) parse OK via
mermaid@11, and a two-way reference-link check (every use defined, every
relative target exists) passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
…#705)

Stop Docker Desktop and Update WSL During a Docker Install or Upgrade

#701 checked the WSL platform floor before a docker install or upgrade
and only named the remedy, upgrade-host.ps1 -Wsl. That left docker to
skip outright whenever WSL was behind, since that script also refuses
while Docker Desktop is running. Verifying #701 on a real Windows host
surfaced two more gaps. Docker Desktop's own WSL integration goes
stale across most engine bumps, surfacing as "WSL integration with
distro '<name>' unexpectedly stopped". The in-app "Restart the WSL
integration" button does not clear it. And wsl --update raises its own
UAC prompt, which a headless run cannot answer.

- `install-tools.ps1`: a docker install, upgrade or reinstall now
  drives the whole maintenance window itself. It stops Docker Desktop
  through its own CLI (`docker desktop stop`/`start`), runs `wsl
  --update` where the floor is not met, shuts every WSL distro down
  with `wsl --shutdown` so each one's integration remounts fresh, and
  restarts Docker Desktop once the package itself is settled.
  Confirmed first, unless `-Yes` was given. A non-elevated,
  non-interactive run refuses to start `wsl --update` rather than hang
  on its UAC prompt, and restores Docker Desktop to how it found it.
  The WSL-readiness check moved from an unconditional early gate to
  just before real work happens, so an already-current docker no
  longer fails a run over an unrelated stale WSL platform.
- `README.md`: documents the moved boundary. WSL used to be strictly
  read-only here, naming `upgrade-host.ps1 -Wsl` as a person's own
  step. A docker version bump already needing the same stop-then-
  restart window for its own integration is what moved it.

## Verification

Exercised live on a real Windows host, not simulated: a real docker
upgrade (4.85.0 -> 4.86.0) through winget; the WSL-below-floor path
through a real `wsl --update` past an actual UAC prompt (WSL 2.7.10.0
-> 2.7.11.0), re-verifying the floor and restarting Docker Desktop
afterward; the plain engine-bump stop, shutdown, restart cycle; the
declined-prompt and neither-condition-true branches, through mocked
extraction of the real functions; and the headless-UAC-refusal guard,
both tripping unelevated and bypassing elevated correctly.
`Invoke-ScriptAnalyzer` against the repo's own settings, a parse
check, `pytest scripts/test_bootstrap.py scripts/test_host_gate.py`
(82 passed), and `host_gate.py` all pass.
…704)

Closes #700.

## What

- **Every ruff and mypy finding is fixed**: 88 ruff findings (`PLW1510`,
`SIM117`, `EXE001`, `BLE001`, `ISC004`, and others) and 5 mypy errors at
the configured contract (latest defaults plus `extend-select = ["I"]`)
are at zero. `subprocess.run` calls carry an explicit `check=False`
(behavior-preserving), nested `with`/`if` blocks are merged, shebang
files carry the exec bit, and the deliberate blind catches (hook and
sweep isolation boundaries) carry scoped `# noqa: BLE001` with their why
comments.
- **CI carries the Python tooling** (`validate-task.yml`): `uvx
ruff@latest check .`, `uvx mypy@latest`, and the self-test surface under
`uvx coverage@latest` with `--append` and a report, informational with
no threshold. `astral-sh/setup-uv` is SHA-pinned per the catalog
precedent.
- **The unit tests move to `scripts/tests/`**, with imports, repo-root
constants, `.gitattributes` pins, and the `.editorconfig` LF section
(`scripts/**.py`, since an EditorConfig `*` stops at `/`) updated, and
every prose reference swept (`OPERATIONS.md`, `scripts/README.md`,
`docs/fleet-map.md`, host-setup READMEs, the skill sources plus
regenerated plugin).
- **Linter versus utility is a documented naming split**: a gate checks
and exits non-zero and carries a `_lint`/`_gate` suffix (`prose_lint`,
`repo_gate`, `host_gate`), a utility carries none (`build_dist`,
`pr_review`, `skills_install`).
- **The law amendments**: the `python-codestyle` skill's Scripts profile
now requires Python tooling in CI, coverage included, and states the
`tests/` layout and naming split fleet-wide. `CODESTYLE.md` Shell,
`GOVERNANCE.md` Repository Layout, `spec/project-types.json`
(`python.coverage.codecov` note), and `spec/host-tools.json` (the python
floor's why no longer claims no Python linter runs in CI) follow.

## Decisions left open, deliberately

- **`ruff format` is not adopted**: a `format --check` gate would
reformat 19 files (~12k diff lines) in the same PR. Measured and left
for a separate decision.
- **The gates stay at `scripts/prose_lint.py` / `scripts/repo_gate.py`**
rather than moving to a `scripts/lint/` directory, because those paths
are named in carried text (`.github/copilot-instructions.md` points
every fleet repo at them), so a move stales the whole fleet. The issue's
naming-separation floor is met instead.

## Verification

All gates run locally the way CI runs them: ruff, mypy, the unittest
suite under coverage (all seven files, plus the audit, write-guard, and
agent-safety self-tests), `build_dist.py --check`, `repo_gate.py`, the
nine-rule prose gate, `spec/validate.py`, actionlint,
editorconfig-checker, markdownlint, cspell, shellcheck, and
PSScriptAnalyzer. `test_install.py` passes on a clean tree, and
OPERATIONS.md now documents its dirty-checkout STALE verdict as by
design.

After merge the machines need `python3 scripts/skills_install.py` re-run
per the documented cadence, since the `python-codestyle`,
`shell-codestyle`, and `skill-lifecycle` skills changed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Closes #707, the follow-up #704 deliberately deferred.

## What

- **`df12931` is the one-time reformat**: `uvx ruff@latest format` over
`scripts/`, `spec/`, and `host-setup/` (19 files, ~12k diff lines),
format-only except for the two source-scan test assertions the new
quoting exposed in `scripts/tests/test_pr_review.py`. The `add_argument`
option scan now matches either quote and a wrapped call and holds a
floor of five options, since the quoting change had silently emptied it
to one match and an empty scan reads exactly like a pass. The `--match`
assertion reads the formatted double quotes.
- **`52884ab` holds the tree there**: a `uvx ruff@latest format --check
.` step in `validate-task.yml` beside the lint step, the same invocation
in the OPERATIONS.md runbook, and the `python-codestyle` skill's Scripts
profile naming `format --check` in its CI tooling sentence, with the
plugin regenerated.

## Verification

`format --check` reports 117 files already formatted, `ruff check`,
mypy, and the full unittest suite pass, `test_install.py` passes on the
clean tree, and `build_dist.py --check`, `repo_gate.py` (eol,
eol-coverage, sha-pin), the nine-rule prose gate, actionlint, and
markdownlint are all clean. Every `.py` stays LF.

After merge the machines need `python3 scripts/skills_install.py`
re-run, since `python-codestyle` changed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary

The `host-setup/windows/` directory carries a README documenting the
Windows-specific nuances, while `host-setup/linux/` carries none, and
the top-level `host-setup/README.md` stays platform-agnostic by design.
This adds the missing Linux counterpart.

The new `host-setup/linux/README.md` documents the decisions the four
Linux scripts embody:

- The three kinds of source (distro apt, upstream apt repository,
released binary) and why each tool uses the one it does, plus the
keyring-proved-not-trusted `gpgv` check and sha256 verification.
- PATH shadowing in both directions, including the deliberately shadowed
distro `jq` and the dpkg-owned-file exception.
- Report semantics: the stale-apt-cache caveat, what `unmanaged` means
here versus on Windows, docker read from the CLI, and failures-collected
versus refusals-fatal.
- The docker-on-WSL skip, `node` displacing distro packages, and the
dotnet feed-mixing rule.
- Release-upgrade guards (Proxmox refusal, one release at a time, the
Debian codename rewrite scope, sources backup), WSL restart handling,
the `setup-github.sh` browser gates and read-only `--status`, and the
`install-skills.sh` fetchability exception.
- A Verification section separating read-only commands, dry runs, and
the two guards that refuse under `--dry-run`.

The comparison table stays in the Windows README, referenced rather than
duplicated, so the two columns cannot drift. `cspell.json` gains the new
technical terms the README uses.

## Verification

- `prose_lint.py` clean on the default checks, and the opt-in
`sentence-length` check reports zero findings.
- `markdownlint-cli2`, `cspell`, and `editorconfig-checker` clean.
- `scripts/tests/test_bootstrap.py`, `scripts/tests/test_host_gate.py`,
and `repo_gate.py` pass.
- Every reference-style link target verified to exist on `develop`,
including the relocated `scripts/tests/test_bootstrap.py`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Why

Closes the root cause behind #706: an agent on a Windows host concluded
commit
signing was broken and stopped work, based on `git config --get
commit.gpgsign
&& ssh-add -L`. That check tests one specific delivery path (an agent
holding
the key). `gpg.format=ssh` can sign straight from a key file with no
`ssh-agent` running at all -- this host's actual setup -- so the probe
failed
while signing itself worked cleanly the whole time.

A follow-up comment on the same issue chased a second red herring: mixed
GPG/SSH signatures in `develop`'s history, read as evidence of a
still-misconfigured fleet host. Investigating it here found no such host
--
every GPG-signed commit on `develop` is a squash-merge, committed and
signed
by `GitHub <noreply@github.com>` itself, server-side, regardless of what
the
PR author signed with locally. That's structural on every fleet repo,
not
drift.

## What

In `.agents/skills/git-commit-conventions/SKILL.md` (`.claude-plugin/`
regenerated via `scripts/build_dist.py`):

- Bans agent-liveness probes (`ssh-add -L`, a `gpg-agent` check) as an
  invalid signing test, and states why.
- Replaces it with a real scratch commit read back via git's own `%G?`
verdict character -- tech-agnostic across SSH agent-backed, SSH
key-file,
GPG agent-backed, and GPG keyring signing, and immune to git
version/locale
  text differences that a "Good" grep would not be.
- The same scratch commit's `%ae` now backs the identity check too, so
one
  probe verifies both signing and identity instead of trusting
  `git config` values that don't prove what lands on the commit object.
- Documents the GitHub-committer/GPG-at-every-squash-merge pattern so an
agent checks `commit.committer.name` before treating a differing
signature
  type in history as a clue worth chasing.

Verified the new probe directly on this host (`sig=G
email=ptr727@users.noreply.github.com`) before committing with it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds the rule from #712: an agent must not claim platform-specific code
(PowerShell on
Windows, a macOS-only `mktemp`/`ssh-agent` behavior, a WSL-specific path
quirk) works,
is verified, or is fixed unless it actually executed that code on that
platform.
Reasoning by structural analogy to an already-tested equivalent on a
different platform
is a plausible first pass, not verification, and has to be reported as
exactly that.

Three spots, matching the existing pattern where GOVERNANCE.md keeps the
canonical rule
text and the skills excerpt or reference it at their decision moment:

- `GOVERNANCE.md` "Verification Discipline": the full rule, alongside
the other
  green-but-wrong checks in that section.
- `.agents/skills/agent-conduct/SKILL.md` "Before Claiming Done": the
same rule,
  abbreviated to match its sibling bullets there.
- `.agents/skills/pr-review-conduct/SKILL.md` outcome 1 ("Real, so fix
it"): a caveat
that a platform-specific review finding is not closed by a SHA alone,
since that is
the exact moment the incident behind #712 happened (round 4 of PR #708's
review loop).

Per "Issue-closing keywords" in "Branching Model," the closing keyword
belongs on the
`develop -> main` promotion PR, not here. This references #712 rather
than closing it.

Local gates run: `prose_lint.py` (full check set, diff-scoped),
`repo_gate.py`,
`unittest discover -s scripts/tests` (665 tests), `spec/validate.py`.
All green.
…-worktree Skill (#717)

## What this does

One consolidated update covering #711 and #714, per the maintainer's
direction that the two land together rather than as scattered rules. It
includes the `fix-714-branch-verification` branch (all of PR #716 plus
its unpushed Copilot nit-fix commit), so **this PR supersedes #716**,
which can be closed unmerged.

### The worktree mandate (#711)

- **GOVERNANCE.md "Repository Boundaries and Write Safety"** gains the
affirmative task-start rule: every task, a continuation of a prior
session's task included, isolates into its own git worktree before its
first file edit, based on the branch work starts on per "Branching
Model". The primary checkout is the maintainer's own surface.
- **New `repo-worktree` skill** (kept-authority shape: GOVERNANCE keeps
the law, the skill is the task-start surface) carrying the mandate's
trigger moments plus the mechanics as its own content: base-branch
choice, the #699 layout convention (`~/repos/<Repo>`,
`~/repos/worktrees/<Repo>-<task-slug>`), the `git worktree add` +
`EnterWorktree path:` sequence, listing, and post-merge cleanup. The
physical migration of existing checkouts stays tracked in #699.
- **`git-commit-conventions` tightened**: stage by explicit path, never
`git add -A` or `git add .`, and the pre-commit `git status` check
generalizes from "the maintainer's own uncommitted edits" to "any change
this session did not make", with ask-or-stop as the response, never
bundling. The GOVERNANCE "Git and Commit Rules" summary matches.
- **Host-wide agent-safety block**
(`host-setup/agent-safety/claude-md-safety.md`) gains the same
task-start bullet, naming "worktree" in so many words so Claude Code's
`EnterWorktree` tool is armed even in sessions no `AGENTS.md` reaches.
Machines pick it up on their next installer re-run (#365 cadence).
- **AGENTS.md map** annotates the boundaries row with the new skill and
updates the no-skill-by-decision paragraph and the closing skill
inventory.

### The base-branch rule (#714, from PR #716)

Carried in unchanged apart from consolidation cross-links: GitHub's
default-branch setting reads `main` but work starts on `develop`, so a
worktree defaulted to "the default branch" silently misses in-flight
content, and a "does not exist" claim names the branch it was checked
against.

## Verification

- `build_dist.py --check` clean (both skill trees regenerated and
committed together)
- `prose_lint.py`, `repo_gate.py`, `host_gate.py` all pass
- `test_build_dist.py` (19), `test_prose_lint.py` (244),
`test_repo_gate.py` (70), `test_host_gate.py` (72),
`test_skills_install.py` (29), `host-setup/agent-safety/test_install.py`
(45), `spec/validate.py` all pass
- Signed-commit probe run before committing (sig=G, noreply identity on
author and committer)

Closes #711. Closes #714. Supersedes #716.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 15, 2026 13:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR promotes a large batch of previously-squashed changes from develop into the canonical branch, primarily landing the fleet Skills system (source + generated distribution + installer), expanded host setup automation (Windows + Linux), and strengthened Python/CI gating and documentation.

Changes:

  • Add fleet Skills source tree (.agents/skills/), generated Claude plugin distribution (.claude-plugin/), and cross-platform installers/wrappers.
  • Extend host bootstrap/setup flows to install Skills (new host-setup install scripts + bootstrap integration) and formalize tool-floor “remedy” commands in the host-tools spec/schema.
  • Update governance/docs and operational runbooks (WORKFLOW/AUDIT/README/OPERATIONS) to reflect the new guarantees, diagrams, and CI/tooling expectations.

Reviewed changes

Copilot reviewed 91 out of 115 changed files in this pull request and generated no comments.

Show a summary per file
File Description
WORKFLOW.md Updates mermaid diagrams/labels to reference D-guarantees and clarify workflow contract seams.
spec/project-types.json Refines Python coverage check wording for lint-only vs build profiles.
spec/host-tools.schema.json Requires remedy alongside source for any declared version floor in host-tools entries.
spec/host-tools-local.schema.json Extends overlay schema to allow a remedy object in repo-local overrides.
spec/fidelity-model.md Clarifies intent fidelity behavior (presence + staleness advisory) in the audit model.
spec/host-tools.json Adds per-platform “remedy” commands for floored tools so below-floor findings are self-fixing.
scripts/skills_install.py (Referenced by wrappers) Acts as the single cross-platform Skills installer entry point.
scripts/skills_install.sh Adds a POSIX wrapper that locates Python 3.7+ and runs skills_install.py.
scripts/skills_install.ps1 Adds a Windows wrapper that probes Python launchers and runs skills_install.py.
scripts/test_bootstrap.py Removes the old location of bootstrap tests (moved under scripts/tests/).
scripts/tests/test_bootstrap.py Updates/bootstrap-tests to cover Linux + Windows bootstraps and validate remedy coverage.
README.md Adds an “Install the Fleet Skills” section and entry-point diagram/linking to the fleet map.
OPERATIONS.md Updates “Run the gates the way CI runs them” to include Python tooling + coverage and PSScriptAnalyzer invocation.
PSScriptAnalyzerSettings.psd1 Adds repo settings for PSScriptAnalyzer with documented exclusions.
host-setup/bootstrap.sh Adds a --skills mode and installs Skills as part of the --host flow; reports Skills state.
host-setup/linux/install-skills.sh Adds Linux host-setup entry point to drive the Skills installer from a fetched tree.
host-setup/windows/install-skills.ps1 Adds Windows host-setup entry point to drive the Skills installer from a fetched tree.
host-setup/agent-safety/README.md Updates safety-doc wording to include the “isolate into worktree before first edit” rule.
host-setup/agent-safety/claude-md-safety.md Adds an explicit worktree mandate bullet to the host-wide safety block content.
docs/peer-messaging.md Adds hub-only documentation for local peer messaging between agent sessions.
cspell.json Adds newly-used technical terms to the wordlist.
AUDIT.md Adds/updates mermaid procedure diagrams and clarifies audit verdict/staleness semantics.
.gitattributes Updates LF pinning for moved Python tests and newly-added scripts (build/install/test surfaces).
.editorconfig Expands LF pinning to cover Python under scripts/tests/ via a recursive scripts/**.py rule.
.claude-plugin/marketplace.json Adds Claude marketplace metadata for the generated fleet-skills plugin distribution.
.claude-plugin/fleet-skills/.claude-plugin/plugin.json Declares the generated plugin and skill list for Claude Code.
.claude-plugin/fleet-skills/.source-digest Tracks the generated distribution digest for change detection.
.claude-plugin/fleet-skills/skills/* Adds the generated Claude-plugin copies of the Skills (mirrors .agents/skills/).
.agents/skills/README.md Introduces documentation for the Skills source tree and the source-vs-generated split.
.agents/skills/* Adds the canonical Skills source tree used by Codex/opencode and to generate .claude-plugin/.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ptr727
ptr727 merged commit 0e84805 into main Aug 15, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants