Commit Graph
17 Commits
Author SHA1 Message Date
Omar SobhandClaude Opus 5 9e61e3ba35 feat(viz): what the agents actually did, as structured events
The World could draw a mission's shape but nothing about the work. The
detail existed only as prose in checkpoint.log and model output, where a
tool name is indistinguishable from an agent *talking about* a tool — so
it was never parsed, deliberately. `mission_events` is the structured
channel that replaces it.

Three taps, one table:

- Container tier: the `_ => {}` at the end of topology_exec's typed frame
  stream now matches `tool_call` and reads the tool's JSON ARGUMENTS for a
  path. Never the prose summary — a path scraped from a sentence would put
  files on the map that no agent opened, and the test proves a Grep whose
  summary says "src/main.rs" produces no file touch. The frame name itself
  is unverified, so the same commit ships an unmatched-frame-type
  histogram: a tap that matches nothing looks exactly like a mission that
  used no tools, and this is how one gw-04 run names the real frame.

- microVM tier: a `PostToolUse` hook, the seam vm_stop_gate already proved
  fires under `claude -p`. It copies stdin to /root/tap and exits 0
  unconditionally — a non-zero PostToolUse hook talks back to the model,
  which would turn the observer into a participant. Drained before collect,
  since the VM is destroyed moments later.

- Phase transitions: five identical copies of the pending→running UPDATE
  became one `mark_phase_running`, and `close_finished_phases` grew
  RETURNING. Its CASE decides each phase's status inside SQL from rows the
  statement does not change, so it cannot be re-derived afterwards without
  writing that CASE twice — without RETURNING it emits zero phase.completed
  and reports success.

The settings.json hazard the plan called out: the stop gate wrote the
WHOLE document, so a second hook writer would have silently erased it and
a coding phase would then complete having written nothing — the exact
failure the gate exists to catch. There is now one composer,
`vm_tool_tap::guest_settings`, one writer, and a source-walk test that
fails if anything else writes a settings document.

`mission_events.run_id` carries no FK on purpose: phase_runner DELETEs
topology_runs on retry, and a cascade would erase a phase's whole history
the moment it retried — silently, since a cascade is not an error.

world.rs streams it with a cursor that separates backfill from motion.
Everything already in the table when a subscriber arrives is drawn as
settled history; only what lands afterwards animates. Otherwise opening a
finished mission replays an hour of tool calls as a burst storm.

Bounded twice: 400 events per phase (enforced inside the INSERT, since
two concurrent taps would each read a count below the cap) and a 7-day
retention sweep in mission_gc.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-11 09:16:50 -07:00
Omar SobhandClaude Opus 5 e2c312b728 docs(runtime): the judge no longer runs on a dead credential
`provider_alias_for` still documented the judge as deliberately sitting on
`anthropic.judge`/API key, so a subscription throttle would degrade missions
while verification kept working. That credential is an account with a zero
balance — driving the real path returns 400 "Your credit balance is too low" —
so the comment pointed the next reader at something that cannot answer.

`anthropic.default` and `anthropic.judge` are retired from the runtime config
and every agent that named them was repointed onto a live credential. The
independence argument that put the judge there still holds; it is now served by
a different FAMILY rather than a different key — CLAWMATES_VALIDATOR_MODEL is
glm:glm-4.7 on gw-04, and cross_provider_judge already refuses a validator in
the implementer's own family.

Config-side (gw-04, not in this repo): 755 -> 246 lines, 128 -> 14 agent
blocks, after sweeping 19 [agents.claw_<uuid>] corpses — every one verified
against agents WHERE deleted_at IS NULL. Nothing reaped those, and the file is
byte-copied into every mission.

Verified: scout/judge/worker_kimi/worker_glm each answer on their new
provider, and multirole passes 4/4 against the reorganized config.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-10 13:18:16 -07:00
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
Omar SobhandClaude Opus 5 ac47dcbe94 feat(runtime): run agents on the subscription via the real claude binary
ci / gates (push) Failing after 5s
ci / rust (push) Skipped
ci / frontend (push) Skipped
ci / e2e (push) Skipped
ci / publish (push) Skipped
provider_alias_for now resolves Claude models to `claude_cli.default`,
which spawns the actual `claude` binary, instead of `anthropic.default`,
which posts to the raw API with Claude Code identity headers. Agent work
is ~99% of tokens, so this moves essentially all of it onto the Max
subscription and onto the supported client.

The judge deliberately stays on the API key. If both rode one credential,
a single subscription limit would blind the verifier at exactly the
moment there is most to verify; this way a throttle degrades missions but
verification keeps working.

Runtime config (applied on gw-04, reloaded via loopback — remote admin
reload is disabled by design):
  - [providers.models.claude_cli.default] with mcp_config pointing at the
    §15 door, so a subscription agent can ACT and not merely reason
  - disallowed_tools denies Claude Code's own Bash/Write/Edit/WebFetch so
    the gated door is the ONLY actuator and nothing bypasses the audit log
  - env CLAUDE_CODE_OAUTH_TOKEN = "$CLAUDE_CODE_OAUTH_TOKEN" — the $NAME
    form reads the daemon env, keeping the token out of config.toml
  - anthropic.judge swapped to the API key (0 oat01 left in config)

Verified before changing anything: the real binary returned SUBSCRIPTION-OK
through the token, then ENV-OK once the daemon carried it in env.

Note for future readers: /api/config/prop reflects what is CONFIGURED, not
what the binary supports — `openai` 404s there too. An earlier note that
the image "has no claude_cli in its schema" was true of the old :sync
image and is not true of the rebuilt one.

400 tests, clippy clean.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-03 17:14:42 -07:00
Omar SobhandClaude Opus 5 2eb0880fc0 fix(skills): reconcile team-template skill names so role bindings actually bind
ci / gates (push) Successful in 5s
ci / rust (push) Failing after 10s
ci / frontend (push) Failing after 19s
ci / e2e (push) Skipped
ci / publish (push) Skipped
Every skill reference in every team template was failing to resolve. The
TOMLs used snake_case slugs (`write_rust`, `index_selection`) while the
authored skills under `skills/**/*.md` declare kebab-case names
(`write-rust-current-edition`, `postgres-index-selection`), so
`get_by_name` missed on all of them: 128 skipped bindings across 51
distinct names, and no mission agent received any of its template's
skills.

The mirror-image half was equally invisible: ten authored skills —
including `int-xx-marker-protocol`, whose own `when_to_use` says "pin on
every coding role" — were referenced by no role at all, so nothing could
ever load them.

- Rename the 14 references that have authored skills behind them, and
  dedupe the two that now collapse onto the commit-protocol skill.
- Attach all ten orphaned skills to the roles their `when_to_use` names.
  All 23 authored skills now reach at least one role.
- Aggregate the loader's per-name logging into one line per template.
  The old per-name spam is why this went unnoticed; a bound/unresolved
  count is noticeable. References with no authored skill are kept and
  listed — they record intent for skills not yet written.
- Two regression tests: no authored skill may be orphaned, and every
  authored skill must be referenced by its exact name.

Also clears the two standing clippy warnings: group
`mint_team_from_template`'s eight positional args into `TeamMint`, and
make `provider_alias_for` branch on `is_exact_provider_match` so the
helper is live code and the two can't disagree about what counts as an
exact family match.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-31 19:47:18 -07:00
Omar SobhandClaude Opus 5 ca45597c79 feat(credentials): make provider substitution and runtime auth mode visible
ci / gates (push) Successful in 8s
ci / rust (push) Failing after 11s
ci / frontend (push) Failing after 22s
ci / e2e (push) Skipped
ci / publish (push) Skipped
Three guardrails around which credential pays for what.

1. Boot announces the mission-runtime auth mode, and warns when subscription
   auth is configured on a deployment with more than one user. A consumer
   subscription credential may only run the account holder's own work, and
   that condition is otherwise invisible -- it holds today and quietly stops
   holding the first time someone else signs up. Adds users::count_all
   (dynamic query, so the offline cache needs no regeneration).

2. Reject an ANTHROPIC_API_KEY shaped like a subscription OAuth token
   (sk-ant-oat...) at boot rather than failing on the first model call far
   from the mistake. Both credentials start sk-ant-, so the confusion is easy
   to make and hard to spot.

3. provider_alias_for's GLM/Kimi -> anthropic.default fallback was documented
   as deliberate but was silent in effect: a user picking "kimi" in the UI got
   an agent spending the Anthropic key, with nothing saying so. It now logs
   the substitution, and is_exact_provider_match() lets callers tell a real
   family match from a substitution so a UI can say which model will actually
   run. Behaviour is unchanged -- only the silence is.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-30 19:41:19 -07:00
Omar SobhandClaude Opus 5 b1bdfbbf87 fix(provision): let callers declare write access instead of guessing from the role name
default_risk_profile_for_role decides whether a claw gets file edits, git and
shell by substring-matching its role against a fixed keyword list. On the
planner path that role string is free text the model invented for this
proposal, so a model's choice of wording silently decided tool access: a
proposed "implementation_lead" matches no keyword, lands research_readonly,
and then fails every file edit for a reason invisible from the role name.

TeamMemberInput and the planner's member schema now carry `needs_write`, and
resolve_risk_profile prefers it over the guess. The planner prompt asks for it
per member and says to grant write only to members that produce code or
commits. Absent (older clients, autoprovision, a model that omitted the field)
falls back to the old guess, so nothing changes for callers that don't set it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-30 10:53:08 -07:00
Omar SobhandClaude Opus 4.8 06ae608d0c fix(missions): provision claws into the mission's own daemon + reload the pin
Mission turns execute against the per-mission runtime container, but claws
were provisioned via RuntimeProvisioner::from_env() — i.e. the GLOBAL gateway.
That daemon loads config once at boot and never re-reads the file, so the
per-mission daemon had no claw_* agents at all: querying it for a mission
claw's risk_profile returned 404 while the global daemon returned 200. With
the alias unresolvable, the daemon silently fell back to the default `scout`
agent, which is jailed to the global workspace — agents reported "the scout
agent workspace" and "/mission/repo isn't accessible", produced no files, and
burned tokens. This is the deeper cause behind the empty-output runs; the
tool-allowlist and workspace-pin fixes were necessary but not sufficient.

- RuntimeProvisioner::for_gateway(url) — aim the provisioner at a specific
  gateway (mirrors ZeroClawDriveExecutor::from_env_for_gateway); from_env now
  delegates to it.
- mission_orchestrator captures the per-mission endpoint from ensure_container
  and provisions every claw there, falling back to the global gateway only
  when there is no per-mission runtime (dev/no-docker).
- workspace.path is file-only (the config prop API cannot set a PathBuf), and
  the daemon never re-reads the file, so pin_agent_workspaces is now followed
  by restart_container(): restart + wait for /health to answer. Agents created
  through the daemon's own config API are already persisted to that file, so
  they survive; the pairing code is re-minted on every launch.
  The readiness probe inspects the /health BODY — exec_capture only fails on
  docker errors, so a curl that cannot connect still "succeeds".

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-28 10:27:54 +02:00
Omar SobhandClaude Opus 4.8 34409bca0c fix(missions): grant coding tools + pin claw workspace to /mission/repo
Mission agents were burning ~275K tokens producing nothing: the coder had
only file_read and its workspace was the empty ephemeral sandbox, so it
dumped a full spec inline instead of writing files. Two root causes:

1. Risk-profile allowlists used pre-0.8 tool names. `coding_readwrite`
   allow-listed `file_write` (renamed to `file_edit` in ZeroClaw 0.8, and
   `file_write` now refuses on ephemeral workspaces) and omitted file_edit
   / content_search / glob_search / git_operations — the exact tools the
   phase prompt tells agents to use. Since allowed_tools is a strict
   allowlist, agents were effectively read-only. Documents the correct
   profiles in agent.config.example.toml (they only lived in host config;
   the live runtime profiles were corrected via its config API).

2. workspace.path never got set. `agents.<alias>.workspace.path` is an
   Option<PathBuf> the ZeroClaw Configurable macro skips from prop
   enumeration, so provision_claw's set_prop always 404'd and the whole
   call errored into a swallowed eprintln. Removes the dead set_prop and
   pins the workspace out-of-band: MissionRuntimeProvisioner::
   pin_agent_workspaces patches the shared config file on the per-mission
   container (format-preserving via toml_edit, atomic temp+mv); the daemon
   applies it on the same reload that surfaces the freshly-provisioned
   claws. Covered by unit tests for the TOML stamp.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-28 08:40:18 +02:00
Omar Sobh 6d5e7c87d7 fix(claws): point per-mission workspace at /mission/repo + tool-inventory preamble
ci / gates (push) Successful in 18s
ci / frontend (push) Successful in 53s
ci / rust (push) Successful in 3m30s
ci / publish (push) Successful in 4m6s
ci / e2e (push) Skipped
Two stacked issues after risk_profile was fixed:

1. Claws had file_edit + 46 other tools available, but the templates
   trained the agents to expect file_read/file_write (older ZeroClaw
   tool names). Result: agent output kept saying "I only have file_read"
   and dumped implementations into the context window as text.

2. Even with file_edit, the sandbox pointed at
   /zeroclaw-data/.zeroclaw/agents/<alias>/workspace/ — NOT
   /mission/repo where the checked-out mission repo actually lives.
   unrestricted_filesystem=false blocked agents from reaching it.

Fixes:
- provision_claw now takes workspace_path. mission_orchestrator passes
  /mission/repo — pins the per-claw workspace via
  agents.<alias>.workspace.path to the bind-mount path so file_edit /
  content_search / glob_search operate on the mission's git checkout.
- phase_task_text prepends an explicit tool inventory (file_edit,
  content_search, glob_search, git_operations, git_forge, ...) plus a
  WORKSPACE line pinned at /mission/repo. Each phase directive is
  rewritten to reference file_edit / git_operations explicitly and to
  call out "do NOT paste code in your reply expecting the platform to
  save it."
2026-07-24 13:14:30 -07:00
Omar Sobh 84572186e9 fix(runtime_provision): use team-template risk_profile, not hardcoded toolfree
ci / gates (push) Successful in 6s
ci / publish (push) Successful in 4m4s
ci / frontend (push) Successful in 38s
ci / rust (push) Successful in 3m48s
ci / e2e (push) Skipped
The provisioner was hardcoding risk_profile=toolfree for every claw,
which the ZeroClaw config explicitly configures to EXCLUDE every
usable tool (shell, file_read, file_write, http_request, browser).
Result: coder/tester/committer claws had zero tools and produced text
in the context window with no ability to actually write files or run
tests — exactly what the last mission summary showed.

Fixes:
- provision_claw now takes risk_profile: &str, passed through from
  the team template (development teams already had coding_readwrite,
  which now actually gets applied).
- Research team templates updated from toolfree → research_readonly
  (file_read) and papers_research → research_web_readonly
  (file_read + web_search + web_fetch). Applied to both the on-disk
  TOML files and the live DB rows.
- Added RuntimeProvisioner::default_risk_profile_for_role for
  auto-provision code paths that lack a template context — picks
  coding_readwrite for coder-like roles, research_readonly otherwise.
- Split rebind_model out of provision_claw so the model-change UI
  path doesnt inadvertently clobber the existing risk_profile.

Templates DB fixup for missions launched pre-deploy is already
applied via manual UPDATE.
2026-07-23 19:44:27 -07:00
Omar Sobh fdb8cfeecc slice 9 cleanup: drop legacy research/loops backend + tables
Retires the legacy research/loops backend after the missions arc
(slices 1-9) fully replaced it. Frontend cutover was 4663348; this
commit finishes the job on the backend + database.

Migration:
  - 0053_drop_legacy_research_loops.sql — drops the 8 legacy tables
    (research_topics, research_topic_agents, research_outcomes,
    research_publish_approvals, loops, loop_agents, loop_orgs,
    loop_teams) and the 3 topology_runs FK columns
    (research_topic_id, loop_id, iteration). parent_run_id stays;
    recursive_exec still uses it.

Files deleted (11):
  - crates/cm-api/src/routes/{research,loops,research_setup,
    research_pipeline,wizard_repo,probe}.rs
  - crates/cm-api/src/research_container.rs
  - crates/cm-db/src/repo/{research_topics,research_outcomes,
    research_publish_approvals,loops}.rs
  - crates/cm-runtime/src/loops.rs
  - crates/cm-api/tests/research_publish_role.rs

Files edited:
  - crates/cm-api/src/lib.rs — dropped 20 legacy route registrations
    (all /api/research/* + /api/loops/* + /webhooks/loops + probe)
    and module decls
  - crates/cm-api/src/topology_worker.rs — deleted legacy dispatch
    (freeze_research_outcome, advance_loop_after_completion,
    continue_initial_burst, maybe_transition_research_topic,
    parse_reorder_rationale, per-topic/loop gateway resolver).
    reap_stuck_runs now keys on mission_id (not topic_id).
    Executor path unconditionally uses ZeroClawDriveExecutor::from_env
    — mission_orchestrator provisions each claw as an agent inside
    the shared runtime via RuntimeProvisioner, so per-team gateway
    resolution is no longer applicable.
  - crates/cm-api/src/routes/topology.rs — deleted container-log SSE
    endpoint (research/loop-specific), dropped loop_id filter and
    iteration field from ListRunsQuery/RunSummary
  - crates/cm-api/src/routes/world.rs — removed
    active_research_topics/active_loops/preseed_repo_paths;
    World SSE no longer emits repo:{topic}/loop:{id} landmark orbs
    (follow-up task #21 tracks adding mission:{id} equivalents)
  - crates/cm-api/src/runtime_provision.rs — removed now-unused
    mint_workspace_service_token
  - crates/cm-db/src/repo/topology_runs.rs — removed 9 legacy
    helpers (research_topic_id lookup, loop_id_for_run,
    iteration_for_run, active_runs_for_research_topic, etc.)
  - crates/cm-db/src/repo/teams.rs — removed 4 dead helpers
    (team_for_loop, team_for_research_topic + setters)
  - crates/cm-api/tests/topology_jobs.rs — removed loop/topic
    tests, dropped enqueue_run_with_topic helper
  - crates/bins/clawmates-server/src/main.rs — removed
    spawn_loop_scheduler call
  - crates/cm-api/src/routes/mod.rs, crates/cm-db/src/repo/mod.rs,
    crates/cm-runtime/src/lib.rs — module decls stripped

sqlx cache: regenerated against post-migration schema
  (71 files changed, ~+70 / -8896 net)

Test/build: SQLX_OFFLINE=true cargo check --workspace clean;
cargo test --workspace --no-run clean.

Follow-up (task #21): World view lost the in-flight-work landmarks
when repo:{topic} / loop:{id} orbs disappeared. Add mission:{id}
orbs as the missions-era replacement.
2026-07-19 18:37:24 -07:00
Omar SobhandClaude Opus 4.7 657b666219 mcp door: extend service-session bearer to per-topic + per-loop spawns
ci / gates (push) Successful in 5s
ci / rust (push) Failing after 9s
ci / frontend (push) Successful in 27s
ci / e2e (push) Skipped
ci / publish (push) Skipped
Per-team runtimes had their MCP bearer swap wired in the prior slice,
but per-topic (research_container::spawn) and per-loop (spawn_loop)
containers still baked the stale template bearer and 401'd every
tools/list. Same fix, extended: mint a workspace-owner service session
via runtime_provision::mint_workspace_service_token and inject via
prewrite_daemon_config_with_risk.

Move mint_workspace_service_token from topology_worker into
runtime_provision so all three spawn call sites share the helper.

Callers updated: routes/research.rs (start_topic), routes/research_setup.rs
(prepare_topic_runtime), routes/loops.rs (ensure_loop_container).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-07-18 16:14:38 -07:00
Omar Sobh 8cd0c7bd01 runtime_provision: migrate provider_alias_for to v0.8.3 families
ci / gates (push) Successful in 16s
ci / frontend (push) Successful in 39s
ci / rust (push) Successful in 3m14s
ci / e2e (push) Skipped
ci / publish (push) Successful in 2m20s
Auto-provision (and every other build_team caller) hit
'dangling_reference: claude_cli is not a known provider family'
because provider_alias_for still returned v0.7.x aliases —
claude_cli.default / claude_cli.glm / claude_cli.glm5 /
kimi_cli.default — all deleted upstream when providers.models
schema was restructured.

Now the mapping resolves to real configured aliases:
- 'claude'* prefix → anthropic.default
- 'gemini'* prefix → gemini.default
- 'llama'* / 'groq' → groq.default
- glm* + kimi* → anthropic.default (fallback until glm.default /
  moonshot.default provider tables land in the runtime template)
- unknown → anthropic.default

Covers the model picker's full roster (claude-sonnet-5 / opus-4-8 /
haiku-4-5 / sonnet-4-6 / glm-4.6 / glm-5.2 / kimi-k2 /
gemini-2.0-flash / llama-3.3-70b-versatile) plus every legacy
shorthand.

Tests updated to assert the new mappings including the model
picker's ids.
2026-07-17 21:39:26 -07:00
Omar Sobh ebb5b5780b chore: cargo fmt --all — clean up a2a merge's fmt violations
ci / gates (push) Successful in 7s
ci / rust (push) Failing after 49s
ci / frontend (push) Successful in 52s
ci / publish (push) Successful in 3m6s
ci / e2e (push) Has been skipped
The a2a merge (d0d8e7f) landed with a handful of pre-existing rustfmt
diffs that were failing `cargo fmt --all --check` in CI. Pure whitespace
reformatting from `cargo fmt --all`; no semantic changes. Files touched:
mcp_door.rs, quota.rs, routes/a2a.rs, routes/world.rs, runtime_provision.rs,
chat_repos.rs test, and tools/chat.rs.
2026-07-05 18:54:15 -07:00
Omar SobhandClaude Opus 4.8 cbfa0ff24f feat: agent-to-agent platform on ZeroClaw 0.8.2 — rooms, delegation, A2A ingress
Builds on the v0.8.2 runtime. Four workstreams, all behind the §15 MCP door:

- Group rooms (Phase 1): migration 0026; N-way threads repo with a DM/room
  count-guard; chat.send {room} + room.create/invite/leave tools; RoomMessage
  -> room.message SSE; /api/claw-chat/rooms* APIs; Observer room badge.
- Per-claw door identity: door caller_agent resolves the X-ZeroClaw-Agent
  header (set by the fork) to the specific claw, falling back to roster[0].
- Gated delegation bridge (Phase 3): clawmates__delegate door tool drives a
  sibling via the existing /ws/chat ZeroClawDriveExecutor (not A2A); self-deny,
  per-workspace hourly budget, audit trail, untrusted-banner result. Native
  in-daemon delegation stays off (it would bypass the door).
- A2A tenant ingress (Phase 2): migration 0027 (workspace_a2a + a2a_tokens);
  runtime_provision enable_a2a_server/publish_claw; routes/a2a.rs tenant-aware
  proxy (per-workspace tokens, injected internal bearer, daemon stays internal,
  cards URL-rewritten to the cm-api edge); a2a.invoked taxonomy.

Tests: cm-db room repos, cm-runtime chat tools, door units. sqlx cache updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-28 16:11:01 -07:00
Omar SobhandClaude Opus 4.8 8123a27bcf Teams (deploy ladder rung 1): schema + provisioning + API
A team = a baseline topology staffed with real claws. Migration 0010 (teams +
team_members node→claw bindings) + cm-db repo/teams.rs. runtime_provision.rs
turns a claw into a live runtime agent claw_<id> via the synced gateway config
API (#7468): create agent + bind model_provider (mapped from chosen model) +
risk_profile=toolfree + clawmates_door bundle — atomic, immediately drivable.

routes/teams.rs: POST /api/teams (create claws + provision + build(kind,roles)
+ bind node.attrs["agent"]=claw_<id> + persist), GET /api/teams[/{id}],
POST /api/teams/{id}/run (enqueue a durable run of the team graph — reuses the
topology worker + SSE). v1 persona = topology role via the prompt builder; the
claw's system_prompt stays its chat identity.

Spike confirmed: runtime agent provisioning works; IDENTITY.md persona works
for API models (Gemini/Groq), masked by CLI models (Claude/Kimi Code). 16
cm-api tests + provision unit tests pass, clippy clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-18 13:13:14 -07:00