用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ci/persops --skill jjpr命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | jjpr |
| description | Manage stacked pull requests with jjpr in Jujutsu repositories. |
Use with the $jj skill. Keep one authority per layer:
jj owns changes, ancestry, bookmarks, workspaces, and recovery.jjpr owns ordinary GitHub, GitLab, and Forgejo PR submission and landing.jjpr creates or updates the PRs,
gh stack link or the Stacks REST API registers them, and gh stack merge
lands them.Never use Git-local gh stack init, add, modify, rebase, sync, push,
or submit in a jj-owned repository.
The ordinary workflow is validated with jjpr 0.39.1. The native GitHub path is
additionally validated with gh 2.97.0, gh-stack 0.1.0, and API version
2026-03-10. If a selected tool version differs, stop before its first forge
write and revalidate that path.
jj status and jjpr --version. For native GitHub work, also run
gh --version and gh stack --version.OWNER/REPO, Stack base, and Git remote values. Never depend on
repository inference from a .git-less jj workspace.jjpr auth test before the first forge operation. After selecting the
native GitHub path, or before using GitHub REST to detect native membership,
also run gh auth status --active --hostname github.com. Never use
--show-token.jjpr submit as push/PR-write, gh stack link and unstack as remote
Stack writes, and gh stack merge as landing. Require matching authority.git push in a jj repository.modules/jjpr.nix; do not edit the
generated jjpr config.jjpr status has no remote selector in 0.39.1. Treat it as an optional local
hint only; explicit REST reads are authoritative for remote Stack state.Use one bookmark per independently landable PR, ordered bottom to top. Commits
between bookmarks belong to the upper bookmark's PR. Bookmarks follow rewritten
changes but do not move to a newly created child; use jj bookmark set when
advancing one. Finish with an empty @ above the top bookmark.
Before any submission, verify the whole range:
jj status
jj log -r '<base>..<top>'
jj log -r 'conflicts() & <base>..<top>'
jj bookmark list --all-remotes
Stop on conflicts, divergent bookmarks, an unexpected base, or extra changes inside a PR segment.
For work intended to become a native Stack, declare and count the complete PR list before the first forge write. Native Stacks contain 2–100 PRs. Keep a singleton as an ordinary unstacked PR; split a larger series into separately authorized Stacks before submitting anything.
For ordinary chained PRs on GitHub, GitLab, or Forgejo, read and follow
Ordinary jjpr stacks and do not run gh stack.
For an existing GitHub PR chain, use explicitly scoped REST reads to detect
native membership before choosing. Continue below only when the user wants a
new native GitHub Stack or the PRs are already native members.
Before any live jjpr submit on the native path, obtain exclusive remote-writer
coordination for the desired PR heads and bases and any existing Stack. Hold it
through final projection verification. If that cannot be guaranteed, stop for
manual coordination.
Pass the top bookmark explicitly; a normal empty @ above the stack is not a
reliable inference target. Preview the complete write:
jjpr submit <top> --base <base> --remote <remote> --dry-run
Require the intended repository, the bottom PR targeting the chosen base, and every higher PR targeting the bookmark directly below it.
After the dry-run and before its live counterpart, resolve each existing open PR by exact repository and head ref. Require zero or one result per bookmark; an ambiguous result is a stop:
gh pr list --repo OWNER/REPO --state open --head '<bookmark>' --limit 100 \
--json number,headRefName,headRefOid,baseRefName,state,isDraft,url
For every existing result, read both its PR record and landing state:
gh api 'repos/OWNER/REPO/pulls/PR_NUMBER' \
-H 'X-GitHub-Api-Version: 2026-03-10' \
--jq '{number,head:.head.ref,head_sha:.head.sha,base:.base.ref,state,merged,locked,stack}'
gh api graphql -F owner=OWNER -F repo=REPO -F number=PR_NUMBER \
-f query='query($owner:String!,$repo:String!,$number:Int!){repository(owner:$owner,name:$repo){pullRequest(number:$number){state merged mergeQueueEntry{id} autoMergeRequest{enabledAt}}}}'
Require the exact expected head ref, the recorded remote bookmark SHA, OPEN,
unmerged, unlocked, no merge-queue entry, and no auto-merge request. Any native
membership selects Update a registered Stack; the create path additionally
requires every existing PR to be unstacked. Stop before pushing on any drift or
ineligible PR.
Use this live-submit path only after the native pre-submit gate, for initial creation or when every desired PR is proven unstacked. If any PR is a native member, use Update a registered Stack instead.
jjpr submit <top> --base <base> --remote <remote>
Use --draft only when requested; otherwise submit ready for review. Optional
reviewer flags are:
jjpr submit <top> --base <base> --remote <remote> --reviewer alice,bob
jjpr submit <top> --base <base> --remote <remote> --reviewer alice,bob --reviewer-scope all
After submission, resolve each bookmark to exactly one open PR and record the PR numbers bottom to top. Verify the head and base, not only the number:
gh pr view <bookmark> --repo OWNER/REPO \
--json number,headRefName,headRefOid,baseRefName,state,isDraft,url
jj log -r '<bookmark>' --no-graph -T 'commit_id ++ "\n"'
Require headRefOid == commit_id for every bookmark before continuing.
Do not pass bookmark or branch names to gh stack link; PR-number-only linking
prevents another tool from pushing the branches.
gh stack link has no dry-run. It can attempt PR-base writes before rejecting
an invalid reorder, so read remote state and classify it before calling link.
Reconfirm that the complete desired list still contains 2–100 PRs.
The link API has no expected-membership or compare-and-swap guard. Keep the exclusive remote-writer coordination acquired before live submission through this read/write/verification sequence.
Read every desired PR using the preview API:
for pr in PR1 PR2 PR3; do
gh api "repos/OWNER/REPO/pulls/$pr" \
-H 'X-GitHub-Api-Version: 2026-03-10' \
--jq '{number,head:.head.ref,head_sha:.head.sha,base:.base.ref,state,merged,draft,locked,auto_merge,stack}'
gh api graphql -F owner=OWNER -F repo=REPO -F number="$pr" \
-f query='query($owner:String!,$repo:String!,$number:Int!){repository(owner:$owner,name:$repo){pullRequest(number:$number){state merged mergeQueueEntry{id} autoMergeRequest{enabledAt}}}}'
done
Require every desired PR to remain open, unmerged, unlocked, unqueued, and
without auto-merge. Draft state may differ only when the authorized
jjpr submit changed it. Immediately before link or the REST add, repeat the
PR and complete-Stack reads and require the recorded heads, bases, membership,
order, eligibility, and intended classification to be unchanged.
If a PR reports Stack membership, read that complete Stack:
gh api 'repos/OWNER/REPO/stacks/STACK_NUMBER' \
-H 'X-GitHub-Api-Version: 2026-03-10' \
--jq '{number,base:.base.ref,pull_requests:[.pull_requests[] | {number,head:.head.ref,state}]}'
Permit exactly one case:
link.link; insertion, reorder, removal,
mixed Stack membership, or a base mismatch needs an explicit reshape.For a new Stack, pass every PR bottom to top:
GH_REPO=OWNER/REPO gh stack link --base BASE PR1 PR2 PR3
For a clean top append, bypass gh-stack 0.1.0's unpaginated Stack-number lookup and call the already-preflighted official add endpoint with only the new top PRs:
gh api --method POST 'repos/OWNER/REPO/stacks/STACK_NUMBER/add' \
-H 'X-GitHub-Api-Version: 2026-03-10' \
-F 'pull_requests[]=PR3' -F 'pull_requests[]=PR4'
Let jjpr own draft/ready state; do not pass --open to link. Never retry a
failed link blindly: reread membership and every PR base first because an
earlier write may have succeeded.
Read the Stack again and prove all of these:
Fail closed on any partial or inconsistent result. Do not make jjpr status
part of this gate; it cannot select the submitted Git remote.
After REST confirms the current membership and exact base chain, rewrite or append changes with jj and range-check:
jj status
jj log -r 'conflicts() & <base>..<top>'
Repeat Native pre-submit gate. Run the live update only if the dry-run preserves every native member's target branch. A lower head commit changing is a content update; a member targeting a different branch is a shape change.
jjpr submit <top> --base <base> --remote <remote>
Resolve every desired PR number, head ref, and head SHA again, then repeat
Preflight native Stack registration and Verify the projection. A new top
PR remains unstacked until the top-append REST add succeeds. Do not call an
update complete merely because jjpr submit succeeded.
An unchanged PR chain can be updated normally. jjpr 0.39.1 refuses before
pushing when the local graph would require retargeting a native member. Treat
that refusal as a shape conflict; do not bypass it with gh pr edit or a raw
base update.
GitHub supports only exact reuse and top append in place. Insertion, reorder, removal, or a member target-branch change requires separate authorization to recreate the remote Stack. “Update the PRs” is not reshape authorization. After the user approves a stated final PR order and target-branch chain, read and follow Native Stack reshape. It journals local and remote state, checks for concurrent drift immediately before unstacking, and fails closed on partial writes.
Never use jjpr merge or jjpr watch for native members; jjpr 0.39.1 refuses
them intentionally. Native landing has separate policy, scope, asynchronous
settlement, and JJ reconciliation requirements. Resolve the intended landing
scope, then read and follow Native Stack landing
in full. It handles approval/CI parity with jjpr, merge-method selection,
partial-merge number ambiguity, survivor restacking, and final verification.
Deploys persops configurations to aglaea and amalthea. Use when asked to build, apply, switch, or deploy persops locally or through an Amp runner.
Add or update agent skills in ~/p/persops, including vendoring upstream skills into modules/ai/skills, choosing the right propagation profile (`all`, `coding`, `claw`, `codex`), updating metadata, and applying local+remote Nix switches. Use when the user asks to add a skill, install a skill, update a skill, make a coding skill, make a Codex-only skill, or make a claw/openclaw/clawdbot-only skill in persops.
Install and configure the anti-slop Oxlint plugin in a local TypeScript or JavaScript repository. Use whenever a user asks to add anti-slop lint rules, copy the anti-slop plugin, configure opinionated Oxlint rules, or migrate an existing local anti-slop setup.