# OpenChrome v1.12.0

Release date: 2026-05-14

## Summary

v1.12.0 is the largest feature release in the v1.x line. It merges the
entire accumulated `develop` backlog into `main`:

```
v1.11.1  →  v1.12.0   (cumulative, this release)

  878 files changed
  +111,050 / -8,148 lines
  972 commits (237 first-parent)
  105 PRs merged
  ~30 new MCP tools           (default tools/list now returns 110 entries)
  2  new MCP resources         (openchrome://state, resource subscriptions)
  5  new CLI command families  (oc run / oc replay / oc playbook / oc doctor / oc vault)
  0  source files removed
  0  new mandatory runtime deps (argon2 remains the only native dep)
```

This release builds directly on the **portability-harness contract**
established in the v1.11 line (see [`v1.11.1.md`](v1.11.1.md) for the
canonical v1.10.x → v1.11 reference). Every principle from that contract
still holds: the core tier preserves the v1.10.x surface bit-identically,
the pilot tier stays opt-in behind `--pilot`, no outbound LLM call is
required by either tier, and `argon2` remains the only mandatory native
dependency.

What v1.12.0 adds, in one sentence: a **goal-level task harness**, a
**deterministic recovery/reflection runtime**, a **CLI that can drive the
MCP surface directly** (one-shot `oc run`, declarative `oc playbook`,
`oc doctor` diagnostics), a **Streamable HTTP daemon mode**, and roughly
thirty new fact-capturing MCP tools — all while keeping the
facts-versus-decisions split intact.

---

## Upgrade

```bash
npm install -g openchrome-mcp@1.12.0
openchrome check        # verify the installed CLI and runtime wiring
openchrome doctor       # NEW in v1.12 — full environment diagnostics
```

Fresh install:

```bash
npm install -g openchrome-mcp@latest
openchrome check
openchrome info
```

No configuration changes are required to keep your existing v1.10.x /
v1.11.x experience. Every new subsystem is either additive (new tools,
new CLI commands) or opt-in (`--pilot`, `--http`, new env vars). A
v1.11.x `~/.claude/.mcp.json` works unchanged.

The pilot tier is still opt-in:

```json
{
  "mcpServers": {
    "openchrome": {
      "command": "openchrome",
      "args": ["serve", "--pilot"]
    }
  }
}
```

---

## Breaking changes

**No source-code-level breaking changes for tool callers.** Every existing
tool keeps its name, input schema, and core return shape. The items below
are the **observable behavioral changes** a v1.11.x user can hit. Each one
has a migration path.

### 1. `read_page` / `find` output now carries action-affordance markers

DOM-mode `read_page` and `find` output prefix each element identifier with
a compact affordance marker:

| Marker | Meaning |
|---|---|
| `#` | text input (`input[type=text]`, `textarea`, `contenteditable`, `role=textbox/searchbox`) |
| `@` | link (`<a>`, `role=link`) |
| `$` | button / control (`<button>`, `<select>`, `role=button/checkbox/radio/combobox/...`) |
| `%` | visual target (`<img>`, `<canvas>`, `<video>`, `<svg>`, `role=image`) |
| *(none)* | plain text / structural |

```
# [142]<input type="search" .../> ★
$ [156]<button type="submit"/>Search ★
@ [289]<a href="/home"/>Home ★
[352]<h1/>Welcome
```

The marker is **display metadata only** and is rendered *outside* the
canonical identifier. Pass the identifier itself (`142`, `node_142`, or
`ref_N`) to action tools exactly as before.

**Migration**: if a downstream parser matches the *start of the line*
with a regex like `^\[(\d+)\]`, update it to tolerate an optional
`[#@$%] ` prefix (e.g. `^(?:[#@$%] )?\[(\d+)\]`). Parsers that extract
the bracketed identifier anywhere in the line are unaffected.

### 2. Interactive elements may now show an inline `[hints]` segment

The interactive marker (`★`) in DOM-mode output can be followed by a
bracketed hint segment — `★ [hint]` — when the serializer has extra
affordance hints for that node. Parsers that assumed the marker is always
exactly ` ★` should treat everything after `★` up to end-of-line as
optional metadata.

### 3. Console capture is now bounded by default

`console_capture` retains console entries under two new hard caps:

| Env var | Default | Effect |
|---|---|---|
| `OPENCHROME_CONSOLE_BUFFER_MAX_LINES` | `1000` | max retained entries per capture session |
| `OPENCHROME_CONSOLE_BUFFER_MAX_BYTES` | `4194304` (4 MiB) | max aggregate byte size; oversized single entries become a truncated placeholder with `truncatedFrom` recording the original size |

The `1000`-line default matches the legacy `maxLogs` default, so most
callers see no change. **Migration**: if you relied on effectively
unbounded console retention on a high-log-volume page, raise
`OPENCHROME_CONSOLE_BUFFER_MAX_LINES` / `_MAX_BYTES` explicitly.

### 4. Large-output tools can return an output handle instead of inline content

`read_page`, the crawl tools, `network_capture_*`, `extract_data`, and
`oc_evidence_bundle` may now return a compact **output handle** rather
than dumping a very large payload inline. Redeem it with the new
`oc_output_fetch` tool, which supports `offset`/`limit` pagination.

**Migration**: if your client only ever read the inline text result,
add a fallback: when a result contains an output handle, call
`oc_output_fetch` to page through the full content. Small results are
still returned inline as before.

### 5. Tier 1 tool surface expanded

The default `tools/list` surface grew by roughly thirty tools — a
default (no `--pilot`) introspection now returns **110 tool entries**.
All additions are **additive** — no tool was removed or renamed.

**Migration**: if your MCP client or test harness pins an exact tool
count, refresh the expected value. If it enumerates tools by name, no
change is required.

### 6. Streamable HTTP transport + transport lifecycle policy

A Streamable HTTP transport landed alongside a formal **transport
lifecycle policy** (`docs/transport-lifecycle.md`). **No transport is
deprecated** — `stdio`, `http`, and `both` all remain stable with no
sunset date. The policy document only establishes the *rules* for future
deprecations (minimum 3 minor versions or 6 months overlap). The
boot-time deprecation warning described in that document is not emitted
yet.

---

## New MCP tools

Roughly thirty new tools register on the core tier (no flag) unless
marked **pilot**. All are deterministic fact-capture / fact-transform
tools — none performs LLM judgement, consistent with principle P4.

### Goal-level task harness

| Tool | Purpose |
|---|---|
| `oc_task_start` | Open a host-driven task envelope; optionally forward args to an underlying tool. |
| `oc_task_get` | Read a task envelope by `task_id`. |
| `oc_task_list` | List task envelopes, optionally filtered by creation time. |
| `oc_task_update` | Update a task envelope's phase or note. Does not execute browser actions. |
| `oc_task_wait` | Block until a task envelope reaches a terminal state. |
| `oc_task_cancel` | Cancel a task envelope by `task_id`. |
| `oc_task_finish` | Finish a task envelope as `completed`, `failed`, or `cancelled`. |
| `task_run` | Start an opt-in goal-level `TaskRun` — tracks user goal, success criteria, progress summary, item progress, and evidence across many tool calls without changing existing browser tools. |

The task harness is a **bookkeeping layer**, not an orchestrator: it
records goal/criteria/progress facts; the host LLM still decides what to
do next (principle P1).

### Crawl

| Tool | Purpose |
|---|---|
| `crawl_start` | Start an async crawl job from a seed URL. Returns a job id. |
| `crawl_status` | Poll a crawl job by id; supports cursor pagination over discovered pages. |
| `crawl_cancel` | Cancel a running crawl job by id. |

Crawl results are delivered through the output-handle mechanism and
support cache modes documented in `docs/harness/crawl-cache-modes.md`.

### Page observation & element resolution

| Tool | Purpose |
|---|---|
| `oc_observe` | Deterministic numbered list of actionable elements — collapses the `read_page → query_dom → inspect → interact` pattern into one call. |
| `oc_query` | Resolve a semantic element query into stable refs using local AX/DOM matching only (no AgentQL, no LLM provider). |
| `element_pick` | Start/cancel an in-page human element-picker overlay; returns selector + DOM + style + bounding-box facts. Env-gated; does not persist skills directly. |

### Evidence, diff & context portability

| Tool | Purpose |
|---|---|
| `oc_diff` | Compare two evidence-bundle ids or paths; returns deterministic DOM / screenshot-pHash / URL / console / network diff facts. |
| `oc_context_export` | Export a tab's `ContextEnvelope` with a SHA-256 integrity hash. |
| `oc_context_import` | Strict-replace import of a `ContextEnvelope`; verifies the integrity hash first and rejects on mismatch. |

### Network capture

| Tool | Purpose |
|---|---|
| `network_capture_lite` | Passive recorder for request metadata + headers (no bodies). Actions: `start` / `stop` / `getLogs` / `clear`. |
| `network_capture_full` | Recorder including capped response bodies; bodies over `maxBodyBytes` are omitted with `reason="over_cap"`. |

### Performance & Web Vitals

| Tool | Purpose |
|---|---|
| `oc_performance_insights` | Capture a CDP performance trace and return named insights (`LCPBreakdown`, `DocumentLatency`, `RenderBlocking`, `CLSCulprits`, …) plus a trace handle. |
| `oc_performance_analyze` | Drill into one named insight from a captured trace; returns Markdown detail + an evidence handle. |
| `oc_vitals` | Read-only Web Vitals snapshot of the current page — no injected page scripts, no added dependencies. |

### Recovery & reflection

| Tool | Purpose |
|---|---|
| `oc_reflect` | Create / get / list / validate reflection artifacts over a run's trajectory. |
| `oc_pilot_run_with_recovery` | **Pilot.** Bounded deterministic recovery wrapper around one tool call under declared safe recipes. Requires `--pilot` + `OPENCHROME_CONTRACT_RUNTIME=1`. |
| `oc_skill_replay` | **Pilot.** Replay a recorded skill (steps + optional contract) against the active tab. Returns `PASS` / `STEP_FAIL` / `CONTRACT_FAIL` / … |

### Diagnostics & policy

| Tool | Purpose |
|---|---|
| `oc_doctor_report` | Read the most recent `openchrome doctor` diagnostic report from cache (does not trigger new checks). |
| `oc_progress_status` | Read-only diagnostics for whether the current session is progressing, stalling, or stuck. |
| `oc_devtools_url` | Return the Chrome DevTools inspector URL for the active page — paste into any local browser to attach live DevTools. |
| `oc_policy` | Inspect the deterministic safety policy: `action="matrix"` lists irreversible-action rules; `action="evaluate"` previews a policy decision for a tool/args context. |

### Output handling

| Tool | Purpose |
|---|---|
| `oc_output_fetch` | Redeem an output handle from a large-output tool (`read_page`, crawl, `network_*`, `extract_data`, `oc_evidence_bundle`); supports `offset`/`limit` pagination. |
| `oc_normalize_action` | Validate and normalize a near-valid browser/computer action payload **without executing it**. |

---

## New MCP resources

| Resource | Purpose |
|---|---|
| `openchrome://state` (live state) | Read-only snapshot of live session state. |
| Resource subscriptions | MCP `resources/subscribe` support so a client can be notified when a subscribed resource changes, instead of polling. |

These join the `openchrome://skill-graph/<domain>` resource shipped in
the v1.11 line.

---

## New CLI

The CLI can now drive the MCP surface directly — useful for shell
scripting, CI smoke tests, and debugging without an MCP host.

### `oc run` — one-shot tool execution

`oc run <tool> [--arg key=value ...] [--json]` spawns the same stdio MCP
server an MCP host would, performs the initialize handshake, validates
the tool name via `tools/list`, and sends one `tools/call`.

```bash
oc run navigate --arg url=https://example.com
oc run read_page --arg mode=dom --json
oc run oc_assert --arg contract=json:'{"type":"text","contains":"Example"}' --json
```

Arg grammar: `true`/`false` → boolean, `json:<value>` → parsed JSON,
everything else → string. Exit codes: `0` ok, `1` tool `isError`, `2` CLI
usage error, `3` transport/server failure. `--reuse` connects to a
running Streamable HTTP daemon instead of spawning a child.

**Sugar commands**: common tools have positional aliases that call
`oc run` internally — `oc navigate URL`, `oc click REF`,
`oc form_input REF VALUE`, `oc javascript_tool CODE`, etc.

### `oc playbook` — declarative YAML scenario runner

`oc playbook run <file.yaml>` executes a declarative scenario where each
step maps to exactly one MCP tool call. The runner is a thin client, not
a new orchestration tier. Each step carries an inline **Outcome
Contract** assertion instead of an LLM judgement, so runs stay
deterministic.

```bash
oc playbook run scenario.yaml
oc playbook run scenario.yaml --reuse --json | jq '.summary'
oc playbook run scenario.yaml --vars url=https://iana.org --out report.md
```

Supports variable substitution, `--reuse` daemon connection, and
Markdown report output. See `docs/cli/playbook.md`.

### `oc replay`

Replays recorded artifacts (recording / codegen replay support) through
the same thin-client path.

### `oc doctor` — environment diagnostics

`oc doctor` runs a battery of independent environment checks and writes a
cached `DoctorReport` (readable later via the `oc_doctor_report` tool):

- Node version, disk space, home-directory writability
- Chrome binary presence, Chrome port reachability, orphan-Chrome processes
- macOS permissions, optional native deps, PID-lock and profile-lock state
- Local + remote network reachability

### `oc vault` — credential vault

`oc vault save|list|delete|rotate-key` manages an at-rest encrypted
credential store for use by automation flows. Keys can be rotated
independently.

---

## Subsystem highlights

### Deterministic recovery / reflection runtime

A new family of modules (`src/recovery/`, `src/reflection/`,
`src/trajectory/`, `src/failure/`, `src/run-harness/`) records *what
happened* during a run so the host can decide *what to do next*:

- **Trajectory ledger** — append-only record of tool calls, progress
  status, and evidence per run (`docs/recovery/trajectory-ledger.md`).
- **Reward scorer** — deterministic scoring of recovery attempts
  (`docs/recovery/reward-scorer.md`).
- **Failure taxonomy** — structured classification of plan failures
  (`docs/orchestration/plan-failure-taxonomy.md`).
- **Reflection strategy / task-critic loop / subgoal decomposition /
  task-drift ledger / locator-fallback** — reliability building blocks
  documented under `docs/reliability/`.
- **Recovery runtime** — pilot-tier bounded recovery wrapper exposed via
  `oc_pilot_run_with_recovery` (`docs/pilot/recovery-runtime.md`).

All of it is fact capture and deterministic scoring — no LLM judgement
inside the server (principle P4).

### Transport: Streamable HTTP daemon

OpenChrome ships a first-class HTTP daemon mode so multiple MCP clients
can share one browser process, the server can outlive its launching
process, and sidecars can poll `/health` and `/metrics` independently:

```bash
npx openchrome serve --http 3100 --auth-token <token> --idle-timeout 30m
curl -s http://127.0.0.1:3100/health
```

Full walkthrough: `docs/getting-started/http-daemon.md`. Transport
stability rules: `docs/transport-lifecycle.md`.

### Extraction pipeline

- **Static-fetch waterfall** — cheap static fetch before falling back to
  a full browser render.
- **Fit-markdown** — token-efficient Markdown extraction
  (`docs/recipes/fit-markdown.md`).
- **Semantic extract / scoped structured extract** — semantic and scoped
  structured-data extraction modes.
- **Cursor pagination** — `read_page` markdown mode and crawl results
  both support stable cursor pagination (`docs/mcp/pagination.md`).
- **Async crawl jobs** — `crawl_start` / `crawl_status` / `crawl_cancel`
  with documented cache modes.

### Perception & vision

- **Semantic `read_page` mode** — semantic page representation tuned for
  agent consumption (`docs/perception/read-page-semantic.md`).
- **Action-affordance markers** — the `#`/`@`/`$`/`%` prefixes described
  in breaking change #1.
- **Vision accuracy improvements** and **visual grounding** benchmark
  guardrails (`docs/perception/ralph-visual-grounding.md`).
- **`verify`** perception verification surface (`docs/perception/verify.md`).

### Observability

- **Structured logging** — machine-parseable log records.
- **Trajectory bundles** + **visual trajectory** — exportable run
  evidence (`docs/observability/`).
- **Token metrics** — per-run token accounting.
- **Progress notifications** — MCP progress notifications during
  long-running tool calls.
- **Resource subscriptions** — push instead of poll for live resources.

### Security

- **Secrets masking** — credential redaction across logs/outputs.
- **Host allowlist** — restrict which hosts automation may touch.
- **Credential vault** — at-rest encrypted store with key rotation
  (`oc vault`).
- **Irreversible-action policy** — deterministic policy matrix
  inspectable via `oc_policy`
  (`docs/security/irreversible-action-policy.md`).

### CLI / harness tooling

- **Doctor CLI** with a dozen independent environment checks.
- **Harness certification** + **candidate evaluation** harnesses
  (`docs/harness/certification.md`, `docs/harness/candidate-evaluation.md`).
- **Episode-harness** and **visual-grounding** benchmarks plus the
  **WebVoyager** benchmark runner (`docs/benchmarks/`).
- **Capability map generator** — `npm run docs:capability-map`
  (`docs/agent/capability-map.md`).
- **Auto-connect** — smoother first-connection flow
  (`docs/auto-connect.md`).
- **Research recipes** — composable host-LLM-driven research workflows
  with runnable fixtures (`docs/recipes/`).

---

## Storage policy & dependency footprint

Unchanged from the v1.11 contract. All new storage layers (task
envelopes, trajectory ledger, recovery state, crawl cache, credential
vault) use JSON / JSONL files plus `proper-lockfile` via the existing
`src/utils/atomic-file.ts` helpers. `better-sqlite3` is still not
adopted. `argon2` remains the only mandatory native runtime dependency.

No source files were removed in this release; no runtime dependency was
added or removed.

---

## Reliability & security carried forward

All v1.10.x / v1.11.x hardening continues unchanged:

- HTTP transport fail-closed policy (unauthenticated boots rejected
  unless `allowUnauthenticatedHttp: true` is explicitly set)
- Dashboard REST authz with tenant ownership checks
- File upload root restriction with `realpath` symlink resolution
- Screenshot + vision capture payload guards
- Same-origin CORS bypass scheme matching + DNS-rebinding defense
- Pilot handoff AES-256-GCM persistence with ephemeral-key default

New hardening in v1.12.0:

- Stale CDP reconnect completions are invalidated by a connection
  generation counter — an async connect that resolves after a
  `forceReconnect` can no longer resurrect a stale browser handle.
- HTTP request-stream `close` is distinguished from `aborted`: a normal
  end-of-stream `close` is no longer mistaken for a client disconnect.
- Console capture is bounded by line and byte caps (breaking change #3).
- Secrets masking and host-allowlist enforcement added across the
  automation surface.

---

## Verification

- `npm install`: clean
- `npm run build`: clean (`tsconfig.cli.json` + `tsconfig.json`)
- `npm run lint:tier`: 0 violations (522 modules, 1241 dependencies cruised)
- Full Jest suite: passes on the merged `main`
- Merge `develop` → `main` resolved 5 conflicts (`package.json` scripts,
  `dom-serializer.ts` affordance+hints combination, three test files
  taking the develop-side implementation)

---

## References

- v1.11 canonical reference: [`docs/releases/v1.11.1.md`](v1.11.1.md)
- Portability-harness contract: `docs/roadmap/portability-harness-contract.md`
- Transport lifecycle policy: `docs/transport-lifecycle.md`
- CLI reference: `docs/cli.md`, `docs/cli/playbook.md`
- HTTP daemon guide: `docs/getting-started/http-daemon.md`
- Recovery/reflection: `docs/recovery/`, `docs/reliability/`, `docs/pilot/recovery-runtime.md`
- Research recipes: `docs/recipes/README.md`
</content>
</invoke>
