From f9996c05846ed1e43616da5d99283d38894ed9d0 Mon Sep 17 00:00:00 2001
From: Sam Willis
Date: Wed, 3 Jun 2026 09:49:36 +0200
Subject: [PATCH 01/75] docs(website): plan /app page revamp and add nav entry
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Adds APP_PAGE_PLAN.md outlining the rewrite of website/app.md from
a downloads index into a product landing page that explains what
the desktop and mobile apps actually do: multi-server / multi-device,
bundled Horton coding agent, state explorer + tile workspace for
SDK builders, and attach-to-remote flows for software-factory-style
workloads (CI / webhooks / GitHub issues / cron).
Also adds an `App` entry to the main nav in MegaNav.vue and
MegaNavMobile.vue, in its own visual group between Sync and Cloud
with a `'|'` divider on each side. Plain link to /app; no dropdown
panel since the page is self-contained.
No user-facing copy on /app changes yet — follow-up PRs land the
page sections per the plan.
Co-authored-by: Cursor
---
APP_PAGE_PLAN.md | 547 ++++++++++++++++++
.../.vitepress/theme/components/MegaNav.vue | 9 +
.../theme/components/MegaNavMobile.vue | 2 +
3 files changed, 558 insertions(+)
create mode 100644 APP_PAGE_PLAN.md
diff --git a/APP_PAGE_PLAN.md b/APP_PAGE_PLAN.md
new file mode 100644
index 0000000000..a7ca413592
--- /dev/null
+++ b/APP_PAGE_PLAN.md
@@ -0,0 +1,547 @@
+# /app page revamp — plan
+
+> **Status:** draft for review.
+> **Goal:** turn `website/app.md` (`AppDownloadPage.vue`) from a Cursor-style downloads index into a real product landing page that explains what `@electric-ax/agents-desktop` + `@electric-ax/agents-mobile` actually do.
+> **Tone:** matches existing landing pages — `agents-home`, `streams-home`, `sync-home`, `cloud-home`. Reuses `Section`, `BottomCtaStrap`, `InstallPill`, `HeroNetworkBg`-style chrome.
+> **Author/agent note:** all desktop/mobile capability claims below are grounded in code that is already in `packages/agents-desktop` and `packages/agents-mobile` — nothing on this page should make promises the apps don't keep.
+
+---
+
+## 1. Why the current page underdelivers
+
+`website/app.md` → `src/components/app-download/AppDownloadPage.vue` is today:
+
+```text
+┌─────────────────────────────────────┐
+│ Hero (text only) │ Electric Agents App
+│ "A native home for your │
+│ long-running agents." │
+│ [Download for Mac] [Other …] │
+├─────────────────────────────────────┤
+│ Desktop — per-platform cards │
+│ mac arm / mac x64 / win / linux │
+├─────────────────────────────────────┤
+│ Mobile · Coming soon │ ← actually working; not just "soon"
+│ ios / android (disabled) │
+├─────────────────────────────────────┤
+│ Canary builds │
+├─────────────────────────────────────┤
+│ Bottom CTA (Quickstart, Docs, Cloud)│
+└─────────────────────────────────────┘
+```
+
+The hero copy is one line of vague positioning, the screenshot slot is an explicit `TODO`, and **every section below the fold is about which `.dmg` to grab**. The page sells nothing about what the app does.
+
+What it **should** sell, in priority order:
+
+1. **It is one app for the whole platform**, not just a chat client.
+ - Coding locally with Horton.
+ - Attaching to remote sessions spawned by CI / webhooks / issues / cron — software-factory-style workflows.
+ - Observing and steering the agents _you are building_ on the Electric Agents infra and SDK — state explorer, entity timeline, fork-from-here, MCP, skills, working-directory picker.
+2. **It works across devices and users.** Desktop on macOS / Windows / Linux, native mobile on iOS / Android, all looking at the same durable Electric streams. Multi-server, multi-tenant, Electric Cloud sign-in built in.
+3. **The bundled Horton.** General-purpose chat agent and coding agent in the same app — pick a model (Anthropic / OpenAI / DeepSeek / Moonshot / Codex), point at a working directory, go.
+4. **It bridges local and cloud.** Your laptop can act as a pull-wake runner for cloud agents, so the same desktop is both a UI and a worker.
+
+That is the story this page is missing.
+
+---
+
+## 2. The unifying narrative — one app, three jobs
+
+The user-facing pitch we land on:
+
+> **One app, three jobs, one platform.**
+>
+> Electric Agents is durable infrastructure for long-running agents, with an SDK for shipping your own. The desktop and mobile apps are how you work with that platform — whether you're **building** agents, **running** them, or **steering** them while they work.
+>
+> - **Code with Horton, locally** — chat with a bundled coding agent that can read, write and edit files in any directory you point it at.
+> - **Attach to remote sessions** — sessions spawned by CI, webhooks, GitHub issues, cron or your own software factory show up live in the sidebar. Pick one up on your laptop. Continue it on your phone.
+> - **Introspect your own agents** — the same app is the dev tool for the entities you write with the SDK. State explorer, entity timeline, fork-from-here, MCP, skills.
+>
+> One UI. One streaming control plane. Many devices, many users.
+
+**On the "software factory" phrase.** It's a useful frame for the middle bullet — remote sessions spawned by CI / webhooks / issues — but it is **not** the headline. The page should mention it relatively high (in the §3 "Attach remotely" card body, and once in §1 hero sub-copy), then move on. The main narrative is _one app for the whole platform_; software factory is one named scenario within it.
+
+The phrase already shows up in `website/blog/posts/2026-03-26-stream-db.md`; this page is the first place we let it act as a named scenario rather than a throwaway aside.
+
+---
+
+## 3. Page structure (8 sections)
+
+```text
+┌─────────────────────────────────────────────────────────────┐
+│ §1 HERO │
+│ Headline + sub + primary CTA (platform-detected) │
+│ Glyph row: macOS · Windows · Linux · iOS · Android │
+│ Release-notes link │
+├─────────────────────────────────────────────────────────────┤
+│ §2 VISUAL STRAP (desktop + mobile screenshots side by side) │
+│ "Same session, two devices" — illustrates multi-device │
+├─────────────────────────────────────────────────────────────┤
+│ §3 THREE WAYS TO USE IT (three feature cards + scenarios) │
+│ [Code] [Attach] [Introspect] │
+│ local remote SDK │
+├─────────────────────────────────────────────────────────────┤
+│ §3.5 SCENARIOS (worked end-to-end examples) │
+│ GitHub issue → CI → triage on phone → finish on desk · … │
+├─────────────────────────────────────────────────────────────┤
+│ §4 MULTI-DEVICE, MULTI-USER │
+│ Diagram: phone ↔ Cloud ↔ desktop-runner │
+│ Cloud sign-in, pull-wake runner, shared sessions │
+├─────────────────────────────────────────────────────────────┤
+│ §5 BUNDLED HORTON │
+│ Model picker, working dir, tools, skills, /slash │
+│ BYO keys (OS keychain) or sign in to Codex │
+├─────────────────────────────────────────────────────────────┤
+│ §6 BUILT FOR BUILDERS │
+│ State explorer, entity timeline, fork-from-here, MCP, │
+│ local discovery, tile workspace, deep-link layouts │
+├─────────────────────────────────────────────────────────────┤
+│ §7 DOWNLOAD │
+│ Desktop per-platform cards (current §2) │
+│ Mobile App Store / Play row (current §3, upgraded) │
+│ Canary builds (current §4) │
+├─────────────────────────────────────────────────────────────┤
+│ §8 BOTTOM CTA STRAP │
+│ "Build with Electric Agents" — Quickstart, Docs, Cloud │
+└─────────────────────────────────────────────────────────────┘
+```
+
+Every section uses the existing `` block from `website/src/components/agents-home/Section.vue` (eyebrow chip + brand-accented title + subtitle + body slot). The hero and the bottom CTA reuse `` and the matching hero pattern from ``.
+
+---
+
+## 4. Section-by-section copy + structure
+
+### §1 Hero
+
+```text
+ ┌─────────────────────────────┐
+ │ ELECTRIC AGENTS APP │
+ └─────────────────────────────┘
+
+ Run, observe and steer your agents.
+
+ Desktop and mobile clients for the Electric Agents
+ platform — one app to code with Horton, attach to
+ remote sessions, and build your own agents on the
+ infra and SDK.
+
+ ┌──────────────────────────┐ ┌────────────────┐
+ │ Download for Mac (M-) │ │ Other platforms│
+ └──────────────────────────┘ └────────────────┘
+
+ Apple Windows Linux iOS Android
+ (glyph row, muted)
+
+ Release notes →
+```
+
+- **Headline:** `Run, observe and steer your agents.`
+ Keep the brand-accented "Agents" treatment from `` if we want it.
+- **Sub:** `Desktop and mobile clients for the Electric Agents platform — one app to code with Horton, attach to remote sessions, and build your own agents on the infra and SDK.`
+- **Primary CTA:** platform-detected download button (existing behaviour; keep `detectMacArch()`).
+- **Secondary CTA:** `Other platforms` jumping to `#download`.
+- **New glyph row** under the CTAs: 5 platform glyphs in a muted row. Communicates multi-platform breadth without scrolling.
+- **Release notes link** stays where it is today.
+
+> Why this matters: the current hero is text-only and the platform breadth is buried in §2/§3. Surfacing macOS / Windows / Linux / iOS / Android above the fold reframes the page from "download a desktop app" to "download an app for your fleet".
+
+### §2 Visual strap
+
+```text
+┌─────────────────────────────────────────────────────────────┐
+│ ┌────────────────────────────────┐ ┌─────────────────┐ │
+│ │ Desktop window │ │ Phone │ │
+│ │ Sidebar tree · tile workspace │ │ Same session, │ │
+│ │ Horton chat in left tile │ │ chat view │ │
+│ │ State explorer in right tile │ │ │ │
+│ └────────────────────────────────┘ └─────────────────┘ │
+│ │
+│ "Same session. Two devices. One control plane." │
+└─────────────────────────────────────────────────────────────┘
+```
+
+- No copy headline of its own — this is a between-section strap that makes the hero believable.
+- We will need to **capture two real screenshots** for this:
+ - Desktop: a session with the sidebar tree visible + a split tile workspace (chat on the left, state explorer on the right) — proves both "regular UI" and "dev tool" in one image.
+ - Mobile: the chat session screen from `packages/agents-mobile/src/screens/SessionScreen.tsx` showing the _same_ session URL.
+- File the resulting assets under `website/public/img/app/`. Suggested filenames: `desktop-hero.png`, `mobile-hero.png`, plus 2× variants.
+
+### §3 Three ways to use it
+
+This section does the heavy positioning lift. It is also where the **software-factory** scenario is named (in the middle card), without being made the whole pitch.
+
+```text
+┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
+│ CODE LOCALLY │ │ ATTACH REMOTELY │ │ BUILD WITH SDK │
+│ │ │ │ │ │
+│ Bundled Horton │ │ Sessions spawned│ │ State explorer │
+│ with bash / │ │ by CI, webhooks,│ │ + entity │
+│ read / write / │ │ GitHub issues, │ │ timeline for │
+│ edit / search / │ │ cron, or your │ │ the agents YOU │
+│ workers. │ │ software │ │ build with the │
+│ │ │ factory show up │ │ SDK. │
+│ Point it at any │ │ live in your │ │ │
+│ folder, BYO │ │ sidebar. Pick │ │ Fork from any │
+│ keys. │ │ one up, steer │ │ point. MCP + │
+│ │ │ it, hand it │ │ skills + tile │
+│ │ │ off. │ │ workspace. │
+│ │ │ │ │ │
+│ You can: │ │ You can: │ │ You can: │
+│ · refactor a │ │ · pick up a CI- │ │ · watch a stuck │
+│ folder │ │ spawned PR │ │ entity live │
+│ · bisect a bug │ │ review on │ │ · fork to A/B │
+│ · scaffold a │ │ your phone │ │ a prompt fix │
+│ project │ │ · steer a GitHub│ │ · trace a │
+│ · review a diff │ │ triage agent │ │ failed worker │
+└──────────────────┘ └──────────────────┘ └──────────────────┘
+ one integrated platform
+```
+
+- **Card 1 — "Code with Horton, locally."**
+ - Eyebrow: `Code locally`
+ - Body: Horton ships in the desktop. Pick a model (Anthropic, OpenAI, DeepSeek, Moonshot, Codex). Pick a working directory. Chat to a coding agent that can read, write, edit, run bash, search the web, fetch URLs, and spawn parallel workers.
+ - **You can:**
+ - Refactor a folder of TypeScript files while Horton runs parallel workers per module.
+ - Bisect a regression by spawning a worker to reproduce, then another to fix.
+ - Scaffold a fresh project with `/init`, then iterate with `/quickstart`.
+ - Review a diff or a PR description and ask Horton to draft follow-ups.
+ - Backed by: `packages/agents-desktop/src/runtime/lifecycle.ts` (BuiltinAgentsServer), `packages/agents/src/agents/horton.ts`, `WorkingDirectoryPicker`, `ApiKeysForm`, `CredentialsPage`.
+
+- **Card 2 — "Attach to remote sessions."**
+ - Eyebrow: `Attach remotely`
+ - Body: Connect to any agents-server — your own, your team's, or Electric Cloud. Sessions spawned by CI, webhooks, GitHub issues, cron or your software factory appear live in the sidebar. Pick one up on the desktop, follow it on your phone, stop or steer it from either.
+ - **You can:**
+ - Triage a GitHub-issue-spawned Horton session on your phone, finish it from your laptop.
+ - Watch a CI agent open a PR, push a steering message before it merges.
+ - Pause a long-running cron-triggered pipeline and resume from where it left off.
+ - Hand a session off to a teammate by sharing the entity URL — the multi-user view sees the same stream.
+ - Backed by: `ServersPage` (multi-server config), `cloud-auth.ts` + `cloud-agent-servers.ts`, `local-discovery.ts`, mobile `ServerSetupScreen` / `SessionListScreen` / `SessionMenu` (signal stop/steer).
+
+- **Card 3 — "Build with the SDK."**
+ - Eyebrow: `Build with the SDK`
+ - Body: It's also the dev tool for the entities _you_ write with the SDK (`@electric-ax/agents-runtime`). Live state explorer, entity timeline, fork-from-here, manifest drawer, MCP servers, skills, and a tile workspace for following parent + workers in parallel.
+ - **You can:**
+ - Drop in on a stuck entity and watch its inbox / runs / manifest update in real time.
+ - Fork a session at any past point to A/B test a prompt or tool change.
+ - Step through a failed worker's tool calls without redeploying the host app.
+ - Run a parent and three children side-by-side in a tile workspace, then deep-link the layout.
+ - Backed by: `StateExplorerPanel`, `EntityTimeline`, `EntityContextDrawer`, `Workspace` + `TileContainer`, `McpServersPage`, `useExpandedTreeNodes`.
+
+- **Strip under the cards** (one line, centred, muted):
+ `One integrated platform — code, attach, and build in one app.`
+
+### §3.5 Scenarios
+
+A 2×2 (or horizontally-scrolling) strip of worked end-to-end examples. The purpose is to take the abstract "one app, three jobs" pitch and make it visceral — by the time the reader leaves this section, they should be picturing themselves doing one of these.
+
+```text
+┌──────────────────────────────────────────────────────────────┐
+│ Scenario 1 │
+│ GitHub issue → CI spawns Horton → triage on phone → │
+│ finish on desk │
+│ │
+│ A new GitHub issue (or `issue_comment`, or a workflow_ │
+│ dispatch from CI) opens a new agent session on Electric │
+│ Cloud. You get a notification on your phone, skim the │
+│ diff Horton drafted, push back a steering message │
+│ ("don't touch the migration files"), then pick up on │
+│ your laptop to merge. │
+│ │
+│ Touches: Cloud · mobile · steer · stop · merge │
+├──────────────────────────────────────────────────────────────┤
+│ Scenario 2 │
+│ Local refactor with parallel workers │
+│ │
+│ Open the desktop, point Horton at a repo, ask for a │
+│ rename across packages. Horton spawns a worker per │
+│ package, you watch all four in a 2×2 tile workspace, │
+│ fork the one that took the wrong turn, ship the diff. │
+│ │
+│ Touches: desktop · working-dir · workers · tile · fork │
+├──────────────────────────────────────────────────────────────┤
+│ Scenario 3 │
+│ Build an agent on the SDK, debug it without a redeploy │
+│ │
+│ You ship a custom `summarizer` entity with the SDK. │
+│ It's getting stuck on certain inputs. Open the state │
+│ explorer, watch its shared state evolve, fork the │
+│ failing session, change the prompt, replay. │
+│ │
+│ Touches: SDK · state explorer · timeline · fork · MCP │
+├──────────────────────────────────────────────────────────────┤
+│ Scenario 4 │
+│ Cron-triggered overnight pipeline │
+│ │
+│ Cron kicks off a nightly research agent on the cloud │
+│ server. Open the mobile app in the morning, see what │
+│ it found, hand off the most promising lead to a fresh │
+│ session for follow-up. │
+│ │
+│ Touches: Cloud · cron wake · mobile · fork · send │
+└──────────────────────────────────────────────────────────────┘
+```
+
+- **Headline:** `What this looks like in practice.`
+- **Sub:** Four short stories that span the three modes above. None of them require code you don't have today.
+- Format suggestion: render as four cards with an eyebrow tag (the _"Touches:"_ line) in mono, the title in semi-bold, then ~3 lines of body. Reuse the `.ad-platform-card` chrome from the current page so the visual rhythm doesn't fork.
+- **Implementation note:** each scenario gets a placeholder image slot at the top of the card (`
`). We'll fill those in later when we capture the actual flows; PR ships with a styled placeholder block.
+
+Backed by: every capability cited is a composition of the features already mapped in §5 of this doc. No new code required to ship the page.
+
+### §4 Multi-device, multi-user
+
+```text
+ ┌────────────────────────┐
+ │ Electric Streams / │
+ │ Electric Cloud │
+ │ ◯ durable agents │
+ └────────────────────────┘
+ ▲ ▲ ▲
+ │ │ │
+ │ │ │ pull-wake runner
+ sees+steers sees+steers registers itself
+ │ │ │
+ ┌────────┐ ┌──────┐ ┌──────────────┐
+ │ phone │ │ web │ │ desktop app │
+ └────────┘ └──────┘ │ (also a │
+ │ worker for │
+ │ cloud) │
+ └──────────────┘
+```
+
+- **Headline:** `Multi-device, multi-user.`
+- **Body:** Agents run on the server, not the client. The desktop and mobile apps are live views into the same Electric streams — open the same session from your laptop and your phone, hand work off between devices, share a workspace with your team. Sign in once with GitHub or Google; your Electric Cloud workspaces appear automatically. The desktop can even register itself as a pull-wake runner so your laptop becomes a worker for your cloud agents — close the lid and they finish on the next runner that comes online.
+- Backed by: `cloud-auth.ts` (GitHub/Google OAuth), `cloud-agent-servers.ts`, `pullWake` config in `BuiltinAgentsServer` startup, mobile `CloudAuthContext` + `CloudServerPicker`.
+- **No screenshot needed** — keep the ASCII flavour or render the diagram as an inline SVG matching the existing `EntityOverviewDiagram.vue` style (already in `website/src/components/`).
+
+### §5 Bundled Horton
+
+```text
+┌─────────────────────────────────────────────┐
+│ Bundled Horton │
+│ │
+│ Tools: │
+│ bash · read · write · edit │
+│ web_search · fetch_url │
+│ spawn_worker · send · skills │
+│ │
+│ Providers (you BYO key, OS keychain): │
+│ Anthropic · OpenAI · DeepSeek │
+│ Moonshot · Brave Search · E2B │
+│ — or sign in to Codex (OAuth / │
+│ codex-cli / opencode auth) │
+│ │
+│ /slash skills: /quickstart · /init · … │
+└─────────────────────────────────────────────┘
+```
+
+- **Headline:** `Horton, in the box.`
+- **Sub:** A friendly, capable general-purpose chat agent with code-editing superpowers — no server-side setup required.
+- Three sub-bullets:
+ - **Pick your provider.** Bring your own API key (stored in the OS keychain via `SecretStore`), or sign in to Codex.
+ - **Pick your working directory.** Horton reads and edits whatever you point it at — no per-project install.
+ - **Skills + slash commands.** Type `/quickstart` to load the guided onboarding skill; install your own skills to ship workflows to your team.
+- **Things you can ask Horton to do** (3-column list, short verbs):
+ - _Chat:_ `Summarise this docs page`, `Plan a refactor`, `Explain this stack trace`, `Draft a launch tweet`.
+ - _Code:_ `Refactor this file`, `Write tests for X`, `Bisect this regression`, `Apply the same change across these 4 files`.
+ - _Research:_ `Find the latest spec for Y`, `Diff what changed since v1.2`, `Pull the open PRs touching this dir`.
+- Backed by: `packages/agents-desktop/src/credentials/`, `WorkingDirectoryPicker`, `OnboardingModal`, `createSkillTools`, `createHortonDocsSupport`, `createHortonTools` in `packages/agents/src/agents/horton.ts`.
+
+### §6 Built for builders
+
+```text
+┌──────────────────────┐ ┌──────────────────────┐
+│ TILE WORKSPACE │ │ STATE EXPLORER │
+│ Split right/down │ │ Live view of every │
+│ cycle, find, │ │ shared-state source │
+│ ?layout= deep link │ │ per entity │
+└──────────────────────┘ └──────────────────────┘
+┌──────────────────────┐ ┌──────────────────────┐
+│ ENTITY TIMELINE │ │ MCP & SKILLS │
+│ Runs, inbox, │ │ Add MCP servers, │
+│ manifests, │ │ OAuth handled │
+│ fork-from-here │ │ natively, workspace │
+│ │ │ mcp.json override │
+└──────────────────────┘ └──────────────────────┘
+┌──────────────────────┐ ┌──────────────────────┐
+│ LOCAL DISCOVERY │ │ CLI INSTALLER │
+│ Finds dev servers │ │ Installs the │
+│ on localhost ports │ │ `electric` command │
+│ │ │ system-wide │
+└──────────────────────┘ └──────────────────────┘
+```
+
+- **Headline:** `Built for builders.`
+- **Sub:** When you ship your own entities on the Electric Agents infra and SDK (`@electric-ax/agents-runtime`), the same app becomes the dev tool you'd otherwise have to write yourself.
+- A 2×3 (or 3×2) grid of compact cards covering the six features above. Each card is icon + 4-word title + one-sentence body.
+- **Each card carries a one-line "use it to…" hint** so the feature card doesn't read as a spec sheet:
+ - **Tile workspace** → _"…follow a parent and three workers in parallel without losing context."_
+ - **State explorer** → _"…watch shared state evolve while your agent runs."_
+ - **Entity timeline** → _"…fork at any past point to A/B test a change."_
+ - **MCP & skills** → _"…snap in a tool server, OAuth handled for you."_
+ - **Local discovery** → _"…the dev server you just `pnpm dev`'d shows up automatically."_
+ - **CLI installer** → _"…drop `electric` on your PATH without touching npm."_
+- Backed by:
+ - `Workspace.tsx`, `TileContainer.tsx`, `SplitContainer.tsx`, `decodeLayout`.
+ - `StateExplorerPanel`, `EventSidebar`, `StateTable`.
+ - `EntityTimeline`, `useEntityTimeline`, "fork from here" in `ChatView`.
+ - `McpServersPage`, `runtime/mcp.ts`, `createSkillTools`, skills catalog.
+ - `discovery/local-discovery.ts`.
+ - `cli/controller.ts`.
+
+### §7 Download (the current page, trimmed)
+
+```text
+┌──────────────────────┐ ┌──────────────────────┐
+│ Apple Silicon │ │ Apple Intel │
+│ Electric-Agents- │ │ Electric-Agents- │
+│ mac-arm64.dmg │ │ mac-x64.dmg │
+└──────────────────────┘ └──────────────────────┘
+┌──────────────────────┐ ┌──────────────────────┐
+│ Windows │ │ Linux │
+│ -win-x64.exe │ │ AppImage · .deb │
+└──────────────────────┘ └──────────────────────┘
+
+ Unsigned-preview banner (kept as-is, current copy)
+
+┌──────────────────────┐ ┌──────────────────────┐
+│ iOS │ │ Android │
+│ TestFlight invite │ │ Internal-testing │
+│ · App Store (soon) │ │ link · Play (soon) │
+└──────────────────────┘ └──────────────────────┘
+
+ Pre-release / canary (existing compact list)
+```
+
+- **Desktop sub-section** — keep `` per-platform cards and the recommended-card highlight. Keep the `Unsigned Preview` callout exactly as it is.
+- **Mobile sub-section** — upgrade from "Coming soon" to _actual_ download paths:
+ - **iOS:** TestFlight invite link (we have EAS builds in `packages/agents-mobile/dist/`). Public App Store badge stays "coming soon" until the listing is live.
+ - **Android:** internal-testing Play link (EAS `export:android`). Public Play badge stays "coming soon" until the listing is live.
+ - If TestFlight / internal-testing isn't ready by ship day, fall back to a `Download .ipa / .apk` build artifact link — but **only** if there's a real artifact to point at. Don't ship the section if it's still vapor.
+- **Canary** — keep the existing list verbatim. It's already the right shape.
+
+### §8 Bottom CTA strap
+
+Keep the existing `` block but tighten the copy and reorder buttons to put the runtime-first story ahead of Cloud:
+
+```text
+┌──────────────────────────────────────────────────────┐
+│ · Durable · long-running · cloud-connected · │
+│ │
+│ Build with Electric Agents │
+│ │
+│ Stand up the open-source runtime locally, or │
+│ connect to Electric Cloud. │
+│ │
+│ [Quickstart] [Agents docs] [Cloud] │
+└──────────────────────────────────────────────────────┘
+```
+
+No copy change required here — the current `` invocation is fine.
+
+---
+
+## 5. Mapping every claim back to code
+
+Use this table as a checklist when writing the copy so the page makes no claim the apps can't back up.
+
+| Page claim | Implementation reference |
+| --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Bundled Horton coding agent (bash / read / write / edit) | `packages/agents/src/agents/horton.ts` (`createHortonTools`), `BuiltinAgentsServer` start in `packages/agents-desktop/src/runtime/lifecycle.ts` |
+| Pick your model provider (Anthropic / OpenAI / DeepSeek / Moonshot / Codex) | `packages/agents-desktop/src/credentials/{api-keys.ts,codex-auth.ts,model-picker.ts}`, `CredentialsPage.tsx`, `OnboardingModal` |
+| Bring-your-own keys in the OS keychain | `packages/agents-desktop/src/services/secret-store.ts`, `apiKeysRef` in `settings.json` |
+| Working-directory picker | `packages/agents-desktop/src/credentials/controller.ts` (`chooseWorkingDirectory`), `WorkingDirectoryPicker.tsx` |
+| Skills + `/slash` commands | `createSkillTools` from `@electric-ax/agents-runtime`, `AGENT_SKILLS_DIR`, system prompt in `buildHortonSystemPrompt` |
+| Multi-server (manual / discovered / cloud) | `packages/agents-desktop/src/shared/types.ts` `ServerSource`, `ServersPage.tsx`, `discovery/local-discovery.ts`, `cloud/cloud-agent-servers.ts` |
+| Electric Cloud sign-in (GitHub / Google) | `packages/agents-desktop/src/cloud/cloud-auth.ts` |
+| Pull-wake runner registration | `packages/agents-desktop/src/runtime/lifecycle.ts` (`pullWake` config block) |
+| State explorer | `packages/agents-server-ui/src/components/stateExplorer/StateExplorerPanel.tsx` and siblings |
+| Entity timeline + fork-from-here | `packages/agents-server-ui/src/hooks/useEntityTimeline.ts`, `EntityTimeline.tsx`, `ChatView.tsx` (anchor / `forkEntity`) |
+| Tile workspace + split menu + deep-link layouts | `packages/agents-server-ui/src/components/workspace/Workspace.tsx`, `TileContainer`, `SplitMenu`, `decodeLayout` |
+| MCP servers (settings + workspace `mcp.json`) | `packages/agents-desktop/src/runtime/mcp.ts`, `packages/agents-server-ui/src/components/settings/pages/McpServersPage.tsx` |
+| Local discovery of dev servers | `packages/agents-desktop/src/discovery/local-discovery.ts` |
+| Same session on desktop + mobile | `packages/agents-mobile/src/screens/SessionScreen.tsx` + Expo DOM embed of `packages/agents-server-ui/src/embed/EmbedApp.tsx` |
+| Mobile chat with queue / steer / stop | `NativeMessageComposer` + `NativeEntityContextDrawer` in `packages/agents-mobile/src/screens/SessionScreen.tsx` |
+| CLI installer (system-wide `electric`) | `packages/agents-desktop/src/cli/controller.ts` |
+| Tray + launch-at-login + power-save blocker | `packages/agents-desktop/src/ui/tray.ts`, `packages/agents-desktop/src/app/login-items.ts`, `packages/agents-desktop/src/runtime/lifecycle.ts` (`refreshPowerSaveBlocker`) |
+
+If a claim can't be linked to a row in this table, cut it from the page before merging.
+
+---
+
+## 6. Visual assets we'll need
+
+> **Ship placeholders first.** Every image / SVG slot on this page lands as a styled placeholder block in PR 1, with a `data-placeholder="…"` attribute and a TODO comment marking where the real asset goes. The page can ship and look credible without any of these files existing yet — we fill them in as PR 5 (or as individual follow-ups). Don't block the rewrite on imagery.
+
+The placeholder block should be a single component (suggested: ``) styled as a dashed-border, soft-bg rectangle with the slot name centred in mono — same visual language as the existing `.ad-platform-card` border + tone. Putting them behind one component means swapping each one for a real `` / `
-
+
Durable · long-running · cloud-connected
From d363296fc914e36521b42d0eb2f8bfb63c8a0b27 Mon Sep 17 00:00:00 2001
From: Sam Willis
Date: Wed, 3 Jun 2026 10:17:17 +0200
Subject: [PATCH 05/75] =?UTF-8?q?feat(website):=20/app=20phase=202=20?=
=?UTF-8?q?=E2=80=94=20hero=20rewrite=20+=20glyph=20row=20+=20=C2=A72=20st?=
=?UTF-8?q?rap=20pair?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Phase 2 of the /app page rewrite (see APP_PAGE_PLAN.md §7 phase 2).
Hero copy is locked to the final headline + sub described in
APP_PAGE_PLAN.md §1:
Run, observe and steer your agents.
Desktop and mobile clients for the Electric Agents platform —
one app to code with Horton, attach to remote sessions, and
build your own agents on the infra and SDK.
The word "agents" carries the brand accent treatment from
. The previous "Electric Agents App" product-name H1
is dropped in favour of the new headline — the product name is
now carried by the nav entry instead.
Adds a five-platform glyph row under the CTAs (macOS · Windows ·
Linux · iOS · Android) as muted icon + mono-label pairs. The iOS
and Android glyphs are slightly desaturated and share a single
"Preview" pill positioned beneath them, communicating the mobile
apps' preview status without cluttering each individual glyph.
The platforms grid uses an explicit 2-row CSS grid so the
preview pill stays anchored under the mobile pair on any width.
Restructures §2 from a single placeholder block into a desktop +
mobile placeholder pair (16:10 + 9:16) with the locked caption
"Same session. Two devices. One control plane." underneath. The
grid uses `minmax(0, …)` columns so the placeholders' aspect-ratio
+ intrinsic content widths can't push the strap past the section's
max-width. Phase 5 will swap each AdPlaceholder for the real
screenshot without touching the surrounding chrome.
Also renames the lower CSS section headings to match the new §7
numbering (§3 mobile → §7b mobile, §4 canary → §7c canary). No
runtime behaviour change from the rename.
Co-authored-by: Cursor
---
.../app-download/AppDownloadPage.vue | 206 ++++++++++++++++--
1 file changed, 192 insertions(+), 14 deletions(-)
diff --git a/website/src/components/app-download/AppDownloadPage.vue b/website/src/components/app-download/AppDownloadPage.vue
index 7e3293f0bb..9f1bf4b406 100644
--- a/website/src/components/app-download/AppDownloadPage.vue
+++ b/website/src/components/app-download/AppDownloadPage.vue
@@ -240,10 +240,13 @@ const primaryPlatform = computed(
- Electric Agents App
+ Run, observe and steer
+ your agents.
- A native home for your long-running agents.
+ Desktop and mobile clients for the Electric Agents platform — one app
+ to code with Horton, attach to remote sessions, and build your own
+ agents on the infra and SDK.
@@ -653,7 +731,107 @@ const primaryPlatform = computed(
border-bottom-color: var(--vp-c-brand-1);
}
-/* ── §2 desktop ─────────────────────────────────────────────── */
+/* ── §1 hero — platform glyph row ───────────────────────────── *
+ Sits between the CTA buttons and the release-notes link, two
+ rows in a 5-column grid:
+ row 1 — five [icon + label] pairs (macOS · Windows · Linux ·
+ iOS · Android)
+ row 2 — a single `Preview` pill positioned beneath the iOS +
+ Android pair (columns 4–5), softly marking the native
+ mobile apps as not-yet-public.
+ On narrow viewports the row collapses to 3 columns, with iOS +
+ Android wrapping onto a second visual row that keeps the
+ preview pill anchored beneath them. */
+
+.ad-hero-platforms {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(56px, auto));
+ justify-content: center;
+ align-items: start;
+ gap: 14px 28px;
+ margin: 32px auto 0;
+ max-width: 540px;
+}
+
+.ad-hero-glyph {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 6px;
+ color: var(--vp-c-text-3);
+}
+
+.ad-hero-glyph-icon {
+ font-size: 22px;
+ color: var(--vp-c-text-2);
+}
+
+.ad-hero-glyph.is-preview .ad-hero-glyph-icon {
+ /* Mobile glyphs are noticeably (but gently) more muted than the
+ desktop trio so the eye reads "this is a different cluster"
+ before it ever reaches the Preview pill below. */
+ color: color-mix(in srgb, var(--vp-c-text-2) 65%, transparent);
+}
+
+.ad-hero-glyph-label {
+ font-size: 10px;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+ color: var(--vp-c-text-3);
+}
+
+.ad-hero-platform-preview {
+ grid-row: 2;
+ grid-column: 4 / 6;
+ justify-self: center;
+ align-self: start;
+ margin-top: 4px;
+ padding: 3px 10px;
+ font-size: 10px;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ color: color-mix(in srgb, var(--vp-c-brand-1) 80%, var(--vp-c-text-3));
+ background: color-mix(in srgb, var(--vp-c-brand-1) 10%, transparent);
+ border: 1px solid
+ color-mix(in srgb, var(--vp-c-brand-1) 32%, var(--vp-c-divider));
+ border-radius: 999px;
+ white-space: nowrap;
+}
+
+/* ── §2 visual strap ────────────────────────────────────────── *
+ Desktop screenshot left (16:10), phone screenshot right (9:16);
+ the 2.4:1 column split keeps both placeholders' rendered
+ heights close while preserving each device's natural aspect
+ ratio. Caption sits centred below the pair. */
+
+.ad-visual-strap {
+ display: grid;
+ /* `minmax(0, …)` overrides the default `min-width: auto` on grid
+ items so that the placeholders' aspect-ratio + intrinsic content
+ can't push the columns past their fractional allocation. Without
+ this, the AdPlaceholder labels widen the mobile column enough to
+ overflow the section's max-width. */
+ grid-template-columns: minmax(0, 2.4fr) minmax(0, 1fr);
+ gap: 24px;
+ align-items: stretch;
+}
+
+.ad-visual-strap-caption {
+ margin: 22px 0 0;
+ text-align: center;
+ font-size: 13px;
+ letter-spacing: 0.04em;
+ color: var(--vp-c-text-3);
+}
+
+@media (max-width: 768px) {
+ .ad-visual-strap {
+ grid-template-columns: 1fr;
+ gap: 16px;
+ }
+}
+
+/* ── §7a desktop ────────────────────────────────────────────── */
.ad-desktop-grid {
display: grid;
@@ -764,7 +942,7 @@ const primaryPlatform = computed(
gap: 6px;
}
-/* ── §3 mobile ──────────────────────────────────────────────── */
+/* ── §7b mobile ─────────────────────────────────────────────── */
.ad-mobile-grid {
display: grid;
@@ -838,7 +1016,7 @@ const primaryPlatform = computed(
color: var(--vp-c-text-1);
}
-/* ── §4 canary ──────────────────────────────────────────────── *
+/* ── §7c canary ─────────────────────────────────────────────── *
Single compact list rather than four mini-card boxes. Each row:
icon + platform + inline download chips, hairline-separated
like an engineering reference table. */
From 58dfb8e9741201c5827c87393013dc7e1d14f3e8 Mon Sep 17 00:00:00 2001
From: Sam Willis
Date: Wed, 3 Jun 2026 10:26:31 +0200
Subject: [PATCH 06/75] =?UTF-8?q?fix(website):=20/app=20phases=201+2=20rev?=
=?UTF-8?q?iew=20=E2=80=94=20Mobile=20=C2=B7=20Preview=20+=20cleanup?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Self-review of phases 1 and 2. The biggest issue surfaced was an
internal inconsistency between the new hero glyph row (which marks
iOS + Android as "Preview") and the §7b mobile sub-section (which
still said "Coming soon" with disabled App Store / Google Play
badges). Same iOS + Android, two different framings on the same
page.
Resolves that by landing the §7 Mobile · Preview card now rather
than deferring it to phase 5. Final-copy body string and CTA are
already locked in APP_PAGE_PLAN.md §7, so no new design work is
needed:
- §7b sub-section eyebrow changes from `Mobile · Coming soon` to
`Mobile · Preview`.
- Two-card iOS + Android grid (disabled App Store / Play badges)
is replaced by a single content card with the locked body
string + a `View on GitHub →` CTA pointing at
packages/agents-mobile on the default branch.
- Drops the now-unused MobilePlatform type, mobilePlatforms data
array, the .ad-icon--appstore / --googleplay mask definitions,
and the .ad-mobile-grid / .ad-mobile-card / .ad-mobile-icon /
.ad-mobile-name / .ad-soon-pill / .ad-store-badge /
.ad-store-glyph CSS rules + their media-query partners. Net
delta is -46 lines despite adding the new card markup.
Also fixes a few smaller review findings:
- The .ad-hero-platforms style comment claimed a 3-column
responsive collapse that the code doesn't implement. Replaced
with an honest note that the 5-column layout is preserved at
all widths and compresses cleanly to ~360px.
- The §2 visual strap was passing .ad-visual-strap-desktop /
-mobile classes to the AdPlaceholder pair but never styling
them. Dead classes removed.
- AdPlaceholder's `name` prop jsdoc now documents the two valid
conventions in use today: section identifier (e.g.
"§3 — Three ways to use it") for full-section placeholders, or
asset filename (e.g. "desktop-hero.png") for image / SVG slots
that match the final path under website/public/img/app/.
- Tightened the now-stale "Phase 1 placeholder block" template
comment and the §7 wrapper comment so both describe the
current state rather than phase-1-vs-future-phase posture.
No new copy or visuals are introduced beyond what APP_PAGE_PLAN.md
§7 already locked for the mobile sub-section.
Co-authored-by: Cursor
---
.../components/app-download/AdPlaceholder.vue | 12 +-
.../app-download/AppDownloadPage.vue | 230 +++++++-----------
2 files changed, 98 insertions(+), 144 deletions(-)
diff --git a/website/src/components/app-download/AdPlaceholder.vue b/website/src/components/app-download/AdPlaceholder.vue
index 95775f006f..f187aac4c1 100644
--- a/website/src/components/app-download/AdPlaceholder.vue
+++ b/website/src/components/app-download/AdPlaceholder.vue
@@ -14,8 +14,16 @@
for the real content one section at a time; the surrounding chrome
doesn't change. */
defineProps<{
- /** Short label rendered inside the placeholder, e.g.
- * "§3 — Three ways to use it". Also written to `data-placeholder`. */
+ /** Short label rendered inside the placeholder and written to the
+ * `data-placeholder` attribute. Two conventions in use today:
+ * - **Section slot** — e.g. `§3 — Three ways to use it`. Use when
+ * the placeholder stands in for an entire section's content
+ * (cards, copy, scenario grid, etc.) that lands in a later
+ * phase.
+ * - **Asset filename** — e.g. `desktop-hero.png`. Use when the
+ * placeholder stands in for a specific image / SVG slot that
+ * will be filled by a captured asset. The filename matches the
+ * final asset path under `website/public/img/app/`. */
name: string
/** Optional CSS aspect-ratio (e.g. "16/9", "21/9"). When omitted,
* the placeholder uses its content's intrinsic height with the
diff --git a/website/src/components/app-download/AppDownloadPage.vue b/website/src/components/app-download/AppDownloadPage.vue
index 9f1bf4b406..c76a165525 100644
--- a/website/src/components/app-download/AppDownloadPage.vue
+++ b/website/src/components/app-download/AppDownloadPage.vue
@@ -27,6 +27,7 @@ import AdPlaceholder from './AdPlaceholder.vue'
const githubReleaseBase = `https://github.com/electric-sql/electric/releases`
const appReleaseNotesUrl = `${githubReleaseBase}?q=%22%40electric-ax%2Fagents-desktop%22&expanded=true`
+const agentsMobileRepoUrl = `https://github.com/electric-sql/electric/tree/main/packages/agents-mobile`
type DesktopPlatformId =
| 'macos-arm64'
@@ -149,31 +150,6 @@ const canaryEntries: CanaryEntry[] = [
},
]
-type MobilePlatform = {
- id: 'ios' | 'android'
- icon: 'apple' | 'android'
- storeIcon: 'appstore' | 'googleplay'
- name: string
- storeLabel: string
-}
-
-const mobilePlatforms: MobilePlatform[] = [
- {
- id: `ios`,
- icon: `apple`,
- storeIcon: `appstore`,
- name: `iOS`,
- storeLabel: `App Store`,
- },
- {
- id: `android`,
- icon: `android`,
- storeIcon: `googleplay`,
- name: `Android`,
- storeLabel: `Google Play`,
- },
-]
-
function releaseUrl(tag: string, assetName: string): string {
return `${githubReleaseBase}/download/${encodeURIComponent(tag)}/${assetName}`
}
@@ -338,17 +314,14 @@ const primaryPlatform = computed(
blocks below (desktop / mobile / canary)
collectively make up §7 of the new page. They keep their own
- anchors (#desktop, #mobile, #canary) for backwards compatibility
- with any external links; phase 6 verifies these still resolve
- after the rest of the page is in place.
-
- Phase 1 leaves their copy untouched. The mobile sub-section is
- still labelled "Coming soon"; a later phase reframes it as
- "Mobile · Preview" linking to packages/agents-mobile on GitHub
- (see APP_PAGE_PLAN.md §7).
+ anchors (#desktop, #mobile, #canary) for backwards
+ compatibility with any external links; phase 6 verifies these
+ still resolve after the rest of the page is in place.
+
+ Desktop and canary keep their original cards / list verbatim.
+ The mobile sub-section is reframed as `Mobile · Preview`
+ pointing at packages/agents-mobile on GitHub (see
+ APP_PAGE_PLAN.md §7 for the locked body string).
-->
@@ -505,37 +476,47 @@ const primaryPlatform = computed(
-
+
- Mobile · Coming soon
+ Mobile · Preview
Native iOS & Android
- Native mobile clients are in development. Same agents you run on the
- desktop, in your pocket.
+ Same agents you run on the desktop, in your pocket.
-
+ Native iOS and Android clients are in active development. The source
+ lives in
+ packages/agents-mobile
+ — clone the repo and run the Expo dev build today, or watch the repo
+ to be notified when the public App Store and Google Play listings
+ ship with v1.
+
+
+
+
+
@@ -659,12 +640,6 @@ const primaryPlatform = computed(
.ad-icon--android {
--icon-url: url('https://api.iconify.design/simple-icons/android.svg');
}
-.ad-icon--appstore {
- --icon-url: url('https://api.iconify.design/simple-icons/appstore.svg');
-}
-.ad-icon--googleplay {
- --icon-url: url('https://api.iconify.design/simple-icons/googleplay.svg');
-}
/* ── §1 hero ────────────────────────────────────────────────── */
@@ -739,9 +714,10 @@ const primaryPlatform = computed(
row 2 — a single `Preview` pill positioned beneath the iOS +
Android pair (columns 4–5), softly marking the native
mobile apps as not-yet-public.
- On narrow viewports the row collapses to 3 columns, with iOS +
- Android wrapping onto a second visual row that keeps the
- preview pill anchored beneath them. */
+ The 5-column layout is preserved on narrow viewports — the per-
+ glyph `minmax(56px, auto)` columns compress comfortably down to
+ ~360px without label truncation, so a responsive collapse to a
+ 2-row grid would only add complexity for no readability gain. */
.ad-hero-platforms {
display: grid;
@@ -942,78 +918,45 @@ const primaryPlatform = computed(
gap: 6px;
}
-/* ── §7b mobile ─────────────────────────────────────────────── */
-
-.ad-mobile-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 20px;
-}
+/* ── §7b mobile · preview ───────────────────────────────────── *
+ Single card replacing the previous two-card iOS/Android grid.
+ Body text + GitHub CTA — body and actions sit side-by-side on
+ desktop, stack vertically below 768px. */
-.ad-mobile-card {
+.ad-mobile-preview-card {
display: grid;
- grid-template-columns: 40px minmax(0, 1fr) auto;
+ grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
- gap: 14px;
- padding: 20px;
+ gap: 24px;
+ padding: 24px 28px;
border: 1px solid var(--vp-c-divider);
border-radius: 16px;
background: var(--vp-c-bg);
+ max-width: 920px;
}
-.ad-mobile-icon {
- font-size: 22px;
- width: 40px;
- height: 40px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- border-radius: 10px;
- background: var(--vp-c-bg-soft);
- border: 1px solid var(--vp-c-divider);
- color: var(--vp-c-text-1);
-}
-
-.ad-mobile-icon .ad-icon {
- font-size: 22px;
-}
-
-.ad-mobile-name {
+.ad-mobile-preview-body {
margin: 0;
- font-size: 18px;
- font-weight: 600;
- letter-spacing: -0.01em;
- color: var(--vp-c-text-1);
+ font-size: 15px;
+ line-height: 1.6;
+ color: var(--vp-c-text-2);
+ text-wrap: pretty;
}
-.ad-soon-pill {
- padding: 3px 9px;
- font-size: 10px;
- letter-spacing: 0.1em;
- text-transform: uppercase;
- background: color-mix(in srgb, var(--vp-c-brand-1) 16%, transparent);
+.ad-mobile-preview-link {
color: var(--vp-c-brand-1);
- border-radius: 999px;
- white-space: nowrap;
- justify-self: end;
+ text-decoration: none;
+ border-bottom: 1px solid
+ color-mix(in srgb, var(--vp-c-brand-1) 30%, transparent);
}
-.ad-store-badge {
- grid-column: 1 / -1;
- display: inline-flex;
- align-items: center;
- gap: 10px;
- padding: 10px 14px;
- border-radius: 10px;
- background: var(--vp-c-bg-soft);
- color: var(--vp-c-text-2);
- font-size: 14px;
- font-weight: 500;
+.ad-mobile-preview-link:hover {
+ border-bottom-color: var(--vp-c-brand-1);
}
-.ad-store-glyph {
- font-size: 18px;
- color: var(--vp-c-text-1);
+.ad-mobile-preview-actions {
+ display: flex;
+ align-items: center;
}
/* ── §7c canary ─────────────────────────────────────────────── *
@@ -1108,8 +1051,7 @@ const primaryPlatform = computed(
/* ── Responsive ─────────────────────────────────────────────── */
@media (max-width: 900px) {
- .ad-desktop-grid,
- .ad-mobile-grid {
+ .ad-desktop-grid {
grid-template-columns: 1fr;
}
}
@@ -1124,6 +1066,13 @@ const primaryPlatform = computed(
.ad-hero-text {
font-size: 18px;
}
+ .ad-mobile-preview-card {
+ grid-template-columns: 1fr;
+ padding: 20px 22px;
+ }
+ .ad-mobile-preview-actions {
+ justify-self: start;
+ }
}
@media (max-width: 560px) {
@@ -1136,9 +1085,6 @@ const primaryPlatform = computed(
max-width: 280px;
margin: 0 auto;
}
- .ad-mobile-card {
- grid-template-columns: 36px minmax(0, 1fr) auto;
- }
.ad-canary-item {
grid-template-columns: 20px minmax(0, 1fr);
}
From e6259b8884c8867dd7524c5d26c182953e7adb0d Mon Sep 17 00:00:00 2001
From: Sam Willis
Date: Wed, 3 Jun 2026 10:43:41 +0200
Subject: [PATCH 07/75] =?UTF-8?q?feat(website):=20/app=20phase=203=20?=
=?UTF-8?q?=E2=80=94=20three=20ways=20+=20scenarios=20+=20built=20for=20bu?=
=?UTF-8?q?ilders?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Lands the three deepest copy sections on the /app rewrite:
§3 "Three ways to use it." — three side-by-side mode cards (Code locally
· Attach remotely · Build with the SDK), each with the locked body copy,
a four-item "You can:" anchor list, and a brand-tinted lucide icon. A
muted centred strip below the grid restates the one-integrated-platform
takeaway.
§3.5 "What this looks like in practice." — four scenario cards in a 2×2
grid on a dark Section. Each card stacks a 16:9 placeholder illustration
slot (filled in phase 5), a `Touches · …` mono eyebrow, the scenario
title, and the locked body paragraph. "Software factory" appears in
scenario 1 as planned.
§6 "Built for builders." — six compact 3×2 cards covering tile workspace,
state explorer, entity timeline, MCP & skills, local discovery and the
CLI installer. Each carries a lucide icon, short feature description and
a "Use it to…" hint anchored to the card bottom by a dashed divider.
Adds nine lucide Iconify mask URLs (code-2, radio-tower, microscope,
layout-grid, database, history, cable, radar, terminal) following the
existing `.ad-icon--*` pattern. Adds responsive breakpoints so each grid
collapses sensibly: modes 3 → 2 → 1, scenarios 2 → 1, builders 3 → 2 → 1.
All claims are still backed by the §5 mapping in APP_PAGE_PLAN.md; no
new features promised. Section orientation comment marks §3 / §3.5 / §6
as complete, leaving §4 / §5 for phase 4.
Co-authored-by: Cursor
---
.../app-download/AppDownloadPage.vue | 695 +++++++++++++++++-
1 file changed, 670 insertions(+), 25 deletions(-)
diff --git a/website/src/components/app-download/AppDownloadPage.vue b/website/src/components/app-download/AppDownloadPage.vue
index c76a165525..42324b7464 100644
--- a/website/src/components/app-download/AppDownloadPage.vue
+++ b/website/src/components/app-download/AppDownloadPage.vue
@@ -321,12 +321,12 @@ const primaryPlatform = computed(
the same across phases, so each fill-in is a localised diff.
Phase ownership for each section:
- §2 visual strap → phase 2 placeholder pair · phase 5 real shots
- §3 three ways to use it → phase 3
- §3.5 scenarios → phase 3
- §4 multi-device → phase 4
- §5 bundled Horton → phase 4
- §6 built for builders → phase 3
+ §2 visual strap → phase 2 placeholder pair · phase 5 real shots
+ §3 three ways to use it → phase 3 ✓
+ §3.5 scenarios → phase 3 ✓ copy · phase 5 illustrations
+ §4 multi-device → phase 4
+ §5 bundled Horton → phase 4
+ §6 built for builders → phase 3 ✓
-->
@@ -356,22 +356,218 @@ const primaryPlatform = computed(
-
+
-
+ What you can do
+ Three ways to use it.
+
+
+
+
+
+
+
Code locally
+
Code with Horton, locally.
+
+ Horton ships in the desktop. Pick a model (Anthropic, OpenAI,
+ DeepSeek, Moonshot, Codex). Pick a working directory. Chat to a
+ coding agent that can read, write, edit, run bash, search the
+ web, fetch URLs, and spawn parallel workers.
+
+
You can
+
+
+ Refactor a folder of TypeScript files while Horton runs
+ parallel workers per module.
+
+
+ Bisect a regression by spawning a worker to reproduce, then
+ another to fix.
+
+
+ Scaffold a fresh project with /init, then
+ iterate with /quickstart.
+
+
+ Review a diff or a PR description and ask Horton to draft
+ follow-ups.
+
+
+
+
+
+
+
+
+
Attach remotely
+
Attach to remote sessions.
+
+ Connect to any agents-server — your own, your team's, or
+ Electric Cloud. Sessions spawned by CI, webhooks, GitHub
+ issues, cron or your software factory appear live in the
+ sidebar. Pick one up on the desktop, follow it on your phone,
+ stop or steer it from either.
+
+
You can
+
+
+ Triage a GitHub-issue-spawned Horton session on your phone,
+ finish it from your laptop.
+
+
+ Watch a CI agent open a PR, push a steering message before
+ it merges.
+
+
+ Pause a long-running cron-triggered pipeline and resume from
+ where it left off.
+
+
+ Hand a session off to a teammate by sharing the entity URL —
+ the multi-user view sees the same stream.
+
+
+
+
+
+
+
+
+
Build with the SDK
+
Build agents on the SDK.
+
+ It's also the dev tool for the entities you write
+ with the SDK (@electric-ax/agents-runtime). Live
+ state explorer, entity timeline, fork-from-here, manifest
+ drawer, MCP servers, skills, and a tile workspace for
+ following parent + workers in parallel.
+
+
You can
+
+
+ Drop in on a stuck entity and watch its inbox / runs /
+ manifest update in real time.
+
+
+ Fork a session at any past point to A/B test a prompt or
+ tool change.
+
+
+ Step through a failed worker's tool calls without
+ redeploying the host app.
+
+
+ Run a parent and three children side-by-side in a tile
+ workspace, then deep-link the layout.
+
+
+
+
+
+
+ One integrated platform — code, attach, and build in one app.
+
-
-
-
+
+
+ Scenarios
+ What this looks like in practice.
+
+ Four short stories that span the three modes above. None of them
+ require code you don't have today.
+
+
+
+ GitHub issue → CI spawns Horton → triage on phone → finish on
+ desk
+
+
+ A new GitHub issue (or issue_comment, or a
+ workflow_dispatch from CI) opens a new agent
+ session on Electric Cloud. You get a notification on your
+ phone, skim the diff Horton drafted, push back a steering
+ message ("don't touch the migration files"), then pick up on
+ your laptop to merge.
+
+ Open the desktop, point Horton at a repo, ask for a rename
+ across packages. Horton spawns a worker per package, you
+ watch all four in a 2×2 tile workspace, fork the one that
+ took the wrong turn, ship the diff.
+
+
+
+
+
+
+
+
+ Touches · SDK · state explorer · timeline · fork · MCP
+
+
+ Build an agent on the SDK, debug it without a redeploy
+
+
+ You ship a custom summarizer entity with the
+ SDK. It's getting stuck on certain inputs. Open the state
+ explorer, watch its shared state evolve, fork the failing
+ session, change the prompt, replay.
+
+
+
+
+
+
+
+
+ Touches · Cloud · cron wake · mobile · fork · send
+
+
+ Cron-triggered overnight pipeline
+
+
+ Cron kicks off a nightly research agent on the cloud server.
+ Open the mobile app in the morning, see what it found, hand
+ off the most promising lead to a fresh session for follow-up.
+
+
+
@@ -392,13 +588,107 @@ const primaryPlatform = computed(
/>
-
+
-
+ Dev tools
+ Built for builders.
+
+ When you ship your own entities on the Electric Agents infra and
+ SDK (@electric-ax/agents-runtime), the same app
+ becomes the dev tool you'd otherwise have to write yourself.
+
+
+
+
+
+
+
+
Tile workspace
+
+ Split right / down cycle, find, ?layout= deep
+ link.
+
+
+ Use it to follow a parent and three workers in parallel
+ without losing context.
+
+
+
+
+
+
+
+
State explorer
+
+ Live view of every shared-state source per entity.
+
+
+ Use it to watch shared state evolve while your agent runs.
+
+
+
+
+
+
+
+
Entity timeline
+
+ Runs, inbox, manifests, fork-from-here.
+
+
+ Use it to fork at any past point to A/B test a change.
+
-
+
+ Multi-device
+ Multi-device, multi-user.
+
+ Agents run on the server, not the client. The desktop and mobile apps
+ are live views into the same Electric streams.
+
+
+
+
+
+
+
+
+
Same session, every device
+
+ Open the same session from your laptop and your phone, hand work
+ off between devices, follow a long-running run from wherever
+ you happen to be.
+
+
+
+
+
+
+
+
Shared with your team
+
+ Sign in once with GitHub or Google; your Electric Cloud workspaces
+ appear automatically. Share a session with a teammate by sharing
+ its URL — the multi-user view sees the same stream.
+
+
+
+
+
+
+
+
Pull-wake runners
+
+ The desktop can register itself as a pull-wake runner, so your
+ laptop becomes a worker for your cloud agents. Close the lid and
+ they finish on the next runner that comes online.
+
+
+
-
-
-
+
+
+ Bundled agent
+ Horton, in the box.
+
+ A friendly, capable general-purpose chat agent with code-editing
+ superpowers — no server-side setup required.
+
+
+
+
+
+
+
+
Pick your provider.
+
+ Bring your own API key (stored in the OS keychain via
+ SecretStore), or sign in to Codex. Anthropic,
+ OpenAI, DeepSeek and Moonshot for models; Brave Search and
+ E2B for tools — keys never leave your machine.
+
+
+
+
+
+
+
+
Pick your working directory.
+
+ Horton reads and edits whatever you point it at — no per-project
+ install. Bash, web search, fetch URL, spawn worker, send,
+ skills: all in the bundled toolset.
+
+
+
+
+
+
+
+
Skills + slash commands.
+
+ Type /quickstart to load the guided onboarding
+ skill; install your own skills to ship workflows to your team.
+ Slash commands are first-class — discoverable, composable,
+ shareable.
+
+
+
+
+
+
Things you can ask Horton to do
+
+
+
+
+
+
+
Chat
+
+
+
Summarise this docs page
+
Plan a refactor
+
Explain this stack trace
+
Draft a launch tweet
+
+
+
+
+
+
+
+
+
Code
+
+
+
Refactor this file
+
Write tests for X
+
Bisect this regression
+
Apply the same change across these 4 files
+
+
+
+
+
+
+
+
+
Research
+
+
+
Find the latest spec for Y
+
Diff what changed since v1.2
+
Pull the open PRs touching this dir
+
+
+
+
+ with the SDK). Each card: lucide icon + sentence-form title + body
+ + 3-item "You can:" bullet list. No card-level eyebrows — the
+ titles carry the categorization on their own. The strip beneath
+ the grid restates the one-integrated-platform line as the
+ section's takeaway. Body strings locked in APP_PAGE_PLAN.md §3. -->
- What you can do
Three ways to use it.
Horton ships in the desktop. Pick a model (Anthropic, OpenAI,
@@ -393,12 +390,8 @@ const primaryPlatform = computed(
another to fix.
- Scaffold a fresh project with /init, then iterate
- with /quickstart.
-
-
- Review a diff or a PR description and ask Horton to draft
- follow-ups.
+ Use /quickstart to learn Electric Agents by building
+ a multi-agent tutorial app.
Connect to any agents-server — your own, your team's, or Electric
@@ -429,10 +421,6 @@ const primaryPlatform = computed(
Pause a long-running cron-triggered pipeline and resume from where
it left off.
-
- Hand a session off to a teammate by sharing the entity URL — the
- multi-user view sees the same stream.
-
It's also the dev tool for the entities you write with the
@@ -463,10 +450,6 @@ const primaryPlatform = computed(
Step through a failed worker's tool calls without redeploying the
host app.
-
- Run a parent and three children side-by-side in a tile workspace,
- then deep-link the layout.
-
@@ -486,7 +469,6 @@ const primaryPlatform = computed(
interlude. Body strings are locked in APP_PAGE_PLAN.md §3.5;
do not edit them here without updating that doc. -->
- Scenarios
What this looks like in practice.
Four short stories that span the three modes above. None of them require
@@ -505,12 +487,10 @@ const primaryPlatform = computed(
GitHub issue → CI spawns Horton → triage on phone → finish on desk
- Your software factory opens a new agent session on Electric Cloud —
- a fresh GitHub issue, an issue_comment, or a
- workflow_dispatch from CI. You get a notification on
+ Your software factory opens an agent session on Electric Cloud from
+ a fresh GitHub issue or a CI dispatch. You get a notification on
your phone, skim the diff Horton drafted, push back a steering
- message ("don't touch the migration files"), then pick up on your
- laptop to merge.
+ message, then pick up on your laptop to merge.
Open the desktop, point Horton at a repo, ask for a rename across
- packages. Horton spawns a worker per package, you watch all four in
- a 2×2 tile workspace, fork the one that took the wrong turn, ship
- the diff.
+ packages. Horton spawns a worker per package; you fork the one that
+ took the wrong turn and ship the diff.
@@ -543,10 +522,9 @@ const primaryPlatform = computed(
Build an agent on the SDK, debug it without a redeploy
- You ship a custom summarizer entity with the SDK. It's
- getting stuck on certain inputs. Open the state explorer, watch its
- shared state evolve, fork the failing session, change the prompt,
- replay.
+ You ship a custom summarizer entity with the SDK and
+ it's getting stuck on certain inputs. Open the state explorer, fork
+ the failing session, change the prompt, replay.
Cron kicks off a nightly research agent on the cloud server. Open
- the mobile app in the morning, see what it found, hand off the most
- promising lead to a fresh session for follow-up.
+ the mobile app in the morning and hand off the most promising lead
+ to a fresh session.
@@ -576,7 +554,6 @@ const primaryPlatform = computed(
across the subtitle and the three pillars below the diagram so
the body reads as scannable rather than a wall of prose. -->
- Multi-device
Multi-device, multi-user.
Agents run on the server, not the client. The desktop and mobile apps
@@ -644,7 +621,6 @@ const primaryPlatform = computed(
rung) but consistent; in light mode it's a pronounced dark
strip on a light page. -->
- Bundled agent
Horton, in the box.
A friendly, capable general-purpose chat agent with code-editing
@@ -658,10 +634,9 @@ const primaryPlatform = computed(
Pick your provider.
- Bring your own API key (stored in the OS keychain via
- SecretStore), or sign in to Codex. Anthropic, OpenAI,
- DeepSeek and Moonshot for models; Brave Search and E2B for tools —
- keys never leave your machine.
+ Bring your own API key (stored in the OS keychain), or sign in to
+ Codex. Anthropic, OpenAI, DeepSeek and Moonshot for models; Brave
+ Search and E2B for tools.
- Type /quickstart to load the guided onboarding skill;
- install your own skills to ship reusable workflows to your team.
+ Type /quickstart to learn Electric Agents itself; write
+ your own skills to ship reusable workflows.
@@ -743,14 +718,13 @@ const primaryPlatform = computed(
+ Each card: lucide icon + 2-4 word title + one-sentence body.
+ Intentionally terse spec-sheet rhythm — the page already has
+ scenarios above, so cards here just identify what's in the
+ box. Every feature listed here is shipping today; see the
+ claim→code mapping in APP_PAGE_PLAN.md §5 / §6 if you're
+ tempted to add anything else. -->
- Dev tools
Built for builders.
When you ship your own entities on the Electric Agents infra and SDK
@@ -767,10 +741,6 @@ const primaryPlatform = computed(
Split right / down cycle, find, ?layout= deep link.
-
- Use it to follow a parent and three workers in parallel without
- losing context.
-
- Use it to drop electric on your PATH without touching
- npm.
-
@@ -1380,14 +1333,6 @@ const primaryPlatform = computed(
font-size: 22px;
}
-.ad-modes-eyebrow {
- margin: 0 0 8px;
- font-size: 11px;
- letter-spacing: 0.1em;
- text-transform: uppercase;
- color: var(--vp-c-text-3);
-}
-
.ad-modes-title {
margin: 0 0 12px;
font-size: 22px;
@@ -1818,21 +1763,10 @@ const primaryPlatform = computed(
text-wrap: pretty;
}
-.ad-builders-body code,
-.ad-builders-hint code {
+.ad-builders-body code {
font-size: 12px;
}
-.ad-builders-hint {
- margin: auto 0 0;
- padding-top: 12px;
- font-size: 13px;
- line-height: 1.55;
- color: var(--vp-c-text-3);
- border-top: 1px dashed var(--vp-c-divider);
- text-wrap: pretty;
-}
-
/* ── §7a desktop ────────────────────────────────────────────── */
.ad-desktop-grid {
From 5d27d762654c8a9489123955abdcea1bc4d395b9 Mon Sep 17 00:00:00 2001
From: Sam Willis
Date: Wed, 3 Jun 2026 12:32:13 +0200
Subject: [PATCH 13/75] =?UTF-8?q?fix(website):=20/app=20hero=20polish=20?=
=?UTF-8?q?=E2=80=94=20divider=20+=20smaller=20pill=20+=20relocate=20relea?=
=?UTF-8?q?se=20notes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Three small hero-row tweaks raised in review:
- Add a thin vertical divider in the 28px gap between the desktop trio
(macOS · Windows · Linux) and the mobile pair (iOS · Android) in the
§1 platform glyph row. Pseudo-element on the iOS glyph (4th child),
absolutely positioned at -14px so it sits centred in the column gap.
Height ~22px matches the icon glyph so the line reads as part of the
row rather than a section divider.
- Shrink the `Preview` pill under the mobile pair: font-size 10px → 8px,
padding 3px/10px → 1px/7px, letter-spacing 0.12em → 0.14em to keep the
text readable at the smaller size. The pill is now visibly subordinate
to the iOS/Android labels above it instead of competing with them.
- Drop the `Release notes` link from the hero and put it under the §7a
desktop download grid (between the cards and the Unsigned Preview
aside) where it pairs naturally with the download CTAs. Rename
`.ad-hero-meta` → `.ad-download-meta` to reflect the new home.
Co-authored-by: Cursor
---
.../app-download/AppDownloadPage.vue | 53 +++++++++++++------
1 file changed, 37 insertions(+), 16 deletions(-)
diff --git a/website/src/components/app-download/AppDownloadPage.vue b/website/src/components/app-download/AppDownloadPage.vue
index 69206f8608..2782fcd6a4 100644
--- a/website/src/components/app-download/AppDownloadPage.vue
+++ b/website/src/components/app-download/AppDownloadPage.vue
@@ -301,16 +301,6 @@ const primaryPlatform = computed(
>Preview
-
-