Skip to main content

Elements

The Element type is the foundation for all types in Stoneforge. It provides a unified identity system, timestamp tracking, tagging, and metadata capabilities.

Base Element Type

All types in Stoneforge (Task, Message, Document, Entity, etc.) extend the base Element interface:
interface Element {
  readonly id: ElementId;
  readonly type: ElementType;
  readonly createdAt: Timestamp;
  updatedAt: Timestamp;
  readonly createdBy: EntityId;
  tags: string[];
  metadata: Record<string, unknown>;
  deletedAt?: Timestamp;
}
id
ElementId
required
Hash-based identifier, supports hierarchical format (el-{hash} or el-{hash}.{n})
type
ElementType
required
Discriminator for element subtype (task, message, document, entity, etc.)
createdAt
Timestamp
required
ISO 8601 datetime when element was created
updatedAt
Timestamp
required
ISO 8601 datetime of last modification
createdBy
EntityId
required
Reference to the entity that created this element
tags
string[]
required
User-defined tags for categorization (max 50 tags, 100 chars each)
metadata
Record<string, unknown>
required
Arbitrary key-value data (max 64KB serialized, keys starting with _el_ reserved)
deletedAt
Timestamp
ISO 8601 datetime when element was soft-deleted (undefined if active)

Element Types

All valid element types in the system:
const ElementType = {
  TASK: 'task',
  MESSAGE: 'message',
  DOCUMENT: 'document',
  ENTITY: 'entity',
  PLAN: 'plan',
  WORKFLOW: 'workflow',
  PLAYBOOK: 'playbook',
  CHANNEL: 'channel',
  LIBRARY: 'library',
  TEAM: 'team',
} as const;
  • task - Work tracking primitive
  • message - Immutable communication records
  • document - Content storage and versioning
  • entity - Identity for agents, humans, and systems

Branded Types

Stoneforge uses TypeScript branded types for type safety:
// Branded type for Element IDs
declare const ElementIdBrand: unique symbol;
export type ElementId = string & { 
  readonly [ElementIdBrand]: typeof ElementIdBrand 
};

// Branded type for Entity IDs
declare const EntityIdBrand: unique symbol;
export type EntityId = string & { 
  readonly [EntityIdBrand]: typeof EntityIdBrand 
};

// Timestamp type - ISO 8601 formatted string
export type Timestamp = string;

Branded Type Casts

Use these utilities at trust boundaries only:
// Cast string to EntityId
asEntityId(id: string): EntityId

// Cast string to ElementId
asElementId(id: string): ElementId
Only use cast functions at trust boundaries (API inputs, database reads). Within the application, rely on type-safe functions.

Validation

Tag Validation

MAX_TAGS
number
default:"50"
Maximum number of tags per element
MAX_TAG_LENGTH
number
default:"100"
Maximum characters per tag
Tag rules:
  • Only alphanumeric, hyphen, underscore, colon allowed
  • No leading or trailing whitespace
  • No duplicates
// Validate a single tag
validateTag(tag: unknown): string

// Validate tags array
validateTags(tags: unknown): string[]

// Type guard
isValidTag(tag: unknown): tag is string

Metadata Validation

MAX_METADATA_SIZE
number
default:"65536"
Maximum metadata size in bytes (64KB)
RESERVED_METADATA_PREFIX
string
default:"_el_"
Reserved key prefix for system use
Metadata rules:
  • Must be JSON-serializable
  • Max 64KB when serialized
  • Keys starting with _el_ are reserved
// Validate metadata object
validateMetadata(metadata: unknown): Record<string, unknown>

// Type guard
isValidMetadata(metadata: unknown): metadata is Record<string, unknown>

Timestamp Validation

// Validate ISO 8601 timestamp
validateTimestamp(value: unknown, field: string): Timestamp

// Type guard
isValidTimestamp(value: unknown): value is Timestamp

// Create new timestamp
createTimestamp(): Timestamp

// Parse timestamp to Date
parseTimestamp(timestamp: Timestamp): Date
Timestamp format: YYYY-MM-DDTHH:mm:ss.sssZ

Type Guards

// Check if value is valid Element
isElement(value: unknown): value is Element

// Check if value is valid ElementType
isValidElementType(value: unknown): value is ElementType

// Comprehensive validation with detailed errors
validateElement(value: unknown): Element
validateElementType(value: unknown): ElementType

Utility Functions

Tag Utilities

// Normalize tags (dedupe and sort)
normalizeTags(tags: string[]): string[]

// Add tag to element (validates and dedupes)
addTag(element: Element, tag: string): string[]

// Remove tag from element
removeTag(element: Element, tag: string): string[]

Equality Checking

// Deep equality check for elements
elementsEqual(a: Element, b: Element): boolean
Compares all fields including tags (order-insensitive) and metadata.

Factory Types

interface CreateElementInput {
  type: ElementType;
  createdBy: EntityId;
  tags?: string[];
  metadata?: Record<string, unknown>;
}
Type-specific subtypes extend this base input (e.g., CreateTaskInput, CreateEntityInput).

Best Practices

Use Branded Types

Always use ElementId and EntityId instead of plain strings for type safety

Validate at Boundaries

Use validation functions at API boundaries and trust boundaries

Immutable Where Possible

Treat id, type, createdAt, and createdBy as immutable

Leverage Type Guards

Use type guards for runtime type checking before operations

Build docs developers (and LLMs) love