Commit Graph
45 Commits
Author SHA1 Message Date
Omar SobhandClaude Opus 5 fe45f72f09 feat(podcast): a PODCAST tier, a topics field, and a feed a phone can actually reach
deploy / test (push) Successful in 4m28s
deploy / build (push) Successful in 6m25s
Three gaps between "the pipeline works" and "you can use it".

**1. Topics could not be set.** The wizard never sent `config.topics`, so every
mission created through the UI silently fell back to
`library::default_topics()` — a hardcoded list that is somebody else's research
interests. The card now takes one arXiv search per line, and the description
field says plainly that for this template it IS the brief the agents judge
relevance against.

**2. There was nowhere to see or subscribe.** New PODCAST tier in the left rail,
between AGENT and REPOS: the feed URL with a copy button, the episode list, and
an inline player for checking one at a desk. `GET /api/podcast/episodes` and
`/subscription` back it. The panel also reports how many missions produced no
audio, so a missing day reads as a known gap rather than silence.

**3. The feed 404'd for the only client that will ever request it.** Three
layers each assumed a browser:

  - `resolveBearer` is server-only (`next/headers`), so a client component that
    imported it broke the build outright. The panel now goes through the
    same-origin proxy like every other panel, and the backend mints the feed URL
    because the session lives in an httpOnly cookie JavaScript cannot read.
  - The `/api` proxy demanded a session COOKIE. A podcast app has none and
    carries `?token=` instead — the same shape as the existing `hooks/` prefix,
    which is already exempt for exactly this reason.
  - The local autologin middleware 307'd it to `/auth/autologin`. A podcast app
    follows redirects blindly and would have stored an HTML page as the episode.

Neither exemption weakens auth: the backend still validates the token and
answers 401 to a bad one, verified. `episode_audio` accepts the token from
either the query string or an Authorization header, because the app fetches it
one way and the browser player the other, and refusing either breaks one of the
two ways this is listened to.

`CLAWMATES_PUBLIC_URL` matters and was wrong first: the tailnet root proxies to
a different service on :18789, and this frontend is on :8443. A feed advertising
an unreachable origin syncs silently forever, so `/subscription` returns a
`reachable` flag and the panel warns when it is still localhost.

Verified from a phone's point of view: feed 200 application/rss+xml over the
tailnet, enclosure 200 with 6,739,582 bytes of audio at 421s, bad token 401.

367 tests pass.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-18 11:55:19 -07:00
Omar SobhandClaude Opus 5 022ef98e44 feat(auth): opt-in local auto-login for single-user deployments
deploy / test (push) Successful in 4m51s
deploy / build (push) Successful in 6m33s
Skips the login form and lands on the dashboard. It performs a REAL backend
login — the API still issues and can revoke the session — so this does not
weaken auth; it only removes a form for a deployment with exactly one operator.

Gated on BOTH LOCAL_AUTOLOGIN_EMAIL and LOCAL_AUTOLOGIN_PASSWORD, and refuses
outright in clerk mode. Prod sets neither, so the route 404s there. Two
conditions rather than one flag: a single misread value should not be able to
hand a session to an anonymous visitor.

The route emits a RELATIVE Location — inside the container request.url is the
0.0.0.0:3000 bind, so NextResponse.redirect would send the browser to a host
that only exists in Docker — and the cookie's secure flag keys on
x-forwarded-proto rather than NODE_ENV.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-13 10:47:14 -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 Sobh 821cbb8622 feat(missions): hold every producing phase to delivering, and read markdown instead of PDFs
Two changes the portal review asked for.

1. `benchmark` and `security_hardening` had no delivery guarantee.

`empty_delivery_is_a_failure` tested `kind == "coding"`, on the reasoning that
"research phases legitimately write nothing to the tree" — which the research
directive three modules over contradicts, since it tells the agent to save
findings under /mission/repo/research/. The cost: a `benchmark` mission is ONE
benchmark phase, and with that phase exempt nothing in the platform could fail
it. Same for `security_hardening`, whose first two phases are security_scan and
research.

Now keyed on PRODUCING_KINDS = coding, research, benchmark, security_scan.
`review` stays exempt — a reviewing phase that changes nothing has done its job,
the same distinction `vm_stop_gate::per_node` makes. The test that encoded the
old rule is rewritten rather than deleted, with the reasoning that replaced it.
All 8 harness fixtures are coding phases, so harness behaviour is unchanged.

2. PDFs are dropped; markdown is the deliverable.

Rendering a PDF meant asking an LLM to convert markdown to HTML — a paid API
call per document, on the critical path of "let me read my research", which
failed on depleted Gemini credits and left every artifact unreadable. Styling at
render time is free, offline, instant and cannot 429.

- `mission_outputs` no longer requests a render.
- New `GET /api/missions/{id}/artifacts/{artifact_id}/content`. The frontend had
  no way to READ an artifact at all: it listed paths and offered a PDF preview
  that never rendered (and whose `rendered_pdf_path` had no route serving it).
  Two containment rules, both enforced: the artifact must belong to a mission in
  the caller's workspace, and the CANONICALISED path must stay under `_outputs`
  — canonicalise first, because checking the string before resolving `..` is the
  classic hole.
- `MarkdownBlock` now uses react-markdown + remark-gfm + rehype-slug. It was a
  deliberate zero-dep renderer for "the subset the refiner emits", and that
  subset stopped matching reality: agent briefs are largely GFM pipe tables,
  which it showed as literal pipes. MissionOutputReader and RefineDiffModal use
  the same component and gain tables for free.
- Heading ids come from rehype-slug and `outlineOf` slugs with the same
  GithubSlugger, so the outline rail's anchors still resolve. A test pins that
  invariant, including duplicate headings.

Styles live in globals.css under `.md-view`: the markup is generated so there
are no class hooks, and this project has no styled-jsx registry — the app-router
requirement is documented in next/dist/docs/01-app/02-guides/css-in-js.md, which
frontend/AGENTS.md exists to make me read.

The artifacts tab moved to `MissionArtifacts.tsx`. MissionCanvas was 1341 lines
against a 1250 limit BEFORE this change — already failing lint; it is now 1248.

238 backend lib tests, 20 backend test binaries, 89 frontend tests, clean tsc,
clean eslint on every file touched, production build succeeds.
2026-08-07 12:19:06 -07:00
osobh 1cb643142c research/publish: gate approve+reject on Owner role (#4)
ci / gates (push) Successful in 5s
ci / frontend (push) Successful in 24s
ci / rust (push) Successful in 4m5s
ci / e2e (push) Skipped
ci / publish (push) Successful in 4m32s
2026-07-15 04:28:01 +00:00
Omar SobhandClaude Opus 4.8 e61724ff82 Agent computer: terminal (tmux + drives + tabs), Obsidian vault, UI polish
Terminal app (xterm ⇄ WebSocket ⇄ per-agent themed container):
- zsh + oh-my-zsh + powerlevel10k image (agent-terminal), runs as uid 65532 to
  share read-write ownership of the file-drive volume with the server.
- Interactive PTY in cm-sandbox (bollard exec tty/attach + resize) + a
  TerminalManager; ticket-authed WS bridge routed straight to the backend via a
  Traefik PathRegexp(/ws) rule. MOTD greets the user by name.
- tmux resumable sessions; multi-tab (one tmux session per tab, same container),
  drag-to-reorder, rename, and a Save that persists named tabs to the server
  (terminal_tabs, migration 0014) so they survive logout / a new device.
- Files drives mounted per-agent (subpath) at ~/drives/{documents,received,
  shared}; a reconciler keeps the Files app's index in sync with terminal writes.
  Storage moved to a shared `filedata` volume (CLAWMATES_STORAGE__DATA_DIR).

Obsidian vault (a markdown "second brain" per agent):
- New `vault` FileDrive (migration 0015) mounted into the terminal at ~/obsidian;
  a file-content read route; a purple Obsidian tile + a vault viewer app.

Computer UI:
- Draggable computer-panel width (min = phone preset) keeping the size presets.
- Green Terminal glyph, "Claw Chat" → "Chat", colored gradient-outline app icons.
- Agent page: avatar↔activity-grid spacing + larger, uniform section fonts with
  colored section-tinted tag chips.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-23 16:52:35 -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 Opus 4.8 bd6f48c2b7 Dashboard: integrated post-login screen + service-worker auto-update
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Login landed on an empty "Pick a claw" stub — the integrated dashboard from the
design comp was never assembled as the home. Now `/` IS the dashboard.

- public/sw.js: cache v2→v3; RegisterServiceWorker reloads once when a new
  worker activates, so deploys are picked up without a manual hard-refresh
- (workspace)/layout: ShellChrome renders the dashboard bare on "/" (it's
  self-contained) and the shared TopBar/LeftRail/StatusBar on every other route
- components/dashboard: Dashboard (state machine + data) — top bar w/ breadcrumb,
  ORG/CO/TEAM/CLAW tier rail, tier-aware context list, TopologyCanvas (6-mode
  view-as selector, generalized layouts), and the agent "computer" slide-out
  (cm-fade) wrapping the existing ComputerPanel; status bar
- motion.css: cm-fade keyframe

Wired to existing endpoints (/api/teams|companies|orgs, /api/structure/*,
/api/team/claws, /api/structure/stats, + ComputerPanel's apps/runtime-config/
routines). Defaults to the most-recent team; claw click opens the slide-out.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-19 06:17:19 -07:00
Omar SobhandClaude Opus 4.8 d2354e1f72 Brand assets: node-mesh favicon + PWA icons + manifest palette
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
The token redesign couldn't touch static rasters/config — these were still the
old claw mark + old coral. Regenerate favicon (icon.svg + icon.png) and PWA
icons (192/512) as the node-mesh glyph; manifest theme_color #f96565→#ff6f61,
background #121212→#08080a; refresh the description/tagline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-19 05:16:43 -07:00
Omar SobhandClaude Opus 4.8 540c74f42e Adopt design comps: dark system, new landing/auth, dashboard shell + canvas
Re-skins the whole app to the dark design comps and wires the new surfaces to
the backend (the /api proxy + auth + schemas are unchanged).

Design system:
- globals.css: remapped @theme tokens to the comp palette (#08080a base, coral
  #ff6f61, status cyan/green/amber/purple/teal); token names preserved
- MeshMark: triangle + 3-node brand glyph; cm-flow/cm-blink/cm-halo keyframes
- marketing flipped light → dark

Backend (migration 0012):
- agents.model_binding (persisted on team deploy) + GET /api/claws/{id}/runtime-config
- routine_runs table + scheduler journaling + GET /api/routines/runs
- GET /api/claws/{id}/compartments (anatomy aggregate)
- GET /api/structure/stats (workspace counts)

Frontend:
- Landing: full dark marketing page (hero constellation, deploy ladder,
  12-topology taxonomy, recursive execution, compare/Pareto, safety, self-host)
- Auth: dark split-panel AuthShell + comp LoginForm + Clerk SignIn themed dark
- Dashboard shell: TopBar (breadcrumb + live stats + deploy + user) + StatusBar
  (runner/sandbox/doors); rail slimmed to 60px + 252px context column
- ConstellationCanvas (radial recursive) replaces the graph view in StructureCanvas;
  selecting a claw opens ComputerPanel (apps/now-running/dock); RoutinesPanel
- Claw anatomy view (/claws/[id]/anatomy) from compartments + runtime-config

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-19 04:12:16 -07:00
Omar SobhandClaude Opus 4.8 3eca4ed70c Recursive deploy ladder: Company + Org tiers, mesh mark, two-tier rail
Completes the scale ladder (single → team → company → org). Every tier is a
topology whose nodes are the tier below; running a parent recursively runs each
child's sub-topology down to the leaf claws.

Backend:
- migration 0011: companies/company_teams, orgs/org_companies, topology_runs.tier
- cm-db repos for companies + orgs (mirror teams)
- TurnRequest.attrs (forwarded from node.attrs) for child-id binding
- SubTopologyExecutor (recursive_exec.rs): a parent "turn" runs the child's
  sub-topology; durability via parent updated_at keepalive + cancel propagation
  + depth cap; boxed future breaks the org→company recursion
- topology_worker selects executor by job.tier
- routes: /api/companies, /api/orgs (create/list/get/run) + unified
  /api/structure/{level}/{id} for the zoom canvas

Frontend:
- MeshMark: node-mesh brand glyph (replaces the claw PNG), tier variants
- TopologyGraphView: optional onNodeClick/nodeMeta + dark-token theming
- StructureCanvas + Breadcrumb: one recursive zoom view for every tier
  (drill down on node click, breadcrumb up); TeamRunPanel extracted + shared
- two-tier Discord-style rail: StructureRail (mesh mark + org/company/team
  glyphs + tools popover + deploy + user) | RosterColumn (selected group's
  children, or your claws); SecondaryNav for cross-cutting tools
- ComposeWizard (company/org) wired into DeployWizard; /companies + /orgs pages

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-18 14:25:06 -07:00
Omar SobhandClaude Opus 4.8 bba18a4687 Teams UI: deploy scope selector + TeamWizard + Team page
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
The "+" deploy flow now opens a scope selector (Single / Team / Company-soon /
Org-soon). Single = the existing CreateClawForm. Team = TeamWizard: pick a
baseline topology (from the catalog + role distribution), set size, auto-staff
editable claw cards (name / role / model / persona), preview the topology
graph, then POST /api/teams → land on the Team page.

Team page (/teams/[id]): topology SVG + claw roster (each links to its chat) +
a Run panel that drives the team on the durable runner with live SSE progress
(reuses the topology-run streaming). /teams list page + a Teams nav entry.

lint + typecheck + next build clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-18 13:17:30 -07:00
Omar SobhandClaude Opus 4.8 654ec0f511 feat(frontend): topology compare/Pareto UI
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Add a Compare tab to /topologies: pick a task + roles + topology kinds, build a
graph per kind, run POST /api/topologies/compare, and render a leaderboard table
+ a quality/cost Pareto scatter (SVG, no deps). Wrap Build + Compare in a tabbed
TopologyWorkbench. e2e p8 extended to run a comparison end-to-end (build×N →
compare → leaderboard + Pareto). Full suite 39 green; build + TS clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-16 03:54:54 -07:00
Omar SobhandClaude Opus 4.8 7648487a59 feat(frontend): Topologies page — catalog browser + builder
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
New authed workspace page (/topologies, in the global nav) that browses the
topology catalog and builds + visualizes a topology from a kind + roles:
- lib/api/topology.ts: zod schemas + fetchTopologyCatalog (server, authed).
- TopologyGraphView: lightweight SVG renderer (no new deps), laid out per kind
  (row for pipeline/ring, star for delegation kinds, circle otherwise).
- TopologyExplorer (client): catalog list + roles input → POST
  /api/topologies/build via the /api proxy → render the graph.
- ShellNav: add the Topologies nav item.
- e2e (p8): sign in → nav → browse catalog → build a pipeline → graph renders.

Full suite green (38); npm build + TS clean. Goes live with the next server+
frontend deploy (compare/Pareto UI to follow).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-16 03:41:30 -07:00
Omar SobhandClaude Opus 4.8 05c49dc418 feat(marketing): add value sections + trim FAQ
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / e2e (push) Has been cancelled
Page is now Hero → Hierarchy → Scale → Why → Use cases → FAQ → CTA → footer.

- Scale: per-tenant runtime / scale-to-zero / delegation hierarchy.
- WhyGoverned: humans-in-the-loop, single audit journal, delegation, no rogue access.
- UseCases: support / marketing / research / engineering / finance / data.
- FinalCta: dark ink band bookending the hero ("Build your agent company").
- Trim FAQ to 4 (keep the e2e-referenced Qs); repoint nav/footer anchors to
  the live section ids. Refresh the @visual baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 16:44:14 -07:00
Omar SobhandClaude Opus 4.8 16c3231fba feat(marketing): drop crew/security usage + refresh baseline
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Completes 02cde39: remove the CrewStrip and Security functions, their consts,
and the now-unused AgentToken/lucide imports from Sections.tsx; render only
Hero → Hierarchy → FAQ in the marketing page; refresh the @visual baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 16:16:15 -07:00
Omar SobhandClaude Opus 4.8 5638006eb6 feat(marketing): trim landing to hero, crew, hierarchy, security
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Remove the Pitch, One-click, Works, Always-on and Skills sections and the
"Build your AI crew" footer CTA banner. Page is now Hero → CrewStrip →
Hierarchy → Security → FAQ → footer (dark tier kept). Prune the now-dead
section functions, consts, and imports (Image, skills icons). Repoint the
"marketing rendered" heading assertion (p0/p7/visual) from the removed
Pitch heading to the hero h1 (/agentic systems/); refresh the @visual baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 16:06:05 -07:00
Omar SobhandClaude Opus 4.8 44512a744f feat(marketing): redesign landing as "trusted infrastructure"
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Re-skins the playful/consumer feel into disciplined agent-infrastructure,
keeping the animated hero canvas (re-themed) and adding the hierarchy story.

- Palette: re-point coral→ember (#E0584A); add ink/surface/mist/slate-light/
  azure/teal tokens. One accent per viewport; retire the black/coral split-
  headline pattern across all 8 headings (single ink color).
- Typography: hero/section weights 800→~650-675, tighter tracking, smaller
  hero size; uppercase eyebrow label.
- Hero: dark ink base with glowing azure/indigo + faint ember canvas blooms;
  light copy; new positioning ("Build safe, scalable agentic systems" + the
  single-agent-to-company subhead); ember primary CTA + ghost "Read the docs".
- Imagery overhaul (code-built, no mascots): AgentToken chips (CrewStrip,
  OneClick card, footer), AlwaysOn rebuilt as a terminal/log with an approval
  line, SkillsShowcase as duotone lucide cards on Mist, Security as a shield/
  lock motif.
- New HierarchyDiagram section ("One agent, or a whole org chart"): SVG org
  chart with an azure active path and teal human-approval checkpoints on
  sandbox-leaving actions.
- Tests: dark-hero/terminal/eyebrow contrast fixed to AA; refreshed the
  marketing @visual baseline (hero masked).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 15:56:58 -07:00
Omar SobhandClaude Opus 4.8 6823147334 fix(frontend): read AUTH_MODE at request time so Clerk toggle works
The frontend is documented as a single image whose AUTH_MODE env var
selects local vs Clerk auth per deployment (docs/clerk.md). But the root
layout and /login read AUTH_MODE during render with no request-time
signal, so Next 16 statically prerendered them at build time in the
build host's mode (local). The deployed image then served the local
login form forever, ignoring AUTH_MODE=clerk at runtime — ClerkProvider
and <SignIn/> never appeared.

Add `await connection()` (the v16 way to read env at request time) in
the layout's IdentityProvider and in /login so both render per-request
and honor the runtime AUTH_MODE.

Also add a root .dockerignore: the repo had none, so every image build
shipped the 67GB Rust target/ dir as build context.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 01:29:03 -07:00
Omar SobhandClaude Opus 4.8 34b8d2f903 Brand: replace PawPrint mark with the new clawmates claw logo
Swapped the placeholder PawPrint icon for the new claw logo everywhere it
appears: the marketing nav (mobile + desktop), the footer, the login card,
and the app left rail. The supplied PNG was a red claw on a solid near-black
background, so I flood-filled the background to transparent (the dark-red
outline survives the black threshold) and exported a trimmed, optimized
public/images/clawmates-mark.png (321x256, 88KB from 1.7MB). It reads cleanly
on both light (nav/login) and dark (footer/rail) surfaces.

Also regenerated the favicon + PWA icons from the new mark:
- src/app/icon.png (Next uses it as the favicon; removed the old favicon.ico)
- public/icons/icon-192.png and icon-512.png (claw on #0a0a0a, maskable)

Roster-card avatars on the login panel stay as PawPrint (decorative, not the
brand). Regenerated all seven @visual baselines that contain the mark — the
swap is sub-threshold for maxDiffPixelRatio, so I deleted and recaptured them
rather than relying on update-snapshots.

typecheck/lint/build green · all @visual green · deployed and verified live
(mark, /icon.png, and PWA icons all 200).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 18:43:14 -05:00
Omar SobhandClaude Opus 4.8 8d9ea7faaa Login: match WorkClaw's /sign-in form exactly (progressive, Clawmates)
The live /sign-in is a Clerk-rendered SignInForm (SSR is just a spinner); the
rendered design is the email-first progressive form. Reworked our /login to
match it visually while keeping our real email+password auth underneath.

- Email step: "Sign up with Slack" (cosmetic), OR, Work Email / Phone Number
  tabs, work-email field, "Continue with work email →", "Other SSO Options".
  Slack / Phone / SSO are cosmetic placeholders we don't support yet.
- Password step: "Continue" reveals the password field + "Sign in" (our actual
  POST to /auth/session). A Back link returns to the email step.
- Headline now mirrors WorkClaw ("Multiply your team's brainpower" / "Sign up
  to get early access").
- Right panel is now the role-card roster grid (PawPrint avatars, our own
  roles) + "The AI crew for your team" + the claws-at-desk art.
- Updated all eight E2E signIn helpers (and the load assertions) for the new
  two-step flow: fill Email → Continue → fill Password → Sign in. Labels
  (Email/Password) and the "Sign in" button name are preserved.
- A11y: bumped the inactive tab text to full slate (was 3.41:1).

typecheck/lint/build green · p0-shell (full sign-in) green · p6-a11y (login
clean) green · all six @visual baselines green (login regenerated) · deployed
and verified live.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 14:27:53 -05:00
Omar SobhandClaude Opus 4.8 a5ae0d6042 Login: clone WorkClaw's two-panel /sign-in shell (Clawmates-branded)
Restyled /login into WorkClaw's two-panel auth design: a white form card on
the left, a periwinkle "meet the crew" panel on the right (claw roster strip,
"Your AI crew, all hands on deck", the claws-at-desk art), light-themed via
the marketing palette. The right panel is hidden on mobile.

- Kept /login as the canonical route (workspace redirect, /api/auth/login,
  and the whole E2E sign-in flow depend on it) and kept our email/password
  mechanism — only the chrome changed. Field labels (Email/Password) and the
  "Sign in" button are preserved so p0–p6 keep passing.
- Added /sign-in → /login redirect so WorkClaw's URL resolves.
- New AuthShell wraps both the local form and the Clerk SignIn branch.
- LoginForm restyled to the light card aesthetic (rounded inputs, full-width
  ink button); uses AA-safe coral-strong for the focus ring / error.
- Regenerated the login visual baseline.

typecheck/lint/build green · p0-shell (full sign-in flow) green · p6-a11y
green · login + marketing @visual green · deployed and verified live
(/login 200, /sign-in 307 → /login).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 14:13:20 -05:00
Omar SobhandClaude Opus 4.8 df589b70d4 Marketing landing: rebuild to WorkClaw structure 1:1 (Clawmates-branded)
Re-scanned the live workclaw.com (same content as our prior capture; they
redeployed but shipped no landing changes) and rebuilt our landing to mirror
its full structure section-for-section, keeping Clawmates branding and honest
claims (no borrowed customer logos, no unverified SOC 2).

Now matches the real layout: sticky pill nav (Product/Blog/Pricing/FAQ +
Sign In + dark Get Started) · light-blue hero with the claws-at-desk art ·
crew strip (honest stand-in for the customer-logo marquee) · "Multiply your
brainpower…" + four trait badges · One-click setup with the create-claw card
(Sandy Clawson) · Works where you do with the 13-app icon grid + Slack
conversation mockup · Always on (dark, moon + composite art) · Your work,
your way skills tiles · Enhanced security (hand-key + key-snap, 4 icon
columns) · FAQ on the textured field · two-tier footer (Build your AI crew
+ dark footer with socials).

- Pulled the WorkClaw assets the public capture missed (claws-at-desk,
  support-claw, slack-convos/cards, always-composite, 13 app icons, security
  icons, footer-team). Dropped WorkClaw's own logo mark for our PawPrint.
- Honest substitutions where WorkClaw's claims aren't ours: no SOC 2 (4th
  security column is "Air-gappable"; trust pill is "Self-hostable &
  air-gapped"), and the FAQ keeps our self-host/air-gap positioning.
- A11y: consolidated to AA-safe coral-strong (#d23a3a) for button fills and
  small coral text; axe reports zero serious/critical.
- Regenerated the marketing visual baseline.

typecheck/lint/build green · p7-marketing (render + a11y) green · @visual
green · deployed via Compose and verified live on :3000.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 13:54:25 -05:00
Omar SobhandClaude Opus 4.8 3b699f2e98 Marketing landing: full WorkClaw-structure clone with ship-crew copy
Rebuilt the public landing to mirror WorkClaw's complete section layout
(verified against tools/wc-capture/out/shots/marketing.png), with original
"clawmates crew on a ship" copy and captured WorkClaw art wired as
swappable placeholders.

Sections (top to bottom): sticky pill nav (dark Get-started CTA) · hero
(dual CTA + trust row + crew banner) · crew strip · positioning headline +
four trait badges · One-click setup (periwinkle panel) · Works where you do
· Always on watch (dark panel) · Your work, your way (3 skill tiles) ·
Safety built into the hull (security columns) · FAQ on the blue field · Build
your AI crew CTA on the dotted field · dark footer.

- No SOC 2 / compliance claims (p7-marketing enforces this); honesty kept by
  replacing WorkClaw's customer-logo marquee with our own crew strip.
- A11y: AA contrast fixes — text-xl coral CTAs (large-text bar), darker
  coral-strong accent on periwinkle, deeper FAQ blue for white text.
- New tokens: marketing-blue, marketing-coral-strong.
- visual.spec marketing test scrolls + waits for lazy art before the shot;
  regenerated the marketing baseline. (Deepest <img> — the security art —
  renders for users but is blank only in Playwright's full-page capture.)
- Vendored the captured WorkClaw asset bundle under public/images/.

Built, typechecked, linted, p7-marketing + @visual green, deployed via
Compose and verified live on :3000.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 09:37:45 -05:00
Omar SobhandClaude Opus 4.8 36087c30f5 Computer panel: match measured WorkClaw geometry (from capture)
Forensic capture of the live app's Computer panel gave exact ground truth,
correcting my prior commit (which trusted a reviewer's measurements):

- Dock is content-width (~380px) centered by a w-full wrapper, NOT stretched
  full-width — my last change had wrongly stretched it. Reverts to the real
  centered-pill behaviour.
- Dark tiles (#1f1f1f) gain the measured grounding drop in --shadow-dock-tile
  (0 4.65px 9.35px rgba(0,0,0,0.2)); previously flat (hairline + inset only).
- AppIcon cells fixed to 68px / 8px gap; grid gap 34px×16px; icons 34px; the
  dock now uses the same nested tile component as the grid.
- White brand-tile shadow + tile nesting were already exact (capture confirms).

Regenerated computer-home baseline. typecheck/lint/86 unit/31 E2E/6 visual green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 08:00:16 -05:00
Omar SobhandClaude Opus 4.8 c7b71f0ae9 Align --surface-warm-muted to WorkClaw prod (#1a1a1a → #1f1f1f)
Verified against workclaw.com's own compiled CSS (.dark scope defines
--surface-warm-muted:#1f1f1f). Used by 11 components (composer, credits,
welcome chips, tabs, app tiles). Subtle — below the visual-diff threshold,
so baselines are unchanged — but it's the correct prod value.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 06:09:13 -05:00
Omar SobhandClaude Opus 4.8 62d4338309 Set color-scheme so native UI matches the theme
The app sets the `.dark` class but never `color-scheme`, so the browser
renders native UI (scrollbars, form controls, select/date popups,
autofill) in its light default over the dark app — the one real gap a
panel review surfaced. Set `color-scheme: dark` on `.dark`, and reset it
to `light` on the `.marketing` scope (it lives inside the dark <html> and
color-scheme inherits).

The review's other claims were verified against the compiled CSS and are
non-issues: shadow utilities (shadow-dock-tile/screen/…) ARE generated
with values inlined into --tw-shadow (Tailwind v4 doesn't emit them as
root vars); --computer-width/--app-origin-scale are runtime inline styles,
not :root tokens; all 54 @property --tw-* are present.

typecheck/lint/86 unit/31 E2E green; all 6 visual baselines unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 03:52:15 -05:00
Omar SobhandClaude Opus 4.8 5ff2b2ca33 Adopt WorkClaw's shadcn/ui Neutral token contract (Tailwind v4)
Replace the hand-rolled @theme color block with a real shadcn init shape:
bare :root (light) + .dark (dark) tokens mapped to --color-* via
@theme inline, plus the missing semantic/chart/radius tokens. --accent
is now neutral (#262626) to match WorkClaw; the ~16 coral-via-accent
usages migrate to the dedicated `coral` brand token so they stay coral.

Adds cn() (clsx + tailwind-merge) and components.json so future
`npx shadcn add` works. Clawmates-specific tokens (coral brand,
marketing palette, measured shadows, motion, layout, type scale) are
preserved verbatim in a separate @theme block. Root <html> gains `dark`
(app/login read .dark; marketing stays light via explicit colors).

We do NOT add shadcn's Button/Card/etc. — they'd conflict with the
existing measured-to-WorkClaw components.

Verified value-preserving: typecheck/lint/86 unit/31 E2E all green, and
all 6 visual baselines pass with no diff. Compiled + live CSS confirm
bg-accent→#262626 (neutral), text-coral→#f96565, chart tokens present.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 22:00:06 -05:00
Omar SobhandClaude Fable 5 ddc1f8fbe0 Fonts: drop body antialiased so text renders at the reference weight
The <body> carried Tailwind's `antialiased` (-webkit-font-smoothing:
antialiased), which inherits through the whole tree and renders every
chat/message/UI text thinner & lighter than WorkClaw. WorkClaw leaves the
browser default (`auto`), giving the crisper/heavier weight. Removed the
class — body is now just `min-h-full`; computed -webkit-font-smoothing is
`auto`. The font itself was always 14px/400 Geist; only the smoothing
differed. Global rendering change → regenerated all 7 visual baselines;
full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 14:06:03 -05:00
Omar SobhandClaude Fable 5 ea27715202 Fonts: add ui-sans-serif to the sans fallback chain (match WorkClaw)
--font-sans was 'var(--font-geist), system-ui, sans-serif'; WorkClaw's
chain includes ui-sans-serif before system-ui. Added it so the fallback
order matches: geist, geist Fallback, ui-sans-serif, system-ui, sans-serif.
Fallback-only — Geist always loads (vendored locally), so rendering is
unchanged; full suite (37, incl. visual) green with no baseline diff.

(The lowercase 'geist' / 'geist Fallback' names are next/font's
auto-generated, metric-adjusted family names — CSS font-family matching is
case-insensitive, so they render identically to 'Geist'/'Geist Fallback'.)

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 13:50:48 -05:00
Omar SobhandClaude Fable 5 96e0134fc6 Left rail restructure + Computer panel as a right-anchored overlay
PART 2 — panel positioning (the 'pushes the chat left' root cause):
DevicePanel was an in-flow flex sibling, so opening it consumed width and
shoved the chat. Now phone/tablet anchor it as an ABSOLUTE right-edge
overlay (md:absolute right-0 top-0 h-full z-30, w-[448px]/w-[550px]) so
the chat keeps full width and does NOT reflow; only 'full' stays in-flow
(grow-[4]) and lets the chat shrink. The chat row is now relative; the
aside is pointer-events-none with the screen card pointer-events-auto so
the header toggles/close stay clickable under the overlay's transparent
top padding. Verified live: composer.left is identical (472px) panel
open vs closed in tablet — the chat no longer shifts.

PART 1 — left rail:
- Logo in its own 80px header row as a 48px black rounded-2xl brand tile
  with a coral PawPrint mark (our placeholder logo) + sr-only 'clawmates'.
- Agent tiles bumped to 58px (Avatar 'rail' size + rounded-[20px]
  squircle), centered, gap-1, 2px coral active ring (rounded-[22px]).
- Hover-revealed ⋯ menu per agent row (new AgentRowMenu): a 176px #1A1A1A
  popover with Pin + Settings rows (coral 15px icons, 14px labels), closes
  on outside-click/Escape. Pin pins the claw to the top of the rail
  (persisted in localStorage, client-side); Settings deep-links to that
  claw's Computer → Settings (the claw redirect now forwards ?app=).

86 unit + 31 functional E2E green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 05:26:09 -05:00
Omar SobhandClaude Fable 5 0383d8fd77 Fix interface fidelity: invalid Tailwind classes + restore lost HomeScreen
Side-by-side comparison surfaced that several restyle classes silently
generated NO CSS (confirmed against the compiled .next CSS) — invisible
to tests because unit tests assert class strings, not computed styles,
and visual baselines were captured from the broken build.

Root causes fixed:
- rounded-radius-button (51) / rounded-radius-squircle (3) generated
  nothing → every pill/button/chip was border-radius:0. Tailwind v4 maps
  --radius-button to 'rounded-button', not 'rounded-radius-button'.
  Replaced with rounded-full / rounded-[17px].
- duration-normal/fast/slow (58) generated nothing → transitions had
  easing but 0 duration (snapped). Replaced with the token-arbitrary
  form duration-(--duration-normal). (Also fixed an over-replace that
  double-wrapped var(--duration-normal) inside animate-[…] values.)
- HomeScreen.tsx was the OLD emoji version — the R3 rewrite was never
  committed. Restored: brand Chrome/Slack squircle tiles, coral
  GradientGlyph icons, 56px tiles with press-scale, and the frosted
  glass dock (bg-white/[0.07] backdrop-blur-[40px] saturate-150).

Targeted gaps from the feedback:
- raised surface --color-surface-warm-muted #1f1f1f → #1a1a1a (composer,
  chips, tabs)
- welcome chips: max-w-[422px] gap-3 → centered 2×2 grid
- composer input + rail nav labels → 14px
- DeviceSizeToggle: Full/Tablet/Phone text → lucide monitor/tablet/
  smartphone icons (aria-label keeps the radio names)
- SW cache bumped v1→v2 so redeployed clients purge the stale bundle
- LeftRail drawer: ref-during-render → prev-state pattern (lint)

Compiled CSS now emits .rounded-full, transition-duration:var(--duration-
normal), border-radius:17px, and shadow-dock-capsule. Button/Avatar unit
tests updated to the real class names. 83 unit tests green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 21:21:20 -05:00
Omar SobhandClaude Fable 5 337f059afd R7: test reconciliation + visual baseline lock
- Regenerated all 7 @visual darwin baselines for the restyled surfaces
  (login, workspace home, chat welcome, computer panel, credits) and
  added two new ones: the marketing landing (full page) and the Team
  org-chart tab.
- Credits visual made deterministic: balance + the whole usage card are
  masked (testids), and the runway line always renders so the card
  height is constant — shared-backend credit spend during the full run
  no longer shifts the diff.
- Full gate sweep green end to end: 173 Rust tests + clippy/fmt clean,
  83 frontend unit + lint + typecheck, all 37 Playwright journeys
  (functional + visual), axe serious/critical at zero across every
  surface, LOC ≤1250 and no-placeholder gates.

The interface now matches the reference design system across the app,
the Computer panel, the global pages, and a new light-theme marketing
site — design system only, our brand throughout.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 20:26:10 -05:00
Omar SobhandClaude Fable 5 200bb56299 R5: marketing landing — light-theme public site at /
A new (marketing) route group with its own LIGHT layout (slate palette +
marketing coral #E95656 + periwinkle cards on near-white), the inverse of
the dark app. The middleware rewrites '/' → /marketing for logged-out
visitors (keyed on the session cookie / Clerk __session); authed users
fall through to the workspace app unchanged.

Built to the measured marketing system with OUR copy and honest claims —
NO SOC 2 / compliance badges: floating white pill nav, the 75px/800/-3px
display hero with a single coral keyword span, dual pill CTAs (coral
primary / white-bordered secondary), trust badges ('free credits',
'no credit card', 'self-hostable & air-gapped'), periwinkle feature
cards, a structural-security section (approval-gated, broker-held creds,
air-gappable — our real differentiators), an interactive FAQ accordion,
CTA band, and footer.

E2E (p7-marketing): renders for logged-out visitors, FAQ accordion works,
asserts NO SOC 2 claim, and an axe pass (coral CTAs sized to clear the
AA large-text threshold). p0-shell updated: logged-out '/' now shows
marketing with a Sign-in link to /login.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 20:13:09 -05:00
Omar SobhandClaude Fable 5 1bfbccf172 R4 frontend: global pages restyled, Team tabs, /apps page, Buy credits
Shared PageChrome (28px/600 title + muted desc + top-right action pill)
now fronts every global page. Skills → 2-col r24 Card grid with team
install counts. Credits → three-card layout (balance w/ Buy credits;
usage meter w/ runway; promo; Talk-to-sales → mailto). The Stripe Buy
credits button only mounts when /api/billing/config reports it enabled
(honest degradation) and opens a real Checkout Session.

Team page gains the three reference tabs via SegmentedTabs: Members
(restyled), Claw org chart (real /api/team/orgchart — members grouped
with the claws they manage, each a deep link into chat), and Leaderboard
(real /api/team/leaderboard — claws ranked by usage with a coral bar).

New /apps global page (workspace-wide connections via ?workspace=true):
category pills + SearchPill + 2-col rows with inline API-key connect;
Apps added to the rail nav.

Wizard restyled to the system: coral-fill white-text CTAs with the glow
shadow, coral progress bars, swatch enter animation, system inputs —
all step text/behavior preserved.

83 unit + 29 functional E2E + a11y green; contrast fixed (subtle-fg →
muted-fg on cards).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 20:04:34 -05:00
Omar SobhandClaude Fable 5 6e061515b8 R1+R2: shell and chat restyled to the reference system
Shell (main-chat-shell-spec): rail rebuilt around a 48px squircle claw
avatar stack with a 2px coral active ring + name beneath + online dot,
dashed 'New claw' tile, lucide-icon nav pills with the live credits
balance shown inline (coral when negative, aria-hidden so the nav link
name stays 'Credits'); 80px transparent chat header with 36px round
sessions/new-session icon buttons and the 42px coral-glow Computer
launcher; 768px centered content rail. RosterList computes the active
claw from the pathname so AgentRosterItem stays presentational.

Chat (chat-message-components): asymmetric layout — user pill #1A1A1A
radius 24/24/4 with inset white ring + dual shadow, capped 75%, vs the
bubble-less assistant message (50px squircle avatar, 15px gap, plain
14px/1.7 text); messageSlideIn entrance; 126px welcome avatar with the
24px/600/-0.6px heading (claw name in coral) and lucide-led suggestion
chips; floating 24px-radius neutral-800 composer card with the cream
Send pill; StepTrace rows restyled to the system.

Brand marks (Chrome, Slack) vendored to public/services from the bundle.
83 unit tests, full 29-journey functional E2E green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 19:41:31 -05:00
Omar SobhandClaude Fable 5 3ec1d3b829 R0: design foundations — reference tokens, motion set, lucide primitives
- globals.css @theme merged with the measured reference system
  (docs/tokens.css): hover/divider/subtle-fg colors, cream + bubble
  tokens, squircle/toggle radii, spec-verbatim shadow set (bubble, card,
  dialog, dock-tile, CTA glow, launcher glow, screen-card ambient, dock
  capsule), marketing light palette, default 0.25s ease-app transition
  tokens. Legacy aliases (--color-accent, --spacing-rail/panel-*)
  retained so existing classes keep working
- motion.css: full app-shell choreography (zoom-in/out from tile origin
  w/ --app-origin-scale, push/pop slides, cross-fade) + messageSlideIn,
  create-claw step/swatch, device-* set — keyframes verbatim from
  docs/motion.md
- lucide-react installed (ISC). New tested primitives: Button (cream/
  coral/ghost/icon/launcher variants per measured states), GradientGlyph
  (per-instance coral linearGradient stroke, the reference glyph
  technique), SegmentedTabs, Card + SectionLabel + GroupedRows,
  SearchPill; Avatar extended (squircle r17, rail/chat/welcome sizes,
  online-dot overlay)

82 unit tests; functional e2e suite green (visual baselines regenerate
in R7).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 18:07:35 -05: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 ceca21ca79 Clerk frontend integration: one image, runtime-switched identity
- src/lib/auth/bearer.ts is the single identity dispatch for both
  server-side token consumers (RSC apiFetch and the /api proxy route):
  local -> httpOnly tc_session cookie; clerk -> Clerk getToken() session
  JWT. The Clerk SDK is imported lazily, so the air-gapped/local path
  never loads it
- Runtime env (AUTH_MODE / CLERK_PUBLISHABLE_KEY / CLERK_SECRET_KEY),
  deliberately NOT build-time NEXT_PUBLIC_*: the same standalone image
  serves both deployment targets
- Conditional <ClerkProvider> in the root layout (publishableKey passed
  at render from runtime env); /login renders Clerk's <SignIn /> in
  clerk mode and the local form otherwise; proxy.ts middleware delegates
  to clerkMiddleware() only when active
- Helm: frontend deployment injects the Clerk keys from a Secret when
  auth.mode=clerk
- mode.ts unit-tested (default local, exact-match clerk, loud failure
  without the publishable key); the local path stays proven by all 29
  journeys; the Clerk branch is thin delegation to the SDK, exercised in
  deployment smoke per docs/clerk.md

157 Rust + 68 frontend tests + 29 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 10:36:51 -05:00
Omar SobhandClaude Fable 5 ace66d7ffb P6 complete: PWA, route motion, dex browser-flow OAuth, release pipeline
- PWA (§16): hand-rolled 60-line service worker (network-first pages with
  offline fallback, cache-first hashed statics, /api NEVER touched — SSE
  and approvals stay live), app manifest with §2 identity, stdlib-
  generated coral claw icons, prod-only registration. E2E asserts
  manifest, real PNG icons, an ACTIVATED service worker, and the /api
  bypass. (Serwist was tried and dropped: its webpack plugin fights
  Next 16's Turbopack builds; sixty lines we own beat a plugin we fight.)
- Route motion (§3): (workspace) template re-mounts per navigation with a
  quiet fade-rise, zeroed under prefers-reduced-motion. The a11y sweep
  now settles running animations before scanning — axe was reading
  mid-fade opacity as contrast failures
- OAuth browser flow vs REAL dex: the e2e harness boots dexidp/dex with
  static client + password; the journey drives the actual dex login form
  from /api/apps/oauth/start through the callback 303 and asserts the
  app reads connected (closing the P4 deferral honestly)
- release.yml: tag-triggered — builds all four images + postgres, saves
  tarballs, assembles the SIGNED air-gapped bundle (compose, config,
  migrations, seccomp profile, installer, bundler binary), derives the
  public key via the new Could not find command "pubkey". subcommand (tested), verifies
  the bundle customer-style with the public half only, attaches tarball
  + public key to the GitHub release

153 Rust + 63 frontend tests + 29 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 09:57:21 -05:00
Omar SobhandClaude Fable 5 a8efada690 P5 exit: usage metering, credit billing, promo codes, 3-step wizard
- LlmEvent::Usage across all three providers (Scripted deterministic
  word-count accounting; Anthropic message_start/delta usage; OpenAI-compat
  stream_options include_usage)
- tc-billing: ceil(tokens/1000) min 1 credit; lots drain oldest-first under
  FOR UPDATE; balance clamps at zero while the usage ledger records the
  full obligation; promo codes redeem exactly once via CAS (migration 0006)
- Runtime charges every completed run (billing failure never fails a run);
  proven: 1 token in + 3 out -> 1 credit deducted
- API: GET /api/team/usage, POST /api/credits/redeem (409 on reuse, audited)
- Credits page: balance, 7-day usage meter with runway estimate, PromoRedeem
- /claws/new is the full §9 wizard: ?step=identity|access|slack deep-linked
  progress, accent swatches + name randomizer, access toggles, optional
  Slack step, explicit review-and-confirm (creation = live agent), animated
  provisioning state -> straight into chat
- E2E: chat decrements the visible balance and fills the usage meter;
  WELCOME500 adds exactly 500 once then refuses; wizard round trip

140 Rust + 63 frontend tests + 23 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 07:19:34 -05:00
Omar SobhandClaude Fable 5 1fd2c287f1 P3 exit: Computer panel with all 8 apps, themed and deep-linkable
- DevicePanel in the 448px SlidePanel: ?app= routes (home + 8 sub-apps via
  dynamic imports), ?device=full|tablet|phone size toggle, per-agent
  accent-derived wallpaper theme + feTurbulence grain, glassy dock + grid
  home screen, Computer button in the chat header
- Apps: Files (3 drives, real listings), Skills (installed + add from
  library), Routines (list/refresh/empty state), Claw Chat (threads +
  sensitive badge + detail), Settings (push/pop nav: edit profile PATCHes
  the system prompt, Other-Claws access toggle PUTs the policy, confirmed
  destructive delete), Slack (§7.3 pre-connect gate), Add Apps (live
  /api/apps directory + search), Browser (chrome + spec'd empty state)
- /skills Skill Library page + nav entry; curated /api/apps directory
  endpoint; e2e seed gains a catalog skill
- P3 exit E2E (6 journeys): themed home screen + device toggle in URL,
  agent-written file appears in Files, agent-scheduled routine appears in
  Routines, system-prompt edit persists across reload, deep-link cold-load
  of ?app=settings&device=full, every app reachable, library installs

132 Rust + 63 frontend tests + 20 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 05:37:18 -05:00
Omar SobhandClaude Fable 5 de38449b41 P2 BLOCKING exit green: approval interception chain end-to-end
- tc-tools: Effect declarations -> §15 GatedCategory mapping, deny-by-default
  external reach, taint invariant property-tested (tainted external effects
  are NEVER auto-allowed)
- tc-safety: pending approvals with exact payload+preview, CAS decide with
  audit + single-use grant in one tx, checkpoint suspend/load, exclusive
  resume claim, expiry sweep, decided-unresumed work queue (migration 0004
  adds the outbox the gated email.send tool writes)
- tc-runtime: resumable LoopState checkpointed to agent_runs; gated tool ->
  approval row -> approval_required/run_suspended events -> suspend; resume
  consumes the grant BEFORE executing (spent grant = no execution), rejection
  feeds a structured refusal in-band; durable resume sweeper; continuous
  journal seq across suspension (tested). ContentPart::Text became a struct
  variant — internally-tagged newtype primitives don't serialize
- tc-api: GET/decide approvals endpoints (409 double-decide, tenant
  isolation), decision triggers in-process resume; full chain proven over
  HTTP incl. gateway resumeFrom continuation
- frontend: approval_required/run_suspended events, suspended reply state,
  inline ApprovalCard (§10: summary, category, exact payload preview,
  approve/reject -> decide + stream re-attach), /approvals queue page, nav
- E2E (14 journeys, workers:1 to serialize the shared backend): gated email
  blocks with disabled composer -> approve -> continuation + ✓ step + reload
  replay; reject -> ✗ step, nothing executed; queue page decides pending

106 Rust + 61 frontend tests + 14 Playwright journeys green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 04:58:47 -05:00
Omar SobhandClaude Fable 5 9f9f507c15 P1 exit: chat UI, sessions column, agent create — 11 E2E journeys green
- Stream layer: incremental SSE parser tested against bytes captured from
  the REAL gateway (chunking-independent, UTF-8-safe, heartbeat-tolerant);
  Zod gateway event schemas; pure transcript reducer (optimistic send,
  delta streaming, step traces, resume dedupe, error states)
- Same-origin /api proxy route: httpOnly cookie -> bearer, unbuffered SSE
  passthrough; NuqsAdapter in root layout
- Chat workspace: route /claws/{id}/chat/{key} (RSC history + settings),
  WelcomeState with suggested prompts, MessageList (right user bubbles,
  left agent messages, blink caret), collapsible StepTrace, Composer
  (Enter sends, Shift+Enter newline)
- SessionsColumn in 208px SlidePanel (?sessions=1): search, relative
  times, active coral border, new session; /claws/{id} resumes latest or
  opens fresh; minimal create-claw form; rail + button and roster links
- P1 exit E2E: scripted reply streams, tool step trace survives reload,
  separate transcripts across sessions with column switching, create claw
  and chat immediately

83 Rust + 56 frontend unit/component tests + 11 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-09 23:29:27 -05:00
Omar SobhandClaude Fable 5 172a3c8fed P0: Next.js shell — tokens, motion, SlidePanel, LeftRail, auth plumbing
- Tailwind v4 @theme block encoding all spec §2 tokens; full §3 keyframe
  inventory with prefers-reduced-motion handling; Geist vendored (air-gap)
- SlidePanel width-animation primitive (component-tested: exit-transition
  unmount, fixed-width inner content, a11y region semantics)
- session-key.ts mirroring the Rust codec + URL-param encoding; nuqs
  panel-params with spec ?sessions=1 flag shape and routines->scheduled alias
- Zod-typed API client; httpOnly cookie session bridge (/auth/session);
  login page; (workspace) layout with LeftRail roster/nav/user; Team and
  Credits pages on real endpoints (+ GET /api/team/members in tc-api)
- Vitest + Testing Library harness (26 tests); ESLint max-lines 1250 +
  no-warning-comments mirroring the CI gates

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