From 728985b9aaa35bc415a9a766f06a20cd4907ce6a Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 12 Oct 2026 14:55:56 -0700 Subject: [PATCH] docs: move task-specific procedures from AGENTS.md into skills Every agent session loads AGENTS.md whole, but three of its sections only matter for one kind of task. They move, word for word, into skills under .claude/skills/, which agents that support skills load when the task comes up: - implement-component: the component implementation checklist - upgrade-carbon: upgrading the `carbon` catalog and TypeScript - port-ai-chat-component: porting Carbon AI Chat, with its gotchas AGENTS.md keeps a short section for each, with the rules that apply to every change (never bump a catalog dependency on its own; AI Chat's barrel) and a link to the SKILL.md, which any agent can open. It also lists the skills up front, and its update guidelines say where new procedures go. The root .gitignore lets .claude/skills through; the rest of .claude/ stays ignored. Signed-off-by: Alexey Kulakov --- .claude/skills/implement-component/SKILL.md | 21 ++++++++ .../skills/port-ai-chat-component/SKILL.md | 34 +++++++++++++ .claude/skills/upgrade-carbon/SKILL.md | 10 ++++ .gitignore | 3 ++ AGENTS.md | 48 ++----------------- 5 files changed, 73 insertions(+), 43 deletions(-) create mode 100644 .claude/skills/implement-component/SKILL.md create mode 100644 .claude/skills/port-ai-chat-component/SKILL.md create mode 100644 .claude/skills/upgrade-carbon/SKILL.md diff --git a/.claude/skills/implement-component/SKILL.md b/.claude/skills/implement-component/SKILL.md new file mode 100644 index 0000000000..29dcad46c5 --- /dev/null +++ b/.claude/skills/implement-component/SKILL.md @@ -0,0 +1,21 @@ +--- +name: implement-component +description: Add a Carbon component to this addon, or bring an existing one to parity with Carbon React. The checklist from reading the React source to the signature, barrel export, prop parity, tests and stories. +--- + +# Component Implementation Checklist + +Follow AGENTS.md's patterns, conventions and pitfalls at each step. + +- [ ] Review React implementation at GitHub +- [ ] Check Storybook for visual reference +- [ ] Map each React construct to its Ember idiom +- [ ] Create `.gts` file in `carbon-components-ember/src/components/` +- [ ] Define TypeScript signature — fully typed, no `any` +- [ ] Use `cds--` prefix for CSS classes +- [ ] Export it: run `pnpm generate` to regenerate public barrel exports +- [ ] Match React's props: `pnpm --filter dom-parity args --component ` +- [ ] When the PR closes a `[Parity Check]` issue, run `node scripts/parity-check.mjs --mark-synced ` (with `GITHUB_TOKEN`) and commit `.parity-check-data.json`, or the weekly check reopens it; a React directory with no same-named export needs `--exclude --reason "..."` +- [ ] Create test file in `tests/components/` +- [ ] Add a colocated `.stories.gts` mirroring Carbon React's stories; `node scripts/story-parity.mjs --title "Components/"` lists the ones it's missing +- [ ] Validate locally: `pnpm build && pnpm test && pnpm test:storybook` diff --git a/.claude/skills/port-ai-chat-component/SKILL.md b/.claude/skills/port-ai-chat-component/SKILL.md new file mode 100644 index 0000000000..5b2919f03a --- /dev/null +++ b/.claude/skills/port-ai-chat-component/SKILL.md @@ -0,0 +1,34 @@ +--- +name: port-ai-chat-component +description: Port a Carbon AI Chat component from `@carbon/ai-chat-components` (the Lit widget library) to Ember in this repo, or change one under `src/components/ai-chat/`. Covers names and the ai-chat barrel, slots, styling, and the autotracking and modifier gotchas these components hit. +--- + +# Porting Carbon AI Chat + +The port target is the Lit-based framework-agnostic widget library `@carbon/ai-chat-components`, **not** the React shell application. + +## 1. Names and the AI Chat Barrel +AI Chat's components live in `src/components/ai-chat/` and are exported from their own barrel, `carbon-components-ember/ai-chat`, as upstream's are from a package of their own. So they take upstream's names even where Carbon React has a component of the same name: `ai-chat/code-snippet.gts` exports `CodeSnippet` from `carbon-components-ember/ai-chat`, next to Carbon's `CodeSnippet` in `carbon-components-ember/components`. The parity check compares each source with its own barrel. + +## 2. Slots and Block Mappings +- Upstream kebab-case slots become camelCase named blocks (e.g. `header-after` -> `<:headerAfter>`). +- Use `{{has-block "name"}}` instead of Lit `SlotObserver` MutationObservers. + +## 3. Styling Guidelines +- Adapt upstream shadow-DOM `:host(...)` selectors to plain light-DOM classes. +- Reference `@carbon/styles` compiled CSS custom properties directly (`var(--cds-*)`) rather than theme Sass variables. +- Prefer static SCSS for layout over upstream's shadow-DOM-specific runtime CSSOM-injection helpers. + +## 4. Technical Gotchas for AI Chat Components +- **Avoid `@tracked` on internal lazy caches**: If you lazily create or cache values (e.g. `URL.createObjectURL`), use plain private fields rather than `@tracked` properties if they are read and written in the same computation. Reading a tracked field in a getter and modifying it in the same pass triggers Ember's backtracking-rerender assertion. +- **Announcer Region Tracking**: Do not use `@tracked` on the active announcer region index if multiple updates occur synchronously in a single runloop. Keep as plain private state to prevent re-entrant writes. +- **Autotracking in Mount Modifiers**: A modifier's install function must never read a tracked `@arg` directly in its body if you don't want it to teardown and rebuild on every keystroke (e.g., streaming `@content`). Capture initial arguments in the constructor as plain fields, and use separate narrow modifiers (`syncArgs`, `syncValue`) to handle updates. +- **Modifier Rerun Idempotency**: Glimmer can re-evaluate and rerun modifiers even if their declared args haven't changed. For modifiers with destructive or expensive side-effects (like loading a player/editor), use an internal shadow field (e.g. `lastLoadedSource`) to diff before executing. +- **`.module.scss?inline` Imports in Theme Support**: Vite returns classname maps, not CSS text, for CSS Modules imported with `?inline`. Do not interpolate raw style exports into `