Scripts — GitHub Automation & Issue Management
GitHub Automation & Issue Management
TypeScript and shell scripts powering the GitHub issue lifecycle. Includes duplicate detection, stale issue sweeping, label management, and a restricted GitHub CLI wrapper.
⚙️ Automation🛠️ Issue Lifecycle🔒 Security Wrapper🕑 Cron-Driven
📚 What is this & why does it exist?
The scripts directory contains the automation backbone of the Claude Code project’s GitHub issue management. These 8 scripts handle everything from detecting and closing duplicate issues, to sweeping stale issues after 14 days of inactivity, to posting formatted lifecycle comments that warn users before auto-closure. The restricted gh.sh wrapper ensures that CI/CD pipelines can only execute a whitelisted subset of GitHub CLI commands, preventing accidental or malicious repository mutations.
💡 Real-world analogy
Think of these scripts as the janitorial and security staff for a large office building. The sweep script is the nightly cleaning crew that identifies abandoned desks (stale issues) and eventually clears them out. The duplicate-detection scripts are the mailroom workers who catch when two packages are addressed to the same person. And gh.sh is the security guard at the front desk who only lets through people on the approved visitor list — no matter who asks.
Architecture
flowchart TB
subgraph Triggers["Trigger Sources"]
CRON["⏰ Cron Schedule\n(10am/10pm UTC)"]
EVENT["🔔 GitHub Events\n(issue opened/labeled)"]
MANUAL["👋 Manual Dispatch"]
end
subgraph Engine["Script Engine"]
SWEEP["sweep.ts\n(Main Engine)"]
LIFECYCLE["issue-lifecycle.ts\n(Config & Timers)"]
COMMENT["lifecycle-comment.ts\n(Warning Posts)"]
end
subgraph Duplicates["Duplicate Pipeline"]
DETECT["auto-close-duplicates.ts\n(3-day close)"]
BACKFILL["backfill-duplicate-comments.ts\n(Old issues)"]
POST["comment-on-duplicates.sh\n(Format & Post)"]
end
subgraph Utilities["Utilities"]
LABELS["edit-issue-labels.sh\n(Label CRUD)"]
GH["gh.sh\n(Security Wrapper)"]
end
CRON --> SWEEP
EVENT --> DETECT
EVENT --> COMMENT
MANUAL --> BACKFILL
SWEEP --> LIFECYCLE
SWEEP --> LABELS
DETECT --> POST
BACKFILL --> POST
ENGINE --> GH
LABELS --> GH
POST --> GH
style GH fill:#f85149,stroke:#f85149,color:#fff
style SWEEP fill:#58a6ff,stroke:#58a6ff,color:#fff
Issue Lifecycle Flow
sequenceDiagram
participant User as Issue Author
participant GH as GitHub
participant Triage as Triage Workflow
participant Sweep as sweep.ts
participant LC as lifecycle-comment.ts
participant Close as Auto-Close
User->>GH: Opens new issue
GH->>Triage: issue_opened event
Triage->>GH: Assigns labels (bug/feature/etc.)
Note over Sweep: Runs twice daily (cron)
Sweep->>GH: Query issues inactive >14d
GH-->>Sweep: Stale candidates list
alt Issue has 10+ upvotes
Sweep->>Sweep: Skip (protected)
else Issue is stale
Sweep->>GH: Apply "stale" label
Sweep->>LC: Trigger warning comment
LC->>GH: Post lifecycle warning
LC->>User: "This issue will close in 14d"
end
Note over Sweep: Next sweep cycle
Sweep->>GH: Query stale issues >14d since label
alt Author responded
GH-->>Sweep: Activity detected
Sweep->>GH: Remove "stale" label
else Still inactive
Sweep->>Close: Mark for auto-close
Close->>GH: Close issue
Close->>User: "Closed due to inactivity"
end
Scripts Reference
🛠️ sweep.ts
Main engine — marks stale issues (14d inactive) and auto-closes expired ones. Respects the upvote threshold: issues with 10+ reactions are protected from auto-closure.
- Queries GitHub API for inactive issues
- Applies
stale/autocloselabels - Supports
DRY_RUNmode for testing
⏰ issue-lifecycle.ts
Configuration hub — defines lifecycle label timeouts: invalid (3d), needs-repro (7d), needs-info (7d), stale (14d), autoclose (14d).
- Central source of truth for all timers
- Exported constants used by sweep & comment scripts
💬 lifecycle-comment.ts
Warning system — posts formatted comments when lifecycle labels are applied, giving authors a chance to respond before auto-closure.
- Templates per label type
- Includes countdown and instructions
🗑️ auto-close-duplicates.ts
Duplicate closer — auto-closes issues marked as duplicates after a 3-day grace period.
- Checks
duplicatelabel age - Extracts original issue reference
- Posts closing comment with link
🔄 backfill-duplicate-comments.ts
Backfill tool — triggers the deduplication workflow for older issues that predate the automated pipeline.
- Batch processes historical issues
- Calls
triggerDedupeWorkflow()
💬 comment-on-duplicates.sh
Duplicate commenter — posts a formatted duplicate comment showing up to 3 matching issues with similarity scores.
- Max 3 duplicates per comment
- Includes similarity percentage
🏷️ edit-issue-labels.sh
Label manager — add or remove labels with repository validation. Ensures labels exist before applying.
- Add / remove operations
- Validates repo and label existence
🔒 gh.shSECURITY
Security wrapper — restricted GitHub CLI proxy that only permits whitelisted commands. All CI/CD GitHub API calls route through this guard.
- Whitelist-only command execution
- Blocks destructive operations
- Audit logging of all invocations
Key Functions
| Function | Script | Purpose |
|---|---|---|
githubRequest() | sweep.ts | Authenticated GitHub API call wrapper with rate-limit handling |
markStale() | sweep.ts | Applies stale label and triggers lifecycle comment |
closeExpired() | sweep.ts | Closes issues past the autoclose deadline |
extractDuplicateIssueNumber() | auto-close-duplicates.ts | Parses duplicate reference from issue body/comments |
closeIssueAsDuplicate() | auto-close-duplicates.ts | Closes issue with duplicate reason and cross-reference |
triggerDedupeWorkflow() | backfill-duplicate-comments.ts | Dispatches the deduplication GitHub Actions workflow |
Configuration Reference
| Parameter | Default | Description |
|---|---|---|
STALE_UPVOTE_THRESHOLD | 10 | Issues with this many 👍 reactions are protected from auto-closure |
STALE_DAYS | 14 | Days of inactivity before an issue is marked stale |
AUTOCLOSE_DAYS | 14 | Days after stale label before auto-closing |
INVALID_DAYS | 3 | Days before closing issues labeled invalid |
NEEDS_REPRO_DAYS | 7 | Days to wait for reproduction steps |
NEEDS_INFO_DAYS | 7 | Days to wait for additional info from author |
DUPLICATE_GRACE_DAYS | 3 | Grace period before closing confirmed duplicates |
GITHUB_TOKEN | (required) | GitHub API token for authenticated requests |
DRY_RUN | false | When true, logs actions without executing them |
REPO_OWNER | anthropics | GitHub repository owner |
REPO_NAME | claude-code | GitHub repository name |
Interactions
| Module | Interface | Data Exchanged |
|---|---|---|
| GitHub Actions Workflows | Workflow dispatch / cron triggers | Scripts are invoked by .github/workflows/*.yml |
| GitHub REST API | HTTP requests via gh.sh | Issue queries, label mutations, comment creation |
| Claude Code (AI triage) | Workflow integration | Triage results feed into lifecycle labels |
| Issue authors | Comment notifications | Lifecycle warnings and closure notices |
Directory Map
Source tree for Scripts
scripts/
├── auto-close-duplicates.ts ← Closes duplicate issues after 3d grace
├── backfill-duplicate-comments.ts ← Triggers dedupe for old issues
├── comment-on-duplicates.sh ← Posts formatted duplicate comments (max 3)
├── edit-issue-labels.sh ← Add/remove labels with validation
├── gh.sh ← SECURITY: restricted GitHub CLI wrapper
├── issue-lifecycle.ts ← Lifecycle config & timer constants
├── lifecycle-comment.ts ← Posts warning comments on lifecycle labels
└── sweep.ts ← Main engine: stale marking & auto-close