docs: on Capy, comment and request reviews only through tools.pr.comment / tools.pr.edit, never gh (GST-1417 follow-up) (#4027)

* docs: on Capy, comment, tag and request reviews only through tools.pr.comment / tools.pr.edit, never gh; unattended /modernize posts nothing (GST-1417 follow-up)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* changelog: own fragment for the GST-1417 follow-up; landed fragments are never edited

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-11-05 05:16:39 +00:00
1 parent c8db3c5b60
commit 4a2e208e3d
9 files changed
+30 -17

No files matched your search

+3 -1
View File
@@ -917,7 +917,9 @@ fix, each with its reason in the closing comment. An issue we intend to fix
later stays open under the `parked` label with one comment saying where it is
tracked (a TODOS.md theme or a tracking issue) and what fixes it. An agent
triaging for the maintainer posts these comments under its bot identity
(`capy-ai[bot]` on Capy), never the maintainer's own account. The full rule,
(`capy-ai[bot]` on Capy), never the maintainer's own account. On Capy, comment only through
`tools.pr.comment`, never `gh pr comment`, `gh issue comment` or `gh api`, because
`gh` runs as the maintainer. The full rule,
including the labels and the close reasons, is in [docs/triage.md](docs/triage.md).
## Community PR triage (wave process)
@@ -0,0 +1 @@
- **On Capy, agents comment and request reviews only through Capy's PR tools, never `gh`.** docs/triage.md, CONTRIBUTING.md, docs/captain.md, docs/recommended-harness.md and /modernize now say that comments and tags go only through `tools.pr.comment` and review requests only through `tools.pr.edit`, both acting as `capy-ai[bot]`. `gh pr comment`, `gh issue comment`, `gh api` and `gstack-post` are never used for them, because `gh` on Capy runs as the maintainer's own account. An unattended /modernize run pushes, closes and posts nothing. (GST-1417)
+3 -2
View File
@@ -248,8 +248,9 @@ dependencies, CI permissions and weakened tests before anything runs it, and do
a fork's "tests pass": run a focused review and the free tier at the port head before the
port opens. When the contributor's fix is right, land it with their authorship kept
(cherry-pick, `Co-authored-by`, the lane's own fixes as separate commits on top of
theirs) and close the original with a specific thank-you that links the port, posted under
the lane's bot identity (`capy-ai[bot]`), never the owner's own account. Closing a
theirs) and close the original with a specific thank-you that links the port, posted as
`capy-ai[bot]` through `tools.pr.comment`, never `gh pr comment`, `gh issue comment` or `gh api` (`gh` runs
as the owner). Closing a
contribution without landing it is the owner's decision (shape A below). The repository's
own statement of the porting steps is [CONTRIBUTING.md](../CONTRIBUTING.md#porting-a-contributors-pr).
+1 -1
View File
@@ -351,7 +351,7 @@ on a few points. Ship the one that fits the repository; both are supported.
| Small fixes | one PR each, batched by the train | batched into wave PRs, since serial slots cost about 30 minutes each |
| After the merge | the main backstop gates any push a train did not cover, and freezes the queue on red | the controller watches main's test, e2e and release runs until the release publishes; a red main freezes the queue until root-caused |
| Severe triage | the Captain watches issues and PRs and starts a thread per unowned severe item | a scheduled severe sweep (every 4 to 8 hours) with a fixed severity bar, dedupe against owned lanes, one hotfix thread per batch |
| Contributor PRs | ported onto a crew branch with the author's commits kept and `Co-authored-by`; the fork PR is closed with a thank-you that links the port, posted under the bot identity (`capy-ai[bot]`) | landed through a wave PR with "Contributed by @handle", `Co-Authored-By` and `Supersedes` lines |
| Contributor PRs | ported onto a crew branch with the author's commits kept and `Co-authored-by`; the fork PR is closed with a thank-you that links the port, posted as `capy-ai[bot]` through `tools.pr.comment`, never `gh` | landed through a wave PR with "Contributed by @handle", `Co-Authored-By` and `Supersedes` lines |
| Privacy | the pregate's sealed-output and secret scans before every push | plus a per-user denylist grep (names, hostnames, identifying counts from private sources) before any public artifact |
## Known Capy limits
+1 -1
View File
@@ -832,7 +832,7 @@ Claude: Claim: #2187 caches the skill census so `bun run skill:check` stops
Verdict: CLOSE. The base solves the problem another way (a2f9c01). Nothing
was pushed and the PR stays open; say "close it" and I will post the reason
and the superseding commit, with thanks to its author.
and the superseding commit from the bot account, with thanks to its author.
```
Three verdicts, one chosen before anything is pushed. **MODERNIZE**: the claim still
+11 -6
View File
@@ -7,12 +7,17 @@ feature requests into TODOS.md themes with a "not rejected" note, and reporters
still saw a closed issue with no fix. Those were reopened on 2026-10-25 under
the `parked` label, and this page is the rule going forward.
An agent triaging for the maintainer may post every comment this page
describes, tag people, request reviews and leave short notes for outside
authors, but only under its bot identity (`capy-ai[bot]` on Capy), never the
maintainer's own GitHub account. An agent with no bot identity writes the
comment as a draft for the maintainer instead. GitHub comments are the only way
an agent reaches people for the maintainer: it never sends them email, chat
An agent triaging for the maintainer may post every comment this page describes,
tag people, request reviews and leave short notes for outside authors, but only
under its bot identity (`capy-ai[bot]` on Capy), never the maintainer's own
GitHub account. On Capy, comment and tag people only through Capy's PR comment
tool (`tools.pr.comment`), and request reviews only through `tools.pr.edit`;
both act as `capy-ai[bot]`. Never comment, tag or request a review with
`gh pr comment`, `gh issue comment`, `gh api` or `gstack-post` on a Capy
machine: `gh` there runs as the maintainer's own account. Elsewhere, comment through `gh` only
when `gh api user --jq .type` prints `Bot`. A comment no bot-identity tool can
post is a draft for the maintainer instead. GitHub comments are the only way an
agent reaches people for the maintainer: it never sends them email, chat
messages, DMs or social posts, and never reads the maintainer's inbox (Garry,
2026-11-04: "never send emails or messages to human beings on my behalf ever";
amended 2026-11-05: "Oh you can leave comments on GitHub").
+4 -2
View File
@@ -116,7 +116,9 @@ your own; this skill is for a branch that has gone stale, often someone else's.
- A comment you post on the PR (a closing note, a thank-you to its author) goes
under your bot identity (`capy-ai[bot]` on Capy), never the maintainer's own
account; with no bot identity, it is a draft in your report for the person to
post. Never email, chat or DM its author.
post. On Capy, post through `tools.pr.comment` (it posts as `capy-ai[bot]`),
never `gh pr comment`, `gh issue comment` or `gh api`, which run as the
maintainer. Never email, chat or DM its author.
- Textual cleanliness is not currency. "Git reports no conflicts" says nothing
about whether the change still makes sense; a PR that applies cleanly to code
whose contract moved is more dangerous than one that conflicts.
@@ -181,7 +183,7 @@ Pick exactly one and state it with the evidence from Steps 1 and 2:
Show the table row you chose and the three sentences from Step 1, then STOP and
ask (AskUserQuestion) before any push, close or comment. If the session is
unattended, the verdict and its evidence are the handoff and nothing is pushed.
unattended, the verdict and its evidence are the handoff and nothing is pushed, closed or posted.
## Step 4 (MODERNIZE only): Rebase and prove intent survived
+4 -2
View File
@@ -45,7 +45,9 @@ your own; this skill is for a branch that has gone stale, often someone else's.
- A comment you post on the PR (a closing note, a thank-you to its author) goes
under your bot identity (`capy-ai[bot]` on Capy), never the maintainer's own
account; with no bot identity, it is a draft in your report for the person to
post. Never email, chat or DM its author.
post. On Capy, post through `tools.pr.comment` (it posts as `capy-ai[bot]`),
never `gh pr comment`, `gh issue comment` or `gh api`, which run as the
maintainer. Never email, chat or DM its author.
- Textual cleanliness is not currency. "Git reports no conflicts" says nothing
about whether the change still makes sense; a PR that applies cleanly to code
whose contract moved is more dangerous than one that conflicts.
@@ -110,7 +112,7 @@ Pick exactly one and state it with the evidence from Steps 1 and 2:
Show the table row you chose and the three sentences from Step 1, then STOP and
ask (AskUserQuestion) before any push, close or comment. If the session is
unattended, the verdict and its evidence are the handoff and nothing is pushed.
unattended, the verdict and its evidence are the handoff and nothing is pushed, closed or posted.
## Step 4 (MODERNIZE only): Rebase and prove intent survived
+2 -2
View File
@@ -33,14 +33,14 @@ describe('/modernize skill', () => {
expect(skill.indexOf('## Step 3: The disposition')).toBeLessThan(skill.indexOf('## Step 4 (MODERNIZE only)'));
expect(skill.indexOf('## Step 4 (MODERNIZE only)')).toBeLessThan(skill.indexOf('## Step 5 (MODERNIZE only)'));
expect(flat).toContain('STOP and ask (AskUserQuestion) before any push, close or comment.');
expect(flat).toContain('If the session is unattended, the verdict and its evidence are the handoff and nothing is pushed.');
expect(flat).toContain('If the session is unattended, the verdict and its evidence are the handoff and nothing is pushed, closed or posted.');
});
test('never closes a PR on its own', () => {
expect(flat).toContain('You never close a PR.');
expect(flat).toContain('Without explicit permission in this session, the PR stays open.');
expect(flat).toContain('The PR stays open until someone with the authority says so.');
expect(flat).toContain('A comment you post on the PR (a closing note, a thank-you to its author) goes under your bot identity (`capy-ai[bot]` on Capy), never the maintainer\'s own account; with no bot identity, it is a draft in your report for the person to post.');
expect(flat).toContain('A comment you post on the PR (a closing note, a thank-you to its author) goes under your bot identity (`capy-ai[bot]` on Capy), never the maintainer\'s own account; with no bot identity, it is a draft in your report for the person to post. On Capy, post through `tools.pr.comment` (it posts as `capy-ai[bot]`), never `gh pr comment`, `gh issue comment` or `gh api`, which run as the maintainer.');
expect(skill).not.toMatch(/gh pr close/);
});