How you actually wire this thing
The technical configuration.
Everything above describes behaviour. This page is the build sheet: where the briefs and skills live on disk, what the database really is, the unusual write-path that makes it work, the MCP servers behind it, which models the agents run, and the rules that keep rotation safe.
Where everything lives
Filesystem layout
All paths are under the user's Clawpilot home, ~/.copilot (i.e. C:\Users\smccormick\.copilot).
CHIEFOFSTAFF.md (CoS), SOLUTIONARCHITECT.md (SA), STEWARD.md. Plus m-role-briefs/scouts/ for the 4 K-scout briefs: BACKLOG-SENTINEL.md, PIPELINE-WATCHER.md, REUSE-SCOUT.md, INTAKE-TRIAGE.md. (Signal Scout's contract lives inline in ring-tick/SKILL.md Job B.)daily-brief, decision-capture, ado-bulk-triage, ado-scribe, ring-tick, outbound-voice, bootstrap-roles, rotate-role, plus the utility cowork and the deprecated forwarding shims bootstrap-clawpilot-roles / rotate-clawpilot-role. Five further folders (signal-scout, backlog-sentinel, pipeline-watcher, reuse-scout, intake-triage) are empty scaffolding — the scout contracts live in the role briefs.bootstrap-roles and rotate-role read. haleon/workflow.json declares CoS/SA/Steward/Operator + DAB audit mode (haleon-aiac-db) + phase boundaries (2026-09-14 Pilot→Scale, 2027-02-08 Scale→Transform). loom/workflow.json declares Architect/Operator/Steward + plan_md_only audit.ui-designer and visual-storyteller (used to build this very site), plus pptx, docx, xlsx, loop, web-artifacts-builder, etc.ring-tick is built and staged, but its recurring schedule is intentionally off pending a Charlie posture decision — see Roadmap).dab-config.json (52 entities post Batch 6) and dab-mcp-shim.js (the MCP wrapper).Two rings, one ceremony library. Both the Haleon delivery ring (CoS / SA / Steward) and
the Loom illustrator stack (Architect / Operator / Steward) are launched and rotated by the same generic
skills bootstrap-roles + rotate-role, dispatched on
workflow-name. All workflow-specific surface (role names, brief paths, models, audit
entities, ledger location, escalation channel, phase calendar) lives in workflow.json — no
skill hardcodes a ring. The old loom-specific bootstrap-clawpilot-roles /
rotate-clawpilot-role remain as deprecated forwarding shims for back-compat.
The single brain
The database
localhost:5432) — not Azure Database for PostgreSQL or any managed service.haleon_aiachaleonrotation_log, agent_snapshots, tick_lease, scout_lease, drainer_lease, scout_watermark, scout_enable_flags)*In shim views + action-views (e.g. CostRollupDayIn, CostBreakerRollingIn, ScoutEnabledCheckIn, OpenAgentRun)haleon-aiac-db MCP server → Data API Builder → Postgres. No application talks to Postgres directly.The 22 base tables
| Table (snake_case plural) | DAB entity (PascalCase singular) | Holds |
|---|---|---|
signals | Signal | raw inbound pings to triage |
briefs | Brief | the 5-3-2-1 briefs |
pod_intel | PodIntel | per-pod status intelligence |
customer_health | CustomerHealth | customer sentiment / health signals |
comms_drafts | CommsDraft | outbound drafts awaiting sign-off |
quiet_watch_state | QuietWatchState | the Quiet Watch list |
recipient_registry | RecipientRegistry | recipient voice profiles |
meetings | Meeting | meeting records |
meeting_preps | MeetingPrep | meeting prep docs (+ loop_page_url) |
steerco_preps | SteercoPrep | SteerCo prep docs |
pd_sync_preps | PdSyncPrep | PD-sync prep docs |
risks_issues_blockers | RiskIssueBlocker | the RIB register |
ado_writeback_queue | AdoWritebackQueue | pending ADO write-back ops (drained by ado-scribe; CAS-guarded via sp_update_ado_writeback) |
decisions | Decision | engagement + technical decision narrative (now with decision_class, owning_peer, adr_id, narrative routing columns) |
agent_runs | AgentRun | per-turn audit spine (multi-writer; 7-member class enum; gap-scan key (session_id, session_turn_seq)) |
adrs | Adr | architecture decision records |
compliance_state | ComplianceState | per-use-case compliance posture |
cost_telemetry | CostTelemetry | idempotent whole-UTC-day cost cells (derived rollup of agent_runs) |
reuse_catalog | ReuseCatalog | reusable pattern catalog |
schema_version | SchemaVersion | schema migration marker |
skill_versions | SkillVersion | installed skill versions |
transcripts | Transcript | meeting-transcript archive (rotation snapshots now live in agent_snapshots) |
Plus 7 Batch 3–7 substrate tables not listed above:
rotation_log + agent_snapshots (Steward audit, D4); tick_lease,
scout_lease, drainer_lease (three independent single-flight mutexes);
scout_watermark (per-source scan cursors); scout_enable_flags (the 3-greens DB gate,
read by sp_check_scout_enabled()).
Naming footgun. The DB tables are snake_case plural; DAB exposes them
as PascalCase singular. A mapping table is patched into CHIEFOFSTAFF.md
(~lines 29–53). Use the entity name (left column of your MCP calls) — not the table name — when calling DAB.
The clever bit
The write-path shim — and why it exists
The schema uses 15 PostgreSQL ENUM types (e.g. agent_tier,
brief_slot, comms_draft_status, decision_status,
rib_severity/rib_status/rib_type, pod_id,
tone) plus jsonb columns. Data API Builder v1.7.93 cannot bind
text → enum or text → jsonb over its Postgres path — a direct
create_record on those columns fails with SQLSTATE 42804.
The fix that is actually in place
<Entity>In view→
INSTEAD OF trigger→
sp_* function casts→
base table
- 17+ write-shaped views named
v_<entity>_in, exposed as DAB entities:SignalIn,BriefIn,CommsDraftIn,QuietWatchIn,PdSyncPrepIn,MeetingPrepIn,SteercoPrepIn,AgentRunIn,DecisionIn,AdoWritebackIn,RibIn,RecipientIn(the original 12), plus Batch 2–7 additions:AdrIn,ComplianceStateIn,DrainerLeaseIn,AdoWritebackResetIn,RotationLogIn,AgentSnapshotsIn,TickLeaseIn,ScoutLeaseIn,ScoutWatermarkIn,ScoutEnableFlagsIn,SchemaMigrationIn, plus action-viewsCostRollupIn/CostRollupDayIn/CostBreakerIn/CostBreakerRollingIn/ScoutEnabledCheckInand the read-viewOpenAgentRun. - Each shim view has at least an INSTEAD OF INSERT trigger that casts
text → enum/jsonband delegates to one of thesp_*PL/pgSQL functions (well over 25 now — covering create, CAS-guarded UPDATE, reset, rollups, breakers, lease acquire/release, watermark advance, ADR stage advance, session-seq allocation, etc.). INSTEAD OF UPDATE triggers exist onv_comms_draft_in,v_agent_run_in,v_ado_writeback_in(CAS-guarded per ISS-03),v_adr_in(stage-CAS viasp_advance_adr_stage, Fix-G) andv_brief_in(Unit H);v_signal_incarries an explicit deny on UPDATE (signals are append-only); the rest do their update semantics by repeating the INSERT (upsert inside the SP). - Writes go through the
*Inentities; reads use the base entities.jsonbcolumns are passed as JSON-encoded strings at the MCP boundary.
Why not just call the functions? An earlier attempt exposed the sp_*
functions directly as DAB stored-procedure entities. That failed — DAB does not
support procedure/function entities on PostgreSQL. The views-plus-triggers approach replaced it.
The data-API layer
Data API Builder surfaces
database-type: postgresql/api/graphqldab.exe --mcp-stdio exposes tools read_records, create_record, update_record, delete_record, execute_entity, describe_entitiesSimulator (dev); the MCP runs as the anonymous role (now read-only on all base tables — ISS-22)anonymous role is tightened to least-privilege: every base table is read-only, so the only sanctioned write path is the validating *In views (which carry the INSTEAD OF triggers + sp_* functions). Six base tables were flipped to read-only in Unit H (Brief, MeetingPrep, PdSyncPrep, QuietWatchState, Signal, SteercoPrep); the original 6 (ado_writeback_queue, agent_runs, comms_drafts, decisions, recipient_registry, risks_issues_blockers) had already been tightened. authenticated=* is defined on every entity as the dormant production posture; the MCP runs a single role:anonymous instance.The DAB MCP shim. dab-mcp-shim.js wraps dab.exe --mcp-stdio and
rewrites spec-violating null envelope fields in DAB's responses
(instructions: null → "", annotations: null → {}, _meta: null → {})
so strict MCP clients accept them. It is load-bearing — without it, strict clients reject DAB's replies.
The tool surface
MCP topology
Clawpilot spawns one DAB shim + one dab.exe per session
connected to haleon-aiac-db — there is no shared global server. The consequence:
a config change requires respawning each consuming session to pick it up; there is no
global hot-reload. (This is what drives the rotation chain when the schema or config changes.)
| Server | Kind | Role in the ring |
|---|---|---|
haleon-aiac-db | node shim → dab.exe | the shared Postgres brain (all reads/writes) |
azure_devops | @azure-devops/mcp | ADO backlog read + write-back (via ado-scribe drainer). This MCP is the single source of truth for the ADO org/project/area path — the ado-bulk-triage and ado-scribe skills no longer hardcode a target (ISS-05, resolved). Currently pointed at smccormick0886/Haleon-AIAQ; that pointer is environment config and will change per deployment. |
m365_* (native) | builtin Clawpilot capability | mail / calendar / Teams signal sources — a builtin, not an MCP entry, so it appears in a separate permissions section rather than m-mcp-servers.json. The deferred m365-softeria MCP was removed (ISS-21, resolved); the ring uses these native tools. |
msx-mcp | Microsoft Sales Experience / Dataverse | Pipeline Watcher scout's data source — opportunities scoped by the MCP's own identity (territory + RLS). Confidentiality labels routed to SA via decisions, not enqueued raw. |
github (or gh CLI) | GitHub | Reuse Scout's data source — configured engagement org commits + PRs (allowlist). |
filesystem | builtin | workspace file access |
filesystem_extra | server-filesystem | extra root at the loom illustrator working tree |
playwright | builtin | browser automation (e.g. Loop, Cowork) |
Who runs on what
Model assignments
The CoS, SA and Steward all run on claude-opus-4.7-1m-internal
per the haleon workflow.json (this site's model assignment) — the 1M-context build, picked
uniformly for the engagement. Self-rotation has historically lifted individual roles to newer builds (a
previous Steward briefly ran on claude-opus-4.8); the canonical default expressed in
workflow.json is the 1M build for all three. Scout agents run as short-lived child sessions
under model NULL in their agent_runs rows because the v1 scout sweeps are
deterministic / rule-based and don't make LLM calls; if a future scout variant adds LLM classification,
that field is populated.
Always pass an explicit model on spawn. Implicit inheritance of the parent's model
previously caused a wrong-model incident. Every m_spawn_session in the ceremony skills
names its model explicitly — never rely on inheritance.
Keeping rotation safe
Rotation governance
These rules were written from real incidents and are enforced by the Steward:
- Rotator spawns the successor. A role being rotated never spawns its own replacement.
The Steward is the special case: Operator is the named
selfRotationRotatorinhaleon/workflow.json, so the outgoing Steward emits a self-rotation audit row and Operator runsrotate-roleon its behalf (D6). - Archive, never delete. The Steward always closes with
delete:false. The sole exception is a genuine ZOMBIE session, and only with an explicit Charliem_ask_userack quoting the zombie'ssessionId+lastActivityAt(D5 ZOMBIE redesign — default is cold-spawn + archive, transcript-synthesis /delete:trueis the escalated path). - Check before closing. Before closing any session it doesn't own, the Steward checks
totalTurns+lastActivityAtand requires Charlie ack if the session looks active. - No boot-turn race (D3). The rotator awaits the successor's
## Context healthgreen ack BEFORE releasing the SDK handle, and releases withkeepPendingTurn:false. A red/malformed/file-not-found ack means do NOT release, do NOT shut down the predecessor. - No orphan-turn race (D4). A lightweight status-probe re-adopts the successor handle AFTER release and BEFORE the heavy readiness smoke-test.
- Address by sessionId from spawn until close (D8). The reused
sessionNameis ambiguous between predecessor and successor for the duration of the ceremony; every op targets asessionId. - Brief-missing HALTs the rotation. If the resolved
briefPathfromworkflow.jsondoesn't exist on disk,rotate-roleHALTs and surfaces to the workflow'scontactchannel — it does NOT fall through to the ZOMBIE branch (D1 second-half fix).
What is deliberately not here
Secrets
This documentation contains no credentials by design. The Postgres connection string — host, database, username and password — lives only in dab-config.json under the DAB runtime folder. It is intentionally excluded from every page of this site and must never be copied into documentation, screenshots, or any committed file. The same applies to the Loop sandbox link (an access-bearing tokenised URL) and any ADO PAT: document where they live and how things are wired, never the secret values themselves.