Prefix enforcement prevents extension CSS from leaking into the kernel
or sibling extensions. All 12 in-tree packages migrated to .ext-{slug}-*
naming convention.
- Add data-ext attribute to extension mount container
- Add CSS linter (scripts/lint-package-css.sh) enforcing .ext-{slug} prefix
- Add kernel CSS contract doc (docs/EXTENSION-CSS.md)
- Migrate 12 packages: chat, dashboard, editor, git-board, hello-dashboard,
icd-test-runner, notes, schedules, sdk-test-runner, tasks,
team-activity-log, workflow-demo (CSS + JS in lockstep)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4.6 KiB
Extension CSS Contract
Version: v0.6.12 — Extension CSS Isolation
This document defines the CSS contract between the Armature kernel and extension packages. Extensions must follow these rules; the kernel guarantees the listed classes and variables are stable public API.
Naming Rule
All class selectors in extension CSS (packages/{slug}/css/main.css) must start
with .ext-{slug}-. The {slug} is the package directory name.
/* Good */
.ext-my-app-sidebar { ... }
.ext-my-app-card { ... }
/* Bad — will be rejected by the linter */
.sidebar { ... }
.my-sidebar { ... }
Compound selectors: Descendant classes scoped under your .ext-{slug} root
are allowed to reference kernel classes or state modifiers:
/* Allowed — kernel class scoped under extension namespace */
.ext-my-app .sw-btn { margin-top: 8px; }
/* Allowed — state modifier on an extension element */
.ext-my-app-item.active { ... }
Run bash scripts/lint-package-css.sh to validate. The linter checks that the
first class selector in every rule starts with .ext-{slug}.
Stable Kernel Classes
Extensions may reference these classes in compound selectors. They are part of the public API and will not change without a major version bump.
Components (from sw-primitives.css)
| Class pattern | Component |
|---|---|
.sw-btn, .sw-btn--{variant}, .sw-btn--{size} |
Buttons |
.sw-input |
Text inputs |
.sw-field, .sw-field__label, .sw-field__hint |
Form fields |
.sw-dialog, .sw-dialog__header, .sw-dialog__body, .sw-dialog__footer |
Dialogs |
.sw-toast, .sw-toast-container |
Toast notifications |
.sw-menu, .sw-menu-item |
Context menus |
.sw-tabs, .sw-tab-btn |
Tab strips |
.sw-dropdown |
Custom dropdowns |
.sw-spinner |
Loading spinners |
.sw-avatar |
User avatars |
.sw-drawer |
Slide-out drawers |
.sw-banner |
Banner bars |
.sw-tooltip |
Tooltips |
Extension Mount
The extension surface container has a data-ext attribute set to the package
slug. Use this for scoping if needed:
[data-ext="my-app"] .ext-my-app-sidebar { ... }
Stable CSS Variables
All variables from variables.css are public API. Extensions should use these
instead of hardcoded colors to respect the user's theme.
Colors
| Variable | Purpose |
|---|---|
--bg |
Page background |
--bg-secondary |
Secondary/darker background |
--bg-elevated |
Elevated surface background |
--bg-raised |
Raised card background |
--bg-surface |
Surface-level background |
--bg-hover |
Hover state background |
--bg-active |
Active/pressed state background |
--bg-code |
Code block background |
--text |
Primary text color |
--text-2 |
Secondary text color |
--text-3 |
Tertiary/muted text color |
--text-on-color |
Text on colored backgrounds |
--accent |
Primary accent color |
--accent-dim |
Dimmed accent for backgrounds |
--accent-hover |
Accent hover state |
--accent-light |
Light accent variant |
--border |
Default border color |
--border-light |
Light border variant |
--border-elevated |
Border for elevated surfaces |
--danger |
Error/destructive color |
--danger-dim |
Dimmed danger background |
--danger-light |
Light danger variant |
--success |
Success/positive color |
--success-dim |
Dimmed success background |
--success-light |
Light success variant |
--warning |
Warning/caution color |
--warning-dim |
Dimmed warning background |
--warning-light |
Light warning variant |
--purple |
Purple accent |
--purple-dim |
Dimmed purple background |
Layout & Typography
| Variable | Purpose |
|---|---|
--font |
Primary font family |
--mono |
Monospace font family |
--radius |
Default border-radius (8px) |
--radius-lg |
Large border-radius (12px) |
--transition |
Default transition timing |
--shadow-lg |
Large elevation shadow |
--overlay |
Modal overlay color |
--glass |
Glassmorphism backdrop |
--input-bg |
Form input background |
--sidebar-w |
Sidebar width |
What Is Internal
Everything not listed above is internal kernel CSS and may change between minor versions. Extensions must not depend on:
- Kernel layout classes (
.admin-*,.surface-*,.sidebar, etc.) - Kernel CSS file load order
- Specific HTML structure of the shell or topbar
- Undocumented CSS variables
Enforcement
The linter script scripts/lint-package-css.sh runs against all
packages/*/css/main.css files. It exits non-zero if any rule's first class
selector does not start with .ext-{slug}.