Search guides, workflows, and reference pages.

Docs/tools

github-rollup

Capability: contract:tracker

Kind: implementation

Vendor: GitHub

Append to (or create) the status-rollup comment on a GitHub issue without bringing the rollup body into agent context.

Prerequisites

  • Runtime: Python 3.11+ run via uv (uv run --directory tools/github-rollup github-rollup …); stdlib-only, no third-party dependencies.
  • CLIs: uv; gh — the script shells out to it for all GitHub access (the default @user comes from gh api user).
  • Credentials / auth: an authenticated gh session (gh auth status must pass) — the comment read / append / PATCH all go through gh.
  • Network: api.github.com via gh.

Configuration

This helper has no persistent config file of its own. Callers pass the target issue from <project-config>/project.md → tracker_repo; the status-rollup comment format is the GitHub tracker convention documented in tools/github/status-rollup.md and reused by security lifecycle skills.

Why

Every skill that updates a <tracker> issue (import receipt, sync passes, CVE allocation, dedupe, fix-PR announcements) folds its status update into one rollup comment per tracker. The existing recipe in tools/github/status-rollup.md walks the agent through: fetch the comment, concatenate <old body> + ruler + new entry, PATCH the comment. That loops the full rollup body — which grows monotonically and is the single largest comment on a long-running tracker — through agent context every sync pass.

This tool does the read / append / PATCH in a subprocess. Only a one-line confirmation lands on the agent’s stderr. The body never crosses the boundary. append and amend-latest print the rollup comment’s URL on stdout, so a caller can link to it without reading the rollup.

Invocation

uv run --directory tools/github-rollup github-rollup <subcommand> ...

Under the secure agent setup this CLI’s gh runs sandboxed and fails, so skills call the same procedures through vetted-ops instead: vetted-op-tracker --caller <skill> rollup-append <N> "<action>" <scratch>/entry.md, rollup-amend-latest <N> "<action>" <scratch>/entry.md, and rollup-fold <N> <comment-id> "<action>". The uv CLI remains for use outside the sandbox.

append <issue> --action "<label>" ...

Append a new entry to the rollup comment on <issue>. Creates the rollup if none exists. Required: --action <label> (the right-hand field of the entry’s summary line). Body comes from either --entry-body "<text>" or --entry-body-file <path> (- reads stdin).

Optional flags:

  • --user @handle — override the summary’s @user field (default: the authenticated gh user from gh api user).
  • --now <ISO8601> — override the date used in the summary (default: real now). Useful for deterministic replay tests.
  • --dry-run — print the decision (create vs append) without writing.

A new rollup’s marker line names the tracker repository (<!-- <repo-name> status rollup v1 — … -->); an existing rollup is found by any <!-- <name> status rollup v<N> marker.

amend-latest <issue> --action "<label>" ...

Replace the body of the most recent entry, keeping its date and user. Use it when a later step of the same pass has to fill in a value the entry already mentions (for example a draft id). Refuses with exit 4 when the latest entry’s action is not <label>, so an entry someone else appended in the meantime is never overwritten. Body from --entry-body or --entry-body-file; --dry-run supported.

fold <issue> --comment-id <id> --action "<label>"

Fold one legacy bot comment into the rollup: the entry takes the legacy comment’s own date and author, every line is left-trimmed, and the legacy comment is deleted only after the append succeeded. Refuses (exit 4) when the comment is the rollup itself. Which comments are foldable, and the action label to use, is the caller’s decision — see status-rollup.md. --dry-run supported.

list <issue>

Print every entry’s summary line in order (or --json for a machine-readable array of {date, user, action}). Exit 3 if the issue has no rollup yet.

latest <issue>

Print just the body of the most recent entry. Useful for “what did the last sync do?” in a follow-up script. Exit 3 if the rollup or entries are missing.

Failure modes

Exit Meaning
0 Success (or --dry-run planned).
2 CLI argument error (mutually-exclusive flags, missing required).
3 Issue has no rollup yet, or rollup has no entries (for latest / amend-latest).
4 Refused: amend-latest action mismatch, or fold pointed at the rollup itself.
other gh returned non-zero; the underlying stderr is forwarded.
Suggest a change