Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save danielabar/87730357992409e51384cc41bdc0e07a to your computer and use it in GitHub Desktop.

Select an option

Save danielabar/87730357992409e51384cc41bdc0e07a to your computer and use it in GitHub Desktop.
Thoughtbot Rails Audit → GitHub Backlog: Agent Playbook

Thoughtbot Rails Audit → GitHub Backlog: Agent Playbook

Companion artefact to the post "Auditing a Rails Side Project with the thoughtbot Audit Skill."

This file is written for a coding agent (Claude Code, etc.) to act on. The intended workflow:

  1. Run /rails-audit-thoughtbot on your Rails project so you have a RAILS_AUDIT_REPORT.md under scratch/rails-audit/.

  2. Save this file into your project as scratch/rails-audit/AGENT_PLAYBOOK.md.

  3. In a Claude Code session, hand it over with one line:

    read scratch/rails-audit/AGENT_PLAYBOOK.md and execute it

The agent will do the rest. Skim the sections below if you want to know what you're authorising before you do.


Agent instructions

You are turning the findings in scratch/rails-audit/RAILS_AUDIT_REPORT.md into a labelled GitHub backlog. Work in this order. Do not skip ahead; each step assumes the previous one's artefacts exist.

Step 0 — Prerequisites

  • Confirm scratch/rails-audit/RAILS_AUDIT_REPORT.md exists. If not, stop and ask the human to run /rails-audit-thoughtbot first.
  • Confirm gh auth status succeeds. If not, stop and ask the human to run gh auth login.
  • Read the report end-to-end before drafting anything. Count the findings; you will reference the count later.

Step 1 — Draft one markdown file per finding

For each finding in the report, create a file at scratch/rails-audit/issues/<short-kebab-slug>.md using the Issue file template below. Fill in every section. Keep titles short and imperative (Add trigram index on visits.url, not There is a missing index on the visits table).

Use the report's own severity/category as the source of truth. If the report doesn't assign a severity, pick one and note your reasoning in the issue body.

Do not push anything to GitHub yet. Iterating on local files is much cheaper than editing live issues.

Step 2 — Propose a label scheme, then create the labels

Before creating labels, run gh label list and read the project's existing labels. The Default label scheme below is a starting point — adapt it:

  • If the project already has equivalents (e.g. priority/high instead of severity: high), use the existing names and skip creating duplicates.
  • If a proposed area label has no issues that would carry it, drop it.
  • If the audit surfaces a category not covered (e.g. lots of accessibility findings), propose an extra area label and explain why.

Write your final proposal to scratch/rails-audit/github-issue-new-labels.md as a table with name | hex | description, then ask the human to confirm before creating anything destructive.

Once confirmed, create the labels with gh label create "<name>" --color <hex> --description "<desc>". Add --force only if the human explicitly asks to overwrite existing labels.

Step 3 — Apply labels to the draft files

Edit every file in scratch/rails-audit/issues/. Add (or update) a **Labels**: line in the header so each issue carries:

  • Exactly one severity label.
  • One or more area labels.
  • The audit (or equivalent origin) label.
  • Any existing project labels that fit (chore, enhancement, documentation, etc.).

The **Labels**: line is what Step 4 parses, so keep the format exactly: backtick-quoted, comma-separated, on a single line.

Step 4 — Push the issues to GitHub

For each file in scratch/rails-audit/issues/:

  1. Title comes from line 1 (strip the leading # ).
  2. Labels come from the **Labels**: line (strip backticks, keep the comma-separated list).
  3. Body is the full file contents.

Before running any gh issue create calls, print a dry-run summary of titles + labels for every file and ask the human to confirm. Then create the issues:

gh issue create --title "<title>" --label "<label1,label2,...>" --body-file "<path>"

After pushing, report back: how many issues were created, link to the filtered list (gh issue list --label audit --web), and any files that failed.

Step 5 — Verify

  • Run gh issue list --label audit --state open | wc -l and confirm the count matches the number of findings drafted in Step 1.
  • Spot-check one issue in the browser. Confirm severity colour, label set, and the provenance callout at the bottom all render correctly.

Issue file template

Use this verbatim shape for each file in scratch/rails-audit/issues/. Every section is required; if a section genuinely has nothing to say, write one sentence explaining why rather than deleting the heading.

# <ID>: <short imperative title>

**Severity**: <High | Medium | Low>
**Category**: <Testing | Security | Models | Controllers | Code Design | Views | Database & Performance | ...>
**Labels**: `severity: <high|medium|low>`, `<area-label>`, `audit`

## Problem

What's broken or smelly. Be concrete — quote the offending code, name the file path.

## Why We're Addressing It

The motivation in plain language. What goes wrong if we don't fix it? Who feels the pain, and when?

## Expected Result

What "done" looks like. One or two sentences describing the end state — not the steps to get there.

## How to Verify

A numbered checklist a future agent can follow without re-reading the audit.

1. Run `bin/rspec` — all existing tests still pass.
2. <Run the command / open the file / inspect the output that proves the change took effect>.
3. <Any DB / console / curl check that confirms behaviour at runtime>.

## Implementation Notes

Example code, migration snippets, gotchas. Anything that would have taken 10 minutes to figure out the first time.

```ruby
# illustrative snippet

Note

This issue was identified by the Rails Audit skill, a code audit tool based on thoughtbot best practices.


Why this shape:

- **Problem / Why** separates *what's wrong* from *why we care* — useful when triaging weeks later.
- **Expected Result / How to Verify** is the contract a future agent needs to close the issue without re-reading the audit.
- **Implementation Notes** captures the audit's example code so it survives even if the report is archived.
- The provenance callout at the bottom is non-negotiable — it tells future readers (human or agent) where the issue came from.

---

## Default label scheme

Eight labels across three groups. Adapt freely (see Step 2).

### Severity (one per issue)

| Label | Hex | Description |
|---|---|---|
| `severity: high` | `#dc2626` | Needs attention before next production push |
| `severity: medium` | `#d97706` | Address this sprint |
| `severity: low` | `#16a34a` | Technical debt, schedule when convenient |

### Area (one or more per issue)

| Label | Hex | Description |
|---|---|---|
| `security` | `#f97316` | Security vulnerabilities and hardening |
| `performance` | `#0ea5e9` | Database indexes and runtime performance |
| `testing` | `#7c3aed` | Test coverage and spec quality |
| `code-quality` | `#db2777` | Code smells, duplication, readability |

### Origin (one, on every audit issue)

| Label | Hex | Description |
|---|---|---|
| `audit` | `#65a30d` | Surfaced by an automated Rails audit |

---

## Stop conditions

Stop and ask the human before proceeding if any of these are true:

- The report has more than ~50 findings. Confirm scope before drafting that many files.
- `gh auth status` shows a different account than the project's repo owner.
- The repo already has audit-style issues open (search by `label:audit` or similar). Don't double-file.
- Any `gh` command fails with a permission error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment