
Clawsweeper Status
- 43 installs
- 6.5k repo stars
- Updated August 3, 2026
- steipete/agent-scripts
Helps with ai & agent building tasks during AI-assisted development.
About
clawsweeper-status is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- clawsweeper-status
- AI & Agent Building
- AI-coding skill
Clawsweeper Status by the numbers
- 43 all-time installs (skills.sh)
- +3 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #7,884 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/steipete/agent-scripts --skill clawsweeper-statusAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 43 |
|---|---|
| repo stars | ★ 6.5k |
| Last updated | August 3, 2026 |
| Repository | steipete/agent-scripts ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
ClawSweeper Status
Quick Start
Run the bundled status script first:
/Users/steipete/Projects/agent-scripts/skills/clawsweeper-status/scripts/clawsweeper-status.shUseful options:
# Last 10 hours for the default target repo, openclaw/openclaw
/Users/steipete/Projects/agent-scripts/skills/clawsweeper-status/scripts/clawsweeper-status.sh --hours 10
# A different target repo
/Users/steipete/Projects/agent-scripts/skills/clawsweeper-status/scripts/clawsweeper-status.sh --repo openclaw/clawhub
# More rows per activity section
/Users/steipete/Projects/agent-scripts/skills/clawsweeper-status/scripts/clawsweeper-status.sh --limit 15Output Contract
Report these sections concisely:
Workers: active workflow count, queued/waiting count, active Codex job estimate, and active workflow groups.Recently merged: merged PR URLs plus one-line titles.Recently reviewed: ClawSweeper/Codex review comment URLs plus one-line comment summary.Recently commented: other recent ClawSweeper comment URLs plus one-line comment summary.Recently closed: closed issue/PR URLs plus one-line titles.
If the script returns no rows for a section, say none found in window.
Efficient Data Sources
Prefer the script because it uses bounded API calls:
- field-bounded Actions run queries and bounded in-progress job probes from
openclaw/clawsweeper; - recent issue comments for review/comment URLs;
- a field-bounded closed-item search for close URLs and actors;
- field-bounded recent merged PRs.
Do not browse the web for these checks. Use gh directly.
Interpretation
- Cancelled repository-dispatch review runs are usually expected supersession when a newer event for the same item arrives.
- Count active Codex from in-progress/queued jobs whose names match review, commit review, repair, or worker execution lanes.
- Treat stale worker counts cautiously; compare the status-filtered
gh run listresults with the default recent-run list when numbers disagree. - Use full GitHub URLs in the final answer.
interface:
display_name: "ClawSweeper Status"
short_description: "Summarize ClawSweeper activity and worker health."
default_prompt: "Use $clawsweeper-status to show recent comments, reviews, closes, merges, and active Codex workers."
#!/usr/bin/env bash
set -euo pipefail
target_repo="openclaw/openclaw"
clawsweeper_repo="openclaw/clawsweeper"
hours="6"
limit="8"
run_limit="100"
bot_regex='(clawsweeper|openclaw-ci|github-actions)'
usage() {
cat <<'USAGE'
Usage: clawsweeper-status.sh [--repo owner/name] [--hours N] [--limit N]
Shows recent ClawSweeper activity and worker health:
- recently merged PRs
- recently reviewed/commented items
- recently closed items
- active workflows and estimated active Codex jobs
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--repo)
target_repo="${2:?missing value for --repo}"
shift 2
;;
--clawsweeper-repo)
clawsweeper_repo="${2:?missing value for --clawsweeper-repo}"
shift 2
;;
--hours)
hours="${2:?missing value for --hours}"
shift 2
;;
--limit)
limit="${2:?missing value for --limit}"
shift 2
;;
--run-limit)
run_limit="${2:?missing value for --run-limit}"
shift 2
;;
--help|-h)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 2
;;
esac
done
if ! command -v gh >/dev/null 2>&1; then
echo "gh is required" >&2
exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
echo "jq is required" >&2
exit 1
fi
since="$(date -u -v-"${hours}"H '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || date -u -d "${hours} hours ago" '+%Y-%m-%dT%H:%M:%SZ')"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
runs_json="$tmpdir/runs.json"
all_runs_jsonl="$tmpdir/all-runs.jsonl"
comments_json="$tmpdir/comments.json"
closed_items_json="$tmpdir/closed-items.json"
pulls_json="$tmpdir/pulls.json"
jobs_jsonl="$tmpdir/jobs.jsonl"
activity_page_size=$((limit * 3))
if [ "$activity_page_size" -lt 10 ]; then
activity_page_size=10
elif [ "$activity_page_size" -gt 20 ]; then
activity_page_size=20
fi
normalize_runs='.[] | {
id: .databaseId,
name,
status,
conclusion,
created_at: .createdAt,
html_url: .url
}'
fetch_activity_page() {
local endpoint_template="$1"
local output="$2"
local page_size="$activity_page_size"
local error_file="$tmpdir/activity-error"
while :; do
if gh api "${endpoint_template/__PAGE__/$page_size}" >"$output" 2>"$error_file"; then
return 0
fi
if [ "$page_size" -eq 1 ]; then
cat "$error_file" >&2
return 1
fi
page_size=$((page_size / 2))
[ "$page_size" -lt 1 ] && page_size=1
done
}
: >"$all_runs_jsonl"
gh run list --repo "$clawsweeper_repo" --limit "$run_limit" \
--json databaseId,name,status,conclusion,createdAt,url \
| jq -c "$normalize_runs" >>"$all_runs_jsonl"
run_query_failures=0
run_query_truncated=0
for status in in_progress queued waiting pending requested; do
status_runs_json="$tmpdir/runs-${status}.json"
if gh run list --repo "$clawsweeper_repo" --status "$status" --limit "$run_limit" \
--json databaseId,name,status,conclusion,createdAt,url >"$status_runs_json"; then
jq -c "$normalize_runs" "$status_runs_json" >>"$all_runs_jsonl"
status_run_count="$(jq 'length' "$status_runs_json")"
if [ "$status_run_count" -ge "$run_limit" ]; then
run_query_truncated=$((run_query_truncated + 1))
fi
else
run_query_failures=$((run_query_failures + 1))
fi
done
jq -s '
{
workflow_runs: (
unique_by(.id)
| sort_by(.created_at)
| reverse
)
}
' "$all_runs_jsonl" >"$runs_json"
fetch_activity_page "repos/${target_repo}/issues/comments?sort=updated&direction=desc&per_page=__PAGE__&since=${since}" "$comments_json"
closed_search="repo:${target_repo} is:closed closed:>=${since} sort:updated-desc"
# GraphQL variable references must remain literal for gh to bind them.
# shellcheck disable=SC2016
closed_query='query($searchQuery: String!, $first: Int!) {
search(type: ISSUE, query: $searchQuery, first: $first) {
nodes {
... on Issue {
title url closedAt
timelineItems(last: 1, itemTypes: [CLOSED_EVENT]) {
nodes { ... on ClosedEvent { createdAt actor { login } } }
}
}
... on PullRequest {
title url closedAt
timelineItems(last: 1, itemTypes: [CLOSED_EVENT]) {
nodes { ... on ClosedEvent { createdAt actor { login } } }
}
}
}
}
}'
gh api graphql -f query="$closed_query" -f searchQuery="$closed_search" \
-F first="$activity_page_size" >"$closed_items_json"
gh pr list --repo "$target_repo" --state merged \
--search "merged:>=${since} sort:updated-desc" --limit "$activity_page_size" \
--json title,url,mergedAt,mergedBy,labels >"$pulls_json"
in_progress_count="$(jq '[.workflow_runs[] | select(.status == "in_progress")] | length' "$runs_json")"
job_probe_limit=40
active_ids="$(jq -r --argjson limit "$job_probe_limit" '[.workflow_runs[]
| select(.status == "in_progress")
| .id][0:$limit][]' "$runs_json")"
if [ "$in_progress_count" -gt "$job_probe_limit" ]; then
unprobed_job_runs=$((in_progress_count - job_probe_limit))
else
unprobed_job_runs=0
fi
: >"$jobs_jsonl"
job_batch_size=8
job_batch_count=0
while IFS= read -r run_id; do
[ -n "$run_id" ] || continue
(
if jobs="$(gh run view "$run_id" --repo "$clawsweeper_repo" --json jobs \
--jq '[.jobs[] | {name,status,conclusion}]' 2>/dev/null)"; then
jq -cn --argjson jobs "$jobs" '{jobs: $jobs, query_failed: false}'
else
jq -cn '{jobs: [], query_failed: true}'
fi
) >"$tmpdir/jobs-${run_id}.json" &
job_batch_count=$((job_batch_count + 1))
if [ "$job_batch_count" -ge "$job_batch_size" ]; then
wait
job_batch_count=0
fi
done <<<"$active_ids"
wait
for job_file in "$tmpdir"/jobs-*.json; do
[ -e "$job_file" ] || continue
cat "$job_file" >>"$jobs_jsonl"
done
active_count="$(jq '[.workflow_runs[] | select(.status == "in_progress" or .status == "pending" or .status == "queued" or .status == "waiting")] | length' "$runs_json")"
queued_count="$(jq '[.workflow_runs[] | select(.status == "queued" or .status == "waiting")] | length' "$runs_json")"
bad_count="$(jq '[.workflow_runs[] | select(.conclusion == "failure" or .conclusion == "timed_out" or .conclusion == "action_required")] | length' "$runs_json")"
codex_running="$(jq -s '[.[].jobs[]?
| select(.status == "in_progress")
| select(.name | test("Review shard|Review, comment|Review commit|Plan and review|Run worker|Execute credited fix|Codex"; "i"))
] | length' "$jobs_jsonl")"
codex_queued="$(jq -s '[.[].jobs[]?
| select(.status == "queued" or .status == "waiting" or .status == "pending")
| select(.name | test("Review shard|Review, comment|Review commit|Plan and review|Run worker|Execute credited fix|Codex"; "i"))
] | length' "$jobs_jsonl")"
job_query_failures="$(jq -s '[.[] | select(.query_failed)] | length' "$jobs_jsonl")"
job_query_failures=$((job_query_failures + unprobed_job_runs))
queued_codex_workflows="$(jq '[.workflow_runs[]
| select(.status == "queued" or .status == "waiting" or .status == "pending")
| select(.name | test("Review|repair|Run worker|Execute credited fix|Codex"; "i"))
] | length' "$runs_json")"
codex_queued=$((codex_queued + queued_codex_workflows))
echo "# ClawSweeper status"
echo
echo "Target: ${target_repo}"
echo "Window: last ${hours}h since ${since}"
echo
echo "## Workers"
echo
if [ "$run_query_failures" -gt 0 ] || [ "$run_query_truncated" -gt 0 ]; then
printf -- "- Active workflow runs: at least %s (%s failed, %s truncated status queries)\n" "$active_count" "$run_query_failures" "$run_query_truncated"
else
printf -- "- Active workflow runs: %s\n" "$active_count"
fi
if [ "$run_query_failures" -gt 0 ] || [ "$run_query_truncated" -gt 0 ]; then
printf -- "- Queued/waiting workflow runs: at least %s\n" "$queued_count"
else
printf -- "- Queued/waiting workflow runs: %s\n" "$queued_count"
fi
printf -- "- Failed/timed-out/action-required recent runs: %s\n" "$bad_count"
if [ "$job_query_failures" -gt 0 ] && { [ "$run_query_failures" -gt 0 ] || [ "$run_query_truncated" -gt 0 ]; }; then
printf -- "- Estimated active Codex jobs: at least %s running, %s queued/pending (%s job queries unavailable; workflow status may be incomplete)\n" "$codex_running" "$codex_queued" "$job_query_failures"
elif [ "$job_query_failures" -gt 0 ]; then
printf -- "- Estimated active Codex jobs: at least %s running, %s queued/pending (%s job queries unavailable)\n" "$codex_running" "$codex_queued" "$job_query_failures"
elif [ "$run_query_failures" -gt 0 ] || [ "$run_query_truncated" -gt 0 ]; then
printf -- "- Estimated active Codex jobs: at least %s running, %s queued/pending (workflow status pages incomplete)\n" "$codex_running" "$codex_queued"
else
printf -- "- Estimated active Codex jobs: %s running, %s queued/pending\n" "$codex_running" "$codex_queued"
fi
echo
jq -r '[.workflow_runs[]
| select(.status == "in_progress" or .status == "pending" or .status == "queued" or .status == "waiting")
] | group_by(.name) | sort_by(-length) | .[]
| "- \((length))x \((.[0].name)): \((.[0].html_url))"' "$runs_json" | head -20
print_section() {
local title="$1"
local body="$2"
echo
echo "## ${title}"
echo
if [ -n "$body" ]; then
printf '%s\n' "$body"
else
echo "- none found in window"
fi
}
merged="$(
jq -r --arg since "$since" --argjson limit "$limit" '
def one_line: gsub("[\r\n\t]+"; " ") | gsub(" +"; " ") | .[0:160];
[.[] | select(.mergedAt != null and .mergedAt >= $since)
] | sort_by(.mergedAt) | reverse | .[0:$limit][]
| "- \(.url) — \(.title | one_line) (merged \(.mergedAt))"
' "$pulls_json"
)"
print_section "Recently merged" "$merged"
reviewed="$(
jq -r --arg bot "$bot_regex" --argjson limit "$limit" '
def visible_line:
split("\n")
| map(gsub("[\r\t]+"; " ") | gsub(" +"; " ") | select(length > 0))
| map(select(test("^<!--") | not))
| (.[0] // "");
def one_line: visible_line | .[0:180];
[.[] | select((.user.login // "") | test($bot; "i"))
| select((((.body // "") | test("clawsweeper-command-status"; "i"))) | not)
| select((.body // "") | test("Codex review:|clawsweeper-action:review|ClawSweeper review"; "i"))
][0:$limit][]
| "- \(.html_url) — #\(.issue_url | split("/")[-1]) \((.body // "") | one_line)"
' "$comments_json"
)"
print_section "Recently reviewed" "$reviewed"
commented="$(
jq -r --arg bot "$bot_regex" --argjson limit "$limit" '
def visible_line:
split("\n")
| map(gsub("[\r\t]+"; " ") | gsub(" +"; " ") | select(length > 0))
| map(select(test("^<!--") | not))
| (.[0] // "");
def one_line: visible_line | .[0:180];
[.[] | select((.user.login // "") | test($bot; "i"))
| select((((.body // "") | test("Codex review:|clawsweeper-action:review|ClawSweeper review"; "i"))) | not)
][0:$limit][]
| "- \(.html_url) — #\(.issue_url | split("/")[-1]) \((.body // "") | one_line)"
' "$comments_json"
)"
print_section "Recently commented" "$commented"
closed="$(
jq -r --arg bot "$bot_regex" --arg since "$since" --argjson limit "$limit" '
def one_line: gsub("[\r\n\t]+"; " ") | gsub(" +"; " ") | .[0:160];
[.data.search.nodes[]
| .timelineItems.nodes[0] as $event
| select(.closedAt >= $since)
| select(($event.actor.login // "") | test($bot; "i"))
| {title, url, closed_at: .closedAt, actor: $event.actor.login}
] | sort_by(.closed_at) | reverse | .[0:$limit][]
| "- \(.url) — \(.title | one_line) (closed by \(.actor) at \(.closed_at))"
' "$closed_items_json"
)"
print_section "Recently closed" "$closed"
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
cat >"$tmpdir/gh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >>"${GH_TEST_LOG:?}"
case "$1 $2" in
"run list")
if [[ " $* " == *" --status in_progress "* ]]; then
printf '%s\n' '[{"databaseId":21,"name":"ClawSweeper review","status":"in_progress","conclusion":null,"createdAt":"2099-01-01T00:00:00Z","url":"https://github.test/runs/21"}]'
elif [[ " $* " == *" --status queued "* ]]; then
printf '%s\n' '[{"databaseId":22,"name":"ClawSweeper review","status":"queued","conclusion":null,"createdAt":"2099-01-01T00:00:00Z","url":"https://github.test/runs/22"}]'
elif [[ " $* " == *" --status "* ]]; then
printf '%s\n' '[]'
else
printf '%s\n' '[{"databaseId":11,"name":"Sweep","status":"completed","conclusion":"failure","createdAt":"2099-01-01T00:00:00Z","url":"https://github.test/runs/11"}]'
fi
;;
"run view")
printf '%s\n' '[{"name":"Review shard 1","status":"in_progress","conclusion":null}]'
;;
"pr list")
printf '%s\n' '[{"title":"Generated repair","url":"https://github.test/pull/7","mergedAt":"2099-01-01T00:00:00Z","mergedBy":{"login":"maintainer"},"labels":[]}]'
;;
"api repos/test/target/issues/comments"*)
if [[ "$*" == *"per_page=20"* ]]; then
echo "github_response_too_large" >&2
exit 1
fi
printf '%s\n' '[{"user":{"login":"clawsweeper"},"body":"Codex review: clean","html_url":"https://github.test/comment/8","issue_url":"https://api.github.test/issues/8"}]'
;;
"api graphql")
printf '%s\n' '{"data":{"search":{"nodes":[{"title":"Fixed issue","url":"https://github.test/issues/9","closedAt":"2099-01-01T00:00:00Z","timelineItems":{"nodes":[{"createdAt":"2099-01-01T00:00:00Z","actor":{"login":"clawsweeper"}}]}}]}}}'
;;
*)
echo "unexpected gh call: $*" >&2
exit 1
;;
esac
EOF
chmod +x "$tmpdir/gh"
export GH_TEST_LOG="$tmpdir/gh.log"
PATH="$tmpdir:$PATH" "$script_dir/clawsweeper-status.sh" \
--repo test/target \
--clawsweeper-repo test/sweeper \
--limit 8 \
--run-limit 12 >"$tmpdir/output"
grep -Fq -- '- Active workflow runs: 2' "$tmpdir/output"
grep -Fq -- '- Failed/timed-out/action-required recent runs: 1' "$tmpdir/output"
grep -Fq -- '- Estimated active Codex jobs: 1 running, 1 queued/pending' "$tmpdir/output"
grep -Fq 'https://github.test/pull/7' "$tmpdir/output"
grep -Fq 'https://github.test/comment/8' "$tmpdir/output"
grep -Fq 'https://github.test/issues/9' "$tmpdir/output"
grep -Fq 'run list --repo test/sweeper --limit 12 --json' "$GH_TEST_LOG"
grep -Fq 'issues/comments?sort=updated&direction=desc&per_page=20' "$GH_TEST_LOG"
grep -Fq 'issues/comments?sort=updated&direction=desc&per_page=10' "$GH_TEST_LOG"
if grep -Eq 'actions/runs|per_page=100|pulls\?state=closed' "$GH_TEST_LOG"; then
echo "broad GitHub payload query detected" >&2
exit 1
fi
echo "clawsweeper-status tests passed"
Related skills
AI & Agent Buildingagents