Post Draft Review
agent-substrate/substrate
Posts pull request review findings as GitHub draft (pending) inline comments for a human to edit and submit, instead of publishing them straight to the PR author.
Repost GitHub review content (Copilot bot reviews, human-reviewer threads, etc.) from a closed public PR onto its GHSA temporary-private-fork (TPF) PR, anchored to the source's originalcommitid at…
$ npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install BoldGrid/w3-total-cache repost-pr-reviews-to-tpf --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/BoldGrid/w3-total-cache.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/repost-pr-reviews-to-tpf .claude/skills/repost-pr-reviews-to-tpf && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "repost-pr-reviews-to-tpf" agent skill from https://github.com/BoldGrid/w3-total-cache/tree/master/.claude/skills/repost-pr-reviews-to-tpf into .claude/skills/repost-pr-reviews-to-tpf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "repost-pr-reviews-to-tpf", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/BoldGrid/w3-total-cache/tree/master/.claude/skills/repost-pr-reviews-to-tpfType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install BoldGrid/w3-total-cache repost-pr-reviews-to-tpf --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/BoldGrid/w3-total-cache.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/repost-pr-reviews-to-tpf .agents/skills/repost-pr-reviews-to-tpf && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "repost-pr-reviews-to-tpf" agent skill from https://github.com/BoldGrid/w3-total-cache/tree/master/.claude/skills/repost-pr-reviews-to-tpf into .agents/skills/repost-pr-reviews-to-tpf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "repost-pr-reviews-to-tpf", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install BoldGrid/w3-total-cache repost-pr-reviews-to-tpf --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/BoldGrid/w3-total-cache.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/repost-pr-reviews-to-tpf .cursor/skills/repost-pr-reviews-to-tpf && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "repost-pr-reviews-to-tpf" agent skill from https://github.com/BoldGrid/w3-total-cache/tree/master/.claude/skills/repost-pr-reviews-to-tpf into .cursor/skills/repost-pr-reviews-to-tpf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "repost-pr-reviews-to-tpf", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/BoldGrid/w3-total-cache.git --path .claude/skills/repost-pr-reviews-to-tpf--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install BoldGrid/w3-total-cache repost-pr-reviews-to-tpf --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/BoldGrid/w3-total-cache.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/repost-pr-reviews-to-tpf .gemini/skills/repost-pr-reviews-to-tpf && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "repost-pr-reviews-to-tpf" agent skill from https://github.com/BoldGrid/w3-total-cache/tree/master/.claude/skills/repost-pr-reviews-to-tpf into .gemini/skills/repost-pr-reviews-to-tpf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "repost-pr-reviews-to-tpf", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install BoldGrid/w3-total-cache repost-pr-reviews-to-tpfInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/BoldGrid/w3-total-cache.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/repost-pr-reviews-to-tpf .github/skills/repost-pr-reviews-to-tpf && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "repost-pr-reviews-to-tpf" agent skill from https://github.com/BoldGrid/w3-total-cache/tree/master/.claude/skills/repost-pr-reviews-to-tpf into .github/skills/repost-pr-reviews-to-tpf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "repost-pr-reviews-to-tpf", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install BoldGrid/w3-total-cache repost-pr-reviews-to-tpf --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/BoldGrid/w3-total-cache.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/repost-pr-reviews-to-tpf .opencode/skills/repost-pr-reviews-to-tpf && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "repost-pr-reviews-to-tpf" agent skill from https://github.com/BoldGrid/w3-total-cache/tree/master/.claude/skills/repost-pr-reviews-to-tpf into .opencode/skills/repost-pr-reviews-to-tpf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "repost-pr-reviews-to-tpf", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
repost-pr-reviews-to-tpfRepost GitHub review content (Copilot bot reviews, human-reviewer threads, etc.) from a closed public PR onto its GHSA temporary-private-fork (TPF) PR, anchored to the source's originalcommitid at…
Repost PR Reviews To Tpf is an agent skill from BoldGrid/w3-total-cache. Repost GitHub review content (Copilot bot reviews, human-reviewer threads, etc.) from a closed public PR onto its GHSA temporary-private-fork (TPF) PR, anchored to the source's originalcommitid at originalline so each comment renders as a historical outdated comment matching the original review UX exactly. Use after move-pr-to-private-ghsa to restore reviewer-thread continuity on the TPF, since reviews/inline comments do not migrate with the commits. Encodes the pull-via-gh api → group-by-review →…
Its SKILL.md is about 5.9k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development, covering Pull requests and Technical documentation. It works with GitHub. The licence is GPL-2.0.
7 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 99a8bbc. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
ghjqpython3From the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
github.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
JIRA_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Repost PR Reviews To Tpf loads about 5.9k tokens when it runs. Until then it costs about 239 tokens; SKILL.md has 1,908 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from BoldGrid/w3-total-cache at commit 99a8bbc, republished under its GPL-2.0 licence (© BoldGrid). 1,908 words, ~5,948 tokens.
.claude/skills/repost-pr-reviews-to-tpf/SKILL.md (or your agent's skills folder).Restore reviewer-thread continuity on a GHSA temporary private fork (TPF) PR by replaying the closed public PR's review history. Each source review becomes one repost-review on the TPF, with its inline comments anchored to the original commits at the original line numbers — GitHub then renders them as "outdated on commit X" exactly the way they appeared on the original public PR.
This skill is the natural follow-up to move-pr-to-private-ghsa. That skill moves the code into the TPF; this one restores the review context that was deliberately left behind on the public PR.
Tested against BoldGrid/w3-total-cache#1313 → BoldGrid/w3-total-cache-ghsa-rgpr-5m2g-gvh2#1 on 2026-05-20: 2 Copilot reviews, 16 inline comments, anchored to a2b94e5d (round 1) and 498aa3e8 (round 2). See "Caveats to surface every time" for the line-drift / event-state / attribution issues this skill exists to avoid re-encountering.
move-pr-to-private-ghsa (the source PR is closed; its branch may be deleted).move-pr-to-private-ghsa (the TPF starts as a fork of the public repo with all branches), so all original_commit_id SHAs should still be in the TPF chain.pr-content-to-jira), but you want operational continuity in the TPF reviewer UI on top of the audit-trail copy.Do not use this to manufacture review consensus — the reposts will be authored by you, not the original reviewer. Attribution lives in an inline preface on every body so the audit trail is grep-able, but anyone scanning the reviewer column in the timeline sees your login. The flip side: never use APPROVE or REQUEST_CHANGES events on the repost; that would inject your account into the TPF's review state on someone else's behalf. Always COMMENT.
gh CLI logged in. Two distinct permission surfaces:repo scope on the public source repo (to read closed PR reviews + comments — public read is enough, but ratelimit-friendliness wants auth).repo (or pull-requests:write via GitHub App) on the TPF repo. Repo-admin on the public repo usually carries through to the TPF; verify:gh api repos/{TPF-OWNER}/{TPF-REPO} --jq '{full_name, permissions}'gh api).jq available locally..cursor/working/ directory (gitignored).{owner}/{repo}#{n}, the TPF PR's {owner}/{repo}#{n}, and the parent Jira key (used in attribution prefaces so reposts are bidirectionally linkable to the audit trail).Per AGENTS.md "Working Files", every scratch file follows {KEY}-{REPO}-{PR}-{role}.{ext}. The "primary" PR for this skill is the TPF PR you're posting into — the source PR is referenced from the filename role, not the keying triple. {REPO} is the lowercase slug (right-hand half of org/repo); GHSA TPFs follow w3-total-cache-ghsa-… (ghsa lowercase). Capture the prefix once in Phase 1 and reuse:
KEY=ENG7-2908 # Jira ticket
TPF_REPO=BoldGrid/w3-total-cache-ghsa-rgpr-5m2g-gvh2
TPF_PR=1 # TPF PR number (almost always 1)
TPF_SLUG="${TPF_REPO#*/}" # → "w3-total-cache-ghsa-rgpr-5m2g-gvh2"
PFX="${KEY}-${TPF_SLUG}-${TPF_PR}" # canonical scratch-file prefixEvery file path below expands as .cursor/working/${PFX}-{role}.{ext}:
${PFX}-source-pr-${SRC_PR}-reviews.json — source review summaries (/reviews, filtered by author regex)${PFX}-source-pr-${SRC_PR}-comments.json — source inline comments (/comments, filtered by author regex)${PFX}-tpf-chain.json — TPF PR commit list (Phase 2 reachability check)${PFX}-repost-reviews.py — the reposter script${PFX}-repost-{round}-payload.json — POST body for /pulls/{n}/reviews (one per source review)${PFX}-repost-{round}-response.json — API response for verify${PFX}-verify-reposted.json — Phase 5 verification dumpNever write to /tmp/ or anywhere outside the project tree.
Capture from the user (or ask):
{SRC-OWNER}, {SRC-REPO}, {SRC-PR}.{TPF-OWNER}, {TPF-REPO}, {TPF-PR}.ENG7-2908) — used in attribution prefaces.[Cc]opilot for Copilot bot reviews, a specific human login, or . to include all reviewers. Be explicit; never just default to "all" without confirming.Verify GitHub permissions on the TPF:
gh api repos/{TPF-OWNER}/{TPF-REPO} --jq '{full_name, permissions, default_branch}'
# expect permissions.push: true and permissions.admin: true (or maintain: true)Two calls, both filtered by the same author regex. The /reviews endpoint gives you the review-level data (state, body, commit_id, submitted_at); /comments gives you the per-inline-comment data (path, original_line, original_commit_id, pull_request_review_id, body, side):
SRC_REPO=BoldGrid/w3-total-cache
SRC_PR=1313
FILTER='[Cc]opilot' # or specific login, etc.
gh api "repos/${SRC_REPO}/pulls/${SRC_PR}/reviews" --paginate \
> .cursor/working/${PFX}-source-pr-${SRC_PR}-reviews-raw.json
jq "[.[] | select(.user.login | test(\"${FILTER}\")) | {id, state, commit_id, submitted_at, body, user_login: .user.login}]" \
.cursor/working/${PFX}-source-pr-${SRC_PR}-reviews-raw.json \
> .cursor/working/${PFX}-source-pr-${SRC_PR}-reviews.json
gh api "repos/${SRC_REPO}/pulls/${SRC_PR}/comments" --paginate \
> .cursor/working/${PFX}-source-pr-${SRC_PR}-comments-raw.json
jq "[.[] | select(.user.login | test(\"${FILTER}\")) | {id, path, line, original_line, original_commit_id, side, pull_request_review_id, body, user_login: .user.login}]" \
.cursor/working/${PFX}-source-pr-${SRC_PR}-comments-raw.json \
> .cursor/working/${PFX}-source-pr-${SRC_PR}-comments.jsonQuick sanity check — comment count grouped by review:
jq '[.[] | {id, review_id: .pull_request_review_id}] | group_by(.review_id) | map({review_id: .[0].review_id, count: length})' \
.cursor/working/${PFX}-source-pr-${SRC_PR}-comments.jsonThe count per review should match the body of the source review (Copilot reviews usually include a "generated N comments" line you can cross-reference).
Inline comments anchored to a commit that's no longer in the TPF PR's chain will be rejected by the API with 422. Verify up front:
gh api "repos/${TPF_REPO}/pulls/${TPF_PR}/commits" --paginate --jq '[.[] | .sha]' \
> .cursor/working/${PFX}-tpf-chain.json
jq -r '[.[] | .original_commit_id] | unique | .[]' \
.cursor/working/${PFX}-source-pr-${SRC_PR}-comments.json \
| while read sha; do
if jq -e --arg sha "$sha" 'index($sha)' \
.cursor/working/${PFX}-tpf-chain.json > /dev/null; then
echo "OK $sha"
else
echo "MISS $sha (will need fallback to PR-level comment)"
fi
doneAny MISS rows need to be handled separately — see "Caveats" #6. Most of the time everything resolves to OK because move-pr-to-private-ghsa preserves the full commit chain.
One payload per source review. For each comment, anchor to original_commit_id + original_line. Attribution wrapper goes on both the review body and each inline comment body, so attribution survives every UI surface (timeline, file-tree review, individual comment permalink).
The template script (write to .cursor/working/${PFX}-repost-reviews.py):
#!/usr/bin/env python3
"""
Repost reviews from {SRC_REPO}#{SRC_PR} onto TPF PR {TPF_REPO}#{TPF_PR}.
Each review is anchored to its source's original_commit_id, with each inline
comment placed on its original_line. GitHub then renders them as historical
outdated comments anchored on those commits, matching the original review UX.
Audit-trail copy of the same content lives on Jira {KEY} (added via
pr-content-to-jira) so this is operational continuity, not the audit trail.
"""
import json
import subprocess
import sys
from pathlib import Path
WORKING = Path("/home/.../.cursor/working")
TPF_REPO = "{TPF-OWNER}/{TPF-REPO}"
TPF_PR = {TPF-PR}
SOURCE_PR_URL = "https://github.com/{SRC-OWNER}/{SRC-REPO}/pull/{SRC-PR}"
JIRA_KEY = "{KEY}"
# Filename prefix per AGENTS.md "Working Files": {KEY}-{REPO-SLUG}-{TPF-PR}-...
# (the TPF PR is the keying PR for this skill; SRC-PR lives in the role part).
PREFIX = f"{JIRA_KEY}-{TPF_REPO.split('/', 1)[1]}-{TPF_PR}"
def load_reviews():
with open(WORKING / f"{PREFIX}-source-pr-{{SRC-PR}}-reviews.json") as fh:
return json.load(fh)
def load_comments():
with open(WORKING / f"{PREFIX}-source-pr-{{SRC-PR}}-comments.json") as fh:
return json.load(fh)
def build_payload(review, comments):
login = review["user_login"]
header = (
f"_Reposted from [{login}] review on {SOURCE_PR_URL} "
f"(review id {review['id']}, submitted {review['submitted_at']}). "
f"Anchored to commit `{review['commit_id'][:10]}` so file/line positions match the original review. "
f"Audit-trail copy also lives on Jira {JIRA_KEY}._\n\n"
f"---\n\n"
)
body = header + (review["body"] or "")
comments_payload = []
for c in comments:
if c["pull_request_review_id"] != review["id"]:
continue
inline_body = (
f"_From {c['user_login']} inline comment on PR #{{SRC-PR}} "
f"(comment id {c['id']}, originally anchored at L{c['original_line']} of `{c['path']}` "
f"at commit `{c['original_commit_id'][:10]}`). Verbatim text below._\n\n"
f"{c['body']}"
)
comments_payload.append({
"path": c["path"],
"line": c["original_line"],
"side": c.get("side") or "RIGHT",
"body": inline_body,
})
return {
"commit_id": review["commit_id"], # the source's original commit
"event": "COMMENT", # ALWAYS COMMENT — never re-use APPROVE / REQUEST_CHANGES
"body": body,
"comments": comments_payload,
}
def post(payload, round_label):
payload_path = WORKING / f"{PREFIX}-repost-{round_label}-payload.json"
payload_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2))
print(f"\n=== Posting {round_label} ===")
print(f" commit_id: {payload['commit_id'][:10]}")
print(f" comments: {len(payload['comments'])}")
result = subprocess.run(
["gh", "api", "--method", "POST",
f"/repos/{TPF_REPO}/pulls/{TPF_PR}/reviews",
"--input", str(payload_path)],
capture_output=True, text=True,
)
if result.returncode != 0:
print("STDERR:", result.stderr)
sys.exit(result.returncode)
response = json.loads(result.stdout) if result.stdout.strip() else {}
(WORKING / f"{PREFIX}-repost-{round_label}-response.json").write_text(
json.dumps(response, ensure_ascii=False, indent=2)
)
print(f" Review ID: {response.get('id')}")
print(f" URL: {response.get('html_url')}")
def main():
reviews = sorted(load_reviews(), key=lambda r: r["submitted_at"])
comments = load_comments()
for i, r in enumerate(reviews, start=1):
post(build_payload(r, comments), f"round{i}")
if __name__ == "__main__":
main()Fill in the curly-brace tokens for the specific run. Keep event: "COMMENT" regardless of the source review's state (see "Caveats" #2).
python3 .cursor/working/${PFX}-repost-reviews.pyExpect one POST per source review, each returning a review id + html_url. Save responses to ${PFX}-repost-{round}-response.json.
If a POST fails with 422:
Pull request review thread line must be part of a diff → the original_line isn't in the original_commit_id's diff against base. Most often a data integrity issue from the source PR (force-push or rebase) rather than the script. Pull the comment out of that review's payload and fall back to a PR-level conversation comment for it (see "Caveats" #6).Pull request review thread commit_oid is not part of the pull request → the original_commit_id isn't in the TPF chain. Same fallback.Pull request comment body is too long → 65536-char ceiling per body; trim the verbatim content or split into multiple comments.Read back the comments on the TPF PR and assert each reposted comment's original_line matches the source. Same script pattern works for both — query, then sort by id, then diff:
gh api "repos/${TPF_REPO}/pulls/${TPF_PR}/comments" --paginate \
--jq "[.[] | select(.body | test(\"Reposted from\\\\b|From ${FILTER} inline comment\")) | {path, original_line, original_commit_id: (.original_commit_id // \"\")[0:10], review_id: .pull_request_review_id}]" \
> .cursor/working/${PFX}-verify-reposted.json
jq '. | length' .cursor/working/${PFX}-verify-reposted.json
# expect: same as total inline-comment count across all source reviewsOptional sanity check: open https://github.com/${TPF_REPO}/pull/${TPF_PR} in a browser, click "Conversation", and confirm the reposted reviews appear in chronological order with their inline comments rendered as outdated against the historical commits.
The Jira back-link comment from move-pr-to-private-ghsa Phase 5b is the place to record that the TPF now has the original review threads as well. Add a short follow-up comment (Jira MCP cannot edit existing comments) referencing the reposted review URLs so future ticket-readers know the operational view of the reviews lives on the TPF, not just the audit-trail view that's in Jira:
## Follow-up to GHSA back-link: source PR reviews reposted on the TPF
For ongoing-review continuity, the original [{login}] reviews from {SOURCE_PR_URL}
have been reposted on the TPF, anchored to the historical commits so file/line
positions match the source review exactly:
- Round 1 ({source review id, source commit_id[:10]}): {tpf-review-1-url}
- Round 2 ({source review id, source commit_id[:10]}): {tpf-review-2-url}
Each comment is attributed to its original author via an inline preface; the
reposts are authored by my account on the TPF.
Audit-trail copy of the same content remains as comment {original-jira-comment-id}
on this ticket — Jira is the durable record; the TPF reposts are the operational
view for active reviewers.Skip this step if there's no Jira ticket in scope.
Anchor to the source's original_commit_id, not the current head. The whole point of the anchored-to-historical-commit approach is to avoid line drift. If you anchor to the current head, GitHub will try to map the line through subsequent diffs, fail on fixed-and-removed code, and either reject the comment or display it at a misleading position. Always use original_commit_id + original_line from the source data.
Always use event: "COMMENT" on the repost, regardless of the source review's state. Re-using APPROVE or REQUEST_CHANGES would put your account in those review states on the TPF on someone else's behalf — wrong attribution and wrong semantics. Even if Copilot's source review was a COMMENTED review (the typical case), keep the explicit COMMENT event hardcoded so a future copy-paste run against a human-reviewer source doesn't accidentally APPROVE the TPF.
Attribution lives in the body preface, not the author column. The repost is authored by your GitHub login. The "Reposted from [{login}] review on {SOURCE_PR_URL}..." preface on the review body and the "From {login} inline comment on PR #{N} (comment id ..., originally anchored at L###...)..." preface on each inline comment are what preserve the original authorship. Make these prefaces grep-able and unambiguous — they're the only attribution surface a reader has.
Reviews/inline comments are PR-scoped, not branch-scoped. Even after move-pr-to-private-ghsa Phase 6 closed the source PR and deleted its branch, /repos/{owner}/{repo}/pulls/{n}/reviews and /comments continue to return historical content indefinitely. Pulling from a closed-deleted PR works exactly the same as from an open one.
side may be null in the source data; default to "RIGHT". GitHub's /comments response sometimes omits side for older comments. The vast majority of review comments anchor to additions (RIGHT). If you have specific knowledge that a source comment was on a deletion, set LEFT; otherwise default to RIGHT.
Unreachable original_commit_id → fall back to PR-level conversation comment. If a source PR was force-pushed or had commits orphaned before the move, an original_commit_id may not be in the TPF chain. The Phase 2 reachability check catches this. For each affected comment, drop it from the review's comments[] payload and post a separate gh pr comment ${TPF_PR} with body text like "From {login} inline comment on PR #{N} (comment id ..., originally anchored at {path} L{N} on a commit no longer in the chain). Verbatim text below.\n\n{body}". The line anchor is lost; the content is preserved.
Body length ceiling: 65536 chars per comment. Most review/inline bodies are well under, but Copilot's "Pull request overview" body with the file-table can approach the ceiling on large PRs. If exceeded, split the body into a primary repost-review with the overview + the first half of comments, and a follow-up PR-level conversation comment with the rest. Don't truncate the verbatim text — that breaks audit traceability.
Re-running the script is non-idempotent. Posting twice creates two reviews and duplicates every inline comment. There's no easy "delete all reposted reviews" undo — gh api -X DELETE /repos/.../pulls/.../comments/{id} works per-comment, but the review wrapper itself stays. Verify the source JSON before running and dry-run by inspecting the payload files first.
GitHub Copilot review content travels in two places: /reviews (review wrapper + body) and /comments (inline anchors). Both must be pulled and rejoined via pull_request_review_id. Don't try to reconstruct from /comments alone — you'll miss the review-level summary body (which for Copilot includes the "Pull request overview" + file-table that contextualizes the inline findings).
The Jira audit-trail copy is the source of truth; the TPF repost is operational continuity. Don't skip preserving content in Jira just because you've also reposted on the TPF. Jira is durable and bidirectionally linkable across the workflow (ticket → public PR → GHSA → TPF). The TPF reposts live or die with the TPF, which itself goes away once the advisory is merged or withdrawn.
Reviewers see the reposts as "outdated" by default. Because every repost is anchored to a historical commit, GitHub renders them with the "Outdated" badge and the "Show outdated" toggle collapsed by default. This is the correct UX — matches how Copilot's original reviews appeared on the closed public PR once subsequent commits landed. Don't try to "fix" this by re-anchoring to head; you'd lose line accuracy.
This skill is downstream of move-pr-to-private-ghsa and (usually) pr-content-to-jira. Run them in that order. Trying to repost while the public PR is still open is technically possible but loses the framing of "continuity restoration" — at that point the comments are still readable on the open public PR and the duplicate on the TPF is just noise.
0. Inputs:
- Source PR: {SRC-OWNER}/{SRC-REPO}#{SRC-PR} (closed; branch may be deleted)
- TPF PR: {TPF-OWNER}/{TPF-REPO}#{TPF-PR}
- Jira ticket key (for attribution prefaces + back-link follow-up)
- Author filter regex (e.g. "[Cc]opilot" or specific reviewer login)
1. Pull source reviews + inline comments via `gh api`, filtered by author regex.
`gh api repos/{SRC}/pulls/{N}/reviews --paginate | jq filter > reviews.json`
`gh api repos/{SRC}/pulls/{N}/comments --paginate | jq filter > comments.json`
Sanity-check inline counts per review match the source review body.
2. Verify each unique `original_commit_id` is still in the TPF chain:
`gh api repos/{TPF}/pulls/{N}/commits --paginate --jq '.[].sha'`
Flag any MISS — those become PR-level conversation comments in Phase 4.
3. Build one payload per source review:
{ commit_id: source.original_commit_id,
event: "COMMENT", # never APPROVE / REQUEST_CHANGES
body: attribution-preface + source.body,
comments: [{path, line: original_line, side: side or "RIGHT",
body: attribution-preface + source.body}, ...] }
4. Post each payload:
`gh api -X POST /repos/{TPF}/pulls/{TPF-N}/reviews --input payload.json`
For any MISS commits from Phase 2: `gh pr comment {TPF-N}` with body referencing
the lost line anchor + verbatim text.
5. Verify:
`gh api repos/{TPF}/pulls/{TPF-N}/comments --paginate` and confirm:
- reposted-comment count matches the sum across source reviews,
- each reposted comment's `original_line` == source's `original_line`,
- each reposted comment's `original_commit_id` is in the TPF chain.
6. Optional: append a follow-up Jira comment on the parent ticket recording
the reposted-review URLs, so the Jira back-link from move-pr-to-private-ghsa
Phase 5b also knows where the operational copies live.
Always run AFTER `move-pr-to-private-ghsa` (so the TPF exists and the source PR
is closed). Pair with `pr-content-to-jira` so the audit-trail copy in Jira and
the operational copy on the TPF are both in place.© BoldGrid, GPL-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/repost-pr-reviews-to-tpf of BoldGrid/w3-total-cache.
Open the folder on GitHubat commit 99a8bbc
Repost PR Reviews To Tpf next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Repost PR Reviews To Tpf this skillBoldGrid/w3-total-cache | 166 | — | ~5.9k | Automated safety check: Pass | GPL-2.0 | |
| Post Draft Reviewagent-substrate/substrate | 4.8k | — | ~2.8k | Automated safety check: Pass | Apache-2.0 | |
| Review Kedro PRkedro-org/kedro | 11k | — | ~2.8k | Automated safety check: Pass | Custom licence | |
| Review PRjavierbrea/eslint-plugin-boundaries | 997 | — | ~2.9k | Automated safety check: Pass | MIT | |
| Human Writingkylesnowschwartz/SimpleClaude | 114 | — | ~3.6k | Automated safety check: Pass | None | |
| Inline PR Commentshyperlane-xyz/hyperlane-explorer | 102 | — | ~1.1k | Automated safety check: Pass | Custom licence |
agent-substrate/substrate
Posts pull request review findings as GitHub draft (pending) inline comments for a human to edit and submit, instead of publishing them straight to the PR author.
kedro-org/kedro
Review a Kedro PR for checklist compliance, architecture, correctness, and clarity.
javierbrea/eslint-plugin-boundaries
Review a GitHub pull request from three perspectives — functional fit against its linked issue, code correctness/quality, and architectural boundaries — then post a single GitHub review: one general…
kylesnowschwartz/SimpleClaude
MUST be used for any request to draft, write, compose, or reword text another person will read, including 'draft a message', 'draft a reply', 'draft a Slack message', 'write an email', 'draft a PR…
hyperlane-xyz/hyperlane-explorer
Post a single consolidated PR review with summary and inline comments.
DataDog/dd-trace-java
Clarify or review Java Javadocs, Javadoc tags, and explanatory code comments for legibility, accuracy, and source alignment.
BoldGrid/w3-total-cache
Maps the W3TCQA AWS test matrix (orchestrator ~/ci, EC2 boxes, /share paths, report artifacts, box naming, log formats).
BoldGrid/w3-total-cache
Add or verify W3 Total Cache release changelog bullets in readme.txt and changelog.txt.
BoldGrid/w3-total-cache
Move an in-progress public GitHub PR for a security fix into a GitHub Security Advisory's temporary private fork (TPF) so the remaining work continues privately.
Works with
Categories
Repost GitHub review content (Copilot bot reviews, human-reviewer threads, etc.) from a closed public PR onto its GHSA temporary-private-fork (TPF) PR, anchored to the source's originalcommitid at…. Repost PR Reviews To Tpf is an agent skill from BoldGrid/w3-total-cache.) from a closed public PR onto its GHSA temporary-private-fork (TPF) PR, anchored to the source's originalcommitid at originalline so each comment renders as a historical outdated comment matching the original review UX exactly.
Repost PR Reviews To Tpf fits situations like: tasks that involve Pull requests; tasks that involve Technical documentation.
Run `npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a claude-code`. Or copy the skill folder (.claude/skills/repost-pr-reviews-to-tpf in BoldGrid/w3-total-cache) into .claude/skills/repost-pr-reviews-to-tpf in your project. Claude Code loads it when a task matches its description.
Run `npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a codex`. Or copy the skill folder (.claude/skills/repost-pr-reviews-to-tpf in BoldGrid/w3-total-cache) into .agents/skills/repost-pr-reviews-to-tpf in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add BoldGrid/w3-total-cache --skill repost-pr-reviews-to-tpf -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/repost-pr-reviews-to-tpf, .gemini/skills/repost-pr-reviews-to-tpf, .github/skills/repost-pr-reviews-to-tpf and .opencode/skills/repost-pr-reviews-to-tpf in your project.
Going by SKILL.md and its folder, Repost PR Reviews To Tpf needs the command-line tools its instructions call (gh, jq and python3) and credentials named JIRA_KEY. Our summary lists: Python 3; A credential in JIRA_KEY.
SKILL.md names 1 domain. In commands or code: github.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Repost PR Reviews To Tpf is published under the GPL-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.9k tokens (SKILL.md is roughly 24k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Repost PR Reviews To Tpf: Post Draft Review (agent-substrate/substrate, 4.8k stars), Review Kedro PR (kedro-org/kedro, 11k stars), Review PR (javierbrea/eslint-plugin-boundaries, 997 stars) and Human Writing (kylesnowschwartz/SimpleClaude, 114 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
BoldGrid (a GitHub organization) maintains it in BoldGrid/w3-total-cache, which has 166 GitHub stars. The repository holds 4 skills in this directory. The repository was last updated on October 6, 2026.
Source: BoldGrid/w3-total-cache on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.