You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Route the README by Reader and Document the Cross-Owner Write Grant (#631)
The README opened straight into prose written for an agent, so a human
arriving from GitHub had no path to what they actually ask: how to use
this repo, how to deploy the host rules, how to diverge from one, and
where to file an issue. It now forks by reader, and it carries the
write-grant documentation that `TODO.md` recorded as ready in #629
without doing.
## The README, routed by reader
A **Getting Started** table above the Table of Contents states the
human/agent split outright, an agent starting at `AGENTS.md` and a human
starting at the table, then routes six reader shapes to one destination
each. Three new sections fill the gaps, placed in the slots
[`spec/readme-structure.md`](./spec/readme-structure.md) already orders
them in so the redesign does not fight the hub's own spec:
- **Using This Repo** (Installation slot), covering the host guardrails,
carrying the rules into a repository, and an honest note that the
registry does not transfer, so adopting outside this fleet means running
your own hub.
- **Diverging From a Rule** (Configuration slot), which separates the
two kinds of exception that get confused: a repository diverging from a
carried unit, where the fidelity level usually already grants the
freedom and the rest is recorded in `spec/divergences.json`, and a write
the host guard denies.
- **Questions or Issues**, previously absent entirely, saying what an
issue needs and that a downstream agent filing here is the normal path
rather than an exception.
## The cross-owner write grant
The guard denies a `gh` write whose explicit target sits under another
owner and names `GH_WRITE_GUARD_ALLOW` in the denial, and no document
said how to give one. [`docs/host-setup.md`](./docs/host-setup.md) now
carries it where the reader already is when the denial arrives:
- The **fork asymmetry** that raises it, where `origin` is your fork and
only the half of the work aimed at `upstream` denies.
- The channel that works, an `env` block in the checkout's
`.claude/settings.local.json`, which scopes the grant to that checkout
rather than the host, and the **session restart** that loads it.
- The value's exact shape: one string and never a JSON array, split on
any run of whitespace or commas, with `owner/*` granting a whole owner
and a token carrying no `/` silently granting nothing. Verified against
`_granted_targets` and `_target_permitted`.
- The **two forms that fail silently**, an inline `VAR=x gh ...` prefix
and an `export` in a shell call, neither of which reaches a hook running
as its own process. That is the property making a grant a deliberate act
outside the session rather than something an agent does for itself once
blocked.
- A **confirmation that does not involve making the write**. Worth
recording: feeding the hook a synthetic payload is not a usable probe
from inside a session, because the payload text carries the very write
shape the guard matches, so the guard denies the probe command itself.
Observed twice while writing this.
`host-setup/agent-safety/README.md` carries the mechanics beside the
hook description and links across.
## Also here
- The **license shield** moves into the closing License section,
matching the form PlexCleaner carries.
[`spec/readme-structure.md`](./spec/readme-structure.md) still states
the old placement under Build and Distribution, so this README is
deliberately ahead of the spec, and reconciling the two is the
`decision`-state **README Structure Rework** cluster's edit rather than
a loose end here. That cluster's `Settled` bullet asserting the old
placement as fact is rewritten to record it.
- **Proxmox** drops out of every supported-platform list, since it is
Linux. The two remaining mentions name the actual Proxmox host in the
rollout, which is correct.
- `untriaged` joins the cspell word list, since the new Diverging
section names the literal value the divergence report renders.
- `TODO.md` loses the shipped cluster and its orphaned link definitions,
and the stale "Refresh the README" chore becomes the open question this
change leaves behind: whether these human entry points belong in the
spec so fleet repos are measured on them. The per-section index
alternative is recorded as declined, with the reason.
## Verification
markdownlint, cspell, editorconfig-checker, `spec/validate.py`, and
`scripts/prose_lint.py --diff develop` all clean locally. CRLF preserved
in every Markdown file, LF preserved in `install.sh`. Every relative
link target and every in-file anchor resolves, checked mechanically.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@@ -28,20 +27,44 @@ Agent enablement for a fleet of repositories: autonomy and repeatable quality in
28
27
29
28
See [Release History][history] for the full history.
30
29
30
+
## Getting Started <!-- omit from toc -->
31
+
32
+
This repo has two kinds of reader, a human and an AI coding agent, and they enter at different doors. **An agent starts at [AGENTS.md][agents]**, which maps a task to the document that governs it and is written to be read one section at a time. **A human starts here**, and the table below is the fork: find the row that describes why you opened this page, and read the one it points at rather than the whole file.
33
+
34
+
| You are | Your question | Start at |
35
+
| --- | --- | --- |
36
+
| Browsing GitHub | What is this, and why does it exist? |[What This Repo Is][what-this-repo-is] and [What It Achieves][what-it-achieves]|
37
+
| Setting up a machine where an agent runs | How do I deploy the host guardrails? |[`docs/host-setup.md`][host-setup]|
38
+
| Adopting the rules in a repository | How do I stand a repo up, or bring an existing one into line? |[`STANDUP.md`][standup], then [`AUDIT.md`][audit]|
39
+
| Blocked by a rule | How do I diverge from one, or grant a write the guard denies? |[Diverging From a Rule][diverging-from-a-rule]|
40
+
| Reporting a defect or proposing a rule | Where does that go, and what does it need? |[Questions or Issues][questions-or-issues]|
41
+
| An AI coding agent | Which document governs the task in front of me? |[`AGENTS.md`][agents]|
42
+
43
+
Nothing here is installed as a dependency. The rules are read, the baseline is carried into a repository as files it then owns, and the one thing that is genuinely installed is the host guardrail kit, which lands in your home directory rather than in any repository.
44
+
31
45
## Table of Contents <!-- omit from toc -->
32
46
33
47
-[What This Repo Is](#what-this-repo-is)
34
48
-[What It Achieves](#what-it-achieves)
35
49
-[How This Repo Operates](#how-this-repo-operates)
50
+
-[Using This Repo](#using-this-repo)
51
+
-[Deploy the Host Guardrails](#deploy-the-host-guardrails)
52
+
-[Carry the Rules Into a Repository](#carry-the-rules-into-a-repository)
53
+
-[Adopting Outside This Fleet](#adopting-outside-this-fleet)
54
+
-[Diverging From a Rule](#diverging-from-a-rule)
55
+
-[A Repository Diverging From a Carried Unit](#a-repository-diverging-from-a-carried-unit)
56
+
-[A Write the Host Guard Denies](#a-write-the-host-guard-denies)
36
57
-[Rules](#rules)
37
58
-[Always](#always)
38
59
-[Never](#never)
39
60
-[If a C# Project](#if-a-c-project)
40
61
-[If a Python Project](#if-a-python-project)
62
+
-[If Both C# and Python](#if-both-c-and-python)
41
63
-[If Publishing a Package (NuGet or PyPI)](#if-publishing-a-package-nuget-or-pypi)
42
64
-[If a Docker Image](#if-a-docker-image)
43
65
-[For a README or Human-Facing Doc](#for-a-readme-or-human-facing-doc)
@@ -59,12 +82,15 @@ This repo is the single home for those rules, a machine-readable spec they are c
59
82
-**[GOVERNANCE.md][governance]** - cross-cutting rules for AI coding agents: git, branching, release model, doc style, the recurring-violation rules (comments, ASCII charset, US spelling, line endings), PR review etiquette, and workflow YAML conventions.
60
83
-**[CODESTYLE.md][codestyle]** - code style for .NET and Python.
61
84
-**[WORKFLOW.md][workflow]** - the CI/CD workflow contract (behavioral guarantees D1-D9) and its audit methodology.
85
+
-**[STANDUP.md][standup]** - how an agent stands a repository up and carries the baseline it is owed.
62
86
-**[AUDIT.md][audit]** - how an agent audits a repository against the spec and reports drift.
63
87
-**[spec/][spec]** - the machine-readable ground truth: project-type requirements, the file/section baseline, required/forbidden secrets, and the preferred README structure.
64
88
-**[registry/repos.json][repos]** - the fleet registry: every project, its type(s), publish mechanism, and status (cataloged or standardization backlog).
65
89
-**[repo-config/][repo-config]** - branch rulesets and the apply script (kept out of `.github/`, which is Actions-owned), plus the GitHub setup reference.
90
+
-**[host-setup/][host-setup-dir]** - the host guardrail kit, which is per machine rather than per repository.
-**[docs/][docs]** - the human setup and reference guides: host prerequisites, SSH signing, devcontainers, and the carry procedures.
68
94
69
95
**The words a request is phrased in are defined here.** A repository is asked to audit itself against the hub, or to close the review loop on a pull request, and the phrasing carries the whole instruction, so each term below names the file that answers it and a request using one is a complete instruction rather than a starting point for interpretation.
70
96
@@ -105,6 +131,54 @@ ProjectTemplate follows the same model it documents, and audits its own rules ag
105
131
-**Review loop.** Every PR is reviewed by GitHub Copilot, and the agent drives the review loop to green and merges only with explicit maintainer permission. See [GOVERNANCE.md "PR Review Etiquette"][governance-pr-review-etiquette].
106
132
-**Release.** A `develop -> main` merge is promoted through a GitHub release (tag plus a source zip, README, and LICENSE). Versioning is NBGV-driven from [version.json][version]. See [WORKFLOW.md][workflow].
107
133
134
+
## Using This Repo
135
+
136
+
Three things are deployed from here, and they land in different places. The host guardrails install once per machine, the baseline is carried once per repository, and the audit is run whenever a repository changes materially. Do them in that order on a new machine, because the guardrails bound every session that follows and retrofitting them means the sessions in between ran unguarded.
137
+
138
+
### Deploy the Host Guardrails
139
+
140
+
The guardrails are the one component that is installed rather than read, and they are **host state rather than repository content**, because they have to cover ad-hoc sessions in no project at all. They deny a mis-targeted GitHub write under your identity, and a git operation that would only land by bypassing a branch rule.
.\host-setup\agent-safety\install.ps1 # Windows, and the .\ prefix is required
148
+
```
149
+
150
+
Restart Claude Code sessions on the machine afterward so the hook and the `CLAUDE.md` blocks load. The installer is idempotent, so re-running it is also how a machine picks up an upstream change to the guard. What it installs, how to verify it, and what it deliberately does not catch are in [`host-setup/agent-safety/README.md`][agent-safety], and the surrounding host prerequisites (git identity, SSH signing, `gh`, `docker`, `uv`) are in [`docs/host-setup.md`][host-setup].
151
+
152
+
### Carry the Rules Into a Repository
153
+
154
+
A repository that does not exist yet is stood up with [`STANDUP.md`][standup], which is ordered rather than a menu: verify commit identity and signing before the first commit, hand the maintainer what only they can supply, classify the repo and write its [registry][repos] entry, carry the instruction set before authoring anything of your own, then carry the remaining baseline, the workflows, and the settings. The two steps with a closing window are first, because signing has to be live before the first commit and the rules have to be loaded before the first authored file.
155
+
156
+
A repository that already exists is measured with [`AUDIT.md`][audit] instead. The audit is read-only and ends in a report under [reports/][reports], so nothing is changed by measuring, and applying what it found is a separate reviewable change per its section 10. Onboarding is complete when the repo passes, or carries a committed report plus a tracking issue for the residual deltas, per [GOVERNANCE.md "Repository Onboarding and Conformance"][governance-repository-onboarding-and-conformance].
157
+
158
+
The mechanical helpers that go with those procedures are documented beside them: [`docs/repo-config-carry.md`][repo-config-carry] for branch rulesets and repository settings, and [`docs/content-import.md`][content-import] for importing existing content into a new repo.
159
+
160
+
### Adopting Outside This Fleet
161
+
162
+
The rules, the spec, and the procedures are readable and reusable by anyone, and the guardrail kit installs on any host. What does not transfer is the registry, since [registry/repos.json][repos] lists this fleet's projects, and standing a repository up writes an entry in it. Adopting outside this fleet therefore means running your own hub, forked or copied, holding your own registry and your own reports, with `AGENTS.md`, `GOVERNANCE.md`, `CODESTYLE.md`, `WORKFLOW.md`, and `spec/` adapted to what your projects actually are. There is no supported mode where an outside repository points at this hub's registry.
163
+
164
+
## Diverging From a Rule
165
+
166
+
A rule that cannot be diverged from is a rule people work around silently, which is worse than the divergence, so both kinds of exception have a declared channel. The two kinds are genuinely different: one is a repository not matching a carried unit, and the other is a host guard denying a write. Neither is granted by editing the thing that blocked you.
167
+
168
+
### A Repository Diverging From a Carried Unit
169
+
170
+
**Check the unit's fidelity level first, because most apparent divergences are not divergences at all.** Each [spec/files.json][files] entry declares one of `verbatim`, `interface`, `intent`, or `presence`, defaulting to `presence`, and the two permissive levels already hand the repo its content outright. A repo rewriting a `presence` or `intent` file to suit itself is exercising the freedom the level grants rather than breaking a rule, and the audit asserts nothing beyond presence for it. See [spec/fidelity-model.md][fidelity-model] for which unit sits where and why.
171
+
172
+
**A divergence from a `verbatim` or `interface` unit is recorded, not hidden.** The ledger is [spec/divergences.json][divergences], where each entry names the path, the repos, a disposition, and a reason, and `spec/fidelity_honesty.py --report` joins it against live fleet reality to regenerate [reports/divergences.md][divergences-report]. A divergence recorded as `accepted` is a legitimate permanent one and no further action is owed. A live divergence with no entry renders as `UNTRIAGED`, which is the point: the audit does not care whether a difference is deliberate, only whether someone decided about it. Edit the ledger and regenerate the report, never the report.
173
+
174
+
**A rule that is wrong for many repositories is a hub defect rather than a per-repo exception.**[AUDIT.md][audit] section 9 says so directly, that a repeated letter miss many repos share is a signal the spec needs adjusting, so raise it here instead of accumulating one exception per repository.
175
+
176
+
### A Write the Host Guard Denies
177
+
178
+
The guard denies a `gh` write whose explicit target sits under an owner other than the checkout's `origin` owner, which is the shape that once put a stray comment on a stranger's repository. Sibling repositories under the same owner are allowed, so the denial appears only on a write that leaves the owner, and the common case that raises it is a fork, where `origin` is yours and `upstream` is the project you forked from.
179
+
180
+
The only way past it is a grant the maintainer makes **outside the session**, in `GH_WRITE_GUARD_ALLOW`. It is deliberately not something an agent can do for itself once blocked, so an inline `GH_WRITE_GUARD_ALLOW=owner/repo gh ...` prefix and an `export` inside a shell call both leave the write denied. The worked example, the file the grant goes in, and how to confirm one took effect are in [`docs/host-setup.md` "Granting a Write the Guard Denies"][host-setup-granting-a-write-the-guard-denies].
181
+
108
182
## Rules
109
183
110
184
A human-readable index of the rules agents enforce, implement, and audit. The authority for each is [GOVERNANCE.md][governance], [CODESTYLE.md][codestyle], and [WORKFLOW.md][workflow]. The machine-checkable form lives in [spec/][spec].
@@ -160,13 +234,36 @@ A human-readable index of the rules agents enforce, implement, and audit. The au
160
234
161
235
- Make GitHub Actions satisfy the [WORKFLOW.md][workflow] contract (guarantees D1-D9), which the audit verifies.
162
236
237
+
## Questions or Issues
238
+
239
+
File everything at [Issues][issues-link], including a defect in a rule, a procedure that did not survive contact with a real repository, and a proposal for a new rule. Use [Discussions][discussions-link] for an open question that is not yet a defect. This repo ships no application code, so an issue here is about the rules, the spec, the procedures, or the tooling under [`scripts/`][scripts] and [`spec/`][spec], never about a downstream project's behavior, which belongs on that project's own tracker.
240
+
241
+
An issue is most useful when it names the ground truth it disagrees with, so include the file and section that states the rule, the repository and branch where the problem was observed, and what you expected instead. A finding measured against a specific commit is worth more than one measured against a memory of the docs, per [GOVERNANCE.md "Verification Discipline"][governance-verification-discipline].
242
+
243
+
Two kinds of report are worth calling out because they are the ones that improve the procedures rather than one repository:
244
+
245
+
-**A procedure that could not be followed cold.** The onboarding docs are sufficient only when a context-free agent can stand a repo shape up from them alone, so a step that needed knowledge the docs never gave is a documentation defect tracked in the [conformance matrix][matrix] and fixed here rather than worked around per repo.
246
+
-**A rule that many repositories miss the same way.** That is a signal the spec needs adjusting rather than a queue of per-repo exceptions, per [AUDIT.md][audit] section 9.
247
+
248
+
Issues are also filed here **by agents working in downstream repositories**, which is the normal path rather than an exception, since the agent that hit the gap is the one holding the evidence for it.
249
+
163
250
## Development Environment Setup
164
251
165
252
Contributors sign every commit. See [docs/ssh-signing.md][ssh-signing] for SSH commit-signing setup, [docs/host-setup.md][host-setup] for host prerequisites, and [docs/devcontainer.md][devcontainer] for devcontainer SSH-agent forwarding. Run the linters before pushing (see [GOVERNANCE.md "Running the Linters Locally"][governance-running-the-linters-locally-known-working-invocations]).
166
253
254
+
Changes land the same way every fleet change does: a feature branch, a squash merge into `develop`, a Copilot review loop driven to green, and a merge only with the maintainer's explicit approval. The backlog is [`TODO.md`][todo], which holds the work that is ready to pick up along with the reasoning behind each item, so read it before proposing something it already covers.
0 commit comments