Clean break, no compatibility alias. Renames the product name, the CLI binary (`ccam` -> `agenthub`), the env var prefix (`CCAM_` -> `AGENTHUB_`), the Prometheus metric namespace (`ccam_*` -> `agenthub_*`), the tmux session prefix (`ccam-lane-<id>` -> `agenthub-lane-<id>`), the per-repo runtime profile directory (`.ccam/profile` -> `.agenthub/profile`), the lanes state root (`~/.claude/ccam-lanes` -> `~/.claude/agenthub-lanes`), the bundled plugins (`plugins/ccam*` -> `plugins/agenthub*`) and their slash commands (`/ccam-doctor` -> `/agenthub-doctor`, `/ccam:*` -> `/agenthub:*`). Because there is no alias, an existing install has to be updated by hand: rename its `.ccam/profile` directory and any `CCAM_*` variables, and reinstall the plugin under its new name. Two other name families are deliberately left alone here, since they are not just strings: the `Claude-Code-Monitor` repository/marketplace name, and the `agent-dashboard` npm package plus its `~/.claude/agent-dashboard` runtime directory, which holds the live database and needs a migration rather than a rename. Verified: server 1406/1406, client 459/459, `grep -i ccam` clean across tracked files, `openapi.yaml` regenerated (95 paths, unchanged count).
5.6 KiB
agenthub ci status — unblock Stage 13's CI-wait half
Status: approved 2026-08-25.
Problem
ship-feature-lane's Stage 13 (post-merge verification) is hardcoded
skipped. Two integrations gate it: dev-CI-wait (watch CI on development
after a PR merges, before QCing the deployed site) and dev-QC (QC the
deployed site). Neither exists yet.
This spec covers only the CI-wait half. agenthub lanes integration ci_wait
already exists (server/lib/lane-profile.js:isIntegrationEnabled,
bin/agenthub.js:cmdLanesIntegration) and reports whether a profile wants the
integration on — but nothing acts on it. agenthub ci doesn't exist
(skills/ship-feature-lane/SKILL.md:167 notes this explicitly at Stage 10,
where the skill falls back to raw gh pr checks/gh run view).
Dev-QC (QCing the deployed site) is a separate, later task — out of scope here. Stage 13's dev-QC half stays noted as unavailable until that lands.
Approach
A read-only status snapshot, not a wait loop. Per the project's
orchestration doctrine (docs/LANES.md § "Orchestration: what AgentHub does NOT
do" — no chaining, no queue, no retry logic), agenthub ci status reports a
fact once; it does not poll, block, or retry. The driving skill owns the
poll loop and the fix/escalate decision, the same shape Stage 12 already
uses for watching a PR (sleep 300 backgrounded, re-invoked per iteration).
This also means agenthub ci status needs no flake classification. Stage 10
already does that triage (infra/flake signature vs. real failure) reading
gh output directly — Stage 13 reuses the same triage, now reading this
command's structured JSON instead of raw gh.
Server-backed, following the sync-base pattern, not a CLI-local gh
spawn. Every existing agenthub command is a thin HTTP client — no command in
bin/agenthub.js spawns a child process directly (worktree.js's git()
helper is the only child-process boundary AgentHub has today, always
server-side). A new server/lib/gh.js mirrors that helper:
async function gh(cwd, args) { /* execFile("gh", args, { cwd }) */ }
New route: GET /api/lanes/:id/ci/status?ref=<branch-or-sha>
- Resolves the lane's
cwd(same lookup every other lane route uses). - Runs
gh run list --branch <ref> --json databaseId,conclusion,status,url --limit 1to find the latest run for that ref, thengh run view <id> --json jobsfor per-job conclusions. (Asharef:gh run listaccepts a commit SHA via--commit, not--branch— the route tries--branchfirst and falls back to--commitif the ref doesn't look like a branch name a lane would use, i.e. it's a 7-40 char hex string.) - No run found for the ref at all →
state: "pending"(CI hasn't started yet, not an error). ghmissing or not authenticated →{ error: { message } }, HTTP 500.
New CLI: agenthub lanes ci status <branch-or-sha> [<lane-id>]
- GETs the route above, prints the JSON, sets
process.exitCode. - Resolves the lane the same way every other
agenthub lanes <verb>command does (resolveLaneArg), so it works with an implicit lane-from-cwd or an explicit id, matchingagenthub lanes integration.
Response shape
{
"state": "success",
"ref": "a1b2c3d",
"checks": [
{ "name": "server-tests", "conclusion": "failure", "url": "https://github.com/.../runs/123" }
]
}
state is derived, never taken from a single field: any job still
in_progress/queued → pending; else any failure/cancelled/
timed_out → failure; else (success/skipped only) → success.
Exit codes
CLI mirrors the response into a process exit code, same convention as
sync-base's distinct exit codes per outcome:
0—state: "success"1—state: "failure", OR any execution error (ghmissing, lane not found, route error) — printed as✖ ci status → <message>on stderr3—state: "pending"(covers both "checks running" and "no run found yet for this ref")
Skill changes
skills/ship-feature-lane/SKILL.md Stage 13: replace the hardcoded-skip
note with a poll loop mirroring Stage 12's:
- Get the merge SHA:
gh pr view <pr_url> --json mergeCommit -q .mergeCommit.oid. - Loop (
sleep 300,run_in_background: true, bump heartbeat each iteration):agenthub lanes ci status <sha>.pending→ keep waiting.failure→ triage like Stage 10 (gh run viewfor job logs on the same run id returned inchecks[].url), fix + re-enter from Stage 2, or escalate.success→ dev-QC half is still unavailable (separate task) — note that explicitly and proceed to Stage 14, same as today but now honest that CI-wait specifically passed.
- Update
docs/LANES.md: the "Stages currently hardcoded skipped" list (Stage 13 becomes "CI-wait works; dev-QC still off"), theagenthub lanes integrationsection's claim thatci_wait's consumer isn't built, and addagenthub ci statusto the command reference.
Non-goals
- No flake auto-classification or auto-rerun inside
agenthub ci status— stays a dumb fact-reporter; the skill keeps owning that judgment, per AgentHub's no-retry-logic rule. - No change to Stage 10 (PR CI watch) — it keeps using raw
ghdirectly. Reusing this command there is a plausible future cleanup, not required now. - No dev-QC implementation — separate task, tracked independently.
Testing
server/tests— new test for the/api/lanes/:id/ci/statusroute, mockingexecFile/ghoutput for: pending (no run yet), pending (in-progress run), success, failure, andgh-not-found — pattern after the existingsync-baseroute tests.npm run test:serverbefore considering this done.