How the Dynamic Status System Works in Craft Agents Workspaces: A Technical Deep Dive

The dynamic status system in Craft Agents workspaces enables per-workspace customization of conversation states through a three-layer architecture that separates data models, JSON persistence, and business rule enforcement while protecting fixed core statuses from deletion.

The craft-ai-agents/craft-agents-oss repository implements a flexible dynamic status system that allows each workspace to define its own session statuses—such as "Todo", "In Progress", or "Done"—while maintaining system stability through immutable core statuses. This architecture decouples the data model from persistence logic and CRUD operations, enabling runtime modifications that instantly reflect in the UI and session management layers.

Architecture Overview

The dynamic status system is organized into three distinct layers, each handling specific responsibilities from type definitions to file system operations.

Data Model Layer

The foundational types are defined in packages/shared/src/statuses/types.ts. Each status follows the StatusConfig interface, which includes:

  • id: Unique identifier for the status
  • label: Display name shown in the UI
  • color: Visual indicator for the status
  • icon: Emoji, URL, or local filename (SVG)
  • category: Grouping classification
  • order: Position in the status list
  • isFixed: Boolean flag preventing deletion
  • isDefault: Boolean flag indicating the default status for new sessions

The workspace-wide configuration is defined as WorkspaceStatusConfig, which contains an array of StatusConfig objects and a defaultStatusId reference.

Persistence Layer

The packages/shared/src/statuses/storage.ts module handles loading and saving the JSON configuration to statuses/config.json within each workspace directory. Key functions include:

  • getDefaultStatusConfig: Loads the workspace-specific status configuration
  • ensureDefaultIconFiles: Auto-discovers or creates placeholder SVGs in statuses/icons/{id}.svg for built-in statuses

When a workspace opens, packages/shared/src/workspaces/storage.ts invokes the status storage layer to cache the configuration in memory for use by the UI and session manager.

CRUD Logic Layer

The packages/shared/src/statuses/crud.ts file implements business rule enforcement for all status modifications. This layer ensures that fixed statuses cannot be deleted, order values remain unique, and session migrations occur when statuses are removed.

Workspace Status Initialization

When a workspace initializes, the system follows this sequence:

  1. The workspace storage module calls getDefaultStatusConfig to locate statuses/config.json
  2. The configuration is validated against required fixed statuses
  3. Missing icon files are generated via ensureDefaultIconFiles
  4. The resulting WorkspaceStatusConfig is cached and distributed to the UI layer
// From packages/shared/src/workspaces/storage.ts
const statusConfig = await getDefaultStatusConfig(workspacePath);
// Cached for use by packages/ui/src/lib/layout.ts

Dynamic Status Operations

The CRUD layer in packages/shared/src/statuses/crud.ts provides type-safe operations for modifying workspace statuses at runtime.

Creating New Statuses

The createStatus function validates that the id is unique, automatically assigns the next sequential order value, and appends the new StatusConfig to the array before persisting to disk.

// packages/shared/src/statuses/crud.ts
const newStatus: StatusConfig = {
  id: 'review',
  label: 'In Review',
  color: '#F59E0B',
  category: 'active',
  order: 3,
  isFixed: false,
  isDefault: false
};

await createStatus(workspacePath, newStatus);

Updating Existing Statuses

The updateStatus function restricts modifications based on status flags. While mutable fields like label, color, icon, and category can be edited for any status, fixed statuses (isFixed: true) cannot have their category changed, and default statuses (isDefault: true) cannot be deleted.

// Updates allowed for custom statuses
await updateStatus(workspacePath, 'review', {
  color: '#10B981',
  icon: 'check-circle.svg'
});

Reordering Statuses

The reorderStatuses function accepts an ordered array of status IDs, validates that every ID exists in the configuration, and rewrites the order fields to match the new sequence.

// Reorder by providing complete ordered ID list
await reorderStatuses(workspacePath, ['todo', 'review', 'done', 'archived']);

Deleting Statuses and Session Migration

When deleteStatus removes a custom status, the system triggers a migration process. The function walks all sessions in packages/shared/src/sessions/storage.ts and replaces any references to the deleted status with the workspace's defaultStatusId, ensuring data integrity.

// Deletes status and migrates affected sessions
await deleteStatus(workspacePath, 'review'); // Cannot delete if isFixed: true

Icon Handling and Assets

The system supports three icon types: emoji characters, remote URLs, or local SVG filenames. If the icon field is omitted from the configuration, the loader automatically discovers files named statuses/icons/{id}.svg. The ensureDefaultIconFiles function creates placeholder SVGs for built-in statuses when they are missing from the workspace directory.

UI Integration and Rendering

The dynamic status system integrates deeply with the UI layer through two primary pathways.

The packages/ui/src/lib/layout.ts module consumes the cached WorkspaceStatusConfig to build the sidebar navigation, rendering each status with its associated color and icon.

Status Activities and Turn Phases

When processing system messages, packages/ui/src/components/chat/turn-utils.ts converts status-type activities into UI elements with type: 'status'. The helper deriveTurnPhase treats a status activity with status: 'running' as part of the "awaiting" phase, ensuring the turn card remains visible until the status completes.

// packages/ui/src/components/chat/turn-utils.ts
const activity = {
  type: 'status',
  status: 'running',
  label: 'Generating response...'
};
// This keeps the assistant turn card visible

Summary

  • Three-layer architecture: The system separates data models (types.ts), persistence (storage.ts), and business logic (crud.ts) to enable safe runtime modifications.
  • Immutable core: Fixed statuses (isFixed: true) and default statuses (isDefault: true) are protected from deletion and certain modifications.
  • Automatic migration: Deleting a status triggers automatic updates to all affected sessions via packages/shared/src/sessions/storage.ts.
  • Flexible icons: Supports emoji, URLs, or local SVG files with auto-discovery in statuses/icons/{id}.svg.
  • UI synchronization: Changes reflect immediately in the sidebar (layout.ts) and conversation turns (turn-utils.ts).

Frequently Asked Questions

What happens when I delete a status that is currently assigned to active sessions?

When you call deleteStatus on a custom status, the system automatically migrates all affected sessions by replacing the deleted status ID with the workspace's defaultStatusId. This operation is performed in packages/shared/src/statuses/crud.ts and ensures no sessions are left with invalid status references.

Can I modify the built-in "Todo" or "Done" statuses?

You can modify mutable fields like color, icon, and label on fixed statuses, but you cannot delete them or change their category if isFixed is set to true. The updateStatus function in packages/shared/src/statuses/crud.ts enforces these restrictions based on the isFixed and isDefault boolean flags.

How does the system handle missing icon files?

If an icon is not explicitly defined in the status configuration, the ensureDefaultIconFiles function in packages/shared/src/statuses/storage.ts attempts to auto-discover a file at statuses/icons/{id}.svg. If the file is missing for built-in statuses, the system generates placeholder SVGs automatically.

What is the difference between a fixed status and a default status?

A fixed status (isFixed: true) cannot be deleted and has restricted modification rules—its category cannot be changed. A default status (isDefault: true) serves as the fallback for new sessions and sessions affected by status deletion, but it can be modified otherwise. A status can be both fixed and default, or neither.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →