Skip to content

Commit d457d3a

Browse files
authored
docs(specs): the site as a demo / lite app — reuse plan + portability map (#87)
Ariel's idea: make peerd.ai a demo/lite version of the extension — feature demos on the homepage, and a "try it out" page where the real agent loop drives the real sandboxes client-side (paste a key), minus browser control. This spec captures the de-risking from the extension side: a per-module portability map (provider 0/13 chrome-coupled, the agent loop IO-injected, the sandbox runtimes already proven standalone by notebook-seal.test.js + the live VM demo), the narrow host shims the lite app supplies (IDB-backed KV, in-page sandbox hosting, a `lite` tool manifest dropping browser-control, the existing vault key flow), both products, the in-page-host recipe (reuse buildWorkerSource, swap one bridge handler), and the one risk to validate early (provider CORS). The build lands in peerd-site (which vendors snapshots from here); this is the plan, documented where the reuse seams live.
1 parent 987bd68 commit d457d3a

1 file changed

Lines changed: 123 additions & 0 deletions

File tree

docs/specs/SITE-LITE-APP.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Spec: the peerd.ai site as a demo / lite app
2+
3+
> Status: **forward-looking spec** (no code here yet). The build lands in the
4+
> `peerd-site` repo, which vendors snapshots from this one. This file is the
5+
> reuse plan + portability map, written from the extension side so the seams are
6+
> documented where the code lives.
7+
8+
## Goal — two products
9+
10+
1. **Homepage feature demos.** Embedded, interactive widgets that show off the
11+
sandboxes without installing anything: a JS Notebook you can type into, a
12+
WebVM terminal, a client-side App. No agent, no key — just the runtimes.
13+
2. **A "try it out" lite app** (a separate page). Paste a model key (stays
14+
client-side), and the **real agent loop** drives the **real sandboxes** in
15+
the page — minus browser control (no tabs/DOM/CDP). The "lite" peerd.
16+
17+
## Why it's feasible — the architecture is already shaped for it
18+
19+
peerd's rule is *functional core, imperative shell — IO is injected*. The agent
20+
brains and the sandbox runtimes don't depend on the extension chassis; only the
21+
**hosting** (tabs, the service worker, `chrome.*`) does. Measured couplings
22+
(`grep` for `chrome.*` / `browser.<api>` / direct polyfill imports):
23+
24+
| Module | Files touching chrome/browser | Verdict |
25+
|---|---|---|
26+
| `peerd-provider` (adapters) | **0 / 13** | fully portable — injected `fetch` + a key |
27+
| `peerd-runtime/loop` (agent loop) | **1 / 16** | portable — IO-injected; `agent-loop.js`/`turn-driver.js` import no chassis |
28+
| `peerd-engine` (sandboxes) | **5 / 15** | runtimes portable; the registries/tab-trackers are the chassis-coupled part |
29+
| `notebook-tab` (sealed worker) | **1 / 6** | the worker/seal/std are portable; only the host file relays to the SW |
30+
| `peerd-egress` (vault, safeFetch, denylist, audit) | crypto portable; storage KV wraps `chrome.storage` | swap the KV backend to IDB |
31+
32+
### Most of the portability is *already proven* by existing tests
33+
- **Provider**: `tests/peerd-provider/*` run the adapters under bun with an
34+
injected `fetch` — i.e. already outside any extension.
35+
- **Sealed worker + realm seal**: `extension/tests/unit/notebook-tab/notebook-seal.test.js`
36+
spawns the production worker over **plain http** (the CDP harness, no
37+
extension) and plays the host side of the fetch bridge. The runtime already
38+
runs standalone.
39+
- **Registries**: `tests/peerd-engine/*-registry.test.ts` run on an injected
40+
storage stub.
41+
- **Vault crypto**: `tests/peerd-egress/vault*` run argon2 + WebCrypto under bun.
42+
- **WebVM**: per `CLAUDE.md`, the site **already vendors a live VM-demo runtime**
43+
CheerpX standalone is a shipped precedent.
44+
45+
So the lite app isn't a port — it's a **re-host**: supply the IO graph the loop
46+
already expects, minus browser control.
47+
48+
## The host shims the lite app must provide
49+
50+
1. **Storage backend.** `peerd-egress/storage/kv.js` is the seam — it abstracts
51+
`chrome.storage.local`. On web, back it with the existing `storage/idb.js`
52+
(IndexedDB). Everything above it (vault, denylist, audit, sessions,
53+
registries) is unchanged.
54+
2. **In-page sandbox hosting** (the one genuinely-new piece). Today each sandbox
55+
runs in an extension *tab*; the registries + tab-trackers manage those tabs.
56+
On web, host each runtime in an **in-page element** — the Notebook/`js_run`
57+
worker as a `Worker`, the App as an opaque `<iframe>`, the WebVM as the
58+
vendored CheerpX page/iframe. The registries' *catalog* logic is reusable;
59+
only the tab-host layer is replaced with an in-page-host layer.
60+
3. **Replace the SW message bridges with in-page handlers.** The worker's
61+
postMessage bridges (`fetch-request`, `opfs-request`, `subagent-request`,
62+
`display`, `log`) are handled today by `notebook-tab.js` — and `opfs-request`
63+
is **already handled in-page** (not via the SW). Only `fetch-request` relays
64+
to the SW (`sw/web-fetch``safeFetch`); on web, handle it in the page with a
65+
direct `safeFetch`/`fetch`. Reuse `buildWorkerSource` (the production worker
66+
assembly) verbatim — it's `import.meta.url`-relative and host-agnostic by
67+
design (the offscreen job-runner already reuses it).
68+
4. **A reduced tool manifest.** The machinery exists: `/tools` presets +
69+
`session.toolManifest` (`tools/manifests.js`), enforced in `gates.js`. Define
70+
a `lite` preset = the sandbox/compute/memory/web-read tools, **dropping**
71+
do/get/check, `page_*`, tabs, CDP — the browser-control surface. No new gating
72+
code; just a manifest.
73+
5. **Paste-a-key vault flow.** The vault already stores secrets client-side
74+
(IDB + passphrase/WebAuthn). The lite app's "plug in a test key" *is* the
75+
vault's existing key path — store the model key client-side, unlock per
76+
session. (Demo nuance: a "session-only, never persisted" mode is a one-line
77+
policy on top.)
78+
79+
## Product 1 — homepage feature demos
80+
81+
Each is one runtime + a thin UI, no agent:
82+
- **JS Notebook**: a code box → `buildWorkerSource` → in-page `Worker`
83+
`output-render.js` renders the result. The fetch bridge is in-page. This is the
84+
smallest, most self-contained demo and the recommended first build.
85+
- **WebVM terminal**: the already-vendored CheerpX runtime + the existing
86+
`vm-tab` terminal UI.
87+
- **App**: an opaque `<iframe>` running a client-side app the agent could build.
88+
89+
## Product 2 — the "try it out" lite app
90+
91+
Wire `makeTurnDriver` (the agent loop) with the host-supplied IO graph:
92+
- **Provide** (all portable): `vault`, `sessions`/`sessionState`/`sessionCache`,
93+
the provider stack (`callModel`, `resolveFailoverChain`, `costOf`, …),
94+
`memory`, `auditLog`, `safeFetch`, the tool dispatcher with the **lite**
95+
manifest, `settingsStore`, cost/temporal/system-prompt helpers.
96+
- **Stub or drop**: `browser`, `originOfTabUrl`, `uiPorts`/`uiConnected` (replace
97+
with an in-page event sink), `currentAppScope`, the do/get/check runner, and
98+
the dweb deps (`DWEB_ENABLED=false`, the `filterByDweb*`).
99+
- The streaming UI is the existing Mithril `sidepanel` components, re-mounted in
100+
the page (they're projections of state — already host-agnostic per DESIGN-12).
101+
102+
## Open questions / risks
103+
104+
- **Provider CORS.** Browser→API calls need permissive CORS. The extension sends
105+
`anthropic-dangerous-direct-browser-access`; the same applies on a web origin,
106+
and OpenRouter allows browser calls. **Validate early with a real key** — this
107+
is the likeliest surprise. (Can't be tested here without a key.)
108+
- **CheerpX weight + COOP/COEP.** The WebVM needs cross-origin isolation headers;
109+
the site already serves the VM demo, so this is solved there — confirm the
110+
lite-app page inherits the same headers.
111+
- **Key handling.** "Stays client-side" must be real: no key in any request to
112+
the site's own origin, only to the model API. A session-only (non-persisted)
113+
default is the safe demo posture.
114+
- **What to cut.** Browser control (the whole point of the extension) is absent;
115+
the lite app should say so plainly so it reads as a *demo*, not a lesser app.
116+
117+
## First steps (in `peerd-site`)
118+
1. Stand up the **JS Notebook homepage demo** — reuse `buildWorkerSource`, swap
119+
the fetch bridge to in-page. Smallest end-to-end proof of the re-host pattern.
120+
2. Add the **IDB-backed KV** shim; bring up the vault + a paste-a-key flow.
121+
3. Define the **`lite` tool manifest**.
122+
4. Wire `makeTurnDriver` with the host IO graph on the **"try it out"** page;
123+
start with one provider + the Notebook/`js_run` tool, then add VM/App.

0 commit comments

Comments
 (0)