From 010e8c07a2b89d4e0d47d851dc3d44951481bf78 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Sun, 31 May 2026 11:13:47 -0400 Subject: [PATCH] Add Go focus-OS reimagining design Co-Authored-By: Claude Opus 4.8 --- .../specs/2026-05-31-go-focus-os-design.md | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-31-go-focus-os-design.md diff --git a/docs/superpowers/specs/2026-05-31-go-focus-os-design.md b/docs/superpowers/specs/2026-05-31-go-focus-os-design.md new file mode 100644 index 0000000..9127e36 --- /dev/null +++ b/docs/superpowers/specs/2026-05-31-go-focus-os-design.md @@ -0,0 +1,175 @@ +# AntiDrift Go Reimagining — Design + +Date: 2026-05-31 + +## Purpose + +AntiDrift is being reimagined from its current Rust implementation (~7,500 +lines) into Go, to become the user's focus operating system on the computer: +fast, good-looking, and deeply integrated with AI from the start. + +This is **not a faithful 1:1 port**. The existing domain model and the +`commitment-os-design.md` spec remain the north star. The Rust code is a +reference, not a thing to replicate line-for-line. The move to Go is an +opportunity to shed incidental complexity — most notably the token-heavy +event-log replay/revalidation design — while preserving what is genuinely +valuable. + +### Why Go, why now + +- **Token efficiency for AI-assisted development.** The current pain is not + runtime cost; it is that any AI edit to the core must load + `session.rs` (3,475 lines, ~80% replay-validation logic and its tests). + Go's smaller idioms plus a redesigned, smaller core directly reduce the + context any change requires. +- **Predictable LLM codegen.** Go's rigid syntax produces functional code on + the first pass with fewer correction loops. +- **Runtime fit.** Concurrency and local HTTP serving are first-class, which + suits a long-running focus daemon that also talks to AI. + +## What Carries Over vs. What Changes + +**Preserved (high value, ports cleanly):** + +- The domain model: `Commitment`, `PolicySnapshot`, `RuntimeState`, + `CommitmentState`, `AllowedContext`, `EnforcementLevel`. +- The pure runtime/commitment state machines (`state_machine.rs`) — a near 1:1 + port. +- The `commitment-os-design.md` spec as the conceptual foundation, including + "no unchosen transitions" and the staged threat model. +- Hash-chained tamper evidence — but relocated to the audit log only. + +**Reimagined:** + +- **Persistence.** Replace replay-everything-and-revalidate-on-startup with an + in-memory state-of-truth, a persisted **snapshot**, and an append-only audit + log. This removes roughly 3,000 lines (the bulk of `session.rs`). +- **UI.** Replace the ratatui TUI with a **local web app** (Gin backend + + browser). This is the surface that must "look good." +- **AI.** AI is a first-class participant from the start, not a later add-on. + +**Deferred for v1:** + +- The AI **reviewer** role (session-end reflection). The three live roles ship + first. +- Privileged enforcement (guardian, IPC, nftables, delayed admin) — same Stage 2 + boundary as the original spec. + +## Process Model + +A single Go binary, `antidriftd`, runs as a **local daemon** and owns all +state. The **browser** is its face. + +``` +┌─────────────────────────────────────────┐ +│ antidriftd (one Go process) │ +│ │ +│ web (Gin) ──HTTP + SSE──▶ browser UI │ +│ │ │ +│ session ── statemachine ── domain │ +│ │ │ +│ store (snapshot + audit log) │ +│ evidence (xdotool/X11) │ +│ ai (CLI backend, async workers) │ +└─────────────────────────────────────────┘ +``` + +- The daemon holds live state **in memory** as the single source of truth. +- It persists a **snapshot** on every state change (crash/restart recovery). +- It appends every significant event to an **append-only audit log** (the + tamper-evident, hash-chained trail — for audit and later review, not for + state reconstruction). +- The browser is stateless: it renders what the daemon pushes over Server-Sent + Events (SSE) and POSTs user actions back. No business logic in the browser. + +### Why snapshot instead of replay + +The original Rust design reconstructs all state by replaying the entire event +log on startup and re-validating every transition, with a dedicated test per +illegal sequence. That is correct and tamper-aware, but it is the single +largest source of code and token weight. A snapshot of current state plus an +append-only audit trail gives the same recoverability and keeps tamper evidence +on the log, at a fraction of the code. State-machine *correctness* is still +enforced — by the pure transition functions at the point of transition, tested +directly — just not re-litigated on every startup. + +## Package Layout + +| Package | Ports from | Size | Purpose | +| -------------- | ------------------------ | ------ | ------- | +| `domain` | `domain.rs` | small | Commitment, PolicySnapshot, runtime/commitment states, AllowedContext, EnforcementLevel, validation | +| `statemachine` | `state_machine.rs` | small | Pure transition functions (1:1 port) | +| `session` | reimagined `session.rs` | medium | In-memory controller; drives transitions, snapshots, audit appends; no replay validation | +| `store` | `event_log.rs` | small | Snapshot file (current state) + append-only hash-chained audit JSONL | +| `evidence` | `window/*` + `context.rs`| small | Active-window snapshot (xdotool/X11), evidence health, allowed-context matching | +| `ai` | new | small | `Coach` / `JudgeDrift` / `Nudge` behind one interface; CLI backend | +| `web` | new (replaces TUI) | medium | Gin routes, SSE stream, static browser UI | + +Design constraint: every package stays small and single-purpose so an AI edit +loads one focused file, not a monolith. This is the concrete mechanism for the +token-efficiency goal. + +## AI Integration + +AI is reached through one narrow interface with a single CLI backend to start: + +```go +type Assistant interface { + // Planning: turn a vague intent into a concrete commitment. + Coach(ctx context.Context, intent string) (domain.Commitment, error) + // Live: is the current window on-task for this commitment? + JudgeDrift(ctx context.Context, c domain.Commitment, w evidence.WindowSnapshot) (Verdict, error) + // Ambient: periodic check-in based on recent activity. + Nudge(ctx context.Context, c domain.Commitment, recent []evidence.WindowSnapshot) (string, error) +} +``` + +- **Backend (v1):** shell out to `claude`/`codex` with a strict prompt that + demands JSON output. Reuses existing CLI auth; no API key plumbing. +- **Latency containment** (the CLI is slow, ~seconds, and AI is in the live hot + path): all AI calls run in **background goroutines**; the UI never blocks. + Drift judgments are **debounced** (no faster than ~10s) and **cached per + (commitment, window-class)** so the same window is not re-judged. The UI + shows a pending state and updates via SSE when a verdict lands. +- **Swap path:** the interface boundary lets an Anthropic API backend (faster, + structured, prompt-cached) drop in later without touching callers. Not built + in v1. + +The three live roles ship first: planning **coach**, live **drift +interceptor**, ambient **nudge**. The reviewer is deferred. + +## Roadmap + +Each milestone is independently shippable and gets its own spec → plan → build +cycle. + +- **M0 — Walking skeleton.** Daemon + Gin + minimal browser UI; port `domain` + + `statemachine`; snapshot persistence; manual commitment → timebox → end. + Proves the full stack end-to-end. No AI, no window tracking. +- **M1 — Evidence & audit.** xdotool active-window tracking, evidence health, + per-window time stats, append-only hash-chained audit log, live SSE updates. +- **M2 — AI planning coach.** `ai` package + CLI backend; "sharpen this + commitment" in the Planning view. +- **M3 — Drift interceptor + ambient nudge.** Allowed-context matching + live + AI drift judgment (debounced/cached) + violation friction UI. +- **M4 — Look good.** A real design pass on the web UI. + +The first sub-project to brainstorm and spec in detail is **M0**. + +## Repo Strategy + +- New Go module at the repository root. +- Move the existing Rust into a `legacy/` directory (or a `rust` branch) so it + remains available as reference while the Go code becomes the front door. + +## Out of Scope (v1) + +- Privileged enforcement: guardian process, root-owned Unix socket IPC, + nftables/DNS domain blocking, delayed admin, break-glass. +- AI reviewer / session-end reflection. +- Wayland compositor adapters beyond the existing degraded reporting. +- Planner/project/task model and outcome writeback. +- Presence sensing. + +These remain governed by `commitment-os-design.md` and may return as later +milestones.