LCARS operations console and agent telemetry pipeline
Overview
Agent LCARS is the control plane for headless Claude Code, Codex, and OpenCode work on the shared self-hosted GitHub Actions runner fleet. It turns GitHub issues into accountable agent work, shows maintainers where attention is needed, and retains the session evidence behind each outcome. To dispatch work, add exactly one routing label to an issue in an onboarded repository: The shared agent protocol is the complete behavioral contract for every dispatched run. The LCARS skill is a situational control-plane reference for developers changing dispatch and reconciliation machinery. The console then tracks the run from intake through review, merge, and any maintainer follow-up. See Operations for Work API access and parked-item cleanup. Use the console for decisions and inspection; use the supporting services when working on a specific part of the fleet. The console keeps the active fleet, its decision queue, and its session history in focused workspaces.
README
Agent LCARS
Agent LCARS is the control plane for headless Claude Code, Codex, and OpenCode work on the shared self-hosted GitHub Actions runner fleet. It turns GitHub issues into accountable agent work, shows maintainers where attention is needed, and retains the session evidence behind each outcome.
Dispatch
To dispatch work, add exactly one routing label to an issue in an onboarded repository:
| Label | Agent |
|---|---|
agent:claude |
Claude Code |
agent:codex |
Codex |
agent:opencode |
OpenCode |
The shared agent protocol is the complete behavioral contract for every dispatched run. The LCARS skill is a situational control-plane reference for developers changing dispatch and reconciliation machinery. The console then tracks the run from intake through review, merge, and any maintainer follow-up.
Operating surfaces
See Operations for Work API access and parked-item cleanup.
Use the console for decisions and inspection; use the supporting services when working on a specific part of the fleet.
| Surface | Use |
|---|---|
Console queue (/) |
Work requiring a maintainer action |
Console agents (/agents) |
Active runs, CLI sessions, and recent outcomes |
Console sessions (/sessions) |
Search and inspect session records |
apps/telemetry-watcher |
Interactive and CI session telemetry |
apps/runner-autoscaler |
Runner placement and lifecycle |
apps/github-actions-exporter |
GitHub Actions metrics |
infra/terraform |
GCP services, IAM, storage, secrets, and budget |
Console views
The console keeps the active fleet, its decision queue, and its session history in focused workspaces. The Decision Inbox is the starting point for work that needs a human response; Agents is the live operational view; and the Session Archive is the durable record for investigation and audit.
Active agents
Session archive
Documentation map
The full task-oriented index is docs/README.md, and
ARCHITECTURE.md maps system ownership and proof
boundaries. Common entry points:
| Need | Source of truth |
|---|---|
| Onboard a repository to the agent fleet | Repository onboarding |
| Agent labels and routing | GitHub label contract |
| Credentials and GitHub App identity | Fleet credentials and bot identities |
| CI dispatch and published actions | Published actions |
| Local/CI E2E boundary | E2E security boundary |
| E2E test policy | E2E reliability |
| Runtime diagnosis | Lifecycle systems |
Development
For setup, FQDN sharing, fixture reset, browser journeys, and troubleshooting, use the local console SUT playbook.
Use the Node and pnpm versions pinned in package.json:
pnpm install
pnpm verify
For iterative console/control-plane work, use the credential-free development
stack instead of rebuilding the standalone production bundle. The commands are
Nx targets (with uncached runtime operations and no production-build prerequisite),
following Sprinkles’ serve-emulator / serve-lan target convention:
pnpm dev
# Equivalent: ./tools/nx run @agent-lcars/console:serve-emulator
This starts the Next.js development server with hot reload, the Firebase Auth
and Firestore emulators, the Firebase emulator UI, local-only authentication,
and populated synthetic fixtures. It listens only on loopback: the console is
at http://127.0.0.1:4300 and the emulator UI is at
http://127.0.0.1:4301. No production credential is loaded or required.
For feedback from another machine, use the host’s fully qualified DNS name:
FQDN=dev.example.net pnpm dev:lan
# Equivalent: FQDN=dev.example.net ./tools/nx run @agent-lcars/console:serve-lan
The console is then at http://dev.example.net:4300. Its FQDN must resolve to
a private IPv4 interface on the serving host; only that interface and loopback
are bound. Next.js receives the same FQDN for hot-reload origins. Emulators
remain private on loopback because LCARS accesses them server-side. Host/origin
checks reject DNS rebinding and cross-origin requests before injecting the
synthetic administrator. This is a trusted-LAN fixture preview, not a public
authenticated service. No secrets or dotenv files are changed.
Use pnpm dev:reset to restore the synthetic data without restarting the
server and pnpm dev:status for a quick health check. These commands and
pnpm dev:test discover the running stack’s FQDN automatically; there is no
need to repeat FQDN. A second worktree can use an independent seven-port range:
pnpm dev -- --port-base 4310
pnpm dev:reset -- --port-base 4310
Run pnpm dev:test against the running stack for the existing native Work
edit/save/reload journey. Select another existing browser journey using
Playwright’s usual arguments, without rebuilding or restarting:
pnpm dev:test -- native-work.spec.ts --grep 'reply persists'
pnpm dev:test -- --port-base 4310 native-work.spec.ts --grep 'opens populated'
FQDN=dev.example.net pnpm dev:test
Browser tests reset the stack’s synthetic data, then restore the populated fixture set afterward. Failure traces and screenshots are saved to the temporary diagnostics directory printed by the command. Auth-cookie and production-cache tests still use the hermetic standalone E2E entrypoint; the development stack injects the fixture administrator for ordinary browser requests, while preserving explicit E2E identity headers from tests.
Stop the foreground stack with Ctrl-C. The supervisor shuts down the Next.js server and its Firebase emulator processes together.
The real Orchestrator runs in-process with the Work API and writes durable task/run/outbox/queue state to the Firestore emulator. External GitHub calls use local fixtures. This stack does not launch QueueExecutor, direct runners, provider processes, the telemetry watcher, or periodic reconcile/schedule ticks; queued work will not execute by itself. It is a control-plane integration SUT, not a complete fleet execution SUT.
Start with the focused document that matches your task. This README intentionally does not duplicate deployment steps, runner topology, credential setup, or migration history; those operational contracts live with their owning systems and should be verified there.
Console startup configuration
The console validates static backend configuration before accepting requests.
Local development uses the same boot checks as production. Supply the runtime
variables declared in apps/console/apphosting.yaml, including the GitHub App
client ID and PEM private key, webhook secret, project and webhook queue/location,
AUTH_URL, QUICK_TASK_EVIDENCE_BUCKET, and AGENT_LCARS_WORK_AUDIENCE. Store
credentials in the supported private environment; never commit them. A blank
value or malformed App key fails startup with the variable name, without printing
the credential. Dispatch drains continue rebuilding token providers so key
rotation is still observed.
Hermetic E2E uses tools/e2e/ci.env plus an unregistered App key generated in
memory for each Playwright server launch. The standalone bundle smoke generates
its own ephemeral key. Neither path imports deployment credentials or bypasses
the production boot validator. An autoscaler using a custom Work audience must
set LCARS_WORK_AUDIENCE to match the console’s explicit audience.
Recommended Tools
Try a different keyword or remove a filter.
Install
npx skillfish add jlapenna/agent-lcars