From aradotso-trending-skills-37
Automates conservative GitHub issue and PR triage: scans open items, generates AI-powered markdown reviews with Codex, and closes only on strict criteria like staleness or resolution.
npx claudepluginhub joshuarweaver/cascade-ai-ml-agents-misc-1 --plugin aradotso-trending-skills-37This skill uses the workspace's default tool permissions.
```markdown
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
---
name: clawsweeper-issue-triage
description: ClawSweeper is a conservative GitHub maintainer bot that scans all open issues and PRs, writes per-item markdown review records, and closes only when evidence meets strict criteria.
triggers:
- set up clawsweeper for my repo
- automate issue triage with clawsweeper
- how do I run clawsweeper locally
- configure clawsweeper to close stale issues
- apply clawsweeper closures to my repository
- review open PRs with clawsweeper
- clawsweeper dashboard not updating
- how does clawsweeper decide what to close
---
# ClawSweeper Issue Triage Bot
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
ClawSweeper is a conservative AI-powered GitHub maintainer bot that reviews every open issue and PR in a target repository, writes a regenerated markdown record per item, and closes only when evidence is strong. It runs on a weekly cadence per item and uses Codex (`gpt-5.5`) to evaluate each item against a strict set of allowed close reasons.
## What ClawSweeper Does
- Scans all open issues and PRs in a target repo (e.g. `openclaw/openclaw`)
- Writes one markdown file per item under `items/<number>.md`
- Proposes closes only for items that match allowed reasons
- Actually closes items only when `apply_closures=true` is explicitly set
- Archives closed item records to `closed/<number>.md`
- Updates a live dashboard in the README after each run
- Never auto-closes items authored by `OWNER`, `MEMBER`, or `COLLABORATOR`
### Allowed Close Reasons
1. Already implemented on `main`
2. Cannot reproduce on current `main`
3. Belongs on a plugin/skill hub, not in core
4. Too incoherent to be actionable
5. Stale issue older than 60 days with insufficient data to verify the bug
## Installation
Requires **Node 24**.
```bash
git clone https://github.com/openclaw/clawsweeper.git
cd clawsweeper
npm install
npm run build
Set required environment variables:
export GITHUB_TOKEN=$GITHUB_TOKEN # read access to target repo
export OPENAI_API_KEY=$OPENAI_API_KEY # Codex access
export CLAWSWEEPER_REPO="owner/repo" # target repo to scan
Scans open items and produces shard batches for review jobs.
npm run plan -- \
--batch-size 5 \
--shard-count 40 \
--max-pages 250 \
--codex-model gpt-5.5 \
--codex-reasoning-effort medium \
--codex-service-tier fast
Runs Codex on each planned item inside a local checkout of the target repo.
npm run review -- \
--openclaw-dir ../openclaw \
--batch-size 5 \
--max-pages 250 \
--artifact-dir artifacts/reviews \
--codex-model gpt-5.5 \
--codex-reasoning-effort medium \
--codex-service-tier fast \
--codex-timeout-ms 600000
Merges shard artifacts and updates dashboard. Does not close anything yet.
npm run apply-artifacts -- --artifact-dir artifacts/reviews
Re-fetches issue context, recomputes snapshot hash, and closes if nothing changed since the proposal.
npm run apply-decisions -- --limit 20
Options:
| Flag | Default | Description |
|---|---|---|
--limit | unlimited | Max fresh closes in this run |
--apply-kind | issue | issue, pr, or all |
--apply-min-age-days | 0 | Minimum age of proposal before applying |
--close-delay-ms | 5000 | Delay between close API calls |
Moves externally closed items from items/ to closed/ and reopened items back to items/ as stale.
npm run reconcile -- --dry-run # preview only
npm run reconcile # apply changes
ClawSweeper is designed to run as a scheduled GitHub Actions workflow on the clawsweeper repo itself. Key workflow inputs:
# Trigger a manual run with apply enabled
workflow_dispatch:
inputs:
apply_closures:
description: "Set to true to actually close issues/PRs"
default: "false"
apply_existing:
description: "Apply existing proposals without re-running Codex"
default: "false"
apply_kind:
description: "issue | pr | all"
default: "issue"
apply_min_age_days:
description: "Min age in days for a proposal to be applied"
default: "0"
The normal scheduled run is proposal-only — it never comments or closes without explicit apply_closures=true.
Each item is stored as items/<number>.md. Example structure:
# Issue #58150
**Title:** [Bug]: RISC-V64: OpenClaw fails with LLM request failed
**Outcome:** keep_open
**Reason:** Bug is reproducible and not fixed on main. Insufficient evidence
to close as cannot-reproduce.
**Snapshot hash:** abc123def456
**Reviewed:** Apr 25, 2026, 16:55 UTC
**Proposed close comment:** N/A
When outcome is proposed_close, the record includes the exact comment that will be posted before closing.
| Item type | Cadence |
|---|---|
| All PRs | Daily |
| Issues < 30 days old | Daily |
| Issues ≥ 30 days old with no recent activity | Weekly |
| Items with new activity since last snapshot | Daily (promoted) |
The planner prioritizes: active items → PRs → new issues → older weekly issues when more items are due than fit in a run.
ClawSweeper reads configuration from environment variables and CLI flags. There is no separate config file — all settings are passed at invocation time.
| Env Var | Purpose |
|---|---|
GITHUB_TOKEN | GitHub API access (read for review, write for apply) |
OPENAI_API_KEY | Codex API key |
CLAWSWEEPER_REPO | Target repo in owner/repo format |
| CLI Flag | Command | Description |
|---|---|---|
--batch-size | plan, review | Items per shard batch |
--shard-count | plan | Number of parallel review shards |
--max-pages | plan, review | Max GitHub API pages to scan |
--codex-model | plan, review | Model to use (default: gpt-5.5) |
--codex-reasoning-effort | plan, review | low, medium, high |
--codex-service-tier | plan, review | default, fast |
--codex-timeout-ms | review | Per-item timeout (default: 600000) |
--artifact-dir | review, apply-artifacts | Directory for shard output |
--dry-run | reconcile | Preview without writing |
--apply-closures | review | Actually close items (use carefully) |
import { readFileSync } from 'fs';
import { join } from 'path';
function loadItemRecord(itemNumber) {
const filePath = join('items', `${itemNumber}.md`);
const content = readFileSync(filePath, 'utf-8');
const outcomeMatch = content.match(/\*\*Outcome:\*\*\s+(\S+)/);
const snapshotMatch = content.match(/\*\*Snapshot hash:\*\*\s+(\S+)/);
return {
number: itemNumber,
outcome: outcomeMatch?.[1] ?? 'unknown',
snapshotHash: snapshotMatch?.[1] ?? null,
raw: content,
};
}
const record = loadItemRecord(58150);
console.log(record.outcome); // "keep_open" or "proposed_close"
import { readdirSync, readFileSync } from 'fs';
import { join } from 'path';
function getProposedCloses(itemsDir = 'items') {
const files = readdirSync(itemsDir).filter(f => f.endsWith('.md'));
return files
.map(file => {
const content = readFileSync(join(itemsDir, file), 'utf-8');
const number = parseInt(file.replace('.md', ''), 10);
const outcomeMatch = content.match(/\*\*Outcome:\*\*\s+(\S+)/);
return { number, outcome: outcomeMatch?.[1] };
})
.filter(item => item.outcome === 'proposed_close')
.map(item => item.number);
}
const toClose = getProposedCloses();
console.log(`Proposed closes: ${toClose.length}`);
console.log(toClose);
import { readFileSync } from 'fs';
function parseDashboard(readmePath = 'README.md') {
const content = readFileSync(readmePath, 'utf-8');
const stateMatch = content.match(/State:\s+(.+)/);
const checkpointMatch = content.match(/Checkpoint (\d+) finished/);
const totalClosesMatch = content.match(/Total fresh closes in this run:\s+(\d+)\/(\d+)/);
return {
state: stateMatch?.[1]?.trim(),
checkpoint: checkpointMatch ? parseInt(checkpointMatch[1], 10) : null,
closesApplied: totalClosesMatch ? parseInt(totalClosesMatch[1], 10) : null,
closesLimit: totalClosesMatch ? parseInt(totalClosesMatch[2], 10) : null,
};
}
const dashboard = parseDashboard();
console.log(dashboard);
// { state: 'Apply in progress', checkpoint: 7, closesApplied: 350, closesLimit: 500 }
import { Octokit } from '@octokit/rest';
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
async function triggerApplyRun({ limit = 50, kind = 'issue', minAgeDays = 0 } = {}) {
await octokit.actions.createWorkflowDispatch({
owner: 'openclaw',
repo: 'clawsweeper',
workflow_id: 'sweep.yml',
ref: 'main',
inputs: {
apply_existing: 'true',
apply_closures: 'true',
apply_kind: kind,
apply_min_age_days: String(minAgeDays),
},
});
console.log(`Apply run triggered: limit=${limit}, kind=${kind}`);
}
await triggerApplyRun({ limit: 100, kind: 'issue' });
Apply a small batch first to verify the bot is behaving correctly:
# Step 1: review only (default, no closes)
npm run plan -- --batch-size 5 --shard-count 10
npm run review -- --openclaw-dir ../myrepo --artifact-dir artifacts/reviews
npm run apply-artifacts -- --artifact-dir artifacts/reviews
# Step 2: inspect proposals
ls items/ | wc -l
grep -l "proposed_close" items/*.md
# Step 3: apply a small batch
npm run apply-decisions -- --limit 5 --apply-kind issue
The default apply_kind=issue already excludes PRs. To explicitly target only issues:
npm run apply-decisions -- --limit 50 --apply-kind issue
# Run plan with a targeted batch override (if supported by your build)
npm run review -- \
--openclaw-dir ../myrepo \
--batch-size 1 \
--artifact-dir artifacts/manual \
--codex-timeout-ms 600000
Then check artifacts/manual/ and items/<number>.md for the result.
The dashboard is updated by the final publish job in the workflow. If it's stale:
ClawSweeper makes the target repo checkout read-only in CI and verifies it before and after each review. If Codex writes anything, the item is marked as failed. Locally, ensure the --openclaw-dir path is not the same repo you are actively editing.
Apply mode implements long retry backoff automatically. When throttled, it posts a heartbeat to the dashboard:
Throttle heartbeat: checkpoint 3, processed 120, retry in 65s
If you need to stop and resume, re-dispatch with apply_existing=true — already-closed items are skipped automatically.
If an issue is reopened externally, reconcile moves it back from closed/ to items/ as stale so the planner re-reviews it:
npm run reconcile -- --dry-run # check what would move
npm run reconcile # apply
ClawSweeper reads author_association from the GitHub API. Items authored by OWNER, MEMBER, or COLLABORATOR are excluded from automated close actions at both plan and apply time. If a maintainer item appears as proposed_close, verify that the GitHub token has sufficient scope to read association data, and re-run the review for that item.