Skip to content

Dashecorp Rig — Brain

Fresh-agent entry point. Read this first. One fetch (~57 KB) gives you the repo manifest, deployed surfaces (rig-conductor's 77 endpoints and its built-in Dashboard included), agent instances, primary flows, the frontmatter schema, 45 event types (summary; full schemas at /events.md), a 20-whitepaper catalog, and the current backlog with prior_art links. Every claim traces to its source file in facts/.

Compiled from facts/*.yaml + live GitHub state (gh api /orgs/dashecorp/repos for the repo list; manifest validation for agents). Do not hand-edit BRAIN.md. Regenerate with npm run brain. CI runs --check and fails on drift.

What this is

The Dashecorp rig is an autonomous coding-agent system. A human posts a user story; agents research, propose, code, review, and ship. Canonical docs live in dashecorp/rig-docs (Astro Starlight); operational memory lives in a Postgres + pgvector Memory MCP; deployments are Flux-managed on a 3-node k3s cluster on GCE (invotek-k3s in invotek-github-infra: control plane + 2 STANDARD workers, europe-north1-b).

Published surfaces

Rig landing — discoverable index of all surfaces

  • URL: https://rig.dashecorp.com/
  • Type: html

Canonical brain entry point (this file, rendered)

  • URL: https://docs.rig.dashecorp.com/brain/
  • Raw: https://research.rig.dashecorp.com/BRAIN.md
  • Type: markdown

Brain map — visual architecture + doc-linkage graph

  • URL: https://research.rig.dashecorp.com/map/
  • Type: astro-starlight
  • Note: Two auto-derived diagrams (architecture from facts/, linkage from doc frontmatter) — the shape of what the rig knows, before fetching pages.

LLM site map (research, proposals, user-stories)

  • URL: https://research.rig.dashecorp.com/llms.txt
  • Type: llms-txt

Full content dump (single-shot ingestion)

  • URL: https://research.rig.dashecorp.com/llms-full.txt
  • Type: llms-full-txt

Research, proposals, user-stories (rendered Starlight site)

  • URL: https://research.rig.dashecorp.com/
  • Type: astro-starlight
  • Source: dashecorp/rig-docs

Aggregated engineering docs (architecture, guides, whitepapers, per-repo docs)

  • URL: https://docs.rig.dashecorp.com/
  • Type: mkdocs-material
  • Source: dashecorp/rig-gitops (docs-site/)
  • Note: Built by rig-gitops/scripts/build-docs.sh on push + hourly cron, pulling each repo's docs/ via gh api. Engineering reference, not research (that is research.rig.dashecorp.com).

Sitemap (XML)

  • URL: https://research.rig.dashecorp.com/sitemap-index.xml
  • Type: sitemap-xml

rig-conductor API (/api/*)

  • Type: rest-api
  • Visibility: access-gated
  • Endpoints:
  • POST /api/events — Submit any of the 40+ event types — see /events.md
  • GET /api/assignments/next — Claim next issue assignment. Query: agentId=dev-e-node
  • GET /api/pr-reviews/next — Claim direct-PR review (no issue) for infra/tooling PRs
  • GET /api/pr-reviews/item — Inspect a single PR review item. Query: repo, prNumber
  • POST /api/pr-reviews/merge — Server-side merge gate for direct PR reviews (rc#1028)
  • GET /api/issues — List tracked issues. Query: state=open|done|stuck
  • GET /api/issues/item — Fetch a single issue projection by (repo, issueNumber)
  • GET /api/issues/trace — Per-issue event trace + state transitions for debugging
  • GET /api/stuck-issues — List issues in a non-terminal state for too long (stuck-watcher candidate set)
  • GET /api/releases — Release-note feed (rc#1439) — most-recent 30 posted release notes
  • GET /api/queue — Current dispatch queue state
  • GET /api/usage — Token / cost usage by agent and/or repo. Query: agentId, repo
  • GET /api/costs/issue — Cost for a specific issue. Query: repo, issueNumber
  • GET /api/costs/summary — Aggregate cost. Query: days (default 7)
  • GET /api/costs/daily — Daily cost time series. Query: days
  • GET /api/events/live — SSE stream of live events (for Dashboard.html)
  • GET /api/streams/status — Stream consumer status
  • GET /api/streams/{agentId} — Per-agent stream tail (recent assignment messages). Query: count
  • GET /api/agents — List registered agents (heartbeat + status). Query: archived=true
  • DELETE /api/agents/{agentId} — Forcibly archive a specific agent (admin)
  • DELETE /api/agents/offline — Bulk-archive all agents that are offline (no recent heartbeat)
  • GET /api/agent-capacity — Per-agent capacity / quota / dispatch eligibility snapshot
  • GET /api/agents/heartbeat-softdrops — Heartbeat soft-drop counter, total + per agent (rc#1870, process-local)
  • POST /api/webhook/github — GitHub webhook intake — normalizes GH events into rig-conductor stream
  • POST /api/webhook/flux — Flux deploy confirmation webhook (rc#413 in_deploy → deployed)
  • POST /api/merge — Server-side merge gate
  • POST /api/execution-logs — Create execution log envelope
  • POST /api/execution-logs/{id}/logs — Append log entries
  • POST /api/execution-logs/{id}/steps — Append structured step
  • POST /api/execution-logs/{id}/complete — Mark log complete
  • GET /api/execution-logs/{id} — Fetch log by id
  • GET /api/execution-logs/issue — Logs per issue. Query: repo, issueNumber
  • GET /api/execution-logs — List logs. Query: limit, status
  • GET /api/execution-logs/stats — Turn/cost/token stats per agent. Query: agentId, days, status
  • POST /api/execution-logs/cleanup — Prune old logs
  • GET /api/repo-learnings — Fetch learnings. Query: repo
  • POST /api/repo-learnings — Upsert learning
  • DELETE /api/repo-learnings — Delete learning. Query: repo, key
  • GET /api/guard-blocked — Guard-block counts per agent. Query: agentId
  • GET /healthz — Liveness probe (rc#1522) — rig_control reachability only. 200 / 503
  • GET /health — Liveness probe — always 200 if the process is alive
  • GET /healthz/deep — Deep readiness probe — Marten + Valkey + dependency checks (rc#1188)
  • GET /api/health — Detailed health snapshot for the dashboard (component-level)
  • GET /api/version — Build version + git SHA
  • GET /dashboard — Built-in single-page dashboard (HTML) — Engineering Rig control plane
  • GET /api/events/stream — Single event-stream tail by stream id. Query: id
  • GET /api/events/recent — Recent events across all streams. Query: hours
  • GET /api/main-ci — Main-branch CI status snapshot. Query: repo
  • GET /api/ci-failures — List CI failures across repos. Query: repo, includeAcked
  • POST /api/ci-failures/{repo}/{workflowName}/{runId:long}/ack — Ack a CI failure so it stops showing as active
  • GET /api/main-guard/incidents — Main-guard incidents (rc#1226 + rc#1234). Query: repo, status
  • GET /api/a11y — Accessibility scan results per repo. Query: repo
  • GET /api/stuck-watch — Live stuck-watch snapshot (proxies upstream cluster check)
  • GET /api/stuck-patterns — List active stuck patterns. Query: includeResolved=true for all
  • POST /api/stuck-patterns/{fingerprint}/resolve — Mark a stuck pattern as resolved (writes memory)
  • GET /api/stuck-patterns/brain-section — Generate the ## Known stuck patterns markdown for BRAIN.md
  • GET /api/agent-logs — List recent agent log entries across all agents. Query: count
  • GET /api/agent-logs/{agentId} — Tail recent log entries for one agent. Query: count
  • POST /api/agent-logs — Append a batch of log entries from an agent (push from pod)
  • GET /api/agent-logs/live — SSE stream of live agent log entries
  • GET /api/self-improvement/signatures — Watcher signature states (rc#947): occurrences, OpenIssue, clean-tick counter
  • GET /api/tenancy — Tenancy census (rc#1523) — tenantCount, isMultiTenant, bare tenant ids
  • GET /api/admin/tenants — Tenant roster from the rig_control allowlist (id/name/status/type DTO)
  • POST /api/admin/tenants — Onboard a tenant (B2C grace needs a verified X-Operator-Discord-Id)
  • DELETE /api/admin/tenants/{tenantId} — Tenant erasure — operator-allowlisted, fail-closed, confirmation header
  • POST /api/admin/issues/force-done — Operator force-close an issue's read-model state to Done (admin)
  • POST /api/admin/overrides — Record an operator override event (audit trail)
  • GET /api/admin/overrides — List recent operator overrides for audit
  • POST /api/planner/trigger — Dispatch a planner task (planner agent stream)
  • Note: In-cluster, AND at the edge on rig-conductor.dashecorp.com — that hostname is behind a catch-all Cloudflare Access app (admin email + the cockpit service token) and the ONLY bypass is /api/webhook/github (infra cloudflare/dashecorp.com/access.tf). Exact in-cluster host/port is intentionally not surfaced. There is NO in-process authorization on any /api/ route (zero RequireAuthorization calls in Program.cs): the whole boundary is Access at the edge plus rig-cockpit-worker's operator-session check. Since 2026-09-08 that worker proxies only a small explicit allowlist (src/config/api-allowlist.js), NOT /api/ generically. GPU pod control and /public/* are separate surfaces below.

rig-conductor RunPod GPU pod control (start / stop / status)

  • Type: rest-api
  • Source: dashecorp/rig-conductor (src/ConductorE.Api/Endpoints/RunPodPodEndpoints.cs)
  • Visibility: access-gated
  • Endpoints:
  • POST /api/pods/{name}/start — Volume-first wake onto any acceptable GPU. 200 AlreadyRunning|Started|Created · 202 Waiting (poll again) · 409 Failed · 503 unconfigured · 404 unknown name. Body {name,outcome,podId,gpuId,pricePerHour,proxyUrl,message}
  • POST /api/pods/{name}/stop — Stops EVERY pod on the volume (a stale pod and its replacement can both bill). 200 {name,ok,pods[]} · 404 no pod · 503 unreadable/unconfigured
  • GET /api/pods/{name} — Always 200 except 404 unknown name. {name,configured,status,isRunning,podId,proxyUrl,podsOnVolume,datacenter,lookup,readySince}
  • Note: infra#434 / rig-conductor#2008. Registered by MapRunPodPodEndpoints() outside Program.cs, so the endpoint drift-check misses them. {name} is the friendly pod name (RUNPOD_POD_NAME, default qwen), NEVER a RunPod pod id — the pod is resolved through the network volume, and an unknown name 404s before any RunPod call. isRunning = RUNNING with >= 1 GPU, the only state that serves; proxyUrl is set whenever a pod is named, so check isRunning too. readySince (#2056) = the idle monitor's first vLLM /metrics answer since boot, so isRunning:true + readySince:null is "waking, not usable yet" (in-process — a restart forgets it). Unconfigured (RUNPOD_API_KEY unset OR RUNPOD_VOLUME_ID blank) → 503 on start/stop, 200 configured:false on GET, idle monitor exits at startup. Auth is Cloudflare Access at the edge only; an X-Operator-Discord-Id gate on these cost-incurring writes is proposed, not shipped. rig-cockpit-worker allowlists GET /api/pods/{name} (rcw#86, 2026-09-09) so a client can read pod status; the writes stay refused. The cockpit status tile (rcw#87) and Stop button (rcw#85) are still open, and the iOS app has no chat and no pod surface at all. Config: RUNPOD_VOLUME_ID is the ONLY pod identity (RUNPOD_POD_ID is read nowhere; REST v1 deleted in #2043), plus RUNPOD_TEMPLATE_ID, RUNPOD_DATACENTER_ID=EU-RO-1, RUNPOD_POD_NAME=qwen, IDLE_MINUTES=15, MAX_RUNTIME_MINUTES=360, RUNPOD_BOOT_GRACE_MINUTES=20; code defaults CHECK_SECONDS=60, RUNPOD_POD_PORT=8000, RUNPOD_MIN_VRAM_GB=32, RUNPOD_MAX_PRICE_PER_HOUR=1.00 USD/h, no GPU allowlist. The idle window starts at model-READY, not RUNNING: a pod not ready within RUNPOD_BOOT_GRACE_MINUTES (20) is stopped as a dead model, and MAX_RUNTIME_MINUTES (360) hard-stops any pod up that long regardless of the streak. Full tables: rig-conductor docs/runpod-pod-control.md.

rig-conductor sanitized read-only API (/public/*)

  • Type: rest-api
  • Source: dashecorp/rig-conductor
  • Visibility: access-gated
  • Endpoints:
  • GET /public/agents — id, status, lastHeartbeat, currentRepo only
  • GET /public/issues — Active issues — title, state, GitHub URL only
  • GET /public/streams/status — Per-stream xlen + aggregate pending
  • GET /public/cost-summary — Aggregate daily + weekly cost, no per-agent breakdown. Query: days
  • GET /public/events — SSE feed of sanitized events
  • Note: Designed for a future public rig-dashboard (PublicSanitizer — no secrets, tokens, env vars or internal paths; 60 req/min per IP) but NOT publicly reachable today: rig-conductor.dashecorp.com is fully Access-gated and nothing bypasses Access for /public/ (only /api/webhook/github does). The name is the intent, not the exposure. A separate surface for the sanitization contract — not for a visibility difference from /api/.

rig-conductor Dashboard (the built-in cost/activity UI)

  • Type: html-dashboard
  • Source: dashecorp/rig-conductor (src/ConductorE.Api/Dashboard.html)
  • Visibility: access-gated
  • Note: Served at the root of the Access-gated rig-conductor.dashecorp.com. ~102 KB single-page HTML dashboard, "Engineering Rig — Control Plane" (104,822 bytes on 2026-09-09; the long-quoted "42 KB" is stale). Costs, Issues, Agents, Streams tabs on /api/costs/, /api/usage, /api/issues, /api/streams/. No Grafana/Starlight dashboard is needed — this already renders per-agent / per-issue / per-day cost.

Memory MCP (Postgres + pgvector)

  • Type: mcp-server
  • Package: @dashecorp/rig-memory-mcp
  • Tools:
  • read_memories — Query prior memory by topic/repo/scope with vector similarity
  • write_memory — Persist a new memory with scope/kind/importance/tags
  • mark_used — Increment hit_count on a memory that informed a decision

Discord agent channels (notifications)

  • Type: discord
  • Channels: #dev-e, #review-e, #ibuild-e, #admin
  • Note: Agents post thread updates here; humans watch for stuck / pending state.

Repos

Live from gh api /orgs/dashecorp/repos merged with facts/repos.yaml annotations. Archived repos are dropped automatically.

Repo Purpose Language Depends on AGENTS.md
rig-gitops GitOps manifests (Flux HelmReleases, Kustomize bases) and the canonical AGENTS.md every rig repo imports. Also hosts the aggregated MkDocs b shell compiled
rig-agent-runtime The AI agent runtime (Node) — one image that deploys as Dev-E, Review-E, rig-planner or Rig-E depending on character + environment (prompt/l javascript rig-memory-mcp, rig-conductor imports-rig-gitops
rig-memory-mcp MCP server backing persistent agent memory with Postgres + pgvector. Exposes read_memories / write_memory / mark_used tools consumed b javascript postgres-pgvector claude-md
rig-conductor Event store + dispatch service (C# + Marten + Postgres). Receives PR/issue events, assigns work, tracks turns/cost/stuck state, serves the ` csharp postgres, pgvector imports-rig-gitops
rig-manager Agent runtime, caged executor, verb schemas and the reproducible container build. Its deterministic SHA-256 digest IS the KMS attestation me dockerfile none
rig-docs Research, proposals, user-stories, and rig-wide reference (Astro Starlight). This repo — you're reading its BRAIN.md. Deploys to research.ri astro hand
rig-tools Shell scripts, Git hooks, and workflow sync for AI-assisted development. Developer tooling, not deployed. The one repo without an AGENTS.md shell none
infra OpenTofu for GitHub org settings, Cloudflare (DNS, Pages, tunnels), GCP (the 3-node k3s cluster invotek-k3s — control plane + 2 STANDARD wor hcl imports-rig-gitops

Per-repo doc index (token-efficient discovery)

Before cloning a repo to find docs, consult this list to decide which docs are relevant to your issue. Then fetch raw markdown for only the relevant ones:

gh api repos/dashecorp/<repo>/contents/docs/<file>.md --header 'Accept: application/vnd.github.raw'

Auto-derived per compile via gh api /repos/<r>/contents/docs. Repos without a docs/ dir are omitted.

  • rig-gitops — architecture-current.md, architecture-proposed-v2.md, architecture-proposed.md, documentation-standard.md, onboarding.md, research-multi-agent-platforms.md, review-e-bootstrap.md, sops.md
  • rig-agent-runtime — architecture.md, configuration.md, dashboard.md, deployment.md, discord-setup.md, heartbeat.md, index.md, memory.md, messaging.md, observability.md, quickstart.md, usage-tracking.md
  • rig-memory-mcp — api.md
  • rig-conductor — api.md, architecture.md, deployment.md, event-store.md, index.md, principles.md
  • rig-manager — container.md, reproducible-build.md
  • rig-tools — agent-workflow.md

Agents (deployment instances)

Dev-E — writes code

  • Runtime: dashecorp/rig-agent-runtime
  • Deployed in: k3s on GCE — invotek-k3s 3-node cluster (control plane + 2 STANDARD workers, europe-north1-b, invotek-github-infra)
  • Manifest: dashecorp/rig-gitops/apps/dev-e/
  • Variants:
  • node: apps/dev-e/rig-agent-helmrelease.yaml
  • python: apps/dev-e/python-helmrelease.yaml
  • dotnet: apps/dev-e/dotnet-helmrelease.yaml
  • node-codex: apps/dev-e/rig-agent-helmrelease-codex.yaml
  • python-codex: apps/dev-e/python-helmrelease-codex.yaml
  • dotnet-codex: apps/dev-e/dotnet-helmrelease-codex.yaml
  • Character: baked into HelmRelease values
  • Triggers: signal:dev-e-node/-python/-dotnet (+ -codex) LIST + assignments:dev-e STREAM
  • Notes: SIX instances in namespace dev-e, not three: a claude lane (node = claude-tmux, dotnet + python = claude-cli, all claude-opus-4-7[1m], maxTurns 300) and a codex lane (codex-cli + gpt-5.5, maxTurns 150). Stream-consumed via Valkey, NOT REST polling: each variant's ScaledObject watches its signal: LIST at valkey-primary.rig-conductor.svc.cluster.local:6379 to scale 0→1, then the agent drains assignments:dev-e. KEDA is NOT uniform — dev-e-dotnet-codex is PINNED ON (min = max = 1), dev-e-python-codex is OFF (replicaCount 0 + paused-replicas "0"), the other four scale 0→1. Trust the ScaledObject spec, not its comments: dev-e-node-codex's still claims a paused annotation it no longer has.

Review-E — reviews PRs

  • Runtime: dashecorp/rig-agent-runtime
  • Deployed in: k3s on GCE — invotek-k3s 3-node cluster (namespace review-e)
  • Manifest: dashecorp/rig-gitops/apps/review-e/rig-agent-helmrelease.yaml
  • Triggers: signal:review-e LIST + assignments:review-e STREAM
  • Discord: #review-e
  • Notes: TWO live instances, both in namespace review-e, both replicaCount 1, both with AGENT_ID review-e, both KEDA-scaled on the SAME signal:review-e LIST (an atomic LPOP splits the work): review-e (claude-tmux + claude-sonnet-4-6, maxTurns 150) and review-e-codex (codex-cli + gpt-5.5, maxTurns 75) — parallel since gitops#476 because the codex quota saturates under burst. DISPATCH is Valkey + KEDA, not cron/REST polling (the cron + search_filter are dead code). Because both pods register as review-e, the conductor's quota-split router can never select review-e-codex (it only matches registered agent ids) — and if it ever did, the XADD/LPUSH would land on assignments/signal keys no pod or ScaledObject watches, since both ScaledObjects watch signal:review-e. ROUTING — auto-routed only for dev-e-bot / ibuild-e-bot / dependabot authors, or an orchestrator PR on a rig-internal repo; everything else needs the needs-review label, honoured by the 5-minute ReviewScanService.

Rig-E — read-only tenant chat agent (dashecorp) behind Rig Cockpit

  • Runtime: dashecorp/rig-agent-runtime
  • Deployed in: k3s on GCE — invotek-k3s 3-node cluster (namespace dashecorp, tenantId dashecorp)
  • Manifest: dashecorp/rig-gitops/apps/dashecorp/rig-e-helmrelease.yaml
  • Character: baked into HelmRelease values
  • Triggers: synchronous POST /api/chat — no KEDA ScaledObject, no assignment stream
  • Discord: none — chat-only (messagingPlatform none, rar#659/#660)
  • Notes: LIVE since rig-gitops#712 at replicaCount 1 — chat is synchronous, so no ScaledObject and no scale-to-zero. Surface: Rig Cockpit → rig-cockpit-worker → rig-e.dashecorp.com → Cloudflare tunnel → the pod's POST /api/chat, gated by CHAT_API_TOKEN (infra#442). readOnly true, strict MCP, and its WHOLE tool grant is six conductor GET endpoints (health, agents, streams/status, stuck-issues, issues, events/recent) served as MCP tools by the in-image httptools bridge. Brain = the operator's own GPU: openai-api + Qwen/Qwen2.5-32B-Instruct-AWQ on the on-demand RunPod pod qwen, with NO literal pod URL — llm.baseUrlFrom { conductorPod: qwen, conductorUrl: http://rig-conductor-api.rig-conductor.svc.cluster.local:8080 } (rig-gitops#737, rar#674/#676/#677). llm.timeoutMs 300000 OVERRIDES the runtime's 120 s openai-api default. NO fallbackProviders, deliberately: a fallback would inherit llm.model, so a stopped pod fails loud instead of masking the pod path. Image pinned BY HAND (not one of the 10 auto-pinned files) — tag and baseUrlFrom must move together.

iBuild-E — macOS / iOS builds

  • Runtime: Stig-Johnny/claude-3
  • Deployed in: Mac Mini M4 (Ålesund, Møre og Romsdal — the operator's parents' house, remote-only; on the operator's Tailnet)
  • Manifest: not-in-cluster
  • Discord: #ibuild-e
  • Notes: Does NOT run dashecorp/rig-agent-runtime: it runs the agent-runner bridge from Stig-Johnny/claude-3 as the launchd LaunchAgent ai.invotek.ibuild-e (agent-runner/agents/ibuild-e.json), as the ibuild-e-bot GitHub App. Xcode + App Store Connect; off-cluster because iOS builds need macOS. The site is Ålesund, never Oslo, with NO hands-on access — assume remote-only recovery.

Planner-E — plans sprints, manages backlog, assigns issues to agents

  • Runtime: dashecorp/rig-agent-runtime
  • Deployed in: k3s on GCE — invotek-k3s 3-node cluster (namespace rig-planner)
  • Manifest: dashecorp/rig-gitops/apps/rig-planner/
  • Triggers: signal:rig-planner LIST + assignments:rig-planner STREAM
  • Discord: #planner
  • Notes: GitHub App rig-planner-bot (App ID 3546083) handles issue intake. NOT scaled 0→1: its ScaledObject carries paused-replicas "1" (operator pin 2026-05-14) and the HelmRelease sets replicaCount 1, so it is always-on. It reads signal:rig-planner (LIST) + assignments:rig-planner (STREAM). Provider claude-cli + claude-opus-4-7[1m] (NOT sonnet), maxTurns 50. A second instance rig-planner-codex (codex-cli + gpt-5.5) is OFF (replicaCount 0 + paused-replicas "0"). Persona: /whitepaper/planner/.

Primary flows

PR lifecycle in dashecorp (orchestrator-owned — DO NOT copy legacy personal-org workflow files)

Trigger: A PR in a dashecorp repo authored by dev-e-bot / ibuild-e-bot / dependabot, or an orchestrator (Stig-Johnny) PR on one of the six rig-internal repos. Every other PR is opt-in via the needs-review label, picked up by the 5-minute ReviewScanService backstop, not the webhook.

  1. GitHub — POSTs the webhook to rig-conductor /api/webhook/github (HMAC fail-closed — GITHUB_WEBHOOK_SECRET unset ⇒ 503; every delivery must carry a matching X-Hub-Signature-256)
  2. rig-conductor — Normalizes the PR event, XADDs assignments:{agentId} (group agents) then LPUSHes signal:{agentId}. agentId is ALWAYS review-e today: ReviewDispatchRouter only considers candidates registered as review-e / review-e-codex, and BOTH reviewer pods run AGENT_ID=review-e, so nothing ever registers as codex and the quota-split router falls back to ClaudeReviewerId every time — it stays inert until the codex pod gets its own AGENT_ID. The issue-link rule is ADVISORY: a non-bot PR with no Closes|Fixes|Resolves #N gets a warning comment, then processing continues — nothing blocks dispatch or merge on it
  3. Review-E — Consumes its review assignment from the assignments:review-e Valkey stream (woken by KEDA scaling 0→1 on the signal:review-e list), reviews, posts approval or CHANGES_REQUESTED
  4. rig-conductor (POST /api/merge → MergeGate) — /api/merge does NOT merge — it sets MergeGate's review-approved condition. MergeGate merges on review-approved + ci-passed + NOT blocked, after a fail-closed re-check that every non-skip-listed check_run on the PR's CURRENT head SHA completed success/skipped/neutral. Squash merge, then emits MERGED

Rules: - Do NOT copy the operator's per-repo request-review.yml / auto-merge.yml from legacy personal-org repos into dashecorp repos — that is the pre-conductor pattern, and the conductor owns this lifecycle. If a dashecorp repo isn't reviewed or merged, the fix is configure the GitHub webhook, not add a workflow file. - The operator's personal-org repos keep the per-repo workflow pattern (they predate rig-conductor) until they are archived post-migration. - MergeGate checks three Valkey hash conditions on merge-gate:{repo}#{prNumber}review-approved, ci-passed, NOT blocked. It does not check thread resolution, and the label is do-not-merge, never manual-merge — and that label is INERT (Block()/Unblock() are its only writers and have zero callers). It can merge WITHOUT ci-passed: it merges at once when branch protection reports no required checks, else waits 30 s (MERGE_GATE_WAITING → MERGE_GATE_TIMEOUT) and merges anyway — both paths still pass the head-SHA check_runs guard. Complete when: conductor emits the MERGED event (there is no PR_MERGED type) and downstream consumers (CF Pages, iBuild-E, etc.) react

Epic to merged work

Trigger: Human opens a user-story issue in a serviceable-tenant repo that is NOT rig-internal. Issues in the rig-internal repos (rig-docs, rig-conductor, rig-agent-runtime, rig-gitops, rig-tools, infra, terraform) are SKIPPED as rig_internal_repo — orchestrator work.

  1. rig-conductor — Push-based, not a scan: issues.opened without the agent-ready label LPUSHes signal:rig-planner; issues.labeled with label exactly agent-ready dispatches to an agent. IssueScanService is only a 10-minute backstop for missed webhooks
  2. Dev-E — Reads issue + relevant research; authors research / proposal / code PR
  3. Review-E (stream-consumed via assignments:review-e, KEDA-scaled) — Finds PR, reviews against AGENTS.md + memory, requests changes or approves
  4. Human — Merges (or Review-E's approval satisfies branch protection; auto-merge fires)
  5. Cloudflare Pages — Redeploys research.rig.dashecorp.com and docs.rig.dashecorp.com Complete when: issue closed via `Closes

rig-conductor self-deploy (post-merge image rollout via Flux)

Trigger: A PR merges to dashecorp/rig-conductor main (the MERGED step in the PR lifecycle flow)

  1. GitHub Actions (.github/workflows/publish-image.yml — job publish) — Builds the container and pushes :latest + :sha-<commit> to GHCR and Artifact Registry (europe-north1-docker.pkg.dev/invotek-github-infra/dashecorp/rig-conductor); 3-attempt retry on transient registry / WIF / BuildKit errors
  2. GitHub Actions (job update-gitops, needs publish) — sed-bumps the image tag in deploy/k8s/deployment.yaml to :sha-<commit>, opens a chore: pin rig-conductor image to sha-<sha> PR, validates the diff is exactly the one-line image bump, then admin-merges it
  3. Flux source-controller (GitRepository rig-conductor) — Polls dashecorp/rig-conductor main every 5m and picks up the new deployment.yaml
  4. Flux kustomize-controller (Kustomization rig-conductor-api) — Reconciles every 10m from path: deploy (prune true); the new image (imagePullPolicy Always) rolls the pod

Rules: - paths-ignore: deploy/k8s/deployment.yaml on the workflow stops the pin commit from re-triggering Publish Image (loop guard). The publish build+push is the real success signal — a pin PR that fails because a newer pin already landed is benign supersession (rc#1532), not a failure. - Worst-case propagation is ~15m (5m GitRepository interval + 10m Kustomization interval), not 5m. - The sibling flow for AGENT images is automatic and different: after a successful Build & Push on rig-agent-runtime, rig-conductor's ImagePinDispatchService opens one atomic chore: pin rig-agent-runtime images to <sha> PR on rig-gitops as dev-e-bot, covering EXACTLY 10 HelmReleases — dev-e (node/dotnet/python × claude+codex), review-e (×2), rig-planner (×2). Rig-E, the dashecorp tenant fleet, the stigjohnny fleet and dev-e-staging are NOT covered and are pinned by hand, which is why they drift behind. - Verify a deploy from inside the cluster: kubectl -n rig-conductor exec deploy/rig-conductor-api -- curl -s localhost:8080/api/version (returns the git SHA) and the same for /healthz/deep (200 = Marten + Valkey + deps healthy). Both endpoints are cluster-internal — already in surfaces.yaml. Complete when: the rig-conductor-api pod runs the new sha- image and /healthz/deep passes

GPU brain wake-on-chat (Rig-E → rig-conductor → RunPod pod qwen)

Trigger: An operator chats with Rig-E in Rig Cockpit while the on-demand vLLM pod is stopped (it is OFF by default and bills only while up).

  1. Rig-E (openai-api provider) — Resolves its endpoint from GET /api/pods/qwen (llm.baseUrlFrom). Not running ⇒ providerNotReady — retryable, no fallback; a stopped pod never crashes the boot. The conductor's proxyUrl is accepted only as a bare https origin on an allowed host suffix (default .proxy.runpod.net, widened via llm.baseUrlFrom.allowedHostSuffixes)
  2. Rig-E (chat.js, decideWakeOnNotReady) — POSTs /api/pods/qwen/start fire-and-forget (3 s cap, never throws) and answers HTTP 200 in the normal {reply,sessionId} shape: "Waking the GPU brain — that takes about 9 minutes." Asking again inside the 15-min window reports elapsed minutes and does NOT re-wake; past it, it wakes again; lookup UNREADABLE wakes nothing
  3. rig-conductor (RunPodWakeService) — Volume-first wake on the application lifetime (a 524 at the edge never aborts it; a retry joins the same run): start the pod on the volume, else create a replacement on the cheapest acceptable GPU in the volume's datacenter, terminating the stale sibling only once the replacement is RUNNING — proven live 2026-09-09, and it needs no gitops change
  4. RunPod → RunPodIdleMonitor — Measured 2026-09-09: start 09:37:51Z → RUNNING 09:40:41Z (≈3 min) → model loaded 09:46:57Z (≈6-7 min more, ≈9 min total). The first /metrics success is READY and publishes readySince. The completion runs against {proxyUrl origin}/v1/chat/completions, capped by llm.timeoutMs (Rig-E 300 s, default 120 s), re-resolving ONCE per turn on 404/502/503/504/network
  5. rig-conductor (RunPodIdleMonitor) — Stops the pod 15 min (IDLE_MINUTES) after READY, not after RUNNING (rc#2055/#2056) — the earlier bug billed the model load as idle (usable 8.7 of ~16 billed min). Config + defaults: the pod-control surface above

Rules: - KNOWN GAPS as of 2026-09-09. rar#685 (RUNNING-but-still-loading answered a raw 502 in the very window the user was told to retry) is FIXED and live: rig-agent-runtime#689, shipped to Rig-E as node-sha-418a948 by rig-gitops#749 on 2026-09-09 — that window now answers "The GPU is up and the model is still loading…" and gives up after 20 minutes. Still open: rar#684 — a timed-out start POST logs requested=false although the wake proceeds; rig-conductor#2058 — a conductor rollout mid-wake loses the tail; rig-cockpit-worker#87 — the cockpit GPU status tile, and #85 — the Stop button (the read route is allowlisted, rcw#86). Complete when: GET /api/pods/qwen reports isRunning true with a non-null readySince and the turn answers; the pod stops itself 15 min after the last request

Research and proposal authoring

Trigger: An Epic needs investigation before implementation

  1. author dated research/YYYY-MM-DD-slug.md with user_story frontmatter
  2. author proposals/YYYY-MM-DD-slug.md with source_research frontmatter
  3. user_story file gets research_docs and proposal fields pointing back
  4. RelatedDocs component auto-renders the graph; no manual cross-linking

Rules: - bidirectional links required - schema enforced in src/content.config.ts - CI rejects PRs missing required fields

Cold-start agent session

Trigger: Fresh agent with blank memory receives an Epic or task

  1. WebFetch https://research.rig.dashecorp.com/brain/ (or raw BRAIN.md)
  2. Parse facts/repos.yaml equivalent in BRAIN.md — learn repo manifest
  3. Parse facts/surfaces.yaml equivalent — learn URLs and endpoints
  4. WebFetch https://research.rig.dashecorp.com/llms.txt for topic index
  5. WebFetch relevant research/proposal docs directly via raw URL
  6. For the target repo, fetch its AGENTS.md (compiled or imports-rig-gitops)
  7. read_memories scoped to repo + topic via Memory MCP
  8. Begin work with full context in ~15 KB total Token budget: ~15 KB read, leaves 200K+ for actual work on Opus

Docs-memory promotion (weekly Lint)

Trigger: Weekly scheduled Lint job

  1. Scan Memory MCP for rows with importance >= 4 AND hit_count >= 5
  2. For each candidate, check if docs already cover the topic (BM25 sim)
  3. If not covered, propose a docs PR with the memory content promoted
  4. Human approves PR, merge triggers redeploy Status: not-yet-built (design in research/2026-04-18-docs-memory-drift-lint)

Diagram-as-code authoring

Trigger: A research / proposal / user-story needs a diagram Rule: Mermaid source inline in fenced code block. No PNG or SVG ever committed. Rendering: remark-mermaid plugin wraps in <figure> with <pre class=mermaid> and <details> source; mermaid.js renders client-side; source preserved post-render for agent readers.

Frontmatter schema (for authoring rig-docs content)

  • type (optional): one of research | proposal | decision | postmortem | reference | user-story | runbook
  • audience (optional): one of human | agent | both — not a free-form array
  • Required: title, description
  • Optional linkage fields (paths are relative to src/content/docs/, no leading slash, no .md or .mdx extension):
  • type — See type enum above.
  • subtype — See subtype enum above (whitepapers only).
  • audience — See audience enum above.
  • created — ISO date string YYYY-MM-DD.
  • updated — ISO date string YYYY-MM-DD.
  • topic — Short slug grouping related docs.
  • source_refs — Array of external source URLs.
  • supersedes — Path to the doc this replaces (no leading slash, no extension).
  • superseded_by — Path to the newer doc replacing this.
  • user_story — (research/proposal) Path to the user story this supports.
  • research_docs — (user-story) Research doc paths this story spawned.
  • proposal — (user-story) Path to the proposal answering this story.
  • source_research — (proposal) Research paths this proposal synthesises.
  • github_issue — (user-story only) Full GitHub issue URL. Omit entirely if none — never an empty string.
  • whitepaper — (user-story) Whitepaper slug this story supports — filename without extension. Rolls up story counts in the sidebar.
  • whitepapers — (user-story) List form of whitepaper: — inline [a, b] or block list; counts on each paper's badge. Both keys together is tolerated (merged, deduped).

Path examples: user-stories/2026-04-18-docs-memory-strategy, research/2026-04-18-docs-tools-evaluation, proposals/2026-04-18-docs-tooling-decision, decisions/2026-04-18-docs-tooling-decision.

Omit a field entirely when it has no value — do not use empty string.

Whitepapers (private — catalog only)

These whitepapers live at dashecorp/rig-gitops/docs/whitepaper/*.md (private repo — requires gh auth to fetch). BRAIN.md surfaces their titles + 1-line summaries so agents know what exists. Full content must be fetched with: gh api /repos/dashecorp/rig-gitops/contents/docs/whitepaper/<file> --jq .download_url | xargs curl -sL.

  • Whitepaper index (index.md) — Entry point listing every whitepaper section and companion doc.
  • MVP scope (mvp-scope.md) — What the rig does in the MVP. Gatekeeper for "is this in scope?"
  • Design principles (principles.md) — First principles — measurement precedes trust, honest gaps, portability.
  • Trust model (trust-model.md) — Who can approve what, which gates exist, human-in-the-loop rules.
  • Safety (safety.md) — Dangerous-command guards, sandboxing, blast-radius containment.
  • Security (security.md) — Secrets handling, attestation, audit trail, SOPS+age.
  • Agent secrets broker (agent-secrets-broker.md) — Capability-based secret lifecycle broker: agents hold opaque refs while the broker handles plaintext across Bitwarden, GitHub, SOPS, k8s and Cloudflare, so it never enters a prompt, tool argument or log. Covers the tool surface, the ref grammar, the policy model and the audit trail.
  • Provider portability (provider-portability.md) — Multi-runtime (Claude Code, Codex CLI, Gemini CLI) via OTel GenAI conventions. Swap runtime without changing backend.
  • Observability — OTel, Langfuse, Prometheus, SLOs (observability.md) — Self-hosted Langfuse (agent traces) + Grafana Cloud (infra) + local Prometheus (SLO gates); native OTel via CLAUDE_CODE_ENABLE_TELEMETRY=1, one Collector per cluster. Per implementation-status: OTel Collector Partial (deployed for rig-conductor, agents not yet emitting), Langfuse Planned, cost dashboard Partial (TokenUsageProjection exists, no LiteLLM proxy).
  • Cost framework (cost-framework.md) — Budget policy, per-model rate tables, cost attribution strategy. Companion to observability.
  • Self-healing (self-healing.md) — Automatic recovery loops, StaleHeartbeatService, escalation severity routing.
  • Memory architecture (memory.md) — Memory MCP scope, importance/hit_count model, promotion-to-docs threshold design.
  • Quality and evaluation (quality-and-evaluation.md) — How the rig evaluates its own output. Judge-agent pattern, fixed rubrics.
  • Drift detection (drift-detection.md) — Schema drift, docs drift, infra drift — detection thresholds and response.
  • Development process (development-process.md) — Issue → Epic → research → proposal → PR lifecycle, agent-human gates.
  • Example first story (example-first-story.md) — Worked walkthrough of one Epic end-to-end.
  • Glossary (glossary.md) — Rig-specific terminology (Epic, proposal, rig-conductor, Review-E, etc).
  • Known limitations (limitations.md) — Honest catalog of what the rig can't do today.
  • Implementation status (implementation-status.md) — Single source of truth for deployed vs planned per capability. 78 tracked across 11 domains; 21 deployed/partial (27%), 44 planned/deferred (56%). Every capability named in the whitepapers gets a row with status + whitepaper section + ticket/evidence.
  • Tool choices (ADRs) (tool-choices.md) — Decision records for tooling. Includes rejection list with rationale.

Most agents should start with: the /implementation/ dashboard (structured per-capability status — see summary below) and whichever domain-specific whitepaper matches the Epic.

Capability status (40 in registry · full dashboard)

shipped:16 · partial:8 · planned:15 · deferred:0 (registry seed — full migration tracked in rig-docs#124)

Top blockers: default-deny-egress (dashecorp/rig-docs#57), gpu-brain-wake-on-chat (dashecorp/rig-agent-runtime#684)

Multi-tenancy

Shared control plane + per-tenant siloed data plane. tenant_id is resolved ONCE at a trusted edge (GitHub installation_id for webhooks, Cloudflare Access identity for the dashboard, the conductor-issued session token for agents) and threaded immutably as a Marten event header — never asserted by the LLM, never read from a body or tool argument ("the LLM is the threat model, not the guard").

Boundary: The database IS the tenant boundary. Marten master-table tenancy (the rig_control registry) routes each tenant to its own Postgres database (rig_t__evt); read models stay tenant-naive and isolation is enforced at the per-request connection, not a row filter.

Active tenants: invotek (type: B2B) — Tenant-0, on its legacy database (renamed rig_t_invotek_evt at the PR-5 cutover). Post-handover (rig-docs#324) githubOrg=null — invotek is verifiably not a GitHub org or user, so it owns no namespace. It keeps pinned ownership of the 6 rig-internal repos via RepoTenant rows, plus all pre-cutover dashe- history (drain-don't-migrate).; dashecorp (type: B2B) — Org-default tenant for the dashecorp GitHub org. First-party / Model B (operator-owned, no external DPA counterparty). Owns the 8 dashe- app / site repos, pinned via RepoTenant during the suspended provisioning window then caught by the org-default after activation (pins stay as belt-and-braces). New data-plane DB rig_t_dashecorp_evt; dashe-* starts FRESH (pre-cutover history stays in invotek's DB). Activation gated on rig-conductor#1926/#1476; the pin-first / activate-last sequence means the interim window can only fail-to-null, never mis-route.

Target (gated, 4-tenant lock): - dashecorptype: B2B, model: B (hosted), first-party — org-default host — see Active tenants above. - invotektype: B2B, model: B (hosted), first-party — tenant-0 — see Active tenants above. - stigjohnnytype: B2C, model: A (BYO), first-party — consumer-facing persona; the B2C gate (consent + age-gate + rc#1496 subject-level erasure) blocks Status=active until rc#1496 ships. - run-the-docstype: B2B, model: A (BYO), first-party — docs/content pipeline; subjects = contributors.

Type axis status: ratified-design / not-yet-enforced-in-code (operator-ratified 2026-06-20, /reference/tenant-types/, rig-docs#314). The type values below are policy metadata only; the code-enforced Tenant.Type field is rig-conductor#1476.

Human gates: - Review — ReviewRoutingPolicy: a PR routes to Review-E iff authored by a known bot (dev-e-bot/ibuild-e-bot) or dependabot, OR it carries the needs-review operator opt-in label. - Merge — MergeGate (event-driven): merges only on review-approved + CI-passed + not-blocked; agents never self-merge (fallback is a manual operator squash). - Fail-closed write — RequireTenant throws on a blank/invalid tenant, so an unattributed write lands in no tenant's DB; a CI scope-guard blocks new unattributed write paths. Dashboard READS stay lenient (coalesce to invotek). - Onboarding — TenantOnboardingGate refuses activating an external tenant until its data-plane DB + erasure prerequisites exist (invotek exempt; preserves the GDPR no-window invariant). - Schema fence — env-gated (MARTEN_TENANT_SCHEMA_LOCKED), armed at the PR-5 cutover: the boot assert then checks every registered tenant's schema and fails closed on drift. Default-off until armed. - GDPR — rig-conductor#1486 is the launch blocker. The DPA SIGNATURE is EXTERNAL-tenant-only: all four targets are first-party, so none needs an operator signature to launch. They are gated instead on controller duties toward third-party contributors — Art.17 erasure (shipped), sub-processor disclosure, EU residency — plus the DPO minimal-field-set opinion (#1486 §3.4).

Built (merged + deployed): DB-per-tenant (rc#1515), the fail-closed write boundary (rc#1608), tenant resolution (TenantMatch), per-tenant dispatch (rc#1481) + per-installation GitHub tokens (rc#1665), the cross-tenant isolation gate (rc#1617), the onboarding gate (rc#1614), per-tenant Discord routing (rc#1643/#1661/#1668), the PR-5 schema fence (rc#1685) and per-tenant pgvector memory (#1478, rig-memory-mcp#24).

Pending (gated): secrets-broker tenant-prefixed refs (#1479), the PR-5 cutover, the dashecorp org-default activation (rig-docs#324, gated on rc#1926/#1476) and the #1486 GDPR pack. invotek is the only tenant ACTIVATED in the registry, but the DEPLOYED state is ahead of it: Rig-E (tenantId dashecorp) runs at replicaCount 1 in namespace dashecorp with its own ServiceAccount, secret and memory DB, beside a dormant dashecorp dev-e/review-e/rig-planner fleet, and the stigjohnny namespace is provisioned (review-e replicaCount 1, older image, secrets not yet in its kustomization). Only invotek is registered statically at boot — every other tenant lives in the Marten master registry table, so the live tenant list is NOT derivable from any repo.

Launch blocker: dashecorp/rig-conductor#1486. Canonical operating guide: https://research.rig.dashecorp.com/proposals/multi-tenancy/.

rig-conductor event types (POST /api/events)

All events from dashecorp/rig-conductor/src/ConductorE.Core/UseCases/SubmitEvent.cs MapToEvent switch. Names only here — fetch /events.md for full field schemas (no auth required).

Pipeline (issue → PR → merge → deploy): ISSUE_APPROVED, ISSUE_ASSIGNED, ISSUE_UNASSIGNED, WORK_STARTED, BRANCH_CREATED, PR_CREATED, CI_PASSED, CI_FAILED, REVIEW_ASSIGNED, REVIEW_PASSED, REVIEW_DISPUTED, HUMAN_GATE_TRIGGERED, HUMAN_GATE_REMINDER, MERGED, MERGE_GATE_WAITING, MERGE_GATE_MERGED, MERGE_GATE_TIMEOUT, MAIN_CI_STARTED, MAIN_CI_PASSED, MAIN_CI_FAILED, DEPLOYED_STAGING, DEPLOYED_PRODUCTION, SMOKE_PASSED, SMOKE_FAILED, BUILD_FAILED, VERIFIED, ISSUE_DONE, ESCALATED, MILESTONE_COMPLETE, DUPLICATE_PR_CLOSED

Direct PR path (no issue): PR_OPENED, PR_REVIEW_ASSIGNED, PR_REVIEW_APPROVED, PR_REVIEW_REJECTED

Agent lifecycle: AGENT_STARTED, HEARTBEAT, AGENT_STUCK

CLI sessions: CLI_STARTED, CLI_PROGRESS, CLI_COMPLETED

Observability (cost + tooling): TOKEN_USAGE, TOOL_USED

Memory MCP: MEMORY_WRITE, MEMORY_READ, MEMORY_HIT_USED

Known gaps (rig backlog)

Cold-start agents should see these so they don't re-discover what's already identified. Each gap links to prior_art — existing stubs, research, or PRs that have already touched it. When a gap is being worked, linked_user_story points to the user story; when closed, the entry is removed from facts/backlog.yaml.

[observability] Cost tracking mostly deployed — LiteLLM proxy + external access are the remaining gaps

DO NOT propose "build a cost pipeline" — most is shipped: (1) TokenUsageProjection + CostProjection consume TOKEN_USAGE + CLI_COMPLETED into Marten read models; (2) GET /api/usage + /api/costs/{issue,summary,daily}; (3) Dashboard.html Costs tab at / and /dashboard. Remaining: (a) LiteLLM proxy not deployed (blocks hard budget enforcement / kill-switch); (b) /dashboard is cluster-internal — no external read-only view; (c) no Discord alert on threshold breach. Rough spend ~$5-15/day fleet-wide.

Prior art: - rig-conductor src/ConductorE.Api/ — cost endpoints, Dashboard.html, Adapters/MartenProjections.cs (TokenUsage + Cost projections) - TOKEN_USAGE + CLI_COMPLETED events — see /events.md - rig-gitops/docs/whitepaper/{cost-framework,observability}.md (private)

Status: mostly-deployed

[observability] OTel collector deployed for rig-conductor only — agents not yet emitting

OTel Collector is Partial — deployed for rig-conductor; agent pods have not enabled native OTel (CLAUDE_CODE_ENABLE_TELEMETRY=1). Langfuse and Grafana Cloud ingest are Planned. Design: observability whitepaper.

Prior art: - rig-gitops/docs/whitepaper/observability.md + implementation-status.md (OTel 'Partial', Langfuse 'Planned') - Enable native OTel: CLAUDE_CODE_ENABLE_TELEMETRY=1 + OTEL_EXPORTER_OTLP_ENDPOINT at the in-cluster collector

Status: partial

[docs-memory] Docs-memory drift lint not implemented

Weekly LLM-as-judge pass promoting memory→docs (importance≥4 AND hit_count≥5), flagging stale research and orphan docs. Designed, not built.

Prior art: - Design: research/2026-04-18-docs-memory-drift-lint; story: user-stories/2026-04-18-docs-memory-strategy; principles: research/2026-04-18-docs-vs-memory-principles

Linked user story: user-stories/2026-04-18-docs-memory-strategy

Status: open

[docs-surfaces] Two docs surfaces with overlapping scope

docs.rig.dashecorp.com (MkDocs from rig-gitops/docs-site/) and research.rig.dashecorp.com (Starlight from rig-docs) both host rig docs; the boundary is not formalised, so agents learn it empirically.

Prior art: - MkDocs built by rig-gitops/scripts/build-docs.sh; Starlight in rig-docs - decisions/2026-04-18-docs-tooling-decision — Starlight for research, MkDocs for aggregation

Status: open

[agents] ATL-E retired, no active coordinator agent

ATL-E (legacy personal-org atl-agent) was a k3s CronJob handling handoff-stall Discord notifications; undeployed since ~2026-03-26, repo dormant. If an Epic needs a coordinator role, decide redeploy vs replace.

Prior art: - Dormant personal-org atl-agent repo (last push 2026-03-26); no ArgoCD manifest in the personal-org GitOps repo

Status: open

[cleanup] Plane residue — uninstall GitHub App + archive workspace

Plane was retired 2026-04-18 but the makeplane GitHub App is still installed on the dashecorp org and the workspace is alive (token revoked). Manual UI.

Prior art: - Retraction decision: decisions/2026-04-18-docs-tooling-decision (What retires section) - Retirement commit: dashecorp/infra PR #74

Status: open

Architecture at a glance

flowchart LR
  H[Human]

  subgraph Code["Code repos"]
    RD[rig-docs]
    RG[rig-gitops]
    RAR[rig-agent-runtime]
    CE_R[rig-conductor]
    RMM_R[rig-memory-mcp]
    RT[rig-tools]
    INF[infra]
  end

  subgraph Deployed["Deployed services + agents"]
    direction TB
    CE[rig-conductor svc]
    RMM[rig-memory-mcp svc]
    DE[Dev-E pod]
    RE[Review-E cron]
    IB[iBuild-E — Mac Mini]
  end

  subgraph Publish["Published surfaces"]
    direction TB
    S1[research.rig.dashecorp.com<br/>Astro Starlight]
    S2[docs.rig.dashecorp.com<br/>MkDocs aggregator]
    CFP[Cloudflare Pages]
  end

  %% Authoring + dispatch
  H -->|user-story issue| RD
  RD -->|dispatch| CE
  CE -->|assign issue| DE
  CE -->|assign PR review| RE
  CE -->|assign iOS build| IB
  DE -->|author PR| RD
  RD -->|PR opens| RE
  RE -->|approve / request changes| RD
  RD -->|merge| CFP
  CFP -->|publish| S1
  RG -->|docs aggregation| S2

  %% MCP + memory
  DE -->|tool use| RMM
  RE -->|tool use| RMM
  IB -->|tool use| RMM
  RMM_R -.implements.-> RMM

  %% Flux GitOps
  RG -->|Flux deploys| CE
  RG -->|Flux deploys| RMM
  RG -->|Flux deploys| DE
  RG -->|Flux deploys| RE

  %% Runtime image used by all agent deployments
  RAR -.image.-> DE
  RAR -.image.-> RE
  RAR -.image.-> IB
  CE_R -.image.-> CE

  %% Per-repo docs/ feeding into the MkDocs aggregator
  RG -.docs/.-> S2
  RAR -.docs/.-> S2
  CE_R -.docs/.-> S2
  RMM_R -.docs/.-> S2
  RT -.docs/.-> S2

  %% Infra — outside the loop but manages everything above
  INF -.OpenTofu.-> CFP

Legend: solid arrows are runtime flows (dispatch, tool calls, deploys). Dashed arrows are source-of relationships — "this repo's image powers that pod" or "this repo's docs/ feeds that site". Every rig repo from facts/repos.yaml is represented.

Conventions (rig-wide)

  • Docs are markdown with YAML frontmatter. Required fields: title, description, type, audience, created/updated, topic. See AGENTS.md in this repo.
  • Bidirectional linkage. User story ↔ research ↔ proposal → decision via research_docs, proposal, user_story, source_research, supersedes/superseded_by. RelatedDocs component renders the graph.
  • Diagrams as code. Mermaid source inline in markdown. No PNG or SVG committed. Source preserved post-render via <details> blocks.
  • Per-repo CLAUDE.md auto-loads when Claude Code starts a session in that repo's cwd (Claude Code reads CLAUDE.md, not AGENTS.md — cross-vendor standard is AGENTS.md but the loader is CLAUDE.md). Same-repo local @AGENTS.md imports work; cross-repo @owner/repo/file does not fetch from GitHub (filesystem-only, max 5 hops).
  • Rig-wide agent instructions live in TWO places: (1) each running agent's HelmRelease character.personality prompt (authoritative for Dev-E, Review-E in-cluster), (2) each repo's root CLAUDE.md (authoritative for interactive sessions). Both include the BRAIN.md fetch at session start.
  • Closes #N required in PR bodies. Review-E blocks on this.
  • Memory MCP scope: operational / ephemeral state only. Durable knowledge goes to rig-docs.
  • Default to a two-PR split for feature work >500 LOC. large-pr-ok is reserved for migrations, codemods, dependency bumps, and generated code — not feature work that decomposes into policy + adapter. A/B-validated 2026-05-18: same code shipped as a labelled single PR got zero code-level feedback; the disciplined split caught 3 real bugs. Rig-side enforcement in rar#492; full decision tree in research/2026-05-18-pr-size-and-large-pr-ok-semantics.
  • Behavior PRs ship their doc updates in the same PR. Per-file convention: when src/<X>.{cs,js,ts,go,py,...} changes, docs/<X>.md (if it exists) updates alongside. Rig-side enforcement in rar#497 (detectDocMismatches surfaces a warning in the size-gate review body).
  • Three-layer drift-prevention playbook. When the operator catches the orchestrator drifting on a discipline recurringly + structurally observable + measurable cost: ship L1 memory rule + L2 rig-side enforcement at the trigger point + L3 durable artifact. Three instances codified the week of 2026-05-18 (PR-split shortcut, doc-staleness, main-guard rig-internal dispatch). Meta-playbook in research/2026-05-18-three-layer-drift-prevention-playbook.

Token-efficient cold start

When you pick up a new Epic with blank memory, the cheapest order of operations:

  1. Fetch this file (https://research.rig.dashecorp.com/BRAIN.md, public, no auth) — ~57 KB.
  2. Fetch /llms.txt for the research hub topic index — ~2 KB.
  3. Identify 1-3 relevant research / proposal docs, fetch raw — ~5-15 KB.
  4. Fetch target repo's AGENTS.md (each repo's is ≤8 KB) — ~5 KB.
  5. read_memories from Memory MCP scoped to repo + topic — ~2 KB.

Total cold-start context: this file (~57 KB) + ~15-25 KB of targeted fetches. Leaves the rest of the budget for actual work.

When this file needs updating

Manual fields that live in facts/*.yaml — update when the matching reality changes:

  • facts/repos.yamlannotations only (purpose, depends_on, used_by, agents_md, docs_surface). The repo list itself is auto-derived from gh api on every compile. Adding a new annotation, or updating an existing one, happens here.
  • facts/surfaces.yaml — URLs, API endpoints, MCP tools. Update when an endpoint changes or a new surface is published.
  • facts/agents.yaml — agent deployment instances. Compile validates each manifest: path exists on GitHub and warns on drift (how ATL-E retirement was caught).
  • facts/flows.yaml — documented rig processes. Update after retrospectives.
  • facts/schema.yaml — mirrors the Zod schema in src/content.config.ts. Keep in sync manually when the schema changes.
  • facts/events.yaml — rig-conductor event types. Keep in sync with MapToEvent in the C# source.
  • facts/backlog.yaml — known gaps. Add when identified; remove when closed.

Then run npm run brain. CI (build workflow) runs brain:check and fails on drift.