GitHub Issue Triage

Use this skill to run the daily open-source GitHub triage routine for CascadeGuard. It handles the full lifecycle: scan, label, prioritize, detect vulnerabilities, track PRs, report to the board, and hand off approved work into Paperclip.

Prerequisites

  • GITHUB_TOKEN environment variable with repo, security_events, and read:org scopes on the cascadeguard org
  • PUSHOVER_APP_TOKEN and PUSHOVER_USER_KEY environment variables for digest delivery
  • Paperclip agent context (PAPERCLIP_API_KEY, PAPERCLIP_COMPANY_ID, etc.)

Multi-Repo Scope

All triage operations cover every public repo in the cascadeguard org. The known repos are:

RepositoryPurpose
cascadeguard/cascadeguardCore product
cascadeguard/cascadeguard-open-secure-imagesCurated secure base images
cascadeguard/cascadeguard-appWeb application
cascadeguard/cascadeguard-docsDocumentation site
cascadeguard/cascadeguard-exemplarExample/reference configs

Auto-Discover New Repos

On each triage run, discover any new public repos in the org so they are automatically included.

# List all public repos in the org
curl -s -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  "https://api.github.com/orgs/cascadeguard/repos?type=public&per_page=100" \
  | jq -r '.[].full_name'

Use the resulting list as $REPOS for all subsequent steps. Any repo not in the known list above should be flagged in the digest as newly discovered.

Label Taxonomy

Create these labels on every repo in $REPOS if they do not already exist.

LabelColorMeaning
triaged#0e8a16Issue has been reviewed and categorized
inscope#1d76dbFits the current roadmap (v1)
next#fbca04Top 10 prioritized items ready for CTO review
cto-reviewed#d93f0bCTO has added assessment and solution design
ready#0075caBoard-approved, can be pulled into Paperclip today
needs-info#e4e669Unclear scope, waiting for clarification from author
security#b60205Security-related issue or vulnerability report

Ensure Labels Exist (All Repos)

for repo in $REPOS; do
  for label in triaged inscope next cto-reviewed ready needs-info security; do
    color=""
    case $label in
      triaged)      color="0e8a16" ;;
      inscope)      color="1d76db" ;;
      next)         color="fbca04" ;;
      cto-reviewed) color="d93f0b" ;;
      ready)        color="0075ca" ;;
      needs-info)   color="e4e669" ;;
      security)     color="b60205" ;;
    esac
    curl -s -X POST \
      -H "Authorization: token $GITHUB_TOKEN" \
      -H "Accept: application/vnd.github+json" \
      "https://api.github.com/repos/$repo/labels" \
      -d "{\"name\":\"$label\",\"color\":\"$color\"}" 2>/dev/null
  done
done

Triage Workflow

Execute these steps in order during each daily triage heartbeat.

Step 1 — Vulnerability Detection (IMMEDIATE)

This step runs first and has immediate-action SLAs. Do NOT batch vuln handling into the daily digest.

For each repo in $REPOS:

1a. Scan for Vulnerability Reports in Public Issues

Check all new/untriaged issues for patterns that indicate a vulnerability report (keywords: “vulnerability”, “CVE”, “security flaw”, “exploit”, “injection”, “RCE”, “XSS”, “CSRF”, “auth bypass”, “privilege escalation”, “disclosure”, etc.).

for repo in $REPOS; do
  curl -s -H "Authorization: token $GITHUB_TOKEN" \
    -H "Accept: application/vnd.github+json" \
    "https://api.github.com/repos/$repo/issues?state=open&per_page=100" \
    | jq '[.[] | select(.pull_request == null) | select(.labels | map(.name) | index("triaged") | not)]'
done

If a public issue looks like a vulnerability report:

  1. Immediately close the issue with a comment:

    Thank you for reporting this. For security issues, please use our private security advisory process instead. We have moved this report to a private advisory for investigation. See SECURITY.md for our responsible disclosure policy.

  2. Create a GitHub Security Advisory (draft) on the affected repo with the issue details.
  3. Notify the board immediately via Pushover with priority=1 (high):
    curl -s -X POST "https://api.pushover.net/1/messages.json" \
      -d "token=$PUSHOVER_APP_TOKEN" \
      -d "user=$PUSHOVER_USER_KEY" \
      -d "title=⚠️ Vuln Report Detected — $repo" \
      -d "message=Public issue #$issue_number closed and moved to private advisory. Immediate review required." \
      -d "priority=1" \
      -d "retry=300" \
      -d "expire=3600" \
      -d "html=1"

1b. Track GitHub Security Advisories

for repo in $REPOS; do
  curl -s -H "Authorization: token $GITHUB_TOKEN" \
    -H "Accept: application/vnd.github+json" \
    "https://api.github.com/repos/$repo/security-advisories?state=draft,triage" \
    2>/dev/null
done

Track all open advisories and their state. Include in the daily digest.

1c. Vulnerability SLA Tracking

SLATarget
Acknowledgement24 hours
Assessment complete48 hours
Critical fix24 hours
High fix48 hours

For each open advisory, calculate time elapsed since creation and flag any SLA breaches. Critical and High severity vulns that breach SLA trigger an immediate Pushover notification (priority=1), not batched into the daily digest.

Step 2 — Triage New Issues (All Repos)

For each repo in $REPOS, scan for issues that do not have the triaged label.

for repo in $REPOS; do
  curl -s -H "Authorization: token $GITHUB_TOKEN" \
    -H "Accept: application/vnd.github+json" \
    "https://api.github.com/repos/$repo/issues?state=open&per_page=100" \
    | jq '[.[] | select(.pull_request == null) | select(.labels | map(.name) | index("triaged") | not)]'
done

For each untriaged issue:

  1. Categorize: bug, feature request, question, security, docs
  2. Assess scope against the current v1 roadmap
  3. Label:
    • In scope: add triaged + inscope
    • Security: add triaged + security (and follow Step 1 vuln handling)
    • Out of scope: convert to GitHub Discussion with an explanatory comment
    • Unclear: add triaged + needs-info, comment asking for clarification
# Add labels to an issue (substitute repo and issue_number)
curl -s -X POST \
  -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/$repo/issues/{issue_number}/labels" \
  -d '{"labels":["triaged","inscope"]}'

Step 3 — Prioritize In-Scope Issues

Review all issues with the inscope label across all repos. Rank by impact, urgency, and alignment with current sprint goals.

  • Apply next label to the top 10 highest priority items
  • Remove next from any issues that have fallen out of the top 10

Step 4 — CTO Review

For any next issue not yet labeled cto-reviewed:

  1. Add a detailed technical assessment comment with:
    • Complexity estimate (S/M/L/XL)
    • Solution design outline
    • Dependencies and risks
    • Suggested assignee capacity (% of sprint)
  2. Create or update PRDs/ADRs as appropriate
  3. Add the cto-reviewed label

Step 5 — PR Review Tracking (All Repos)

Scan all open PRs across every repo in $REPOS.

for repo in $REPOS; do
  curl -s -H "Authorization: token $GITHUB_TOKEN" \
    -H "Accept: application/vnd.github+json" \
    "https://api.github.com/repos/$repo/pulls?state=open&per_page=100"
done

For each open PR, collect:

  • PR number, title, author
  • Age (time since creation)
  • Review status: approved, changes requested, pending, no reviewers assigned
  • CI status: passing, failing, pending
# Get review status for a PR
curl -s -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/$repo/pulls/{pr_number}/reviews"
 
# Get CI/check status for a PR
curl -s -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/$repo/commits/{head_sha}/check-runs"

Flags to raise:

  • PRs with no reviewers assigned → auto-request review from CTO/engineer
  • PRs awaiting review for >24 hours → flag in digest as stale
  • PRs with failing CI → flag in digest

Ensure all PRs have an engineer or CTO assigned as reviewer:

# Request review if none assigned
curl -s -X POST \
  -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/$repo/pulls/{pr_number}/requested_reviewers" \
  -d '{"reviewers":["cto-github-username"]}'

Step 6 — Generate Daily Digest

Build a summary containing:

  • Vulnerability report:
    • Open security advisories by repo (with SLA status)
    • Any vuln reports detected and closed today
    • SLA breaches (highlighted)
  • PR review status (grouped by repo):
    • All open PRs with age, author, review status, CI status
    • Stale PRs (>24h without review)
    • PRs missing reviewers
  • New issues: issues triaged today with recommended labels/actions
  • Triage status: counts by label (inscope, next, needs-info, moved to discussions)
  • In-scope pipeline: summary of all inscope issues and current state
  • Today’s top 3: highest-priority next + cto-reviewed items recommended to start
  • Board decisions needed: items requiring approval or scope clarification
  • GitHub monitoring (see Step 7):
    • Dependabot alert summary
    • Actions workflow failures
    • Discussions trending topics
    • Stars/forks weekly trend
    • Release/tag status
  • Newly discovered repos (if any)

Deliver via Pushover

curl -s -X POST "https://api.pushover.net/1/messages.json" \
  -d "token=$PUSHOVER_APP_TOKEN" \
  -d "user=$PUSHOVER_USER_KEY" \
  -d "title=CascadeGuard Daily Triage" \
  -d "message=$DIGEST_TEXT" \
  -d "priority=0" \
  -d "html=1"

Also post the full digest as a Paperclip comment on the triage task for history and auditability.

Step 7 — Additional GitHub Monitoring (All Repos)

Collect this data for inclusion in the daily digest.

Dependabot Alerts

for repo in $REPOS; do
  curl -s -H "Authorization: token $GITHUB_TOKEN" \
    -H "Accept: application/vnd.github+json" \
    "https://api.github.com/repos/$repo/dependabot/alerts?state=open&per_page=100"
done

Group by severity (critical, high, medium, low) and repo.

GitHub Actions Workflow Failures

for repo in $REPOS; do
  curl -s -H "Authorization: token $GITHUB_TOKEN" \
    -H "Accept: application/vnd.github+json" \
    "https://api.github.com/repos/$repo/actions/runs?status=failure&per_page=10"
done

Report failures from the last 24 hours, grouped by workflow name and repo.

# Use GraphQL for discussions
for repo in $REPOS; do
  curl -s -X POST "https://api.github.com/graphql" \
    -H "Authorization: bearer $GITHUB_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{
      \"query\": \"query { repository(owner: \\\"cascadeguard\\\", name: \\\"${repo#*/}\\\") { discussions(first: 10, orderBy: {field: UPDATED_AT, direction: DESC}) { nodes { title url number comments { totalCount } updatedAt } } } }\"
    }"
done

Include top 5 most active discussions across all repos.

Stars/Forks Weekly Trend

for repo in $REPOS; do
  curl -s -H "Authorization: token $GITHUB_TOKEN" \
    -H "Accept: application/vnd.github+json" \
    "https://api.github.com/repos/$repo" \
    | jq '{repo: .full_name, stars: .stargazers_count, forks: .forks_count}'
done

Compare with previous week’s snapshot (stored in Paperclip comment history) and report delta.

Release/Tag Status

for repo in $REPOS; do
  curl -s -H "Authorization: token $GITHUB_TOKEN" \
    -H "Accept: application/vnd.github+json" \
    "https://api.github.com/repos/$repo/releases?per_page=5"
done

Report latest release per repo and any draft releases pending publication.

Step 8 — Board Approval Gate

No work starts without board sign-off.

  • Board reviews the digest (via Pushover notification linking to Paperclip comment)
  • Board responds via Paperclip comment on the triage task
  • Approved items get the ready label on GitHub
  • Only then are Paperclip issues created and assigned
# Add ready label after board approval (substitute repo and issue_number)
curl -s -X POST \
  -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/$repo/issues/{issue_number}/labels" \
  -d '{"labels":["ready"]}'

Create Paperclip Issue for Approved Work

curl -s -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/issues" \
  -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID" \
  -d '{
    "title": "Implement GitHub {repo}#{issue_number}: {title}",
    "description": "From GitHub issue {repo}#{issue_number}.\n\nLink: https://github.com/{repo}/issues/{issue_number}",
    "status": "todo",
    "priority": "{priority}",
    "parentId": "{parent_task_id}",
    "goalId": "{goal_id}",
    "projectId": "{project_id}",
    "assigneeAgentId": "{assignee_agent_id}"
  }'

Cross-link: add a comment on the GitHub issue with the Paperclip task reference.

Step 9 — If No Board Response

If no board response within 24 hours, the next digest flags unanswered items again. Nothing proceeds without sign-off.

Moving Issues to Discussions

When an issue is out of scope, convert it to a GitHub Discussion rather than closing it, to preserve the conversation for future consideration.

# Use GitHub GraphQL API to convert issue to discussion
# Requires the discussion category ID (e.g., "Ideas" or "Feature Requests")
curl -s -X POST "https://api.github.com/graphql" \
  -H "Authorization: bearer $GITHUB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation { convertIssuesToDiscussion(input: {issueId: \"{issue_node_id}\", categoryId: \"{category_node_id}\"}) { discussion { id url } } }"
  }'

PR Triage for Community Contributions

External PRs follow the same triage flow (labels on the PR), across all repos:

  1. CTO reviews code quality, test coverage, and architecture alignment
  2. Board approves merge (consistent with SDLC manual approval gate)
  3. Agent comments on the GitHub PR with status updates

Notes

  • GitHub is the source of truth for issue state until board approval
  • Paperclip issues are only created when work is approved and scheduled — do NOT create Paperclip tickets for raw CVE findings, scan results, or Dependabot alerts. These stay in GitHub as issues/advisories. A Paperclip ticket is only warranted when an agent needs to take a concrete action (code change, config update, investigation) and the board has approved it.
  • 20% of Lead Platform Engineer capacity is allocated to community work
  • WhatsApp via OpenClaw is a Phase 3 enhancement (Pushover is day-one)
  • Vulnerability handling is immediate/non-batched; all other monitoring is daily
  • GITHUB_TOKEN must have org-level access for multi-repo operations