Install
$ agentstack add skill-bobby-gray-gh-tendr-gh-tendr ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
gh-tendr — GitHub Issue-Driven Review
A workflow for asynchronous design review and implementation between the user and Claude. The user reviews decisions / proposals via the GitHub Issues UI and leaves comments. Claude polls for new comments on an interval, applies directed changes, posts status replies, and closes issues when work is done.
When to invoke
Trigger when the user says some variant of:
- "Let's run gh-tendr against ``"
- "Let's do issue-driven review"
- "Move the decision docs to issues and monitor them"
- "I'll comment on issues from work"
- "Set up the issue queue for the design docs"
The user has already authorized Claude to act autonomously on directed comments. Don't invoke if the user wants synchronous back-and-forth — that's normal interactive work.
Prerequisites
ghCLI authenticated (gh auth statusreturns OK)- The repo exists and you can write issues to it
- The decision documents (or other reviewable artifacts) live in the repo at known paths
- The repo MUST be private. This skill is only safe against private repos — issue access controls are coarser than file access, and we routinely write security review notes, threat models, and unannounced product details into issue bodies. Verify visibility before any setup work:
``bash gh repo view "$REPO" --json visibility --jq .visibility # Must return "PRIVATE". If "PUBLIC" or "INTERNAL", refuse to proceed. ``
If the repo is public, halt the skill, tell the user the constraint, and stop. Never offer to switch the repo to private — visibility changes have legal/compliance implications (DMCA notices, contributor license assumptions, archive snapshots) that aren't mine to reverse. If the user wants to move review work to a private repo, that's a manual operator decision; instruct them to make the change in the GitHub UI themselves and re-invoke the skill afterward.
The loop
Step 1 — Setup (one-time)
- Verify gh auth. If the token is stale, ask the user to run
gh auth loginin their prompt. Don't try to recover automatically. - Create the standard label set. The kind labels below are sensible defaults; users can extend or rename via the
LABEL_PREFIXparameter (e.g.proposal:orrfc:) and by adding their own project-specific kinds.
Kind labels (decision categories):
decision:design— architecture / UX / API decision requireddecision:policy— governance / legal / compliance decision requireddecision:strategy— business / market / IP / patent strategy decisiondecision:security— security-relevant decision required
Process labels (workflow state):
awaiting-review— needs operator eyesawaiting-implementation— decision made, ready to buildblocked-on-operator— explicit human input required
Use gh label create with --force for idempotency. Skip kind labels that don't apply to the project; add new ones (e.g. decision:performance, decision:data-model) as the workflow needs them.
- For each decision doc, create one issue. The body MUST be richly self-contained — last review-pass found that bare-minimum bodies (1-line summary + link) were cumbersome to triage from the GH UI alone, especially for items the user wanted to compare against the larger backlog. Required structure:
```markdown ## Summary 2–4 sentences describing the feature/fix in concrete terms. State what changes about the user/operator/system experience after this ships. No "see the doc" — actually summarize.
## Why now 1–2 sentences on the trigger: what surfaced this (security review, user feedback, dependency change, regulatory requirement). Cite the source doc by name and date.
## Concrete proposal The plan in 3–6 bullets. File paths, schemas, function names, env vars. "Add users.foo column" not "track foo somewhere." The reader should be able to estimate the change without opening any other file.
## Open decisions The actual asks — bulleted, each phrased as a question with a recommended answer:
- Should X be Y or Z? (Recommend Y because …)
- Default value for the new env var? (Recommend "off" so existing
deploys keep their current behavior)
## Effort + priority Restate the size estimate (S/M/L/XL) and priority tag (P0/P1/…) from the source doc. Repeating these in the issue body lets the user sort by glance without cross-referencing.
## Source
- Backlog row:
:(e.g.BACKLOG.md:142orROADMAP.md#milestone-2) - Decision doc (if separate):
/.md - Permanent link to the doc on the default branch
```
- Title: short feature name with a stable prefix that maps to the source doc/section. Examples:
[backlog/security] Rate limit signup endpoint,[admin/audit #6] Cron health dashboard,[rfc/0007] Multi-tenant data partitioning. The prefix lets the user see which family of work each issue belongs to without opening it. - Labels: apply both the kind label (
decision:design, etc.) AND a source label that mirrors the prefix (source:backlog,source:admin-audit,source:rfc, etc). Source labels help filter the backlog later. - Track the issue→doc mapping in a
.gh-review-state.jsonfile at the repo root (issue number ↔ source doc/section) so the monitor can resolve "which doc does this issue belong to" on every comment. The file is load-bearing for the polling loop — without it, a comment posted to issue #42 has no way to know whether to editdocs/decisions/0007.md,BACKLOG.md#rate-limit, or something else.
Minimum schema (see [examples/state-file.example.json](examples/state-file.example.json) for a fully-populated reference):
``jsonc { "repo": "owner/name", "issues": { "": { "doc": "/.md | ", "section": "", "title_prefix": "[backlog/security]", "kind_label": "decision:design", "source_label": "source:backlog", "created_at": "2026-05-13T..." } }, "processed_comment_ids": [/* every comment.id you've acted on */], "last_setup_at": "2026-05-13T..." } ``
processed_comment_ids is the idempotency anchor — checked on every poll so a re-armed monitor or replayed since=... query doesn't re-act on the same comment.
- Post a single explanatory comment on each issue: "Comment on this issue with edits / questions / 'please implement' / 'close'. The full doc is at ; this issue body summarizes. New decisions you propose in comments will spawn their own issues. I'll respond on the next polling cycle."
Step 2 — Polling loop
Arm a Monitor script that polls for new comments since the last poll. The script structure:
LAST_SEEN_FILE=/tmp/gh-issue-poll-${REPO//\//_}.last
LAST=$(cat "$LAST_SEEN_FILE" 2>/dev/null || date -u +%Y-%m-%dT%H:%M:%SZ)
while true; do
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
gh api -X GET "repos/${REPO}/issues/comments" -f since="$LAST" --paginate --jq '.[] | "ISSUE_COMMENT|\(.issue_url|split("/issues/")[1])|\(.id)|\(.user.login)|\(.created_at)|\(.body | gsub("\n"; "⏎")[0:300])"' 2>/dev/null || true
echo "$NOW" > "$LAST_SEEN_FILE"
LAST="$NOW"
sleep ${INTERVAL:-240}
done
Critical: interval respects the prompt cache TTL (5 min). Pick from one of three zones:
| INTERVAL | Behavior | When to use | |---|---|---| | 60–270s (under 5 min) | Cache stays warm; cheap + fast per poll | Active review session | | 300–540s (5–9 min) | Worst of both — cache misses without amortizing | Avoid | | 1200–1800s (20–30 min) | One cache miss amortized over a long wait | Idle / backgrounded / overnight |
Default to 240s during active review; bump to 1200s when the user signals stepping away ("back in a few hours") and 1800s for overnight. See docs/monitor-script.md for re-arm + rate-limit handling details.
Each emitted line is one new comment, parseable on the | delimiter.
Step 3 — React to a new comment
When a notification fires, classify the comment intent:
| Comment kind | Response | |---|---| | Question / clarification | Reply in the issue, no code change | | "Please implement" / "ship this" / "yes go ahead" | Build per the doc + commit + push + post status comment ("shipped in `, here's what's in it") + close issue if work is fully done | | "Update the doc to X" or edits to design | Apply doc change + commit + push + post comment with summary | | "Add Y to backlog" / "this should be done eventually" | Update ` + commit + post comment | | New decision proposed in a comment | Write new decision doc + create new issue + post comment linking to both | | "Close this" / "we're not doing this" | Close issue + post acknowledgment + capture in backlog if relevant | | Anything destructive / hard-to-reverse | Comment back asking for confirmation rather than acting |
Rule of thumb: if you're not 75%+ sure what the user wants, post a clarification comment instead of acting.
Step 4 — Status comments
When you DO act, the status comment template:
✅ Done in ``.
What changed:
-
Pushed to `main`. Closing this — reopen if more work needed.
When you ask for confirmation:
🤔 Want to confirm before I act:
- I'd by
- Specifically that means
Reply with "yes" / "go ahead" or refine the request.
When you create a new issue from a comment:
📑 Spun up a new decision doc + issue for this: #NN
The doc is at `/.md`. Continue the discussion there.
Step 5 — Things you will NOT do autonomously
- File legal documents on the operator's behalf (patents, trademark filings, contracts) — require explicit confirmation each time, plus a paper trail
- Push to any repo other than the configured
REPO git push --force,git reset --hard, delete branches- Merge PRs without review
- Modify CI / GitHub Actions configuration
- Delete issues (closing is fine; deleting is not)
- Spend past the project's daily LLM budget (if configured)
- Destructive DB operations (drop tables, migration rollbacks)
- Add or remove repo collaborators
- Change repo visibility (public ↔ private — has legal/compliance implications)
If a comment requests one of these, respond with the confirmation template instead of acting.
Step 6 — Loop hygiene
- Re-arm the Monitor when it times out (default monitor TTL is 1 hour; max 1 hour). Polling for a full workday means several re-arms.
- Track which comment IDs you've already processed so a re-armed monitor doesn't re-act on old comments. Persist in a small file or in-memory map keyed by comment ID.
- If
ghreturns rate-limit errors, back off (sleep 5x normal interval) and post a status comment on the most recent active issue noting the delay. - If the user's last comment was a question and you replied, mark the issue as
awaiting-reviewagain so you don't keep acting until they confirm.
Step 7 — End-of-day handoff
When the user signals end-of-day ("I'm logging off", "we're done for tonight"), summarize:
- Issues touched today (count + closed count)
- Commits pushed
- Outstanding
awaiting-reviewissues (their numbers + one-line each) - Stop the monitor explicitly via TaskStop
Adapting to other repos / projects
The skill is repo-agnostic. The setup parameters:
REPO—owner/nameof the target private repoINTERVAL— polling interval in seconds (240 / 1200 / 1800)DOCS_DIR— repo-relative path to the artifacts being reviewed (default:docs/decisions/)BACKLOG_FILE— repo-relative path to the backlog document (default:BACKLOG.md)LABEL_PREFIX— defaults todecision:but could beproposal:orrfc:for other use cases
The pattern works for any artifact-review flow: design docs, RFCs, ADRs, architectural proposals.
Optional companion skills
Two skills compose well with gh-tendr but neither is required. The decision tree:
| Question | If yes → use | If no → | |---|---|---| | Does the user want a single "please implement" comment to spawn a long-running build session (rather than inline edits)? | unattended-dev — gh-tendr delegates to it as a sub-protocol on "implement"/"ship" comments | gh-tendr implements inline per the comment's directives | | Are the review artifacts (decision docs / RFCs / proposals) produced by another structured workflow upstream? | product-research-flow — that skill produces docs; gh-tendr mirrors them to issues | The user brings existing docs/RFCs/proposals; gh-tendr is the entry point |
Full pipeline (all three): product-research-flow produces the docs → gh-tendr mirrors them to issues → user reviews via the GitHub UI → gh-tendr applies directed changes, delegating implementation work to unattended-dev.
Standalone (gh-tendr only): User writes (or has Claude write) decision docs in a normal session, then invokes gh-tendr to set up the issue queue. The review/implementation loop works identically.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Bobby-Gray
- Source: Bobby-Gray/gh-tendr
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.