Central Agentic Ops (CAO) governs agentic workflows and runs them from a central GitHub repository against an explicitly bounded repository fleet. This repository is both the public campaign catalog and a source-managed control plane used to develop and exercise campaigns and standalone workflows.
This document is a map of the stable system boundaries and source tree. The
normative contracts live under specs/; operator-facing explanations live
under docs/.
CAO separates the decision to run an operation from the mechanism that executes it:
- Catalog: publishes versioned operation campaigns.
- Control repository: owns rollout policy, credentials, installed workflows, and workflow runs.
- Target repository: supplies source data and may receive a declared safe output. It does not run control-plane workflows.
- GitHub Agentic Workflows (gh-aw): compiles workflow sources and owns execution capabilities, limits, authentication, and safe-output mechanics.
flowchart LR
Catalog["CAO catalog<br/>campaigns and workflows"]
Control["Control repository<br/>policy and credentials"]
Resolver["CAO policy resolver"]
Orchestrator["Campaign orchestrator"]
Worker["One-target worker"]
Review["Review repository"]
Target["Target repository"]
Catalog -->|install reviewed release| Control
Control --> Resolver
Resolver -->|admit and narrow| Orchestrator
Orchestrator -->|bounded dispatch| Worker
Worker -->|review mode| Review
Worker -->|authorized live mode| Target
The effective authority of a run is the intersection of reviewed CAO policy, the dispatch request, worker ceilings, credential reach, and capabilities compiled by gh-aw. No one input can widen another.
CAO's authority kernel (.github/workflows/shared/authority.mjs) is independent
of workflow roles and orchestration topology. It resolves mode/target ceilings,
checks scope and validates versioned scoped grants. It performs no discovery,
GitHub requests, credential acquisition or workflow dispatch. Existing campaign
and standalone policy adapters use this same resolver while preserving their
legacy output contracts. Campaigns remain first-class, opinionated operating
patterns, not prerequisites for operation execution.
operations.mjs provides the direct-operation policy and gh-aw integration
adapter. An exact workflow slug under control-plane.operations can import
shared/operation.md and request an explicit target or JSON target set without
campaigns, workers, inventory cells or rollout configuration. Identity conflicts
with existing campaign/worker/standalone declarations reject. Multiple targets
are review-only with a common destination; live requires one target_repo and
target-bound compiled safe outputs.
The direct operation request, verified execution context and resolved envelope are distinct contracts. Version 1 binds each scoped target/mode/destination grant to the control repository, exact policy SHA, workflow reference, run and attempt. Requests cannot provide verified context or execution capabilities. The adapter re-resolves exact-revision policy and compares the admitted handoff before preparing candidates; redirected, archived, disabled or incompletely observed repositories block execution. Review destination privacy and scope checks remain independent of target allowlists.
Required enforcement controls are versioned and fail closed when unsupported.
The envelope is neither a credential nor standalone proof of provenance.
Narrowing comparisons require independently verified inputs and cannot grant
delegation. Direct delegation, pooled allowances, runtime-loaded plugins and
additional execution backends are unsupported. Native gh-aw authorization,
credential reach, tools and safe outputs remain cumulative constraints.
See docs/authority-envelopes.md for the contracts and authoring example.
- A schedule or manual dispatch starts an orchestrator in the control repository.
.github/workflows/shared/control.mdand its Node.js support modules load.github/workflows/cao.jsonat the exact workflow revision and resolve an effective run envelope.- The orchestrator discovers, filters, ranks, and selects repositories within that envelope.
- It dispatches one worker run for each selected repository.
- Each worker revalidates the envelope, analyzes only its dispatched target, and emits only safe outputs declared by its compiled workflow.
Orchestrators decide rollout and selection; workers are independent, single-target enforcement points.
A standalone agentic workflow may instead import shared control with
role: standalone and its exact workflow slug. It declares no campaign or
worker and needs no campaign record. control-plane.workflows.<workflow> owns
its enablement, mode, optional max-mode ceiling, target modes, repository cap,
and rollout percentage. Admission verifies that identity against the actual
compiled workflow reference, loads policy at the exact workflow SHA, and checks
API capacity through the same admission path as campaigns. Precompute reuses
bounded inventory, deterministic cells and batches, excludes archived/disabled
repositories, and admits a deterministic subset capped by repository count and
rollout percentage. Each admitted repository carries its own effective mode and
output destination. The workflow performs its mission directly on that set;
it cannot discover extra targets or dispatch more work. No orchestrator or
downstream workflow inventory is required. Missing inventory evidence fails
closed. Credential reach and safe-output capabilities remain declared by gh-aw;
CAO does not expand them for fleet execution.
Bare setup rejects policies with declared standalone workflows or direct
operations before changing scope or authentication, just as it rejects declared
operational campaigns.
A local debugger may manually launch one worker in request-only debug mode.
Admission verifies a human workflow_dispatch sender with current write access
to the control repository, retains policy scope, enablement, and limits, and
rejects dispatcher-envelope inputs. The target and proposed-output repository
must match; precompute records the debugger actor and empty dispatcher
correlation. Shared control forces gh-aw safe-output staging and suppresses
automatic activation/failure issues. Debug grants no live authority and cannot
be persisted in policy or selected by an orchestrator. GitHub cannot attest
local CLI origin; repository-memory staging remains owned by gh-aw.
CAO Activity is a separate evidence pipeline. It supports observability but grants no rollout or write authority.
flowchart LR
Logs["gh aw logs"]
Shards["Bounded JSONL shards"]
Runs["Compact run-information shards"]
Records["Detailed domain, tool, audit, and issue shards"]
SQLite["SQLite projection"]
Publisher["Dashboard publisher"]
Worker["Browser data Web Worker"]
IndexedDB["IndexedDB projection"]
Postgres["Postgres dashboard entities<br/>optional server profile"]
Redis["Operational caches, queues, sessions<br/>Postgres default, Redis opt-in, or process memory"]
Query["Dashboard Language queries"]
GoServer["Go HTTP(S) query server"]
GitHub["GitHub / gh-aw<br/>authoritative state"]
Compute["Versioned computations<br/>bounded insights"]
HostedValue["Hosted Operational Value<br/>reviewed adapters"]
Results["Materialized computation results<br/>generation-scoped"]
UI["Static dashboard"]
CLI["cao CLI and agents"]
Logs --> Shards
Shards --> SQLite
Shards --> Runs
Shards --> Records
Runs --> Publisher
Records --> Publisher --> Worker
Worker --> IndexedDB
IndexedDB --> Query
Publisher --> GoServer --> Postgres
GitHub -->|"webhooks + rebuild input"| GoServer
GoServer --> Redis
Postgres --> GoServer --> Query
IndexedDB --> Compute --> Results --> Query
SQLite --> Compute
Postgres -->|"bounded repository-scoped<br/>Dashboard Language queries"| HostedValue
HostedValue -->|"revision-checked canonical publication"| Postgres
Query --> UI
Compute --> CLI
Activity collects a bounded snapshot once and publishes immutable cache
artifacts. SQLite and IndexedDB are independently rebuildable projections of
the authoritative inputs. It deterministically separates compact, immutable run
information from detailed run-linked records so the browser data worker loads every run
before continuing with event shards. Raw Activity JSONL remains available only
inside the Activity cache for audits and projection rebuilds. The deployed
dashboard artifact contains the SQLite projection, inventory, and compacted
normalized run and record JSONL; browser ingestion fails closed rather than
falling back to raw Activity JSONL. Static-browser download, normalization,
persistence, and queries run in a dedicated Web Worker. Actions and explicitly
selected static Operational Value
reconstruction use the rebuildable SQLite projection. A collector-enabled
hosted server instead runs the same reviewed JavaScript metric definitions
against one repeatable-read, exact-enrollment PostgreSQL revision through the
production Dashboard Language SQL boundary. It does not create, copy, open, or
ingest an intermediate SQLite database. Completed observations replace the
canonical operationalValues collection under the namespace writer lock with
an expected-revision check; the accepted JSONL is mirrored only for cold-start
lake recovery and is never the hosted computation input. The optional Go server
profile ingests the same deployed
dashboard artifact into Postgres, keeps database credentials server-side,
compiles hosted Dashboard Language queries to parameterized SQL in the
request's repeatable-read transaction, and returns
only canonical or explicitly registered bounded runtime-source query payloads
to the browser. Operational state is accessed through typed contracts in
server/internal/operational/, with PostgreSQL as the default adapter and a bounded,
volatile memory adapter for an explicitly acknowledged single-process server.
The PostgreSQL operational adapter implements durable
deployment-scoped services in separate cao_operational_* tables. Operational
adapters never store dashboard entities or execute dashboard queries.
The independent statistical-runs query projection selects a deterministic,
seven-day, date/outcome-stratified sample from the current canonical snapshot.
Selection belongs to the data worker and server storage boundary, before
consumer predicates, with separate backend capacities and explicit frame/weight
metadata. It does not change exact sources, retention, or Operational Value.
The Models & Agents composition chart describes sampled observations rather
than population shares; its cost/token summaries continue using exact retained
runs. PostgreSQL atomically persists complete sampled bundles, typed frame and
membership metadata, source quality, and structural parents at canonical snapshot
publication; statistical dependencies read those private, non-partitioned copies
without changing exact dependencies. Incremental revisions mark the frozen source
stale, never mutate sampled evidence or weights; only a complete publication
rebuilds the seven-day frame. Admission limits reject an entire statistical
snapshot rather than truncate bundles. SQLite and browser sampling remain query
projections. Hot eviction and daily aggregates from the three-tier proposal remain
separate work; persistence cannot recover evidence missing at admission or reduce
canonical storage/downloads.
The Go server is the unified local and hosted dashboard serving runtime.
npm run dev and npm run dashboard:local build the site and invoke serve
against a verified cached SQLite snapshot; serve-hosted retains the reviewed
PostgreSQL/OAuth host. Explicit serve-pages serves a prepared static Pages
artifact unchanged, including repository base paths, so the browser exercises
IndexedDB rather than the hosted HTTP backend. The local Pages preparation
script runs production Activity normalization/SQLite ingestion and Dashboard
building from an existing snapshot or explicitly labelled synthetic evidence;
it does not simulate GitHub collection, Actions permissions or artifact transport.
There is no standalone Node dashboard CLI, admin server or process replacement.
The Copilot canvas also uses Go serve: dashboard/canvas-go-host.mjs launches
the bundled server module or an explicitly selected compatible executable.
Go owns the capability-protected browser origin, assets, verified canonical
SQLite queries, diagnostics, read-only repository memory and revision events.
Canvas startup requires a checksum-verified published SQLite snapshot; there is
no Node query backend, logical-source HTTP transport or browser ingestion
fallback. Published inventory quality may accompany the snapshot as metadata
only; missing quality remains unknown, never inferred complete from row counts.
dashboard/canvas-server.mjs is a private loopback-only integration adapter
for JSON composition/live reload, authoring callbacks, bounded local-user
GitHub reads and trusted command callbacks. Go proxies only those integration
routes on the same public origin. Installed plugins carry the server sources
and native query module; they never build or import executable workspace code.
The adapter owns the Go child's stdin lifetime, stops it before removing staged
assets, and cleans up failed startup. Canvas command execution requires paired
trusted execution and approval callbacks; read-only authoring starts no command queue.
Trusted canvas CLI actions use a separate, single-owner
operational SQLite queue in .cao/cli-actions.sqlite, never browser IndexedDB
or the disposable dashboard projection. Capability-protected local endpoints
admit only declared, validated actions with the existing trusted approval
boundary. One existing CLI executor runs approved FIFO work independently of
browser connections, with bounded concurrency, a fifteen-minute execution
deadline, explicit cancellation, persistent ordered output and manual retries
as new entries. Terminal history follows UTC seven-day retention windows;
active work must not expire. Unclean shutdowns fail closed when subprocess
termination cannot be verified: interrupted entries fail without automatic
retry, and only explicit local operator acknowledgement after reconciliation
resumes queued work. The local quota helper reuses the Go
githubquota service against authoritative observations from the execution
credential context; unavailable evidence fails closed. Queue operations and
reactive runtime-source queries cross the browser data worker. Dashboard
Language owns command selection, filtering and view composition, while terminal
components only present output and interactions. Published dashboards initialize
no queue, perform no queue requests and gain no execution authority.
The focused CLICommandQueues / CLICommandQueue operational service contracts
also provide PostgreSQL-backed command storage through OperationalServices.CLICommands.
This is separate from the collection task queue and does not enable hosted
command execution or replace the local SQLite executor. PostgreSQL stores
queue policy, command history and ordered output in namespace-isolated
cao_operational_cli_* tables under protected-state budgets. Database-time leases
and monotonic ownership fences reject stale writers; lease loss retains
uncertain execution claims and blocks new starts until explicit operator
reconciliation. Cancellation and deadlines do not release an execution slot
before subprocess settlement. Bounded maintenance removes only fully expired
terminal UTC weeks and their output. Memory and Redis do not advertise this
restart-durable capability.
The HTTP and MCP query boundary uses a disposable cache-aside layer for
expensive queries with compact output. SHA-256 query identities include the
definitions, parameters, pagination, schema, and current authorization class,
not ingestion revisions for ordinary queries. Value-evidence-dependent queries
also key by the current canonical revision so publication is visible when
subscriptions refresh. Each entry has a fixed five-minute lifetime; ingestion
and data egress do not renew it. Redis-side atomic expiry and
oldest-first eviction bound both allocator-reported result/index memory and
entry count without changing global Redis eviction policy or touching sessions
and queues. Cached payloads retain their original evidence revision and
evaluation time; cache hits report no fresh query-plan work.
All Redis server profiles also have a configurable whole-node Redis memory-pressure
budget, defaulting to 200,000,000 bytes and capped at 80% of provider-reported
maxmemory. Providers supporting scripted memory introspection use atomic
query-result, marketplace, and repository-memory admission and reserve outgoing
allocation before serving cache hits. Providers prohibiting that introspection
explicitly disable disposable-cache admission and serving rather than spend
independently sampled headroom; protected storage stays enabled. Startup and
cancellation-scoped 30-second maintenance use provider-compatible pressure
measurement and one namespace-scoped cursor pass to reclaim only disposable
caches. Final pressure reporting always refreshes the memory evidence.
Sessions, queues, quota state, revocation retries, and other namespaces remain
protected. Unreclaimable operational pressure fails startup or is reported by
running maintenance; cache writes decline admission rather than widening the
budget or changing Redis configuration. The budget is not a process-RSS or
persistence-disk cap and cannot bound protected-state growth by cache eviction.
Its local mode remains loopback-only. Its ordinary host-neutral mode uses
GitHub OAuth and explicit organization or team authorization, verifies and
deduplicates GitHub webhooks, and atomically replaces the current Postgres
sources and state. server/spec/storage.tsp owns the fresh-only physical
Postgres contract. Its emitter generates the standalone
server/internal/postgresx/schema.sql and matching Go column bindings.
Canonical collections map one-to-one to entity tables containing only
query-consumed fields and identity/storage keys. Scalars use native SQL types;
required structured fields use entity-owned relational child values, not
JSON, JSONB, or serialized row documents. Scalar entity rows are never duplicated
in generic source storage. Compact presence bits preserve missing versus null.
Operational Value evidence retains one bounded current packet per target
repository, workflow and frozen contribution metric/version. Its acquired
contract, output, acceptance, lineage, independent snapshot, quality and
coverage facts are typed relational children, replaced atomically with their
packet and retained independently of seven-day Run detail. The single
operational-value-evidence logical source only normalizes those facts.
Retained source identity materializes observed Repository and Workflow parents,
never registration or activation; packet cutoff/capture provenance supplies
source metadata without asserting complete coverage or current freshness.
Counts, comparisons, movement and report presentation remain declarative
queries; importing evidence grants no target authority and navigation never
acquires evidence.
Separate workflowValueCollections records retain reviewed registrations and
bounded collection decisions through the same producer, normalization and
browser/SQLite/PostgreSQL paths. Decisions do not advance actual-attempt,
accepted-capture or evidence-cutoff clocks. Declarative Value queries expose
enabled, disabled and unconfigured health before a first report; stale/conflicting
decisions and regressed attempt history fail closed.
Explicit gh cao value publish writes one validated original packet through
administrator-only POST /api/v1/value into PostgreSQL. The namespace writer
lock serializes publication with snapshot replacement; typed ownership metadata
preserves the packet, fact children and required observed parents across
replacement, without another canonical copy. Exact retries preserve the revision;
older/conflicting captures, frozen-contract drift and immutable-history rewrites
fail. Hosted publication requires fresh administrator OAuth assurance and CSRF;
loopback PostgreSQL uses its existing bearer capability. SQLite and static Pages
have no direct-publication endpoint. Upload never executes or registers code.
Recurring acquisition requires reviewed registration for an exact repository and
workflow under control-plane.campaigns.activity.workflow-values. After the
frozen function and bounded collector pass verification, the skill stages that
registration automatically with value enable --if-absent, preserving existing
registrations and explicit enabled: false disables. Mere function presence
never grants execution authority. Reviewed local collectors and policy deploy
together. Remote collectors also declare a reviewed request ceiling. Actions
Activity finishes ordinary owner-scoped collection first, admits the full
ceiling only above the selected credential's protected reserve, and persists a
secret-free grant that is consumed before every uncached REST, search, artifact
or GraphQL request. Missing enforcement, insufficient capacity and exhaustion
fail closed without replacing accepted evidence. Hosted cycles keep remote
collection deferred until they provide equivalent admission. Due collectors run
only within effective collection scope and frozen cadence. They continue from
the retained proof/cutoff, reuse immutable receipts, merged implementations,
snapshots and Git measurements, and refresh only the new discovery/source
interval plus required mutable lifecycle evidence. Failed refreshes retain the
previous capture without reporting a fresh success or zero. Disabling collection retains history.
No dashboard navigation, report upload or workflow discovery creates an opt-in,
and no per-workflow schedule or model call is introduced.
The optional Go ADX add-on (server/internal/adxingest/, documented in
server/ADX-INGEST.md) exports bounded snapshots of already retained completed
canonical sessions through a neutral sessionexport.Reader. PostgreSQL reads
one exact-scope Run and its observations in a repeatable-read transaction,
closed before destination I/O. This is not transactional capture of every
intermediate publication. One immutable approved pending projection/cursor lives
in existing protected operational state, not a second canonical store or queue
platform; oversize/expired delivery records explicit bounded gap summaries.
The existing OAuth host owns one confirmed exporter replica and its
cancellation/drain lifecycle. Default-off means no destination client, token,
worker, capture/state activity, extra GitHub acquisition or changed retention.
The free-compatible destination uses direct streaming HTTP, explicit Entra app
credentials, six typed tables and exact visibility checks before ready-version
publication; curated KQL deduplicates retries and corrections. It does not require
Blob, Event Hubs, ARM provisioning, materialized views or paid ADX features.
server/spec/adx.tsp owns the closed data model and canonical source mappings;
the repository-owned emitter generates Go projection metadata and embedded
operator KQL together. Server-spec checks verify reproducibility and canonical
field/type compatibility. No new PostgreSQL schema or HTTP operation is added.
Enablement requires exact repository scope and destination/data suitability
approval. Independent bounded retries, capacity checks, gaps and degraded status
never make dashboard/collection readiness depend on ADX. Static Pages, local
SQLite, volatile state and per-request workers do not export; v1 does not
propagate deletion/withdrawal or promise physical purge or full-session coverage.
ADX is derived analytics, never enrollment, rollout, billing or query authority.
The local HTTP simulator validates delivery, not Kusto execution or real free
capacity/permissions.
The separately default-off unified trace option (server/internal/adxtrace/,
server/ADX-TRACES.md) reuses co-resident collection's existing usage-artifact
visit before lossy normalization. A staged metadata cache is committed only
after durable approved trace admission; uncaptured attempts remain eligible
for reacquisition within the same authorized scope. No raw trace content enters
canonical PostgreSQL, public shards or dashboard IndexedDB. A closed versioned
content policy, universal rights/content approval and redaction precede private
durable capture. One file-locked worker uses an operator-verified owner-only
durable spool, atomic fsync-backed ledger, immutable multipart trace versions,
bounded 1 MiB streaming batches and exact deduplicated digest verification before
ready manifests. server/spec/trace.tsp owns the additional nine-table contract
and generated Go/KQL. Direct streaming and credentials reuse the existing client;
capacity is configurable without different content models by destination tier.
Full capture or frozen closed-day whole-trace probability sampling retains the
same approved evidence. Frames describe observed acquired repository/run-attempt
cohorts, not complete upstream populations; preserve cutoff, eligibility/source
gaps, N/k, probabilities, weights and delivery readiness. Corrections, late
arrivals, withdrawal and local evidence expiry invalidate frames without refill.
Recorded episode/hop lineage is preserved, never inferred from time; harness
and historical compiled configuration are not inferred from engine IDs or head
SHAs. Curated KQL reconstructs verified ordered JSON and produces evidence-backed
investigation candidates, not causal/savings claims. Offline dataset export
requires separate training-use approval, labelled evidence, tool-schema binding,
source/transform lineage and grouped splits; excludes reasoning by default and
never trains or replays tools. Withdrawal blocks replay, removes private local
content and queues newer destination tombstones and dataset invalidations;
physical purge/backups/external copies require operator reconciliation.
Separately approved, default-off episode/outcome export reads bounded exact-run
canonical PostgreSQL snapshots through sessionexport.MiningReader, without new
GitHub acquisition. A source namespace is frozen in the ledger; selected-attempt
membership, exact Audit/output URL provenance and original clocks remain explicit.
Unknown output attempts are not inferred from a selected trace: only approved
correlated successful creation-tool results can attest the same exact URL.
One fair bounded polling/delivery loop persists independent mining versions and
freshness heartbeats, verifies declared fact counts and invalidates mining/dataset
readiness on correction, source loss, expiry or withdrawal. Unrelated canonical
revisions do not rewrite traces or invalidate semantic dataset lineage.
Outcome datasets pin the mining version, cutoff and rule, independently reviewed
quality, exact attempt and mined episode/output split bindings. Lifecycle
disposition is not correctness; partial scopes and run-attempt sampling do not
establish complete episodes or unbiased episode/output rates.
Static, snapshot-only, admission-only, standalone collect/backfill and
per-request hosts cannot capture traces. Destination failures cannot authorize
collection, widen policy or replace ordinary dashboard readiness.
The independently default-off Parquet session archive
(server/internal/sessionarchive/, server/internal/sessionarchiveblob/,
specs/session-archive.md, and server/SESSION-ARCHIVE.md) adds private full
approved analytics without changing PostgreSQL schemas, queries, ingestion,
retention, or operational state. It reuses the existing approved adxtrace
projection and the authorized pre-normalization acquisition visit. Local
SQLite backfill supplies only snapshot-declared repositories; co-resident
hosted workers supply only enrolled authorized repositories. Archive scope
further narrows those visits. Multiple enabled destinations intersect admitted
metadata-cache membership and fan out capture/withdrawal without another
collector. Failed admission cannot commit an acquisition-cache skip.
One private durable owner stages approved complete traces, converts explicit TypeSpec-generated logical rows through the checksum-pinned DuckDB v1.4.3 CLI into packed immutable Zstandard Parquet, verifies counts/order/integrity, and publishes exact projection membership through fenced generations. Local filesystem generations use locking and durability barriers; hosted generations use a Blob lease, immutable objects/manifests and conditional active publication. Staging acknowledgement follows durable publication, never merely conversion or upload. Query readers pin generations; corrections replace active membership, while withdrawal/authorization loss overrides pinned access and preserves bounded replay fences. Retention and recovery grace are independent of disposable source caches and dashboard detail; logical exclusion is not physical erasure. Publisher retries, maintenance and shutdown belong to the existing server's tracked lifecycle, not PostgreSQL archive state.
Local trusted queries read authorized Parquet directly without persistent DuckDB event tables. Hosted trusted ADX queries require verified external-table layout, exact pinned object hashes and active membership before operations, and real Azure conformance bound to the destination; simulated protocol success does not authorize query activation. Existing HTTP authentication is necessary but insufficient: explicit full-trace-read approval and an exact hosted-reader allowlist with fresh existing strong-authentication assurance gate the private timeline/summary endpoints. Responses recheck authorization, are bounded to 8 MiB/10000 rows and 30 seconds, and never expose arbitrary SQL/KQL, paths, credentials, or caller-selected generations. Existing dashboard query backends, frontend and native ADX profiles are unchanged. Persistent single-owner hosts are required; canvas, ephemeral/per-request hosts and distributed ownership are unsupported. Sampling without existing frozen membership, compaction, arbitrary queries, training and new acquisition remain deferred or fail closed. The ADR remains proposed pending its independent local/hosted acceptance gates and representative capacity evidence.
Owner-run bootstrap initializes this schema and its UTC daily partitions; runtime
opens and validates provisioned state without DDL. Daily owner-run maintenance
keeps historical, current, and 28 upcoming days provisioned, expiring only
complete days at each configured retention cutoff. Weekly layouts require a
fresh canonical schema rebuilt from authoritative inputs without removing
operational audit/queue state. A fixed schema-qualified
ANALYZE capability preserves ingestion statistics without runtime ownership.
Publication refreshes native estimates before daily reconciliation and integrity
checks. Counts, evidence clocks, and capacity accounting use source-local plans
to avoid planner amplification across the daily partition horizon.
Canonical snapshot, admission, and conclusion writes enforce the same
namespace-local Run-subtree capacity boundary: 200,000 rows per Run-owned source
and 256 MiB of combined logical typed-row bytes. After daily-count reconciliation,
oldest complete subtrees are removed atomically, preserving newest evidence,
structural inventory, independent Operational Value, and operational state.
Execution status does not pin canonical detail; durable operational state
remains independent. An oversized newest subtree fails the write without
changing the published revision.
Eviction marks source coverage partial and invalidates full-population sampling
weights. This is not a physical disk/RSS cap or the full three-tier proposal.
Bootstrap performs no legacy conversion or
backward-compatible import. There are no persistent Postgres generations.
The additive daily run-count projection, compact contribution receipts, and
state in specs/dashboard-data.md §72.2 are the only persisted derived-projection
exception; other daily metrics and computation results remain request-scoped.
Redis remains reconstructable
operational state, not an entity
authority. The same server binary provides a read-only diagnostic check-up
that inspects the runtime, Redis operations, Postgres canonical state and
integrity, query definitions, and the optional collection profile. It
produces stable check identifiers as text or versioned JSON, never contacts
GitHub or mutates either store, and requires deep mode to read every source.
Server construction independently resolves an app server target module and an operational backend (and, for Redis, a declarative provider module), then composes their provider-agnostic capabilities before configuring authentication or ingestion. Target modules own authentication, listener ownership, HTTPS, and trusted-proxy requirements. Redis modules own environment mappings, session semantics, process namespace isolation, replica constraints, and collection support. Local, host-neutral container, Azure Functions, and Upstash are compositions rather than provider checks in shared request handling. Startup rejects configurations or services that do not satisfy the selected per-feature coordination scope and restart-persistence capabilities. Business services receive narrow cache, OAuth, limiter, quota, collection, and coordination contracts, never raw commands or concrete adapter assertions. Atomicity, CAS, namespace isolation, and fail-closed errors are mandatory contract semantics; they cannot be disabled by a capability flag. Application-owned maintenance and background work stop before an owned store is closed.
The memory adapter requires mandatory GitHub OAuth, HTTPS, explicit single-process
and volatile-state acknowledgements, and one owning process for HTTP admission,
quota, collectors, projection, and backfill. Platform listeners, multiple replicas,
admission-only deployment, and detached collection/backfill roles are rejected.
Its protected state has separate accounting-byte and entry bounds; cache eviction
cannot evict sessions or accepted work. These bounds do not claim to measure RSS.
On restart all CAO sessions and pending login states are invalid, while GitHub
tokens themselves are not expired or revoked. Revocation retry and acknowledged
unfinished deliveries can be lost. A fresh GitHub scope enumeration gates
admission and workers; partial enumeration never authorizes destructive scope
inference. Retained evidence is replayed through the existing projector, fresh
quota observations fail closed, and backfill is rerun idempotently. The protected
rebuild action also reruns backfill in this mode. Recovery repairs observable
state and available history, not every missed event or expired artifact. There
is no memory disk journal, automatic failover, or dual-write path.
specs/server-operational-storage.md specifies these guarantees.
The optional hosted activation-admission service (server/internal/admission/)
implements gh-aw's separate OIDC-only POST /api/admission contract, never CAO
rollout authority. Explicit server configuration selects a protected, atomically
published policy/accounting snapshot; immutable signed repository, workflow
revision and original-actor identities gate exact enrollment. Accounting must
be fresh and expressed in AI Credits; missing evidence is an outage, not zero.
The initial GitHub.com/string-audience profile denies ambiguous reusable calls
and never authorizes from an unverified triggering actor or workflow hash.
The service receives a narrow durable decision contract; the PostgreSQL
operational adapter atomically retains the first primary/optional allowances,
a non-sliding five-minute authorization window and permanent expiry/revocation
tombstones within protected capacity. Every retry revalidates policy and usage;
transient failures preserve retained decisions. No cache eviction, financial
mutation, dashboard-session authentication, trace-response identifier or CAO
scope widening is permitted. Redis, memory and local modes cannot enable it.
server/ADMISSION.md documents the trust profile, publisher requirements,
capacity/retention lifecycle and cooperative fail-open limitations.
The HTTP contract is pinned to published gh-aw b2707604dd52732afa66ff7ae270bda96cf6c9fd;
its activation wire remains unchanged from merged be70cb4ec4317135a1ab21d5b830b6fae7d5be4a.
Its isolated admission job relays caller-owned tracing through activation.
Valid incoming traceparent parents the server HTTP span and dependencies;
HTTP instrumentation must consume the sanitized context without re-extracting
global baggage/tracestate or another parent. Invalid/duplicate context starts
a fresh trace without changing authorization, and responses expose no trace ID.
Admission reuses the hosted OTLP providers and bounded shutdown flush, emits
fixed-name identity/JWKS/policy/decision/replay spans, and labels HTTP
duration/status metrics with the fixed admission route even across its separate
authentication path. Raw errors, credentials, identities, allowance values and
denial reasons never enter those signals; exporter failures do not change
operation results.
The compiler's isolated conclusion_admission callback uses POST /api/conclusion
on the same configured origin/audience and independently verified identity.
Current exact enrollment authorizes completion independently of budget freshness,
spend thresholds or a prior admission record. The receiver validates the strict
64 KiB envelope, compact profile 1 (128 records/16 KiB), six coverage fields and
up to two canonical artifact IDs before atomically recording the immutable
invocation-bound payload and receipt. Before empty 204 it also populates existing
canonical Run/Audit and available grader collections, then durably marks the
receipt populated. Pending retries repair publication; canonical rows and revision
are idempotent across the separate transactions. Conflicts never overwrite facts.
Publication shares ingestion's namespace lock, reuses verified Run/parent identity,
enriches API-only Runs without replacing known facts, and preserves native event
types, observation time, missing-versus-zero measures and explicitly partial quality.
Usage ranking matches the canonical session adapter by phase/dimension; snapshots,
proxy copies and cumulative AIC are not double counted. Unrelated/API-only snapshot
replacement retains compact facts; collected session evidence at the winning
attempt supersedes them and older attempts cannot mix into newer records.
The callback does not fabricate approval or GitHub workflow outcome/timestamps.
Compact request payloads expire after a
fixed 24 hours and bounded operational maintenance removes them; permanent
digest/completion receipts consume protected capacity and prevent late recreation.
There is no public session read, artifact fetch, hydration, billing settlement
or inferred GitHub run-result mutation. Canonical typed facts use ordinary
dashboard evidence retention. Full sessions remain unavailable until an
independently authenticated, invocation-bound consumer exists; compact metadata
and overlapping usage are untrusted evidence, not complete accounting.
The callback shares admission's deadlines, peer limiting, sanitized tracing and
private no-store responses, with no new rollout or credential authority.
Verified successful admission publishes a sparse canonical Run in admitted
state before returning approval; blocked attempts publish nothing. Publication
uses existing canonical IDs, inserts only missing parent identity facts,
advances revision once and never downgrades collected evidence. Namespace
ingestion locks serialize publication with replacement; replacement temporarily
preserves missing admitted runs/parents but authoritative incoming Run evidence
wins. Sparse quality stays partial and no start/completion/spend is inferred.
Canonical publication failure is transient without changing the first durable
decision; retry repairs the idempotent projection, not a financial commitment.
Native gh cao admission setup/status/disable commands configure the
selected scope's three managed non-secret variables. gh cao setup admission
reuses admission setup without introducing workflow secrets. Setup/disable apply
unless --dry-run is supplied; setup defaults to outage block, publishes the URL
last and preserves unrelated defaults. Status resolves available organization
variables beneath repository overrides; disable writes an empty repository URL
rather than deleting an override that could reactivate inheritance. These
commands neither deploy/enroll an authority nor change CAO rollout policy.
Bulk --all-repos selects exact repositories from validated global CAO scope
or enumerates allowed organization inventories when no exact list exists.
Explicit repeatable --org and --enterprise select organization variables
with visibility all; enterprise rollout enumerates organizations, never invents
an enterprise Actions-variable scope. Repository overrides remain authoritative.
Discovery and all variable preflight reads precede mutations; bounded sequential
writes report partial progress and stop without automatic retries or rollback.
Setup reuses an existing target endpoint/audience, or the current control
repository's effective configuration for bulk rollout and disabled-target
recovery, when --url is omitted; missing configuration is an error.
The server's read-only admission validate command checks protected policy and
current accounting without network calls, mutations or fabricated evidence;
it does not attest live deployment readiness. docs/admission-gate.md covers
the operator journey and the independent trusted-publisher requirement.
Hosted CLI actions are an experimental opt-in
serve-hosted --experimental --hosted-cli-actions mode. Step-up administrators
enqueue catalog-declared actions into the PostgreSQL CLI command queue after the
server checks their own repository permission. Web replicas share durable
queue state; executor replicas coordinate through one fenced lease and durable
execution claims, so a command is not dispatched twice. A crash with uncertain
subprocess state blocks further claims until an operator confirms termination
and acknowledges recovery; interrupted commands are never automatically
replayed, so external effects are not exactly-once. Command deadlines and queue
state survive process restarts. A separate execute-cli process drains the
queue, rechecks the actor's live write permission, and runs each command in an
isolated workspace with a single-use, repository-scoped GitHub App installation
token that is revoked on completion. A bounded broker pre-mints tokens for
backlog.
The Go planner translates the hosted CAO package-update action into a native
gh-aw update; it never executes control-repository shell scripts.
The executor runs only gh or the Go gh-aw CLI in the official digest-pinned
gh-aw container by default, mounting only command-owned workspace and egress
relay/socket resources and passing the
single-use token through a temporary protected environment file. The broker
revokes and rejects any token whose granted scope exceeds the request. Both
processes append credential-free audit events (server/internal/audit) to the
hash-chained, append-only PostgreSQL table cao_operational_audit_events and
mirror logger-produced events as JSON lines; privileged steps fail closed
when the event cannot be stored. Result commits, claim settlement and
interrupted-command recovery append lifecycle evidence in the same queue
transaction, using state transitions to deduplicate replay. Unconfirmed VM
termination and audit failures retain execution claims. Token cleanup replaces
encrypted ownership with a credential-free terminal receipt independently of
audit availability, then atomically appends its evidence and deletes the
receipt. CAS journal transitions preserve pending failure evidence and terminal
receipts without expiry; capacity exhaustion backpressures issuance rather
than evicting them. Receipt replay never issues or revokes credentials.
External revocation before local receipt persistence remains an explicit
uncertainty window, resolved by a later repeat revoke or expiry observation,
not an exactly-once claim. Complete forwarding consumes committed audit rows,
including storage-owned events absent from the inline mirror.
For local debugging only, --hosted-cli-sqlite and execute-cli --sqlite
share a loopback-only SQLite file (server/internal/operational/sqlite) that
provides the same queue and audit table without PostgreSQL.
Local database bootstrap --store operational --sqlite PATH provisions that
file explicitly; runtime opens only existing state, and audit retention runs
only through the explicit database retain-audit command. audit deliver
uses a read-only SQLite connection and deferred verification transaction, while
audit verify retains append authority to record its result. SQLite does not
replace the canonical dashboard backend or reproduce PostgreSQL role isolation.
That SQLite development profile may explicitly select an alternative
ContainerLifecycle adapter without changing admission or token authority.
Docker remains the production default and keeps its local-default-context
restriction. Production workloads use --network none; a private read-only
Unix socket and SHA-256-verified, architecture-matched relay built from reviewed
server source carry HTTPS CONNECT to an executor-owned exact-host proxy.
Every DNS address is validated before numeric dialing, private GHES needs
exact host/IP approval, and metadata/loopback/link-local reach stays denied.
Policy and verified relay bytes are immutable for the executor lifetime.
Missing production egress configuration fails startup; only SQLite Docker
development with no egress settings retains the previous bridge mode.
The proxy is bounded and canceled with its command; losing egress never proves
workload termination or releases retained claims. No shared host-network
configuration changes or new runtime providers are introduced.
Apple Silicon development uses Apple's container CLI with the
same pinned Linux image, a private VM, dropped capabilities, and an in-guest
no-new-privileges bootstrap. Windows development uses Windows Sandbox and a
separately SHA-256-pinned archive of Windows gh, gh-aw, and Git tools, not a
Linux-image fallback. Native providers preserve registration before creation,
private workspace isolation, bounded cleanup, and original-runtime recovery.
Guest result receipts or launcher exit never prove VM termination. Windows
Sandbox ownership is exclusive across local executor namespaces; unrelated
user sandboxes must not be reused or stopped. Without a verified Sandbox-to-HCS
VM identity mapping, this conservative profile rejects other HCS-managed VMs
and requires empty host-compute VM inventory before settlement.
These development exceptions do
not enable a new production runtime or exactly-once external effects.
Tokens appear in those events only as GitHub's hashed_token digest.
cao-dashboard audit verify checks the chain against external head anchors
and audit export writes rows as JSON Lines. Logger-produced audit events are also OTLP log
records carrying the active trace ID, and the executor and broker emit
command and token spans and metrics without tokens or actors.
Every hosted administrator operation requires a fresh, assured interactive
OAuth authentication (2FA or attested SSO) within a bounded maximum age.
specs/server-hosted-cli.md and specs/tla/HostedCLIActions.tla specify and
model these guarantees.
The PostgreSQL operational adapter is independent of postgresx canonical
storage and the TypeSpec-generated entity schema. It implements narrow cache,
OAuth, request-limit, quota, collection, coordination, and diagnostic contracts.
Each namespace has a row lock serializing atomic transitions and protected
accounting across replicas. Cache bounds are independent, and session admission
reserves logout/revocation capacity. All replicas must use identical capacity
settings. Database time governs expiry; blocking queue reads release transactions
between cancellation-aware polling attempts. Application-owned maintenance
reclaims only bounded expired state. Sessions, accepted work, enrollment,
checkpoints, and pending revocations survive process restart under the database's
configured durability. Backend selection comes from reviewed host policy, with PostgreSQL as the
selector-free default and explicit legacy Redis configuration preserved.
This is not an operational-state migration, fallback, or campaign rollout change.
The read-only doctor opens existing
operational state without initializing it.
PostgreSQL bootstrap, runtime, audit retention, and evidence-reader credentials
are separate authorities. Runtime uses audit SELECT/INSERT and namespace budget
updates, not namespace destruction or DDL. Audit retention runs only through a
separately granted owner-defined function with a pinned search path and fixed
400-day/512-row limits; ordinary maintenance never deletes audit history.
server/POSTGRES.md specifies migration order, grants, and operator schedules.
Hosted server observability uses the same vendor-neutral OTLP contract as
agentic workflows. Standard OTEL_* runtime environment variables select the
collector; exporter endpoints and headers remain deployment secrets and never
enter policy, browser state, or logs. Server debug and error logs may also be
exported through OTLP when CAO_OTEL_LOGS_ENABLED=true and a log endpoint are
configured; the existing DEBUG namespace patterns select which logs are sent.
When tracing is active, every API response
has W3C trace and span headers. JSON failures repeat those identifiers, the
browser exposes the trace ID as a request ID, and bounded server error logs emit
the same identifiers so operators and agents can correlate client failures,
server logs, query and ingestion spans, and Postgres child spans. An
observability backend is diagnostic infrastructure only: it cannot become
dashboard data authority, policy, or rollout authority.
The local Go serve command defaults to a cached canonical SQLite projection
through the ordinary HTTP query, canonical API, diagnostics, revision
subscriptions, and optional read-only MCP boundary.
It reuses .cao/gh-aw-logs.sqlite in the checkout without another download, or
downloads deployed data on demand when the cache is missing. --sqlite PATH
selects another cache with the same behavior. An explicit --postgres-url,
--source, or --redis-url selects the PostgreSQL profile; database service
environment variables alone do not override the SQLite default.
server/internal/sqlitex/ implements the existing canonical storage reader
contract behind server/internal/dashboardstore/; PostgreSQL's SQL executor,
ingestion, and hosted defaults remain unchanged.
Automatic acquisition uses DASHBOARD_DATA_URL or the public CAO Pages snapshot.
serve --download-sqlite[=URL] explicitly refreshes even an existing cache before
opening it. Any Pages site or custom-domain directory, dashboard directory, or
direct manifest URL may supply the snapshot; directory
discovery checks its root and then cao/ on HTTP 404. Bounded streaming,
manifest SHA-256 verification, and canonical-version validation precede atomic
replacement; failed acquisition preserves the old file and fails startup.
This acquisition path does not ingest shards or relax read-only snapshot access.
Invalid or unreadable existing caches and dangling symlinks fail closed rather
than triggering automatic repair downloads.
This profile is loopback-only and bearer-authenticated, with no PostgreSQL or
Redis service requirement. It opens the existing versioned snapshot read-only,
never bootstraps, migrates, repairs or ingests it, and uses one consistent read
transaction per request. The bounded native Go evaluator and canonical SQLite
reader live in the small independent internal/dashboardquery/ module shared
by the root extension and server; neither module acquires the other's dependency
graph. Request services use bounded volatile memory without OAuth, collection,
webhook, or hosted execution capabilities. Query result caching is disabled;
in-place commits change the revision and notify active subscriptions. Snapshot
quality remains unknown without stronger evidence. This default local mode
does not introduce a hosted SQLite backend or a fallback from PostgreSQL.
Outside the internal canvas profile, SQLite's native ATTACH DATABASE links the
read-only snapshot to a writable local delta (--sqlite-overlay, default
snapshot path plus .local.sqlite). The shared overlay SQL in
internal/dashboardquery/overlay.sql unions historical records with local
upserts and deletion markers without copying snapshot records. Every HTTP
request remains query-only. The overlay is bound to the snapshot's canonical
content revision; a different base requires another overlay and never silently
discards the previous delta.
Local background backfill uses GH_TOKEN, GITHUB_TOKEN, or the local gh
login, never a hosted App identity. It refreshes only repositories present in the
deployed snapshot (at most 10,000), with no token-driven inventory expansion,
rollout changes, webhooks, or hosted collector authority. Per-repository run
watermarks overlap one day and include older unfinished runs within 30 days;
collection is capped at 10,000 runs and five minutes per repository, and 30
minutes per pass. The existing Activity collector/compactor and canonical
ingester read the attached history while writing a staged copy of only the
local delta. Failed repositories are discarded and reported independently;
failed ingestion never changes committed data. Successful publication swaps
local rows and tombstones transactionally, rejects a stale concurrent generation,
and broadcasts the revision. Private per-pass evidence is removed afterward.
Backfill starts asynchronously and repeats five minutes after each pass;
--backfill-interval changes that delay and --backfill=false provides offline
serving while retaining local data. Missing credentials/tools or failed refreshes
are explicit and retry without blocking snapshot serving or claiming complete
quality. Application shutdown cancels and joins this local work. The internal
canvas and read-only constructor remain snapshot-only.
Its fixed local evaluator profile admits 500,000 input/intermediate rows and 50 million operations with 1 GiB working-source and 2 GiB / 2 million live retained-row budgets; final-consumer release discards completed DAG inputs. Backward field liveness narrows row-local projections and removes unused pure computations. SQLite executes root field selection natively while retaining full stored-record byte checks, JSON types, missing-value semantics and IndexedDB UTF-16 key ordering; unknown shapes and requested raw sources remain complete. Read-only memory mapping is capped at 1 GiB. Remaining local operators execute in the shared Go evaluator, not a claimed SQLite SQL-plan compiler. Wire output remains bounded to 100,000 rows. The shared engine's default CLI limits and hosted PostgreSQL limits remain unchanged. This local-only profile defaults to a 300-unit/minute weighted query-admission bucket while preserving explicit embedding overrides and all other request policies.
The hosted dashboard has one strict storage split:
| Store | Owns | Must not own |
|---|---|---|
PostgreSQL canonical adapter (postgresx) |
Current dashboard entities, quality metadata, diagnostics, revision state, and Dashboard Language query execution | Operational records, sessions, queues, and transient resolver caches |
| PostgreSQL operational adapter (default) | Deployment-scoped durable operational services in separate cao_operational_* tables and namespace |
Canonical entities, canonical schema changes, Dashboard Language execution, automatic migration, or fallback |
| Redis | Sessions, rate limits, webhook and collection queues, delivery deduplication, distributed coordination, GitHub quota state, pending token revocations, and bounded runtime caches | Dashboard entity rows, canonical source documents, query indexes, persistent query projections, or dashboard query execution |
| In-process memory (explicit opt-in) | The same operational contracts within one owning process, with bounded volatile state and restart recovery limitations | Dashboard entity storage, query execution, cross-process coordination, restart durability, or fallback for a failed Redis deployment |
The Go HTTP(S) server serves the hosted dashboard itself, including its built
HTML, JavaScript and other assets, OAuth routes, query API, and revision events
on one origin. Container, Azure Functions, and externally owned listeners all
expose the complete CAO handler, not an API behind a separately hosted Pages
application. Hosted startup requires a readable, non-empty built index.html.
The server injects the server-http backend bootstrap into dashboard entry
responses; the browser uses server-side PostgreSQL queries rather than static
shard ingestion or IndexedDB query execution. Hosted failures do not fall back
to the separate Pages deployment.
The browser communicates only with the Go HTTP(S) server. It never connects to either store. Artifact ingestion and rebuilds transactionally replace the current PostgreSQL data; Redis failure may make protected operations unavailable, but Redis is never a fallback dashboard database. PostgreSQL failure makes dashboard data unavailable even when Redis is healthy.
An externally owned HTTP host is a separate, explicit generic target with
listener: external, not an alias for Azure's platform listener. The public
server/hosting/ facade constructs the same hosted CAO application from the
reviewed host policy, starts its artifact projection and optional collection,
and exposes only the complete http.Handler. The host owns transport and
graceful HTTP draining; CAO owns OAuth, session/CSRF authorization, webhook
verification, proxy trust, rate limits, Redis, and background-task cancellation.
Requests fail closed before startup and after shutdown. The host must preserve
streaming and response deadline control for revision events, and must not apply
a finite whole-request timeout to that route. External hosting introduces no
runtime-loaded modules, rollout authority, or dependency on a particular
HTTP framework.
Hosted startup may compile that profile and its generic Redis connection from
the non-secret control-plane.web.host section of
.github/workflows/cao.json. The policy names environment variables rather
than storing connection URLs, credentials, server-name overrides, or CA
certificates. Managed-provider modules map provider conventions into the same
generic URL and verified-TLS configuration; they do not create provider-specific
runtime paths. When no host section exists, legacy environment configuration is
retained for existing deployments.
Modules are compiled registry entries, not dynamically loaded code. Policy selects one target and one operational backend; Redis selection also resolves one provider module. Unknown names, attempts to override fixed module capabilities, incompatible compositions, and runtime clients that do not satisfy the composed profile fail before serving traffic.
The host-neutral server also has a constrained Upstash profile for a provider that guarantees causal ordering only within one TCP session. That profile runs exactly one application replica, serializes all Redis operations through one non-reconnecting connection, and uses a fresh internal namespace on every process start. A lost connection fails closed until restart. Restart rebuilds from the verified artifact and invalidates prior sessions. Its encrypted pending-revocation queue alone retains a stable deployment prefix so token revocation retries survive restart; server-side collection is not available in this profile. The default hosted and Azure profiles retain their ordinary pooled Redis behavior.
The Go server profile acquires evidence through exactly one of two mutually
exclusive ingestion profiles. By default the Activity workflow collects
evidence in GitHub Actions and publishes a snapshot that the server ingests.
As an alternative, the server itself collects evidence from GitHub App
installations, admitting webhook deliveries into a queue, collecting one
repository at a time with the same gh aw logs --audit and activity/cao.mjs
commands the workflow runs, and writing into an evidence lake laid out exactly
like a published snapshot. Because the layout is the same, one projector serves
both profiles and a retained lake repopulates a database on cold start without
contacting GitHub. Configuring both profiles fails at startup: a canonical
database has one writer. The collection profile also persists allowlisted
Redis-backed operational counters and exposes a read-only health status API.
Verified GitHub issue lifecycle deliveries for enrolled repositories enqueue
repository collection through the durable operational queue. Webhook payloads
remain invalidation signals, not authority for direct entity-row mutations.
Authorized operators receive the registered collection-health runtime source
through the Dashboard Language query boundary; it is not published or stored in
browser IndexedDB. The Ingestion page renders that bounded snapshot alongside
the rest of the operational dashboard. Delivery-recovery pagination checkpoints
are durable and separate from the processed-delivery high-water mark; a failed
redelivery request cannot advance that mark. Enrollment mutations are
serialized; withdrawal enqueues durable repository erasure before removing the
same enrollment snapshot, and workers serialize deletion with collection under
the repository lease, rechecking scope before collection.
The main thread receives only bounded view payloads in either profile.
Versioned computations transform canonical evidence into partitioned measures
and actionable insights so consumers do not repeatedly scan the full Activity
corpus. Computation results remain derived evidence:
they preserve source quality and provenance and grant no operational authority.
The cao computation runtime-health command executes the first production
measure through declarative canonical queries. Future CLI measures extend the
same computation namespace.
activity/cao.mjs is the executable entry point and preserves the public CLI
exports. activity/cli/ owns argument parsing, dispatch, policy and campaign
configuration, authentication, evidence ingestion and publication, downloads,
and local queries in focused modules. activity/commands/ owns one handler per
command; implementation modules depend on shared helpers, not the entry point.
Successful-Run value computations keep produced safe outputs, native
operational-grader measurements, and efficiency evidence separate; they do not
turn runtime success or output creation into accepted value.
Package-level operational-value.mjs programs compute repository-scoped metric
records through cao operational-value. Automatic remote acquisition remains
deferred without shared per-request API admission; separate workers are not
separate quota. Actions Activity may admit a reviewed collector only after
ordinary collection and only when its complete request ceiling fits above the
protected reserve. It durably counts each uncached GitHub request before
execution and retains accepted packets/proof on missing capacity or exhaustion.
Hosted cycles remain deferred pending equivalent admission. Health reconciles
the latest decision and actual attempt independently of arrival order; unknown
attempts never erase known history.
Bounded cache-only/local computation remains independent:
Actions runs it only after a successful eligible Activity snapshot, while the
hosted worker uses its own single-owner lease and verified private snapshot.
Both use the reviewed local-only standard adapter, explicit local-capability
modules or exact versioned cache reuse, no target credentials or automatic
backfill, and a two-minute batch/thirty-second adapter budget. Scope, explicit
disables, fast, public-only and API-limited gates remain enforced. A later
ordinary snapshot imports completed results; optional work does not acquire
the projection lease, hold a long core evidence lock, or initiate a
compute/publication retry loop. Hosted final publication rechecks enrollment
and the starting generation, manifest, policy and retained-result identities;
changed inputs defer publication rather than overwrite concurrent evidence.
Normalized timestamped records then rebuild
the canonical Operational Value collection in every storage profile.
Package-level problem-clustering.mjs programs read a private Activity SQLite
snapshot and emit bounded problem records with actionable fix prompts through
cao cluster-problems.
Activity validates their output and atomically replaces only the contributing
package's rows in the disposable cao_problems SQLite projection; a failed
package computation retains its prior rows and cannot mutate canonical evidence,
while removing a package removes its rows on the next clustering run. Package
computations run as bounded, timed, cancelable subprocesses so one worker fault
does not block other contributors.
The read-only campaign marketplace is another trusted-resolution flow. An
ordered registry list in cao.json identifies gh-aw package repositories and
references secret names, never secret values. Activity resolves registries
during static precomputation and publishes safe normalized package metadata into
the canonical IndexedDB path. The hosted Go server resolves the same contract
on demand and caches safe results in Redis. Registry credentials remain in the
trusted resolver in both profiles. Marketplace views consume only the existing
data-worker query boundary and render declarative package cards and copy-only
CAO add commands; browsers never fetch registries or install packages.
The browser materializes bounded runtime and failure-scope results by
generation, computes detailed audit causes only for selected or prioritized
partitions, and discards every result safely because canonical evidence remains
reconstructable.
server/cmd/cao-webhook-gateway/ is a standalone, opt-in receiver/dispatcher,
distinct from dashboard webhook reconciliation and collection. Consumer-owned
contracts and pure subscription, bounded generic filter, authorization, and
outcome decisions live in server/internal/webhookgateway/; infrastructure
adapters live in server/internal/webhookgatewayhost/. Event names and
compiler-declared identity constraints are data, not event-specific routing code.
The host reuses existing githubapp authentication, githubquota, operational
request limits, and OpenTelemetry rather than creating parallel frameworks.
The explicit webhook-gateway-runtime target in server/Dockerfile is a lean,
non-root image without Node or dashboard dependencies; the default final
dashboard target is unchanged. Production startup requires an explicit role and policy path.
Receive permits plaintext only on numeric loopback; non-loopback listeners
require both TLS certificate and key.
The explicit local role uses a private, dedicated SQLite queue adapter under
server/internal/operational/sqlite/ and a read-only repository Events API
polling adapter under server/internal/webhookgatewaylocal/. It passes signed
in-process HTTP requests through the real ingress and runs the real fenced
worker; only authorization evidence and dispatch acceptance are synthetic.
It requires an exact repository and absolute database file, rejects production
credentials/policy options, cannot issue GitHub writes, and never activates
reviewed policy. Atomic receipts, revisions, rate tokens, CAS versions, and
uncertain-dispatch recovery survive restart. The feed is bounded/best-effort,
not a lossless webhook source or Projects integration. Polling recognizes known
event IDs through committed retained receipts, without re-signing mutable feed
payloads or weakening ingress digest-conflict rejection. RFC-034 defines this
non-authoritative profile, its TLA+ model, and executable conformance traces.
Receive and dispatch are separate processes and credential domains. Receive
verifies bounded raw deliveries with source-specific HMAC secrets (or Azure
service-hook HTTPS Basic credentials) and holds no App private keys.
Dispatch holds independent receiving-App and dispatch-App private keys, but
no ingress credentials. Receiving access is read-only except independently reviewed
source label-consumption grants. It primes 30-second admission authorization proofs in the existing
operational StateStore, even with an empty queue. One primer loop retains a
rotating cursor across deadline-limited rounds so slow or failed subscriptions
cannot always starve later routes. Egress independently rechecks
live GitHub installation/repository grants, identities, visibility, current root
scope, and approved revision; an admission proof never authorizes sending.
Fresh control-plane.webhook-gateway policy in .github/workflows/cao.json
binds exact-SHA compiler artifacts and digests separately from administrative
grants. Missing or invalid policy/evidence fails closed without stale fallback.
The gateway is not installed or enabled by default and cannot widen campaign
scope, enablement, or live authority. Repository and owner allowlists intersect
when both are declared. Production source/destination repositories must be
private; public/internal, archived, disabled, or inaccessible repositories fail
closed. An omitted source repository ID binds organization-only deliveries,
never a wildcard over organization repositories; repository-bearing events
require exact source repository identity at admission and egress.
Static source-route additions, adding/removing managed discovery,
deployment identity and capacity changes require restart; root-scope changes
require a new gateway revision.
Monotonic persisted queue revisions reject
stale callers and serialize observed revocation with the irreversible dispatch
reservation; they cannot recall an in-flight request or guarantee instantaneous
remote revocation.
The existing PostgreSQL operational adapter extends its own namespace with
cao_operational_webhook_* tables, not canonical dashboard schema or collection
jobs. Atomic bounded batch admission reserves deduplication and protected
capacity together. Database-time leases, ownership fences and version CAS guard
claims and completion; HTTP and backoff remain outside database transactions.
Outbound handlers always consume batches of one event kind. Compiler v2 carries
distinct projected deliveries in aw_context.webhook.deliveries and derives
the unique affected-resource array at aw_context.items; incoming item lists
and extra provenance fields are forbidden. Durable immutable provenance binds
the approved artifact revision passed out of band through CompilerDispatcher;
missing capability/evidence blocks sending. Generic approved routes instead
carry a nonempty unique-projection aw_context array, sorted delivery provenance,
and runtime batch identity. Full subscription, artifact/queue revision and
immutable source identities must agree; distinct activity history must not be
discarded or replaced with inferred latest state. The two-second long-running coalescing threshold flushes
singletons; local one-shot flushes immediately. At most 64 jobs and both gateway/
compiler byte ceilings bound each batch; overflow stays Ready. Persisted
tenant/subscription cursor rotation balances workflow routes across replicas,
whose concurrency counts claim groups rather than member rows.
Every member fence and fresh claim-bound authorization must pass one atomic
all-member dispatch reservation with one rate/quota charge per request.
Quota-observation persistence failures before the outbound POST block sending;
post-send failures cannot overwrite known HTTP acceptance or cause replay.
Compatible members may share newly fetched GitHub authority facts, never
admission proofs. Completion is atomic across all member fences; lost/unknown
acceptance makes every reserved member ambiguous, never per-event replay.
Workflow-dispatch metadata must explicitly attest all five batch inputs with
both gatewayInput and batchInput. Legacy singleton wire transport is rejected.
Uncertain acceptance or expired dispatch leases become terminal ambiguous,
never automatic replay. Acceptance is not workflow success or operational value.
Cancellation joins owned workers before storage closes.
specs/rfc-033-webhook-gateway.md specifies the safety contract and bounded model.
The offline discover role builds a bounded, deterministic event-to-workflow
mapping from the compiled .lock.yml single-line gh-aw-manifest header's
webhook_subscriptions, preserving typed conditions, complete paired any_of
groups, dispatch/context routes and limits, and whole-artifact digests. It never
interprets steps/frontmatter or activates subscriptions. This tracks the
inspected github/gh-aw#69772 proposal, not a claim about the installed compiler.
Reviewed discovery.repositories binds at most 64 exact repository names/IDs
and separate receiving/dispatch installation IDs. The dispatch role backfills
and periodically scans only those repositories with fresh repository-restricted
read tokens, regular top-level locks pinned to one default-branch SHA, bounded
file/byte inventories, and a final head recheck. The fixed HMAC compiler route
durably invalidates on lock-update/repository-change hints, without exposing
App keys to the receiver. A protected PostgreSQL operational record publishes
inventory CAS and effective queue-revision changes in one transaction; every
hint fences earlier scans, including already-dirty inventories. Routing changes
cancel old ready/claimed work, while timestamp-only refreshes retain the queue
revision. Reviewed control revisions remain a separate monotonic ceiling.
Explicit activateSecurity delegates only compiler-supported Dependabot and
code-scanning repository events with batch-capable declaration v2 to compiler
routes, with private-only live checks,
event/contents-read permission checks, bounded grants expiring at inventory
freshness, and minimal security notifications under required
dispatch.payload_projection: {"policy":"resource-url-types-filters/v2"}. Missing or
unknown policies and legacy projections fail closed, without a native-body
fallback. Original deliveries are authenticated, classified, and filtered before
projection; GitHub type contains exactly the original action, bound to durable
event identity. Optional filters contains only observed matching literals for
every shared condition and one complete matching alternative, never unselected
array elements, nested source objects, or cross-combined transition pairs.
Azure selected lifecycle matches additionally carry exactly one matching
filters["closed-states"] terminal name, not a source-path condition: entered for
closed, departed for reopened. Otherwise that key is absent. Without predicates
or a selected Azure lifecycle match, filters are omitted except for the explicit
command event/token or label evidence described below. Both old
resource-url-types/v1 and resource-url-types-filters/v1 policies are nonactivating.
All additional data must be resolved inside the workflow through
configured provider-authenticated readers; notification URLs never grant access.
Canonical HTTPS api.github.com
alert URLs must agree with signed source repository/number at ingress and
authenticated current source repository at egress; other API origins are unsupported.
Optional declaration repos is a nonempty bounded lowercase/sorted/unique list
of exact owner/repo or literal owner/* selectors. It intersects reviewed
enrollment and root scope without enumerating App inventory or granting
authority; omission preserves same-repository activation. Both source and
declaring workflow need clean fresh private inventories. A missing workflow
directory may count as an empty source-only inventory only after authenticated
private repository checks and successful initial/final head checks. Each source
has its own tenant, receiving installation, subscription, grant and batch;
destination installation/repository and approved head/lock digest remain the
declaring workflow's. Grants expire at the earlier inventory freshness bound.
Source selectors and URL identity are checked again against live receiving-App
access; workflow revision approval uses the dispatch App and destination
identity. Invalidating either inventory fences affected queued authority.
Secret-scanning declarations are not emitted/supported by this compiler contract.
Missing/invalid/dirty/expired inventories cannot remain active. Both receiving
authority and independent final egress preflight re-fetch the current head and
whole-lock digest. This does not guarantee immutable default-branch execution
across a subsequent remote mutation; deployment must establish trust in the
reviewed/protected default branch. projectAssignments binds each project node
and organization to one enrolled repository and constrains separately approved
subscriptions; discovery does not autoactivate Projects. Hand-authored fixtures,
mock GitHub tests, and separate bounded registry, source-selection and dispatch-batch TLA+ models
demonstrate local contracts, not installed-compiler or live GitHub acceptance.
Legacy compiler declaration v1 remains discovery-only. Declaration-v2 fixed
context paths, same-event/delivery-ID batching, minimal URL/type/matching-filter policy,
and optional source selectors match github/gh-aw#69772 commit fe4f420f. Gateway
aw_context contains only webhook, never supplied items, provenance, or resource
details. Context resource identities are derived from canonical URLs. Discovery
supports Projects, both security families, Jira, Linear, Azure DevOps, ten GitHub
notification families, and synthetic slash/label-command declarations. Custom
webhook declarations and enrollments reject. Projects remain discovery-only. Reviewed, expiring
externalSources independently binds each external route's family, canonical
HTTPS resource prefix, provider scope/collection,
receive-only secret environment name, and explicitly enrolled
private destination IDs. Enrollment is required even when security delegation is
disabled; declarations alone never register sources. Source additions require
restart. Current enrollment plus native authentication establishes external source
authority, not a live provider resource-access or visibility probe. External
references are conservatively restricted; current private GitHub destination
identity, head and whole-lock digest are still independently checked. Source-local
delivery IDs are namespaced.
Native bodies and normalization evidence are never persisted or forwarded.
Incompatible persisted inventories remain nonactivating at the current
policy revision. A higher reviewed gateway policy revision atomically discards
them, fences old ready/claimed work, and permits bounded rediscovery without
reinterpreting old payloads or expanding authority.
Upstream authoring places all declarations under on.gateway-dispatch, with
shared repos selecting notifications, code-scanning/Dependabot and command sources.
The repository's .github/workflows/aw.json opt-in {"gateway-dispatch":true}
remains independently required. Gateway dispatch is exclusive of all other
workflow triggers; non-trigger settings such as roles/bots remain allowed. These compilation
gates never grant activation or dispatch authority; flat triggers, trigger-local
repos, the former workflow on.webhook-gateway flag, obsolete on.gateway,
singular Projects/security spellings, and explicit workflow/repository-dispatch co-declarations
are rejected. Custom webhooks arrays and synthetic event:"webhook" admission
are excluded; the separate manually approved route contract does not provide a
compiler fallback.
Optional compiler orgs is a lowercase/sorted/unique bounded list of GitHub
organization names or * patterns. It intersects repos, project scopes and
reviewed source enrollment, never widens scope or enumerates App inventory.
Registry activation and live source preflight require authenticated Organization
owner type/ID, not merely matching URL owner text; commands also intersect these
GitHub organization selectors, while external families reject this
GitHub-only metadata and retain their mandatory native scopes.
Jira/Linear HMAC and Azure HTTPS Basic authentication are source-specific; Linear
also checks signed timestamps within one minute and acknowledges durable success
with HTTP 200. Receiver and admission policy
revisions must agree. Native normalization derives all established activities,
including edited on updates, but projection and durable activity identity retain
only their intersection with the subscription's selected types. An empty
intersection or contradictory closed/reopened evidence cannot qualify. Every
forwarded type must be selected. Azure closure/reopening requires complete
delivered old/new state evidence and forwards only the applicable configured
terminal name, never the nonterminal side or the entire configured set.
Optional runtime interoperability executes that source's actual validator/
normalizer, including exact/wildcard sources and whole-batch selector rejection,
not a hosted workflow or an installed compiler.
GitHub notifications require separately reviewed discovery.activateNotifications,
absent/false by default, fresh private source/destination inventories, read-only
source-category permissions, shared repos/orgs selectors and independently approved
routes. The embedded semantic catalog mirrors the pinned upstream
github_notification_webhooks.json; conformance compares every semantic field.
The receiver filters original actions, typed catalog conditions and the strict
absent-versus-object issue.pull_request split before projection. Canonical HTML
URLs bind original repository, parent number/commit SHA and comment/review ID to
the reviewed GitHub server and exact Enterprise base path. Review threads require
the first delivered comment's URL and ID; missing evidence never triggers hydration.
Only selected singleton actions and actual declared matching filter literals
persist. Bodyless notifications, reviews and commit comments do not widen the
seven-source command catalog or confer label writes. Source registration and
workflow-trigger exclusivity are separate compiler/enrollment concerns.
Native gateway slash/label commands follow the exact catalog and actual runtime
at github/gh-aw@fe4f420f3f4f40bb1ebbcca85af0903d3a967bf3. Independent reviewed
discovery.activateCommands is absent/false by default. Shared source selectors,
private source/destination inventories, immutable approved routes, fresh App
authority, and the existing numeric-v2/projection-v2 fences still apply.
The receiver alone splits issue versus PR comments, checks original actions and
body paths, parses position-zero tokens with native exact/catch-all/trailing-star
semantics, and matches exact labels. It forwards only the canonical original HTML
item/comment URL, selected singleton action, and exact filters.event plus
filters.command or filters.label; bodies and arguments never persist.
Only the seven native comment/body sources qualify; reviews and bodyless actions
do not. Comment anchors must match the selected source and positive original ID.
The reviewed discovery.serverUrl (public GitHub by default), including a clean
base path, must agree with the receiving API client and resource origin/path.
URLs cannot register a server or confer access. Compiler prompt gateway.events
is local normalized-delivery sugar, not an extra payload channel.
Gateway label commands require remove_label:true metadata; false is rejected,
not a read-only activation mode, matching the published contract.
Label consumption additionally requires the source's independently reviewed
allowLabelRemoval grant and current receiving-App issues/pull_requests/discussions
write permission, never just remove_label metadata. Only the dispatch role has
this capability; receive and local simulation remain mutation-free. Each write
rechecks source authority and occurs after atomic durable batch admission, under
the existing fenced deadline and shared quota. A protected atomic attempt marker
and expiring success receipt outlive the maximum job TTL. Confirmed receipts
survive restart and suppress duplicate writes; unknown outcomes cannot be replayed
against later reapplied labels. Unconfirmed consumption makes the batch terminal
ambiguous without dispatch. Minimal REST issue/PR and GraphQL discussion reads
and removal remain authenticated and never hydrate notification payloads.
| Path | Responsibility |
|---|---|
aw.yml |
Root catalog manifest and default CAO installation bundle. |
<operation>/aw.yml |
Campaign boundary and installation manifest for an operation. User-facing operations include cao-evolution/, dependabot/, eu-cra-compliance/, optimization/, repo-assist/, self-care/, software-development-practices/, and uk-ai-advisory/. |
<operation>/operational-value.mjs |
Optional deterministic repository-scoped operational-value computation installed with its package. |
<operation>/problem-clustering.mjs |
Optional bounded problem computation installed with its package. |
activity/ |
Deterministic Activity collection, JSONL ingestion, SQLite projection, and the cao CLI. |
cmd/gh-cao/, internal/cli/, internal/ghcli/, dashboard/catalog.go |
Independent, entirely Go operator-facing gh cao executable, including onboarding, campaign and policy management, SQLite queries, computations and MCP; embeds the dashboard's authoritative JSON contracts. Actions pipeline commands remain Node-owned. |
internal/dashboardquery/ |
Small independent Go module sharing the bounded local Dashboard Language evaluator and read-only canonical SQLite reader between the extension and explicit local server profile; never a hosted PostgreSQL fallback. |
dashboard/ |
Dashboard campaign, report/source adapters, canvas-only authoring bridge, and shared browser UI built for Pages or the unified Go server. |
server/ |
Optional host-neutral Go HTTP(S) service, deployed-artifact ingester, authenticated canonical API, webhook/rebuild control, Postgres entity storage and default operational state, explicit Redis or single-process memory alternatives, server-side Dashboard Language query engine, externally hosted handler facade, container image, and Azure Functions deployment profile. |
server/cmd/cao-webhook-gateway/, server/internal/webhookgateway/, server/internal/webhookgatewayhost/ |
Optional isolated gateway entry point, consumer contracts and pure decisions, and host adapters; durable state extends the existing PostgreSQL operational adapter. |
server/spec/ |
Editable TypeSpec HTTP/SSE, fresh Postgres storage and optional ADX export contracts; generates OpenAPI 3.1, wire JSON Schemas, standalone SQL DDL, Go bindings and ADX setup KQL; checks routes, payloads and canonical field coverage. |
dashboard/site/src/data/ |
Canonical browser data model, adapters, normalization, storage, and declarative query engine. |
research/ |
Executable notebooks and experimental reference runtimes used to validate proposed computation semantics against canonical data; these are not dashboard production code. |
specs/computations.md |
Versioned computation, bounded insight, provenance, quality, and measure contracts. |
specs/repository-layout-and-installation.md |
Normative canonical runtime layout, ownership, materialization, and installation lifecycle contract. |
.github/workflows/*.md |
Editable gh-aw workflow sources. |
.github/workflows/*.lock.yml |
Generated workflow artifacts; never edit these directly. |
.github/workflows/shared/ |
Shared policy resolution, control admission, checkout, review-bundle, and observability components. |
.github/workflows/cao.json |
Sole persistent, non-secret rollout policy for this source-managed control plane. |
.github/aw/ |
gh-aw instruction, package, and generated campaign-ownership metadata only; CAO executable resources stay at their canonical catalog source paths. |
.github/cao/instructions.md |
CAO-specific operator and authoring guidance; it does not grant rollout authority or execution capabilities. |
skills/ |
Portable Agent Plugin skills exposed by this repository. |
specs/ |
Normative control, Activity, dashboard, and data contracts. |
docs/ |
Explanatory and operator-facing documentation site. |
adr/ |
Durable architectural decision history; normative contracts remain in specs/ and specification-style documentation. |
tests/ |
Unit, integration, load, and workflow-contract tests. |
scripts/ |
Repository validation and maintenance utilities. |
The extension's root go.mod is separate from server/go.mod.
cmd/gh-cao/ owns process lifecycle and depends on internal/cli/, which
depends on internal/ghcli/ and the declarative assets embedded by
dashboard/catalog.go. Shared logging comes from
github.com/github/gh-aw/pkg/logger; GitHub CLI execution uses
github.com/cli/go-gh/v2, the same helper used by gh-aw. The Go command layer
owns all extension implementation, argument validation and help. Campaign installation, policy
initialization, campaign mode changes, and workflow enablement run natively in Go.
gh cao add delegates package ownership and workflow generation to
gh aw add, preserves its option vector, then materializes only the selected
campaign from its installed full resolvedCommit SHA or a local catalog's
Git-tracked files. Archive extraction rejects escaping paths and links; staged
resources and declarations are checked before replacing the campaign directory.
Intelligence metadata is refreshed, generated auto-upgrade Actions are pinned
using the installed setup Action, and worker declarations are merged without
widening scope, modes, enablement, or worker ceilings. Missing policy initializes
only the exact current control repository. Initialization refuses
replacement, preview maps to review, and campaign declarations are fully checked
before workflow enablement/disablement. The extension groups guided setup at
gh cao setup and independent credential profiles under
gh cao setup auth github-app|enterprise-app|hosted-cli|token, with no root-level
setup-auth command. Native authentication preserves the setup-auth result
contract, options, credential prompts, consent, and read/write scope boundaries.
Dedicated hosted-executor App setup also runs natively in Go, using the shared
manifest callback and App-authenticated installation helpers. It requests exactly
actions, contents, pull requests and workflows write plus metadata read, requires
explicit same-owner repositories and browser approval, rejects all-repository
installations and verifies every requested target. Its private key is written
exclusively to a new mode-0600 temporary bootstrap file for import into the executor's
secret manager, never printed or passed in arguments. Hosted credentials remain
separate from dashboard login and Actions read/write credentials. Setup never
changes policy, authentication mode or hosted-feature gates. The retired Node
profile fails before side effects; unreferenced Node App-creation administration is
removed while Actions credential profiles and inspection remain in
.github/workflows/shared/github-apps.mjs.
Repository enrollment (gh cao repos add OWNER/REPO),
updates, onboarding, downloads, computations, and all evidence commands in gh cao
run entirely in Go. No extension command invokes Node.js, npm, or JavaScript
modules; CAO_RUNTIME_ROOT is no longer an extension input. The default reviewed
catalog, fragments, canonical source projections, and MCP contract are embedded
directly from the dashboard's JSON documents, not duplicated as a second catalog.
An explicit --dashboard reads a JSON document with directory-confined fragments.
The Go Dashboard Language evaluator resolves those declarations against canonical
SQLite records; the SQLite connection is read-only and performs no migration or
snapshot repair. JavaScript parity oracles are test-only. Empty-PATH standalone
binary tests enforce independence from the installed runtime.
Execution never changes the working directory or grants policy authority.
Help, version, and catalog discovery work without Node or GitHub access. Native Go
doctor performs bounded read-only GitHub CLI, gh-aw version, authentication,
and basic local policy structure/compiler-pin checks, with text or JSON results
and nonzero status for failed or skipped checks. Authentication may contact
GitHub; raw authentication output and subprocess errors are never reported.
Doctor does not replace production policy/workflow validation, grant authority,
or invoke the Node snapshot-repair command. Actions and Node-only tools invoke
node activity/cao.mjs <command> explicitly, including SQLite snapshot repair-database.
There is no shell launcher.
Node cao owns the Actions runtime, gh cao owns the operator interface, and
cao-dashboard owns the server. Node onboarding and lifecycle implementations
and exports are removed: init, setup, setup-auth, campaign add, mode,
enable, disable, update, and upgrade-gh-aw fail with native replacement
guidance before option parsing, stdin, or legacy two-argument ingestion.
There are no Node compatibility wrappers or native-to-Node bridges.
Node evidence APIs remain supported for agents inside agentic workflows.
The registered queries, query-info, prompt, query, gh runs|issues|prs,
computation, mcp, and download commands and their dependencies must remain
available in the installed runtime. Similar reads in the operator extension are
intentional; the workflow APIs are neither deprecated duplicates nor test-only
parity implementations. They preserve canonical Dashboard Language execution,
bounded evidence/output contracts and existing authentication boundaries, without
granting policy authority or GitHub writes.
activity/authentication.mjs retains only Actions credential profiles, naming,
and bounded Activity collection planning, not credential provisioning.
Root runtime upgrades remove only
content-verified retired launchers; consumer-owned files, links, and directories
are preserved. Verified older archives may contain the retired launcher but
never install it.
Human/operator commands belong in the Go extension; server hosting and
administration belong to cao-dashboard. Actions execution support, including
workflow-agent evidence APIs, belongs in the shipped JavaScript runtime under
activity/ and dashboard/.
Agentic workflow execution and agent evidence preparation must not build,
install, or invoke the native extension. Copilot setup stages dashboard evidence
with node activity/cao.mjs download. Dedicated extension build, release, and
operator-installer compatibility tests remain separate from agent runtime.
Control-plane validation is
Actions-only, with one implementation invoked directly as
node activity/cao.mjs validate --json, using the installed runtime revision
and production policy resolver. The extension exposes no validate command.
Native policy parsing still guards operator construction
and mutation; it is not a second control-plane validator. The workflow does not
build or download the Go extension or require consumer npm metadata. Runtime
tests preserve report and exit-code contracts. The JSON report remains under RUNNER_TEMP, outside
the checkout, so creating it cannot trigger a dirty-working-tree warning.
Dashboard CAO actions and marketplace copy commands use the Go hierarchy;
their executor launches gh cao without invoking repository shell scripts.
From the repository root, make build creates the ignored local extension
binary and make check runs formatting checks, go vet, race-enabled unit
tests, and a build. Go checks are scoped to cmd/, internal/, and the root
dashboard embedding package, excluding
npm dependency sources and the independent server module.
scripts/build-release.sh VERSION [OUTPUT_DIRECTORY] cross-compiles standalone
Linux, macOS, and Windows binaries for amd64 and arm64 with CGO disabled and the
exact stable release tag embedded in main.version, then creates SHA-256
checksums. make release VERSION=vX.Y.Z writes these assets to an empty
dist/gh-cao/ directory.
The root installer downloads the matching platform asset and checksums.txt,
requires one exact SHA-256 entry and the expected embedded version, then
atomically replaces the binary in GitHub CLI's gh-cao extension data directory.
It honors XDG_DATA_HOME and Windows LOCALAPPDATA, refuses linked/source
installations, and never replaces a working binary on download or verification
failure. An explicit stable-format catalog tag selects the same extension
release; other catalog refs use the latest published version-tagged extension,
including prereleases but excluding drafts, independently of the runtime
revision. Before changing tools or CAO files, the installer requires a complete
six-platform asset set and checksums. It accepts the legacy OS-ARCH naming set
as well as gh-cao-OS-ARCH, preferring the latter when both are complete, without
mixing names or retrying another asset after verification failure.
For a newly initialized policy only, it aligns the former catalog's schema URI
from an older extension with the installed catalog's canonical schema URI,
rejecting unknown mismatches without rewriting authority fields or existing policy.
Initialization and setup invoke gh cao. Node.js remains a legacy-installer/pipeline
prerequisite, not a dependency of native setup or other Go extension commands.
Campaign manifests are the catalog's source of truth for installed workflows and
the trusted materializer bootstrap. The materializer copies executable resources
from the package's immutable full resolvedCommit SHA to the same top-level
paths they occupy in the catalog, replacing each bounded campaign-owned
destination so removed files cannot survive an update. Exact focused Activity
or Dashboard records retain ownership of their directories when root
materialization runs; all selected revisions are preflighted before replacement.
The Activity and Dashboard manifests are root-package components rather than
complete standalone installation entry points because gh-aw cannot invoke the
materialization hook. Source-managed and installed control repositories
therefore execute one layout. .github/aw/ remains exclusively gh-aw-owned.
Activity and Dashboard use the standard npm files contract in the dedicated
runtime/package.json, rather than copying their development directories
wholesale. The producer-side npm run runtime:pack -- DESTINATION REVISION
command packs with lifecycle scripts disabled, bundles the YAML parser with
esbuild and its dependency license notices, and seals an exact-revision inventory
and checksums. Neither published nor developer-packed runtimes include retired
Node onboarding or lifecycle administration modules.
Filesystem-relative CLI modules, workers, and build inputs remain at their
canonical paths rather than being forced into a single-file executable.
The conventional cao-runtime.yml pipeline builds on main pushes. Read-only
build/test and source-free attestation use separate jobs, producing exact-SHA
Actions artifacts retained for 90 days. The Release workflow creates a draft
stable tag at an exact main SHA, waits for that SHA's successful runtime push
run, verifies the checksum and signed provenance of both the runtime archive
and the Azure deployment-asset bundle (cao-azure-<sha>.tgz: an allowlisted
Docker build context for the Azure image targets, the compiled ARM template,
and a per-file SHA-256 manifest, with no adopter policy, which builds supply
through the cao-policy and cao-ingest-source named contexts), and attaches
both archives and checksums together with the six extension binaries and their
checksum manifest.
The extension build runs in a separate read-only job at the exact release SHA
with Go caching disabled, runs extension checks, and verifies the embedded tag.
The source-free attachment job checks the complete binary checksum manifest;
publication requires the exact eleven-asset set before publishing the completed
draft as an immutable prerelease. A maintainer reviews the completed notes and
promotes the prerelease to stable. Publication locks
the tag and assets through immutable releases; no workflow mutates release
assets afterward. Stable tag sources use release assets; main/SHA sources use
the successful, unexpired Actions artifacts. The operator materializer verifies GitHub signed provenance bound
to the catalog, signer workflow, source SHA and signer SHA on a GitHub-hosted
runner before extraction, then checks the inventory, checksums and ownership.
When the exact main/SHA runtime build is queued or running, materialization
waits for it for at most five minutes; failed, missing, expired, timed-out, or
unverifiable artifacts fail closed without source/npm packing or latest-release
fallback. Explicit local source materialization remains a developer path using
npm. Normal operator installation needs Node.js and authenticated GitHub CLI
artifact/attestation access, not npm.
The materializer installs only owned canonical destinations from the archive
and does not replace consumer-owned root package metadata. Installed control
repositories keep the
repository-local pipeline CLI, collection and query runtime, canvas authoring,
dashboard production sources, build inputs, and dependency manifests. Tests,
fixtures, screenshots, contributor tooling, and catalog-only component
manifests stay in the catalog. Dashboard workflow builds install production
dependencies only.
The Agent Plugin is a separate distribution: the control-plane installer does
not copy its manifest, Copilot extension, bundled specification documents, or
repository-only dashboard authoring skills. Materialization preserves
pre-existing plugin resources outside its owned runtime destinations. The
installer adds the repository-root aw.yml package. That manifest explicitly
composes only the Activity, dashboard, and validation workflows, seven shared
control-plane resources, seven portable control-repository skills (including
the Agentic Workflows router), one Agentic Workflows agent, and the gh-aw
project settings. The portable router is a thin adapter to the current
canonical upstream Agentic Workflows skill on main, rather than a copied
routing table, and delegates deterministic operations to gh aw, cao, and
repository validation commands. Version-sensitive behavior remains constrained
by the control repository's policy-pinned gh aw CLI. The custom agent
delegates to that installed skill instead of maintaining a second router. The
nonempty agents
declaration prevents agent auto-discovery from installing repository-only
agents. gh-aw v0.91.5 still auto-scans the root skills/ directory after
resolving explicit skill declarations, so that directory contains only the
seven skills intended for control repositories and a contract test locks its
exact inventory.
Operational campaign manifests contain only their owned workflows and catalog
resources; they do not import the root catalog package. gh cao add is the
supported lifecycle boundary after control-plane installation and materializes
the selected campaign's canonical runtime without reinstalling control-plane or
Agent Plugin resources.
gh cao add WORKFLOW_OR_CAMPAIGN is the single workflow/campaign installation
command, without a campaign-add subcommand or repository enrollment. Bare catalog
workflow names, explicit .md sources, GitHub blob URLs and the published
Daily Repo Status qualified shorthands select standalone installation; campaign
coordinates and existing local directories select campaign installation with
unchanged gh-aw options. There is no failure-driven fallback between installation kinds.
Standalone installation delegates installation and compilation to gh-aw, verifies the exact standalone
identity and CAO admission gate, and registers new workflows in review mode without
widening existing policy. Repository enrollment is separate: gh cao repos add OWNER/REPO verifies one exact repository and stages review-safe policy.
npm run test:runtime-install builds the actual producer archive and validates
its installation commit from a fresh
checkout, including the operator CLI, local runtime and policy verification,
the bundled YAML parser without node_modules, and a dashboard build using only
production dependencies. The test requires npm
registry access, but does not create credentials or dispatch workflows.
The primary path uses gh extension install githubnext/gh-cao, then runs
gh cao setup from an existing GitHub control checkout. Documentation presents
the curl installer in a troubleshooting callout for SAML-token installation
failures, not as the default installation path.
The fallback installer uses upstream github/gh-aw's install-gh-aw.sh for gh-aw and
downloads the native gh-cao extension. Public tool release discovery and downloads
are anonymous and ignore curl authentication configuration; only the upstream
installer's child process loses token variables and the Actions INPUT_VERSION
override. Stored credentials and authenticated control-repository and runtime
provenance operations remain intact. Repository creation and cloning remain
explicit gh repo create and gh repo clone operations or the installer's
--create-repo, not native setup effects. Native
internal/cli/native_setup.go owns guided scope and authentication; runtime
preparation lives in internal/cli/setup_runtime.go. Setup distinguishes absent
policy from malformed policy, constructs only a missing exact campaign-free
baseline with the same helper as policy-only gh cao init, and saves it after
configuration succeeds, before optional publication.
After approval and before Pages or credential changes, missing runtime is
prepared by gh-aw in an isolated checkout at the selected stable release, then
materialized from the exact-SHA attested runtime using shared acquisition,
extraction, and verification helpers. All destinations are preflighted; matching
files are retained, missing files added, conflicts rejected, and unrelated
files preserved. Complete installations are reused rather than upgraded.
Missing gh-aw is installed at the release manifest's minimum version; existing
older or broken extensions require explicit repair. Native setup needs no local
Node.js and never changes the process working directory. Failures can leave
prepared runtime files but never claim policy or external settings were rolled
back. Repository creation, commits, pushes, campaign enrollment and execution
are never implicit setup effects.
After configuration, native internal/cli/setup_publish.go may offer interactive
publication with separate default-No confirmation. An isolated Git index
provides the file summary, policy diff and temporary full-diff file without
changing real staging. Eligible files are exact runtime/package destinations
prepared by this setup plus policy, not broad runtime directories. Publication
requires an empty real index, one matching origin push destination, the remote
default branch, and equal local/remote HEADs (or both unborn). It rechecks
reviewed files, Git state and destination before staging only reviewed changes,
and verifies the resulting commit's tree, branch and parent before normal push.
Existing local commits, feature branches or uncommitted earlier runtime require
manual publication. Hooks, identity and branch protections remain effective;
no force, additional tags or submodule pushes are allowed. Failed pushes retain
the local commit and report recovery guidance. Declining/cancelling publication,
headless mode and CI leave configuration local. Successful push returns Actions
and known dashboard links marked deployment pending, never dispatching, polling
or waiting for collection/deployment.
The root install-gh-cao.sh checks required tools, Node.js 24+, GitHub sign-in, and checkout-root
readiness before installing or upgrading anything. Repository creation and
cloning are private-only and require an explicit --create-repo OWNER/NAME;
existing clone directories are never overwritten. Bare installation ends with
the explicit gh cao setup next step. --setup attaches guided setup directly
to the controlling terminal after verified materialization when one is
available. Without a terminal or when CI is set, setup applies only an exact
public-control-repository profile: self-only read and Activity scope, no
campaigns, public Actions-backed Pages, and repository workflow-token
authentication. Private/internal repositories, broader existing policy, or
installed campaigns fail closed. Headless repository creation still requires
an exact --create-repo OWNER/NAME, and missing prerequisites fail rather than
appearing successful. Streamed bootstrap children otherwise retain null stdin.
Native setup owns terminal presentation, cancellation, explicit scope,
public Pages consent and review/apply confirmation. setup --json retains
structured stdout. Native setup/authentication and lifecycle tests exercise the
supported operator paths without a local Node installation; Actions runtime
tests separately enforce retired-command rejection and unchanged files.
Campaign installation and execution are separate operator actions through
gh cao add and gh aw run. Operators review and commit workflows
and bounded review-mode policy together before dispatching work. Campaign
installation never commits, pushes or dispatches; setup's separately approved
publication is monitoring-only.
Enabling an orchestrator
also resumes its schedule; operators may pause it with gh workflow disable
without cancelling requested work. Validation records a manually paused
orchestrator with active workers as a pause note rather than recommending
scheduled re-enablement. Runtime success is not proof of a proposal, applied
change, or operational value.
The policy may declare control-plane.activity.repositories as an exact,
nonempty subset of globally allowed repositories. This separates evidence
collection scope from campaign rollout authority without silently narrowing
either. Authentication planning uses the declared subset when present and
otherwise preserves its existing fail-closed behavior. Repository-local
workflow-token collection remains bounded to the control repository and does
not authorize cross-repository evidence access.
- CAO controls whether and where an operation runs; gh-aw controls how the admitted workflow runs.
.github/workflows/cao.jsonis policy, not a credential store. Credentials stay in GitHub Actions secrets and are resolved inside a run.- Review mode is the default. Live operation requires explicit standalone workflow or campaign/worker policy, scope, and target authority.
- Target repository files cannot grant, narrow, or revoke control-plane authority.
- GitHub tools available to agents are read-only. Repository changes use only safe-output capabilities declared by the workflow.
- Missing policy, authority, credentials, access, or required evidence fails closed.
- Orchestrators may discover and select only within resolved policy. They do not mutate target repositories.
- A worker processes exactly one dispatched target, cannot discover additional targets or dispatch more work, and cannot widen its mode.
- Dispatch envelopes carry repository identity, mode, review destination, and provenance. They never carry credentials.
- Standalone workflows use their own policy identity and bounded precomputed targets, not synthetic campaigns, workers, or dispatcher envelopes.
- Activity records bounded evidence; it does not determine rollout, outcomes, or operational value.
- JSONL snapshots are authoritative inputs. Actions caches, SQLite, IndexedDB, are disposable transport or query projections; hosted Postgres holds current dashboard entities, not rollout authority.
- Missing, stale, partial, and zero evidence are distinct states.
- Computations consume canonical evidence, preserve its quality and provenance, and emit bounded, versioned results; they do not create authority or convert runtime success into verified outcomes or operational value.
- Overview counters use IndexedDB-native counts or request-scoped declarative
queries over canonical records. A separate daily run-count projection and
compact per-Run contribution receipts support explicitly migrated additive
health queries; receipts survive detail eviction and replacement updates
subtract old contributions before adding new ones atomically. Its dimensions
are namespace, UTC run-start date, repository, and workflow. Existing detail
storage and retention are unchanged. Daily buckets and receipts retain the
current UTC Monday-start week and its two preceding weeks independently of
detail-retention overrides; backfill cannot recover already-evicted history.
Other daily metrics and computation-result projections are not persisted.
Changes to this projection, reconciliation, retention, source, or migrated
consumers require
POSTGRES_URL=... npm run test:conformance:daily-run-countsagainst an isolated PostgreSQL database whose test role can create schemas, with native Chromium installed. Skipped backends or browser emulation alone are not conformance;npm run checkdoes not run this additional gate. Failure clustering and audit diagnosis execute in bounded, selected-partition queries. Runtime facts evaluate orchestrators first and enumerate worker targets only when orchestration is eligible. Worker facts use one evaluation partition per target so success on one target cannot mask failure on another. - Dashboard selection, filtering, joins, grouping, aggregation, ordering, and pagination are declared in Dashboard Language. They execute in the data Web Worker for static deployment and as SQL over PostgreSQL for server deployment. Redis may cache bounded server query results but never executes dashboard queries or stores canonical dashboard entities.
- UI effects and components render query results; they do not reconstruct business relationships or query source data.
- The local Redis profile binds to loopback and serves HTTP for local debugging or HTTPS only with operator-supplied certificate files.
- The hosted Redis profile runs behind an explicitly trusted HTTPS proxy, authenticates users through GitHub OAuth plus explicit user, organization, or team authorization, limits rebuild control to explicit administrators, verifies webhook signatures, deduplicates deliveries, and coordinates bounded request-independent rebuilds through Redis so multiple stateless replicas cannot replace the projection concurrently. Its client exposes the active GitHub login and supports explicit account switching through a fresh OAuth account-selection flow without combining account authority. Hosted transport is fail-closed: Redis uses TLS by default when selected and always in Azure; a deployment-managed Redis service may use private plaintext only through an explicit opt-in and a private address. A public listener terminates TLS directly, while a private container listener may rely on proxy TLS only when the direct proxy peer belongs to an explicit private CIDR allow-list. Forwarded hosts must still match the public host allow-list and forwarded protocol must be HTTPS. Logout atomically removes active session authority before remote token revocation; transient GitHub failures retain encrypted credentials only in the selected operational revocation queue (restart-persistent with Redis or PostgreSQL, process-lifetime with opted-in memory), drained by a bounded maintenance worker. Encrypted records identify their key so controlled rotation can retain the previous key until sessions and revocations drain. Refreshed sessions use an atomic compare-and-swap so logout cannot be undone by a concurrent OAuth refresh.
- The Azure deployment baseline provisions private PostgreSQL for both canonical and operational storage, without Redis. One Log Analytics workspace and one workspace-backed Application Insights component are shared by the deployment. A private manual ingestion job publishes explicitly selected adopter snapshots or an explicit empty dataset; builds never download a catalog-owned dataset implicitly. Instance policy, credentials, and target enrollment remain adopter-owned inputs, not public deployment defaults.
- Explicit
CAO_GITHUB_LOCAL_USERdevelopment OAuth replaces membership authorization with one configured GitHub login and a valid numeric account ID. Classic login requestsread:userwithoutread:org; GitHub App clients retainoffline_access. It requires a process-owned loopback TLS listener, one matching allowed host and exact callback authority/path, and loopback request peers. Proxy trust, external/platform hosting, CORS, and simultaneous user/organization/team/SSO policy are rejected. Sessions are bound to the mode and developer and cannot cross into ordinary hosted authorization. Administrator allowlisting, recent OAuth assurance, CSRF, explicit classicrepoconsent, and live target writer checks are unchanged. Operators must not expose this development listener through tunnels or proxies. - In the durable PostgreSQL or Redis server-collection profiles, delivery deduplication, repository debounce, and task append are one atomic admission. Memory provides the same atomic admission within one process lifetime, not restart durability. Queue transitions append replacements or dead letters before ACK in one operational operation; completed entries are ACKed and deleted atomically. The task stream applies backpressure at its configured capacity and never trims recoverable work, so worker crashes and ambiguous client failures may repeat collection but cannot silently lose admitted work. Delivery recovery preserves both its delivery boundary and pagination progress, and advances the boundary only after redelivery requests succeed. Enrollment changes are serialized while withdrawal persists erasure for the exact membership snapshot before removing it; workers serialize erasure with collection and reject or erase stale queued collection tasks. Workers persist not-before retries in a separate due-time set and promote ready tasks without sleeping on delayed work; scheduled tasks count toward backpressure and queue depth. Shutdown preserves leased work, and repository-lock contention backs off without consuming collection attempts.
server/internal/githubquotais the CAO-side authority for GitHub API quota. A bucket is one independently metered quota identified by GitHub App identity, installation, and rate-limit resource, never by a token. Redis keeps GitHub's last authoritative observation separate from expiring reservations. Admission requires remaining minus reserved minus cost to stay at or above the requested floor. Same-window observations never raise remaining quota, and parking never discards the primary quota state. A non-secret provider registry lists the candidate buckets for a workload, and selection prefers the unparked, known bucket with the most headroom. Each accepted observation also merges the bucket's peak usage into a 15-minute Redis slot retained for 24 hours; administrators read it throughGET /api/v1/github-quota/usageand thegithub-quota-usageruntime source that the Ingestion page charts. Existing collection budgets do not use this service yet.- Signed repository lifecycle deliveries are durably queued as independent
discovery hints. Workers reconcile complete authenticated installation
coverage, exclude archived repositories, persist erasure work before removing
absent coordinates from enrollment, and queue collection for verified active
repositories. Archive, deletion, rename, and transfer evict old repository
evidence and retained inventory through the existing erasure/projection path.
Delayed deliveries cannot restore obsolete coordinates or lifecycle states;
legacy lifecycle metadata cannot recreate absent canonical repositories.
Workers also reconcile active installation lists on startup and every hour by
default, configurable with
CAO_COLLECT_REPOSITORY_REFRESH_INTERVAL, coordinating replicas with an operational lease and persisted admission timestamp.cao-dashboard backfill --repositories-onlyforces the same repair without replaying history or scanning workflow runs; unchanged repositories are not recollected by list refresh alone. - The ingestion reliability simulator uses strict, seeded JSON scenarios to generate up to 50,000 synthetic repositories and 1,000,000 workflow and optional issue events combined. Signed webhook traffic uses the production endpoint and queue admission path; a bounded fake GitHub REST API supplies timed latency, outage, rate-limit, and transient-error windows to the normal collection subprocess. The simulator is a local reliability exercise, not a complete GitHub API emulator or a production-capacity guarantee.
- The deployment-neutral CAO server package builds the dashboard and Go server
together, runs as a non-root user, and mounts the authoritative artifact
read-only from an externally populated named volume whose complete payload is
hash-verified and atomically installed. Its workflow publishes
ghcr.io/githubnext/gh-cao/cao-serveron pushes tomainand published releases after protected-main ancestry validation, source tests, Dockerfile and workflow security linting, independent Trivy and Grype high/critical CVE gates, a Dockle hardening check, and Syft SPDX SBOM generation. Lint, test, and image build/scanning run as separate jobs with no package-write authority. Raw static-check outputs are retained in a short-lived artifact even when a lint gate fails. The protected-main.github/workflows/cao-package-publish.ymlreusable publisher revalidates caller authority, exact source metadata, the checksummed image archive, and OCI labels before publishing the exact digest and attaching GitHub SLSA provenance and SBOM attestations. Privacy-preserving non-nested step summaries report only check scope, policy, and outcome. The workflow also admits manual branch builds only when both original and rerun actors have maintain or admin permission, the executing workflow is current protectedmain, and the requested source branch resolves to its current head. Those packages use a separate immutable dispatch identity and cannot redefine main or release identities. The single image exposes the multi-role server binary so downstream Docker Compose deployments selectserve-hosted,collect,backfill, ordoctorper service without rebuilding the package. Canonical identities are immutable commit or release identities, never mutable channel tags. Host-neutral source builds useserver/Dockerfilewith explicit version and revision build arguments; deployment promotion and rollback belong to the application host. The source build produces a lean admission-only dashboard target and a collector target with Node, GitHub CLI, a checksum-verified policy-pinned gh-aw binary, and the Activity projection catalog. The collector target also generates a deterministic control-plane inventory from the exact checked-out source and packages only that inventory plus the shared policy resolver required at runtime; it does not restore a second editable campaign catalog. Before each canonical ingestion replacement, a private collection role resolves the reviewed deployment policy, overlays the exact operational enrollment set, and uses a short-lived installation token for the control repository to enrich and retaincontrol-settings.json,control-plane-inventory.json, andinventory-sources.jsonin the evidence lake. The first activation fails closed without valid campaign inventory; a later transient refresh failure may retain the previous valid inventory. The internet-facing dashboard holds the webhook secret but no collection private key. Unexposed collector and idempotent backfill services hold the read-only GitHub App key and share a persistent evidence volume. The collection profile leavesCAO_SOURCE_DIRECTORYunset, while one verified activity artifact remains an external read-only recovery volume for rollback to the snapshot profile. Locally source-built images are not admitted through the package workflow's vulnerability scans, hardening check, SBOM, or artifact attestations; those guarantees continue to apply only to published packages. - Browsers and external clients never receive Redis or Postgres endpoints or credentials. Dashboard source replacement is transactional in Postgres; a failed replacement leaves the previous committed data available. An empty Postgres store is not ready until loaded from authoritative inputs.
- Edit
.github/workflows/*.md, then compile withgh aw compile; do not edit.lock.ymlfiles by hand. - Keep executable campaign resource destinations aligned with their catalog
source paths; do not add a parallel installed-runtime tree under
.github/aw/. - Update installed campaign records through gh-aw campaign commands rather than
editing
.github/aw/campaigns/*.json. - Keep policy and workflow changes together because admission resolves policy at the exact workflow SHA.
.github/workflows/cao.jsonremains the only rollout policy. Optional.github/workflows/cao.<deployment>.jsonprofiles may extend it only withcontrol-plane.web.host; composition is relative, directory-confined, cycle-bounded, duplicate-key rejecting, and validated after merging. A deployment profile cannot alter scope, campaign enablement, modes, targets, workers, credentials, or any other control-plane authority.
- GitHub Actions and gh-aw provide the execution environment, workflow compiler, agent harness, authentication, and safe-output processing.
- Node.js 24 and ECMAScript modules implement dependency-light control, collection, data, and local tooling.
- JSONL is the bounded evidence interchange; SQLite supports local tools and agents; IndexedDB supports the static browser dashboard; Postgres stores and queries current hosted dashboard sources through the canonical adapter and implements default durable operational services; Redis is an explicit alternative operational adapter for caches, queues, coordination, rate limits, and sessions, with bounded volatile memory available only for an explicitly acknowledged single-process hosted deployment.
- Go serves the hosted dashboard HTML and assets with its same-origin authentication, ingestion, reconciliation, rebuild, query, and revision-event service, plus the independent native GitHub CLI extension scaffold.
- Dashboard Language keeps data operations declarative and off the browser main thread.
- Astro/Starlight builds the documentation site. The operational dashboard has a separately bundled browser UI. Only the static deployment publishes it through GitHub Pages; hosted deployments serve it through the Go handler.
specs/control-architecture.mddefines authority, admission, and execution invariants.specs/activity.mddefines evidence collection and snapshot semantics.specs/dashboard-data.mddefines the canonical data architecture.specs/dashboard.mddefines the dashboard product contract.specs/repository-layout-and-installation.mddefines canonical runtime layout and installation conformance.docs/architecture.mdexplains the control plane for operators.AGENTS.mdrecords repository conventions and focused validation commands.
Update this file when a top-level subsystem, dependency direction, authority
boundary, or source-of-truth location changes. Record narrower design rationale
in adr/, but put current requirements and conformance rules in the relevant
normative specification.