Files
clide/governance/decisions/extensions.md
T
jpmschweitzerandClaude Opus 4.8 9be75d5592 clean-house: fix 37 stale DQR cross-links; sort architecture.md decisions
clean-house sweep over governance/ (validate green, 0 broken refs before
and after):

- RULE-ANCHOR-DRIFT (37): rewrote inline cross-reference links left over
  from before the decisions/questions/rejected subdir split — flat naming
  (questions-architecture.md, questions-process.md, rejected.md) and bare
  same-dir paths that were actually cross-type — to canonical
  subdir-relative form with current slugs. pql resolved these by ID so they
  were never broken to the tooling, only to GitHub anchor navigation.
- RULE-RECORD-SORT (1): reordered decisions/architecture.md D-records to
  strictly ascending (the D-1..D-6 block had been appended after D-41); pure
  block move, line count unchanged, content identical.
- RULE-FILE-OVER-THRESHOLD: deferred (architecture.md 435 > 350; splitting
  would re-churn the anchors just fixed).
- EOF/whitespace and Q↔D backlinks clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 12:50:27 +02:00

65 lines
6.6 KiB
Markdown

# 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](#d-19-lua-runtime-as-ptyc-peer-supporter-tool)). 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](accessibility.md#d-21-i18n-is-a-tier-0-contract-fframe-pattern--locale-fallback-chain)).
- **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](../questions/process.md#q-15-editor-tab--full-lsp-vs-tree-sitter-only-highlight),
[Q-16](../questions/process.md#q-16-tree-sitter-dart-grammar-maintenance)).*