Generalize the focus controller into a harness hosting swappable modes

Loosen AntiDrift's session controller into Keel's general collect→brain→act
loop. A new internal/harness runs at most one mode.Mode at a time, fanning
async completions out to the web SSE and status-bar surfaces.

- internal/mode: the Mode contract (Kind/Command/View/Active) plus optional
  EvidenceConsumer and Expirer ports, and the surfacing Envelope.
- internal/mode/focus: the former session/domain/statemachine packages moved
  under the mode, now satisfying the harness contracts unchanged.
- internal/mode/offscreen: a one-shot away-from-desk mode built on the new
  ai.Proposer, which turns a life-domain brief into one off-screen action.
- cmd/keeld replaces cmd/antidriftd; daemon wires focus + offscreen factories
  with per-mode persistence under ~/.keel/modes/<kind>.
- Finish the rename: KEEL_* env refs in the README, /keeld build artifact
  ignored, stale antidriftd binary removed.

Include the design + implementation plan this refactor was built from under
docs/superpowers/{specs,plans}/2026-06-04-controller-refactor*.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 18:00:49 -04:00
parent 258de2c14b
commit 7d69a1f320
57 changed files with 4069 additions and 627 deletions
+25 -15
View File
@@ -9,27 +9,37 @@ effectors — surfaced on a web UI and the WM status bar. The brain, the storage
> **Architecture:** [`docs/keel-architecture.md`](docs/keel-architecture.md) is the
> source of truth. **Agents:** read [`AGENTS.md`](AGENTS.md) first.
## Focus mode (AntiDrift)
## Modes
What runs in this repo *today* is **AntiDrift**, Keel's first mode: a personal
focus operating system that treats each work session as an explicit commitment
(next action, success condition, timebox) and makes drift visible. Keel
generalizes its controller so a focus-session becomes one mode among several
(house, body, review, capture). The milestone history below is this mode's record.
Keel's controller is now a generic **harness** that hosts one *mode* at a time,
and the daemon ships two:
> **Naming:** the directory and git repo are renamed to `keel`; the *code identity*
> is intentionally still `antidrift` (Go module, `antidriftd` binary, `~/.antidrift/`
> runtime, `ANTIDRIFT_*` env). The code rename lands with a state migration during
> the controller refactor — see `docs/keel-architecture.md` §8.
- **Focus (AntiDrift)** — Keel's first mode: a personal focus operating system
that treats each work session as an explicit commitment (next action, success
condition, timebox) and makes drift visible. The milestone history below is
this mode's record.
- **Off-screen** — an away-from-the-desk mode: it reads today's Marvin tasks plus
the `~/owc` goals and life-domain `bug-*.md` notes, asks the brain for one
worthwhile off-screen action, and on confirm files it as a Marvin task.
When no mode is active the web UI shows a **launcher** to start either one.
Further modes (body, review, capture) are aspirational. The milestone history
below records the focus mode's development.
> **Naming:** the rename is complete — directory, repo, Go module, binary,
> runtime, and env are all `keel` (`keeld` binary, `~/.keel/` runtime,
> `KEEL_*` env). If you have a live ledger under the old `~/.antidrift/`
> directory, move it manually to `~/.keel/`.
## Run
```bash
go run ./cmd/antidriftd
go run ./cmd/keeld
```
The daemon serves a local web UI at http://localhost:7777 and opens your
browser. State is persisted to `~/.antidrift/state.json`.
browser. Per-mode state is persisted under `~/.keel/modes/<kind>/` (e.g.
`~/.keel/modes/focus/state.json`).
## Test
@@ -57,8 +67,8 @@ into the coach's grounding; the reflection lines are short and cross the wire
by design, while the knowledge profile still does not.
M6 (knowledge port): the planning coach now sharpens intents against who you
actually are. A single profile file (`~/.antidrift/knowledge.md`, overridable
via `ANTIDRIFT_KNOWLEDGE_FILE`) holds your standing context — priorities,
actually are. A single profile file (`~/.keel/knowledge.md`, overridable
via `KEEL_KNOWLEDGE_FILE`) holds your standing context — priorities,
values, what counts as good work — and the daemon loads it asynchronously on
entering planning, mirroring the tasks fetch. The cached text grounds the AI
coach prompt only; the drift judge and nudge are untouched, and the profile text
@@ -86,7 +96,7 @@ The drift judge degrades gracefully — without it, local matching still runs.
M2 (AI planning coach): in the Planning view, a rough intent is "sharpened"
into a structured commitment (next action, success condition, timebox) by an
LLM CLI backend (claude or codex, selectable via `ANTIDRIFT_AI_BACKEND`). The
LLM CLI backend (claude or codex, selectable via `KEEL_AI_BACKEND`). The
coach runs asynchronously and degrades gracefully — manual planning always
works.