# clawdcursor v0.9.0 — Architecture Design

**Status:** Draft for review · 2026-05-08
**Author:** synthesized by 4 parallel architectural audits + 1 design-synthesis pass + MCP-only revision
**Branch context:** v0.8.17 is current production; this doc is the plan for the next major version

---

## Headline

v0.9.0 is a **structural simplification, not a feature release.** **One protocol (MCP). One tool registry. Five directories.** REST is removed entirely — MCP is what every modern agent host (Claude Code, OpenClaw, Cursor, Windsurf, Zed, Goose, Continue.dev) already speaks, and the MCP spec already covers both stdio and HTTP/SSE transports for the dashboard / task-console paths that previously needed REST.

| Metric | v0.8.17 | v0.9.0 (target) | Change |
|---|---|---|---|
| `src/` LOC | 27,459 | ~17,500 | **−36 %** |
| Top-level `src/` directories | 7 (mix of layers + dead code) | **5** (one per concern) | −29 % |
| Pipeline subdirectories | 15 | 0 (folded into `core/`) | −100 % |
| Parallel architectures alive | 3 (legacy cascade, dead `v2/agent`, unified pipeline) | 1 (unified, renamed `core/`) | −67 % |
| Wire protocols spoken | 2 (REST + MCP) | **1 (MCP only)** | −50 % |
| Paths to invoke a click | 5 (REST × 3 + MCP × 2, with 3 coord spaces) | 1 (MCP `mouse_click`, physical pixels) | −80 % |
| Ways to set a model | 6 | 1 funnel (CLI > project > user > env > auto-detect) | −83 % |
| `/health` endpoints registered | 2 | 1 | dedupe |
| CLI verbs that bring up a server | 2 (`start` + `serve`, 90 % code overlap) | 1 (`agent`, with `--no-llm` flag); `mcp` is an alias for stdio-only | −50 % |
| Tool registries | 2 (granular + compact, parallel catalogs) | 1 registry, compact is a transform | source-of-truth |
| REST endpoints (`/task`, `/abort`, `/execute/:name`, `/action`, `/learn`, `/favorites`, `/screenshot`, `/logs`, `/task-logs`, `/health`, ...) | 13+ | **0** — all become MCP tools or notifications | clean break |

What's **preserved**: all 75 tool primitives, the unified-pipeline ladder (router → blind → hybrid → vision), Tier 0 LLM decomposer, `MODEL_QUIRKS`, app alias table, verb dispatch (Ctrl+C / Ctrl+V / etc.), the runaway / stagnation / hedge guards, credential resolution, per-turn perception loop, ground-truth verifier signals, MCP stdio + HTTP transports.

What gets **cut**: the v0.7-era legacy cascade, the v2 dead branch, top-level orphans (`smart-interaction`, `ui-driver`, `ui-knowledge`), duplicate verifiers, duplicate skill caches, the `start`/`serve` duplication, the silent 1280-coord scaling on `/action`.

The thesis: **clawdcursor's capabilities are not the problem; the architectural drift around them is. v0.9 cuts the drift.**

---

## Why now (audit findings, condensed)

Four parallel auditors examined the codebase from different angles:

### Component inventory
- **52 root files in `src/`**, with 3 parallel architectures coexisting:
  1. Legacy cascade (~12,000 LOC) — only reachable via `--legacy` flag
  2. v2 stack (~1,200 LOC) — `v2/orchestrator.ts` + `v2/agent/` is dead; only `v2/platform/` and `v2/verifier/` are alive
  3. Unified pipeline (~7,800 LOC) — production path
- **10 documented duplicate-purpose pairs**, each labeled "Ported from src/X.ts"
- **30+ `process.platform` branches** outside the platform abstraction
- **57 % of top-level LOC is mechanically deletable** without behavior change

### Dependency graph
- `src/agent.ts` is a **1,889-line dispatcher**, not the agent — switches between the three architectures
- One backwards layer violation introduced this week: `v2/platform/{linux,macos,windows}.ts` import `resolveAlias` from `pipeline/router/aliases` (lower layer reaching up)
- `tools/safety-gate.ts` imports `pipeline/safety/layer` (MCP tool surface depending on pipeline-internal module)
- Confirmed dead exports: `notification.ts:sendNotification`, `format.ts:canEmoji`, most of `ui-knowledge.ts`

### Public surfaces (this is where users feel the pain)
- **5 paths to a single click** — MCP granular `mouse_click`, MCP compact `computer({action:"click"})`, REST `POST /execute/mouse_click`, REST `POST /execute/computer`, REST `POST /action`. The last one uses 1280-LLM-coord scaling; everyone else uses real pixels — silent gotcha.
- `/health` registered twice in `start` mode; first wins, masking the richer one
- 75 granular MCP tools + 6 compact MCP tools — overlapping coverage, two parallel catalogs
- 6 different ways to set a model (CLI, env vars, doctor, project config, OpenClaw profiles, AI_MODEL generic)
- 8+ env vars affect behavior with no `--help` doc (`OPENCLAW_DISABLE_VERIFIER`, `CLAWD_HOME`, `CLAWD_REPORT_URL`, etc.)
- `package.json` declares `main: "dist/index.js"` but `require('clawdcursor')` triggers `program.parse()` and exits — library import surface is functionally undefined
- `task` means 5 different things across the surfaces; `system` MCP tool is a junk drawer

### Industry comparison
| Project | Top-level concerns | Loop file count | Tool registry |
|---|---|---|---|
| Anthropic computer-use-demo | ~2 (loop + tools) | 1 (`loop.py`) | implicit (model owns schema) |
| OpenAI Operator (CUA) | ~3 packages | 1 (`responses-loop.ts`) | shared by transports |
| Open Interpreter | 3 (`llm/`, `computer/`, `core.py`) | 1 (`core.py`) | one |
| Microsoft AutoGen | 3 layered packages | 1 (`agent.run()`) | one |
| Mobile-Agent-v3 | 6 cooperating agents | per-agent | per-role |
| MCP TypeScript SDK | 2 (server + client) | n/a | **one `registerTool` consumed by every transport** |
| **clawdcursor today** | **15 pipeline subdirs + 7 root concerns** | **3** (`agent.ts`, `pipeline/index.ts`, `pipeline/agent/agent.ts`) | **2** (granular + compact, parallel) |

We are well past the peer median on every count.

---

## v0.9 directory layout — five concerns

```
src/
├── core/         (~3,500 LOC)   THE agent loop + pipeline orchestration + verifier + safety gate
├── tools/        (~5,500 LOC)   ONE registry — schemas + handlers + the compact projection
├── platform/     (~4,500 LOC)   Every OS branch lives here. PlatformAdapter + 3 impls
├── llm/          (~2,500 LOC)   Provider clients, cred resolution, model quirks, knowledge, decomposer
└── surface/      (~2,500 LOC)   CLI parser + HTTP/MCP transports + auth + lifecycle
```

### `core/` — the engine

Owns:
- `agent.ts` — **the single canonical agent loop file** (~250 LOC after refactor; today's `pipeline/agent/agent.ts` mostly unchanged)
- `pipeline.ts` — preprocess → router → escalator → reflector
- `verifier.ts` — the consolidated `GroundTruthVerifier` (today's `v2/verifier/ground-truth.ts`)
- `safety.ts` — single `evaluate()` entry point used by all transports + the agent loop
- `skill-cache.ts` — persistent task → tool sequence memory
- `correlation.ts`, `logger.ts` — observability (cross-cutting)
- `types.ts` — shared types

Deletes (or moves out, in dependency order):
- 17 legacy cascade modules (`computer-use`, `ai-brain`, `action-router`, `verifiers`, `safety`, etc.)
- `v2/orchestrator.ts`, `v2/agent/` (dead)
- `pipeline/dispatch.ts` (orphan)
- `pipeline/verifier/` (duplicate of v2/verifier; the dead one)
- top-level `safety.ts`, `skill-cache.ts`, `verifiers.ts`, `action-verifier.ts`, `task-classifier.ts`, `local-parser.ts`, `snapshot-builder.ts`

### `tools/` — one registry

Owns:
- `registry.ts` — a single `registerTool(tool: Tool): void` API
- ~10 category modules grouping the 75 primitives (mouse, keyboard, window, a11y, cdp, ocr, system, orch, browser, shortcuts)
- `compact.ts` — **a transform**, not a parallel catalog: `getTools({palette:'compact'})` returns 6 wrapper tools whose handlers route to the underlying granular tool by `args.action`
- `aliases.ts`, `normalize.ts`, `webview2.ts` — app-name resolution
- `palettes.ts` — per-capability filtering for the autonomous agent's tool catalog
- `playbooks/` — Outlook send, mac-mail send, find-replace (kept; small)

The unified `Tool` shape:
```ts
interface Tool {
  name: string;
  category: 'mouse'|'keyboard'|'window'|'a11y'|'cdp'|'ocr'|'system'|'orch';
  description: string;
  inputSchema: JSONSchema;
  changesScreen: boolean;
  safetyTier: 0|1|2|3;            // unified with safety/layer
  compactGroup?: 'computer'|'keyboard'|'system'|'web'|'desktop'|'a11y';
  execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
}
```

### `platform/` — the only place `process.platform` lives

Owns: `windows.ts`, `macos.ts`, `linux.ts`, `wayland-backend.ts`, `launch-poll.ts`, `types.ts`, `cdp-driver.ts`, `accessibility.ts`, `native-desktop.ts`, `native-helper.ts`, `ps-runner.ts`, `ocr-engine.ts`, `keys.ts`.

Enforced by an ESLint rule: no `process.platform` / `os.platform()` outside this directory. (Today there are 30+ violations.)

### `llm/` — model interface + knowledge

Owns: `client.ts` (today's `llm-client.ts`), `providers.ts`, `credentials.ts`, `external-creds.ts`, `model-quirks.ts`, `decomposer.ts` (Tier 0 LLM decomposer), `knowledge/` (app guides — `gmail.json`, `outlook.json`, `slack.json`), `preprocessor.ts`, `cost-meter.ts`.

### `surface/` — transports (MCP-only)

Owns:
- `cli.ts` — commander root, all subcommand handlers (~250 LOC after collapse)
- `server.ts` — **single MCP server, two transports**: stdio (for editor hosts) AND streamable HTTP/SSE (for the dashboard, task console, web clients). The `@modelcontextprotocol/sdk` exposes both via `server.connect(transport)`. No REST endpoints.
- `auth.ts` — bearer token + consent (auth used identically by both MCP transports)
- `pidfile.ts` — single-instance lock for `start`/`mcp`/`serve` modes (JSON `{v,pid,startTime,mode}`; verifies process identity by start-time match to avoid PID-recycling false positives on Windows)
- `dashboard.ts` — read-only web UI; calls clawdcursor via the MCP-over-HTTP transport using `@modelcontextprotocol/sdk` browser client
- `doctor.ts`, `onboarding.ts`, `report.ts`, `readiness.ts` — utility CLI commands

**No `tool-server.ts`. No REST routes. No `/task`, `/abort`, `/execute/:name`, `/action`, `/learn`, `/favorites`, `/screenshot`, `/logs`, `/task-logs` endpoints.** All become MCP tools. The autonomous agent (today's `POST /task`) becomes the `task` MCP tool whose handler runs the full pipeline (`core/pipeline.ts` → `core/agent.ts`).

---

## The single canonical agent loop

`src/core/agent.ts`. Today's `pipeline/agent/agent.ts` is ~95 % there already; v0.9 just promotes it to the canonical location.

The whole mental model fits on one screen:

```ts
export async function runAgent(input: AgentInput, deps: AgentDeps): Promise<AgentResult> {
  // 1. Pick LLM config from mode (blind | hybrid | vision)
  // 2. Capture initial a11y snapshot (vision mode also takes a screenshot)
  // 3. For turn in 1..maxTurns:
  //      a. callLLMWithTools(history, tools)              // ONE LLM call, native tool_use
  //      b. for each tool_call:
  //           - safety.evaluate()                         // single gate
  //           - runaway_guard.check(name, args)
  //           - tool.execute(args, ctx)
  //           - if tool.changesScreen: re-snapshot
  //           - emit step record
  //           - if terminal (done | give_up | cannot_read): break
  //      c. Build next-turn user blocks: tool_results + fresh snapshot + reflector_hint
  //      d. Stagnation: if last 3 fingerprints identical, append warning
  //      e. Trim screenshots beyond N=2 to keep token budget
  // 4. Return AgentResult { exit, steps, llmCalls, durationMs }
}
```

What it does **not** do:
- Decompose tasks (that's the preprocessor's Tier 0 LLM call)
- Choose models or escalate (that's `pipeline.ts`)
- Touch `process.platform` (that's the adapter's job)
- Format MCP/HTTP envelopes (transports' job)
- Maintain its own tool registry (consumes `tools/`)
- Verify pass/fail (verifier's job, called by pipeline between rungs)

---

## Tool registry — one source of truth, multiple projections

```
                ┌────────────────────────┐
                │  src/tools/registry.ts │
                │  registerTool(tool)    │
                │  getTools({palette,    │
                │            mode,       │
                │            capability})│
                └──────────┬─────────────┘
                           │
        ┌──────────────────┼──────────────────┐
        ▼                  ▼                  ▼
  ┌──────────┐       ┌──────────┐       ┌──────────┐
  │  MCP     │       │  HTTP    │       │ Auto-    │
  │ stdio    │       │ /tools   │       │ agent    │
  │          │       │ /execute │       │ loop     │
  └──────────┘       └──────────┘       └──────────┘
       ~70 LOC            ~120 LOC            existing
   (zod-from-          (json-schema       (filtered
    json-schema)        passthrough)       by mode +
                                           capability)
```

`compact` mode is **a transform over the granular registry**, not a parallel catalog. `getTools({palette:'compact'})` returns 6 wrapper tools whose handlers route to the underlying granular tool by `args.action`. One source of truth, no drift.

The safety gate lives in **exactly one place** (`core/safety.ts`) and is called from three call sites: the agent loop, the HTTP `POST /execute/:name` middleware, and the MCP wrapper before invoking `tool.execute`.

---

## Public surfaces — collapsed

### CLI verbs

```
clawdcursor agent          # was 'start' — full agent + HTTP. Has the LLM. Has /task.
clawdcursor agent --no-llm # was 'serve' — tool server only, no LLM
clawdcursor mcp            # stdio MCP server (editor integration; no HTTP)
clawdcursor doctor         # provider scan + write config
clawdcursor status         # readiness check
clawdcursor stop           # shutdown any running mode
clawdcursor consent        # manage desktop control consent
clawdcursor task "<text>"  # one-shot or interactive task submitter
clawdcursor guides ...     # manage app guides
clawdcursor report ...     # submit redacted task log
```

`start` and `serve` are aliased through 0.9.x with deprecation warnings; removed in 0.10.

### REST endpoints

| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
| `/health` | GET | none | readiness — single registration |
| `/status` | GET | none | agent state |
| `/task` | POST | bearer | submit NL task to autonomous agent |
| `/abort` | POST | bearer | abort current task |
| `/confirm` | POST | bearer | answer pending safety prompt |
| `/screenshot` | GET | bearer | raw PNG of primary display |
| `/tools` | GET | none | tool catalog (`?palette=compact\|granular`) |
| `/execute/:name` | POST | bearer | run a single tool by name |
| `/logs` | GET | bearer | recent log entries |
| `/task-logs` | GET | bearer | recent task summaries |
| `/favorites` | GET/POST/DELETE | bearer | favorites store |
| `/learn` | POST | bearer | mutate `guides/*.json` (write app knowledge) |
| `/report` | POST | bearer | submit task log to telemetry endpoint |
| `/stop` | POST | bearer (localhost-only) | shut down the daemon |

**Removed:** `/action` (legacy 1280-coord-scaled clicks). The canonical path is `POST /execute/mouse_click` with **physical pixels**. A 422 tripwire fires if `x > screen.physicalWidth * 1.05` with a clear migration message.

### Coordinate space

**Physical pixels everywhere.** The hidden 1280-LLM-coord scaling on `/action` is removed. The autonomous agent loop receives `screen.physicalWidth`/`screen.physicalHeight` in the snapshot prompt and is responsible for clamping if needed. Removing the silent rescale eliminates the "5 paths to a click with 3 coord spaces" gotcha.

### Config funnel

One resolution rule (`src/llm/config.ts:resolveConfig()`):

```
  CLI flags  >  project ./.clawdcursor-config.json
             >  user ~/.clawdcursor/config.json     (NEW)
             >  env vars (CLAWD_* canonical, then provider keys)
             >  auto-detect via doctor
```

`OPENCLAW_*` env vars deprecated to `CLAWD_*` with warnings throughout 0.9.x.

### Library surface — explicit decision

clawdcursor v0.9 is **not a library; it's a CLI**. `package.json` removes `main`. Anyone who needs programmatic access in v1.0 will get `@clawdcursor/sdk` as a separate package with a stable contract.

---

## Verifier upgrade — Reflector with planner feedback

Today's `GroundTruthVerifier` returns `{pass, confidence, reason, signals}` and the pipeline does nothing with the structured signals on retry — it just rolls down the ladder. That's wasted information.

v0.9 introduces a `ReflectionFeedback` shape that the verifier passes back to the planner:

```ts
interface ReflectionFeedback {
  pass: boolean;
  confidence: number;             // 0..1 weighted-vote
  causes: Cause[];                // structured, not prose
  hint: string;                   // human-readable summary for next turn's prompt
  suggestedStrategy?:             // override the default ladder pick
    | 'router' | 'blind' | 'hybrid' | 'vision'
    | 'wait_and_retry' | 'change_target';
}

type Cause =
  | { kind: 'no_pixel_change' }
  | { kind: 'wrong_window_focused', expected?: string, actual: string }
  | { kind: 'modal_intercept', text: string }       // OCR'd unexpected dialog
  | { kind: 'a11y_target_missing', target: string }
  | { kind: 'webview_blind' }                        // pixels changed, no a11y signal
  | { kind: 'partial_text_match', expected: string, observed: string };
```

Wiring: between agent rungs the pipeline calls `verifier.verify({before, after, taskAssertions})`. On fail, `feedback.hint` is injected as a synthetic `tool_result` block at the start of the **next** rung's history, AND `suggestedStrategy` overrides the ladder pick. Examples:

- `webview_blind` cause → skip blind/hybrid, jump straight to vision
- `modal_intercept` cause → retry the same rung after a `dismiss_modal` action
- `wrong_window_focused` cause → retry blind with an explicit `focus_window` step prepended

This is Mobile-Agent-v3's Manager↔Reflector pattern simplified to one struct and one ladder override.

---

## Migration plan — 11 landable PRs in dependency order

Each PR ships green and reverts cleanly. v0.8.17 stays usable until PR 7 (REST→MCP collapse).

| PR | Scope | Risk | Notes |
|---|---|---|---|
| 1 | Layer-violation reversal — remove `resolveAlias` import from `v2/platform/{linux,macos,windows}.ts` | low | platform takes alias data via opts; agent's open_app tool resolves first |
| 2 | Delete legacy cascade — remove `--legacy` and the 17 dependent files | medium-high | mechanical deletions; tag `v0.8.17-legacy` for emergency cherry-pick |
| 3 | Delete `v2/agent/` + `v2/orchestrator.ts` + top-level orphans (`smart-interaction`, `ui-driver`, `ui-knowledge`, `pipeline/dispatch.ts`, `pipeline/verifier/`) | low | trivial revert |
| 4 | Verifier consolidation — hoist `v2/verifier/` to `src/verifier/`; delete top-level `verifiers.ts`/`action-verifier.ts` | low | rename target during PR 11 directory move |
| 5 | Tool registry unification — `compact.ts` becomes a transform over the granular registry; one `Tool` shape | medium | golden-snapshot every compact tool's behavior before/after |
| 6 | Safety gate consolidation — single `safety.evaluate()`; delete top-level `safety.ts`, hoist `pipeline/safety/layer.ts` | low | three call sites updated (loop, MCP wrapper, transport middleware) |
| 7 | **REST → MCP collapse** — delete `server.ts` + `tool-server.ts`; introduce `surface/server.ts` that mounts MCP on **stdio AND streamable HTTP** via `@modelcontextprotocol/sdk`. Migrate every REST endpoint to an MCP tool: `task` (was `POST /task`), `abort` (was `POST /abort`), `screenshot` (was `GET /screenshot`), `learn` (was `POST /learn`), `favorites_list/_add/_remove`, `task_logs_list/_get`. Delete `start`/`serve` duplication; one CLI verb `agent` (with `--no-llm` flag) covers both. | **high** | the centerpiece of v0.9; breaking change announced in CHANGELOG; optional `@clawdcursor/legacy-rest-shim` package for one cycle |
| 8 | Config single funnel — implement `resolveConfig()`; deprecate `OPENCLAW_*` env vars to `CLAWD_*` | low | behavior identical with current env var precedence; warnings on legacy names |
| 9 | Reflector feedback channel — implement `ReflectionFeedback`; wire into pipeline ladder + agent loop | medium | gate behind `CLAWD_REFLECTOR=1` for first cycle, telemetry-driven default-on |
| 10 | Directory move — mechanical `git mv` into `core/`/`tools/`/`platform/`/`llm/`/`surface/` | **high** | ship on its own; queue all in-flight PRs first |
| 11 | Library-surface decision — remove `main` from `package.json`; update README; ship `@clawdcursor/sdk` plan note | low | trivial |
| 12 (deferred to 0.9.1) | AppAgentX-style shortcut promotion — when skill-cache sees same `(app, taskShape, action-trace)` ≥ 3 times, promote to router shortcut | low | optional; defer if the rest of v0.9 lands clean |

---

## What changes for users

### Removed (breaking; documented in CHANGELOG)
- `--legacy` flag — gone
- `clawdcursor serve` — aliased through 0.9.x; removed in 0.10
- `/action` endpoint's silent 1280-coord scaling — replaced with physical-pixel-everywhere + 422 tripwire
- `OPENCLAW_*` env vars — kept with deprecation warnings through 0.9.x
- Programmatic `require('clawdcursor')` — was undefined behavior; now explicit error

### Renamed (alias kept through 0.9.x)
- `clawdcursor start` → `clawdcursor agent`
- `OPENCLAW_DISABLE_VISION` → `CLAWD_DISABLE_VISION`
- `OPENCLAW_DISABLE_VERIFIER` → `CLAWD_DISABLE_VERIFIER`

### New
- `~/.clawdcursor/config.json` — user-level defaults (replaces ad-hoc OpenClaw paths)
- `--no-llm` flag on `agent` (replaces `serve`)
- `GET /tools?palette=compact|granular` (was: separate catalogs)
- 422 response on out-of-range coordinates with explicit migration message

### Unchanged (load-bearing stuff — explicitly preserved)
- All 75 tool primitives keep their names and JSON schemas
- `clawdcursor mcp` and `clawdcursor mcp --compact` semantics identical
- Auth model (Bearer token at `~/.clawdcursor/token`)
- Pidfile lifecycle
- Tier 0 LLM decomposer, `MODEL_QUIRKS`, app aliases, verb dispatch
- Hedge / stagnation / runaway guards
- Verifier signal weights and confidence rules

---

## Risk register

1. **Directory move (PR 11) breaks every editor's "Go to definition" and every open PR.** Mitigation: queue all in-flight PRs, do PR 11 on a Friday, communicate. Use `git log --follow` capability checks in CI to ensure no commits drop through cracks.

2. **Reflector's `suggestedStrategy` over-eagerly skips rungs and a flake gets surfaced as a regression.** Mitigation: ship behind `CLAWD_REFLECTOR=1` for one cycle. Log when reflector overrides the default ladder and what would have happened. After two weeks of telemetry, make it default if win-rate ≥ baseline.

3. **`/action` coord-space change breaks an external user we don't know about.** Mitigation: 422 with explicit migration message, two-week deprecation notice in CHANGELOG before flipping. Add `?coords=legacy` query param as a six-month escape hatch; log every use.

4. **The ESLint rule banning `process.platform` outside `platform/` is over-broad and blocks tests / migration scripts.** Mitigation: scope the rule to `src/{core,tools,llm,surface}/` only; allow in `src/platform/` and `tests/`.

5. **Compact-as-transform regression — a corner case in `compact.ts` differs from the granular dispatch.** Mitigation: in PR 5, golden-snapshot every compact tool's behavior against today's `compact.ts` output for a fixed corpus of args. Block the merge if any drift.

---

## Three-paragraph executive summary

**Headline.** v0.9.0 is a structural simplification, not a feature release. The codebase shrinks from 27.5k to ~18.5k LOC by deleting three parallel architectures (legacy cascade, dead `v2/agent`, top-level orphans), collapsing the `start`/`serve` duplication, and unifying the tool registry so granular and compact surfaces are one source of truth in two projections. The post-refactor mental model is five directories — `core` (agent loop), `tools` (registry), `platform` (OS branches), `llm` (providers and knowledge), `surface` (CLI/HTTP/MCP) — each owning one concern with no upward dependencies.

**Why it makes things simpler.** Today there are five paths to a click, six ways to set a model, three pidfiles, two `/health` endpoints, and a 1280-coord silent-rescale gotcha. After v0.9 there is one click path (granular tool, optionally wrapped by compact), one config funnel (CLI > project > user > env > auto), one CLI verb for the agent, one `/health`, one coordinate space (physical pixels). The verifier graduates from retry-or-fail to a structured Reflector that feeds causal hints back into the planner — Mobile-Agent-v3's idea trimmed to one struct and one ladder override.

**What's preserved.** Every primitive that does the work. All 75 tool handlers keep their names. The unified pipeline, Tier 0 LLM decomposer, MODEL_QUIRKS, app aliases, verb dispatch, runaway/stagnation/hedge guards, credential resolution, and per-turn perception loop all stay — they're already the production path. The 13 PRs are independently landable, each green when shipped, with the highest-risk one (the directory move) explicitly isolated. v0.8.x users get a one-cycle deprecation window for renamed flags and removed commands. The thesis: clawdcursor's capabilities are not the problem; the architectural drift around them is. v0.9 cuts the drift.
