Labels
Labels are additive, colored tags you can apply to sessions. Unlike statuses (which are exclusive — one per session), labels are multi-select — a session can have zero or many labels. They support hierarchical organization via nested trees.
How Labels Work
Section titled “How Labels Work”Labels let you categorize conversations by project, topic, priority, or anything else — making it easy to filter and find related sessions later.
| Feature | Description |
|---|---|
| Multi-select | A session can have many labels simultaneously |
| Hierarchical | Labels can be nested to form groups (up to 5 levels) |
| Color-coded | Each label is rendered as a colored circle |
| Valued | Labels can optionally carry a value (text, number, or date) |
| Auto-applied | Regex rules can apply labels automatically from message content |
Workspace-Level Configuration
Section titled “Workspace-Level Configuration”Labels are configured per workspace. Each workspace starts with zero labels — you create whatever labels you need.
Configuration is stored at:
~/.craft-agent/workspaces/{workspace-id}/labels/config.jsonCreating Labels
Section titled “Creating Labels”You can also create labels manually by editing the configuration file.
Basic Example
Section titled “Basic Example”{ "version": 1, "labels": [ { "id": "bug", "name": "Bug", "color": "destructive" }, { "id": "feature", "name": "Feature", "color": "accent" } ]}Hierarchical Labels
Section titled “Hierarchical Labels”Labels form a nested tree. Parent/child relationships are expressed via the children array. Array position determines display order.
{ "version": 1, "labels": [ { "id": "eng", "name": "Engineering", "color": "info", "children": [ { "id": "frontend", "name": "Frontend", "children": [ { "id": "react", "name": "React", "color": { "light": "#3B82F6", "dark": "#60A5FA" } } ] }, { "id": "backend", "name": "Backend" } ] }, { "id": "bug", "name": "Bug", "color": "destructive" } ]}This renders as a tree in the sidebar:
Engineering |- Frontend | \- React \- BackendBugHierarchy Rules
Section titled “Hierarchy Rules”- IDs are simple slugs (lowercase alphanumeric + hyphens)
- IDs must be globally unique across the entire tree
- Maximum nesting depth: 5 levels
- Array position = display order (no
orderfield needed) - Filtering by a parent includes all descendant sessions
Label Properties
Section titled “Label Properties”Each label object supports these properties:
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | — | Unique slug (lowercase alphanumeric + hyphens) |
name | string | Yes | — | Display name |
color | EntityColor | No | currentColor at 40% opacity | Color for the label circle (see below) |
valueType | "string" | "number" | "date" | "link" | No | (none — presence-only) | Value type hint. Omit for presence-only labels. |
children | Label[] | No | [] | Nested child labels |
autoRules | AutoRule[] | No | [] | Regex rules for auto-applying (see Auto-Apply Rules) |
Colors
Section titled “Colors”Labels are rendered as colored circles in the UI. You can use system colors or custom hex values.
System Colors
Section titled “System Colors”Use semantic color names for common meanings:
| Color | Use For |
|---|---|
"destructive" | Bugs, errors, critical issues |
"accent" | Features, enhancements |
"success" | Completed, passing |
"info" | Informational, metadata |
"foreground/60" | Neutral, miscellaneous |
System colors also support opacity: "accent/80", "info/50", etc.
Custom Colors
Section titled “Custom Colors”For precise control, use light/dark mode pairs:
{ "color": { "light": "#6366F1", "dark": "#818CF8" }}Supports hex, OKLCH, RGB, and HSL formats.
Label Values
Section titled “Label Values”Labels can optionally carry a value with a specific type. This turns labels into structured metadata — for example, a “priority” label with value 3, or a “due” label with a date.
Storage Format
Section titled “Storage Format”Sessions store labels as an array of strings. Boolean labels are bare IDs; valued labels use the :: separator:
{ "labels": ["bug", "priority::3", "due::2026-01-30", "linear::CRA-456"]}- Boolean labels:
"bug"— presence-only, no value - Valued labels:
"priority::3"— ID + value separated by:: - The
::split happens on the first occurrence only (values may contain::)
Value Types
Section titled “Value Types”Values are inferred from the raw string at parse time:
| Type | Format | Example |
|---|---|---|
number | Finite number | "priority::3", "effort::0.5" |
date | ISO date (YYYY-MM-DD) | "due::2026-01-30" |
link | URL (opens in browser on click; scheme optional) | "docs::https://example.com" |
string | Anything else | "team::platform" |
Inference order: ISO date check -> number check -> string fallback.
The valueType in config is a hint for the UI — the parser always infers from the raw value. link is a display affordance: the value renders as a clickable chip (scheme stripped for display) that opens in your external browser, with an Open link action in the value popover for keyboard access. A link value still stores and parses as a plain string.
Sidebar Behavior
Section titled “Sidebar Behavior”Labels appear in the left sidebar as a multi-level expandable section. Clicking a label filters the session list to show only matching sessions. Clicking a parent label includes sessions tagged with any descendant.
Validation
Section titled “Validation”After editing the config file, validate it to catch errors:
config_validate({ target: "labels" })The validator checks:
- Valid JSON and recursive schema structure
- Globally unique IDs across the entire tree
- Valid slug format (lowercase alphanumeric with hyphens)
- Maximum nesting depth (5 levels)
Key Differences from Statuses
Section titled “Key Differences from Statuses”| Labels | Statuses | |
|---|---|---|
| Cardinality | Multi-select (many per session) | Exclusive (one per session) |
| Defaults | None — start empty | Ships with 5 defaults |
| Visual | Colored circles | Icons + colors |
| Hierarchy | Nested tree (up to 5 levels) | Flat list |
| Values | Optional typed values | No values |
| Filtering | Multi-label intersection | Category-based (open/closed) |