althing-chamber: add althing-agent-runner as third compose service

Phase 2 daemon added to the althing-chamber stack per forseti's request
(vh/althing@5cd088a..ad1d025). Polls floor_grants WHERE consumed_at IS
NULL AND agents.driver='worldtree', claims via atomic UPDATE, calls
Worldtree's conversation API, posts the response back through the bus
as a broadcast.

Shape matches the existing forseti daemon:
  - Same ${ALTHING_IMAGE} (the binary is already in [project.scripts]
    as of ad1d025)
  - command: ["althing-agent-runner"]
  - Same shared SQLite bind-mount at /app/data
  - No port, no healthcheck (CLI doesn't expose one; same liveness
    story as forseti)

Safe to enable preemptively per forseti — when no driver=worldtree
handles are declared in config, the runner sleeps at
poll_interval_seconds. Multi-instance safe via the atomic claim
primitive (no flock needed).

Compose top comment, README "Services in this stack" table, playbook
header + verify steps all extended to reflect the three-service
shape. Will land on ana-docker on vh/althing's next push (compose
deployed via the elway playbook's upload step; image already carries
the binary).
This commit is contained in:
vh
2026-05-16 20:01:57 -07:00
parent 91d5417b0b
commit 59899e4e0f
3 changed files with 52 additions and 17 deletions
+26 -5
View File
@@ -1,9 +1,11 @@
# althing-chamber + forseti — web UI + moderator daemon for the althing
# inter-agent message bus.
# althing-chamber + forseti + agent-runner — web UI + moderator daemon +
# Worldtree-driver agent-runner for the althing inter-agent message bus.
#
# Two services share the althing SQLite store via a single bind-mount:
# althing-chamber — FastAPI/HTMX app (port 7881 host → 8000 container)
# althing-forseti — moderator daemon (no port; cross-process glue via the DB)
# Three services share the althing SQLite store via a single bind-mount:
# althing-chamber — FastAPI/HTMX app (port 7881 host → 8000 container)
# althing-forseti — moderator daemon (no port; cross-process glue via the DB)
# althing-agent-runner — Phase 2 daemon: claims worldtree-driver grants and
# dispatches to Worldtree's conversation API (no port)
#
# eventbus.bridge_from_db is load-bearing — forseti's DB commits reach
# chamber's SSE subscribers via the bridge, not via shared memory or IPC.
@@ -74,3 +76,22 @@ services:
# No healthcheck — the forseti CLI doesn't expose one. Liveness signal
# for ops is "container hasn't exited" + chamber-side observation that
# bridge_from_db events are flowing.
althing-agent-runner:
image: ${ALTHING_IMAGE}
container_name: althing-agent-runner
restart: unless-stopped
environment:
- ALTHING_ROOT=/app/data
- ALTHING_DB=/app/data/althing.db
volumes:
- ${ALTHING_DATA_DIR}:/app/data
command: ["althing-agent-runner"]
# Phase 2 daemon (added 2026-05-16). Polls floor_grants WHERE
# consumed_at IS NULL AND agents.driver='worldtree', claims via
# atomic UPDATE, calls Worldtree's conversation API, posts the
# agent's response back through the bus as a broadcast. Harmless
# when no driver=worldtree handles are declared — runner sleeps
# at poll_interval_seconds. Multi-instance safe via claim_grant's
# atomic UPDATE; no flock required. Same lack-of-healthcheck story
# as forseti (CLI doesn't expose one).