From 12cea7ecdd9f3468b7b47869ee8a3e432040f160 Mon Sep 17 00:00:00 2001 From: Karn Date: Sun, 27 Sep 2026 02:27:42 +0530 Subject: [PATCH 01/13] docs: reins do design spec Co-Authored-By: Claude Opus 5.5 --- .../specs/2026-09-27-reins-do-design.md | 404 ++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-27-reins-do-design.md diff --git a/docs/superpowers/specs/2026-09-27-reins-do-design.md b/docs/superpowers/specs/2026-09-27-reins-do-design.md new file mode 100644 index 0000000..1d3453d --- /dev/null +++ b/docs/superpowers/specs/2026-09-27-reins-do-design.md @@ -0,0 +1,404 @@ +# reins do — design + +Date: 2026-09-27 +Status: approved in chat (sections 1–4 + review fixes), pending spec review + +## Problem + +An agent driving reins pays one full LLM turn per browser action: +`reins snapshot` → think → `reins click` → think → … A 15-step form takes +minutes. [browser-use/jev-ultrafast](https://github.com/browser-use/jev-ultrafast) +(MIT) shows the alternative: TypeSafe's **Jev**, a "System One" model that +answers typed multiple-choice questions in ~180 ms, picks the next operation +and its target in one request. Their Google Flights run takes 7.1 s end to end. + +## Principle + +The calling agent stays in charge. It delegates one bounded, verifiable +sub-task to `reins do`, supplies every text value itself (`--fill`), and +verifies the result. Jev only *chooses* among elements that were actually +observed. Model output never becomes a selector, coordinate, or code. There is +no text-generating model in the loop, so the only key is the user's TypeSafe key. + +## Scope + +In: + +- `~/.reins/credentials.json` holding the TypeSafe key, shared by all browsers +- `reins key set|status|clear typesafe` +- Popup "Jev" section: pitch, save/replace/remove key, status +- Extension→daemon `call` frame (key methods only) +- Extension methods `jev_observe` and `jev_act` +- Daemon Jev loop, `reins do`, `--continue`, `--confirm` +- Skill, web docs, PRIVACY/SECURITY/CWS disclosure, changeset +- Offline tests, extension browser tests, a manual paid benchmark + +Out (YAGNI for v1): + +- A text LLM / OpenRouter key (agent supplies text) +- A `low_confidence` stop (Jev target probabilities over 30+ elements are + routinely < 0.5; measure before adding) +- Per-site Jev opt-out or a built-in denylist (the user owns the key and the + decision; we disclose clearly instead) +- Masking filled values in later snapshots +- `TYPESAFE_API_KEY` env var +- Streaming step progress to the CLI +- iframes, shadow DOM, uploads, pop-up tabs, canvas (inherited jev limits) +- Background-tab execution without activation (tracked by #37's + focus-emulation spike) + +## Key storage and setup + +**File.** `~/.reins/credentials.json`, mode `0600`, written atomically +(temp file in same dir → `rename`). Shape: `{ "typesafe": "" }`. Only +the daemon reads it. Read fresh at the start of every `do` run, held in memory +only for that run. + +**CLI.** + +``` +reins key set typesafe # hidden prompt; or: echo "$K" | reins key set typesafe +reins key status # typesafe: set (••••a1b2) | not set +reins key clear typesafe +``` + +`set` validates the key with one minimal `systemone` call (a one-question +noul on a tiny state) before writing; a 401 prints `TypeSafe rejected this +key` and writes nothing. These are daemon RPCs (`key_set`, `key_status`, +`key_clear`) so the CLI and popup share one code path. + +**Popup "Jev" section** (under the connection block): + +- *No key:* one line of pitch: "Add a Jev key and `reins do` runs whole + browser tasks in seconds, not minutes." Link to + `https://console.typesafe.ai/keys` and to the docs' "what is sent" section. + Masked input + **Save**. +- *Key set:* `Jev ready · ••••a1b2` + **Replace** / **Remove**. +- *Daemon not connected:* input disabled, "Start reins to save a key". +- Save shows the daemon's validation error inline. + +**`call` frame (extension → daemon).** New in `@reins/protocol`: + +```ts +CallFrame = { type: "call", id: string, method: string, params: unknown } +``` + +The daemon answers with the existing `ResponseFrame` (same `id`). The +extension's `BridgeClient` gains a small pending-call map mirroring the +daemon's. The daemon accepts `call` only from an already-welcomed browser and +only for `key_set`, `key_status`, `key_clear`. Anything else → +`{ ok: false, error: { code: "METHOD_NOT_ALLOWED" } }`. Popup → background → +offscreen → WS, reusing the existing `chrome.runtime` message path. + +**Invariants.** The key is never returned by any method (status returns only +`set` + last 4), never sent to a page or the extension beyond the single +save hop, and never written to the audit log (`key_set` is logged with its +params dropped). + +## CLI + +``` +reins do "" [--fill name=value]... [--confirm "