Skip to content

Commit 970a084

Browse files
committed
docs: add PLAN.md recording the release/spike/adapter roadmap
1 parent b863efb commit 970a084

1 file changed

Lines changed: 142 additions & 0 deletions

File tree

‎PLAN.md‎

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Where headless goes next
2+
3+
This is the plan for the next few months, written so anyone on the team can follow it.
4+
It records what we decided, why we decided it, and the order we work in.
5+
6+
## What headless is
7+
8+
Headless gives AI agents a real browser through a small command set:
9+
10+
```
11+
headless click --role button --name Continue
12+
```
13+
14+
No screenshots. No pixel coordinates. No Playwright scripts.
15+
The agent asks for things by meaning and gets back bounded, inspectable results.
16+
17+
Two engines already exist behind one contract:
18+
19+
```
20+
one protocol (JSON v0.5 over a private Unix socket)
21+
|
22+
+---------------+----------------+
23+
| |
24+
macOS host Linux host
25+
WKWebView app sandboxed Chromium
26+
(ships with the OS) driven over CDP fd 3/4
27+
```
28+
29+
The shared code lives in `apps/headless/Sources/HeadlessProtocol/`.
30+
Each engine only implements what makes it different. That split is the whole reason
31+
this plan works, so protect it.
32+
33+
## The decision: no rewrite
34+
35+
We looked at rewriting the core in Rust or Go to get Windows and "better performance".
36+
We are not doing that. Here is the honest reasoning.
37+
38+
Performance is not a reason. The benchmark numbers on our own site show agent token
39+
use is dominated by the browser, not by our control plane. Rewriting the socket layer
40+
in Rust would change nothing a user can measure.
41+
42+
Reliability is not a reason either. About ten thousand lines of Swift already pass the
43+
protocol suite, the runtime suite, and E2E tests on two platforms. A rewrite resets
44+
all of that to zero for months.
45+
46+
Windows was the one real argument for a rewrite, because Swift's Windows support is
47+
weak. But Edge ships on every Windows machine and speaks the same CDP protocol our
48+
Linux host already uses. So Windows becomes a third engine adapter, not a rewrite.
49+
We still test the ground truth first, with a spike (step 1 below). If the spike fails,
50+
we port only the shared core to Rust, never the whole product.
51+
52+
## The plan
53+
54+
```
55+
step 0 step 1 step 2 step 3 step 4
56+
ship the Windows add the adapter make each OS hand off
57+
pending work spike OR do the port feel native features
58+
-------------- --------------- -------------------- ---------------- ----------
59+
release v1.1.0 compile the spike passes: winget/MSI C7 review (#35)
60+
close docs shared core keep Swift, add install paths G-series ideas (#54)
61+
debt (#53) on Swift for a Windows engine config paths assigned to
62+
Windows in a adapter code signing SarthakWade
63+
throwaway test spike fails:
64+
branch ADR, then port
65+
only HostCore to
66+
Rust
67+
```
68+
69+
### Step 0: release and docs
70+
71+
Everything since v1.0.2 is unreleased. That is risk piling up, so this goes first.
72+
73+
- Cut the release (#45)
74+
- Close the docs debt (#53): @eN contract, session model, stale paths
75+
76+
### Step 1: the Windows spike
77+
78+
One week, throwaway code, no commits to main. Try to build
79+
`Sources/HeadlessProtocol/` with the Swift toolchain on Windows.
80+
81+
Two outcomes, both fine:
82+
83+
```
84+
spike builds? outcome
85+
--------------- --------------------------------------
86+
yes keep Swift. Write the third adapter.
87+
no write the ADR, port only the shared
88+
core to Rust. Protocol spec, runtime
89+
JS, and all tests stay as they are.
90+
```
91+
92+
Either way we win, because the protocol and the test suites survive untouched.
93+
94+
### Step 2: the adapter or the port
95+
96+
If Swift survived the spike, we add a Windows engine adapter. Edge is Chromium,
97+
so most of `LinuxHost/BrowserProcess.swift` and `CDP.swift` carries over. Only
98+
process spawning and paths differ.
99+
100+
If the spike failed, we write the architecture decision entry first, then port
101+
the shared core to Rust. Scope stays tight: dispatcher, CLI parser, artifacts,
102+
transport. Nothing else moves.
103+
104+
### Step 3: native packaging
105+
106+
Code gets a product onto a machine. Packaging makes it feel like it belongs there.
107+
108+
| | macOS | Linux | Windows |
109+
|---|---|---|---|
110+
| browser | WKWebView, built in | system Chromium | Edge, built in |
111+
| install | brew cask | curl script | winget / MSI |
112+
| config | ~/Library | XDG dirs | %APPDATA% |
113+
| signing | notarized | SHA256SUMS | Authenticode |
114+
115+
Most of this table is packaging work, not engineering. That is the point.
116+
117+
### Step 4: features (SarthakWade)
118+
119+
Once steps 0 to 3 land, feature work starts:
120+
121+
- hover, drag, select, isolation from the design review (#35)
122+
- committed ideas from the tracking issue (#54)
123+
124+
## Rules that do not bend
125+
126+
These live in AGENTS.md and they hold during every step above:
127+
128+
1. no arbitrary JavaScript verb, no TCP listener, no debug port
129+
2. fail closed on anything unknown
130+
3. artifacts never overwrite and never escape their store
131+
4. flows never record fill values
132+
5. everything bounded reports its truncation
133+
134+
Any change to the agent facing contract needs an entry in
135+
`docs/roadmap/architecture-decisions.md` before the code lands.
136+
137+
## What we deliberately skipped
138+
139+
- bun instead of pnpm: churn, no gain, CI already gates on pnpm
140+
- cosmetic folder renames: if the spike leads to a Rust core, those files
141+
get deleted anyway
142+
- the website (#47 to #51): deprioritized until the core plan lands

0 commit comments

Comments
 (0)