Commit Graph
7 Commits
Author SHA1 Message Date
Omar SobhandClaude Opus 5 ceec0423ad feat(teams): staff research phases with a research team
`research_only` is repo-less, one research phase, "produce a markdown
artifact" — and it defaulted to `rust_sdlc`. So it was staffed with a
planner, a coder, a tester, a reviewer and a committer, four of whom had
nothing to do, each carrying the code-and-commit skills its role is bound
to. Measured 2026-08-21: 9 distinct skills across 5 role prompts, ~50KB,
one applicable. That is what "most skills score not_applicable" in the
Skill-Use baseline has been measuring all along — the skills were
correctly bound to their roles; the roles were wrong for the workflow.

None of the three existing research templates fit, so this adds
`topic_research`: frame the brief into answerable questions, gather
evidence with the URL and the quoted passage, check every claim against
its source, write the report. Three roles, four skills, each checked
against its own `when_to_use` before binding — and two obvious candidates
deliberately NOT bound, because `executive-summary-writing` tells the
writer to discard any item not tied to a named project and
`signal-to-noise-ranking` scores relevance the same way. On a standalone
topic report that discards the deliverable.

`default_phase_teams` lets a recipe staff each phase PURPOSE separately,
resolved into `config.phase_teams` at create. A multi-phase recipe does
not have one job: `research_and_code`'s research phase spends a paragraph
of `task` telling its team not to change source files, because
`rust_sdlc` gave that phase a coder and a committer and they did what
coders do — mission 01a00c57 shipped both INT items during RESEARCH and
the coding phase then delivered +0/-0. Prose was the only lever
available; staffing is the actual one.

Also fixed in the three existing research templates, all verified rather
than inferred:

  - `papers_research` bound `arxiv-daily` to its DOMAIN SCOUT. That
    skill's entire content is "Do not search arXiv yourself — the harvest
    already ran", and its `when_to_use` names Continuous Research
    missions, which are the only ones the platform writes a harvest
    manifest for. The role whose job is searching was bound a skill
    forbidding it.
  - Its PAPER READER was told to "fetch the PDF, extract text". The
    runtime image has no pdftotext, no mutool and no pypdf — checked in
    the container. Every paper would have hit the `[read: abstract only]`
    fallback, which reads identically to the fallback working as designed.
  - `insight_research` cross-referenced "our repos'" history. A mission
    binds ONE repo (`missions.repo_id`).
  - `codebase_research` wrote to "the Obsidian vault"; no vault is
    mounted, and both it and `papers_research` were committing in "PRs",
    which the platform does not open.

And `research_only` itself had neither `task` nor `done_when` — the same
defect `benchmark`, `security_hardening` and `research_and_code` were each
fixed for, and it was left out. A phase with no `done_when` is never
judged. It also still asked for `pdf`, a format nothing generates.

Two new guards, both negative-controlled: every team a recipe names must
exist (a typo currently only logs, and the mission is staffed by the
fallback crew looking deliberate), and every `default_phase_teams` key
must be a purpose `purposes_for` actually emits.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018i9Ten1LU4jUr5d7TAWda9
2026-08-21 09:35:33 -07:00
Omar SobhandClaude Opus 5 b5032a732a fix(phase_runner): collect the agent's work BEFORE judging it
deploy / test (push) Successful in 4m24s
deploy / build (push) Successful in 5m15s
`Sandbox::for_mission` builds the judge's verification copy from the HOST
checkout. In copy mode the agents write inside the container, and their work
only reached the host when `sync_out` ran — in the capture sweep, AFTER the
phase closed. So every phase was judged against a tree that did not yet contain
the pass being judged, and the judge truthfully reported nothing there.

Mission 01a00cfa is the proof. Research pass 2 wrote a 434-line
IMPLEMENTATION_BRIEF.md, `cargo test` passed, and it was pushed to a clean
branch (clawmates/mission-01a00cfa-c69f39fd-i2 at 563cdd21). Its verdict:

    failed after 2 pass(es) — met=false — research/IMPLEMENTATION_BRIEF.md
    does not exist anywhere

logged one line BEFORE `captured (+434/-0 across 1 file(s))`. A phase that
succeeded was failed because the evidence had not been collected yet.

This hid because it only bites a phase judged on its OWN pass. The v2 coding
verdict cited real commits (339a5bd, 167671f) — research had already synced
that work to the host in an earlier phase.

`evaluate_finished_phases` now runs `sync_out` first, and on failure leaves the
phase `evaluating` for the next sweep rather than recording a verdict nobody
could stand behind — the same policy the capture sweep already applies, for the
same reason. microVM keeps its carve-out: `microvm_executor` collects out of
the guest over this same path before the VM is destroyed.

Research goes to 3 passes. On 01a00cfa it got no real attempts out of two: one
spent on a fabricated commit claim the judge correctly rejected, one on this
bug.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-16 17:09:05 -07:00
Omar SobhandClaude Opus 5 a582dea4fc feat(workflow): research plans, coding builds — the split was a fiction
deploy / test (push) Successful in 4m1s
deploy / build (push) Successful in 1m36s
`rust_sdlc` gives the research team coding roles and a writable /mission/repo,
so research implemented what it found and the coding phase then opened a clean
tree, produced +0/-0 and failed on the empty-delivery rule. Mission 01a00c57
ended exactly that way: research shipped both INT items itself (+276/-57),
coding delivered nothing.

Worse than the wasted phase is WHERE the code landed. Research ran under a gate
that does not check tests, so its two source changes reached a branch with
`tests_status: null` — never compiled by the gate, never run. Keeping
implementation in the coding phase is what puts it behind `on_green_tests`.

Research now carries a `task` that scopes it to the brief and says plainly that
editing crates/ is not its job this phase, plus a `done_when` describing what
the brief must CONTAIN. The no-source-edits constraint deliberately lives in
the prose and NOT in `done_when`: "and nothing else" phrasings measurably make
a judge invent requirements it was never given.

Coding gets the counterpart `task`: implement the brief's items, one commit
each, tests green. Stated explicitly because a phase that finds a clean tree
and no instructions has historically written a REPORT about the work instead of
doing it — four documentation commits and one implementation, on the run that
became the haiku baseline branch.

Research also gets `commit_policy = "on_green_tests"` as a safety net, so
source it writes anyway still has to pass the suite.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-16 16:48:05 -07:00
Omar SobhandClaude Opus 5 53da4d7e6d fix(runtime): a mission could not build the repo it was given
deploy / test (push) Successful in 4m20s
deploy / build (push) Successful in 5m21s
`clawmates-runtime` shipped with `gcc` and `make` but no `cmake`, no `g++` and
no `python3-dev`. Measured on clawhdf5, three probes:

  no cmake        → "is `cmake` not installed?"        exit 101 after 13s
  no python3-dev  → "cannot find -lpython3.11"          exit 101 at link
  with both       → cargo test PASSES                   exit 0 after 69s

This is not only the delivery gate. The AGENTS run in this image, so a coding
phase was writing Rust it had no way to compile or test — which reframes the
last run's 11 agent commits as unverifiable by construction.

`images/agent-toolchain/Dockerfile` (the microVM path) has had `cmake
build-essential` all along, and its own header warns about precisely this:
"if `cargo` is present in one image and absent in another, the same mission
passes or fails depending on which backend it landed on, and nothing says why."
Both images now install the same set — it was missing `python3-dev` too.

`images/runtime-toolchain.Dockerfile` is a thin local overlay so the laptop can
run today without recompiling zeroclaw from the fork; it is meant to be deleted
once a runtime image built from the corrected deploy/ Dockerfile is published.

Also: a build failure is no longer reported as a red suite. Both are cargo exit
101, and `verify_tests` mapped every non-zero to `Failed(code)` — so a missing
toolchain was recorded as the USER's tests failing. It now returns
`CouldNotRun` with the reason when the output shows a compile or link failure.
Deliberately narrow: a failing `assert!` still reads as red, because letting
broken code past `on_green_tests` is the expensive direction to be wrong in.
Both directions are pinned by tests built from today's two real samples.

And the coding phase finally has a loop: `research_and_code.toml` declared
`loop = "until_no_more_int_items"`, which `phase_config.rs` lists as
DECLARED_BUT_UNREAD. Iteration is driven by `max_iterations` + `done_when`, and
with `max_iterations = 1` and no `done_when` the phase ran ONCE and was never
judged — reporting `completed` whatever it produced. Now 3 passes against a
stated goal, wording per the measured rule (say what the tree must CONTAIN).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-16 11:02:07 -07:00
Omar SobhandClaude Opus 5 49bcf53b84 feat(missions): wire the workflow registry so phase config reaches the database
workflow_registry.rs had zero call sites -- lib.rs declared the module and
nothing ever called load() or get(). So templates/workflows/*.toml was never
read, and because the client's TEMPLATE_PRESETS carries only {kind, order_idx}
with no config, PhaseSpec.config defaulted to Value::Null and every
wizard-created mission stored a null mission_phases.config.

Every per-phase setting was therefore inert. `loop = "until_no_more_int_items"`
and `commit_policy = "on_green_tests"` described a scheduler that does not
exist AND had no path to the database. benchmark_runner and security_scan
already read phase_config(); they were reading from null.

- Mission create derives phases from the recipe when none are sent, and
  backfills config per phase (matched on kind+order_idx, then kind) when the
  caller sends shape without config. An explicit config always wins.
- phases_for_create takes Option<&WorkflowRecipe> rather than reaching for the
  global, because the registry resolves its directory relative to the process
  cwd -- which under cargo test is the crate root, not the repo root.
- GET /api/workflows serves the catalog; the wizard fetches it and falls back
  to TEMPLATE_PRESETS. Adding a TOML now adds a template with no FE change.
- load() runs at boot so a malformed recipe appears in the boot log instead of
  silently producing a mission with no phase config.

Also fixes a latent bug in all five recipes: `default_team_template` was
written below the first [[phases]] block, and TOML scopes a bare key after a
table header INTO that table -- so it parsed as
phases[last].config.default_team_template and the real field was always None.
Invisible while the registry was dead code. Moved above the phases, with a
test asserting it neither returns None nor leaks into a phase config.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-30 12:43:32 -07:00
Omar SobhandClaude Opus 5 285d0c82f2 chore: delete dead scaffolding and stop fabricating claw capability cards
Tier 0 of the prompt-ablation pass -- subtraction only, none of this
reached a model.

- cm-brain: drop ClawBrain::export_markdown (zero callers).
- workflows: drop the `task_preamble` keys. No Rust code ever read them --
  WorkflowPhase.config is an opaque serde_json::Value -- so the comment
  calling the preamble "the belt, the skill the suspenders" described a belt
  that was never implemented. (`commit_policy` is unread for the same reason;
  left in place as documentation pending a decision.)
- mcp_door: derive the unknown-tool error from EXPOSED_TOOLS. The literal had
  drifted to naming one of the three tools the door exposes.
- Dashboard.tsx: drop TEAM_TEMPLATES/COMPANY_TEMPLATES, defined and never
  referenced, and disconnected from the real templates/teams/*.toml.

The substantive one: GET /api/claws/{id}/compartments returned hardcoded
strings for tools/capabilities/safety, identical for every claw. Every card
read "Network: none" and "Shell . blocked" regardless of the claw's real
risk_profile -- which is the actual capability boundary, so the card was
most wrong exactly where it mattered, on a coding_readwrite claw that does
have shell. Now derived from the claw's effective risk_profile (its team's
setting, else the same role-derived default the provisioner applies), with
the allowlists mirroring [risk_profiles.*] in the runtime config.

Note: cm-topology/src/heuristics.rs was slated for deletion here as unused.
It is not -- routes/topology.rs:43 serves it and p0_endpoints.rs:302 asserts
it. Left alone.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-30 10:44:33 -07:00
Omar SobhandClaude Opus 4.7 565f6cae65 slice 4: 5 workflow templates as TOML recipes + mission-launch orchestrator
ci / gates (push) Successful in 4s
ci / frontend (push) Successful in 26s
ci / rust (push) Successful in 4m20s
ci / e2e (push) Skipped
ci / publish (push) Successful in 3m50s
Two things land together:

1. Ships the 5 workflow recipes as TOML files under
   templates/workflows/*.toml:
     - research_only          (hub_spoke research → MD + PDF)
     - research_and_code      (research → coding loop until INT-XX drained)
     - security_hardening     (scan → research patches → coding with
                               reviewer approval + full MCP bundle)
     - refactor               (single-pass coding with dep audit
                               preamble + before/after benchmarks)
     - benchmark              (author + baseline benchmarks per stack)
   Each declares phases[], per-phase config, default_team_template.
   Loaded read-only into an in-memory registry (workflow_registry)
   via OnceLock — no DB row per recipe.

2. Ships the mission-launch orchestrator that closes the loop from
   Slice 3.5d's mechanics. When a mission transitions draft→running,
   `mission_orchestrator::on_launch`:
     - Reads mission.team_template_id (skips if unset)
     - Loads the team template detail (roles + skills bindings)
     - Builds a topology graph from role slots via cm_topology::build
     - Inserts the teams row + stamps template_id/version/risk_profile/mcp_bundles
     - For each role: agent insert, model binding, runtime provision
       (opt-in via RuntimeProvisioner::from_env), brain_seed::ingest
       (Slice 3.5d), agent_template_link::upsert (Slice 3.5d),
       team_members bind, audit trail
     - UPDATE missions SET team_id = ...
   Wired into routes::missions::set_status when prior.status='draft'
   and new='running'. Failures log + are non-fatal (mission still
   flips to running so the user can inspect + retry).

With this, Slice 3.5d's brain-seed + link machinery actually gets
populated, and the MCP skills server's template-defaults-merge path
(Slice 3.5b/d) starts serving real bindings to real agents.

Follow-ups (Slice 5-8):
  - Task-card parser watches run events for TASK/COMPLETED markers
    → mission_tasks rows
  - PDF renderer worker turns MD artifacts into PDFs
  - Before/after benchmark runner honors phases[].config.benchmark
  - Security scan MCP bundle exposes cargo-audit/gitleaks/trivy/semgrep
  - Level-up endpoints diff learned-vs-seeded via agent_template_link

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-07-19 14:34:26 -07:00