Commit Graph
12 Commits
Author SHA1 Message Date
Omar SobhandClaude Opus 5 eb120a10dd perf(image): drop chromium from the server image — 875 MB to 212 MB
deploy / test (push) Successful in 4m0s
deploy / build (push) Successful in 1m41s
Chromium and fonts-liberation were 758 MB of an 875 MB image: 87% of the server
image was a browser it never launched.

It was installed for the Slice 6 mission PDF renderer, which no longer exists —
every call site passes `render_pdf: false` because markdown is the deliverable —
and NOTHING in the workspace reads the CHROMIUM_BIN this image set. The only
Chromium the platform actually uses is `browser.goto`, which runs it inside the
agent's dedicated egress-enabled BROWSER container
(cm-runtime/src/tools/browser.rs), never in the server.

Measured on gw-04: 875 MB -> 212 MB. The remainder is debian-slim (75 MB), git
and its dependencies (~95 MB) and the server binary (42 MB). git stays: research
topic clones shell out to it, which is why this image left distroless in the
first place.

Verified in the slimmed image: git 2.39.5 present, CA bundle present, chromium
absent, binary executable, templates and all 8 skills shipped.

That 663 MB was paid on every deploy, every registry push, and every air-gapped
bundle.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-13 21:24:01 -07:00
Omar SobhandClaude Opus 4.8 11e1379c5f fix(build): normalize /etc/clawmates seed-dir perms for the nonroot user
The server COPYs templates/ and skills/ then drops to USER 65532. When the
build context arrives with mode-700 dirs (e.g. rsync -a preserving a dev's
local perms), COPY bakes 700 into the image and the nonroot runtime user
can't read them — the skills/team-template builtin seed silently skips
("Permission denied (os error 13)"). chmod -R a+rX after the COPYs makes
the seed dirs readable regardless of source perms.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-28 09:07:42 +02:00
Omar Sobh a1d1097b52 ci + ops: cargo-build retry wrapper + runtime systemd unit
ci / rust (push) Successful in 4m27s
ci / e2e (push) Skipped
ci / gates (push) Successful in 5s
ci / frontend (push) Successful in 26s
ci / publish (push) Successful in 3m39s
Two durability fixes closing recurring flakes:

CI flake wrapper (broker + server Dockerfiles):
  Wrapped the cargo build step in a 3-attempt retry loop with
  linear backoff (10s / 20s). Directly targets the crates.io
  transient network errors that keep hitting CI on the runners
  ('curl failed: SSL_ERROR_SYSCALL, errno 0'). Each build only
  loses time on transient failures; a real compile error still
  fails all 3 attempts and surfaces the last error normally.

Runtime systemd unit (deploy/clawmates-runtime/):
  Replaces the manual 'docker run' that had been starting the
  ZeroClaw runtime with no persistence for its network topology.
  Ephemeral prod fixes at 09:30 PDT 2026-07-21 (task #38) were:
    - anthropic.default provider block added to
      /root/clawmates-runtime/data/.zeroclaw/config.toml (already
      durable — bind-mounted from host)
    - docker network connect clawmates_edge clawmates-runtime
      (NOT durable — vanishes on container recreate)
  New systemd unit clawmates-runtime.service (installed +
  enabled on gw-04):
    - ExecStart docker-runs the container attached to
      clawmates_core, then connects clawmates_edge in the same
      shell command, then docker waits.
    - Bind-mounts both /root/clawmates-runtime/data and
      /var/lib/clawmates-missions (for security_scan +
      benchmark_runner).
    - --rm so upgrading is just docker pull + systemctl restart.
    - Restart=on-failure with 5s backoff.

Closes task #38 and preemptively closes the CI flake pattern.
2026-07-21 12:53:30 -07:00
Omar SobhandClaude Opus 4.7 3ac3d53da7 slice 6: LLM + Chromium PDF renderer worker
ci / gates (push) Successful in 6s
ci / frontend (push) Successful in 38s
ci / rust (push) Successful in 3m28s
ci / e2e (push) Skipped
ci / publish (push) Successful in 3m4s
Watches mission_artifacts for MD entries with render_pdf_status='pending'
and turns them into styled PDFs via:
  1. Read source MD from <mission_root>/<path>
  2. Call configured LLM (default gemini-2.5-flash) with a document-
     typesetter system prompt that constrains style to a self-contained
     HTML doc with inline CSS + our color palette
  3. Print to PDF via `chromium --headless=new --print-to-pdf`
  4. Save alongside source MD (foo.md → foo.pdf) + update
     mission_artifacts.rendered_pdf_path + render_pdf_status='done'

Graceful degradation: GEMINI_API_KEY unset OR chromium missing =
row marked failed with a descriptive error, worker keeps ticking.
The frontend's "Open PDF" affordance (Slice 2) light up automatically
when render succeeds.

Boot ordering: PDF worker spawns after task_card_worker. Poll every
30s over up to MAX_PARALLEL=2 rows at a time — respects LLM rate
limits and keeps chromium's peak RAM under control.

Env knobs:
  GEMINI_API_KEY                    — required for LLM step
  CLAWMATES_PDF_RENDERER_MODEL      — model id, default gemini-2.5-flash
  CHROMIUM_BIN                      — chromium binary, default `chromium`
  CLAWMATES_MISSIONS_ROOT           — artifact dir root, default /var/lib/clawmates-missions

Dockerfile now installs chromium + fonts-liberation and sets
CHROMIUM_BIN=/usr/bin/chromium so the container image has everything
the renderer needs.

Also bumps workspace tokio deps to include the `process` feature
(required for tokio::process::Command).

Follow-ups:
  - Anthropic + OpenAI provider variants (only Gemini in this slice)
  - SSE stream on /api/missions/{id}/artifacts for the "PDF ready"
    notification instead of poll-via-mission-GET
  - Per-template PDF style overrides (currently one house style
    for all missions)

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-07-19 15:16:57 -07:00
Omar SobhandClaude Opus 4.7 7b23f61632 slice 3.5c: seed 15 built-in skills across the 6 stacks
ci / frontend (push) Successful in 25s
ci / gates (push) Successful in 4s
ci / rust (push) Failing after 3m41s
ci / e2e (push) Skipped
ci / publish (push) Skipped
Hand-authored skill catalog anchored to real 2026-07 versions:
  - Rust 1.97.1 (stable), edition 2024
  - React 19.2.7, Server Components + Actions
  - TailwindCSS 4.3.3 (CSS-first config, Oxide engine)
  - three.js r185 (WebGPURenderer stable, BatchedMesh matured)
  - React Native 0.86 / Expo SDK 54+ (New Architecture default)
  - cargo-nextest 0.9.140, gitleaks 8.20+, cargo-audit 0.21+
  - Postgres 17 (18 in beta, don't rely on)
  - CUDA Blackwell, Metal Apple7+, ROCm CDNA3

Ships 15 skills across the categories:
  foundation/  workspace-repo-commit-protocol
               small-focused-commits
               tdd-red-green-refactor
               code-review-checklist
               int-xx-marker-protocol
               decompose-int-items
  rust/        write-rust-current-edition
               rust-error-handling
               cargo-test-driven-development
               rust-async-tokio-idioms
  backend/     postgres-migrations-forward-only
               postgres-index-selection
               api-pagination-day-1
  frontend/    react-19-server-components
               tailwind-v4-idioms
               component-4-state-model
  mobile/      expo-managed-vs-bare
               rn-flashlist-perf
  gpu/         gpu-coalescing-and-occupancy
               roofline-model
  threejs/     threejs-perf-and-teardown
  security/    cargo-audit-workflow
               secret-scanning-gitleaks

skills_loader.rs walks skills/**/*.md, parses YAML frontmatter
(name, description, when_to_use, tags), upserts via
skills_catalog::upsert_builtin. Idempotent per boot — bumps version
+ appends skill_versions row ONLY when body changes. Deterministic
sha256-derived ids so builtins are stable across boots.

Dockerfile copies skills/ to /etc/clawmates/skills. Server boot
task spawns loader alongside team_template_loader.

Follow-ups (Slice 3.5c continuation, future PRs):
  - 20-30 more skills (duckdb, shadcn composition, a11y, WebGPU
    migration, metal frame capture, rocprof, deep gitea forge
    integration, semgrep rulepacks)
  - Bind skills to team template roles (add [role.skills] refs to
    templates/teams/*.toml + wire template_role_skills population
    in team_template_loader)

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-07-19 13:55:44 -07:00
Omar SobhandClaude Opus 4.7 9ba5c06a1a slice 3: 6 team templates seeded from TOML recipes
ci / rust (push) Failing after 11s
ci / gates (push) Successful in 6s
ci / frontend (push) Successful in 28s
ci / e2e (push) Skipped
ci / publish (push) Skipped
Team templates are the canonical rosters + tool bundles that mint
concrete teams for a mission. Every builtin ships as a TOML recipe
under templates/teams/*.toml, loaded into the DB at server boot.

Migration 0048 adds:
  - team_templates    (id, key, name, stack, default_topology,
                       risk_profile, mcp_bundles, version, source,
                       workspace_id)
  - template_roles    (m2m: template_id + slot; system_prompt,
                       skills[], brain_seed)
  - teams gets template_id + template_version for level-up lineage

Ships 6 builtins:
  - rust_sdlc  — planner/coder/tester/reviewer/committer for Rust
  - backend    — api_designer/db_engineer/coder/tester/committer
                 (Postgres, DuckDB, graph DBs, wire protocols)
  - frontend   — designer/coder/tester/committer (React + Tailwind + ShadCN)
  - mobile     — designer/coder/tester/committer (Expo, RN, iOS, Android)
  - gpu        — arch_analyst/kernel_author/bench_engineer/coder/committer
                 (CUDA, Metal, ROCm from Rust)
  - threejs    — scene_designer/coder/shader_author/perf_engineer/
                 committer (three.js, WebGL, WebGPU)

Each role has a versioned system_prompt + skill list + brain_seed
markdown. Skills column is a name array today; Slice 3.5a promotes it
to a typed m2m join with the real skills catalog.

Server boot:
  - team_template_loader::load_builtins reads TOML from
    /etc/clawmates/templates/teams (container) or templates/teams (dev),
    upserts idempotently. Deterministic uuid per template key (sha256
    of a fixed namespace + key) so ids are stable across boots.
  - Dockerfile copies templates/ to /etc/clawmates/templates.

Read API:
  - GET /api/team-templates       — list all
  - GET /api/team-templates/{id}  — detail with roles

Wizard:
  - Step 3 rewired from a raw team_id text field to a template picker
    with "LLM auto-provision" as the default option + one card per
    builtin, showing stack, topology, risk profile, and description.
  - Mission create now passes team_template_id (not team_id) so phase
    execution knows which template to mint from.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-07-19 12:41:15 -07:00
Omar Sobh 8417f6e65c server-image: switch base to debian:12-slim + install git
ci / gates (push) Successful in 5s
ci / frontend (push) Successful in 26s
ci / rust (push) Successful in 4m3s
ci / e2e (push) Has been skipped
ci / publish (push) Successful in 2m46s
Distroless static-debian12 has no git binary, so
routes/research_setup::ensure_repo_workspace's `tokio::process::Command::new("git")`
returned "No such file or directory" for every wizard-materialized
research topic. Silent failure — the topic's repo_workspace_path
stayed NULL, prepare_topic_runtime bailed out, the run was enqueued
against the shared workspace-wide gateway which then 401'd or timed
out on cold auth.

Switching to debian:12-slim + apt-installing git + ca-certificates
(needed by clone-over-https). Same UID 65532 as before so bind-mount
hosts don't need re-chown.

Image size grows from ~40MB to ~80-100MB but this is the correct
base for a service that shells out to git. Static distroless was a
premature optimization once the server's job description grew a
"clone repos" responsibility.

Follow-up: research migrating to the `gix` pure-Rust crate so we can
go back to distroless. Nontrivial refactor of ensure_repo_workspace
so not attempted in this fix.
2026-07-10 11:23:55 -07:00
Omar Sobh 4b66930796 image(server): install musl target after rust-toolchain.toml, matching broker
ci / frontend (push) Successful in 24s
ci / gates (push) Successful in 1m53s
ci / publish (push) Successful in 2m12s
ci / rust (push) Failing after 4m44s
ci / e2e (push) Has been skipped
Same fix pattern that unblocked broker in 534eb72. The `rustup target add`
was landing on the base image's default toolchain, but rust-toolchain.toml
(channel = 1.96.0) can prompt rustup to resolve to a distinct pinned
toolchain the target hasn't been installed on. Move the target install
after the COPY so it lands on the toolchain cargo actually uses.
2026-07-05 16:19:42 -07:00
Omar SobhandClaude Opus 4.8 34f744734b Large World graph, agent platform, brain stack & dashboard rebuild
Frontend
- Large World: collapse org/company/team tiers into one expandable React Flow
  hierarchy (WorldFlow) with per-click expand, persisted node positions, a
  compact tree sidebar, wrench multi-select delete across levels, and a sized
  right slide-out (phone/tablet/full) showing an agent summary + drill button.
- Agent page: GitHub-style animated contribution grid (VitalsCard), collapsible
  System Prompt + Personality cards, restructured anatomy cards, bigger avatar
  with name/title header row, Markdown/JSON-aware rendering, brain registry +
  history, avatar generate/upload.
- User-icon menu (Infrastructure/Brains/Tools/Profile/Credits) + ToolPanel;
  Master Planner deploy wizard (Specialists/Swarm/Scheduled/Triggered);
  Team Runs view; reap-progress modal; dashboard is the single live interface.

Backend
- cm-brain crate (.brain as the agent definition) + brain apply/history.
- Hard-purge reap (FK-ordered) + sandbox release + SSE batch-delete.
- Swarm self-verifying loop, mode-aware planner, web.search tool, webhooks
  (migration 0013), org/company/team delete endpoints, scheduler sweeps.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-22 23:21:54 -07:00
Omar SobhandClaude Fable 5 add4f79fed Rebrand: TeamClaw -> Clawmates (clawmates.work)
Full-depth rename per the approved plan; the 'claw' product vocabulary
(claws, /claws routes, clawId, Claw Chat) stays — it is now the brand.

- Display brand: Clawmates (manifest, titles, hero, login/rail logo
  'clawmates'); default host app.clawmates.work; registry
  ghcr.io/clawmates
- Crates tc-* -> cm-* (16 crates + all imports); binaries
  clawmates-server/broker/bundler; images clawmates/*; env prefix
  CLAWMATES_* (+ CM_TEST_DATABASE_URL / CM_LIVE_LLM); config
  clawmates.toml; helm chart deploy/helm/clawmates with clawmates-*
  resources; db names clawmates*; sockets /run/clawmates; cookie
  cm_session; kind cluster clawmates-test; seccomp node profile
  clawmates-agent-profile.json
- All 9 Playwright brand assertions updated in lockstep; historical
  spec document left untouched as the only remaining 'TeamClaw'
- Local env migrated: dev pg clawmates-dev-pg/clawmates_dev, shared
  test server clawmates-test-pg, kind cluster recreated with image +
  profile, compose images rebuilt under clawmates/*

Verified end to end: 161 Rust + 68 frontend tests, 29 Playwright
journeys, 4 live kind tests, helm/install/LOC/placeholder gates, and
the clean-room install rehearsal serving the clawmates login page from
a signed bundle of the rebuilt images.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 12:31:25 -05:00
Omar SobhandClaude Fable 5 8046853feb Post-1.0: OTLP tracing, broker image + compose service, install rehearsal
- tc-telemetry: fmt subscriber always; with [telemetry] otlp_endpoint
  set, spans batch-export over OTLP/HTTP. Tested against a REAL OTLP
  receiver decoding the actual protobuf (official proto types): the
  emitted span and service.name arrive on the wire. No endpoint = no
  export = no network (air-gap stance). tower-http TraceLayer gives
  every API request a span
- The broker finally has its own image (images/broker.Dockerfile,
  9.5MB from scratch) — the Helm chart referenced one that never
  existed — and the compose deployment now RUNS the broker, sharing a
  socket volume with the server (the unix-socket equivalent of the K8s
  sidecar). Compose secret flows were silently dead before this
- server.Dockerfile fixes surfaced by the rehearsal: the workspace
  build needs tools/ (bundler joined the workspace) and
  images/seccomp/ (include_str! profile) in the build context
- scripts/rehearse-install.sh (plan: clean-VM rehearsal): assembles a
  REAL signed bundle from the built images (server/frontend/broker/
  postgres/socket-proxy), runs the customer path — offline verify,
  docker load, compose up — and asserts /healthz plus the served login
  page before teardown. Passing locally; wired as a release.yml step,
  which also builds/ships the broker + socket-proxy images now

161 Rust tests + 29 journeys; clean-room rehearsal green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 11:35:32 -05:00
Omar SobhandClaude Fable 5 fc173f170d P0 exit: e2e harness, Playwright shell journeys green, deploy skeleton
- teamclaw-server e2e mode (TEAMCLAW_MODE=e2e): idempotent deterministic
  seed through the real registration paths
- Playwright suite (6 journeys) against the real backend + prod Next build:
  login redirect, bad-password error, shell/roster/online-dot, team members,
  seeded credits, sign-out revocation — P0 exit criterion met
- Dockerfiles: musl-static server -> distroless, Next standalone -> distroless
  node (multi-arch via TARGETARCH)
- Air-gapped compose topology with edge/core/sandbox_net/secrets_net
  segmentation (engine-validated in CI), config-file + env-overlay pattern
- CI: compose validation + e2e job with trace upload

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-09 22:48:28 -05:00