Help us improve
Share bugs, ideas, or general feedback.
From boxel-cli
Defines file and directory layout conventions for Boxel workspaces. Use when placing .gts definitions, .json instances, or configuring adoptsFrom and linksTo paths.
npx claudepluginhub cardstack/boxel --plugin boxel-cliHow this skill is triggered — by the user, by Claude, or both
Slash command
/boxel-cli:boxel-file-structureThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Rules for organizing files in a Boxel workspace when working locally with boxel-cli.
Creates and edits Boxel card definitions (.gts) and card instances (.json) using CardDef/FieldDef patterns. Covers imports, fields, formats, styling, and common pitfalls.
Automates Box operations like file upload/download, content search, folder management, collaboration, metadata queries, and sign requests using Composio's toolkit.
Automates Box cloud storage: upload/download files, content search, folder management, sharing, collaborations, metadata queries via Rube MCP (Composio).
Share bugs, ideas, or general feedback.
Rules for organizing files in a Boxel workspace when working locally with boxel-cli.
https://[realm-domain]/[username]/[workspace]/[path].[extension]
Example: https://app.boxel.ai/sarah/pet-rescue/animals/dog.gts
| Type | Convention | Example |
|---|---|---|
| Card definitions | kebab-case.gts | blog-post.gts, grammy-award.gts |
| Instance directories | PascalCase/ | BlogPost/, GrammyAward/ |
| Instance files | kebab-case.json | my-first-post.json |
workspace/
├── .realm.json # Workspace config
├── index.json # Workspace index
├── cards-grid.json # Default cards grid
├── blog-post.gts # Card definition (kebab-case)
├── BlogPost/ # Instance directory (PascalCase)
│ ├── my-first-post.json
│ └── another-post.json
├── author.gts
└── Author/
└── jane-doe.json
The adoptsFrom.module path is relative to the JSON file location.
grammy-award.gts # Definition at root
GrammyAward/ # Instances in PascalCase directory
└── record-of-the-year.json
In GrammyAward/record-of-the-year.json:
{
"meta": {
"adoptsFrom": {
"module": "../grammy-award", // ← Go UP to parent, then to file
"name": "GrammyAward"
}
}
}
{
"meta": {
"adoptsFrom": {
"module": "./grammy-award", // ← WRONG! This looks in GrammyAward/
"name": "GrammyAward"
}
}
}
| JSON Location | Definition Location | Module Path |
|---|---|---|
root/Instance.json | root/card.gts | "./card" |
root/Card/instance.json | root/card.gts | "../card" |
root/Card/Sub/instance.json | root/card.gts | "../../card" |
root/Card/instance.json | root/other/card.gts | "../other/card" |
{
"data": {
"type": "card",
"attributes": {
"fieldName": "value",
"numberField": 123,
"boolField": true
},
"relationships": {
"author": {
"links": {
"self": "../Author/jane-doe"
}
}
},
"meta": {
"adoptsFrom": {
"module": "../card-definition",
"name": "CardClassName"
}
}
}
}
🔴 For linksToMany fields, use numbered keys like fieldName.0, fieldName.1, etc.
{
"data": {
"relationships": {
"tags.0": {
"links": {
"self": "../Tag/tech"
}
},
"tags.1": {
"links": {
"self": "../Tag/news"
}
},
"tags.2": {
"links": {
"self": "../Tag/tutorial"
}
}
}
}
}
{
"relationships": {
"tags": {
"links": {
"self": ["../Tag/tech", "../Tag/news"]
}
}
}
}
| Section | Purpose | Required |
|---|---|---|
data.type | Always "card" | Yes |
data.attributes | Scalar field values (string, number, bool) | Yes |
data.relationships | Links to other cards (linksTo/linksToMany) | Only if has links |
data.meta.adoptsFrom | References the card definition | Yes |
Use attributes for:
contains)Use relationships for:
linksTo → single link)linksToMany → array of links)🔴 CRITICAL - memorize this:
| Field Type | Definition uses | Instance uses |
|---|---|---|
Extends CardDef | linksTo / linksToMany | relationships |
Extends FieldDef | contains / containsMany | attributes |
// In .gts definition:
@field author = linksTo(Author); // Author extends CardDef → relationships
@field address = contains(AddressField); // AddressField extends FieldDef → attributes
// In .json instance:
{
"attributes": {
"address": { "street": "123 Main", "city": "NYC" }
},
"relationships": {
"author": { "links": { "self": "../Author/jane" } }
}
}
When linking to other cards, use the card's URL without .json:
{
"data": {
"relationships": {
"author": {
"links": {
"self": "../Author/jane-doe"
}
}
}
}
}
These realms contain shared definitions you can import from:
Production:
https://cardstack.com/base/ - Core types (CardDef, FieldDef, etc.)https://app.boxel.ai/catalog/ - Catalog cardshttps://app.boxel.ai/skills/ - Skill cardsStaging:
https://cardstack.com/base/ - Same core typeshttps://realms-staging.stack.cards/catalog/https://realms-staging.stack.cards/skills/// Core imports (always from cardstack.com/base)
import {
CardDef,
FieldDef,
field,
contains,
linksTo,
containsMany,
linksToMany,
StringField,
NumberField,
BooleanField,
Component,
} from 'https://cardstack.com/base/card-api';
// Import from same workspace
import { Author } from './author';
// Import from base realm
import { Skill } from 'https://cardstack.com/base/skill';
When using the /_search API endpoint:
{
"filter": {
"type": {
"module": "https://realm-url/card-name",
"name": "CardClassName"
}
}
}
With field filters:
{
"filter": {
"on": { "module": "https://realm-url/product", "name": "Product" },
"contains": { "name": "laptop" }
}
}
Operations: eq, contains, range, not, type, every (AND), any (OR)
| Mistake | Fix |
|---|---|
"module": "./card" from subdirectory | Use "../card" |
contains(CardDef) | Use linksTo(CardDef) |
linksTo(FieldDef) | Use contains(FieldDef) |
Link in attributes | Move to relationships |
FieldDef in relationships | Move to attributes |
Missing data wrapper in JSON | Wrap everything in {"data": {...}} |
PascalCase for .gts files | Use kebab-case.gts |
| kebab-case for instance dirs | Use PascalCase/ |
linksToMany as array | Use numbered keys: field.0, field.1, etc. |
Every CardDef should implement these templates:
isolated - Full detail view (scrollable)embedded - Compact summary for listsfitted - Fixed dimensions for grids/dashboards (CRITICAL for good UX)