Symmetric with the research pipeline: every enabled loop can now have its own per-loop team container so scheduled runs don't share state with other loops or with research. Same daemon image, same clawmates network, deterministic name loop-<id>-team. Backend surface: - Migration 0040 adds nullable `zeroclaw_container` + `zeroclaw_gateway_url` columns to loops (parallel to research_topics). - research_container.rs grows loop_container_name_for(), spawn_loop() (state-only mount, no repo), and teardown_loop(). Kept in the same module to share the docker connect() + inherited_env() plumbing; each pattern gets its own labels (clawmates.role=loop-team) so ps filters can tell them apart. - cm_db::repo::loops gains set_zeroclaw_container() + zeroclaw_gateway_url() (dynamic sqlx queries — no offline cache regen needed). - cm_db::repo::topology_runs gets loop_id_for_run(): mirror of research_topic_id, used by the worker. Wiring: - routes/loops::run_now + webhook_receive call ensure_loop_container() before enqueuing an iteration. Idempotent: an already-running container is just reattached. Failures are logged and do NOT block the enqueue — topology_worker falls back to the workspace gateway when the URL isn't set on the loop. - routes/loops::disable_loop + delete_loop both fire teardown_loop() so paused / deleted loops don't hold a docker slot. - topology_worker's per-run URL resolution: existing research fast path unchanged; when it doesn't hit, the worker now looks up loop_id and reads the loop's gateway URL. Deploy step (required on gw-04 for state to persist across container restarts): add a `/var/lib/clawmates-loops:/var/lib/clawmates-loops` bind mount + `CLAWMATES_LOOPS_STATE_ROOT=/var/lib/clawmates-loops` env var to clawmates_server_1 in the compose. Without it, loops still run — the state dir lives inside the API container's filesystem so persistence is limited to that container's lifetime. Follow-up: - Scheduler-tick fires (cron-driven, not run_now) — they call enqueue_iteration in cm-scheduler and don't yet go through ensure_loop_container. Add a symmetric spawn there so cron fires also land on the isolated daemon. - Compose file reconciliation — deploy/compose/docker-compose.yml in the repo has drifted from prod; when we sync it, add the loops mount at the same time.
21 lines
1.1 KiB
SQL
21 lines
1.1 KiB
SQL
-- Path B for loops (P2): give every enabled loop its own per-loop team
|
|
-- container so scheduled runs don't share state / memory with other loops
|
|
-- or with the research pipeline. Two nullable columns:
|
|
--
|
|
-- zeroclaw_container — deterministic docker container name; NULL
|
|
-- until the first `run_now` / `webhook_receive`
|
|
-- / scheduler tick spawns one, set + reused
|
|
-- on subsequent fires.
|
|
-- zeroclaw_gateway_url — http://<container>:42617; topology_worker
|
|
-- prefers this over the workspace-wide URL when
|
|
-- the run belongs to a loop with a spawned
|
|
-- container.
|
|
--
|
|
-- Fallback semantics match research: NULL means "no per-loop container
|
|
-- yet, use the env-derived executor". Never-spawned loops (e.g. from
|
|
-- workspaces where docker isn't reachable) keep firing on the shared
|
|
-- gateway — degraded, not broken.
|
|
ALTER TABLE loops
|
|
ADD COLUMN zeroclaw_container TEXT,
|
|
ADD COLUMN zeroclaw_gateway_url TEXT;
|