Email (broker):
- Rebrand mesh-invitation.tsx to match site (clay accent #d97757,
cream fg, Anthropic Serif/Mono, dark bg). Mesh glyph in header.
- Hero CTA links to the /i/short URL landing page.
- Single one-liner 'npm i -g claudemesh-cli && claudemesh launch --join URL'
so new users copy once, paste once, done.
Web InstallToggle:
- Replace two-step numbered list with single one-liner in the first-time
panel. Reduces copy/paste ops from 2 to 1 and stops prescribing
'YourName' as a literal (CLI now defaults to $USER).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Header now checks session and shows avatar + name + Dashboard link
when logged in, instead of always showing Sign in / Start free.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrites pricing section from single "public beta" card to side-by-side
hosted vs self-hosted comparison reflecting the cleaner product
architecture. Enterprise sell is now concrete: "Run our Docker image,
point your CLI at it, done — your mesh never leaves your VPC."
Updates hero subtitle, CTA, FAQ, and where-mesh-fits claim card to
reinforce the two deployment modes consistently across the landing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New hero section with a live animated mesh background: three equal
Claude Code peers in a triangle layout + six desaturated background
peers, all rendered pixel-perfect from pure React/CSS using the exact
Unicode characters and colors from Claude Code's own source.
- User prompts type into the bottom prompt-input box and "submit" to
scrollback (matching real Claude Code behavior). Mesh sends fly as
envelope icons with fading trails between peers; receivers pulse on
arrival. Dynamic routing by peer displayName.
- Radial vignette overlay keeps the hero title crisp while letting the
corner peers pulse visibly around the edges. Top/bottom linear fades
bleed into adjacent sections.
- Responsive scaling via ResizeObserver: cover-fit in hero bg context,
contain-fit for standalone use.
- Features section: added Skills, MCPs, and Commands as the first
three tabs — the mesh's real differentiators. Updated subtitle copy.
- New "Where claudemesh fits" section positioned between Features and
WhatIsClaudemesh: four-card comparison (vs MCP, vs subagents,
vs OpenClaw, and the positive claim) framing claudemesh as a wire
between Claude Code sessions, not a replacement for any of them.
All work is additive: 10 new files in apps/web/src/modules/marketing/
home/fake-claude-code/ plus hero-mesh-animation.tsx, hero-with-mesh.tsx,
and where-mesh-fits.tsx. Single edit each to features.tsx and
(marketing)/page.tsx to swap in the new hero and mount the new section.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Completes the v2 invite user experience. The generator now ships two
delivery modes behind a simple Link | Email toggle, and the vestigial
ic:// scheme is gone from every user-visible surface.
Modes
- Link (default, existing flow): mints a v2 invite, displays short URL
+ QR + CLI command. No behavioral change vs wave 2.
- Email (new): admin types a recipient email, submit dispatches through
the POST /api/my/meshes/:id/invites/email endpoint (wave 2), which
mints a normal v2 invite, records a pending_invite row, and stubs the
Postmark send with a TODO. Result card shows a "✓ Invite sent to X"
banner plus the same QR card so the admin can also share manually.
Honest UX copy on the stub:
"Email delivery is stubbed in v0.1.x — the invite is valid. Share the
link directly if needed." Avoids pretending something shipped that
hasn't.
ic:// cleanup
- inviteLink field no longer rendered or stored (still returned by the
API for backward compatibility; just not surfaced)
- CLI command now copies `claudemesh join <code>` (falls back to
shortUrl when code is null), matching the new v2 entry point
- Zero remaining `ic://` references in the UI
Implementation notes
- Two separate useForm instances (linkForm, emailForm) with dedicated
resolvers and submit handlers — clearer state boundaries than
conditional validation on a merged schema
- Mode toggle uses role="group" + aria-pressed, focus-visible ring,
keyboard-navigable
- Email result banner is role="status" for screen readers
- RPC client has one `as any` on `(api.my.meshes[":id"].invites as any)
.email.$post` — the endpoint IS registered server-side (wave 2) but
the monorepo's Hono type regen is out-of-band; TODO comment marks the
cast for removal when the RPC types catch up
- No new deps
- Component export signature unchanged
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Editorial timeline with vertical track, colored phase markers,
2-column feature grids per milestone. Shows v0.1→v0.8 evolution:
Foundation → Groups → Shared Intelligence → Files → Data Platform
→ Platform. Anchored by '66 npm releases. Every feature below is
in production today.' Dashed 'next' card at bottom for roadmap.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Simplify getting-started to 2 steps: npm install + launch --join.
Remove "claudemesh install" section, update join page to show
launch --join as the primary flow, update invite format examples.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop /install route (curl|bash script). Install is just `npm i -g
claudemesh-cli`. Update hero, FAQ, getting-started, and join flow to
reflect the simplified 3-step onboarding: install → join → launch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows the full hierarchy: Organization → Mesh → @groups → Peers
with live state + memory. Six coordination patterns below with
code snippets: lead-gather, delegation, voting, chain review,
broadcast, targeted views. Footer: 'All patterns are conventions
in system prompts. The broker routes; Claude coordinates.'
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows the 12 capability categories that flow through the mesh:
messages, groups, state, memory, files, SQL, vectors, graph,
tasks, context, streams, scheduled. Each with a mono icon tag
and one-line description. Anchored by '43 MCP tools, 5
persistence backends' footer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two new panels below the existing peer graph + live stream grid:
- StateTimelinePanel: vertical timeline of audit events and presence
status changes, auto-scrolling, sorted newest-first
- ResourcePanel: 2x2 card grid showing live peers, envelopes by
priority, audit event breakdown, and session status
Both share the same TanStack Query cache key as the existing panels
(no extra API calls). Matches the --cm-* dark terminal aesthetic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Renders peers as SVG nodes in a radial layout with animated edges
showing real-time message traffic. Shares the same TanStack Query
cache as LiveStreamPanel (same queryKey). Side-by-side on desktop,
stacked on mobile.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Landing page copy was stuck at the v0.1 feature set (messaging + state + memory + groups).
The CLI now ships 43 MCP tools across 5 persistence backends. This commit brings the site
copy in sync with what's actually built.
Changes:
- Hero, features, pricing, FAQ, CTA, footer: reflect 43 tools, files, SQL, vectors, graphs
- Features section: expanded from 4 tabs to 7 (added Files, Database, Vectors)
- New /getting-started page: full install guide with correct 4-step flow
- New Mesh vs MCP section: side-by-side diagrams + 8-row comparison table
- Fix: install-toggle on /join page had `npx claudemesh@latest init` (init doesn't exist)
→ replaced with `curl -fsSL https://claudemesh.com/install | bash`
- Navigation: added Getting Started to header, footer, hero link
- COPY.md synced with all 6 capability areas
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hero: sessions form a team with groups, state, memory — not just
messaging. Features: 4 tabs with real CLI code (groups, state,
memory, coordination patterns). Use cases: team sprint with 5
agents, new-hire knowledge transfer via recall(), deploy-frozen
via shared state. All match the shipped spec (v0.3.0).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire list_peers and set_summary MCP tools to the broker's WS
protocol instead of returning stubs. Peers can now discover each
other, see status/summary, and route messages by display name.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three surgical edits for credibility:
Hero subheadline: remove WhatsApp/Slack/phone promises (roadmap,
not shipped), replace "reachable from anywhere you are" (vague)
with concrete value prop: E2E encrypted, delivered mid-turn as
<channel> reminders, broker never sees plaintext. Change "Free
and open-source. Forever." → "Open-source CLI. Free during
public beta." to match the pricing section.
Logo bar: remove Vercel/Linear/Stripe/Supabase/Shopify/Figma
(not actual customers). Replace with tech stack labels: Claude
Code, MCP, libsodium, Bun, TypeScript, MIT.
FAQ: fix "Is claudemesh free?" to match beta pricing. Fix "How
do I get started?" to reference the real curl installer instead
of nonexistent npx claudemesh init. Fix "Which Claude Code
versions?" to name actual install + launch flow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Landing page showed \`curl -fsSL claudemesh.sh/install | bash\` but
the domain didn't resolve, so anyone copy-pasting got a DNS error.
Ship:
- apps/web/src/app/install/route.ts: GET returns an auditable bash
installer (Node preflight, npm install -g claudemesh-cli, runs
claudemesh install, prints next steps, colored output). No Node
auto-install — fails clean if missing with a pointer.
- apps/web/src/proxy.ts: exclude /install from the i18n matcher so
Next.js returns the shell script unmangled.
- hero.tsx + features.tsx: swap claudemesh.sh → claudemesh.com.
Test: curl http://localhost:3000/install | bash -n → OK.
Content-Type: text/x-shellscript; charset=utf-8.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 6-tier grid was selling features that don't exist yet:
- Pro \$12/mo: dashboard, peer registry, message history (not built)
- Plus \$24/mo: Tailscale mesh (already default), MCP bridge (free),
audit log (not built)
- Team \$99/mo: \"self-hosted broker\" AND \"25 peers\" AND
\"unlimited peers\" — three contradictions in one tier
- Business \$499/mo: multi-region, retention, Slack/Linear (roadmap)
- Enterprise: claimed \"SOC 2 pack\" without certification
Replaced with a single Public-Beta card:
- Free, no card required
- Two columns: Shipping today (verified against source) + Roadmap
v0.2–v0.3 (clearly labeled)
- Promise: \"Beta users keep the free plan for life\"
Non-additive rewrite of a shipped section. Authorized by user
explicitly; required because the prior pricing created refund +
legal risk.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Additive NEWS entry pointing to the new public repo
github.com/alezmad/claudemesh-cli and the launch command.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The demo-dashboard embedded MeshStream with a fixed min-h-[480px] grid
+ overflow-y-auto on the message <ol>. Browsers capture every wheel
event that fires over a scrollable container — so hovering the demo
section froze page scroll until the user moved the cursor off.
Landing demo has only 6 messages, never needs internal scroll. The
fixed viewport only makes sense in the live dashboard where envelope
count can exceed the box.
Added `scrollable?: boolean` prop to MeshStream (default false).
- demo-dashboard (landing): no prop → intrinsic height, no overflow,
wheel events propagate to the page
- live-stream-panel (/dashboard/meshes/[id]/live): scrollable → keeps
the chat-style fixed viewport with scroll
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three bugs caught via devtools on live site:
**1. CSP 'font-src 'self' data:' violation × 3 per landing load.**
BaseLayout was loading Geist + Geist_Mono via next/font/google. In
prod builds Next.js self-hosts those under /_next/static, but the
generated CSS still references `--font-sans: "Geist", …` which some
browsers resolve by re-requesting fonts.gstatic.com. Since we ship
Anthropic Sans/Serif/Mono self-hosted already (/fonts/*.woff2 via
@font-face in globals.css), the Geist dependency was pure overhead.
Removed `next/font/google` imports entirely. Added a `.cm-root`
class on <html> that remaps the Tailwind `--font-sans/--font-mono`
tokens to our `--cm-font-sans/--cm-font-mono` vars — so every
Tailwind `font-sans` / `font-mono` utility now resolves to Anthropic
families. No Google Fonts fetch, no CSP violation.
**2. /pricing 401 on public visit.**
`<Plan>` calls `useCustomer()` → `GET /api/billing/customer` which
needs auth. Unauthed visitor on /pricing → 401 in devtools + wasted
round trip. Gated `useCustomer` on `authClient.useSession()` —
query `enabled: !!session?.user`. Public visitors now skip the fetch
entirely; signed-in users still get their customer record.
**3. Residual "Welcome back! 👋" on /auth/login (both locales).**
Emoji sweep (e91fc80) missed the i18n translation files. Removed 👋
from en/auth.json + es/auth.json login header titles.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clickable HTTPS invite URLs replace the raw ic://join/<token> as the
primary share format. Someone receiving a link in Slack now lands on
a friendly page with install instructions, not a dead-end.
Backend:
- createMyInvite returns a new joinUrl field
(https://claudemesh.com/join/<token>) alongside the existing
ic://join/<token> inviteLink and raw token. Schema + Hono route
updated. ic:// scheme stays — CLI parses both.
- New GET /api/public/invite/:token in packages/api/src/modules/public/
(unauthed). Decodes the base64url payload, verifies ed25519
signature against owner_pubkey using the same canonicalInvite()
contract the broker enforces on join, then joins mesh/invite/user
to return the shape needed by the landing page. Does NOT mutate
usedCount — this is a read-only preview.
- Error taxonomy: malformed | bad_signature | expired | revoked |
exhausted | mesh_archived | not_found. Each returned with any
metadata we CAN surface (meshName, inviterName, expiresAt) so the
error page can be specific ("ask Jordan for a new one").
- cache-control: public max-age=30 on valid invites, no-store on
errors (reasons flip as state changes).
Frontend:
- New public route /[locale]/join/[token] (no auth). Server
Component fetches the preview endpoint, branches on valid/invalid,
renders a minimal landing-design-language shell (wordmark header,
clay accents, serif headlines, mono commands).
- Valid-invite view: "You're invited to {meshName}", inviter +
role + member-count lede, install-toggle component.
- Invalid-invite view: per-reason error copy + inviter name when
available + link back to /.
- InstallToggle client component: three-way state
(unknown/yes/no). Asks "first time / already set up?", then shows
either the 3-step install+init+join path with per-step copy
buttons, or the single claudemesh join <token> command for users
who have the CLI. Every code block has copy-to-clipboard.
- Security footer: "ed25519 keypair generated locally, you keep
your keys, broker sees ciphertext only, leave anytime with
claudemesh leave <mesh-slug>".
Invite generator (/dashboard/meshes/[id]/invite):
- QR code now encodes the HTTPS joinUrl instead of ic:// (phone
cameras land on the web page → friendly path).
- Primary CTA copies the HTTPS URL. Secondary "Copy CLI command"
for fast-path users. Footer explanation updated.
CLI coordination note: dispatched to broker/db lane — claudemesh CLI
needs to accept BOTH ic://join/<token> AND
https://claudemesh.com/join/<token> (extract <token> from pathname).
Server side already returns both.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ScrollContainer — the wrapper under every dashboard/admin SidebarInset
— had zero horizontal padding on its scroll child, so pages rendered
edge-to-edge against the viewport. On wide screens content also
stretched to whatever width the sidebar left over (no max-width).
Single-point fix: wrap the scroll child in
<div class="mx-auto w-full max-w-[var(--cm-max-w)] px-4 py-6 md:px-8 md:py-8">
Hits every route under SidebarInset in one change:
- /dashboard
- /dashboard/meshes + /new + /[id] + /[id]/invite + /[id]/live
- /dashboard/invites
- /dashboard/settings (+ billing, security)
- /admin + /admin/users, /organizations, /customers, /meshes,
/sessions, /invites, /audit
px-4 → md:px-8 matches the marketing sections' gutter rhythm.
max-w-[var(--cm-max-w)] (90rem) caps content on ultra-wide.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Live social-proof counter on the landing page, tied to the E2E
narrative. Formatted as understated mono footer, not hero brag.
Backend — new GET /api/public/stats (unauthed, 60s in-memory cache):
{
messagesRouted: SELECT COUNT(*) FROM mesh.message_queue,
meshesCreated: SELECT COUNT(*) FROM mesh.mesh WHERE archivedAt IS NULL,
peersActive: SELECT COUNT(*) FROM mesh.presence WHERE disconnectedAt IS NULL,
lastUpdated: ISO timestamp,
}
Aggregate counts only — no ids, no names, no ciphertext, no routing
metadata. Safe for public consumption. cache-control header sets
public/s-maxage=60 for edge caching. `x-cache: HIT|MISS` for debug.
Frontend — new MeshStats Server Component at
modules/marketing/home/mesh-stats.tsx. Reads the endpoint server-side
via the ~/lib/api/server client, renders monospace footer:
ciphertext routed → 4,217 messages · 12 meshes · 8 peers online
broker sees none of it
Graceful zero state: when messagesRouted === 0 shows
"ciphertext → ready to route" instead of embarrassing zeros. Tabular-
nums for the numeric spans so they don't jitter across renders.
Mounted between <CallToAction /> and <LatestNewsToaster />. Page-level
`export const revalidate = 60` so Next.js ISR refreshes the counter
every minute without a DB hit on every request (combined with the
API cache = two-layer 60s TTL, DB sees ~1 query/minute).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Anthropic design language is icon-only, no emoji. User flagged that
claude-intercom components (and copy I wrote) were leaning on emoji
decoration. Swept all user-visible emojis in apps/web + packages/ui.
Changes:
- meshes/new onboarding banner: "Welcome to claudemesh 👋" → drop the
wave, text stands alone
- meshes/[id]/invite banner: "🎉 Mesh created" → "Mesh created"
- demo-dashboard script message: "thanks 🙏" → "thanks." (inline prose)
- MeshStream message-type chips: replaced the ⟐ / ← / → unicode
glyphs with proper inline SVG icons (10×10 stroke paths). Each chip
now carries: plus-sign for broadcast, up-arrow for hand-raise,
right-arrow for direct. Same claude-orange / emerald / neutral
coloring, same typography — just geometry instead of text symbols.
Nothing swapped to Lucide React imports yet — Icons barrel in
packages/ui/web only exports a subset (Circle, Check, MessageCircle,
Sparkles, Megaphone), and the four glyphs we needed were simpler as
inline SVG than adding barrel exports + per-component import plumbing.
If emoji→Lucide fully lands, we'll add the rest to the Icons barrel
in one pass.
Skipped per PM spec: TTS announcements, commit messages, code
comments, logs — not user-visible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three launch-visible friction fixes:
#3: "Continuar como invitado" (anonymous sign-in) removed. claudemesh
requires an account — mesh membership, invite issuance, and audit
trails are all tied to a user.id. Flipping the toggle is enough:
the AnonymousLogin component is gated by
`authConfig.providers.anonymous` in login.tsx, so disabling the
flag makes the button disappear from both /login and /register.
#4: OAuth buttons now show proper brand labels. Was rendering lowercase
"github" / "google" / "apple" via capitalize CSS (which users read
as "is this broken?"). Now renders "Continue with GitHub" /
"Continue with Google" / "Continue with Apple" next to the existing
brand icons. Also swapped layout: was `grow basis-28` (side-by-side
chips), now `w-full justify-center` (stacked full-width buttons) —
matches claude.com login styling more closely.
#6: Session hydration race on /dashboard — NON-ISSUE verified. The
0-mesh redirect runs in a Server Component AFTER
/dashboard/layout.tsx's getSession() gate. Server api.ts forwards
cookies to the Hono backend, so no client-side auth state is in
play. No fix needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wires the Discord-style demo UI to real user data. Users with 1+ meshes
now get situational awareness: who's online, what's in the queue, what
the broker saw recently — polling every 4s, all E2E encrypted.
Extraction pass:
- New `<MeshStream peers messages channelLabel footer>` renderer at
modules/marketing/home/mesh-stream.tsx — pure presentation, no
playback engine, no data fetching. Handles peer filter, hover-for-
ciphertext tooltip, animated message list.
- demo-dashboard.tsx refactored to use it: keeps the playback loop,
traffic-light chrome, and script-driven messages; passes everything
to MeshStream via props. ~120 LOC shorter.
Backend:
- new GET /api/my/meshes/:id/stream in packages/api (same authz gate
as /my/meshes/:id — owner OR non-revoked member). Returns:
- up to 20 live presences (disconnectedAt IS NULL), joined to
meshMember for displayName
- up to 50 most-recent message_queue envelopes with metadata only:
sender + displayName, targetSpec, priority, createdAt, deliveredAt,
byte size, and a 24-char ciphertext preview (this IS what the
broker sees — no plaintext anywhere in the response)
- up to 20 recent audit events
- getMyMeshStreamResponseSchema in schema/mesh-user.ts matches exactly.
Frontend:
- new LiveStreamPanel client component at modules/mesh/live-stream-panel.tsx
— react-query with refetchInterval: 4000ms, refetchIntervalInBackground
false. Maps presences + envelopes to MeshStream's Peer/Message shape,
classifies targetSpec into message type ("tag:*" → ask_mesh, "*" →
broadcast, else direct). Passes through the ciphertextPreview as the
hover content — no fake ciphertext in live view.
- new route /dashboard/meshes/[id]/live with server-side authz preflight
via /my/meshes/:id. Mounts LiveStreamPanel inside a dashboard page
shell with breadcrumb back to mesh detail.
- Mesh detail page gets a new "Live" pill button (clay-pulsing dot)
next to "Generate invite link" in the header.
- paths config gets dashboard.user.meshes.live(id).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Visitors read the page and still don't grok claudemesh is a *mesh* of
agents, not chatbot integrations. Fix: drop them straight into a live
Discord-style view of 4 peers talking. No auth, no WS, no backend —
a pre-recorded 10-second conversation that loops, encrypted over a
fake broker.
The conversation script (demo-dashboard-script.ts) hits every mental
model the landing needs to plant:
bob-desktop → #payments: "stripe sig verification broken?"
alice-laptop (self-nominates): "hit this 2wks ago, pulling fix"
alice → bob (direct): "<actual fix with file+line>"
bob → alice: "saved me. thanks 🙏"
carol-ios → #infra: "CI red on main?"
bob → carol: "reverting 7af3d, ~2min"
Covers: tag-routed broadcast (ask_mesh), self-election (hand-raise),
direct-peer DM, cross-surface (phone peer in the mix), multi-thread
concurrency.
Component (demo-dashboard.tsx, ~420 LOC):
┌─────────────────────────────────────────────────┐
│ meshes | peers | live message stream │
│ side | list | (motion fade+rise on each msg) │
│ bar | | │
└─────────────────────────────────────────────────┘
- requestAnimationFrame playback loop against SCRIPT[].t offsets
- Auto-loops after SCRIPT_DURATION_MS, 4s pause baked in
- Per-peer filter: click a peer in the sidebar, only their messages
show in the stream (from OR to), shows "filtered: <peer>" in header
- Play / pause / restart buttons
- Hover any message → dashed clay box shows the fake ciphertext:
"broker sees only this: AUp3+n7z1bY=.kQfM9vL4jR8..." — drives the
E2E point without a paragraph of crypto copy
- Status dots: green idle, clay pulse working, grey offline
- Surface glyphs inline (terminal / phone / slack) next to peer names
- Message type chips: ⟐ broadcast, ← hand-raise, → direct
- Progress bar at bottom ties the loop to a visible timeline
- Window chrome with traffic-light dots + "mesh.claudemesh.com ·
flexicar-ops · 4 peers online" header
Mounted between WhatIsClaudemesh and BeyondTerminal — explainer
first, then show-don't-tell.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All conversion CTAs were pointing to the dead github.com/claudemesh/
claudemesh repo or # hash fragments. Landing is the primary funnel for
v0.1.0 — every "Start" button is a conversion-critical surface.
Fixes:
- Header "Start free" → /auth/register
- Header GitHub nav item → REMOVED (kept the icon button, repointed)
- Hero "Start free" → /auth/register
- Pricing 6× CTAs: Solo/Pro/Plus/Team/Business → /auth/register,
Enterprise → /contact
- CTA footer "Star on GitHub" → /auth/register ("Start free")
- BeyondTerminal "Read the protocol spec" → /auth/register
("Get on the mesh")
GitHub reinstated as a dedicated icon button in the header right side,
pointing to https://github.com/alezmad/claude-intercom — the MIT OSS
foundation claudemesh is built on. Honest provenance: claude-intercom
is the local peer-mesh gift to the community, claudemesh is the hosted
cross-machine extension.
Tooltip: "Built on claude-intercom · MIT open source".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes the "chatbot integration" misread of the landing page by framing
claudemesh as a mesh-not-a-bridge above the gateways section.
- Mental shift (before/after): one Claude per project → mesh of Claudes,
mesh-as-substrate with surfaces tapping in
- Three concrete use cases with honest limits: solo multi-machine,
cross-repo team (Alice's Stripe fix / Bob rediscovers), mobile 3am
oversight via WhatsApp gateway
- Inline SVG architecture diagram: broker at center ("routes only · never
decrypts"), six peers hexagon-orbiting with ciphertext edges
- Anti-framing "what claudemesh is NOT" list to kill misreads
- Italic pull-quote closer with the honest one-liner
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Strategic positioning upgrade. claudemesh was framed as terminal-to-
terminal — which is only half the story. The broker is protocol-
agnostic: any peer with an ed25519 keypair joins the mesh, so the mesh
can reach WhatsApp bots, Telegram, iOS apps, Slack, email gateways,
browser extensions. Terminal is ONE client, not THE client.
New section at /#beyond: "Your mesh. Any surface." — 6 gateway cards
(Terminal / WhatsApp / Telegram / iOS·Android / Slack / Email) with
honest status badges:
- shipping → Terminal only (what we have today)
- on the roadmap → WhatsApp, Telegram, iOS/Android (we will build)
- build it yourself → Slack, Email (open protocol, community territory)
No overclaiming: we don't pretend WhatsApp is live. The honest framing
is exactly the aspirational hook — the architecture is there, the hooks
exist, someone could build a gateway peer today.
Each card has a custom 28px inline SVG glyph in clay, short serif
description, and a status chip. Grid staggers in with Motion.
Footer CTA: "the protocol is open · ed25519 + libsodium · build a gateway
for anything" + link to /#protocol on GitHub.
Hero subhead reworked to hint at cross-surface: "Peer mesh for Claude —
reachable from anywhere you are. … Terminal is one client, not THE
client."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New user signs in → /dashboard (user) → hits server-side getMyMeshes → 0
results → redirects to /dashboard/meshes/new?onboarding=1. Create-mesh
page renders a welcome banner explaining what a mesh is. After submit,
if ?onboarding=1 was set, the form bounces to
/dashboard/meshes/[id]/invite?onboarding=1 instead of the mesh detail
page. Invite page renders a "🎉 Mesh created" banner with the
`claudemesh join <link>` CLI snippet.
The onboarding flag is URL-driven — no persistence needed, dismissal
happens naturally when the user navigates away.
Also rewrites the /dashboard (user) home page from the placeholder
"Welcome to your Dashboard" TurboStarter card grid to a claudemesh-
native view: top 6 meshes with badges, All meshes / New mesh CTAs.
Removes the unused Card/Icons imports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two visible launch-polish issues:
1. BuyCtaDialog popup was firing on an exponential backoff schedule
(15s, 30s, 60s, …) pushing users toward turbostarter.dev/#pricing +
Discord. Wrong product, wrong audience. Fully removed: mount point
in [locale]/layout.tsx + the component file + localStorage keys will
self-prune on next visit.
2. WhatsApp/Slack/Twitter link previews were pulling the TurboStarter
boilerplate opengraph-image.png (from Jan 8). Replaced with a 1200×630
claudemesh OG: "CLAUDEMESH" pixel wordmark left side, hero mesh
composition (6 Claude Code terminals + pixel-crab hub + orange
energy lattice + vaporwave grid floor) right side, "peer mesh for
Claude Code sessions" tagline in mono beneath wordmark.
3. Default metadata description swapped from the dangling
`common:product.description` i18n key (which rendered as the key
itself because the key doesn't exist in our trimmed translations)
to a hardcoded claudemesh description.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Step 16 (account / profile) — landed smaller than scoped because turbo-
starter already ships the full /dashboard/settings flow (avatar, name,
email, language, delete-account) and BetterAuth handles security +
sessions out of the box. Reuses that surface; adds the claudemesh-
specific bits only.
- GET /api/my/export — returns a JSON bundle of the user's profile,
meshes they own, meshes they belong to, invites they've issued, and
audit events from their OWNED meshes (privacy: don't leak events
from meshes merely joined). Limited to 5k audit rows.
- ExportData component on /dashboard/settings — button downloads the
bundle as claudemesh-export-<userId>-<YYYY-MM-DD>.json client-side.
- Sidebar (user group) "settings" label swapped to "account" to match
the Step 16 naming. Same /dashboard/settings route, same existing
i18n key ("account" was already in common.json).
No schema changes: user.name (BetterAuth) IS the mesh display name.
meshMember.displayName is the per-join override that lands from the
CLI at registration time.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The fixed full-viewport overlay had overflow-auto AND pointer-events-none,
creating a scroll container that intercepted wheel events on hover in some
browsers — even though it was supposed to be click-through. Any viewport
< lg (1024px) broke page scroll when hovering anywhere above the fold.
Move overflow-y-auto + max-h-full to the inner panel (where it actually
needs to scroll for long nav lists) and keep the outer container purely
as a pointer-events-none positioning wrapper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Four new admin routes backed by the mesh API modules:
- /admin/meshes — paginated data-table (name, owner, tier, transport,
members, created). Tier + transport multiSelect filters.
- /admin/meshes/[id] — detail page: owner row + 4 live sections
(members, presences, invites, last 50 audit events).
- /admin/sessions — live Claude Code WS presences. Status filter,
pulse dot for working sessions, disconnected badge.
- /admin/invites — invite tokens w/ status derived client-side
(active/revoked/expired/exhausted).
- /admin/audit — metadata-only event log, event-type + mesh + date
filters.
Overview page at /admin rewritten to 6 summary cards (users, orgs,
customers, meshes, sessions, messages 24h) joining the base
/admin/summary and /admin/summary/mesh endpoints.
Sidebar navigation gains a second "mesh" group with the four new entries.
paths.ts extended with admin.meshes / sessions / invites / audit.
All UI reuses @turbostarter/ui-web/data-table — columns.tsx + thin
*-data-table.tsx wrapper per the existing users pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Step 3 pruned packages/{ai,cms,cognitive-context} but left whole
route groups + feature modules that depended on them. Those files
were unbuildable since that prune. Removes them now so the workspace
can be validated:
Route groups:
- apps/web/src/app/[locale]/(apps)/{chat,image,pdf,tts}/
- apps/web/src/app/[locale]/(marketing)/blog/
Feature modules:
- apps/web/src/modules/{chat,image,pdf,tts,common/ai,marketing/blog}/
- packages/api/src/modules/ai/ (chat, image, pdf, stt, tts, router)
3 stragglers remain (separate handoff to claudemesh-2):
- apps/web/src/app/[locale]/(marketing)/legal/[slug]/page.tsx (cms)
- apps/web/src/app/sitemap.ts (cms)
- apps/web/src/modules/common/layout/credits/index.tsx (ai)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- pgSchema "mesh" with 4 tables isolating the peer mesh domain
- Enums: visibility, transport, tier, role
- audit_log is metadata-only (E2E encryption enforced at broker/client)
- Cascade on mesh delete, soft-delete via archivedAt/revokedAt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>