Skip to main content

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