plugins/dev/skills/ci-describe-pr/SKILL.md
Generate PR descriptions autonomously for CI/automation (no user interaction). Non-interactive variant of /describe-pr for use in CI pipelines and automated workflows. Auto-detects current PR, generates description, and updates GitHub.
npx skillsauth add coalesce-labs/catalyst ci-describe-prInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate or update PR descriptions autonomously without user interaction. Designed for CI pipelines and automated workflows.
/describe_prhumanlayer thoughts sync automatically# Auto-detect PR for current branch
PR_JSON=$(gh pr view --json number,url,title,state,body,headRefName,baseRefName 2>/dev/null)
if [[ -z "$PR_JSON" ]]; then
echo "No PR found for current branch"
exit 1
fi
PR_NUMBER=$(echo "$PR_JSON" | jq -r '.number')
if [[ -f "thoughts/shared/pr_description.md" ]]; then
# Read template
else
echo "No PR template found at thoughts/shared/pr_description.md"
# Generate without template
fi
gh pr diff $PR_NUMBER
gh pr view $PR_NUMBER --json commits,files
gh pr view $PR_NUMBER --json url,title,number,state,baseRefName,headRefName,author
branch=$(echo "$PR_JSON" | jq -r '.headRefName')
if [[ "$branch" =~ ([A-Z]+)-([0-9]+) ]]; then
ticket="${BASH_REMATCH[0]}"
fi
Analyze all commits and changes. Generate a complete PR description following the template.
CRITICAL: NO Claude attribution — remove any "Generated with Claude" or "Co-Authored-By" lines.
CTL-623 — sibling reference format (REQUIRED): When referencing related/sibling
work in prose, reference it by its GitHub PR number (#NNN), never by a bare Linear
token (TEAM-NNN) or a Linear issue URL. A bare sibling TEAM-NNN token is auto-linked
by Linear's GitHub integration and drags that sibling's workflow status (Done → Implement)
on PR open/merge. Do not emit bare sibling Linear tokens in prose. The own ticket's
Fixes https://linear.app/... line is correct and stays. Sibling neutralization is
handled mechanically by the guard block appended at write-back time (step 6).
body_file="thoughts/shared/prs/${PR_NUMBER}_description.md"
# Save to thoughts
cat > "$body_file" <<EOF
[Generated description]
EOF
# CTL-623: append a Linear automation guard block so sibling tickets embedded in
# the branch name or pulled into the body are NOT auto-linked and dragged backward
# in status when this PR opens/merges. Scans the branch AND the assembled body;
# no-op for single-ticket PRs. See https://linear.app/docs/github (skip/ignore
# negative magic word).
# CTL-633: branch and body are scanned in DIFFERENT modes — the branch goes
# through the awk segmenter (legitimate sibling-number recovery); the body
# uses canonical-only regex so prose, dashed dates, and SHAs cannot fabricate
# fake `skip TEAM-NNN` lines. Stays non-interactive — no cache refresh prompt.
# shellcheck source=/dev/null
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/linear-pr-skip.sh"
body="$(cat "$body_file")"
skip_block="$( {
linear_sibling_skip_block_from_branch "$ticket" "$branch"
linear_sibling_skip_block_from_body "$ticket" "$body"
} | awk '/^skip /{if(!seen[$0]++) print; next} {if(!h){print; h=1}}' )"
[[ -n "$skip_block" ]] && printf '\n%s\n' "$skip_block" >>"$body_file"
# Sync thoughts
humanlayer thoughts sync
# Update PR on GitHub
gh pr edit $PR_NUMBER --title "$new_title"
gh pr edit $PR_NUMBER --body-file "$body_file"
If Linearis CLI is available, update the ticket status to stateMap.inReview from config.
Use linearis issues usage for exact update syntax. Skip silently if CLI not available.
PR description updated: #$PR_NUMBER
URL: $PR_URL
Ticket: $ticket (updated to In Review)
IMPORTANT: Document Storage Rules
thoughts/shared/prs/ for PR descriptionsthoughts/searchable/ — this is a read-only search indexdevelopment
Migrate a single-harness repo to the dual-harness layout so both Claude Code and Codex load the same instructions and skills — AGENTS.md as the portable canonical doc, a thin CLAUDE.md `@AGENTS.md` bridge, and a `.agents/skills` dir with a `.claude/skills` symlink onto it. Use when asked to migrate to dual-harness, make this repo work in both Claude and Codex, or for agent metadata cleanup.
tools
Goal-driven senior-engineer pipeline-unstick sweep (CTL-1176 rung 3). Given the stuck/failed/needs-human set (or ONE ticket handed by the recovery router), its GOAL is to get the pipeline MOVING again — not to fix one ticket's review findings (that is phase-remediate). It runs AFTER the eyes (diagnostician evidence) and the hands (deterministic unstuck-sweep seams) have already tried, and it CONSUMES their output from a recovery-pass.json brief rather than re-diagnosing or redoing their narrow work. It acts like a senior engineer with full tool access — it resolves merge conflicts, rebases, force-pushes, merges green PRs, and re-dispatches stalled phases AUTONOMOUSLY — and escalates to the operator ONLY for a genuine value judgment / something that degrades other functionality / a real cost-benefit trade-off / a serious architecture change / an ADR conflict. On escalation it AUTHORS the operator inbox row + the push notification (executive-voiced). Dispatched as a `claude --bg` job by phase-agent-dispatch via slash command, AND invocable bare by the operator as a sweep — hence `user-invocable: true`. Ships behind CATALYST_RECOVERY_PASS (off by default — no live behavior change until shadow/enforce).
tools
Diagnose and fix Catalyst setup issues. Validates tools, database, config, OTel, direnv, and thoughts. Automatically fixes what it can — creates directories, initializes the database, sets WAL mode, runs migrations. Use for new installs, upgrades, or when something isn't working.
tools
--- name: phase-triage description: Phase agent that triages a Linear ticket — expands acronyms, classifies (feature/bug/docs/refactor/chore), identifies genuine blockers (a semantic second-pass over the backlog — NOT a prose scrape; CTL-838), estimates scope, writes triage.json, and posts a triage analysis comment to Linear. Triage completion is signaled by that comment plus the local triage.json — there is no `triaged` label. Emits phase.triage.complete.<TICKET> on success and phase.triage.fai