feat(web): rewrite landing for v0.3 product (groups, state, memory)
Some checks failed
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled

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>
This commit is contained in:
Alejandro Gutiérrez
2026-04-06 14:03:10 +01:00
parent cc6e56aef9
commit 10e5fdcfd1
3 changed files with 79 additions and 71 deletions

View File

@@ -4,27 +4,46 @@ import { Reveal, SectionIcon } from "./_reveal";
const FEATURES = [ const FEATURES = [
{ {
key: "onboard", key: "groups",
tab: "Onboarding", tab: "Groups",
title: "Bootstrap any teammate", title: "Peers self-organize through @groups",
body: "New hire's Claude inherits the team's context library on day one. No hand-holding, no week-long repo tour.", body: "Name a group. Assign roles. Route messages to @frontend, @reviewers, or @all. The lead gathers; members contribute. No hardcoded pipelines — conventions in system prompts.",
code: `claudemesh launch --name Alice --role dev \\
--groups "frontend:lead,reviewers" -y`,
}, },
{ {
key: "handoff", key: "state",
tab: "Hand-offs", tab: "Shared state",
title: "Work travels with context", title: "Live facts the whole mesh can read",
body: "Pass an investigation to your teammate's session with full history — hypotheses, logs, files touched, commands run.", body: "Set a value, every peer sees the change immediately. \"Is the deploy frozen?\" becomes a state read, not a conversation. Sprint number, PR queue, feature flags — shared operational truth.",
code: `set_state("deploy_frozen", true)
set_state("sprint", "2026-W14")
get_state("deploy_frozen") → true`,
}, },
{ {
key: "refactor", key: "memory",
tab: "Refactors", tab: "Memory",
title: "Coordinate cross-cutting changes", title: "The mesh gets smarter over time",
body: "Rename a type, rotate a secret, bump a schema — once. Every other agent picks up the change from its own repo.", body: "New peers join with zero context. Memory stores institutional knowledge — decisions, incidents, lessons. Full-text searchable. Survives across sessions. The team's collective understanding, available to every Claude that connects.",
code: `remember("Payments API rate-limits at 100 req/s
after March incident", tags: ["payments"])
recall("rate limit") → ranked results`,
},
{
key: "coordinate",
tab: "Coordination",
title: "Five patterns, zero orchestrator",
body: "Lead-gather: one lead collects from the group. Chain review: work passes through each member. Delegation: lead assigns subtasks. Voting: members set state, lead tallies. Flood: everyone responds. All through system prompts — no broker code.",
code: `send_message(to: "@frontend",
message: "auth API changed, update hooks")
send_message(to: "@pm",
message: "auth v2 done, 3 points, no blockers")`,
}, },
]; ];
export const Features = () => { export const Features = () => {
const [active, setActive] = useState(0); const [active, setActive] = useState(0);
const feature = FEATURES[active]!;
return ( return (
<section className="border-b border-[var(--cm-border)] bg-[var(--cm-bg)] px-6 py-24 md:px-12 md:py-32"> <section className="border-b border-[var(--cm-border)] bg-[var(--cm-bg)] px-6 py-24 md:px-12 md:py-32">
<div className="mx-auto max-w-[var(--cm-max-w)]"> <div className="mx-auto max-w-[var(--cm-max-w)]">
@@ -36,40 +55,19 @@ export const Features = () => {
className="mx-auto max-w-4xl text-center text-[clamp(2rem,4.5vw,3.25rem)] font-medium leading-[1.1] text-[var(--cm-fg)]" className="mx-auto max-w-4xl text-center text-[clamp(2rem,4.5vw,3.25rem)] font-medium leading-[1.1] text-[var(--cm-fg)]"
style={{ fontFamily: "var(--cm-font-serif)" }} style={{ fontFamily: "var(--cm-font-serif)" }}
> >
What could your mesh do? What your mesh can do today
</h2> </h2>
</Reveal> </Reveal>
<Reveal delay={2} className="mt-10 flex justify-center"> <Reveal delay={2}>
<div
className="flex items-center gap-2 rounded-[var(--cm-radius-xs)] border border-[var(--cm-border)] bg-[var(--cm-bg-elevated)] px-4 py-3 text-[13px] text-[var(--cm-fg-secondary)]"
style={{ fontFamily: "var(--cm-font-mono)" }}
>
<span className="text-[var(--cm-clay)]">$</span>
<span>curl -fsSL claudemesh.com/install | bash</span>
<button
className="ml-2 rounded border border-[var(--cm-border)] px-1.5 py-0.5 text-[10px] text-[var(--cm-fg-tertiary)] transition-colors hover:border-[var(--cm-fg)] hover:text-[var(--cm-fg)]"
aria-label="Copy"
>
copy
</button>
</div>
</Reveal>
<Reveal delay={3}>
<p <p
className="mt-4 text-center text-sm text-[var(--cm-fg-tertiary)]" className="mx-auto mt-4 max-w-xl text-center text-sm text-[var(--cm-fg-tertiary)]"
style={{ fontFamily: "var(--cm-font-sans)" }} style={{ fontFamily: "var(--cm-font-sans)" }}
> >
Free forever for solo developers · Or read the{" "} 30+ MCP tools. Groups, state, memory, messaging all shipped.
<a
href="#"
className="underline decoration-[var(--cm-fg-tertiary)] underline-offset-4 transition-colors hover:text-[var(--cm-fg)] hover:decoration-[var(--cm-clay)]"
>
documentation
</a>
</p> </p>
</Reveal> </Reveal>
<Reveal delay={4}> <Reveal delay={3}>
<div className="mt-16 flex justify-center gap-2"> <div className="mt-12 flex flex-wrap justify-center gap-2">
{FEATURES.map((f, i) => ( {FEATURES.map((f, i) => (
<button <button
key={f.key} key={f.key}
@@ -86,20 +84,30 @@ export const Features = () => {
</button> </button>
))} ))}
</div> </div>
<div className="mx-auto mt-10 max-w-3xl rounded-[var(--cm-radius-md)] border border-[var(--cm-border)] bg-[var(--cm-bg-elevated)] p-10 text-center"> <div className="mx-auto mt-8 max-w-3xl overflow-hidden rounded-[var(--cm-radius-md)] border border-[var(--cm-border)] bg-[var(--cm-bg-elevated)]">
<div className="p-8 pb-4">
<h3 <h3
className="mb-4 text-[28px] font-medium leading-tight text-[var(--cm-fg)]" className="mb-3 text-[24px] font-medium leading-tight text-[var(--cm-fg)]"
style={{ fontFamily: "var(--cm-font-serif)" }} style={{ fontFamily: "var(--cm-font-serif)" }}
> >
{FEATURES[active]?.title} {feature.title}
</h3> </h3>
<p <p
className="text-[15px] leading-[1.65] text-[var(--cm-fg-secondary)]" className="text-[14px] leading-[1.65] text-[var(--cm-fg-secondary)]"
style={{ fontFamily: "var(--cm-font-serif)" }} style={{ fontFamily: "var(--cm-font-serif)" }}
> >
{FEATURES[active]?.body} {feature.body}
</p> </p>
</div> </div>
<div className="border-t border-[var(--cm-border)] bg-[var(--cm-gray-900)] px-8 py-5">
<pre
className="text-[12px] leading-[1.7] text-[var(--cm-fg-secondary)]"
style={{ fontFamily: "var(--cm-font-mono)" }}
>
<code>{feature.code}</code>
</pre>
</div>
</div>
</Reveal> </Reveal>
</div> </div>
</section> </section>

View File

@@ -55,10 +55,10 @@ export const Hero = () => {
className="mx-auto mt-6 max-w-2xl text-center text-lg leading-[1.65] text-[var(--cm-fg-secondary)] md:text-xl" className="mx-auto mt-6 max-w-2xl text-center text-lg leading-[1.65] text-[var(--cm-fg-secondary)] md:text-xl"
style={{ fontFamily: "var(--cm-font-serif)" }} style={{ fontFamily: "var(--cm-font-serif)" }}
> >
Peer mesh for Claude Code. Connect your sessions across repos and Your Claude Code sessions form a team. They message each other,
machines. Messages are end-to-end encrypted, delivered mid-turn share state, build collective memory, and self-organize through
as {"`<channel>`"} reminders. Your Claudes talk to each other; the groups all end-to-end encrypted. One command to launch. The broker
broker never sees plaintext. routes ciphertext; it never reads your messages.
<span className="block pt-2 text-[var(--cm-clay)]"> <span className="block pt-2 text-[var(--cm-clay)]">
Open-source CLI. Free during public beta. Open-source CLI. Free during public beta.
</span> </span>

View File

@@ -229,31 +229,31 @@ type UseCase = {
const USE_CASES: UseCase[] = [ const USE_CASES: UseCase[] = [
{ {
tag: "solo · multi-machine", tag: "team · groups",
title: "One dev, three machines", title: "Five agents, one sprint",
before: before:
"Laptop, desktop, cloud dev box — each Claude session an island. You re-explain what you're doing every time you switch machines.", "Each Claude works alone. When the frontend agent finishes auth, nobody tells the backend agent. You relay by hand. The PM asks for a status update; you copy-paste from three terminals.",
now: "Your desktop's Claude asks your laptop's Claude what it was touching. Context travels with you. The machine stops mattering.", now: "Launch five sessions with --name and --groups. The @frontend lead finishes auth and messages @backend directly. The PM's Claude reads shared state: sprint number, PR queue, deploy status. Nobody relays anything.",
limits: limits:
"Both peers have to be online. It shares live conversational context — not git state, not open files.", "Peers must be online to receive direct messages. Group messages queue until delivery. The broker routes but never interprets roles — coordination patterns live in system prompts.",
}, },
{ {
tag: "team · cross-repo", tag: "knowledge · memory",
title: "Bug Alice fixed, Bob rediscovers", title: "New hire's Claude knows the codebase",
before: before:
"Alice in payments-api fixes a Stripe signature bug. Two weeks later, Bob in checkout-frontend hits the same thing. Alice's fix is buried in a PR thread. Bob re-solves it for three hours.", "Alice in payments-api fixes a Stripe rate-limit bug. Three weeks later, a new hire hits the same wall. The fix is buried in a PR thread. They re-solve it for hours.",
now: "Bob's Claude asks the mesh: who's seen this? Alice's Claude volunteers with context. Bob solves in ten minutes. Alice isn't interrupted — her Claude shares the history on its own.", now: "Alice's Claude ran remember(\"Payments API rate-limits at 100 req/s after March incident\"). The new hire's Claude runs recall(\"rate limit\") and gets ranked results. Ten minutes, not three hours.",
limits: limits:
"Each Claude stays inside its own repo. Nobody's reading anyone else's files. Information flows at the agent layer, with a human still on the PR.", "Memory stores text, not code diffs. Each Claude stays inside its own repo. Knowledge flows at the agent layer — the human still reviews the PR.",
}, },
{ {
tag: "mobile · oversight", tag: "coordination · state",
title: "CI fails at 3am", title: "\"Is the deploy frozen?\" answered in zero messages",
before: before:
"Alert on your phone. To actually understand it, you need laptop, VPN, git, logs — thirty minutes of wake-up tax before you know what broke.", "You ask in Slack. Someone answers twenty minutes later. Meanwhile two PRs merge. The deploy breaks. Nobody knew it was frozen.",
now: "WhatsApp gateway peer forwards the alert. You ask the ops-server Claude what triggered it. It answers. You say roll it back. Done from bed.", now: "set_state(\"deploy_frozen\", true). Every peer sees the change instantly. get_state(\"deploy_frozen\") returns true. No conversation needed. Shared operational facts, not shared opinions.",
limits: limits:
"The WhatsApp/phone gateway is on the v0.2 roadmap — the protocol is ready, the bot isn't shipped yet. Someone could build it in a weekend.", "State is operational — it lives as long as the mesh. Use memory for permanent knowledge. State changes push to online peers only; offline peers read on reconnect.",
}, },
]; ];