## What Ports `scripts/gc-maintainer-ops.sh` (425 lines of bash: prepare / check / recover-affinity for stock Gas City rigs) into the Go CLI as **`ao gc prepare|check|recover-affinity`**, per ADR-0016 (skill logic ships in Go via `ao`; shell stays thin glue). **Why:** skills ship via plugin/npx as SKILL.md only — a user without a repo checkout could not run the commands the shipped `using-gc` skill teaches. The skill said "From an AgentOps checkout", which was disclosed but weak. ## Changes - **`cli/internal/gcmaintainer`** — full port: rig/import pin verification, bundled pack-cache resolution, PyYAML-capable python selection, atomic runtime staging, managed check wrappers, skill links into city/rig Codex sinks, macOS LaunchAgent + doctor/status health checks, bounded affinity recovery. Output and refusal-message parity with the shell script (incl. refuse-before-mutation ordering). - **`cli/internal/commands/gc` + `cmd/ao/gc_composition.go`** — cobra module on the shared `clicontract.HostOptions` seam; global `--dry-run` always overrides `--apply`. - **Skills source resolution without a checkout**: `--skills-source` > enclosing agentops checkout > installed skills root (`~/.agents/skills`, `~/.claude/skills`). Existing rigs stay recognized: the `managed-by: agentops gc-maintainer-ops` wrapper marker is unchanged. - **Tests migrated**: `tests/python/test_gc_maintainer_ops.py` (7 cases) → Go L2 tests in `cli/internal/gcmaintainer` with the same fake-`gc` harness, plus module wiring tests. `scripts/check-gc-executor.sh` no longer runs the python suite. - **`scripts/gc-maintainer-ops.sh`** reduced to a thin wrapper exec'ing `ao gc`, pinning `--skills-source` to its checkout to preserve historical semantics (`--ao-bin` now selects the ao binary). - **Docs/projections**: `skills/using-gc/SKILL.md` now teaches `ao gc ...`; codex, gemini, and executor-pack projections regenerated via their owning generators; spine/COMMANDS.md/surface artifacts regenerated. ## Verification - `go build ./... && go vet ./... && go test ./...` — 2923 passed, 73 packages - `golangci-lint run` on new/touched packages — clean - `shellcheck -S warning` on wrapper + gate script — clean - `bash scripts/check-gc-executor.sh` — OK - Smoke: built `ao`, ran wrapper → `ao gc` delegation end-to-end
4.9 KiB
Gas City reliability boundary
AgentOps ships skills, evidence contracts, and small operational guidance, not an orchestration backend or a competing Gas City pack.
| Fact | Authority |
|---|---|
| Work and dependency readiness | Beads |
| Sessions, routing, formulas, scoped control dispatch, dashboard/API, OTEL | official Gas City |
| Pack discovery and resolved import locks | Gas City registries and packs.lock |
| Candidate identity | Git commit and tree |
| Semantic acceptance | AgentOps subject-manifest.v1 and verdict.v2 |
| Pull request, hosted checks, merge | GitHub |
Caller-owned work flows through the upstream pack selected by the operator.
AgentOps prefers the official gascity build pack used by Maintainer City, but
also supports the Agentic Coding Flywheel as an independent factory choice.
Agents inside either factory consume AgentOps skills through their provider
runtime's normal skill discovery.
Operational guidance must remain bounded. It may install a pinned upstream pack, configure providers, invoke native commands, observe runs, and stop a city. It must not mirror Beads, Gas City, Git, or GitHub state in an AgentOps schema family, daemon, reducer, receipt graph, formula, or role pack.
For Gas City, install the registry-pinned gascity workflow at city scope and
its sibling role pack at rig scope, preserving the stock gc.* namespace.
Every graph-owning scope retains an unsuspended
core.control-dispatcher. The upstream gc.mayor skill and
gc.run-operator own guided coordination and formula launch.
AgentOps-owned operational adapter
The supported adapter is the shipped CLI command family ao gc
(scripts/gc-maintainer-ops.sh remains as a thin compatibility wrapper over
it). It has three deliberately narrow operations:
prepareverifies the accepted official workflow and rig-role commit, snapshots upstream validation assets unchanged under the selected rig's ignored.gcruntime, installs AgentOps-owned check-path wrappers, selects an already available PyYAML-capable Python, and links AgentOps skills into the city and rig provider sinks;checkreplays the same pin/runtime/skill/service/Doctor checks without writing adapter files or issuing state-changing Gas City commands;recover-affinityis dry-run by default and can clear only a ready formula bead's stale required-session assignee when explicitly passed--apply.
This is not a pack, formula, role, daemon, supervisor, or GC compatibility fork. The contained runtime keeps the official maintainer bytes and directory shape intact so its validator finds its own schemas. AgentOps owns only the wrappers that place those official checks at the rig-local paths declared by the formula. A foreign file at one of those paths is a conflict; preparation fails rather than replacing it.
The adapter does not install PyYAML, edit LaunchAgents, kill processes, restart
the supervisor, patch managed hooks, close beads, re-sling work, or reinterpret
GC outcomes. These operations either belong to the host operator or to Gas
City. On macOS, check fails if an existing supervisor LaunchAgent points to a
missing or different GC binary, preventing the login/reboot failure from being
discovered after a run.
Compatibility qualification uses deterministic toolchain, registry, import lock, config, formula, scoped-dispatcher, and worktree checks before any model session. A live canary is disposable, uses required OTEL, and is repaired only from outside Gas City. It qualifies the selected upstream pack plus AgentOps skill availability; it does not qualify an AgentOps-owned factory.
The 1.4 maintainer canary established additional operational boundaries:
- formula artifact gates require a rig-local check surface even though the implementation lives in the upstream pack;
- skill links prove availability, not invocation, and free-form source-bead skill requirements are not necessarily propagated into decomposed work;
- a workflow root can pass while its caller-owned input bead stays open;
- disabled publishing is a successful no-op and leaves the approved commit in its source anchor;
- a drained session can remain on a future affinity-bound bead, so recovery clears that one ready assignee rather than re-slinging the workflow;
gc statuscan disagree withgc session list; roster/pane evidence governs liveness, bead/run state governs workflow progress, and Doctor governs city metabolism.
Doctor warnings for upstream formula deprecations, managed-hook projection drift, local-only backup, retention, or unused local providers stay visible. The adapter does not downgrade them to PASS or claim that a successful canary proves heavy-load readiness.
Development is two-speed by design. The offline unit and lint contract is the inner loop. Native import, formula preview and route, doctor, and quiescent teardown checks run at a candidate boundary. Live model sessions remain an explicit compatibility test.