acp-runtime
The ACP runtime is the domain service that serves the ACP API contract. It owns the host-scoped dependencies needed to run provider ACP sessions, but it should…
This guide covers the rules and patterns for authoring styles in `packages/ui`. The system uses [vanilla-extract](https://vanilla-extract.style/) (VE) with CSS `@layer` ordering, shared recipes, and composition over inheritance.
How it fires
How this agent gets triggered: by you, by Claude, or both.
Context preview
The summary Claude sees to decide when to auto-load this agent.
This guide covers the rules and patterns for authoring styles in `packages/ui`. The system uses [vanilla-extract](https://vanilla-extract.style/) (VE) with CSS `@layer` ordering, shared recipes, and composition over inheritance.
This guide covers the rules and patterns for authoring styles in `packages/ui`. The system uses [vanilla-extract](https://vanilla-extract.style/) (VE) with CSS `@layer` ordering, shared recipes, and composition over inheritance.
Every CSS property on an element should have exactly **one authoritative source** of truth. When two rules set the same property at the same specificity, source order decides — which is fragile and hard to reason about.
**Anti-pattern (two owners fighting):**
// primitive: always sets padding 0.25rem
export const comboboxList = style({ padding: '0.25rem' });
// consumer: also sets padding → source-order roulette
export const list = style({ padding: '0.25rem' });**Correct (single owner):**
// primitive owns padding; consumer just composes it
// consumer delegates to primitive, no override
<ComboboxList> {/* no extra className needed */}Express component state through `data-*` attributes handled inside the owning `style()` or `recipe()`, not by adding specificity from the outside.
**Anti-pattern (state via higher specificity):**
// parent component pushing state into child via specificity escalation
globalStyle(`${someParent} ${childClass}`, { padding: 0 });**Correct (state-owned selector inside the primitive):**
export const comboboxList = style({
padding: '0.25rem',
selectors: {
'&[data-empty]': { padding: 0 }, // library-owned state drives own style
},
});`globalStyle` with a multi-segment selector that crosses a component boundary (e.g. `${parentClass} [data-slot="child"]`) creates invisible coupling. If the child's class changes, the parent silently breaks.
**Anti-pattern (cross-boundary globalStyle):**
// combobox.css.ts reaching into input-group internals
globalStyle(`${comboboxContent} [data-slot="input-group"]`, {
borderRadius: 0,
boxShadow: 'none',
});**Correct (variant prop on the child):**
// input-group.css.ts adds an "embedded" variant
export const inputGroup = recipe({
variants: {
variant: {
embedded: { borderRadius: 0, boxShadow: 'none' },
},
},
});
// consumer passes the variant explicitly
<InputGroup variant="embedded" />Reuse styles by **composing** `style()` arrays rather than inheriting through class hierarchies or overrides.
// compose shared base into component-specific style
export const menuItem = style([
menuItemBase(), // shared structural recipe
{
selectors: { '&:focus': { backgroundColor: vars.surfaceHover } },
},
]);VE's `style([...])` merges multiple style objects/classes into one atomic class at build time. The `recipe()` base also accepts an array:
recipe({ base: [sharedBase, { componentSpecific: '...' }] })Use the shared helpers from `@styles/effects/svg-helpers.css` instead of hand-rolling `globalStyle` for SVG sizing.
| Helper | Effect | |--------|--------| | `svgContainer` | `svg { pointer-events: none; flex-shrink: 0 }` | | `svgDefaultSize` | `svg:not([class*='size-']) { width: 1rem; height: 1rem }` | | `svgSmSize` | `svg:not([class*='size-']) { width: 0.75rem; height: 0.75rem }` | | `svgTextSize` | same as default (alias for inline text contexts) |
export const menuItem = style([svgContainer, svgDefaultSize, { /* ... */ }]);`@styles/recipes/menu-item.css` — structural recipe for all list item rows (DropdownMenu, Select, Combobox, ComboboxPopup).
import { menuItemBase } from '@styles/recipes/menu-item.css';
export const myItem = style([
menuItemBase({ trailingIndicator: true, fullWidth: true }),
{ selectors: { '&:focus': { backgroundColor: vars.surfaceHover } } },
]);Variants: `trailingIndicator`, `fullWidth`, `inset`, `muted`.
`@styles/recipes/popup-surface.css` — base style for floating popup containers with the animation keyframe selectors and visual properties already wired up.
import { popupSurface, popupShadowMd } from '@styles/recipes/popup-surface.css';
export const myMenu = style([
popupSurface,
popupShadowMd,
{ minWidth: '12rem', padding: '0.25rem' },
]);Shadow variants: `popupShadowSm` (tooltips, comboboxes), `popupShadowMd` (menus, selects).
`InputGroup` accepts a `variant` prop:
// ComboboxInput uses "embedded" automatically <InputGroup variant="embedded" />
`Input` accepts a `bare` boolean that strips its standalone border/shadow/focus ring. `InputGroupInput` passes `bare` automatically; consumers should not need it directly.
The layer order is: `reset < tokens < base < recipes < utilities`.
**Migration path:** To place a style in the `recipes` layer, wrap properties inside `'@layer': { recipes: { ... } }`:
export const foo = style({
'@layer': {
recipes: {
color: vars.foreground,
selectors: { '&:hover': { backgroundColor: vars.surfaceHover } },
},
},
});> **Important:** Unlayered styles always beat ALL layered styles. The migration must > be coordinated — mixing layered and unlayered styles for the same property on the > same element will make the unlayered one always win regardless of intent. > Migrate an entire property-ownership group at once.
If a consumer g
Emdash is the Open-Source Agentic Development Environment (🧡 YC W26). Run multiple coding agents in parallel. Use any provider.
Repo: generalaction/emdash
The ACP runtime is the domain service that serves the ACP API contract. It owns the host-scoped dependencies needed to run provider ACP sessions, but it should…
This page defines the target organization of `packages/core/src/`. Core is organized by module type so that shared domain APIs and their platform…
Git is split into a transport contract and a host-scoped runtime. Renderer, desktop, and workspace-server code share the Wire vocabulary without importing Git…
The main process is organized into domain modules under `src/main/core/`. Each domain typically has a `controller.ts` (RPC handlers) and service/implementation…
`@emdash/core/primitives/path/api` is the source of truth for portable file identity and lexical path operations. The detailed package docs live in…