This repository has been archived on 2026-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
orchestrator/docs/r720-agent-team-design.md

41 KiB

R720 Agent Team — Design (v2)

Status: DESIGN LOCKED — ready to build. Not built yet. v5 folded the final plan-review refinements (SQLite BEGIN IMMEDIATE for the compare-and-set §3.3.1; CI denylist defense-in-depth + authenticated-only pass/fail gate + compromised-box honesty §3.3.2; contention reserve + parked-task aging §6.6; backup integrity definition + post-restore reconciliation §6.7; tested rollbacks §7; per-role canaries §6.4; CLI audit/confirm §3.3.1). The design went through 3 GPT-4.1 sh-plan-review cycles (v1, v3, v4); the architecture was stable throughout and remaining grain is now build-time implementation detail captured in the P1/P3 exit gates. No further gate runs by decision; build may begin with Phase 0 / P1. Earlier status: Drafted 2026-06-17. v3 reframes around Adam's clarified north star: the R720 is not just scheduled checkers, it is a self-hosted, human-gated agentic SDLC pipeline (intake -> clarify -> plan -> review -> build -> verify), fed from the Mac harness and tickets, with the scheduled checkers as one task source. v2's roster work becomes "Plane 1"; the pipeline is "Plane 2" and the centerpiece. v4 folds in every v3 plan-review finding: B2 (§3.3.1) and B4 (§3.3.2) resolved with P1/P3 exit gates; B1 billing realism + contention (§6.6); B3/B5/F5 provisioning + rollback + cross-review gate (§7); F1 state durability + backup (§6.7); F2 canary update process (§6.4); F3 service-account lifecycle + F1 backups (§9); F4 runbook incident handling (Phase 6); Q3 escalation ladder (§5); Q1/Q2 in §3.3.1. Ready for a re-run of sh-plan-review. No build until that gate passes and Adam approves.

Extends the sh-secrev pattern (see security-review/DEPLOY-R720.md) from a single security sweep into a small roster of scheduled, unattended agents that check, plan, and (carefully) build, coordinated by a Claude claude -p brain and using GPT / Gemini / DeepSeek where each is the better fit.

This doc is the plan, not a runbook. It deliberately reuses the security agent's proven substrate.

0. Locked decisions (this revision)

# Decision Choice
D1 Headless claude -p under Max Permitted for now (Anthropic pushed the disallowing ToS change to a later, unannounced date). Build the auth path swappable so the cutover is a config flip. See reference_claude_subscription_billing.
D2 Fixer write path Option B: the always-on box stays read-only; it emits a patch + opens an issue, and a trusted org CI workflow (OIDC) applies the patch on a branch and opens the draft PR. No standing write token on the box.
D3 Checker/planner output mode Report + ALARM-only to start. Clean nights post nothing; confirmed criticals alarm Slack; everything else lands in a mode-600 report. No auto-Jira/Notion writes until signal quality is trusted.
D4 Billing/auth resilience Build a billing-mode abstraction now (subscription OAuth default, API-key / Bedrock fallback ready).
D5 aws-posture Resident on the box via IAM Roles Anywhere, with a new step-ca internal CA for automated short-lived leaf-cert rotation (no long-lived AWS key on the box).
D6 Confluence write identity Dedicated confluence-bot Atlassian service account, edit scoped to the IT space only (Confluence API tokens inherit the whole user's permissions, so a scoped service account is how we bound blast radius). Token in ~/secrev.env (mode 600). Costs one Confluence seat.
D7 Confluence agent modes + Mermaid Scheduled = read + recommend only (gaps/staleness into the report, per D3, never auto-writes). On-demand = SSH-invoked from Adam's Mac for an actual write. Mermaid map edits go through ~/.claude/scripts/confluence_mermaid.py (ADF-only, dry-run-default, macro-count + revert-diff guarded).
D8 Two-plane architecture Plane 1 = scheduled checkers (v2 roster), which also act as a task source. Plane 2 = the agentic SDLC task pipeline (the centerpiece). Shared substrate.
D9 Pipeline foundation LangGraph (the open-source library, runs in-process, NOT SaaS) + a local SQLite checkpointer. Durable, resumable graph; interrupt() for the human gate. Reuses the existing stack.
D10 Human-in-the-loop transport Pluggable, all three adapters (Slack Block Kit, GitHub/Jira ticket comments, Claude Code on the Mac); Adam picks the channel per task. A transport-agnostic notify/resume layer maps answers back to the task thread.
D11 Build/verify execution Org CI is the primary sandbox. Builders emit candidate diffs; the Option-B OIDC workflow builds/tests/security-reviews; the verifier agent reads CI results. Keeps the 4GB box light + read-only. Dedicated builder VM only if fast local loops prove necessary.
D12 Observability (LangSmith) Deprecate LangSmith (the SaaS tracer). Keep LangGraph (framework, local). Local JSONL (telemetry.py, already exists) is the default; self-hosted Phoenix optional later. No SaaS dependency.
D13 Task intake Mac harness first (SSH-invoke enqueues onto the box), GitHub issues next (phased).

1. Goal and scope

Stand up a coordinated team of agents on the existing sh-secrev R720 VM that runs unattended on a schedule, operates across every Sea-Haven-Industries org repo automatically, stays cost-bounded, and reports through one alarm channel. Claude (subscription OAuth) coordinates and does deep reasoning; Gemini does broad scans; GPT does adversarial cross-checks; DeepSeek does mechanical code edits.

In scope: read-mostly checkers, a low-blast-radius planner, a resident AWS posture check (D5), and a CI-applied draft-PR fixer (D2). Out of scope: anything interactive or needing back-and-forth, and (per the secrev ethos) any standing write credential on the always-on box.

This does not replace the security review agent; it sits beside it and reuses its plumbing.

2. What we reuse vs. what is new

Reused from sh-secrev as-is: the VM, the systemd-timer model, the OAuth billing path, clean-clone auto-discovery into ~/repo-mirrors (read-only PAT, scrubbed post-fetch; the team scans the same mirrors, it does not re-clone), the budget primitives (per-call + total caps, fail-toward-over-reporting), ALARM-only Slack, mode-600 reports, the anti-complacency canary + coverage-rotation idea, the orchestrator/ rsync deploy, and the non-Claude provider keys in ~/orchestrator/.env.

New: a coordinator runner (agent-team/ dir; entry CLI run-team.py, importable modules stay snake_case per Python rules; the resource/dir name is kebab-case per handbook), per-role prompt/checklist modules each with its own canary, a billing-mode abstraction (D4), the fixer patch -> CI -> draft-PR path (D2), and the step-ca + Roles Anywhere setup for aws-posture (D5).

3. Architecture

systemd timer (shared with secrev — see §8) 
        │
        ▼
  mirror step (reuse sh-secrev discovery) ──► ~/repo-mirrors  (read-only)
        │
        ▼
  COORDINATOR  (claude -p via billing-mode abstraction; read-only tools + Bash to call orchestrator/gh)
        │  shared budget ledger + versioned rotation/coverage state
        ├──────────────┬───────────────┬────────────────┬──────────────┬───────────┐
        ▼              ▼               ▼                ▼              ▼           ▼
   drift checker   dep/CVE checker  doc-drift checker  aws-posture    planner   (each role
   (Gemini scan    (Claude +        (Gemini large-     (Sonnet via    (Claude)   has its own
    + Claude judge)  GPT tiebreak)   context)           Roles Anywhere)           canary)
        │              │               │                │              │
        └──────────────┴───────────────┴────────────────┴──────────────┘
                                   │ structured JSON per agent
                                   ▼
                          coordinator: dedup + prioritize + route
                                   │
        ┌──────────────────────────┼───────────────────────────┐
        ▼                          ▼                            ▼
   Slack ALARM            mode-600 report                 fix-spec queue (D2)
   (confirmed crit)       (everything else;                     │
                           no auto-Jira/Notion yet, D3)          ▼
                                                    FIXER: DeepSeek edit + Claude
                                                    spec + GPT review ──► patch + issue
                                                          │
                                                          ▼  org CI (OIDC) applies patch,
                                                             opens DRAFT PR, runs pre-push
                                                             hooks + CI gates + Claude Code App

Model assignment (matches how orchestrator already splits them): Claude (subscription) = coordinator, deep checks, fix-spec authoring; Gemini 2.5 Pro = broad whole-repo scans; GPT-4.1 = adversarial cross-check / tiebreak / PR review; DeepSeek = mechanical patch writing.

3.1 Billing-mode abstraction (D4)

A single claude_invoke(...) seam selects the Claude auth/billing path from config: subscription (OAuth token, default today), api (metered ANTHROPIC_API_KEY), or bedrock (cross-account Bedrock, already used by secrev for the rare cross-family tiebreak). Switching modes is a config flip, not a code change. The box still pops any stray ANTHROPIC_API_KEY in subscription mode so OAuth cannot be silently overridden.

3.2 Relationship to the LangSmith orchestrator (what stays vs what the R720 hosts)

Two orchestrators coexist after this plan; neither replaces the other. The split is trigger + Claude billing, not capability.

  • LangSmith orchestrator (Mac-hosted, unchanged). The existing orchestrator/ (LangGraph router + memory retriever + Composio connector + LangSmith tracing on the orchestration project) stays the on-demand, interactive delegation path: one task -> retrieve memory -> route -> one agent -> result, API-billed. This is the CLAUDE.md hybrid-delegation path Claude Code uses for cross-family review, large scans, fast coding, and connector actions. It stays one-shot and stateless (Q1: not refactored for persistence).
  • R720 orchestrator (the agent-team coordinator, new). The scheduled, unattended, multi-agent layer: cadence, the coordinator brain, shared budget ledger, versioned rotation/coverage state, the clean-clone mirror corpus, and per-role canaries. Claude work here runs headless under subscription OAuth (Agent SDK), billing-mode-swappable (§3.1).
Component Today (LangSmith orchestrator, Mac) After this plan
Trigger On-demand from Claude Code / CLI + scheduled (systemd timer) and SSH-invoked on-demand, on the R720
Execution shape One task -> one agent (stateless) + multi-agent coordination with shared budget + versioned state (R720)
Claude billing Metered API key Subscription OAuth on the R720 (swappable to api/bedrock per §3.1)
Non-Claude (GPT-4.1 / Gemini / DeepSeek) run.py router, API-billed, LangSmith-traced unchanged in shape — the R720 coordinator calls the local ~/orchestrator/run.py (already rsync'd to the box) for these single-shot sub-tasks, so they keep API billing + LangSmith tracing
Memory retriever + embeddings cache Mac reused read-only by both (the box's rsync'd copy embeds the same memory store)
Composio connector (Slack/Notion/GitHub) Mac reused; the R720 routes Slack/Jira/Notion through it. Confluence stays OUT of the connector — native Atlassian MCP on the Mac for interactive edits, confluence_mermaid.py + REST for the box
Observability LangSmith SaaS tracing (orchestration project) LangSmith deprecated (D12) — local JSONL (telemetry.py) default, self-hosted Phoenix optional. LangGraph framework stays (it is not SaaS)
models.py factories + model-ID constants Mac shared code (rsync'd); single source of truth for both

What does NOT migrate (stays Mac / interactive): the daily-driver Claude Code sessions, the hybrid on-demand delegation, and interactive Confluence edits via the native Atlassian MCP.

What is genuinely NEW on the R720 (not a migration — these never existed in the LangSmith orchestrator): scheduling, the coordinator + shared state/budget, canary/coverage, and subscription-OAuth Claude.

Net: the LangSmith orchestrator keeps its job (on-demand routing, non-Claude execution, tracing, connector); the R720 becomes the host for everything scheduled, stateful, and subscription-billed, and it reuses the LangSmith orchestrator in place (the local rsync'd copy) for the non-Claude single-shots rather than re-implementing them.

3.3 Plane 2 — the agentic SDLC pipeline (the centerpiece)

A durable, human-gated task pipeline hosted on the R720. A task is a long-lived, resumable record; the coordinator drives it through stages, asking Adam for input when it is not confident and handing off to the org CI to actually build and verify.

INTAKE ─► CLARIFIER ─► PLANNER ─► REVIEW LOOP ─► BUILDERS ─► VERIFIERS ─► draft PR + report
  │          │            │            │              │            │
Mac harness  asks Adam    phased plan  GPT-4.1 +      Claude spec  org CI builds/tests/
(SSH-invoke) question-    (Claude)     multi-model    + DeepSeek   security-review;
GitHub issue sets until                adversarial;   edits ─►     verifier reads results;
checker      98%+, then                loops back     candidate    loops back to builders
finding      HUMAN GATE   	          to planner     diff         on failure

Stages and model per stage:

  • Intake — a task enters from the Mac harness (D13, first), a GitHub issue (next), or a Plane-1 checker finding. It is written as a new task record (LangGraph thread) with a unique thread_id.
  • Clarifier (Claude) — gathers context (repo, memory, handbook), then asks Adam question-sets until 98%+ confident. This is a LangGraph interrupt(): the task suspends and checkpoints, a question-set is delivered over the chosen transport (D10), and the task resumes via Command(resume=...) when the answer arrives. The human gate: no progression to build without the clarifier clearing the bar and Adam approving the plan.
  • Planner (Claude) — produces a phased plan (the format these design docs use).
  • Review loop (GPT-4.1 + optional multi-model) — adversarial plan review (the sh-plan-review / cross_reviewer discipline). Loops back to the planner on REQUEST CHANGES; escalates to Adam if it cannot converge.
  • Builders (Claude spec + DeepSeek edits) — turn the approved plan into a candidate diff. They do not write to repos; per D2/D11 they emit the diff for CI.
  • Verifiers (org CI + a Claude/GPT reader) — CI (Option-B OIDC) applies the diff on a branch, builds, runs tests + the security review + lint; the verifier agent reads the CI results and either loops back to builders or advances. Confirmed pass produces a draft PR plus a report to Adam.

Durable state (D9). LangGraph (local) + a SQLite checkpointer. Each stage transition is checkpointed, so a crash, a budget pause, or an overnight wait on a human answer all resume cleanly instead of restarting. The task record holds: status, current phase, the full Q&A history, the plan, review verdicts, the candidate diff, and CI results.

Human-in-the-loop (D10). A small transport-agnostic responder service owns the notify+resume seam: it posts the interrupt's question-set to the channel Adam chose for that task (Slack Block Kit / ticket comment / a Claude Code session) and maps his reply back to the right thread_id to resume it. Adapters are independent so one can ship first (Slack) and the others follow.

Stability + autonomy bounds (the "stable" requirement). Hard gates, not vibes: (1) no build before the clarifier hits 98% AND Adam approves the plan; (2) draft PRs only, never auto-merge; (3) the verifier must pass or the task loops/holds, never ships; (4) per-task budget cap inside the shared nightly cap (§6.1); (5) every stage checkpointed so failures resume, not restart; (6) a task that stalls (no human answer within a window, or N failed build loops) parks and ALARMs rather than spinning. Plane-1's canary/coverage discipline applies to the pipeline's agents too.

3.3.1 Durable human-in-the-loop suspend/resume (resolves B2)

LangGraph interrupt() + the SQLite checkpointer suspend and resume the graph, but the checkpoint alone does not track the human-interaction lifecycle (delivery, duplicate/late answers, expiry). So the pipeline adds one durable source of truth, a SQLite pending_questions table, and resolves every race with an atomic compare-and-set against it. This is the riskiest mechanic, so it is specified here and P1 must prove it.

  • Identity. Each task is a graph thread_id. Each question-set gets a question_id (uuid) and a monotonic turn within the task. The interrupt payload carries {thread_id, question_id, turn, question_set, transport, deadline}.
  • Ledger. pending_questions(question_id PK, thread_id, turn, status[open|answered|expired|superseded], transport, channel_ref, posted_at, deadline_at, answer_json, answered_at, answered_via). The LangGraph checkpoint holds graph state; this table holds the question lifecycle and is what delivery, the responder, and recovery read.
  • Delivery (and lost-post). On interrupt, write the row open first, then post to the chosen transport and store its channel_ref (Slack message ts / issue-comment id / Claude session id). The posted question embeds the question_id (Slack callback_id; a <!-- shq:<question_id> --> marker in a GitHub comment). If the post fails, the row stays open with no ref and a reconcile loop retries idempotently.
  • Answer mapping + idempotency (first-answer-wins). Each transport's inbound adapter normalizes an answer to (question_id, answer, via). The responder then runs one atomic statement: UPDATE pending_questions SET status='answered', answer_json=?, answered_via=? WHERE question_id=? AND status='open'. rowcount 1 = first valid answer, enqueue a resume job; rowcount 0 = the question was not open (already answered/expired/superseded), so the answer is a duplicate or late and is ignored with a "already closed" reply. This single compare-and-set makes duplicate clicks, transport redelivery, answers via two channels, and answer-after-timeout all safe. The statement runs inside a BEGIN IMMEDIATE transaction (SQLite's default deferred isolation does not serialize concurrent responders, so the check-and-set must take the write lock up front).
  • Resume (single-flight, turn-guarded). A resume worker serializes per thread_id and calls graph.invoke(Command(resume=answer), {configurable:{thread_id}}). Before resuming it checks the live checkpoint is still interrupted on this turn; if the graph already advanced (stale/redelivered job) it marks the question superseded and skips. A resume can never double-apply.
  • Deadline / no-answer. Each open question has deadline_at. A timer loop flips overdue open rows to expired (same compare-and-set) and applies the task policy: park + ALARM Adam, or apply a defined default answer. An answer arriving for an already-expired question loses the compare-and-set and is ignored. Timeout vs answer is a deterministic race on flipping open.
  • Restart recovery. All state is durable (both SQLite stores), so a reboot converges via a startup sweep: retry delivery for open rows lacking a ref; re-enqueue resume for answered rows whose graph is still interrupted on that turn (idempotent via the turn guard); run the deadline policy for overdue open rows. No in-memory-only state.
  • Parallel tasks + isolation (Q1). Each task is its own thread_id with its own checkpoint and ledger rows; the resume worker serializes per thread but runs different threads concurrently within the budget cap.
  • Manual path. A small CLI over the ledger lets an operator list open/parked questions, re-deliver, force-expire, or answer on a task's behalf; a stuck task parks rather than spins. Destructive CLI actions (force-expire, answer-on-behalf, force-resume) are audit-logged and require an explicit confirmation flag.
  • Transport seam (Q2 fallback). A Transport interface (post_question(...) -> channel_ref, parse_answer(raw) -> (question_id, answer, via)) with Slack / GitHub / Claude Code adapters; the ledger + resume logic are transport-independent. Adam picks the channel per task at intake. If the chosen transport is unreachable, reconcile retries and, after N failures, falls back to a Slack ALARM pointing at the task.

3.3.2 CI-as-verifier trust boundary (resolves B4)

The builders are semi-trusted at best: an LLM that read repo content can be wrong or prompt-injected, so the candidate diff is treated as untrusted code. The threat is that executing it in CI with org credentials lets a bad diff exfiltrate secrets, assume the deploy role, or tamper with other repos. Five boundaries bound it:

  1. Split CI: untrusted execution is credential-less; privileged steps never see the patch. The job that checks out and runs the diff (install/build/test) runs with permissions: contents: read, no secrets, no OIDC, no write token, and restricted network egress. The patch executes only here, where there is nothing to steal and nothing to assume. Any privileged action (the OIDC role, authoritative status, opening the PR) runs in a separate job that does not check out or execute patch-controlled code; it consumes the build/test report as data only. This is the standard untrusted-code-in-CI ("pwn request") mitigation, so the workflow must NOT use pull_request_target with a checkout of the head ref.
  2. The patch may not touch the trust-control surface. A box-side check and a CI guard both reject any candidate diff that modifies .github/workflows/**, IAM/policy/permission IaC (CDK/SAM), branch-protection / CODEOWNERS / Dependabot config, or files outside the task's declared scope. Such a diff is escalated to mandatory human review + GPT cross-review, never auto-built (those files are the mandatory-cross-review surface regardless). The match is not naive: enforcement is a CI-side hard fail (not only the box check), it resolves symlinks and canonicalizes paths, and it rejects renames into denied paths and build steps that generate files into them, so a path match cannot be bypassed by indirection.
  3. Diff integrity, box to CI. The builder hashes the candidate diff and records the hash in the task ledger. The box has no write token (D2), so the diff reaches CI as a signed artifact / via a short-lived single-purpose token that can only create the agent branch; CI verifies the diff hash matches the ledger before applying. A tampered or substituted diff fails the hash check.
  4. Pass/fail is a pure-code gate over authenticated CI results, not the LLM verifier. Mirroring secrev's "one pure-code script owns the block decision," a deterministic gate reads the CI run conclusion via the GitHub Checks/Actions API (authenticated as the box read-only PAT), keyed to the specific run id + diff hash. It consumes only that authenticated, patch-independent conclusion; it never trusts a success/failure file or artifact the patch could have written. The verifier agent only reads failures to propose the next fix; it cannot declare success.
  5. Branch protection is the final enforcement. The draft PR targets a protected branch; the locked-down build/test/security-review are required status checks; merge needs them green plus the security-review, the Claude Code App review, and human approval. The agent never auto-merges (D2).

The CI apply/verify workflow is itself IaC + untrusted-input handling, so before it ships it goes through /sh-security-review and the mandatory GPT-4.1 cross-review (in P3), and its actions are SHA-pinned per the handbook Pinning Principle. Provenance (diff hash, CI run id, checks consumed, gate decision) is recorded per task; a diff that tried to touch the denylist, a build job that attempted egress, or a checks/hash mismatch is an ALARM. Egress restriction in the untrusted job is enforced at the runner level (a harden-runner-style egress policy or a self-hosted-runner network deny), but the primary mitigation is that the job holds no secrets, so a successful exfil yields nothing of value.

Threat-model honesty (the diff-hash does not cover a compromised box). The hash protects the box->CI transit (tamper/substitution), not a box that is itself compromised: the box is in the trusted computing base for what it proposes. The real backstops against a bad box are the credential-less build job, the trust-control-surface denylist, and above all the human review of the draft PR plus required checks (nothing merges without Adam). A signed-artifact/attestation step hardens transit further but is not claimed to defend a compromised box.

4. Roster

Tier 1 — checkers (read-only)

Agent Models Cadence Output / gate
compliance-drift Gemini scan + Claude judge nightly Drift vs engineering-handbook (naming, secrets placement, CI/CD present, Dependabot, branch protection). Report + Slack ALARM on violations (no auto-Jira yet, D3)
dependency-cve Claude + GPT tiebreak nightly Cross-ref lockfiles vs advisories org-wide; report + feed fixer. Complements Dependabot
doc-drift Gemini (large context) weekly Flags repos whose architecture moved but Confluence/README did not

Tier 2 — aws-posture (resident, D5) + planner

Agent Models Cadence Output
aws-posture Sonnet collectors + judge weekly Idle/anomalous spend (≈$330/mo flagged) + reasoning layer over baseline findings. Auths via Roles Anywhere (short-lived leaf certs, auto-rotated by step-ca). Complements existing GuardDuty/Security Hub/Config, does not replace them
plan-groomer Claude weekly Drafts a groomed weekly plan into the mode-600 report for now (D3); auto-write to Notion/Jira is a later toggle once trusted
confluence-doc Gemini scan + Claude judge weekly (scheduled) + on-demand Scheduled: diffs repos + AWS inventory + the page-ID map (project_confluence_migration) against Confluence, reports doc gaps / stale pages / missing runbooks (recommend-only, D3). On-demand (SSH-invoked): performs an actual update, including Mermaid map edits via confluence_mermaid.py. Writes as the IT-space-scoped confluence-bot (D6). Overlaps the existing sh-confluence-audit/sh-confluence skills; the box adds unattended cross-repo scope + the tested Mermaid script

Tier 3 — fixer (D2)

Agent Models Trigger Output
fixer DeepSeek edit + Claude spec + GPT review on a confirmed, low-risk finding Emits a patch + opens an issue; org CI applies it and opens a draft PR. Never auto-merges; pre-push hooks + CI + Claude Code App gate it (F3)

5. Coordination model

Nightly, after the mirror refresh, the coordinator: (1) loads the shared budget ledger and the versioned rotation/coverage state (F1); (2) runs the canary suite first, one planted-fault corpus per role, a miss is a COMPLACENCY ALARM and that role is skipped; (3) fans out the scheduled agents over the mirrors, each with a per-call cap, all drawing from one shared total cap (critical for the Claude subscription draw, §6.1), with budget-exhausted roles deferred via the rotation pointer (never dropped) and a COVERAGE ALARM if a role slips past MAX_CYCLE_NIGHTS; (4) collects each agent's structured JSON, dedups across agents, prioritizes; (5) routes per D3: Slack ALARM for confirmed criticals, everything else to the mode-600 report, and fix-specs to the fixer queue if Tier 3 is enabled; (6) a fully clean night posts nothing.

Escalation ladder (resolves Q3). A confirmed critical that stays unaddressed escalates beyond a one-shot Slack ALARM: it re-alarms on a backoff each night it persists, and after N nights (default 3) the coordinator opens a tracking Jira ticket (INFRA) so it cannot quietly linger. The same ladder applies to a COMPLACENCY or COVERAGE alarm that does not clear. Escalation stays ALARM-only in spirit (nothing posts on a clean state).

The coordinator holds its own state; it does not rely on the orchestrator (one-shot, stateless). It may call orchestrator/run.py for GPT/Gemini/DeepSeek single-shot sub-tasks, or call those providers directly (Q1: the team implements its own coordination; the orchestrator is not refactored for persistence).

6. Constraints and how this revision answers them

6.1 Subscription billing draw — shared cap (B1 resolved by D1/D4)

Headless under Max is permitted for now (D1). Every Claude SDK call still draws from the same Max pool as interactive Claude Code, so the team runs under one shared nightly cap across all agents, and pushes volume to Gemini/GPT/DeepSeek (own-account billing) where quality allows. The billing-mode abstraction (D4) lets us flip to api/bedrock when the ToS cutover lands. ANTHROPIC_API_KEY stays unset in subscription mode.

6.2 Fixer write path (B2 resolved by D2)

Box stays read-only; CI applies the patch and opens the draft PR. The CI workflow + its OIDC role is new IAM and goes through the mandatory GPT-4.1 cross-review before it is built (§7, B3).

6.3 step-ca + Roles Anywhere (D5)

New internal CA (step-ca) issues short-lived leaf certs auto-renewed by a systemd timer; the Roles Anywhere trust anchor + the read-only AWS role are new IAM and go through the mandatory cross-review before build (B3). The leaf is short-lived (self-expiring), which is stronger than the box's long-lived GitHub PAT.

6.4 Anti-complacency per role

Each agent ships with its own canary corpus, versioned in the repo. A role with a failing/stale canary is skipped with a COMPLACENCY ALARM, never run silently degraded. Canary update process (resolves F2): canary corpora are version-controlled per agent/role (no shared global corpus, to avoid cross-role confusion); a change to any canary goes through a PR + review with a revert point, and because the canary runs every night, a canary edit that silently weakens recall is itself caught on the next run.

6.5 Host capacity

4GB / 2 vCPU / 40GB. Work is I/O-bound, but more report history + step-ca may pressure disk. Re-check headroom after Phase 1; size up the Hyper-V VM (snapshot first per feedback_ec2_replacement_snapshot discipline) if needed rather than risking the secrev workload.

6.6 Claude budget realism + contention (resolves B1)

A multi-stage pipeline draws far more Claude than a single sweep (clarifier loop + planner + verifier-read per task), all on the same Max pool as Adam's interactive Claude Code. Three controls:

  • Pre-build measurement (gate before P3 builds anything). Using the existing telemetry.py token capture, measure the per-stage Claude token draw on a representative task plus the worst-case clarifier loop, then project per-task and daily aggregate at expected task volume. P1/P2 must emit these numbers before P3 proceeds; the design measures, it does not assume.
  • One shared daily Claude cap across ALL R720 Claude work (pipeline + Plane-1 sweeps), tracked in the persistent budget ledger. Non-Claude stages are pushed to GPT/Gemini/DeepSeek (own-account billing) to keep the Claude draw down.
  • Interactive-first contention rule. Adam's interactive Claude Code is never blocked. The box keeps a reserve headroom; before starting a stage it checks remaining headroom, and if below the reserve it parks new pipeline tasks and ALARMs rather than competing for the pool. A task already mid-flight checkpoints and pauses at the next stage boundary (never killed). A clarifier is capped at N turns per task, then escalates/parks, so an ambiguous task cannot loop-drain the pool.
  • Fairness + no starvation. The reserve is a fixed configured fraction of the daily cap (not guessed at runtime). Parked tasks are FIFO-aged with a MAX_PARK window; a task that exceeds it escalates (ALARM, and a Jira ticket per §5) rather than starving silently, and an operator can force-resume or re-prioritize it via the CLI. A clarifier parked at the turn cap is resumable the same way: Adam adds context and re-opens it, so it is never an indefinite stall.

6.7 State durability + backup (resolves F1)

All durable state (the LangGraph SQLite checkpoint, the pending_questions ledger, the budget ledger, the Plane-1 rotation/coverage pointer) is written atomically (write-temp-then-rename), integrity-checked on load, and included in the nightly offsite backup (mode 600). On corruption the coordinator refuses to proceed silently: the rotation pointer is rebuildable from the report history, and a corrupt task checkpoint parks that task with an ALARM rather than restarting it blindly. "Integrity-checked" is concrete: schema-version match + a stored content hash + a logical-consistency check (e.g. no answered question whose graph is already past that turn). After a restore, a reconciliation step re-syncs against external state (in-flight CI runs, current GitHub PR status) before any task resumes, so a restored backup cannot act on stale external assumptions.

7. Phased rollout (re-sequenced for provisioning order, rollback, cross-review, and docs-as-you-go)

  • Phase 0 — substrate factoring (with rollback, B4). Back up nightly_sweep.sh (tag a revert point); extract discovery/mirror/budget-ledger/rotation/Slack/canary into a shared module used by both secrev and the team. Gate: secrev passes its canary + existing behavior after the refactor, else revert. No team behavior yet.
  • Phase 1 — one checker end to end. Build compliance-drift + its canary + the mode-600 report path + a routing dry-run (F4) for the Slack alarm. Dry-run on the mirrors. Proves the substrate generalizes. Create the project_r720_agent_team memory now (B5/docs-as-you-go).
  • Phase 2 — coordinator + second checker. Add the coordinator (shared budget, dedup, versioned state F1) and dependency-cve. Run a forced budget-squeeze dry-run to prove deferral-not-drop + COVERAGE ALARM (F2).
  • Phase 3 — doc-drift + step-ca/Roles Anywhere + aws-posture. Stand up step-ca and the Roles Anywhere trust anchor + read-only AWS role; cross-review the IAM before building the agent (B3). Wire aws-posture. Add doc-drift.
  • Phase 4 — planner + confluence-doc. plan-groomer writing into the report only (D3). For confluence-doc: create the confluence-bot service account with IT-space-only edit rights (D6), put its token in ~/secrev.env; ship the scheduled gap-detection (read-only, recommend) first, then wire the on-demand SSH-invoked write path. The Mermaid script (~/.claude/scripts/confluence_mermaid.py, already written and offline-tested) must pass a live dry-run against page 1540098 (verify it lists all 16 weweave macros and that a no-op set is clean) before any --apply. Notion/Jira auto-write stays a later toggle.
  • Phase 5 — fixer (D2). Build the org CI apply-and-open-draft-PR workflow; cross-review its OIDC IAM before building (B3). Confirm fixer PRs hit pre-push hooks + CI + Claude Code App (F3). Start with the narrowest fix class (dep bumps). Draft PRs only.
  • Phase 6 — document as standing infra. Update Confluence (the team and the still-undocumented secrev host) in the IT host/LAN inventory; write the operator runbook. The runbook must cover incident handling (resolves F4): pipeline stalls, stuck/parked tasks, failed human-in-the-loop resumes, budget exhaustion mid-pipeline, transport outages, and COMPLACENCY/COVERAGE alarms, each with the manual CLI recovery steps (§3.3.1) and the escalation ladder (§5).

Provisioning + rollback + cross-review gate (resolves B3/B5/F5), applied to every phase:

  • Cross-review is a hard gate, not a note. Any new IAM role/policy, trust anchor, OIDC role, or permission change is provisioned AND passes the mandatory GPT-4.1 cross-review (plus /sh-security-review where it touches the CI / untrusted-input surface) before any code that depends on it is built. A phase cannot start its dependent work until that review is recorded.
  • Every stateful phase has a revert point. Not just Phase 0: before standing up step-ca, the Roles Anywhere trust anchor + AWS role, or the CI apply-workflow, capture a documented rollback (remove the role/CA, restore the prior workflow, revert the cert config) and gate the phase on a successful dry-run. The rollback is exercised (sandbox or simulated teardown/re-provision), not merely written, before the phase is accepted. VM changes snapshot first per feedback_ec2_replacement_snapshot.
  • Docs land with the change, enforced as definition-of-done. A phase is not "done" until its memory entry and the relevant Confluence page are updated; that update is a checklist item in the phase, not deferred (Phase 6 is only the final standing-infra writeup).

7.1 Pipeline track (Plane 2) — depends only on Phase 0 substrate

This track is largely independent of the Plane-1 checker phases (1-6); both build on the Phase 0 substrate. Given the north star, Adam may prioritize this track first. Sequencing within it:

  • Phase P1 — skeleton + the human gate. LangGraph graph + SQLite checkpointer on the box; one trivial task type; Mac SSH-invoke intake; the clarifier with interrupt()/resume over one transport (Slack first). Stops at an approved plan, no build yet. This proves durable suspend/resume across a real human answer (the riskiest mechanic) before anything else. Exit criteria (must demonstrate §3.3.1): (a) kill the box mid-wait and have the task resume after restart; (b) submit a duplicate answer and confirm it no-ops; (c) submit an answer after the deadline expired and confirm it is rejected and the task parked; (d) two tasks suspended concurrently resume independently to the correct thread.
  • Phase P2 — planner + review loop. Wire the planner and the GPT-4.1 review loop (reuse cross_reviewer), including loop-back and the escalate-to-Adam path.
  • Phase P3 — builders + verifier via org CI. Builders emit a candidate diff; the Option-B OIDC workflow builds/tests/security-reviews; the verifier reads CI results and produces a draft PR. Start with the narrowest task class (e.g. a dependency bump or a single-file fix), draft PRs only. Build the §3.3.2 trust boundary: split untrusted/privileged CI jobs, diff-hash integrity, the trust-control-surface denylist, and the pure-code pass/fail gate. The CI apply/verify workflow + its OIDC role go through /sh-security-review AND the mandatory GPT-4.1 cross-review before this phase ships (it is IaC/IAM + untrusted-input handling).
  • Phase P4 — more transports + GitHub intake. Add the ticket-comment and Claude-Code responder adapters (D10) and GitHub-issue intake (D13).
  • Phase P5 — checker findings as a task source. Let a confirmed Plane-1 finding open a pipeline task, closing the loop between the two planes.

Observability for both planes (D12): LangSmith stays off; the existing local JSONL (telemetry.py) covers the LangChain/LangGraph path, the Agent-SDK path keeps its own run logs, and self-hosted Phoenix is an optional later add if per-run trace UI is wanted.

8. Open items folded in (no longer blocking)

  • Shared vs separate timer: shared with secrev (one discovery/mirror pass, one shared budget); error isolation handled by per-role try/skip + canary, documented in the runbook (N2).
  • Read-only PAT sufficiency (Q2): confirm the existing fine-grained PAT covers all mirrors before Phase 1; it already clones every non-archived org repo for secrev, so this is a verification step, not a change.

9. Obligations on build (per global instructions)

  • Memory: project_r720_agent_team created in Phase 1; cross-link project_security_review_agent, project_orchestration_migration, reference_claude_subscription_billing, feedback_cloudwatch_alarms.
  • Confluence: document the team (and secrev) as standing infra (always-on VM holding read-only org PAT + now a Roles Anywhere AWS identity).
  • Handbook/naming: kebab-case dirs/resources (agent-team), snake_case importable Python modules; secrets in .env/Secrets Manager/~/secrev.env (mode 600), never committed; CI/CD for the fixer apply-workflow.
  • Cross-review: the fixer CI OIDC role and the Roles Anywhere trust anchor + AWS read role each go through the mandatory GPT-4.1 cross-review before their phase builds.
  • Service-account lifecycle (F3): the confluence-bot token is rotated on a schedule (90 days, calendared like the GitHub PAT), has a documented revocation step, keeps its edits attributable in Confluence page history, and is decommissioned if the agent is retired.
  • Backups (F1): the durable state stores (checkpoint, ledgers, rotation pointer) are included in the nightly offsite backup.