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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .agents/skills/drive-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,22 @@ promotion PR once the fix lands, is the early exit this skill exists to prevent.
to delete it, which fails when `develop` is already checked out somewhere else, the ordinary
case in this layout. Instead run repo-worktree's post-merge cleanup from the base clone, remove
the worktree and delete the now-merged local task branch, then verify before deleting the remote
one, which is this skill's own step rather than that one's. Both remote commands resolve `origin`,
one, which is this skill's own step rather than that one's. Delete the remote one with
`python3 scripts/pr_review.py cleanup <number> --repo <owner>/<repo>`, run from a hub checkout.
It takes the pull request rather than a branch name and does the verify-then-delete below in
code. It refuses unless the pull request merged into `develop` from a head in that same
repository, and refuses a permanent branch or one any ruleset or branch protection covers. It
checks the tip is still at the pull request's `headRefOid` before deleting, and reads the ref
back to confirm.
Exit `0` is done, the branch deleted or already gone. Any other exit stops and reports rather
than deleting by hand: `1` is a refusal, a moved tip among them, `2` a read that did not answer
or a delete it could not confirm, and `64` a target under an owner other than the hub
checkout's own `origin`, or that `origin` unreadable. A registry refusal is a `1`. It runs
under the host-safety installer's `Bash(python3 scripts/pr_review.py:*)` allow rule,
which is what lets auto mode complete it.
On a host without that rule the hand form below is the fallback, and where this seat cannot
run that either, report its commands to the maintainer, paste-ready with the values substituted.
Both remote commands of the hand form resolve `origin`,
so they hold only where the pull request's head branch lives in this repository, which step 1
guarantees by branching here. A pull request opened from a fork follows
`upstream-contribution-workflow` instead and neither command applies to it, since `origin` would
Expand Down
13 changes: 12 additions & 1 deletion .agents/skills/merge-and-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,18 @@ skill covers all of it, scoped down by what the maintainer actually asks for.
use `git branch -D -- "<exact-branch>"` here, safe only because the GitHub-state check just
proved that exact branch finished, the narrow post-squash exception git-commit-conventions
describes, never applied to an unverified branch. Then, only when the remote branch still
exists, delete it the same way, `git push origin --delete -- "<branch>"`.
exists, delete it with `python3 scripts/pr_review.py cleanup <number> --repo owner/repo`, run
from a hub checkout, `<number>` being the merged pull request the check above returned. It
re-reads that pull request and repeats the merged, base, head-repository, and tip checks in
code, refuses a permanent or protected branch, and confirms the delete by reading the ref
back. Exit `0` is done, and any other exit stops and reports: `1` is a refusal, `2` an
unanswered read or an unconfirmed delete, and `64` a target under an owner other than the hub
checkout's own `origin` or that `origin` unreadable, a registry refusal being a `1`. It runs
under the host-safety installer's `Bash(python3 scripts/pr_review.py:*)` allow rule,
which is what lets auto mode complete it.
On a host without that rule the fallback is `git push origin --delete -- "<branch>"` once the
tip checks above pass, and where this seat cannot run it, report it to the maintainer,
paste-ready with the values substituted.
Comment thread
ptr727 marked this conversation as resolved.
Never `--force-with-lease` here, git-commit-conventions
forbids it unconditionally, the GitHub-state check just completed is the verification gate,
not a compare-and-swap at delete time. Never apply this sweep to `develop` or `main`
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/fleet-skills/.source-digests/drive-pr
Original file line number Diff line number Diff line change
@@ -1 +1 @@
aeb0b23f1960e8f7
227f27065490536c
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0d6d711570caaa67
f94d03359a89a1ea
17 changes: 16 additions & 1 deletion .claude-plugin/fleet-skills/skills/drive-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,22 @@ promotion PR once the fix lands, is the early exit this skill exists to prevent.
to delete it, which fails when `develop` is already checked out somewhere else, the ordinary
case in this layout. Instead run repo-worktree's post-merge cleanup from the base clone, remove
the worktree and delete the now-merged local task branch, then verify before deleting the remote
one, which is this skill's own step rather than that one's. Both remote commands resolve `origin`,
one, which is this skill's own step rather than that one's. Delete the remote one with
`python3 scripts/pr_review.py cleanup <number> --repo <owner>/<repo>`, run from a hub checkout.
It takes the pull request rather than a branch name and does the verify-then-delete below in
code. It refuses unless the pull request merged into `develop` from a head in that same
repository, and refuses a permanent branch or one any ruleset or branch protection covers. It
checks the tip is still at the pull request's `headRefOid` before deleting, and reads the ref
back to confirm.
Exit `0` is done, the branch deleted or already gone. Any other exit stops and reports rather
than deleting by hand: `1` is a refusal, a moved tip among them, `2` a read that did not answer
or a delete it could not confirm, and `64` a target under an owner other than the hub
checkout's own `origin`, or that `origin` unreadable. A registry refusal is a `1`. It runs
under the host-safety installer's `Bash(python3 scripts/pr_review.py:*)` allow rule,
which is what lets auto mode complete it.
On a host without that rule the hand form below is the fallback, and where this seat cannot
run that either, report its commands to the maintainer, paste-ready with the values substituted.
Both remote commands of the hand form resolve `origin`,
so they hold only where the pull request's head branch lives in this repository, which step 1
guarantees by branching here. A pull request opened from a fork follows
`upstream-contribution-workflow` instead and neither command applies to it, since `origin` would
Expand Down
13 changes: 12 additions & 1 deletion .claude-plugin/fleet-skills/skills/merge-and-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,18 @@ skill covers all of it, scoped down by what the maintainer actually asks for.
use `git branch -D -- "<exact-branch>"` here, safe only because the GitHub-state check just
proved that exact branch finished, the narrow post-squash exception git-commit-conventions
describes, never applied to an unverified branch. Then, only when the remote branch still
exists, delete it the same way, `git push origin --delete -- "<branch>"`.
exists, delete it with `python3 scripts/pr_review.py cleanup <number> --repo owner/repo`, run
from a hub checkout, `<number>` being the merged pull request the check above returned. It
re-reads that pull request and repeats the merged, base, head-repository, and tip checks in
code, refuses a permanent or protected branch, and confirms the delete by reading the ref
back. Exit `0` is done, and any other exit stops and reports: `1` is a refusal, `2` an
unanswered read or an unconfirmed delete, and `64` a target under an owner other than the hub
checkout's own `origin` or that `origin` unreadable, a registry refusal being a `1`. It runs
under the host-safety installer's `Bash(python3 scripts/pr_review.py:*)` allow rule,
which is what lets auto mode complete it.
On a host without that rule the fallback is `git push origin --delete -- "<branch>"` once the
tip checks above pass, and where this seat cannot run it, report it to the maintainer,
paste-ready with the values substituted.
Never `--force-with-lease` here, git-commit-conventions
forbids it unconditionally, the GitHub-state check just completed is the verification gate,
not a compare-and-swap at delete time. Never apply this sweep to `develop` or `main`
Expand Down
17 changes: 16 additions & 1 deletion .github/skills/drive-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,22 @@ promotion PR once the fix lands, is the early exit this skill exists to prevent.
to delete it, which fails when `develop` is already checked out somewhere else, the ordinary
case in this layout. Instead run repo-worktree's post-merge cleanup from the base clone, remove
the worktree and delete the now-merged local task branch, then verify before deleting the remote
one, which is this skill's own step rather than that one's. Both remote commands resolve `origin`,
one, which is this skill's own step rather than that one's. Delete the remote one with
`python3 scripts/pr_review.py cleanup <number> --repo <owner>/<repo>`, run from a hub checkout.
It takes the pull request rather than a branch name and does the verify-then-delete below in
code. It refuses unless the pull request merged into `develop` from a head in that same
repository, and refuses a permanent branch or one any ruleset or branch protection covers. It
checks the tip is still at the pull request's `headRefOid` before deleting, and reads the ref
back to confirm.
Exit `0` is done, the branch deleted or already gone. Any other exit stops and reports rather
than deleting by hand: `1` is a refusal, a moved tip among them, `2` a read that did not answer
or a delete it could not confirm, and `64` a target under an owner other than the hub
checkout's own `origin`, or that `origin` unreadable. A registry refusal is a `1`. It runs
under the host-safety installer's `Bash(python3 scripts/pr_review.py:*)` allow rule,
which is what lets auto mode complete it.
On a host without that rule the hand form below is the fallback, and where this seat cannot
run that either, report its commands to the maintainer, paste-ready with the values substituted.
Both remote commands of the hand form resolve `origin`,
so they hold only where the pull request's head branch lives in this repository, which step 1
guarantees by branching here. A pull request opened from a fork follows
`upstream-contribution-workflow` instead and neither command applies to it, since `origin` would
Expand Down
13 changes: 12 additions & 1 deletion .github/skills/merge-and-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,18 @@ skill covers all of it, scoped down by what the maintainer actually asks for.
use `git branch -D -- "<exact-branch>"` here, safe only because the GitHub-state check just
proved that exact branch finished, the narrow post-squash exception git-commit-conventions
describes, never applied to an unverified branch. Then, only when the remote branch still
exists, delete it the same way, `git push origin --delete -- "<branch>"`.
exists, delete it with `python3 scripts/pr_review.py cleanup <number> --repo owner/repo`, run
from a hub checkout, `<number>` being the merged pull request the check above returned. It
re-reads that pull request and repeats the merged, base, head-repository, and tip checks in
code, refuses a permanent or protected branch, and confirms the delete by reading the ref
back. Exit `0` is done, and any other exit stops and reports: `1` is a refusal, `2` an
unanswered read or an unconfirmed delete, and `64` a target under an owner other than the hub
checkout's own `origin` or that `origin` unreadable, a registry refusal being a `1`. It runs
under the host-safety installer's `Bash(python3 scripts/pr_review.py:*)` allow rule,
which is what lets auto mode complete it.
On a host without that rule the fallback is `git push origin --delete -- "<branch>"` once the
tip checks above pass, and where this seat cannot run it, report it to the maintainer,
paste-ready with the values substituted.
Never `--force-with-lease` here, git-commit-conventions
forbids it unconditionally, the GitHub-state check just completed is the verification gate,
not a compare-and-swap at delete time. Never apply this sweep to `develop` or `main`
Expand Down
35 changes: 29 additions & 6 deletions host-setup/agent-safety/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ text says, because the harm it covers was never in the text.
4. **A git operation that would only succeed by bypassing an active branch rule is denied**: a
direct push to a branch whose rules require a pull request, a force-push where history is
protected, a delete where deletion is blocked, or an explicit-bypass flag (`--admin` on a merge,
`--no-verify` or a `-c core.hooksPath=` override on a commit/push). Judge branch-rule cases against that branch's *live* rules, so a
`--no-verify` or a `-c core.hooksPath=` override on a commit/push). An `include.path`/`includeIf`
override on a commit or push is denied as one too. The file it pulls in may set
`core.hooksPath` where the hook cannot read it. These flags are read in a command the hook
parses, a wrapper shell's body among them, and not inside a quoted `eval` argument. Judge branch-rule cases against that branch's *live* rules, so a
code-style `develop` denies and a config-style `develop` allows with no per-repo configuration.
Each refspec's operation is judged on its own, so a `+src` or a `:dst` refspec forces or
deletes only its own branch. A force-push and a delete each write the branch too, so a branch
Expand All @@ -68,8 +71,27 @@ text says, because the harm it covers was never in the text.
that case, a push whose target the hook cannot read at all is denied whatever branch it names.
That covers a push in text the hook does not parse and a push carrying a `-c`/`--config-env`
override. It covers a git command under an `include.path`/`includeIf` override too, where git
lists no such subcommand, since the included file may define it as a push alias. It also covers
a bare push or a `HEAD`/`@` refspec whose directory or branch may change before it runs. The
lists no such subcommand, since the included file may define it as a push alias. The same holds
where git does not build the subcommand in. An `--exec-path`, a `GIT_EXEC_PATH`, or a PATH
change can leave such a name to an alias. The override is also unreadable on a git command that
runs other git commands (`rebase`, `submodule`, `bisect`, `filter-branch`, `difftool`,
`mergetool`), whatever its arguments say. It reaches every git command that one runs. An `eval`
argument holding an include key is read as the command it runs. It also covers a bare push or a
`HEAD`/`@` refspec whose directory or branch may change before it runs. Such a push's local
branch is checked under its whole name, such as `release/1.0`. It is also checked with its first
segment dropped. A remote-tracking push target such as `origin/feature/x` is checked with its
remote dropped. A word the shell rewrites or drops before git reads it is denied where it can
change what git runs. Such a word is a `$`, backtick, or brace-expansion word. It is denied
where any git command's subcommand goes, and among a push's words or a commit's. On any git
command it is denied among the global options where word splitting may split it. A
redirection where the subcommand goes or among the global options is denied too, a numbered
one such as `2>` included. The exception is a git whose first word is an option such as
`--version` that ends git there. A redirection target spanning several words on a push or a
commit is denied, and so is a comment among a push's words. Some words are read as they
stand. They are a directory option's value short of a brace expansion, a commit option's
double-quoted value, a commit path after `--`, and a redirection target held in one word. The
push and include checks also read each command with its quotes and backslashes removed and
`git` in any case, so a `p''ush` or an uppercase `GIT` reaches them. The
workaround is an explicit refspec run as its own command. Every other
requirement here favors precision over recall throughout, denying only a positively-identified
dangerous shape, since a hook that fails closed on an unrelated resolution failure blocks
Expand Down Expand Up @@ -464,9 +486,10 @@ opt-in per clone, visible to anyone reading the repo, and bypassable on purpose,
rule whose harm is a quality miss rather than a destruction, which the host layer's bar excludes.
The hub's own `.husky/pre-push` is the worked example there, refusing a branch push that no
recorded local review pass covers, per [`GOVERNANCE.md`][governance] "Verification Discipline".
The two layers meet at requirement 4, which denies `--no-verify` and a `-c core.hooksPath=`
override unconditionally, so a Claude Code session meets a committed hook it
cannot wave through with either while a human keeps the escape hatch. They do not compose into a
The two layers meet at requirement 4, which denies `--no-verify`, a `-c core.hooksPath=`
override, and an include override on a commit or push unconditionally, wherever it reads them. So
a Claude Code session meets a committed hook it
cannot wave through with any of them while a human keeps the escape hatch. They do not compose into a
seal, and saying so would be the more comfortable claim rather
than the true one. A committed hook is bypassable by construction, since it cannot police its own
invocation, and `--no-verify` is the documented route rather than the only one. This requirement
Expand Down
Loading
Loading