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 theorchestrationproject) 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 viaCommand(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_reviewerdiscipline). 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 aquestion_id(uuid) and a monotonicturnwithin 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
openfirst, then post to the chosen transport and store itschannel_ref(Slack message ts / issue-comment id / Claude session id). The posted question embeds thequestion_id(Slackcallback_id; a<!-- shq:<question_id> -->marker in a GitHub comment). If the post fails, the row staysopenwith 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 aBEGIN IMMEDIATEtransaction (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_idand callsgraph.invoke(Command(resume=answer), {configurable:{thread_id}}). Before resuming it checks the live checkpoint is still interrupted on thisturn; if the graph already advanced (stale/redelivered job) it marks the questionsupersededand skips. A resume can never double-apply. - Deadline / no-answer. Each open question has
deadline_at. A timer loop flips overdueopenrows toexpired(same compare-and-set) and applies the task policy: park + ALARM Adam, or apply a defined default answer. An answer arriving for an already-expiredquestion loses the compare-and-set and is ignored. Timeout vs answer is a deterministic race on flippingopen. - Restart recovery. All state is durable (both SQLite stores), so a reboot converges via a startup sweep:
retry delivery for
openrows lacking a ref; re-enqueue resume foransweredrows whose graph is still interrupted on that turn (idempotent via the turn guard); run the deadline policy for overdueopenrows. No in-memory-only state. - Parallel tasks + isolation (Q1). Each task is its own
thread_idwith 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/parkedquestions, 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
Transportinterface (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:
- 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 usepull_request_targetwith a checkout of the head ref. - 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. - 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.
- 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.
- 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.pytoken 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
Nturns 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_PARKwindow; 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 theproject_r720_agent_teammemory 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-groomerwriting into the report only (D3). Forconfluence-doc: create theconfluence-botservice 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-reviewwhere 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-reviewAND 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_teamcreated in Phase 1; cross-linkproject_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-bottoken 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.