|
| 1 | +# AGENTS.md — working on the Headless repo |
| 2 | + |
| 3 | +Guidance for any coding agent (and any human) contributing to this repository. |
| 4 | +Claude Code reads this via `CLAUDE.md`; Codex/OpenCode/Cursor/Amp read it |
| 5 | +directly. |
| 6 | + |
| 7 | +## What this project is |
| 8 | + |
| 9 | +Headless gives AI agents a persistent, safety-enforced browser driven by a |
| 10 | +semantic CLI (`headless click --role button --name Continue`) instead of |
| 11 | +Playwright scripts or screen coordinates. Two engines behind one contract: |
| 12 | +macOS WKWebView app, Linux sandboxed Chromium over the DevTools fd-3/4 pipe. |
| 13 | +Control plane is a private per-user Unix socket; there is deliberately **no |
| 14 | +TCP listener and no arbitrary-JavaScript verb**. |
| 15 | + |
| 16 | +Read before making non-trivial changes: |
| 17 | + |
| 18 | +- `docs/ROADMAP.md` — product plan, phases, definition of done. |
| 19 | +- `docs/roadmap/what-is-excellent.md` — contracts you must not weaken. |
| 20 | +- `docs/roadmap/architecture-decisions.md` — settled decisions (e.g. the core |
| 21 | + stays Swift; don't propose rewrites). |
| 22 | +- `docs/roadmap/improvements-backlog.md` — known defects with file/line refs; |
| 23 | + check items off when you fix them and add the named test. |
| 24 | +- To *use* Headless as a browser tool (rather than develop it), follow the |
| 25 | + skill: `.agents/skills/headless-computer-use/SKILL.md`. |
| 26 | + |
| 27 | +## Layout |
| 28 | + |
| 29 | +- `apps/headless/` — the product; one SwiftPM package, zero third-party Swift |
| 30 | + deps (keep it that way). |
| 31 | + - `Sources/HeadlessProtocol/` — shared core: protocol, CLI parser, agent |
| 32 | + runtime JS (embedded string in `AgentRuntime.swift`), artifacts, |
| 33 | + recording, diagnostics. |
| 34 | + - `main.swift` + `Host/` — macOS WKWebView host (Cocoa; macOS-only). |
| 35 | + - `LinuxHost/` — Linux Chromium host (fork/exec + CDP over fd 3/4). |
| 36 | + - `MCP/main.swift` — stdio MCP server exposing the CLI as one `argv` tool. |
| 37 | + - `Tests/` — protocol suite, jsdom runtime suite, E2E shell suites, |
| 38 | + benchmark harness, fixtures. |
| 39 | +- `apps/web/` — Next.js marketing/docs site. |
| 40 | +- `docs/` — roadmap set, QA evidence (`docs/qa/evidence/` — the only binary |
| 41 | + media allowed in git), phase contracts in `apps/headless/docs/P0|P1|P2.md`. |
| 42 | + |
| 43 | +## Build & test |
| 44 | + |
| 45 | +```sh |
| 46 | +pnpm test # protocol/security suite (builds Swift; needs swiftc on macOS) |
| 47 | +pnpm test:runtime # jsdom context-pruning suite (node only) |
| 48 | +pnpm test:e2e:linux # Docker + sandboxed Chromium E2E (needs Docker) |
| 49 | +pnpm test:e2e:mac # real WKWebView E2E (macOS GUI session; mutates user defaults) |
| 50 | +pnpm build # macOS app + web |
| 51 | +pnpm build:linux # Linux binaries via Docker (no local Swift needed) |
| 52 | +``` |
| 53 | + |
| 54 | +Minimum bar for a PR touching `apps/headless`: `pnpm test` and |
| 55 | +`pnpm test:runtime` pass; run the Linux E2E if you changed host, transport, |
| 56 | +runtime JS, or artifact code. There is currently no PR CI (backlog §D1) — do |
| 57 | +not rely on the machine to catch you. |
| 58 | + |
| 59 | +## Hard rules (host-enforced contracts — never weaken) |
| 60 | + |
| 61 | +1. No arbitrary-JS execution verb; no TCP listener; no Chromium debug port. |
| 62 | +2. HTTP/HTTPS navigation only; downloads denied; dangerous extensions |
| 63 | + blocked. All page-derived text stays marked `untrustedContent`. |
| 64 | +3. Artifacts: validated bare names, `O_EXCL` create `0600` in the `0700` |
| 65 | + per-user store, never overwrite, never path-traverse. |
| 66 | +4. Fail closed: unknown params rejected; Snap Chromium rejected; root |
| 67 | + refused; missing capability → `UNSUPPORTED_CAPABILITY`, never silent |
| 68 | + partial behavior. |
| 69 | +5. Flows never record `fill` values. Cookie/storage values stay double-gated |
| 70 | + (`--values` + `HEADLESS_ALLOW_SENSITIVE_DIAGNOSTICS=1`). |
| 71 | +6. Every bounded thing stays bounded and reports truncation (`omitted`, |
| 72 | + `truncated`, `contextStats`). |
| 73 | + |
| 74 | +If a change brushes against any of these, stop and record a decision in |
| 75 | +`docs/roadmap/architecture-decisions.md` first. |
| 76 | + |
| 77 | +## Conventions |
| 78 | + |
| 79 | +- Swift: Foundation + system frameworks only; no new SwiftPM dependencies |
| 80 | + without an architecture-decision entry. Match existing style (explicit |
| 81 | + validation, small structs, no force-unwraps in host paths — existing ones |
| 82 | + are backlog items §A2, don't add more). |
| 83 | +- A new protocol command currently must be added in *both* hosts |
| 84 | + (`main.swift` and `LinuxHost/main.swift`), the validator |
| 85 | + (`Protocol.swift`), the CLI (`CLI.swift`), help text, and `capabilities` — |
| 86 | + until the Phase 2 HostCore refactor lands, keep all copies in sync and add |
| 87 | + parse + E2E coverage on both platforms. |
| 88 | +- The agent runtime JS lives in `Sources/HeadlessProtocol/AgentRuntime.swift` |
| 89 | + as a raw string; `Tests/agent-runtime.test.mjs` regex-extracts it — if you |
| 90 | + touch the string delimiters, fix the extractor. |
| 91 | +- Media policy: never commit images/videos except regenerated evidence under |
| 92 | + `docs/qa/evidence/`; local artifacts go to `build/qa-evidence/` (gitignored). |
| 93 | +- Docs: feature docs live in the phase contracts (P0/P1/P2 style — contract, |
| 94 | + deferrals, known limitations). Keep README claims backed by tests or |
| 95 | + evidence. |
| 96 | +- Web (`apps/web`): content is currently hand-duplicated in three places |
| 97 | + (backlog §F2) — if you change CLI behavior, grep the site |
| 98 | + (`app/docs/page.tsx`, `components/docs-markdown.ts`, `README.md`) and |
| 99 | + update all copies. |
| 100 | +- Commits: conventional-ish prefixes in use (`feat:`, `fix:`, `docs:`, |
| 101 | + `ci:`, scope in parens like `fix(macos):`). |
| 102 | + |
| 103 | +## Versioning & release |
| 104 | + |
| 105 | +Tags `v*` trigger `.github/workflows/release.yml` (macOS zip + Linux |
| 106 | +tarballs). `HEADLESS_VERSION` flows from the tag; protocol version (`"0.4"` |
| 107 | +in `Protocol.swift`) is independent — bump it only for wire-visible changes, |
| 108 | +with a decision entry. |
0 commit comments