# Gh Tendr

> Run an asynchronous review-and-implementation loop with the user via GitHub Issues — migrate in-repo decision docs to issues, monitor for new issue comments on a polling interval, and apply directed changes (edits, implementations, new decision docs, closures) automatically. Triggered when the user says "let's run gh-tendr" or "let's do issue-driven review" or "monitor my GitHub issues" or descri…

- **Type:** Skill
- **Install:** `agentstack add skill-bobby-gray-gh-tendr-gh-tendr`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Bobby-Gray](https://agentstack.voostack.com/s/bobby-gray)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Bobby-Gray](https://github.com/Bobby-Gray)
- **Source:** https://github.com/Bobby-Gray/gh-tendr

## Install

```sh
agentstack add skill-bobby-gray-gh-tendr-gh-tendr
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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

- `gh` CLI authenticated (`gh auth status` returns 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)

1. **Verify gh auth.** If the token is stale, ask the user to run `gh auth login` in their prompt. Don't try to recover automatically.
2. **Create the standard label set.** The kind labels below are sensible defaults; users can extend or rename via the `LABEL_PREFIX` parameter (e.g. `proposal:` or `rfc:`) and by adding their own project-specific kinds.

   **Kind labels (decision categories):**
   - `decision:design` — architecture / UX / API decision required
   - `decision:policy` — governance / legal / compliance decision required
   - `decision:strategy` — business / market / IP / patent strategy decision
   - `decision:security` — security-relevant decision required

   **Process labels (workflow state):**
   - `awaiting-review` — needs operator eyes
   - `awaiting-implementation` — decision made, ready to build
   - `blocked-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.
3. **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:142` or `ROADMAP.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.json` file 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 edit `docs/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.

4. **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:

```bash
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 `gh` returns 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-review` again 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-review` issues (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/name` of the target private repo
- `INTERVAL` — 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 to `decision:` but could be `proposal:` or `rfc:` 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](https://github.com/Bobby-Gray)
- **Source:** [Bobby-Gray/gh-tendr](https://github.com/Bobby-Gray/gh-tendr)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-bobby-gray-gh-tendr-gh-tendr
- Seller: https://agentstack.voostack.com/s/bobby-gray
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
