Files
clawmates/deploy/clawmates-runtime
Omar Sobh 87f188ae73 refactor: strip Gemini from the platform, and level up the architecture_mapper
Two things.

1. The architecture_mapper proposal, applied AND made durable.

The GLM proposal (019fddd9) was accepted in full: the agent's system_prompt now
carries the Mermaid-first constraint and its brain was rewritten. Both verified
against the live row and the .h5 file.

But `apply_identity` writes `UPDATE agents SET system_prompt` and
`apply_brain_consolidation` writes that agent's brain — neither touches the team
TEMPLATE. That agent is mission-scoped, so the improvement would have died with
the mission. The model's actual insight was sharp and worth keeping: "Mermaid
diagrams beat prose" lived in the brain SEED and not in the system PROMPT, so it
only applied when the agent happened to consult its brain. That constraint is
now in templates/teams/codebase_research.toml, where every future Codebase
Research team inherits it.

(The proposal's second item mostly restated anti-patterns the seed already
lists, so the seed is unchanged. Applying an LLM's suggestion is not the same as
agreeing with all of it.)

2. Gemini is gone.

Removed: the `gemini.default` provider alias and its `is_exact_provider_match`
prefix, GEMINI_API_KEY forwarding to agent containers, the evaluator's
gemini->gemini family row, the model selectors in claws/teams/planner and in
TeamWizard + AgentComputer, and the commented provider block in the runtime
config example (whose ZEROCLAW_AGENT_MAP example still mapped a worker_gemini
that no longer existed).

`provider_alias_for("gemini")` now returns claude_cli.default via the
unrecognised-model branch, which LOGS. A stray gemini binding degrades visibly
rather than resolving to a provider row we no longer ship. A test pins that, and
another pins that GEMINI_API_KEY is forwarded in NEITHER auth mode, so adding it
back to the list is a visible change rather than an accident.

Avatar generation is DELETED, not disabled — it called Gemini's image model, and
there is no alternative: Claude and Kimi are text-only, and z.ai answers
"Unknown Model" for cogview-3-flash and cogview-4 on our plan (measured, not
assumed). AvatarModal keeps UPLOAD, which never needed a provider; only the
prompt-generation half is gone.

240 backend lib tests, 89 frontend tests, clean tsc + eslint, build succeeds.
2026-08-07 14:15:53 -07:00
..

Clawmates per-tenant runtime (ZeroClaw) — Phase 1 spike

Goal of Phase 1: stand up one Clawmates tenant runtime container (a slim ZeroClaw daemon) on gw-04, drive it from a small Clawmates-side client (provision an agent → run a turn → stream events), and prove one §15 gate by routing an outbound action through a stub Clawmates MCP tool. See docs/agent-engine-architecture.md for the full design.

Confirmed runtime contract (from the live MindHealth/ClawHealth images in prod)

  • Image entrypoint: zeroclaw, default cmd: daemon
  • Gateway port: 42617 (ZEROCLAW_GATEWAY_PORT)
  • Per-tenant data volume mounted at /zeroclaw-data (HOME=/zeroclaw-data, ZEROCLAW_WORKSPACE=/zeroclaw-data/workspace)
  • Config overrides via env: ZEROCLAW_<dotted__path>=value (double-underscore = nesting)

Build the slim image (off-box, push to the private registry)

ZeroClaw's own multi-stage Dockerfile builds the daemon; ZEROCLAW_CARGO_FEATURES selects channels. We drop the heavy defaults (lark/whatsapp) — Clawmates exposes outbound capabilities as gated MCP tools, not native channels.

# from a build host (this Mac, or Gitea CI) with the zeroclaw checkout:
docker build \
  -t web-01:5000/clawmates-runtime:dev \
  --build-arg ZEROCLAW_CARGO_FEATURES="channel-webhook" \
  ~/projects/zeroclaw
docker push web-01:5000/clawmates-runtime:dev      # registry is Tailscale-only, insecure HTTP

Build is heavy (zeroclaw is ~160k LOC Rust). Prefer building on a beefy box or CI, not gw-04; gw-04 only runs the image.

Run the dev stack on gw-04

scp deploy/clawmates-runtime/compose.dev.yml gw-04:/home/redclaw/clawmates/
ssh gw-04 'cd ~/clawmates && docker compose -f compose.dev.yml up -d'

The runtime gateway is bound to 127.0.0.1:42617 on gw-04 (not public). Reach it for the spike over the SSH/Tailscale tunnel; production fronts it with Traefik on its own router, isolated from gr33t/cbh.

§15 model (unchanged moat)

The tenant agent is provisioned with no native outbound tools and no real channel/secret config (tools.allow locked). Every sensitive capability (email/slack/pay/delete/…) is a Clawmates MCP tool; the agent's only egress is that gated MCP door, where cm-safety + cm-secrets apply approvals, taint, single-use grants, broker execution, and journaling.

Confirmed drive recipe (Phase 1 — proven on tank)

A turn ran end-to-end (scout answered over /ws/chat). The working flow:

  1. Configure a tenant daemon. Two gotchas the spike uncovered:
    • Provider-map entries must be set via the prop/env path, NOT a TOML sub-table. [providers.models.groq.default]\nmodel="…" in config.toml parses to an empty entry (groq.default = {}, model <unset>). Set them via env instead: ZEROCLAW_providers__models__groq__default__model=…, ZEROCLAW_providers__models__groq__default__api_key=… (double-underscore = path; key from Infisical).
    • The agent references the provider by type.alias: [agents.scout] model_provider = "groq.default".
    • Onboarding gate is a flag — set [onboard_state] quickstart_completed = true (else /ws/chat returns NEEDS_ONBOARDING). onboard_state + agents.* DO load fine from config.toml.
  2. Pair for a bearer token: read the one-time code from the daemon's startup log (X-Pairing-Code: NNNNNN), then POST /pair with header X-Pairing-Code: <code>{token}.
  3. Run a turn over WebSocket /ws/chat?agent=<alias>&token=<token> (Node's global WebSocket can't set headers, so the token goes in the query — gateway accepts header > subprotocol > query). Send {"type":"message","content":"…"}; receive session_startchunk*tool_call/tool_resultapproval_request (the §15 hook) → done.

Drive client: tools/runtime-spike/drive.mjs (Node ≥22). Example:

PAIR_CODE=<code> node tools/runtime-spike/drive.mjs http://<host>:42617 scout "hi"

Driving topologies from Clawmates (POST /api/topologies/run)

cm-orchestrator owns the topology graph; for each turn it drives one ZeroClaw role-agent in this container over the recipe above, via ZeroClawDriveExecutor (crates/cm-api/src/topology_exec.rs). The server reads these env knobs (unset = the endpoint 500s; the rest of cm-api is unaffected):

  • ZEROCLAW_GATEWAY_URL — e.g. http://127.0.0.1:42617
  • ZEROCLAW_PAIRING_CODE — the one-time code from the daemon startup log
  • ZEROCLAW_AGENT_MAP — optional role=alias,role=alias (e.g. analyst=researcher)
  • ZEROCLAW_DEFAULT_AGENT — fallback alias for unmapped roles (default scout)

agent.config.example.toml declares the multi-agent role-cast (coordinator/researcher/writer/worker

  • scout), all tool-free. Manual E2E: bring up the stack, grab the pair code, sanity-drive one alias with drive.mjs, then POST /api/topologies/run {task, graph} (build a graph via /api/topologies/build) and confirm the RunRecord has real per-step outputs + per-turn tokens.

Next

  • Demonstrate a §15 gate: give scout a tool under the Supervised profile and confirm the approval_request round-trip over the socket (drive client already handles it).
  • Replace zeroclaw's native approval with the Clawmates MCP door (cm-safety/cm-secrets).
  • Map WS events → run_events journal; /api/cost → billing.
  • docker save the image → docker load on gw-04 and run compose.dev.yml there.