Appearance
Workstreams
Workstreams are persistent conversation threads that hold message history, state tracking, and memory blocks. They are the primary unit of interaction between users and agents.
Concepts
A workstream represents a long-running conversation. Each workstream belongs to a user within an organization and persists its full message history in SurrealDB.
Key properties of a workstream:
- Persistent -- messages are stored and survive server restarts.
- Stateful -- each workstream tracks decisions, tasks, risks, questions, and artifacts.
- Scoped -- a workstream belongs to one user and one organization.
- Streamable -- agent responses stream in real time via AI SDK UI message streams.
Modes
Direct Mode
A 1:1 conversation between the user and a specific agent. Direct workstreams have a deterministic ID based on the user, organization, and agent:
workstream:direct_{agentId}_user_{userId}_organization_{orgId}Direct workstreams cannot be renamed, archived, or deleted. Which direct workstreams are provisioned during bootstrap is host-defined through workstreams.bootstrap.onboardingDirectAgents and workstreams.bootstrap.completedDirectAgents.
Group Mode
A conversation led by a designated agent (typically chief) that can consult other specialists. Group workstreams are created on demand and support renaming, archiving, and deletion.
Core Workstreams
Core workstreams are a special category of group workstreams with core=true and a required coreType. They are provisioned automatically after onboarding when the host config includes them, and they have fixed titles and agent assignments defined by getCoreWorkstreamProfile(). Core workstreams cannot be renamed, archived, or deleted.
Which core workstreams exist is host-defined through workstreams.bootstrap.coreTypesAfterOnboarding.
Creating Workstreams
ts
// Direct workstream (1:1 with agent)
const ws = await workstreamService.createWorkstream(userId, orgId, {
mode: 'direct',
agentId: 'chief',
})
// Standard group workstream
const ws = await workstreamService.createWorkstream(userId, orgId, {
mode: 'group',
title: 'Product Launch Plan',
})
// Core workstream
const ws = await workstreamService.createWorkstream(userId, orgId, {
mode: 'group',
core: true,
coreType: 'daily-activities',
})Listing Workstreams
The listWorkstreams method requires a mode parameter and supports pagination for standard group workstreams:
ts
// All direct workstreams (no pagination)
const { workstreams } = await workstreamService.listWorkstreams(userId, orgId, {
mode: 'direct',
includeArchived: false,
})
// Paginated group workstreams
const { workstreams, hasMore } = await workstreamService.listWorkstreams(userId, orgId, {
mode: 'group',
core: false,
take: 15,
page: 1,
includeArchived: false,
})
// Core workstreams (no pagination)
const { workstreams } = await workstreamService.listWorkstreams(userId, orgId, {
mode: 'group',
core: true,
includeArchived: false,
})Message History
Messages are stored as AI SDK UIMessage objects with typed tool parts. History is cursor-paginated for efficient loading:
ts
// Load latest page (6 messages by default)
const page = await workstreamMessageService.listMessageHistoryPage({
workstreamId,
take: 6,
})
// Load older messages before a cursor
const olderPage = await workstreamMessageService.listMessageHistoryPage({
workstreamId,
take: 6,
beforeMessageId: page.prevCursor,
})Each message has:
id-- unique message identifierrole--system,user, orassistantparts-- array of typed parts (text, reasoning, tool invocations, data)metadata-- agent ID, token counts, cost, reasoning profile, timestamps
State Tracking
Each workstream can maintain a structured WorkstreamState:
| Field | Description | Max Items |
|---|---|---|
currentPlan | Lightweight approved or candidate plan text summary. Not the source of truth when an execution run exists. | 1 |
activeConstraints | Binding constraints and candidate constraints | 6 |
keyDecisions | Recorded decisions with rationale and confidence | 8 |
tasks | Lightweight task summary entries for general workstream state, not executor-owned plan nodes | 10 |
openQuestions | Unresolved questions | 5 |
risks | Identified risks | 5 |
artifacts | Lightweight workstream artifact summaries, separate from execution-plan planArtifact records | 10 |
agentContributions | Agent notes and summaries | 6 |
WorkstreamState is a durable structured record that the SDK injects back into prompt context as <workstream-state>. The SDK's built-in transcript compaction can merge WorkstreamStateDelta updates into this state, and hosts may update it through their own turn processing if they need additional state tracking.
Memory Block
Each workstream has a per-workstream memory block for short-term notes accumulated during conversation. Entries are role-labeled and timestamped:
chief: User prefers weekly status updates via email.
cto: Tech stack confirmed as Next.js + Hono + SurrealDB.When the memory block reaches 15 entries, the oldest 10 are compacted into a summary. The summary and remaining entries are both injected into the agent context.
Status and Lifecycle
| Status | Description |
|---|---|
regular | Active workstream |
archived | Hidden from primary list |
Workstreams can be archived and unarchived. Deletion requires archiving first. Direct and core workstreams are immutable in status.
Run Management
Each workstream tracks at most one active agent run via activeRunId. The run lifecycle:
- A new chat message sets
activeRunIdon the workstream. - The agent streams its response.
- On completion,
activeRunIdis cleared. - Users can call
stopActiveRun()to abort an in-flight run.
The isRunning and isCompacting flags expose busy state to the client without leaking internal run IDs.