Skip to content
Merged
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
10 changes: 10 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ jobs:
# shared CI-boot paths trigger it.
- *shared
- 'packages/bxl/**'
# The card-authoring skill's claims are pinned by a BXL suite
# that reads the skill file, so an edit to the skill has to run
# that suite too.
- 'packages/boxel-cli/plugin/skills/bxl-authoring/**'
Comment thread
habdelra marked this conversation as resolved.
# That suite also asserts the host suites the skill cites still
# exist. `bxl-test` runs unconditionally on main, so without
# these a host-only rename would merge green and redden main on
# a commit whose own CI never ran the failing suite.
- 'packages/host/tests/integration/bxl-*'
- 'packages/host/tests/helpers/cards/bxl-*'
bench-amd:
# The AMD transpiler is a runtime-common module with no
# cross-workspace deps that affect its wall-time, so the
Expand Down
41 changes: 21 additions & 20 deletions packages/boxel-cli/plugin/README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/boxel-cli/plugin/skills/boxel-design/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Read it in full before any user-facing card design. This skill (`boxel-design`)

Choose the governing style source before stage 1:

- **Boxel built-in feature work:** use the built-in Boxel Brand Guide as the style guide (`https://cardstack.com/base/Theme/boxel-brand-guide`). This covers base cards, host-facing Boxel UI, Boxel-branded catalog material, and built-in feature design.
- **Boxel built-in feature work:** use the built-in Boxel Brand Guide as the style guide (`@cardstack/base/Theme/boxel-brand-guide`). This covers base cards, host-facing Boxel UI, Boxel-branded catalog material, and built-in feature design.
- **User/custom realm work:** derive or choose the Theme/StyleReference/BrandGuide from the user's domain and content. Do not default to Boxel branding unless the user asks for Boxel-branded output.
- **Logo, mark, or official brand material needed:** use a `BrandGuide`; its `markUsage`, `brandColorPalette`, `functionalPalette`, typography, voice, and quality standards are the source. Do not invent logo URLs or store them as miscellaneous string fields.

Expand Down
39 changes: 23 additions & 16 deletions packages/boxel-cli/plugin/skills/boxel-environment/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ boxel:

You are the orchestrator of the Boxel AI Assistant. You decide which host command to call, when to switch submode, when to swap LLM, and when to activate companion skills. You work alongside `boxel` (the coding skill) and `source-code-editing` (the SEARCH/REPLACE format).

## 🚨 Read this before planning anything

**[`references/host-commands-reference.md`](references/host-commands-reference.md) is where the host commands come from — not this file.** Reading it is what makes `switch-submode`, `show-card`, `search-cards`, and the rest callable. Until you have read it you cannot drive the app at all, no matter what this page says a command does: the names below are descriptions, and the tools themselves arrive with that file.

So read it as your first action, before you plan the work or tell the user what you are about to do. If you find yourself about to say you lack a tool, or asking the user to switch to code mode by hand, you have not read it yet.

---

## ⚠️ Master Decision Tree
Expand Down Expand Up @@ -41,6 +47,7 @@ You are the orchestrator of the Boxel AI Assistant. You decide which host comman
└─ NO → activate via update-room-skills_3875
→ Need file content? read-file-for-ai-assistant
→ Use SEARCH/REPLACE. For NEW files: add "(new)" after the URL in the SEARCH/REPLACE block.
→ Every file the task needs goes in ONE reply — three cards, three blocks, one answer. Handing back after each file ends the turn and nothing resumes the rest of your plan.
→ For code-change intent, ALWAYS use SEARCH/REPLACE. Data/document commands are secondary.
→ After user accepts (stay in current mode):
├─ Run `npx boxel lint` (installed npm CLI) for changed `.gts` files (`boxel/references/lint-workflow.md`)
Expand All @@ -62,7 +69,7 @@ You are the orchestrator of the Boxel AI Assistant. You decide which host comman

Full create/edit tool tables, file naming, and path rules: `references/card-tool-selection.md`.

> **⚠️ Streaming rule:** Create and edit files with SEARCH/REPLACE — avoid `write-text-file`. Tool calls don't stream — the whole payload must be generated before the user sees anything, so the UI looks frozen. SEARCH/REPLACE streams visibly for `.gts` and `.json` alike.
> **⚠️ Streaming rule:** Every text file is created and edited with SEARCH/REPLACE — `.gts`, `.json`, `.md`, `README`, all of themadding `(new)` after the URL to create one. There is no file-writing tool to reach for instead: a tool call cannot stream, so the whole payload has to be generated before the user sees anything and the UI looks frozen.

### Step 5 — Search / find

Expand Down Expand Up @@ -105,27 +112,27 @@ Full create/edit tool tables, file naming, and path rules: `references/card-tool

Batch your reads: fetch the always-relevant set in one multi-file read when this skill activates, and pull by-task references the same way — everything you know you need in one go, not one or two per turn.

Always-relevant:
- `references/assistant-persona.md` — Communication style. Concise, intent-based responses.
- `references/calling-commands.md` — JSON structure for all tool calls. Required before any command execution.
- `references/user-environment-awareness.md` — Parse workspace, mode, open cards from each message.
- `references/host-commands-reference.md` — Full catalog of every host command, what it does, approval rules.
Always-relevant — read these together, first:
- **[`references/host-commands-reference.md`](references/host-commands-reference.md)****the host commands themselves.** Reading this is what makes them callable; every other file here only tells you how to use what it gives you.
- [`references/calling-commands.md`](references/calling-commands.md) — JSON structure for all tool calls. Required before any command execution.
- [`references/assistant-persona.md`](references/assistant-persona.md)Communication style. Concise, intent-based responses.
- [`references/user-environment-awareness.md`](references/user-environment-awareness.md)Parse workspace, mode, open cards from each message.

By task:
- `references/choosing-llm-models.md` — Model selection. Check when code tasks detected or debugging stuck.
- `references/searching-and-querying.md` — Query syntax for finding cards.
- `references/workflows-and-orchestration.md` — Multi-step patterns (migrations, bulk operations).
- `references/markdown-edit.md` — Editing long markdown fields surgically.
- `../boxel/references/lint-workflow.md` — Required installed npm `boxel` lint gate for `.gts` code tasks.
- [`references/choosing-llm-models.md`](references/choosing-llm-models.md) — Model selection. Check when code tasks detected or debugging stuck.
- [`references/searching-and-querying.md`](references/searching-and-querying.md) — Query syntax for finding cards.
- [`references/workflows-and-orchestration.md`](references/workflows-and-orchestration.md) — Multi-step patterns (migrations, bulk operations).
- [`references/markdown-edit.md`](references/markdown-edit.md) — Editing long markdown fields surgically.
- [`../boxel/references/lint-workflow.md`](../boxel/references/lint-workflow.md) — Required installed npm `boxel` lint gate for `.gts` code tasks.

Troubleshooting:
- `references/common-errors.md` — Tool-call JSON errors and their fixes (XML in JSON, wrong key names, escaping, etc.).
- [`references/common-errors.md`](references/common-errors.md) — Tool-call JSON errors and their fixes (XML in JSON, wrong key names, escaping, etc.).

Specialty:
- `references/indexing-operations.md` — Realm reindexing commands.
- `references/fresh-realm-push-integrity.md` — First-deployment ordering: definitions ready before instances, nested-field readback, and forced rewrites when mixed pushes silently store `null` leaves.
- `references/diagnosing-broken-links.md` — The broken-link DOM placeholder as the canonical signal; the `data-test-broken-link-*` attribute contract; `error` vs `not-found`; the follow-the-URL-to-the-linked-instance remediation workflow. (Card-author side: `boxel/references/defensive-link-traversal.md`.)
- `references/source-code-editing.md` — Cross-link to the SEARCH/REPLACE skill.
- [`references/indexing-operations.md`](references/indexing-operations.md) — Realm reindexing commands.
- [`references/fresh-realm-push-integrity.md`](references/fresh-realm-push-integrity.md) — First-deployment ordering: definitions ready before instances, nested-field readback, and forced rewrites when mixed pushes silently store `null` leaves.
- [`references/diagnosing-broken-links.md`](references/diagnosing-broken-links.md) — The broken-link DOM placeholder as the canonical signal; the `data-test-broken-link-*` attribute contract; `error` vs `not-found`; the follow-the-URL-to-the-linked-instance remediation workflow. (Card-author side: `boxel/references/defensive-link-traversal.md`.)
- [`references/source-code-editing.md`](references/source-code-editing.md) — Cross-link to the SEARCH/REPLACE skill.

## Sibling skills

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ boxel:
module: '@cardstack/boxel-host/tools/update-code-path-with-selection'
name: default
requiresApproval: false
- codeRef:
module: '@cardstack/boxel-host/tools/write-text-file'
name: default
requiresApproval: true
- codeRef:
module: '@cardstack/boxel-host/tools/copy-card'
name: default
Expand All @@ -69,7 +65,7 @@ Quick lookup of every command available to this skill, what it does, and notable
## Editing

- **SEARCH/REPLACE** — The way to create or edit files, `.gts` and `.json` alike. Streams as visible text so the user sees real-time progress, and runs through the code-patch pipeline with correctness checking. Create a new file by marking its URL line with `(new)`.
- `write-text-file_e5a1` — **Avoid; use SEARCH/REPLACE instead.** Tool calls don't stream, so the UI appears frozen during long generation, and the write skips the code-patch pipeline.
- There is no file-writing tool. Every text file — `.gts`, `.json`, `.md`, `README`, anything — is written with SEARCH/REPLACE, adding `(new)` after the URL to create one. A tool call cannot stream, so the UI sits frozen through a long generation and the write skips the code-patch pipeline; SEARCH/REPLACE streams as it is produced and goes through lint and correctness checks.
- `patch-fields_3e67` — Fine-grained card field updates (requires approval).
- `patchCardInstance` — Update card data only.
- `ApplyMarkdownEditCommand_c112` — Edit long markdown fields (>500 chars) surgically without truncation (requires approval).
Expand Down Expand Up @@ -110,4 +106,4 @@ Quick lookup of every command available to this skill, what it does, and notable
## Approval requirements

The following require user approval before execution:
- `transform-cards`, `write-text-file`, `copy-card`, `copy-source`, `patch-fields`, `apply-markdown-edit`
- `transform-cards`, `copy-card`, `copy-source`, `patch-fields`, `apply-markdown-edit`
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ Sample command from the shell:
expected=$(find <kit-dir> -name "*.json" -not -path "*/Theme/*" -not -name "_*" | wc -l)
# Currently indexed CardDef instances
indexed=$(npx boxel search --realm <url> --query \
'{"filter":{"type":{"module":"https://cardstack.com/base/card-api","name":"CardDef"}}}' --json \
'{"filter":{"type":{"module":"@cardstack/base/card-api","name":"CardDef"}}}' --json \
| jq '.data | length')
echo "$indexed / $expected indexed"
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ When user has multiple open cards, the navigation stack provides context:
const openCardStack = [
'https://app.boxel.ai/user/BlogApp',
'https://app.boxel.ai/user/BlogPost/1',
'https://cardstack.com/base/Author/jane' // May be read-only realm
'@cardstack/base/Author/jane' // May be read-only realm
];

const currentCard = openCardStack[openCardStack.length - 1];
const navigationPath = openCardStack.map(url => url.split('/').pop());
const navigationPath = openCardStack.map(id => id.split('/').pop());
// → ['BlogApp', '1', 'jane']
```

Use stack URLs to fetch card details and understand user's exploration path.
Use stack ids to fetch card details and understand user's exploration path.


## Location Parsing
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
## Import Paths

```gts
import FileDef from 'https://cardstack.com/base/file-api';
import FileDef from '@cardstack/base/file-api';

// Image types
import ImageDef from 'https://cardstack.com/base/image-file-def';
import PngDef from 'https://cardstack.com/base/png-image-def';
import JpgDef from 'https://cardstack.com/base/jpg-image-def';
import SvgDef from 'https://cardstack.com/base/svg-image-def';
import GifDef from 'https://cardstack.com/base/gif-image-def';
import WebpDef from 'https://cardstack.com/base/webp-image-def';
import AvifDef from 'https://cardstack.com/base/avif-image-def';
import ImageDef from '@cardstack/base/image-file-def';
import PngDef from '@cardstack/base/png-image-def';
import JpgDef from '@cardstack/base/jpg-image-def';
import SvgDef from '@cardstack/base/svg-image-def';
import GifDef from '@cardstack/base/gif-image-def';
import WebpDef from '@cardstack/base/webp-image-def';
import AvifDef from '@cardstack/base/avif-image-def';

// Document / text types
import MarkdownDef from 'https://cardstack.com/base/markdown-file-def';
import TextFileDef from 'https://cardstack.com/base/text-file-def';
import TsFileDef from 'https://cardstack.com/base/ts-file-def';
import GtsFileDef from 'https://cardstack.com/base/gts-file-def';
import JsonFileDef from 'https://cardstack.com/base/json-file-def';
import CsvFileDef from 'https://cardstack.com/base/csv-file-def';
import MarkdownDef from '@cardstack/base/markdown-file-def';
import TextFileDef from '@cardstack/base/text-file-def';
import TsFileDef from '@cardstack/base/ts-file-def';
import GtsFileDef from '@cardstack/base/gts-file-def';
import JsonFileDef from '@cardstack/base/json-file-def';
import CsvFileDef from '@cardstack/base/csv-file-def';
```

### Named vs default export

Most FileDef subtypes are **default-exported** (`import ImageDef from ...`). A few are **named-exported** — confirmed from the monorepo + live realm checks:

```ts
import { MarkdownDef } from 'https://cardstack.com/base/markdown-file-def';
import { SvgDef } from 'https://cardstack.com/base/svg-image-def';
import { PngDef } from 'https://cardstack.com/base/png-image-def';
import { CsvFileDef } from 'https://cardstack.com/base/csv-file-def';
import { TextFileDef } from 'https://cardstack.com/base/text-file-def';
import { MarkdownDef } from '@cardstack/base/markdown-file-def';
import { SvgDef } from '@cardstack/base/svg-image-def';
import { PngDef } from '@cardstack/base/png-image-def';
import { CsvFileDef } from '@cardstack/base/csv-file-def';
import { TextFileDef } from '@cardstack/base/text-file-def';
```

If the import compiles but the linked field resolves to `undefined` at render time, swap default ↔ named — that's the usual fix.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ These are completely different and are **not interchangeable**:
| | `MarkdownDef` | `MarkdownField` |
| ------------------------ | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| **Kind** | FileDef — a `.md` file in the realm | FieldDef — inline text stored in the card's JSON |
| **Import** | `https://cardstack.com/base/markdown-file-def` | `https://cardstack.com/base/markdown` |
| **Import** | `@cardstack/base/markdown-file-def` | `@cardstack/base/markdown` |
| **Declaration** | `@field notes = linksTo(MarkdownDef)` | `@field notes = contains(MarkdownField)` |
| **Stored as** | Separate `.md` file referenced by URL | String embedded in the card's `.json` |
| **Has own URL?** | ✅ Yes — shareable and reusable | ❌ No — owned by the containing card |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ For AI image APIs that return a `data:image/...;base64,...`, strip the `data:mim

```gts
import WriteBinaryFileCommand from '@cardstack/boxel-host/tools/write-binary-file';
import { ImageDef, linksTo } from 'https://cardstack.com/base/card-api';
import { ImageDef, linksTo } from '@cardstack/base/card-api';

@field generatedImage = linksTo(ImageDef);

Expand Down Expand Up @@ -57,7 +57,7 @@ This is the same host-command family used by `packages/host/app/tools/screenshot
`realms-staging.stack.cards/ctse/personal/a-million-dreams-karaoke.gts` handles MP3 and cover art correctly:

```gts
import { FileDef, ImageDef, linksTo } from 'https://cardstack.com/base/card-api';
import { FileDef, ImageDef, linksTo } from '@cardstack/base/card-api';

@field mp3FileDef = linksTo(FileDef);
@field coverArt = linksTo(ImageDef);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
## Using FileDef in Cards

```gts
import { CardDef, field, linksTo } from 'https://cardstack.com/base/card-api';
import ImageDef from 'https://cardstack.com/base/image-file-def';
import PngDef from 'https://cardstack.com/base/png-image-def';
import FileDef from 'https://cardstack.com/base/file-api';
import MarkdownDef from 'https://cardstack.com/base/markdown-file-def';
import { CardDef, field, linksTo } from '@cardstack/base/card-api';
import ImageDef from '@cardstack/base/image-file-def';
import PngDef from '@cardstack/base/png-image-def';
import FileDef from '@cardstack/base/file-api';
import MarkdownDef from '@cardstack/base/markdown-file-def';

export class ProductListing extends CardDef {
@field photo = linksTo(PngDef); // Specifically PNG
Expand All @@ -20,7 +20,7 @@ export class ProductListing extends CardDef {
The A Million Dreams karaoke card keeps a multi-megabyte MP3 out of card JSON by linking to the realm file:

```gts
import { FileDef, ImageDef, linksTo } from 'https://cardstack.com/base/card-api';
import { FileDef, ImageDef, linksTo } from '@cardstack/base/card-api';

@field mp3FileDef = linksTo(FileDef);
@field coverArt = linksTo(ImageDef);
Expand Down Expand Up @@ -49,7 +49,7 @@ When generated media arrives as a `data:image/...;base64,...`, write it to the r

```gts
import WriteBinaryFileCommand from '@cardstack/boxel-host/tools/write-binary-file';
import { ImageDef, linksTo } from 'https://cardstack.com/base/card-api';
import { ImageDef, linksTo } from '@cardstack/base/card-api';

@field outputImage = linksTo(ImageDef);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
It's a format slot like `static isolated`, but emits **plain text**, not HTML. Glimmer HTML-escapes the string in the DOM; the prerender pipeline decodes those entities when it captures `textContent`, so the markdown parser downstream sees the literal characters you emitted.

```gts
import { CardDef, Component } from 'https://cardstack.com/base/card-api';
import { CardDef, Component } from '@cardstack/base/card-api';
import { markdownEscape } from '@cardstack/boxel-ui/helpers';

export class Note extends CardDef {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## The `markdown-helpers` toolkit

Module: `https://cardstack.com/base/markdown-helpers`
Module: `@cardstack/base/markdown-helpers`

```gts
import {
Expand All @@ -14,7 +14,7 @@ import {
markdownLinksForCards,
markdownEmbedForCard,
markdownEmbedsForCards,
} from 'https://cardstack.com/base/markdown-helpers';
} from '@cardstack/base/markdown-helpers';
```

All helpers return pre-escaped strings — safe to interpolate directly.
Expand Down
Loading
Loading