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.

8
Scripts
5
TypeScript
3
Shell
3
Pipelines

⚙️ 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 / autoclose labels
  • Supports DRY_RUN mode 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 duplicate label 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

FunctionScriptPurpose
githubRequest()sweep.tsAuthenticated GitHub API call wrapper with rate-limit handling
markStale()sweep.tsApplies stale label and triggers lifecycle comment
closeExpired()sweep.tsCloses issues past the autoclose deadline
extractDuplicateIssueNumber()auto-close-duplicates.tsParses duplicate reference from issue body/comments
closeIssueAsDuplicate()auto-close-duplicates.tsCloses issue with duplicate reason and cross-reference
triggerDedupeWorkflow()backfill-duplicate-comments.tsDispatches the deduplication GitHub Actions workflow

Configuration Reference

ParameterDefaultDescription
STALE_UPVOTE_THRESHOLD10Issues with this many 👍 reactions are protected from auto-closure
STALE_DAYS14Days of inactivity before an issue is marked stale
AUTOCLOSE_DAYS14Days after stale label before auto-closing
INVALID_DAYS3Days before closing issues labeled invalid
NEEDS_REPRO_DAYS7Days to wait for reproduction steps
NEEDS_INFO_DAYS7Days to wait for additional info from author
DUPLICATE_GRACE_DAYS3Grace period before closing confirmed duplicates
GITHUB_TOKEN(required)GitHub API token for authenticated requests
DRY_RUNfalseWhen true, logs actions without executing them
REPO_OWNERanthropicsGitHub repository owner
REPO_NAMEclaude-codeGitHub repository name

Interactions

ModuleInterfaceData Exchanged
GitHub Actions WorkflowsWorkflow dispatch / cron triggersScripts are invoked by .github/workflows/*.yml
GitHub REST APIHTTP requests via gh.shIssue queries, label mutations, comment creation
Claude Code (AI triage)Workflow integrationTriage results feed into lifecycle labels
Issue authorsComment notificationsLifecycle 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