Files
clide/decisions/extensions.md
T
jpmschweitzerandClaude 6e6546fe32 clean-house sweep: anchor drift, app/-prefix paths, D-59 sunset
Fixes 3 substring-truncated cross-reference anchors so they match
the full heading slug:
- D-3 link in architecture.md
- D-40 link in process.md (heading gained the [SUPERSEDED] tag)
- Q-15 link in questions-process.md

Strips the legacy `app/` prefix from path references in 5 files —
the dirs were flattened to repo root in the Flutter rebuild
(D-56). Three "was `app/...`" historical references in D-5 and
D-56 are deliberately preserved as record of the dissolution.

Adds an inline (tracked in T-88) note to D-59 so the
"must track dugite-native releases for security updates" intent
is wired to a backlog item — RULE-SUNSET-WITHOUT-TICKET would
otherwise keep flagging it on every sweep.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-06 16:40:38 +02:00

6.5 KiB

Extension Decisions

Extension contract, Lua runtime, grain, contribution points.


D-15: Extension grain — container-level, multi-contribution

  • Date: 2026-04-21
  • Decision: An extension is a shipping unit that contributes one or more named contributions (panel, command, theme, keybinding, language, layout, provider, view). Grain is container-sized — a single builtin.git extension contributes panel + commands + keybindings + status-bar items; we do not ship one extension per contribution.
  • Rationale: Finer grain (one extension per contribution) multiplies manifest files with no win and fragments ownership. Coarser grain (one mega-extension per domain) hides which parts a user might reasonably disable.
  • Cost: Extension authors make a taste call about grouping; disagreements go to review.
  • Raised by: 2026-04-21 planning.

D-16: Built-ins in Dart, third-party in sandboxed Lua

  • Date: 2026-04-21
  • Decision: Bundled extensions (every lib/builtin/<name>) are Dart — they link into the app binary. Third-party extensions (Tier 6) run in sandboxed Lua via the ptyc-peer Lua runtime (see D-19). The contribution contract is language-agnostic — same contribution shapes, same manifest schema.
  • Rationale: Dart built-ins get full SDK power (custom painters, isolates, FFI); third-party Lua gets a narrow capability API, no arbitrary syscalls, no deps on pub.dev. VS Code's Node-runs-with-full-power model is a supply-chain nightmare we're explicitly rejecting.
  • Cost: Two implementation paths for the same contract; we pay in API design to keep them equivalent at the seams.
  • Raised by: 2026-04-21 planning.

D-17: Panels are extension-shaped from day one

  • Date: 2026-04-21
  • Decision: Every bundled panel (file tree, git, problems, pql query, terminal, etc.) is a contribution on the extension contract, not a hardcoded widget tree in the panel manager. First party contributes via Dart; third party contributes via Lua; same contract.
  • Rationale: Forces the contract to be real on day one. The alternative ("extensions can contribute panels later") always becomes "the contract doesn't quite fit our bundled panels, so built-ins get a shortcut" — and the shortcut becomes permanent.
  • Cost: Every panel goes through the manifest/registration path even when it's trivial. Price paid once.
  • Raised by: 2026-04-21 planning.

D-18: YAML for themes + manifests; JSON for i18n catalogs

  • Date: 2026-04-21
  • Decision: Themes and extension manifests are YAML; i18n catalogues are JSON (fframe parity — see D-21).
  • Rationale: YAML for human-edited config files (themes, manifests) — comments, multi-line strings, less noise. JSON for machine-written / machine-read files (i18n catalogs get generated by translation tooling eventually). Mixing is fine; each format is where it's best.
  • Cost: Two parsers in the tree. yaml: 3.1.3 is exact-pinned.
  • Raised by: 2026-04-21 planning.

D-19: Lua runtime as ptyc-peer supporter tool

  • Date: 2026-04-21
  • Decision: Third-party extensions run Lua inside a sandboxed runtime (working name TBD; same peer-status as ptyc and pql). The runtime vendors liblua, links from Dart via dart:ffi, exposes a narrow capability API, and takes contributions as a declarative render-intent DSL (widget shapes, not arbitrary widget code).
  • Rationale: Lua is small, embeddable, battle-tested (Neovim, World of Warcraft, Redis). Native sandboxing at the VM level is cheap. A declarative render-intent DSL keeps "run arbitrary Flutter widgets from Lua" off the table — the runtime interprets the DSL into Dart widgets, which keeps Tier 6 supply-chain risk bounded.
  • Cost: Runtime is a separate supporter tool to build; ffi is tricky. Deferred to Tier 6; only the slot is reserved now.
  • Raised by: 2026-04-21 planning.

D-46: Core frame builtins vs shipped extensions boundary

  • Date: 2026-04-22

  • Decision: The lib/builtin/ directory is reserved for core frame infrastructure — components the shell cannot function without. Everything that renders content (editor surfaces, tool panels, integrations) is a shipped extension: still Dart, still bundled in the binary, but architecturally an extension that registers through the contribution contract and could in principle be disabled by the user.

    Core frame builtins (cannot be disabled; the frame breaks without them): default-layout, welcome, ipc-status, theme-picker, terminal, files, grammars-core, settings-ui, extensions-ui, keybindings-ui.

    Split components (core process in the frame, UI surfaces as shipped extensions): git — the daemon-side git process (branch, status, stage, commit, diff computation) is frame infrastructure that the status bar, file tree dirty markers, and other extensions depend on. The git panel, conflict UI, and diff tab are shipped extensions that consume it.

    Shipped extensions (bundled but removable; contribute content, not infrastructure): editor, claude, claude-control, markdown, diff, git-ui, pql, canvas, graph, decisions, tickets, todos, problems.

  • Rationale: The previous session bled several content extensions (jira, todos, decisions, tickets, canvas, graph) into builtin/ as stubs, treating "shipped with the app" as "part of the frame." This conflates two concerns: the frame's structural integrity and the bundled feature set. A user who disables the canvas extension should get a working IDE with no canvas panel; a user who disables the layout extension gets a broken window. The boundary is: can the frame render and function without it? If yes, it's a shipped extension, not a frame builtin.

  • Cost: Shipped extensions need a separate registration path (e.g. lib/extensions/ or equivalent) distinct from lib/builtin/. The extension contract must support "bundled Dart extension" as a first-class category alongside "builtin" and "third-party Lua." Migration is incremental — move one at a time, each behind a working build.

  • Supersedes: Removes builtin.jira (already deleted; should never have been a builtin — Jira integration is a third-party extension, not a shipped one).

  • Raised by: 2026-04-22 session review.


See also the existing builtin.grammars_core stub for tree-sitter questions (Q-15, Q-16).