| name | cicd |
| description | CI/CD lane for culture: branch, commit, push, create PR, wait for automated reviewers, fetch comments, fix or pushback, reply, resolve threads. Delegates `lint` / `open` / `read` / `reply` / `delta` to `agex pr`; keeps two culture-side extensions on top — `status` (SonarCloud gate, OPEN issues, hotspots, unresolved-thread tally) and `await` (`read --wait` + `status`, exits non-zero on Sonar ERROR or unresolved threads). Renamed from `pr-review` in culture 8.8.1; rebased on `agex pr` (from steward 0.12.0) in culture 11.1.0. Use when: creating PRs, handling review feedback, or the user says "create PR", "review comments", "address feedback", "resolve threads", or "use pr-review" / "use cicd".
|
CI/CD Lane (formerly pr-review)
Complete pull request lifecycle for the culture project. Follow every step
in order. The skill was renamed from pr-review to cicd in culture 8.8.1
and rebased on agex pr in culture 11.1.0; existing prompts that say "use
pr-review" still resolve here through the trigger phrases above.
agex pr (in agentculture/agex-cli) is the upstream for the five core
PR-lifecycle verbs — lint, open, read, reply, delta. Culture used
to vendor parallel scripts for each (create-pr-and-wait.sh, pr-batch.sh,
pr-comments.sh, wait-and-check.sh, poll-readiness.sh); in 11.1.0 those
were dropped in favor of delegating to agex. What's left in this skill is
the culture-specific gating layer:
status — SonarCloud quality gate, OPEN issues, hotspots, deploy preview
URL, unresolved-inline-thread tally.
await — composes agex pr read --wait with status and gates on
Sonar ERROR / unresolved threads. The single command to run after
pushing a fix when you want "wake me when this PR is triage-able."
Both extensions are filed upstream
(agex-cli#41); when
they land they migrate out of this skill.
Prerequisites
Hard requirements: agex (already a culture runtime dep — agex-cli>=0.13
in pyproject.toml), gh (GitHub CLI), jq, bash, python3 (stdlib
only), curl (used by pr-status.sh).
If agex is not on PATH (e.g. running outside a culture venv):
uv tool install agex-cli
Step 1 — Branch
If you are on main, create a feature branch first:
git checkout -b <branch-name>
Branch naming conventions:
| Type | Pattern | Example |
|---|
| Bug fix | fix/<short-desc> | fix/server-not-running-crash |
| Feature | feat/<short-desc> | feat/webhook-alerts |
| Docs | docs/<short-desc> | docs/protocol-extensions |
| Skill | skill/<short-desc> | skill/cicd-and-communicate-resync |
Step 1b — Check for existing PRs on the branch
Before adding new work to an existing branch, check if there's already an
open PR:
gh pr view --json number,title,state --jq '{number,title,state}'
If the command fails with "no pull requests found", there is no open PR —
proceed normally. Only act on the result if it returns valid JSON with
state: "OPEN".
If an open PR exists and your new changes are unrelated to that PR's
scope, stop and ask the user:
"There's an open PR (#N: 'title') on this branch. The new changes
are unrelated to that PR. Would you like to merge the existing PR
first before starting the new work?"
Wait for the user's answer before proceeding. If the user says yes,
let them merge (never merge yourself). If they say continue, add the
changes to the existing PR.
If the new changes ARE related to the existing PR, proceed normally —
commit and push to the same branch.
Step 2 — Make changes, commit, push
-
Edit code
-
Run tests via the run-tests skill (parallel by default)
-
Bump the version (required before PR — version-check CI gate
enforces this):
echo '{"fixed":["..."]}' | python3 .claude/skills/version-bump/scripts/bump.py patch
-
Stage and commit:
git add <files>
git commit -m "$(cat <<'EOF'
Commit message here.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
-
Push the branch (no --push flag on workflow.sh open anymore — see
the Migration note at the end):
git push -u origin <branch-name>
Step 3 — Create PR (and wait for an initial briefing in one shot)
Use workflow.sh open — it forwards to agex pr open --delayed-read,
which creates the PR then polls 180s for an initial briefing (CI checks,
SonarCloud gate + new issues, all comments, next-step footer). Automated
reviewers (qodo, copilot, sonarcloud) need that window to post; checking
sooner returns zero comments.
bash .claude/skills/cicd/scripts/workflow.sh open \
--title "Short title" \
--body-file /tmp/pr-body.md
Or pipe the body via heredoc on stdin:
bash .claude/skills/cicd/scripts/workflow.sh open --title "Short title" <<'EOF'
- Bullet points describing changes
- [ ] Test items
EOF
agex pr open writes the body via --body-file to a tempfile under the
hood, so large self-contained briefs don't hit the OS argv length limit.
The auto-signature - <nick> (Claude) is appended by agex from the
repo-root culture.yaml (first agent's suffix) — don't sign manually
in the body.
If you must do it by hand (PR was opened earlier and you only need
to fetch feedback now):
bash .claude/skills/cicd/scripts/workflow.sh read <PR_NUMBER>
Do not check for comments before the 3-minute mark on a brand-new PR.
Empty comment lists in the first 1–2 minutes don't mean reviewers are done
— they mean reviewers haven't started yet.
Step 4 — Wait another window if needed
If the initial briefing came back empty or thin, or you suspect a slow
reviewer (or you just pushed a follow-up commit and want a fresh review
pass), use workflow.sh read --wait for a deliberate poll:
bash .claude/skills/cicd/scripts/workflow.sh read <PR_NUMBER> --wait 180
This polls agex pr read up to 180 seconds, exiting when required
reviewers have posted (or the cap hits). It is not open-ended polling
— it's "give the reviewers one more deliberate window before deciding
they're done." For the SonarCloud-gated variant that exits non-zero on
unresolved threads, use workflow.sh await <PR> instead.
If two windows are also empty, fall back to one-shot reads spaced a
minute apart:
bash .claude/skills/cicd/scripts/workflow.sh read <PR_NUMBER>
sleep 60
bash .claude/skills/cicd/scripts/workflow.sh read <PR_NUMBER>
Three consecutive reads returning zero comments means reviewers are done /
not configured; proceed to triage (or skip directly to merge if there's
truly nothing to address).
Long waits — background polling
agex pr read --wait N polls in-session for up to N seconds. The
Anthropic prompt cache has a 5-minute TTL; sleeping past it burns context
every cache miss. Two ways to drive the wait:
- Synchronous —
workflow.sh await <PR> after workflow.sh open.
Fine when readiness is expected within ~5 minutes.
- Asynchronous — for longer waits, run
agex pr read --wait NNN
inside a background subagent (Agent tool, run_in_background: true)
so the main session only pays the cache cost when readiness fires.
The subagent's only job is to invoke agex pr read --wait and echo
its headline back. The parent triages with workflow.sh await when
the notification arrives.
Step 6 — Triage each comment
For every review comment, decide FIX or PUSHBACK with reasoning.
Default to FIX for: portability complaints (always valid for culture
— recurring bug class), test or doc requests, style nits aligned with
project conventions, exception-type mismatches (e.g. breaking reconnect
loops), Sonar findings.
Default to PUSHBACK for: architecture opinions that conflict with the
project CLAUDE.md (notably the all-backends rule and the citation
pattern), greenfield false-positives.
Alignment-delta rule
If the PR touches CLAUDE.md, culture.yaml, or anything under
.claude/skills/, run workflow.sh delta before declaring FIX or
PUSHBACK on each comment. Note any sibling that needs a follow-up PR and
mention it in your reply.
Step 7 — Fix code and push
- Make all code fixes
- Run tests via the
run-tests skill
- Commit with a descriptive message
- Push:
git push
Step 8 — Reply and resolve threads
workflow.sh reply forwards to agex pr reply <PR> which reads JSONL
from stdin, posts the replies, and resolves the threads in one call.
agex auto-appends - <nick> (Claude) (resolved from culture.yaml's
first agent suffix, falling back to repo basename) when the reply
body isn't already signed — don't sign manually.
Batch reply to all comments at once:
bash .claude/skills/cicd/scripts/workflow.sh reply <PR_NUMBER> <<'EOF'
{"comment_id": 123, "body": "Fixed -- changed X to Y."}
{"comment_id": 456, "body": "Intentional -- this follows the pattern in Z because..."}
EOF
For a one-off reply that doesn't merit JSONL, the vendored
pr-reply.sh (with its _resolve-nick.sh dependency) is still shipped
and runs outside workflow.sh:
bash .claude/skills/cicd/scripts/pr-reply.sh --resolve <PR_NUMBER> <COMMENT_ID> "Fixed -- updated."
Important:
- Don't add
- Claude or any other signature to the reply body — agex
/ pr-reply.sh appends - <nick> (Claude) automatically.
workflow.sh reply resolves threads by default; pr-reply.sh needs
--resolve.
- Every comment must get a reply — no silent fixes.
Step 9 — Check SonarCloud before declaring ready
After CI is green and all inline threads are resolved, run the culture
gate:
bash .claude/skills/cicd/scripts/workflow.sh status <PR_NUMBER>
or the composite wait-then-gate:
bash .claude/skills/cicd/scripts/workflow.sh await <PR_NUMBER>
status (powered by pr-status.sh) surfaces the SonarCloud quality
gate, the OPEN-issue list with [SEVERITY] [rule] path:line, hotspots,
the deploy-preview URL, and the unresolved-inline-thread tally.
await polls agex pr read --wait first, then runs status, and
exits non-zero if Sonar reports ERROR or any thread is still open.
SonarCloud findings do not always arrive as inline PR comments — a
fully-resolved thread list plus an all-green gh pr checks is not
sufficient evidence that the PR is clean. If new findings show up,
loop back to Step 7. For non-standard project keys, set
SONAR_PROJECT_KEY=<key> before running the script (the default is
<owner>_<repo>).
Step 10 — Wait for merge
Never merge the PR yourself. The PR is merged manually on the
GitHub site.
Report completion back to the IRC channel:
CULTURE_NICK="<agent-nick>" culture channel message "#general" "PR #<N> — all review threads addressed and resolved. Ready for merge."
Script reference
| Script | Location | Purpose |
|---|
workflow.sh <subcmd> | .claude/skills/cicd/scripts/ | Single entry point. Subcommands: lint, open, read, reply, delta, status, await, help. lint / open / read / reply / delta forward to agex pr <verb>; status / await are culture extensions. |
pr-status.sh <PR> | .claude/skills/cicd/scripts/ | One-shot status overview: PR state, CI checks, SonarCloud quality gate + issue count, inline-thread resolved tally. Backs workflow.sh status and the post-wait gate in workflow.sh await. |
pr-reply.sh [--resolve] <PR> <ID> "body" | .claude/skills/cicd/scripts/ | One-off single-comment reply. Auto-signs as - <nick> (Claude) via _resolve-nick.sh. Use when JSONL is overkill. |
_resolve-nick.sh | .claude/skills/cicd/scripts/ | Helper used by pr-reply.sh. Resolves the agent's nick from <repo-root>/culture.yaml's first agent suffix, falling back to the repo basename. |
portability-lint.sh [--all] | .claude/skills/cicd/scripts/ | Catch absolute /home/<user>/ paths and per-user dotfile references in committed docs/configs. Default mode lints the current diff (staged + unstaged); --all lints every tracked file. Run via workflow.sh lint (which forwards to agex pr lint --exit-on-violation). |
All scripts auto-detect owner/repo from the current git remote. The
full script set is vendored from guildmaster (the AgentCulture skills
hub, post steward→guildmaster cutover; lineage: steward 0.12.0) — re-cite
from ../guildmaster/.claude/skills/cicd/ if you need updates. Scripts
that have intentionally diverged from the upstream copy carry a
# culture-divergence: header documenting what was changed and why;
preserve those when re-citing.
Conventions
agex pr emits a "Next step:" footer at the end of every command
that names the right next verb (the same chain agex learn cicd
documents) — follow that rather than memorizing an order. workflow.sh help mirrors the verb table when you need the culture-flavored
extensions (status, await) on top.
Migration from create-pr-and-wait.sh
create-pr-and-wait.sh --push is gone in culture 11.1.0. The
auto-push behavior (originally added under issue #318) was a
culture-divergence on top of the upstream steward script; agex pr open
has no --push equivalent yet. The replacement flow is two steps:
bash .claude/skills/cicd/scripts/create-pr-and-wait.sh --push \
--title "..." --body-file /tmp/pr-body.md
git push -u origin HEAD
bash .claude/skills/cicd/scripts/workflow.sh open \
--title "..." --body-file /tmp/pr-body.md
Same body-file ergonomics (large briefs still travel via tempfile under
the hood), same --delayed-read wait, same auto-signature on PR
body — only the push moves out into its own line. Bringing --push
back is filed upstream
(agex-cli#41).
Quick reference — full flow
git checkout -b fix/my-fix
# ... make changes ...
# run-tests skill: bash .claude/skills/run-tests/... (or pytest direct)
echo '{"fixed":["desc"]}' | python3 .claude/skills/version-bump/scripts/bump.py patch
git add <files> && git commit -m "message"
git push -u origin HEAD
bash .claude/skills/cicd/scripts/workflow.sh open \
--title "..." --body-file /tmp/pr-body.md
# ... triage, fix issues, commit, push ...
bash .claude/skills/cicd/scripts/workflow.sh reply <PR> <<< '{"comment_id":N,"body":"Fixed"}'
bash .claude/skills/cicd/scripts/workflow.sh await <PR> # SonarCloud-gated readiness
# Wait for manual merge — never merge yourself