Files
antidrift/docs/superpowers/specs/2026-05-31-go-focus-os-design.md
T
2026-05-31 11:13:47 -04:00

176 lines
8.4 KiB
Markdown

# 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.