system-architecture

v2026.09.24

Canonical joelclaw topology, Central/Relay vocabulary, and wiring map. Use when reasoning about architecture, Panda/Flagg Central migration, satellites, run capture, tracing event flow, debugging why something ran/didn't run, identifying which worker executes a function, checking what listens on a port, or following an event end-to-end.

GitHub
安装命令
npx skhub add joelhooks/system-architecture
Markdown
SKILL.md

System Architecture (Canonical Topology)

This skill is the single source of truth for joelclaw system wiring.

Freshness notes:

  • 2026-08-23 recall cutover: memory_observations and the system-log JSONL/slog path are retired. Production joelclaw recall composes lane-separated flowing reflections, flowing observations, and curated Brain pages. Every request has explicit scope and access. Chorus/Rhizomatic is parked with no briefing injection or live claims; service stop still needs steering sudo. Claude auto-memory is a pointer index, not a content store.

  • 2026-07-10 topology: the old Panda-centric mental model is migration debt. Current responsibility lanes:

  • Central: Flagg/Mac Studio. It is authoritative for agent-mail and Run capture ingress; verify each remaining service family during migration.

  • Relay: Panda account-bound leftovers and explicit decommission blockers.

  • Satellite: Blaine/other capture clients, connectors, outboxes, and transcript backup freshness.

Treat older “Panda is the whole system” wording as stale unless re-verified against live receipts.

Use it for:

  • "why did this run / not run"
  • "which worker handles this function"
  • "what is listening on port X"
  • "how does event Y flow"
  • "where does this Run/capture/memory record go"
  • "is this Central, Relay, satellite, or shadow runtime work"
  • full-stack routing/debug across CLI → Inngest → workers → gateway → telemetry

Ground-Truth Scope + Evidence Snapshot

This document is grounded in direct reads of:

  • apps/docs-api/src/index.ts
  • packages/restate/Dockerfile
  • packages/restate/src/index.ts
  • packages/restate/src/workflows/dag-orchestrator.ts
  • packages/agent-execution/src/microvm.ts
  • packages/system-bus/src/serve.ts
  • packages/system-bus/src/inngest/functions/index.host.ts
  • packages/system-bus/src/inngest/functions/index.cluster.ts
  • packages/system-bus/src/inngest/client.ts
  • infra/worker-supervisor/src/main.rs
  • ~/Library/LaunchAgents/com.joel*.plist
  • k8s/* (all files)
  • infra/pds/values.yaml
  • packages/gateway/src/daemon.ts
  • packages/gateway/src/channels/*.ts
  • ~/.joelclaw/gateway/AGENTS.md
  • ~/.joelclaw/gateway/.pi/settings.json
  • ~/.local/caddy/Caddyfile
  • ~/.colima/default/colima.yaml + colima status --json
  • packages/cli/src/cli.ts, packages/cli/src/config.ts, packages/cli/src/inngest.ts
  • packages/system-bus/src/observability/* (key files: emit.ts, otel-event.ts, store.ts)
  • packages/telemetry/src/emitter.ts
  • packages/system-bus/src/lib/pi-output.ts
  • packages/inference-router/src/tracing.ts
  • CONTEXT.md
  • docs/gateway.md
  • docs/inngest-functions.md
  • docs/runbooks/satellite-rig-setup.md
  • docs/runbooks/flagg-gate5-staged-migration.md
  • infra/central/README.md
  • docs/prd-rhizomatic-network-canary.md
  • infra/central/launchd/*.plist.template
  • scripts/joelclaw-capture-session.ts
  • scripts/joelclaw-capture-codex-session.js
  • ADRs in ~/Vault/docs/decisions/ (required + topology-adjacent)
  • canonical OTel events plus durable Brain .svx receipts (the former system-log JSONL is archived and retired)

Related docs verified

  • docs/architecture.md — Restate/Firecracker runtime + workload execution flow
  • docs/deploy.md — Restate worker deploy + auth/identity/PVC procedures
  • docs/cli.md — workload command tree + runtime bridge
  • docs/observability.md — not inspected in this update

Refresh receipt: 2026-06-15

This refresh folds in work from:

  • Central vocabulary + Project Thread docs (6b3a1b05, CONTEXT.md, docs/gateway.md)
  • Flagg Central scaffold and Gate 5 migration runbooks (6e02a6cd, d36b52f2, infra/central/*)
  • worker-hosted Run capture (f06501a8, docs/inngest-functions.md, packages/system-bus/src/serve.ts)
  • Inngest SDK hardening + connect-mode recovery (d7dd7788, 6c5d2a8e)
  • Talon paging/debounce hardening (c03edc5c, 1f086cfb, d26351cf)
  • satellite rig setup for Blaine/Flagg (bc5738f3, 9cc02f6e)
  • historical Rhizomatic/Chorus network canary (6bebf5b1, docs/prd-rhizomatic-network-canary.md), parked by the 2026-07-17 decision

0) Current Operator Map

The old mental model was "Panda is joelclaw." That is no longer precise enough.

Use these terms:

TermMeaningCurrent truth
NetworkUsers + Machines coordinated by one CentralLogical boundary, not the tailnet/k8s cluster
Centralsingle authoritative joelclaw service for the NetworkFlagg is authoritative for agent-mail and Run capture; verify remaining service families individually during migration
Central host targetMachine consolidating Central responsibilitiesFlagg / Mac Studio, machine_id=mac-studio-central
Relay Machinemachine that hosts account-bound/local-hardware-bound relays while delegating state to CentralPanda becomes this after cutover; satellites stay thin
Satellite Machinethin local Pi/Codex/Claude runner with capture/search/repair hooksBlaine and Flagg bootstrap through scripts/setup-satellite-rig.sh
Runone captured agent invocationraw JSONL + metadata first, SQLite FTS is the live search index
Conversationsibling Run label for an interactive contextnot the source of truth
Project Threadprivate #brain-joel operator workroom for a bounded objectivecoordination only; does not authorize public replies

Current authority split (verified 2026-07-10):

  • Flagg is authoritative for agent-mail and Run capture ingress. The agent-mail daemon binds Flagg loopback; Blaine and Panda use SSH connector LaunchAgents so every joelclaw mail client reaches the same mailbox without exposing the service on the tailnet.
  • Panda is migration debt plus Relay responsibilities. Its independent agent-mail daemon and Talon are removed. A reboot-survivable SSH connector now binds Panda IPv4 loopback 127.0.0.1:3111 and forwards legacy /api/runs and /webhooks ingress to Flagg. The legacy system worker still owns the IPv6 listener until its system LaunchDaemon is booted out with sudo.
  • Satellites stay thin. They run Pi/Codex/Claude, local capture hooks, and connectors to Central. Do not install independent stateful Central services on a satellite without a specific reason.
  • SQLite indexes Runs. NAS/local Run blobs are the source of truth; sessions.db is the compact live FTS index. The retired Typesense runs_dev and run_chunks_dev collections must not be recreated.
  • Flagg splits book search from the operational Typesense node. The system LaunchDaemon on 127.0.0.1:8108 holds operational projections. The user LaunchAgent com.joelclaw.typesense-books on 127.0.0.1:8110 holds docs and docs_chunks_v2. DOCS_TYPESENSE_URL routes book readers and writers. A tailnet-only TCP forward exposes 8110 to Blaine.
  • The book node is not a replica. A Typesense replica would copy every collection and repeat the same memory and startup cost. The separate process gives book indexing its own failure and restart boundary.

Cutover rule: avoid split-brain. Panda and Flagg must not both accept authoritative writes for the same Central service family. Gate 5 permits shadow smoke tests and migration rehearsal, but authority flips only inside an approved freeze/cutover window.


1) Physical Topology

Legacy Central snapshot: Panda

Mac Mini "Panda" (host macOS)
├─ launchd services (gateway, worker supervisor, caddy, talon, agent-mail, etc.)
├─ Colima VM (driver: VZ, arch: aarch64, runtime: docker, VM IP: 192.168.64.2)
│  └─ Talos node: joelclaw-controlplane-1 (k8s v1.35.0, internal IP 10.5.0.2)
│     ├─ namespace: joelclaw
│     │  ├─ inngest (StatefulSet + NodePort 8288/8289)
│     │  ├─ redis (StatefulSet + NodePort 6379)
│     │  ├─ typesense (StatefulSet + ClusterIP 8108)
│     │  ├─ restate (StatefulSet + NodePort 8080/9070/9071)
│     │  ├─ system-bus-worker (Deployment + ClusterIP 3111)
│     │  ├─ restate-worker (Deployment + ClusterIP 9080; full agent image + Firecracker)
│     │  ├─ dkron (StatefulSet + ClusterIP 8080)
│     │  ├─ docs-api (Deployment + NodePort 3838)
│     │  ├─ livekit-server (Deployment + NodePort 7880/7881)
│     │  ├─ bluesky-pds (Deployment + NodePort 3000)
│     │  └─ minio (StatefulSet + NodePort 30900/30901)
│     └─ namespace: aistor
│        ├─ aistor operator (Deployments: adminjob-operator, object-store-operator)
│        └─ aistor-s3 object store (StatefulSet + NodePort 31000/31001)
├─ Caddy reverse proxy (tailnet HTTPS fan-in)
├─ Gateway daemon (embedded pi session)
├─ Firecracker substrate (requires Colima nestedVirtualization=true for /dev/kvm; OFF by default — unstable under load)
└─ NAS "three-body" (NFS tiers per ADR-0088)

Flagg shadow / next Central target

Mac Studio "Flagg" (host macOS; target Central host)
├─ system tailscaled path required for cutover
├─ Central Service Account: joelclaw:staff
├─ service root: /Users/Shared/joelclaw/
│  ├─ services/{redis,typesense,inngest,minio}/
│  ├─ backups/central/
│  ├─ logs/central/
│  └─ src/joelclaw/ (service-owned checkout)
├─ shadow Compose stack (not authoritative)
│  ├─ Redis 7-alpine
│  ├─ Typesense 30.1
│  ├─ Inngest self-hosted
│  ├─ Restate 1.6.2 (Docker named volume for data)
│  └─ MinIO smoke surface
├─ system LaunchDaemon templates
│  ├─ com.joelclaw.central.colima
│  ├─ com.joelclaw.central.compose
│  ├─ com.joelclaw.central.health
│  └─ com.joelclaw.central.nas-mounts
├─ Chorus/Rhizomatic (parked historical canary)
│  ├─ no session briefing injection and no live claims
│  ├─ com.joelclaw.chorus-rhizomatic may remain loaded only until steering completes the sudo stop
│  └─ old 4821/7331 endpoints are historical troubleshooting context, not active dependencies
└─ NAS "three-body" proof path
   ├─ /Volumes/nas-nvme -> three-body:/volume2/data
   └─ /Volumes/three-body -> three-body:/volume1/joelclaw

Flagg Gate 4 is complete: shadow Central recovered after hard reboot with no GUI login. Gate 5 is not complete until Flagg owns Central state, workers, endpoints, and verification while Panda is frozen as rollback-only.

Known runtime endpoints

  • Colima VM IP: 192.168.64.2 (colima status --json)
  • Kubernetes API (stable operator tunnel): https://127.0.0.1:16443
  • Talos API (stable operator tunnel): 127.0.0.1:15000
  • Tailnet hostnames seen in config:
    • panda.tail7af24.ts.net (Caddy routes)
    • pds.panda.tail7af24.ts.net (PDS values)
    • flagg.tail7af24.ts.net (Mac Studio shadow / target Central host)
    • blaine.tail7af24.ts.net (satellite)
  • Current live Run capture URL for satellites:
    • https://panda.tail7af24.ts.net/api/runs
    • served by Panda host system-bus worker on localhost:3111
    • do not use http://panda:3000 or http://panda.tail7af24.ts.net:3000; Panda has no durable Central web listener there.

Tailscale mesh state

  • tailscale status --json failed in this environment: UNKNOWN — needs manual verification

2) Process Inventory (Long-Running)

Herdr launch-domain split

  • com.joelclaw.herdr-server is the default interactive server. It runs as a per-user LaunchAgent in gui/<uid> so pane descendants inherit the Aqua bootstrap namespace and can reach user Keychain services.
  • com.joelclaw.herdr-system-server is the boot-safe automation server. It remains a system LaunchDaemon and owns only the named system Herdr session.
  • Never install the default server as a system LaunchDaemon. A UserName on a LaunchDaemon changes the Unix identity, not the launchd bootstrap namespace. Native macOS clients in those panes cannot resolve the user's com.apple.securityd.xpc service.
  • The installer and cutover contract lives in infra/install-herdr-default-launchagent.sh. The durable rationale is .brain/resources/herdr-launch-domain-contract.svx.

Host launchd inventory (Panda live Central snapshot)

Snapshot source: launchctl print gui/$(id -u)/<label> and plist inspection.

Launchd labelStatePID (snapshot)RolePorts / endpoints
com.joel.system-bus-workerrunning75292Host worker supervisor (worker-supervisor)supervises child bun on 3111
com.joel.restate-workerretired / rollback-only—Historical host Restate wrapper (scripts/restate/start.sh)superseded by deployment/restate-worker on 9080
com.joel.gatewayrunning81275Gateway daemon (packages/gateway/src/daemon.ts)WS :3018, Redis bridge
com.joel.caddyrunning9347Reverse proxy3443, 5443, 6443, 7443, 8290, 8443, 9443
com.joel.talonrunning96359Infra watchdoghealth 127.0.0.1:9999
com.joel.agent-secretsrunning98048Secret lease daemonno public port
com.joel.imsg-rpcrunning61110iMessage JSON-RPC socket daemonUnix socket /tmp/imsg.sock
com.joel.kube-operator-accessrunningvariesstable kubectl/talos operator tunnellocal 16443 (kube), 15000 (talos)
com.joel.voice-agentrunning71887voice agent runtimelocal 8081
com.joel.local-sandbox-janitorscheduled(launchd timer)ADR-0221 local sandbox janitor (scripts/local-sandbox-janitor.sh → joelclaw workload sandboxes janitor)logs in /tmp/joelclaw/local-sandbox-janitor.{log,err}
com.joelclaw.agent-mailspawn scheduled(none in launchctl snapshot)agent-mail MCP HTTP serviceobserved listener 127.0.0.1:8765 (python process)
com.joel.colimanot running—startup helper for Coliman/a
com.joel.k8s-reboot-healnot running—periodic k8s heal scriptn/a
com.joel.system-bus-syncnot running—sync guard watchern/a
com.joel.gateway-tripwirenot running—gateway tripwire scriptn/a
com.joel.content-sync-watchernot running—fs watch -> content/updated eventn/a
com.joel.vault-log-syncnot running—Vault log sync watchern/a

Flagg Central launchd scaffold

Source: infra/central/README.md, infra/central/launchd/*.plist.template, and docs/prd-rhizomatic-network-canary.md.

These labels are part of the Flagg Central shadow/cutover scaffold. They are not proof that Flagg is authoritative.

Launchd labelDomainRolePorts / endpoints
com.joelclaw.central.colimasystem LaunchDaemonstarts the dedicated joelclaw-central Colima/Docker substrate as service infrastructureDocker socket under /Users/joelclaw/.colima/joelclaw-central/docker.sock
com.joelclaw.central.composesystem LaunchDaemonstarts the shadow Central Compose stackRedis, Typesense, Inngest, Restate, MinIO bound to 127.0.0.1 by default
com.joelclaw.central.healthsystem LaunchDaemonbounded health + recovery state machinehealth.sh can invoke recover.sh --all after repeated degraded passes
com.joelclaw.central.nas-mountssystem LaunchDaemonmounts/verifies Flagg NAS tiers/Volumes/nas-nvme, /Volumes/three-body
com.joelclaw.chorus-rhizomaticsystem LaunchDaemonParked historical canary; no briefing injection or live claims; stop pending steering sudoOld endpoint 127.0.0.1:4821/mcp; old satellite tunnel 127.0.0.1:7331

Flagg reboot acceptance rule: Central is not eligible for cutover until infra/central/scripts/reboot-proof.sh passes from another machine after hard reboot with no GUI login.

Process supervision behavior: worker-supervisor

Source: infra/worker-supervisor/src/main.rs

  • Default config:
    • worker dir: ~/Code/joelhooks/joelclaw/packages/system-bus
    • command: bun run src/serve.ts
    • port: 3111
    • health endpoint: /api/inngest
    • sync endpoint: /api/inngest (PUT)
    • health interval: 30s
    • restart after 3 consecutive health failures
    • restart backoff: 1s → 30s max
  • Pre-start kills stale process on port 3111.
  • Runs host import preflight before spawn:
    • bun --eval "await import('./src/inngest/functions/index.host.ts');"
    • on failure, skips spawn and retries with exponential backoff
  • Loads env from ~/.config/system-bus.env plus leased secrets.
  • Forces WORKER_ROLE=host for the supervised host worker.
  • Emits OTEL events via CLI on supervisor failures/restarts:
    • worker.supervisor.preflight.failed
    • worker.supervisor.worker_exit
    • worker.supervisor.health_check.restart

Worker supervision split note

  • Talon is running (com.joel.talon), but host worker is still launched via com.joel.system-bus-worker -> worker-supervisor.
  • ADR + system-log indicate Talon can defer worker supervision during coexistence.

Kubernetes process inventory

Node

  • joelclaw-controlplane-1 (Talos v1.12.4, k8s v1.35.0, internal IP 10.5.0.2)

Core services

ServiceWorkload kindService typeService port(s)NodePort(s) / exposureRole
InngestStatefulSet inngestNodePort (inngest-svc)8288, 82898288, 8289Event API + connect ws
RedisStatefulSet redisNodePort63796379Queue/state/pubsub
TypesenseStatefulSet typesenseNodePort81088108 via Colima/Lima host publishSearch + telemetry store
RestateStatefulSet restateNodePort8080, 9070, 90718080, 9070, 9071Durable workflow ingress + admin + metrics
system-bus-workerDeploymentClusterIP3111in-cluster onlyCluster-role worker (12 functions)
restate-workerDeploymentClusterIP9080in-cluster onlydagOrchestrator + dagWorker + queue drainer in full agent image
docs-apiDeploymentNodePort38383838PDF/docs API + agentic search + taxonomy graph
dkronStatefulSetClusterIP (dkron-svc) + headless peer svc (dkron-peer)8080, 8946, 6868in-cluster only; operator access via short-lived CLI-managed tunnelDistributed cron scheduler for Restate pipelines
livekit-serverDeployment (Helm)NodePort80, 78817880 (for svc port 80), 7881LiveKit signaling + rtc tcp
bluesky-pdsDeployment (Helm-managed)NodePort30003000AT Proto PDS
minioStatefulSetClusterIP + NodePort9000, 900130900, 30901Legacy local S3-compatible runtime
aistor-s3-api (aistor ns)NodePort service (operator-managed)NodePort443, 900031000 (+ dynamic management NodePort)AIStor S3 API (TLS + management)
aistor-s3-console (aistor ns)NodePort service (operator-managed)NodePort944331001AIStor web console

Restate / Firecracker runtime note

  • deployment/restate-worker is the current durable execution worker. The image bundles Bun + Node + pi + codex, the full repo checkout, and 76 symlinked skills.
  • Runtime auth/identity come from secret/pi-auth and configmap/agent-identity, which recreate /root/.pi/agent/auth.json plus the joelclaw identity chain inside the pod.
  • Firecracker is enabled in-pod via privileged access to /dev/kvm on Colima VZ. The /dev/kvm hostPath mount uses type "" (optional) so the pod starts without it when nestedVirtualization is off.
  • Persistent microVM assets live on PVC firecracker-images, mounted at /tmp/firecracker-test for kernel, rootfs, and snapshot files.
  • Retry caps (2026-03-17): dagWorker maxAttempts=5, dagOrchestrator maxAttempts=3. Prevents Restate journal poisoning from infinite retries after code changes or infrastructure failures.
  • Colima stability: nestedVirtualization is OFF by default (crashes VM under Docker build load). Toggle ON only for Firecracker testing sessions, then toggle OFF. See k8s skill for recovery procedures.

Control-plane access

  • kube API exposed locally at 127.0.0.1:16443 via com.joel.kube-operator-access (ssh -S none -o ControlPath=none -L 16443:10.5.0.2:6443)
  • Talos API exposed locally at 127.0.0.1:15000 via the same daemon (ssh -S none -o ControlPath=none -L 15000:10.5.0.2:50000)
  • NodePort/runtime app ports still come from Colima/Lima forwarding; the operator daemon exists specifically because the direct host-published 6443 path was not boring after the rebuild

3) Worker Architecture (Role Split + Registration)

Source files:

  • packages/system-bus/src/serve.ts
  • packages/system-bus/src/inngest/functions/index.host.ts
  • packages/system-bus/src/inngest/functions/index.cluster.ts
  • packages/system-bus/src/inngest/client.ts

Role model

  • WORKER_ROLE parsed as host (default) or cluster.
  • Registered function set is role-dependent:
    • host uses hostFunctionDefinitions
    • cluster uses clusterFunctionDefinitions

Ground-truth counts

  • Measured from the imported definition arrays on 2026-07-29:
    • Host function set: 163
    • Cluster function set: 14
  • gateway/external-delivery-canary is host-only. It appends synthetic message.requested events and watches the canonical event log. It does not run in the gateway driver, transport daemon, or gateway session.
  • Cluster subset functions:
    • agent/approval-request, agent/approval-resolve
    • todoist-comment-notify, todoist-task-completed-notify, todoist-task-created-notify
    • github-workflow-run-completed-notify, github-package-published-notify
    • webhook-subscription-dispatch-generic
    • webhook-subscription-dispatch-github-workflow-run-completed
    • memory/observe-session
    • queue/observer, queue/observer-requested
    • swarm-orchestrator, swarm-agent-exec

App registration isolation

From inngest/client.ts:

  • app id resolves to:
    • system-bus-host when role is host
    • system-bus-cluster when role is cluster
  • explicit INNGEST_APP_ID overrides role-derived id.

This prevents host and cluster workers from overwriting each other’s function graphs.

serveHost behavior

From serve.ts:

  • host role default serveHost: http://host.docker.internal:3111
  • cluster role default serveHost: unset (connect-mode default)
  • INNGEST_SERVE_HOST overrides either role.
  • INNGEST_CONNECT_MODE=1|true|yes starts inngest/connect with instanceId=system-bus-<role>-<hostname> and maxWorkerConcurrency=8.
  • /api/inngest now explicitly allows only GET, POST, and PUT; PATCH, OPTIONS, and DELETE return 405 with Allow: GET, POST, PUT.
  • /api/inngest logs bounded request summaries for failed or ambiguous POST/PUT callbacks, including safe query/debug keys and body shape, not raw huge payloads.
  • Bun server idleTimeout=255 because registration PUTs can exceed the default 10s while the self-hosted runtime is under cron/backlog pressure.

Kubernetes cluster worker manifest sets:

  • INNGEST_BASE_URL=http://inngest-svc:8288
  • INNGEST_SERVE_HOST=http://system-bus-worker:3111
  • TYPESENSE_URL=http://typesense:8108
  • image: ghcr.io/joelhooks/system-bus-worker:d7dd7788 (recorded after Inngest SDK advisory hardening)

Panda host worker config should advertise an SDK callback URL the Inngest pod can actually reach. Current docs call out INNGEST_SERVE_HOST=http://100.93.201.72:3111 on Panda. Do not assume host.lima.internal or host.docker.internal works from inside Talos unless a live pod-to-host probe proves it.

Registration mechanics

  • Worker exposes GET|POST|PUT /api/inngest.
  • Worker sends a delayed self-sync PUT /api/inngest ~5s after startup.
  • worker-supervisor also performs startup PUT sync.

Host is primary today

From index comments + function lists:

  • ADR-0089 transition: host remains authoritative for broad function ownership.
  • Cluster is intentionally limited to cluster-safe subset (12 functions).

4) Event Flow (CLI → Inngest → Worker → Completion)

Canonical flow: joelclaw send

  1. CLI joelclaw send <event> calls Inngest.send().
  2. Inngest.send() POSTs event JSON to:
    • ${INNGEST_URL}/e/${INNGEST_EVENT_KEY}
    • default: http://localhost:8288/e/<key>
    • 2026-06-18: Pi memory-enforcer observe events must follow this keyed Event API shape too; never POST to bare /e/. The extension resolves INNGEST_EVENT_KEY from env/local env files and skips observe emission when no key is available.
  3. Inngest server persists the event and resolves matching function triggers.
  4. Inngest dispatches function steps to the worker app graph that owns that function ID:
    • host app (system-bus-host) for 101-host set
    • cluster app (system-bus-cluster) for 12-cluster subset
  5. Worker handles callbacks via /api/inngest (Hono + inngest/hono handler).
  6. Each step.run result is memoized by Inngest; next step executes when prior completes.
  7. Completion/failure is queryable via GraphQL (/v0/gql) and CLI commands (runs, run, event, events).

Run capture flow: Machine hook → Central /api/runs → memory/run.captured

  1. Runtime-native hook captures only the new Run slice:
    • Pi extension for Pi
    • Claude Code Stop hook via scripts/joelclaw-capture-session.ts
    • Codex hook/helper via scripts/joelclaw-capture-codex-session.js
    • server-side runtimes can call capture inline instead of shelling through a hook.
  2. The hook posts JSON to Central:
    • current live URL for satellites: POST https://panda.tail7af24.ts.net/api/runs
    • Panda serves this through the host system-bus worker on localhost:3111
    • auth: Authorization: Bearer <~/.joelclaw/auth.json token>
  3. packages/system-bus/src/serve.ts validates the bearer token against the persistent local SQLite registry ~/.joelclaw/capture-auth.db. The worker refreshes this four-row registry from Typesense machines_dev in the background every five minutes. Known-token requests never wait for Typesense; an unknown token gets one bounded migration lookup.
  4. Worker writes the raw source of truth through @joelclaw/memory#writeRunBlob:
    • default dev store: ~/.joelclaw/runs-dev/<user>/<yyyy-mm>/<run-id>.jsonl
    • companion metadata includes user_id, machine_id, agent_runtime, parent/conversation IDs, tags, byte count, and SHA-256.
  5. Worker emits memory/run.captured to Inngest.
  6. packages/system-bus/src/inngest/functions/memory/run-captured.ts appends Run metadata, chunks, and FTS rows to SQLite sessions.db in one transaction.
  7. If POST fails from a Machine, the hook writes the POST body into ~/.joelclaw/outbox/; the Machine does not become Central just because capture is temporarily offline.
  8. If raw blobs exist but SQLite is stale, recover Inngest/worker registration first, then backfill with scripts/backfill-session-index.ts. Do not replay thousands of memory/run.captured events casually.
  9. The public Vercel app is not a Run ingress or search surface. Its POST /api/runs and POST /api/runs/search routes return 410. Machine hooks must use the Central system-bus endpoint, and operators must use joelclaw sessions search.

Recall flow: scoped request → CLI composition root → lane-preserving result

  1. Interactive callers run in a trusted GitHub checkout or pass both --project and --workstream. Automatic callers send one exact ComposedRecallRequestV1 through joelclaw recall --request-file - on private stdin.
  2. Every request names principal, purpose, allowed privacy tiers, supersession policy, and independent limits for reflections, observations, and curated pages. The deprecated --limit flag is ignored.
  3. The CLI reads the pinned flowing-memory artifact and curated critical.db projection, then returns three separate lanes: flowing-reflections, flowing-observations, and curated-pages. Never merge their scores.
  4. Unavailable lanes return typed envelopes and exit 3. The gateway shows a generic unavailable marker. Optional Inngest enrichment records redacted telemetry and returns no context. Restate returns a generic degraded marker.
  5. Use joelclaw sessions search "<query>" --source both --extract for exact Run/session wording, commands, and transcript evidence. Composed recall is a broad memory surface, not raw transcript search.
  6. typesense-recall is config-selected rollback only. Status reports it as a visible degraded warning without turning global health red.

Accepted cluster decision (2026-08-23): automatic recall inside the system-bus and Restate cluster images is intentionally disabled/degraded after retiring old observation recall. packages/recall is present for module resolution, but the images do not receive a local semantic store or compiled joelclaw recall binary. Callers must take their explicit optional-enrichment degrade path. This is not a hidden deployment dependency. Re-enable cluster recall only after a separately reviewed secure remote flowing-read substrate exists.

Queue flow: joelclaw queue emit → Restate drainer → durable dispatch

  1. CLI joelclaw queue emit <event> persists a QueueEventEnvelope into Redis stream joelclaw:queue:events and indexes it in sorted set joelclaw:queue:priority.
  2. The restate-worker k8s deployment (packages/restate/src/index.ts) starts a deterministic queue drainer beside the channel callback listener.
  3. On startup, the drainer claims pending + never-delivered entries via @joelclaw/queue#getUnacked(), reindexes replayable entries, and emits OTEL replay evidence.
  4. Each drain tick selects the next priority candidate from the sorted set, resolves its static registry target from packages/queue/src/registry.ts, and POSTs a one-node DAG request to Restate /dagOrchestrator/{workflowId}/run/send.
  5. When backlog remains and a dispatch slot frees, the drainer self-pulses immediately instead of waiting for the next QUEUE_DRAIN_INTERVAL_MS heartbeat. That interval is now the idle poll / retry cadence, not a mandatory 2-second tax between successful sends.
  6. The current Story-3 bridge re-emits the queue item to its registered Inngest event target inside that one-node DAG request. This is deliberate: the deterministic queue/drainer is proven first; per-family Restate cutovers remain Story 4 work.
  7. On accepted Restate dispatch, the drainer acks the queue message; on failure it leaves the message in Redis, applies retry cooldown, and emits queue.dispatch.failed OTEL evidence.
  8. If backlog remains in Redis but the drainer stops making progress past QUEUE_DRAIN_STALL_AFTER_MS, it emits queue.drainer.stalled and exits non-zero so k8s restarts deployment/restate-worker. That is the self-heal path for a wedged drainer inside an otherwise-running Bun process.
  9. Crash recovery comes from the Redis stream + consumer-group replay path, not from vibes: restart the restate-worker pod, let getUnacked() reclaim the inflight entries, then drain resumes.

Workload flow: joelclaw workload run → Redis → Restate DAG → execution

  1. joelclaw workload plan ... --stages-from <file> can load an explicit stage DAG, validate unknown deps/self-deps/duplicates/cycles, and preserve per-stage acceptance gates.
  2. joelclaw workload run <plan-artifact> normalizes the selected stage into the canonical workload/requested runtime request.
  3. Queue admission writes the request into Redis, where the deterministic drainer forwards it into Restate as a dagOrchestrator/{workflowId}/run/send request.
  4. dagOrchestrator executes dependency waves: ready nodes in parallel, chained nodes only after every dependsOn node has terminal output.
  5. dagWorker executes the node handler:
    • shell → subprocess work inside the restate-worker pod
    • infer → pi -p --no-session --no-extensions inside the pod, using the mounted auth + identity + skill set
    • microvm → Firecracker boot/restore through /dev/kvm with kernel/rootfs/snapshot files on PVC firecracker-images
  6. Each node emits OTEL (dag.node.*), and the workflow emits dag.workflow.* so queue → Restate → execution remains observable.
  7. Current truthful limit: the microVM runtime boots and restores snapshots in-cluster, but the broader exec-in-VM workspace drive protocol is still incomplete for general coding slices.

Webhook flow

  1. External service posts to /webhooks/:provider.
  2. Caddy routes /webhooks/* on localhost:8443 to worker localhost:3111.
  3. webhookApp verifies signature, normalizes payload, emits Inngest events (provider/event).
  4. Inngest executes subscribed functions.

"Why did this run / not run" trace recipe

  1. Start with an existing event or run id. Send a probe only when its destination and effects are explicitly authorized.
  2. joelclaw events --prefix <event-prefix> --hours 1
  3. joelclaw event <event-id> (fan-out to function runs)
  4. joelclaw run <run-id> (step trace + errors)
  5. joelclaw runs --count 20 --hours 1
  6. joelclaw otel search "<component/action>" --hours 1
  7. Validate function ownership in index.host.ts / index.cluster.ts.

5) Port Map (Canonical)

Exposure sources: k8s service manifests, Caddyfile, kubectl get svc, lsof listeners.

PortListener / ownerWhat it isExposure path
3111host bun workerhost system-bus worker HTTP (/, /api/inngest, /api/runs, /webhooks, /observability/emit)local host; proxied via Caddy 3443 + webhook path via 8443; Run capture currently exposed at https://panda.tail7af24.ts.net/api/runs
8080ssh forward (Colima) -> restateRestate ingress / workflow APINodePort + host forward
8288ssh forward (Colima) -> Inngest svcInngest API + dashboard backendNodePort + host forward; proxied via Caddy 9443
8289ssh forward (Colima) -> Inngest wsInngest connect websocketNodePort + host forward; proxied via Caddy 8290
6379ssh forward (Colima) -> RedisRedisNodePort + host forward
8108Flagg system LaunchDaemon; historical Panda NodePortOperational Typesense APInon-book projections; tailnet-only TCP forward from Flagg
8110Flagg user LaunchAgent com.joelclaw.typesense-booksBook Typesense APIdocs + docs_chunks_v2; tailnet-only TCP forward from Flagg
9070ssh forward (Colima) -> restateRestate admin APINodePort + host forward
9071ssh forward (Colima) -> restateRestate metricsNodePort + host forward
9080k8s restate-worker serviceRestate worker HTTP (dagOrchestrator, dagWorker, queue drainer)ClusterIP only
random high local porttransient kubectl port-forward (CLI-managed) -> svc/dkron-svc:8080Dkron HTTP APIClusterIP only; short-lived operator tunnel
3838ssh forward (Colima) -> docs-apidocs-api HTTPNodePort + host forward; proxied via Caddy 5443
7880ssh forward (Colima) -> livekit-serverLiveKit signalingNodePort 7880; proxied via Caddy 7443
7881ssh forward (Colima) -> livekit-serverLiveKit RTC TCPNodePort 7881
3000k8s bluesky-pds NodePortBluesky PDS HTTPNodePort 3000
30900k8s minio-nodeportLegacy MinIO S3 API (HTTP)NodePort 30900
30901k8s minio-nodeportLegacy MinIO console (HTTP)NodePort 30901
31000k8s aistor-s3-api (aistor ns)AIStor S3 API (TLS)NodePort 31000
31001k8s aistor-s3-console (aistor ns)AIStor console (TLS)NodePort 31001
3443CaddyHTTPS reverse proxy to localhost:3111tailnet HTTPS
5443CaddyHTTPS reverse proxy to localhost:3838tailnet HTTPS
7443CaddyHTTPS reverse proxy to localhost:7880tailnet HTTPS
9443CaddyHTTPS reverse proxy to localhost:8288tailnet HTTPS
8290CaddyHTTPS reverse proxy to localhost:8289tailnet HTTPS
8443Caddy (HTTP)webhook/public ingress routerexpected Funnel target
6443Caddyreverse proxy to local 6333 (Qdrant)tailnet HTTPS
3018gateway daemongateway websocket stream portlocal
9999talonTalon health endpointlocal 127.0.0.1
8765agent-mail HTTP serviceMCP agent-mail APIlocal 127.0.0.1
4821Flagg com.joelclaw.chorus-rhizomaticparked historical Chorus service; not a live memory dependencyStop pending steering sudo
7331historical satellite tunnel to Flagg Chorusparked; not a live client routeOld path: local 127.0.0.1:7331/mcp -> Flagg 127.0.0.1:4821/mcp
15000com.joel.kube-operator-accessTalos APIstable local talosctl endpoint
16443com.joel.kube-operator-accessKubernetes APIstable local kubectl endpoint

Notes

  • Host NodePort exposure appears through an ssh listener process (Colima portForwarder=ssh).
  • Exact per-port ssh forward command line is UNKNOWN — needs manual verification (process introspection restricted in this environment).
  • Numeric ports such as 6379, 8108, 8288, 8289, 8080, 9070, 9071, 9000, and 9001 can refer to Panda live k8s/NodePort surfaces or Flagg shadow Compose loopback surfaces depending on the host. Check hostname, CENTRAL_BIND_ADDR, JOELCLAW_CENTRAL_URL, and the current shell env before diagnosing.

6) Storage Topology

Run blobs / memory capture

  • Current dev source of truth: ~/.joelclaw/runs-dev/<user>/<yyyy-mm>/<run-id>.jsonl plus .metadata.json.
  • Capture identity is resolved locally by bearer-token hash from ~/.joelclaw/capture-auth.db.
  • machines_dev is the enrollment/migration mirror. A five-minute background sync propagates rotation and revocation without putting Typesense on the capture request path.
  • Search projection: SQLite sessions.db for Run metadata, compact chunks, and FTS5.
  • Failed Machine POSTs spool to ~/.joelclaw/outbox/.
  • Future/target contract from CONTEXT.md: Run blobs live on NAS and SQLite remains rebuildable from those blobs.

Redis

  • Runtime: k8s StatefulSet (redis:7-alpine, appendonly enabled).
  • Primary uses:
    • gateway queue/session keys (joelclaw:events:*, joelclaw:notify:*, joelclaw:gateway:sessions)
    • webhook subscriptions (joelclaw:webhook:*)
    • gateway health mute/streak keys (gateway:health:*)

Typesense

From current runtime code:

  • The old observations and brain_graph_nodes recall collections are not production recall sources. typesense-recall remains registered only as the dated, visible degraded rollback adapter.
  • machines_dev as the enrollment/migration mirror for the local capture-auth registry
  • Flagg operational node: /Users/Shared/joelclaw/data/typesense on 127.0.0.1:8108, owned by the system LaunchDaemon.
  • Flagg book node: ~/.joelclaw/typesense-books/data on 127.0.0.1:8110, owned by the user LaunchAgent.
  • DOCS_TYPESENSE_URL selects the book node for docs-api, docs ingest, joelclaw docs, and the book subset of unified search. TYPESENSE_URL remains the operational node.
  • The book node holds only docs and docs_chunks_v2. Do not recreate these collections on the operational node after cutover.
  • The exported JSONL and collection schemas under ~/.joelclaw/backups/typesense-books/ are the migration rollback source. Never copy a live Typesense data directory as a backup.

Firecracker runtime storage

  • PVC: firecracker-images
  • Mounted in deployment/restate-worker at /tmp/firecracker-test
  • Stores:
    • kernel (vmlinux)
    • rootfs (agent-rootfs.ext4)
    • snapshots (snapshots/vm.snap, snapshots/vm.mem)
  • Firecracker snapshot restore is currently operator-proven at ~9ms on the Colima VZ nested-virt path.

Inngest state

  • StatefulSet PVC mounted at /data
  • INNGEST_SQLITE_DIR=/data

docs-api surface

  • Deployment: docs-api on NodePort 3838
  • Route count: 11 endpoints including /health
  • Key routes:
    • GET /search — hybrid chunk search with concept, concepts, doc_id, expand, and assemble
    • GET /docs/search
    • GET /docs
    • GET /docs/:id
    • GET /docs/:id/toc
    • GET /docs/:id/chunks
    • GET /chunks/:id
    • GET /concepts
    • GET /concepts/:id
    • GET /concepts/:id/docs
  • Taxonomy surface: 21-concept SKOS graph (10 parents + 11 sub-concepts) with broader, narrower, and related edges.

NAS (ADR-0088 + ADR-0187)

Tiering policy:

  • Tier 1 local SSD (hot runtime state)
  • Tier 2 NAS NVMe (/Volumes/nas-nvme ↔ /volume2/data)
  • Tier 3 NAS HDD (/Volumes/three-body)

Access paths

FromNVMe tier (1.5TB)HDD tier (56TB)Method
macOS host/Volumes/nas-nvme/Volumes/three-bodyNFS mount via LaunchDaemon
k8s podsPVC nas-nvmePVC nas-hddNFS PV (192.168.1.163)
host-worker funcs/Volumes/nas-nvme/Volumes/three-bodyDirect path (runs on macOS)

k8s ↔ NAS networking

k8s pods reach the NAS via a LAN route through the Colima col0 bridge: Talos → Docker NAT → VM col0 → macOS (ip.forwarding=1) → LAN → NAS

The VZ NAT on eth0 does NOT forward LAN traffic. Route persisted in Colima provision + colima-tunnel script: ip route replace 192.168.1.0/24 via 192.168.64.1 dev col0

Always use IP 192.168.1.163, never hostname three-body — DNS doesn't resolve from k8s.

Degradation contract (ADR-0187):

  • writes must fallback local -> remote -> queued
  • queue spool default: /tmp/joelclaw/nas-queue

Flagg Central shadow storage

  • Service root: /Users/Shared/joelclaw/
  • Shadow service data:
    • Redis: /Users/Shared/joelclaw/services/redis
    • Typesense: /Users/Shared/joelclaw/services/typesense
    • Inngest: /Users/Shared/joelclaw/services/inngest
    • MinIO smoke data: /Users/Shared/joelclaw/services/minio
    • Restate: Docker named volume ${CENTRAL_RESTATE_VOLUME:-joelclaw-central-restate-data} because macOS/Colima bind mounts reject Restate's Unix socket writes under /restate-data
  • Flagg NAS object-storage proof paths:
    • hot: /Volumes/nas-nvme/s3
    • cold: /Volumes/three-body/s3
  • Current proved NAS route:
    • Flagg interface en0, IP 192.168.1.10, 10Gbase-T
    • three-body IP 192.168.1.163
    • MTU 1500 is the proved safe Gate 5 state; jumbo 9000 caused an NFS blackhole and is follow-up work.
  • CENTRAL_REQUIRE_NAS=1 should only be set after mount proof passes.

Rhizomatic / Chorus (parked historical canary)

  • Decision: parked on 2026-07-17. It does not inject session briefings and no real claims may land.
  • The Brain is the only memory substrate. Any future claim graph must be a Brain-owned projection.
  • Historical artifacts remain at the old Flagg service/checkout/store paths only for cleanup and provenance.
  • com.joelclaw.chorus-rhizomatic shutdown still requires the steering sudo step; a loaded process does not make it an active dependency.
  • Old 4821/7331 endpoints and tunnels are not live routing guidance.

Vault and durable receipts

  • Obsidian vault at /Users/joel/Vault
  • Durable project/system receipts belong in Brain .svx.
  • The former /Users/joel/Vault/system/system-log.jsonl journal is archived and retired; runtime telemetry is canonical OTel in Typesense/ClickHouse.

7) Networking Topology

Central / Relay / Satellite routing rule

  • Live Central URL for capture hooks today: https://panda.tail7af24.ts.net.
  • Satellites post Run capture to /api/runs on that URL and may use JOELCLAW_TYPESENSE_URL=http://panda:8108 for direct search/admin helpers.
  • Flagg shadow services bind to 127.0.0.1 by default and must not be exposed over Tailscale/LAN until cutover planning says so.
  • There is no live Rhizomatic/Chorus routing exception. The old Flagg service and satellite tunnels are parked historical cleanup surfaces.

Caddy reverse proxy routes (from ~/.local/caddy/Caddyfile)

  • https://panda.tail7af24.ts.net:9443 -> localhost:8288 (Inngest)
  • https://panda.tail7af24.ts.net:8290 -> localhost:8289 (Inngest connect)
  • https://panda.tail7af24.ts.net:3443 -> localhost:3111 (worker)
  • https://panda.tail7af24.ts.net:5443 -> localhost:3838 (docs-api)
  • https://panda.tail7af24.ts.net:7443 -> localhost:7880 (LiveKit)
  • https://panda.tail7af24.ts.net:6443 -> localhost:6333 (Qdrant)
  • http://localhost:8443 path router:
    • /webhooks/* -> localhost:3111
    • fallback -> localhost:8288

Tailscale + Funnel

  • Config comments and ADR-0051 describe Funnel path :443 -> localhost:8443.
  • Runtime tailscale status unavailable here: UNKNOWN — needs manual verification.

External webhook ingress

Expected path:

  1. Internet provider -> Tailscale Funnel :443
  2. Funnel -> local :8443
  3. Caddy path route /webhooks/* -> worker :3111
  4. worker /webhooks/:provider verifies + emits Inngest event

Run capture ingress

Expected path:

  1. Machine hook reads JOELCLAW_CENTRAL_URL (satellite setup exports https://panda.tail7af24.ts.net)
  2. hook sends POST /api/runs with bearer token from ~/.joelclaw/auth.json
  3. Tailscale/Funnel/Caddy path reaches Panda host worker localhost:3111
  4. worker writes Run blob and emits memory/run.captured

8) CLI Wiring (Command Tree → Endpoint Surface)

Primary command tree root: packages/cli/src/cli.ts.

Endpoint map by command family

Command familyPrimary backend
sendInngest Event API POST /e/<event-key>
runs, run, functions, event, eventsInngest GraphQL POST /v0/gql
statusInngest/worker health probes + k8s checks + agent-mail liveness
gateway *Redis keys/channels + launchd/system ops
workload *workload planner + Redis queue admission + Restate dagOrchestrator / dagWorker runtime
docs *docs-api REST API (/search, /docs/*, /chunks/*, /concepts*)
restate cron *Dkron REST API via direct --base-url or short-lived kubectl port-forward to svc/dkron-svc
otel *ClickHouse OTEL store via capability adapter
recall *CLI composition root: flowing reflections + flowing observations + curated critical.db pages; exact scope/access required
sessions *Exact evidence drill-down through Central SQLite sessions.db / raw Pi session JSONL fallback
satellite *thin-Machine local probes + optional Central gateway repair request over SSH
mail *Agent-mail MCP HTTP (127.0.0.1:8765) via CLI adapter wrappers
inngest *worker launchd + Talon + k8s + Typesense diagnostics

Run capture is currently hook/script-driven, not a normal operator command family:

  • Claude Code: scripts/joelclaw-capture-session.ts
  • Codex: scripts/joelclaw-capture-codex-session.js
  • Pi: runtime extension hook
  • Central endpoint: POST /api/runs

Config source:

  • ~/.config/system-bus.env (plus env overrides)
  • defaults:
    • INNGEST_URL=http://localhost:8288
    • INNGEST_WORKER_URL=http://localhost:3111

9) Observability + Tracing Topology

OTEL event pipeline

  • Worker emits via emitOtelEvent() / emitMeasuredOtelEvent().
  • Gateway emits via @joelclaw/telemetry (emitGatewayOtel) to:
    • default OTEL_EMIT_URL=http://localhost:3111/observability/emit
  • Worker endpoint /observability/emit validates token (x-otel-emit-token) if configured.
  • Store path (storeOtelEvent):
    1. ClickHouse through the OTEL collector
    2. optional Convex mirror for high-severity recent window
    3. optional Sentry forward for warn/error/fatal

Run/session search observability

  • joelclaw sessions search is an operator bridge, not a new source of truth.
  • SQLite sessions.db searches captured Run chunks when the compacted index is current.
  • Raw fallback searches Pi session JSONL locally or over SSH when SQLite is stale or missing.
  • --extract returns bounded task context with decisions, commands, files, receipts, verification, blockers, next actions, and transcript line pointers. Do not dump whole transcripts.
  • If raw blobs/session files are newer than SQLite, fix indexing or backfill from blobs; do not treat the missing search hit as proof the work never happened.

Talon / health alerting posture

  • Talon should page for actionable critical failures, not normal control-plane taints or repeated noise from the same underlying outage.
  • Recent hardening adds critical-probe debounce and SOS throttling.
  • System worker supervision is a Panda system LaunchDaemon path; Talon checks must inspect system/com.joel.system-bus-worker, not only the user bootstrap domain.
  • Agent Secrets health should prefer secrets status; secrets health can time out under load and false-negative while leases still work.

Langfuse integration points

  • Gateway boot: packages/gateway/src/daemon.ts calls initTracing({}) from inference-router.
  • Inference router traces model-route decisions:
    • packages/inference-router/src/tracing.ts
    • used from packages/inference-router/src/router.ts
  • System-bus LLM traces:
    • packages/system-bus/src/lib/pi-output.ts (traceLlmGeneration)
    • called by packages/system-bus/src/lib/inference.ts and channel-message-classify.ts

10) Key ADR Topology Decisions

ADRTitleStatusTopology impact
ADR-0048Webhook gatewayshipped/webhooks/:provider normalization + signature verification + Inngest emission
ADR-0088NAS-backed storage tieringshippedDefines SSD/NAS NVMe/NAS HDD storage contract
ADR-0089Single-source worker deploymentshippedHost/cluster role split + single canonical source
ADR-0144Gateway hexagonal architectureshippedGateway as composition root; heavy logic in @joelclaw/*
ADR-0155Three-stage story pipelineshippedSimplified story function flow through Inngest durable steps
ADR-0156Graceful worker restartsupersededHistorical restart strategy; superseded by Talon ADR
ADR-0159Talon watchdog daemonshippedCompiled watchdog + infra supervision model
ADR-0038Embedded pi gateway daemonshippedAlways-on gateway session architecture
ADR-0051Tailscale Funnel ingressshippedPublic webhook ingress via Funnel/Caddy pattern
ADR-0148k8s resilience policyacceptedNodePort-first exposure, probe requirements, restart recovery checklist
ADR-0158worker-supervisor binarysupersededLegacy supervisor ADR now superseded, but binary remains in active launchd path
ADR-0182node-0 localhost resilienceshippedendpoint class fallback (localhost -> vm -> svc_dns)
ADR-0187NAS degradation fallback contractacceptedmandatory local/remote/queued write fallback
ADR-0212AIStor as local S3 runtimeacceptedmaintained local S3 runtime in aistor namespace; legacy MinIO retained for rollback
ADR-0243Runs-based memory captureactiveMachine hooks POST Runs to Central /api/runs; raw blobs are source of truth; Typesense is derived
ADR-0244Reply Grantsactivepublic channel replies require explicit per-thread grants; Project Threads do not authorize public posting
ADR-0245Project Threads as operator workroomsactivebounded objectives coordinate through private #brain-joel threads with receipts
ADR-0246Mac Studio Central migrationactiveFlagg shadow bootstrap, no split-brain, whole-Central cutover only after freeze/approval
ADR-0247New Central services start on Flaggactivenew Central-oriented services should prefer Flagg/shadow path instead of deepening Panda-only assumptions

10.1) Sandbox Execution Contract (@joelclaw/agent-execution)

Package: packages/agent-execution/
Purpose: Canonical contract for sandboxed story execution shared between Restate workflows, system-bus Inngest functions, and k8s Job launcher.

Contract Types

Request: SandboxExecutionRequest

  • workflowId, requestId, storyId: identifiers
  • task: story prompt/task to execute
  • agent: { name, variant?, model?, program? }
  • sandbox: "workspace-write" | "danger-full-access"
  • baseSha: git SHA before execution
  • cwd?: working directory
  • timeoutSeconds?: timeout
  • verificationCommands?: post-execution verification
  • sessionId?: tracking identifier

Result: SandboxExecutionResult

  • requestId: correlation ID
  • state: "pending" | "running" | "completed" | "failed" | "cancelled"
  • startedAt, completedAt?, durationMs?: timing
  • artifacts?: execution artifacts (see below)
  • error?: error message (failed state)
  • output?: stdout/stderr output

Artifacts: ExecutionArtifacts

  • headSha: git SHA after execution
  • touchedFiles: list of modified/untracked files from git status --porcelain
  • patch?: git patch content (format-patch or diff)
  • verification?: { commands, success, output }
  • logs?: { executionLog?, verificationLog? }

Repo Materialization (Story 3)

Function: materializeRepo(targetPath, baseSha, options)

Behavior:

  • Clone repo if target path doesn't exist (requires remoteUrl)
  • Fetch + checkout if target path exists
  • SHA verification after checkout
  • Automatic unshallow if SHA not in shallow clone
  • Isolated sandbox-local workspace (host worktree untouched)

Returns: { path, sha, freshClone, durationMs }

Key options:

  • remoteUrl?: remote URL for fresh clone
  • branch?: branch/ref to fetch (default: "main")
  • depth?: shallow clone depth (default: 1)
  • includeSubmodules?: include submodules
  • timeoutSeconds?: timeout (default: 300)

Artifact Export (Story 3)

Function: generatePatchArtifact(options)

Behavior:

  • Captures touched-file inventory via getTouchedFiles()
  • Generates git patch from baseSha..headSha:
    • Uses git format-patch if commits exist in range
    • Uses git diff if only uncommitted changes
  • Optionally includes untracked files as patch content
  • Embeds verification summary and log references
  • Serializable to JSON via writeArtifactBundle()

Key options:

  • repoPath: path to git repo
  • baseSha: base SHA (start of diff range)
  • headSha?: head SHA (default: HEAD)
  • includeUntracked?: include untracked files (default: true)
  • verificationCommands?, verificationSuccess?, verificationOutput?: verification data
  • executionLogPath?, verificationLogPath?: log references
  • timeoutSeconds?: timeout (default: 60)

Returns: ExecutionArtifacts

Promotion Boundary (Phase 1)

Authoritative output is patch bundle + metadata.

Sandbox runs do not merge to main or push to remote. The runtime:

  1. Materializes repo at baseSha in sandbox-local workspace
  2. Executes agent task
  3. Runs verification commands
  4. Exports patch artifact with touched files and verification results
  5. Emits SandboxExecutionResult event with ExecutionArtifacts

Promotion is a separate operator decision:

  • Restate workflow receives ExecutionArtifacts
  • Operator reviews patch + verification summary
  • Operator applies patch to host repo (or discards)
  • Operator commits and pushes (if approved)

This keeps sandbox runs isolated and reversible.

k8s Job Integration

Job spec generation: generateJobSpec(request, options)

Cold k8s Jobs for isolated story execution:

  • Deterministic Job naming keyed by requestId
  • Runtime image contract: Git, Bun, agent tooling, /workspace directory
  • Environment-driven config: WORKFLOW_ID, REQUEST_ID, STORY_ID, TASK_PROMPT_B64, BASE_SHA, etc.
  • Resource limits: 500m-2 CPU, 1-4Gi memory (configurable)
  • TTL cleanup: auto-delete after 5 minutes (default)
  • Active deadline: 1 hour max runtime (default)
  • No automatic retries (backoffLimit: 0)
  • Security: non-root (UID 1000), no privilege escalation, capabilities dropped

Runtime contract:

  1. Decode TASK_PROMPT_B64 from env
  2. Call materializeRepo() at BASE_SHA
  3. Execute agent with task
  4. Run verification commands (if VERIFICATION_COMMANDS_B64 set)
  5. Call generatePatchArtifact() with results
  6. Emit SandboxExecutionResult event with ExecutionArtifacts
  7. Exit 0 (success) or non-zero (failure)

Cancellation: Delete Job resource (SIGTERM to container)

Job deletion: generateJobDeletion(requestId) -> { name, namespace, propagationPolicy }

See k8s/agent-runner.yaml for full runtime contract specification.

Topology Impact

  • Story 2: Added contract types and Job spec generation
  • Story 3: Added repo materialization and artifact export helpers
  • ADR-0221 phase 1: added explicit local sandbox isolation primitives — deterministic sandbox identity, deterministic local sandbox paths, per-sandbox env materialization, minimal/full mode vocabulary, and a JSON registry helper for host-worker sandboxes
  • ADR-0221 phase 2: wired those local helpers into the real host-worker system/agent-dispatch local backend so sandbox runs now allocate deterministic paths under ~/.joelclaw/sandboxes/, materialize .sandbox.env, persist registry state, and carry localSandbox metadata in inbox snapshots
  • ADR-0221 phase 3/4/5/6: phase 3 added terminal retention/cleanup policy (cleanupAfter + registry metadata), opportunistic pruning of expired local sandboxes on new-run startup, copy-first .devcontainer materialization helpers with exclusion rules for env/secret junk, live sandbox env injection so the agent process actually sees the reserved runtime identity, a hash-preserving sandbox identity fix after live dogfood exposed path collisions from long shared requestId prefixes, abbreviated-baseSha acceptance during repo materialization, truthful failed inbox snapshots when dispatch crashes before normal terminal writeback, and a repeatable operator probe at bun scripts/verify-local-sandbox-dispatch.ts; phase 4 adds sandboxMode=minimal|full through the workload front door, requested-cwd mapping inside the cloned checkout, compose-backed full local mode startup, the reality that stale Restate workers can reject workload/requested until restarted and reloaded, a recursion guard because sandboxed stage runs were able to call scripts/verify-workload-full-mode.ts / joelclaw workload run from inside the sandbox and spawn nested canaries instead of terminating honestly, and a guarded workflow-rig proof run (WR_20260310_013158) that completes terminally with healthy compose startup plus clean teardown; phase 5 adds the operator-facing CLI surface joelclaw workload sandboxes list|cleanup|janitor so retained sandboxes can be inspected and janitored on demand instead of only during startup opportunistic pruning, and the operator surfaces now reconcile registry entries against per-sandbox metadata before reporting or deleting so old partial writeback residue stops lying about terminal state; phase 6 makes janitoring scheduled instead of purely manual via repo-managed launchd service com.joel.local-sandbox-janitor, which runs scripts/local-sandbox-janitor.sh → joelclaw workload sandboxes janitor at load and every 30 minutes
  • Future: Runtime image build, hot-image CronJob, warm-pool scheduler, Restate integration

Current state: the host-worker local sandbox path is now using the local-isolation helpers in production code, the package has a concurrent proof that two local sandboxes keep distinct compose identity plus copied devcontainer state, guarded full-mode workflow-rig dogfood closes terminally, and cleanup now has both on-demand CLI surfaces and scheduled launchd janitoring. Follow-on work is now about deeper runtime ergonomics and debugging any remaining non-terminal stale residues, not missing basic cleanup automation.


11) Verification Commands (Health + Wiring)

Core topology

# Colima + VM IP
colima status --json

# Kubernetes control plane + node
kubectl cluster-info
kubectl get nodes -o wide

# Core workloads
kubectl get pods -n joelclaw -o wide
kubectl get svc -n joelclaw -o wide

Host supervision

# Worker supervisor launchd state
launchctl print gui/$(id -u)/com.joel.system-bus-worker | rg "state =|pid =|last exit code"

# Gateway / Caddy / Talon
launchctl print gui/$(id -u)/com.joel.gateway | rg "state =|pid ="
launchctl print gui/$(id -u)/com.joel.caddy | rg "state =|pid ="
launchctl print gui/$(id -u)/com.joel.talon | rg "state =|pid ="

# Talon health
curl -s http://127.0.0.1:9999/health

Worker role split

# Parse role counts directly from source lists
python - <<'PY'
import re
from pathlib import Path
for f,name in [('packages/system-bus/src/inngest/functions/index.host.ts','host'),('packages/system-bus/src/inngest/functions/index.cluster.ts','cluster')]:
    txt=Path(f).read_text()
    body=re.search(rf'export const {name}FunctionDefinitions = \[(.*?)\];', txt, re.S).group(1)
    count=sum(1 for line in body.splitlines() if line.strip() and not line.strip().startswith('//'))
    print(name, count)
PY

# Inngest app ID derivation logic
rg -n "INNGEST_APP_ID|system-bus-host|system-bus-cluster|WORKER_ROLE" packages/system-bus/src/inngest/client.ts

Event flow trace

# Send event
joelclaw send <event> -d '<json>'

# Trace event and resulting runs
joelclaw events --prefix <event-prefix> --hours 1 --count 20
joelclaw event <event-id>
joelclaw runs --hours 1 --count 20
joelclaw run <run-id>

# Telemetry correlation
joelclaw otel search "<component_or_action>" --hours 1

Run capture + session search

Use recall and the current session-search contract. Keep private queries in structured MCP arguments. Raw evidence requires a scope-bound evidenceDrilldownReceipt; missing projections do not grant raw access.

Flagg Central shadow

cd ~/Code/joelhooks/joelclaw
./infra/central/scripts/preflight.sh
./infra/central/scripts/health.sh
ssh joel@flagg 'cd /Users/Shared/joelclaw/src/joelclaw && ./infra/central/scripts/reboot-proof.sh'

# NAS proof when explicitly working Gate 5 storage
sudo -u joelclaw -H env NAS_EXPECTED_INTERFACE=en0 NAS_EXPECTED_MTU=1500 \
  ./infra/central/scripts/verify-nas.sh --write-probe --benchmark-mib 64

Rhizomatic / Chorus parked-state check

# Historical cleanup only: confirm whether the parked service still awaits steering sudo.
launchctl print system/com.joelclaw.chorus-rhizomatic | rg "state =|pid =|last exit code"

Do not health-check or restart Chorus as a live memory substrate. There is no session briefing injection and no real claims may land.

Networking

# Caddy route config
caddy validate --config ~/.local/caddy/Caddyfile

# Listening ports snapshot
/usr/sbin/lsof -iTCP -sTCP:LISTEN -n -P

# Tailscale runtime (if daemon available)
tailscale status --json

12) Known Unknowns (Do Not Guess)

  • Tailscale daemon state is not readable in this environment.
    • tailscale status --json -> failed to connect.
    • UNKNOWN — needs manual verification
  • Live Flagg Central LaunchDaemon state is not implied by repo templates.
    • Check /Library/LaunchDaemons, launchctl print system/<label>, and infra/central/scripts/health.sh.
    • UNKNOWN until verified on Flagg
  • Typesense session search can be stale or missing expected collections while raw session files / Run blobs exist.
    • Diagnose capture and index metadata before declaring memory lost. Raw search and extraction require the scope-bound evidence receipt.
  • Exact command-line ownership of all Colima ssh forwarding ports (64784, 64785, 9627, etc.)
    • UNKNOWN — needs manual verification
  • Ingress controller runtime status for k8s/docs-api-ingress.yaml
    • UNKNOWN — needs manual verification
  • Whether docs/observability.md has fully caught up with Talon/Run-capture hardening.
    • UNKNOWN — needs manual verification

13) Mandatory Update Policy (Non-Optional)

Update this skill in the same change whenever any of these change:

  1. Worker runtime wiring
    • serve.ts, client.ts, index.host.ts, index.cluster.ts
    • WORKER_ROLE, app IDs, serveHost behavior, registration path
  2. Supervision/process topology
    • any ~/Library/LaunchAgents/com.joel*.plist
    • infra/worker-supervisor/*, Talon behavior, gateway launch script/label
  3. Kubernetes topology
    • any file under k8s/
    • Helm values affecting core services (livekit, pds, etc.)
    • Service type/port changes (NodePort/ClusterIP)
  4. Networking/ingress
    • Caddyfile route/port changes
    • Tailscale/Funnel hostnames or ingress path changes
    • Colima/VM networking model changes
  5. Storage topology
    • Redis keyspace contracts for gateway/webhook routing
    • Typesense telemetry collection/schema changes
    • NAS mount/fallback/queue contract changes
  6. Observability/tracing
    • OTEL emit endpoint/token behavior
    • telemetry storage path changes (Typesense/Convex/Sentry)
    • Langfuse integration points
  7. CLI control-plane routing
    • command families moved to different endpoints/services
  8. ADR status changes affecting topology
    • especially ADR-0048, 0088, 0089, 0144, 0155, 0156, 0159, 0182, 0187, 0243, 0244, 0245, 0246, 0247
  9. Central / Relay / Satellite vocabulary or authority changes
    • CONTEXT.md
    • docs/runbooks/satellite-rig-setup.md
    • Flagg/Panda cutover status, Central host identity, or Relay Machine role changes
  10. Run capture / memory ingestion changes
  • /api/runs, memory/run.captured, capture hook scripts, Machine auth, Run blob paths, capture-auth.db, sessions.db, runs_dev, machines_dev
  1. Flagg Central scaffold changes
  • infra/central/*, Central LaunchDaemon templates, NAS proof scripts, shadow Compose services, reboot proof, Gate 5 status
  1. Rhizomatic / Chorus parked-state cleanup
  • service stop state, removal of obsolete tunnels/injection, and preservation of historical receipts; never restore live claims without a new Brain-owned decision

If any item above changed and this skill was not updated, this skill is stale and non-canonical.

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

Sep 24, 2026

分类

未分类

许可证

未指定

源路径

skills/system-architecture

默认分支

main

最新提交

e313432

Tree SHA

eb9cad7