ADR-0002: Viewer-First Application Posture (Not an Editor)
Context and Problem Statement
Stet assumes 100% of code is written by AI. The human's job is editorial: read, comment, react, suggest, and direct. This is a fundamentally different posture from every existing code tool, which is built around a human typing code.
We must decide how the application is organized and what components render code and prose. Getting this wrong — building "yet another editor with AI bolted on" — would forfeit the product's entire reason to exist.
Decision Drivers
- Reading is the primary activity. The default UI should optimize for comprehension and navigation, not text entry.
- Prose is first-class. Markdown (READMEs, ADRs, specs) should render rendered, in the app, not as raw diff text.
- Triage over browse. Users arrive to answer "what needs my attention?" — incoming PRs and files awaiting a stet — not to spelunk a file tree.
- Native fidelity. Code rendering needs tree-sitter-grade syntax highlighting, minimap, gutter messages, and diff — without us building a text engine.
- Editing is the exception, not the rule. Direct human edits happen, but as suggestions, not as the main loop.
Considered Options
- Option A: Viewer-first, inbox-first, document-less app; code canvas via CodeEditSourceEditor (tree-sitter); Markdown via Textual.
- Option B: Fork/embed a full editor (CodeEdit, VS Code webview) and hide the editing affordances.
- Option C: Build a bespoke text/rendering engine from
NSTextView/ TextKit 2.
Decision Outcome
Chosen option: Option A — a viewer-first, inbox-first, document-less application. The home surface is an inbox of PRs and files awaiting review, not a file tree. The center canvas renders code via CodeEditSourceEditor (tree-sitter, minimap, diff, inline messages) and Markdown via Textual, fully rendered. A right-hand Tour rail carries the AI's guided walkthrough and the human's markup (ADR-0008). Editing exists only as suggestion markup that feeds the feedback loop (ADR-0006), never as a primary typing surface.
Consequences
- Good, because the app's structure embodies its thesis; it cannot be mistaken for an editor.
- Good, because CodeEditSourceEditor and Textual give native-grade rendering without us owning a text engine.
- Good, because inbox-first framing makes triage the default job-to-be-done.
- Good, because rendered Markdown makes docs and specs first-class review targets.
- Bad, because CodeEditSourceEditor is edit-capable; we must constrain it to a read/annotate posture and resist feature creep toward "just add editing."
- Bad, because Textual is young (0.5.x); we accept some churn or must pin.
- Neutral, because AppKit interop (
NSViewRepresentable) is required for the canvas, which is the sanctioned exception in ADR-0001.
Confirmation
- The default window presents an inbox, a canvas, and a Tour rail — no file-tree-first layout.
- Code renders with syntax highlighting + minimap + diff via CodeEditSourceEditor.
- Markdown renders rendered (not raw) via Textual.
- There is no primary free-text code editing surface; human changes are captured as suggestion markup.
Pros and Cons of the Options
Option A: Viewer-first with CodeEditSourceEditor + Textual
- Good, native rendering, minimal engine ownership, thesis-aligned structure.
- Bad, must constrain an edit-capable component; young Markdown dependency.
Option B: Embed a full editor, hide editing
- Good, batteries included.
- Bad, heavy, wrong mental model, fights the host's affordances; a webview (VS Code) breaks native aesthetics (ADR-0001).
Option C: Bespoke TextKit 2 engine
- Good, total control.
- Bad, enormous effort to reach parity on highlighting, diff, minimap; distracts from product.
More Information
Markdown library choice: Textual is the maintained successor to swift-markdown-ui (now in maintenance mode). See ADR-0006 (feedback model), ADR-0008 (Tour mode), and SPEC-0001 (app foundation) / SPEC-0002 (feedback review).