|
| 1 | +--- |
| 2 | +name: cicd |
| 3 | +description: > |
| 4 | + Steward's CI/CD lane, layered on `agex pr`. Delegates lint / open / |
| 5 | + read / reply / delta to agex; adds two steward extensions — `status` |
| 6 | + (SonarCloud quality gate + hotspots + unresolved-thread tally) and |
| 7 | + `await` (read --wait + status with non-zero exit on Sonar ERROR or |
| 8 | + unresolved threads). Use when: creating PRs in steward, handling |
| 9 | + review feedback, polling CI status, or the user says "create PR", |
| 10 | + "review comments", "address feedback", "resolve threads". Renamed |
| 11 | + from `pr-review` in steward 0.7.0; rebased on agex in 0.12.0. |
| 12 | +--- |
| 13 | + |
| 14 | +# CI/CD — Steward edition |
| 15 | + |
| 16 | +> Vendored from steward (canonical upstream: `docs/skill-sources.md`); this copy is owned by lepenseur and may diverge. |
| 17 | +
|
| 18 | +`agex pr` (in `agentculture/agex-cli`) is the upstream for the |
| 19 | +five core PR-lifecycle verbs — `lint`, `open`, `read`, `reply`, |
| 20 | +`delta`. Steward used to vendor parallel scripts for each; in 0.12.0 |
| 21 | +those vendored copies were dropped in favor of delegating to `agex`. |
| 22 | +What's left in this skill is **the steward-specific gating layer**: |
| 23 | + |
| 24 | +- `status` — SonarCloud quality gate, OPEN issues, hotspots, deploy |
| 25 | + preview URL, unresolved-inline-thread tally. |
| 26 | +- `await` — composes `agex pr read --wait` with `status` and gates on |
| 27 | + Sonar `ERROR` / unresolved threads. The single command to run after |
| 28 | + pushing a fix when you want "wake me when this PR is triage-able." |
| 29 | + |
| 30 | +Those two are the steward unique surface today. They're filed as a |
| 31 | +feature ask upstream |
| 32 | +([agex-cli#41](https://github.com/agentculture/agex-cli/issues/41)); |
| 33 | +once they land they migrate out of this skill. |
| 34 | + |
| 35 | +The workflow is encapsulated in `scripts/workflow.sh` — follow that |
| 36 | +(or call `agex pr` directly). |
| 37 | + |
| 38 | +## Prerequisites |
| 39 | + |
| 40 | +Hard requirements: `agex` (>=0.1), `gh` (GitHub CLI), `jq`, `bash`, |
| 41 | +`python3` (stdlib only), `curl` (used by `pr-status.sh`). |
| 42 | + |
| 43 | +Install agex once: |
| 44 | + |
| 45 | +```bash |
| 46 | +uv tool install agex-cli # or: pip install --user agex-cli |
| 47 | +``` |
| 48 | + |
| 49 | +Soft requirement: `PyYAML` is needed **only for suffix mode** of the |
| 50 | +sibling `agent-config` skill, where it parses Culture's server |
| 51 | +manifest. Every `cicd` script works without it; suffix mode prints a |
| 52 | +clear install hint when invoked without it. |
| 53 | + |
| 54 | +Per-machine paths (sibling-project layout) live in |
| 55 | +`.claude/skills.local.yaml`; see the committed `.example` for the |
| 56 | +schema. `agex pr delta` reads the same file. |
| 57 | + |
| 58 | +## How to run |
| 59 | + |
| 60 | +`scripts/workflow.sh` is the entry point. Subcommands: |
| 61 | + |
| 62 | +| Command | What it does | |
| 63 | +|---------|--------------| |
| 64 | +| `workflow.sh lint` | `agex pr lint --exit-on-violation` — portability + alignment-trigger check. | |
| 65 | +| `workflow.sh open [gh-flags]` | `agex pr open --delayed-read`. Creates the PR, then polls 180s for an initial briefing. `--title TITLE` required; body via `--body-file PATH` or stdin. | |
| 66 | +| `workflow.sh read [PR] [--wait N]` | `agex pr read`. One-shot briefing (CI checks, SonarCloud gate + new issues, all comments, next-step footer). Pass `--wait N` to poll up to N seconds for required reviewers. | |
| 67 | +| `workflow.sh reply <PR>` | `agex pr reply <PR>` — batch JSONL replies (stdin) + thread resolve. agex auto-signs from `culture.yaml`. | |
| 68 | +| `workflow.sh delta` | `agex pr delta` — sibling alignment dump. | |
| 69 | +| `workflow.sh status <PR>` | **Steward extension.** `pr-status.sh` — Sonar gate, OPEN issues, hotspots, unresolved-thread breakdown, deploy preview URL. Authoritative gate for `await`. | |
| 70 | +| `workflow.sh await <PR>` | **Steward extension.** `agex pr read --wait` then `status`. Exits non-zero on Sonar ERROR or unresolved threads. Tunables: `STEWARD_PR_AWAIT_WAIT` (default 1800s passed to `--wait`), `STEWARD_PR_AWAIT_SECONDS` (legacy fixed pre-sleep, deprecated). | |
| 71 | +| `workflow.sh help` | Print the list. | |
| 72 | + |
| 73 | +You can also call `agex pr <verb>` directly — `workflow.sh` is a |
| 74 | +typing-saver around the same verbs. The steward `status` and `await` |
| 75 | +extensions only have shell entry points. |
| 76 | + |
| 77 | +The vendored single-comment helper `pr-reply.sh` (plus its |
| 78 | +`_resolve-nick.sh` dependency) is still shipped — pinned by |
| 79 | +`tests/test_pr_reply_signature.py` and `tests/test_resolve_nick.py`, |
| 80 | +and useful when a one-off reply doesn't merit batch JSONL. It is not |
| 81 | +called by `workflow.sh` anymore. The vendored `portability-lint.sh` |
| 82 | +is also still shipped — `steward doctor`'s portability check runs it |
| 83 | +directly against target repos. Both are scheduled for follow-up |
| 84 | +migration to agex. |
| 85 | + |
| 86 | +## Long waits (background polling) |
| 87 | + |
| 88 | +`agex pr read --wait N` polls in-session for up to N seconds. The |
| 89 | +Anthropic prompt cache has a 5-minute TTL; sleeping past it burns |
| 90 | +context every cache miss. Two ways to drive the wait: |
| 91 | + |
| 92 | +- **Synchronous** — `workflow.sh await <PR>` after `gh pr create` / |
| 93 | + `workflow.sh open`. Fine when readiness is expected within ~5 |
| 94 | + minutes. |
| 95 | +- **Asynchronous** — for longer waits, run `agex pr read --wait NNN` |
| 96 | + inside a background subagent (Agent tool, `run_in_background: true`) |
| 97 | + so the main session only pays the cache cost when readiness fires. |
| 98 | + The subagent's only job is to invoke `agex pr read --wait` and echo |
| 99 | + its headline back. The parent triages with `workflow.sh await` |
| 100 | + when the notification arrives. The user can interrupt with |
| 101 | + TaskStop. |
| 102 | + |
| 103 | +This pattern was originally borrowed from sibling repo |
| 104 | +[`agentculture/cfafi`](https://github.com/agentculture/cfafi)'s `poll` |
| 105 | +skill. The async guidance is also filed upstream |
| 106 | +([agex-cli#41](https://github.com/agentculture/agex-cli/issues/41)). |
| 107 | + |
| 108 | +## Conventions |
| 109 | + |
| 110 | +`agex pr` emits a **"Next step:"** footer at the end of every command |
| 111 | +that names the right next verb (the same chain `agex learn cicd` |
| 112 | +documents) — follow that rather than memorizing an order. `workflow.sh |
| 113 | +help` mirrors the verb table when you need the steward-flavored |
| 114 | +extensions (`status`, `await`) on top. |
| 115 | + |
| 116 | +Branch naming: `fix/<desc>`, `feat/<desc>`, `docs/<desc>`, |
| 117 | +`skill/<name>`. PR / comment signature: `- <nick> (Claude)`, where |
| 118 | +`<nick>` is resolved by `agex` from the agent's own `culture.yaml` |
| 119 | +(first agent's `suffix`), falling back to the git-repo basename. agex |
| 120 | +auto-appends the signature on `pr open` and `pr reply` only when the |
| 121 | +body isn't already signed. |
| 122 | + |
| 123 | +## Triage rules |
| 124 | + |
| 125 | +For every comment, decide **FIX** or **PUSHBACK** with reasoning. |
| 126 | + |
| 127 | +Default to **FIX** for: portability complaints (always valid for |
| 128 | +Steward — recurring bug class), test or doc requests, style nits |
| 129 | +aligned with workspace conventions. |
| 130 | + |
| 131 | +Default to **PUSHBACK** for: architecture opinions that conflict with |
| 132 | +workspace `CLAUDE.md` or the all-backends rule; greenfield |
| 133 | +false-positives (e.g. "add tests" before there's any source — defer |
| 134 | +to a later PR, don't refuse). |
| 135 | + |
| 136 | +### Alignment-delta rule |
| 137 | + |
| 138 | +If the PR touches `CLAUDE.md`, `culture.yaml`, or anything under |
| 139 | +`.claude/skills/`, run `workflow.sh delta` **before** declaring FIX or |
| 140 | +PUSHBACK on each comment. Note any sibling that needs a follow-up PR |
| 141 | +and mention it in your reply. |
| 142 | + |
| 143 | +## Greenfield-aware steps |
| 144 | + |
| 145 | +The lint and the workflow script are always-on. Stack-specific steps |
| 146 | +are conditional and currently no-op (greenfield repo): |
| 147 | + |
| 148 | +```bash |
| 149 | +[ -d tests ] && [ -f pyproject.toml ] && uv run pytest tests/ -x -q |
| 150 | +[ -f pyproject.toml ] && bump_version_per_project_convention # see project README |
| 151 | +[ -f .markdownlint-cli2.yaml ] && markdownlint-cli2 "$(git diff --name-only --cached '*.md')" |
| 152 | +``` |
| 153 | + |
| 154 | +Revisit each line as the corresponding stack element actually lands. |
| 155 | +A `pr lint --extra=tests,version,markdown` ask is filed upstream |
| 156 | +([agex-cli#41](https://github.com/agentculture/agex-cli/issues/41)). |
| 157 | + |
| 158 | +## Reply etiquette |
| 159 | + |
| 160 | +Every comment must get a reply — no silent fixes. `agex pr reply` |
| 161 | +includes thread-resolve by default. Reference the review-comment IDs |
| 162 | +in the fix-up commit message. |
| 163 | + |
| 164 | +The `status` extension queries SonarCloud directly (it predates the |
| 165 | +upstream Sonar integration in `agex pr read`). Both surfaces are |
| 166 | +trustworthy — `agex pr read` for display in the briefing, `status` for |
| 167 | +the gate. Steward isn't yet a registered mesh agent, so the |
| 168 | +post-merge IRC ping that Culture's `pr-review` includes is still |
| 169 | +skipped — that returns when Steward joins the mesh. |
0 commit comments