You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: web-actor architecture, plus actor_list and message_actor oneShot
The main agent becomes an orchestrator that delegates each environment
(WebVM, notebook, app, open web) to a per-environment sub-agent (an actor)
holding only that environment's tools. One delegation channel,
message_actor; the web actor is the single entry point for all web work.
Three things get better:
- Less context on the main agent: per-environment detail loads only on
delegation, and the redundant web tools collapse into the web actor.
- Fewer tool calls: actor_list replaces five list tools, and message_actor
oneShot drops a model turn on single-round delegations.
- Real isolation: the environment tools are off the main agent entirely,
and untrusted page/VM/fetch output reaches the orchestrator only as a
fenced reply.
Delegations run async and in parallel, show as inline cards you can stop,
report their cost, and survive a service-worker restart via a durable
inbox. Also lands the staged open-PR backlog (PDF reading, on-device OCR,
browser-native VM networking, session auto-resume, whole-extension type
coverage) and bumps the version to 0.2.0. See CHANGELOG.md [0.2.0].
|**`e`** · red |[`peerd-egress`](extension/peerd-egress/README.md)| Security — the vault, the egress chokepoint, the denylist, the audit log |
216
221
|**`e`** · amber |[`peerd-engine`](extension/peerd-engine/README.md)| Sandboxes — WebVMs, Notebooks, Apps, and the headless worker |
217
-
|**`r`** · green |[`peerd-runtime`](extension/peerd-runtime/README.md)| The agent — loop, tools, do/get/check, memory, skills, review, goal mode, voice |
222
+
|**`r`** · green |[`peerd-runtime`](extension/peerd-runtime/README.md)| The orchestrator — agent loop, tools, the `message_actor` delegation channel, actors, sessions, memory, skills, review, goal mode, voice |
218
223
|**`d`** · magenta |[`peerd-distributed`](extension/peerd-distributed/README.md)| The dweb — the peer-to-peer network (preview channel only) |
219
224
220
225
The brand IS the architecture: cross-module imports go through each
@@ -227,15 +232,24 @@ module's `index.js`, never deep paths; nothing outside
227
232
peerd's safety is *who is allowed to do what*: small boundaries
228
233
enforced by the browser platform, not by peerd's own crypto. Two
229
234
principles run through all of it: **the agent that holds your keys never
230
-
touches a raw page or runs untrusted code**, and **the agent never gets the
231
-
final word on correctness; every action is verified against the live page
232
-
before it counts as done.**
235
+
touches a raw page or runs untrusted code** — the environment-operating
236
+
tools are not even attached to it, they belong to per-environment actor
237
+
sub-agents — and **the agent never gets the final word on correctness;
238
+
every action is verified against the live page before it counts as done.**
239
+
240
+
The orchestrator delegates; an actor does the work. Each tab, VM,
241
+
notebook, and app is owned by one actor that holds only that
242
+
environment's tools, runs without keys, and hands back a fenced summary.
243
+
So isolation between environments is structural, not a convention: even a
244
+
fully prompt-injected main agent cannot reach an environment it was not
245
+
asked to, because it never held the tool.
233
246
234
247
| Actor | Trusted with | Never |
235
248
|---|---|---|
236
249
|**The vault** (`peerd-egress/vault`) | your API keys + secrets, decrypted only after Touch ID / passkey / passphrase unlock; idle auto-lock | leaving the device — keys go only to the provider you chose |
237
-
|**The main agent** (`peerd-runtime/loop`) | the conversation, planning, tool dispatch | reading raw page bytes or running untrusted code directly |
238
-
|**The disposable runner** (`peerd-runtime/runner`) | driving + reading the page via do/get/check | holding keys or its own network; its output returns `wrapUntrusted`-fenced |
250
+
|**The orchestrator** (`peerd-runtime/loop`) | the conversation, planning, delegating a goal to an actor via `message_actor`| holding any environment's tools, reading raw page bytes, or running untrusted code directly |
251
+
|**An actor** (`peerd-runtime/subagent`) | driving ONE tab / VM / notebook / app — it exclusively holds that environment's tools, keyless | touching another environment, holding keys, or returning anything to the orchestrator except a `wrapUntrusted`-fenced summary |
252
+
|**The disposable runner** (`peerd-runtime/runner`) | driving + reading a page keyless via do/get/check — the lineage a web actor and subagents use | holding keys or its own network; its output returns `wrapUntrusted`-fenced |
239
253
|**The egress chokepoint** (`safeFetch` / `webFetch`) | every outbound byte — provider allowlist + denylist + SSRF guard | being bypassed; a bare `fetch` is lint-forbidden |
240
254
|**The sandboxes** (WebVM · Notebook · App) | running code — V8 isolates + opaque-origin iframes | extension access; their HTTP routes back through egress |
241
255
|**Web content**| nothing by default | being trusted — all of it is fenced as untrusted input |
@@ -306,14 +320,20 @@ see, focus, and close, grouped under "peerd" in the tab strip and
306
320
surviving browser restarts: the WebVM, the Notebook, and the App. The
307
321
fourth, the headless worker (`js_run`), runs the Notebook's sealed worker
308
322
offscreen with no tab: ephemeral, for the agent's own quick compute. The
309
-
agent picks the lightest kind that fits the task.
323
+
orchestrator picks the lightest kind that fits the task, bootstraps the
324
+
instance, and then delegates the work to that instance's actor; the
325
+
tool lists below are the surface an actor drives, not the main agent. One
326
+
main-agent tool spans all of them: **`actor_list`** enumerates every
327
+
addressable actor — WebVMs, Notebooks, Apps, open tabs, and API
328
+
integrations — each tagged with its `type` and the handle to pass to
329
+
`message_actor`, so discovery is one call instead of five.
310
330
311
331
**WebVM**: CheerpX-emulated Debian (sandboxed Linux). Own disk (IDB
312
332
overlay), own bash, own POSIX. ~10s first boot. Use it when you need
0 commit comments