Sessions
A session is a scratch-pad drafting canvas where the operator selects upstream items, attaches generation variants (each with its own preset, prompt, style and — optionally — its own LLM credential), and iterates through rounds until they have something worth exporting.
Sessions are independent of pipelines: any combination of items from any source can land in the same canvas. The session model is what the workbench's /sessions/[id] page renders.
Mental model
Each canvas is scoped to a single (organization, user) pair. Items, variants, rounds and exports all cascade-delete when the canvas is removed.
Entities
session_canvas
Top-level. Tracks lastActiveAt for ordering, name (nullable) and timestamps. Indexed by (organizationId, lastActiveAt desc) and (userId).
session_item
An immutable snapshot of an upstream item at the moment of selection. Stores:
sourceKind—social/webpage/rss/customexternalItemId— nullable, for resolving back to upstreamtitle,snippet,capturedAtmetrics(jsonb engagement data) andraw(jsonb original payload)
Critically, changes upstream don't propagate — the canvas keeps the title and metrics it captured at selection time. If you need fresh data, remove the item and add it again.
session_variant
A generation slot. Holds:
presetId— built-in slug (social-thread,blog-with-images,long-form,newsletter-section,tldr-brief,custom) oruser-saveduserPresetId— uuid pointing touser_presetwhenpresetId=user-savedprompt,style,typeTagstatus—idle/queued/streaming/done/errorerrorMessage— populated onstatus=erroractiveRoundIndex— 0-based;-1means no rounds yetllmCredentialId— nullable; overrides the workspace default LLM
variant_round
Append-only generation history per variant. Each row captures:
output(generated prose)promptSnapshotandstyleSnapshot(what the variant looked like when this round was generated)llmProvider,llmModel(the LLM actually used)generatedAt
Selecting an older round via session_select_round doesn't delete newer ones; it just moves activeRoundIndex.
user_preset
A user-saved (prompt, style, typeTag) tuple. Scoped per (org, user). Built-in presets are not stored as rows — they live as stable slugs in the codebase. UNIQUE(organizationId, userId, name) prevents duplicates.
session_export
A recorded export event: (sessionId, variantId, roundId?, format). Format today is markdown only. The row backs the EXPORTS 7D KPI on /console.
session_activity
Append-only log of session-affecting events:
client—ui/claude-code/cursor/claude-desktop/cline/other-mcptool— dotted name (e.g.session.add_variant,ui:expand)detail— human-readable context
Drives the /console NowFeed. Useful for "what was this session doing?" reads — both for humans and agents.
Lifecycle
- Create —
session_create({ name? })returns a canvas. No items, no variants. Optionalname(can also be set later). - Select items —
session_add_itemsnapshots an upstream social post / webpage / RSS entry. Pass anupstreamItemIdto fetch from the workbench source registry, or pass the snapshot fields directly (title,snippet,capturedAt,metrics,raw). - Attach variants —
session_add_variant({ sessionId, presetId, prompt, style, typeTag, llmCredentialId? }). Variants startstatus=idle. - Generate —
session_generate_variant({ variantId, sessionId })queues an LLM call. Each call appends avariant_round.session_generate_all({ sessionId })fans out to every variant in the canvas. - Compare rounds —
session_select_round({ variantId, roundIndex })switches the visible round; the others stay in history.session_variant_rounds({ variantId })lists the full history. - Export —
session_export_variant({ sessionId, variantId, roundId?, format })writes asession_exportrow. The actual markdown render is done by the caller (UI uses the export route; agents log via MCP). - Save preset (optional) —
session_save_preset({ name, description, prompt, style, typeTag })persists a variant config as a reusable user preset. - Delete —
session_delete({ sessionId })cascade-deletes items, variants, rounds and exports. Irreversible.
API surface
MCP
18 tools live under apps/web/lib/mcp/tools/sessions.ts. See the MCP tools reference for the full signatures.
| Group | Tools |
|---|---|
| Lifecycle | session_create, session_list, session_get, session_update, session_delete |
| Selection | session_add_item, session_remove_item, session_clear_selection |
| Variants | session_add_variant, session_update_variant, session_remove_variant, session_select_round, session_generate_variant, session_generate_all, session_variant_rounds |
| Exports + presets | session_export_variant, session_save_preset |
| Sources | session_list_sources |
Web (workbench + facade)
| Method | Path | Used for |
|---|---|---|
GET | /api/sessions/activity | Latest activity entries across the org's sessions. Backs /console NowFeed. Param ?limit (1–100, default 20). |
POST | /api/sessions/:sessionId/items | Server-side bridge that mirrors session_add_item for in-app calls that prefer REST. |
POST | /api/sessions/:sessionId/variants/:variantId/regenerate | Triggers variant regeneration (an LLM call producing a new round). |
POST | /api/sessions/sources/:id/refresh | Refresh an upstream source asynchronously (kicks off an ingest run). |
The rest of the session CRUD happens via the MCP transport (/api/mcp) or directly in the UI through server actions in apps/web/lib/session/.
What sessions are NOT
- Not a pipeline — sessions don't ingest on a schedule. Adding an item is a one-shot capture.
- Not a persistent destination — exports are events, not stored output. The workbench doesn't keep markdown files around (yet); the caller is responsible for taking the round text and doing something with it.
- Not a refinement chain — sessions sit alongside the refinement model (which still lives on artifacts). A round is not an artifact.
- Not shared — every canvas is
(org, user)-scoped; teammates don't see each other's canvases. Cross-user surfaces (dashboards, pipelines) are separate.
See also
- Concepts — high-level model that situates sessions next to pipelines.
- MCP tools · sessions — full tool signatures.
- Glossary — terms in one table.