Skip to content

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 identifier
  • role -- system, user, or assistant
  • parts -- 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:

FieldDescriptionMax Items
currentPlanLightweight approved or candidate plan text summary. Not the source of truth when an execution run exists.1
activeConstraintsBinding constraints and candidate constraints6
keyDecisionsRecorded decisions with rationale and confidence8
tasksLightweight task summary entries for general workstream state, not executor-owned plan nodes10
openQuestionsUnresolved questions5
risksIdentified risks5
artifactsLightweight workstream artifact summaries, separate from execution-plan planArtifact records10
agentContributionsAgent notes and summaries6

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

StatusDescription
regularActive workstream
archivedHidden 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:

  1. A new chat message sets activeRunId on the workstream.
  2. The agent streams its response.
  3. On completion, activeRunId is cleared.
  4. 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.