Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/skills/boxel-development/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Use this skill for Boxel card and app development. Keep the top-level guidance l

These three files establish the data model, the `contains` vs `linksTo` rule, required formats, inherited fields, and common import patterns.


## Load By Task

- Card structure and safe patterns:
Expand Down
69 changes: 69 additions & 0 deletions .github/workflows/mirror-boxel-ui-specs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Mirror Boxel UI Component Specs

# Pushes generated boxel-ui component specs into cardstack/boxel-catalog so
# the deployed catalog realm (which is served from that external repo) sees
# them. See CS-10527 for context and packages/boxel-ui/addon/bin/generate-component-specs.mjs
# for the generator.
#
# HUMAN SETUP REQUIRED before this workflow runs successfully:
# 1. Create a deploy key or fine-grained PAT with write access to
# cardstack/boxel-catalog.
# 2. Store it in this repo as the BOXEL_CATALOG_PUSH_TOKEN secret.
# 3. Verify the secret has permissions to push to cardstack/boxel-catalog's
# default branch (or to push branches + open PRs if you prefer the
# PR-based flow — see the commented `gh pr create` step below).
# Until those are set up, this workflow will fail at the push step.

on:
push:
branches: [main]
paths:
- 'packages/boxel-ui/addon/src/components/**/usage.gts'
- 'packages/boxel-ui/addon/bin/generate-component-specs.mjs'

permissions:
contents: read

jobs:
mirror:
name: Mirror specs to cardstack/boxel-catalog
runs-on: ubuntu-latest
concurrency:
group: mirror-boxel-ui-specs
cancel-in-progress: false
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: boxel
- uses: ./boxel/.github/actions/init

- name: Clone cardstack/boxel-catalog into packages/catalog/contents
# The generator writes into packages/catalog/contents/Spec/ — the working
# tree of the boxel-catalog repo. Cloning it there serves both as the
# write target for the generator AND the working copy we'll commit and
# push at the end of the job.
run: |
git clone "https://x-access-token:${BOXEL_CATALOG_PUSH_TOKEN}@github.com/cardstack/boxel-catalog.git" boxel/packages/catalog/contents
env:
BOXEL_CATALOG_PUSH_TOKEN: ${{ secrets.BOXEL_CATALOG_PUSH_TOKEN }}

- name: Generate component specs into the catalog working tree
run: pnpm run generate:component-specs
working-directory: boxel/packages/boxel-ui/addon

- name: Commit and push to cardstack/boxel-catalog
run: |
cd boxel/packages/catalog/contents
git config user.name "boxel-ui-specs-bot"
git config user.email "boxel-ui-specs-bot@users.noreply.github.com"
if git diff --quiet --exit-code -- Spec/; then
echo "No spec changes — nothing to mirror."
exit 0
fi
git add Spec/
git commit -m "chore: mirror boxel-ui component specs from boxel@${GITHUB_SHA::7}

Generated by .github/workflows/mirror-boxel-ui-specs.yaml.
Source: https://github.com/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA}
"
git push origin HEAD:main
68 changes: 65 additions & 3 deletions docs/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,81 @@ Each spec type has specific characteristics and use cases:

### 3. Component Specs (`specType: 'component'`)

**Purpose**: Document reusable UI components that don't represent data.
**Purpose**: Document reusable UI components that don't represent data, so AI agents and developers can discover them by searching the catalog instead of needing a per-component skill.

**Characteristics**:
- No support for examples
- Only when it extends Glimmer Component
- Only when it extends Glimmer Component
- Potentially includes reactive data loading resources from ember-resources
- API documentation, an example, and CSS variables live in the `readMe` markdown field
- `cardDescription` is the keyword-rich one-liner the agent matches against — keep it concrete (e.g. "Form text input with validation states") rather than abstract

**Example Use Cases**:
- `CardsGrid` - Responsive grid layout component for card collections
- `FilterDropdown` - Multi-select dropdown component for filtering
- `Pill` - Badge component for displaying tags and statuses
- `LinksToEditor` - Component for editing card relationships

#### Boxel-UI Component Specs

All `@cardstack/boxel-ui` components ship a generated Spec card. The
generator (`packages/boxel-ui/addon/bin/generate-component-specs.mjs`)
walks each component's `usage.gts` file, extracts the `FreestyleUsage`
metadata (arguments, description, example, CSS variables), and emits a
Spec JSON with:

- `ref: { module: '@cardstack/boxel-ui/components', name: ComponentName }`
- `cardTitle: ComponentName`
- `cardDescription`: the top-level `@description` attribute on the
primary `<FreestyleUsage>` tag, or the first sentence of its
`<:description>` block. **For agent discoverability, add a
keyword-rich `@description` attribute to the primary
`<FreestyleUsage>` block in `usage.gts` whenever the synthesized
description is generic.**
- `readMe`: a markdown body with the API table, a usage example, and the
CSS-variable table.

##### Developer workflow

The generated specs are **not committed to the boxel repo**. The
`cardstack/boxel-catalog` repo is the source of truth — boxel just owns
the generator and the inputs (`usage.gts`).

1. Edit the component's `usage.gts`. Make sure the primary
`<FreestyleUsage>` block has a `@description='…'` attribute and
complete `<Args.X>` documentation.
2. (Optional, but recommended) Run
`pnpm --dir packages/boxel-ui/addon generate:component-specs` locally
to inspect the resulting spec content and have your local
realm-server reindex it. Requires
`pnpm --dir packages/catalog catalog:setup` to have run at least
once (clones `cardstack/boxel-catalog` into
`packages/catalog/contents/`, which is gitignored from boxel).
Output: `packages/catalog/contents/Spec/boxel-ui-<slug>.json`.
3. Commit only your `usage.gts` change to your boxel PR — no spec JSON
needs to land in the boxel repo.
4. On merge to `main`, the
`.github/workflows/mirror-boxel-ui-specs.yaml` job clones
`cardstack/boxel-catalog`, regenerates the specs, and pushes the
diff. That repo is `git pull`ed by realm-server at deploy startup
and full-indexed.

##### Gotchas

- `packages/catalog/contents/` is its own git repo (clone of
`cardstack/boxel-catalog`), gitignored from boxel. Edits made
directly there do **not** appear in boxel PRs. The mirror workflow
is the publish path.
- Because the generator regenerates fresh on every mirror run, there
is no in-boxel-repo drift-detection step. If you change `usage.gts`
but don't run the generator locally to eyeball the result, the
catalog still ends up correct — but you only see what the agent will
read at runtime once the mirror PR lands. Running the generator
locally before pushing is the recommended habit.
- The CI mirror job needs a deploy key or fine-grained PAT for
`cardstack/boxel-catalog`, stored as the repo secret
`BOXEL_CATALOG_PUSH_TOKEN`. Until that's wired up, the workflow runs
but fails at the push step.

### 4. App Specs (`specType: 'app'`)

**Purpose**: Document application-level cards that serve as entry points, typically when other cards are queried within them.
Expand Down
Loading
Loading