Claude API: Threads — Function Reference
Source files: storage.js (1262 LOC), merge.js (902 LOC), branch.js (566 LOC), manager.js (537 LOC), index.js
Exported Functions — storage.js
createThread(options): Promise<ThreadObject>
Purpose: Create a new conversation thread with optional fork metadata. Parameters:
title(string): Thread title (default: “New Thread”)model(string): Claude model ID (default: “claude-3-5-sonnet-20241022”)metadata(object): Arbitrary key/value metadata-
parentThreadId(stringnull): Parent thread if forking -
forkPointMessageId(stringnull): Message ID where fork was created
Returns: ThreadObject — { thread_id, title, model, created_at, updated_at, metadata, archived, parent_thread_id, fork_point_message_id }
Notes for rewrite: Records fork relationship in thread_relationships table automatically.
getThread(threadId): Promise<ThreadObject|null>
Purpose: Retrieve thread by ID, including parent fork relationship. Parameters:
threadId(string): Thread UUID
Returns: ThreadObject or null if not found.
listThreads(options): Promise<ThreadObject[]>
Purpose: List threads with optional filtering by archived state, search, parent fork. Parameters:
archived(boolean): Include archived threads (default: false)-
search(stringnull): Search by title or ID limit(number): Max results (default: 100)offset(number): Pagination offset (default: 0)-
parentThreadId(stringnull): Only list forks of this thread
Returns: ThreadObject[]
updateThread(threadId, updates): Promise<ThreadObject|null>
Purpose: Partial update of thread title, model, metadata, or archived status. Parameters:
threadId(string)updates(object): Any of{ title, model, metadata, archived }
Returns: Updated ThreadObject or null if not found.
deleteThread(threadId): Promise<boolean>
Purpose: Delete thread and all messages/branches. Cascades via transaction.
Returns: true if deleted.
archiveThread(threadId, archived): Promise<ThreadObject>
Purpose: Archive or restore a thread. Parameters:
threadId(string)archived(boolean): true = archive, false = restore (default: true)
addMessage(threadId, options): Promise<MessageObject>
Purpose: Insert a message into a thread (optionally on a specific branch). Parameters:
threadId(string)-
role(string): “user”“assistant” “system” content(string): Message text-
tokens(numbernull): Token count metadata(object): Extra metadata-
branchId(stringnull): Branch to attach to -
parentMessageId(stringnull): Parent message for tree structure
Returns: MessageObject — { message_id, thread_id, role, content, tokens, timestamp, metadata, branch_id, parent_message_id }
getMessages(threadId, options): Promise<MessageObject[]>
Purpose: Retrieve messages with branch filtering and pagination. Parameters:
limit(number): Max messages (default: 100)offset(number): Skip N messages-
afterMessageId(stringnull): Only messages after this ID -
branchId(stringnull): Filter to specific branch includeAllBranches(boolean): Include messages from all branches
Returns: MessageObject[] ordered by timestamp ASC.
getMessage(messageId): Promise<MessageObject|null>
Purpose: Retrieve single message by ID.
updateMessage(messageId, updates): Promise<MessageObject|null>
Purpose: Update message content or metadata.
deleteMessage(messageId): Promise<boolean>
getMessageCount(threadId, branchId): Promise<number>
Purpose: Count messages in a thread, optionally scoped to a branch.
createBranch(threadId, options): Promise<BranchObject>
Purpose: Create a named branch within a thread. Parameters:
name(string): Branch name (e.g., “main”, “experiment-1”)-
parentMessageId(stringnull): Message this branch forks from -
createdFromBranchId(stringnull): Parent branch ID
Returns: BranchObject — { branch_id, thread_id, name, parent_message_id, created_from_branch_id, created_at }
getBranch(branchId): Promise<BranchObject|null>
listBranches(threadId): Promise<BranchObject[]>
getDefaultBranch(threadId): Promise<BranchObject>
Purpose: Get or auto-create the “main” branch for a thread.
updateBranch(branchId, updates): Promise<BranchObject|null>
Purpose: Rename a branch.
deleteBranch(branchId): Promise<boolean>
Purpose: Delete branch and move its messages to main branch.
forkThread(sourceThreadId, forkPointMessageId, options): Promise<ThreadObject>
Purpose: Create a new thread forked at a specific message, optionally copying message history. Parameters:
sourceThreadId(string)forkPointMessageId(string): Message to fork from-
newTitle(stringnull): Title for new thread copyAllBranches(boolean): Whether to copy all branches (default: false)
Exported Functions — merge.js
mergeThreads(targetId, sourceId, options): Promise<MergeResult>
Purpose: Merge source thread into target using specified strategy. Dispatches to strategy-specific implementations. Parameters:
targetId(string): Thread to merge intosourceId(string): Thread to merge from-
strategy(MergeStrategies): appendprepend interleave smart union diff (default: append) -
conflictResolution(ConflictResolution): source_winstarget_wins both newest oldest manual includeTimestamps(boolean): Preserve original timestamps-
prefix(stringnull): Prepend to each merged message content -
suffix(stringnull): Append to each merged message content metadata(object): Extra merge metadata
Returns: { target_id, source_id, strategy, messages_merged, merged_messages }
Notes for rewrite: Each strategy runs in a DB transaction with rollback on failure.
previewMerge(targetId, sourceId, options): Promise<PreviewResult>
Purpose: Dry-run merge to show what would happen without making changes.
Returns: { target_id, source_id, strategy, target_message_count, source_message_count, expected_result }
undoMerge(targetId): Promise<UndoResult>
Purpose: Undo the last merge on a target thread by deleting messages tagged with merged_from metadata.
Returns: { undone: boolean, merge_id?, source_thread_id? }
getMergeConflicts(targetId, sourceId): Promise<ConflictResult>
Purpose: Detect duplicate/conflicting messages between two threads without merging.
Returns: { target_id, source_id, conflicts: [{target_message, source_message, content_preview}], conflict_count }
batchMerge(targetId, sourceIds, options): Promise<BatchMergeResult>
Purpose: Merge multiple source threads into a target sequentially. Parameters:
targetId(string)sourceIds(string[]): Array of source thread IDs
Returns: { target_id, sources_processed, successful, failed, results }
Constants: MergeStrategies
| Value | Description | |——-|————-| | APPEND | Add source messages after target | | PREPEND | Insert source messages before target | | INTERLEAVE | Merge by timestamp | | SMART | Merge with duplicate detection | | UNION | Add only unique messages from source | | DIFF | Add only messages not already in target |
Constants: ConflictResolution
| Value | Description | |——-|————-| | SOURCE_WINS | Add source message even if duplicate | | TARGET_WINS | Skip source message if duplicate | | BOTH | Add both copies | | NEWEST | Keep newer message | | OLDEST | Keep older message | | MANUAL | Flag for manual resolution |
Exported Classes — branch.js
class Branch
Represents a conversation branch with methods:
getMessages(options): Fetch branch messages via storageaddMessage(messageData): Add message to this branchgetMessageCount(): Count messages in branchrename(newName): Rename branchdelete(): Delete branch
class BranchManager(threadId)
High-level branching manager for a thread:
createBranch(name, options): Create named branch (options:fromMessageId,fromBranchId)createBranchFromMessage(name, messageId, options): Fork at specific message, optionally copying historylistBranches(): All branches as Branch objectsgetBranch(branchId): Branch by IDgetMainBranch(): Default/main branchgetBranchByName(name): Branch by nameswitchBranch(branchId): Returns{ branch, messages }mergeBranch(sourceBranchId, targetBranchId, options): Merge two branches (strategies: append, prepend)compareBranches(branchAId, branchBId): Compare two branchesgetBranchLineage(branchId): Parent chain arraygetBranchTree():{ root, branches: {[id]: {..., children: []} } }archiveBranch(branchId): Move messages to main, mark archivedgetVisualizationData():{ nodes, edges, tree }for graph renderingcloneBranch(sourceBranchId, newName): Full clone with message ID remappingsquashBranch(branchId, options): Combine all messages into one (options:newRole,summary)
createBranchManager(threadId): BranchManager
Purpose: Factory function returning a BranchManager instance.
Exported Classes — manager.js
class ThreadManager
Singleton manager with in-memory cache (TTL 5min) and event emission:
Thread CRUD:
createThread(options): Create + auto-create main branch + cache + emit eventgetThread(threadId): Cached fetchlistThreads(filters): Cached listupdateThread(threadId, updates): Update + cache invalidation + emitdeleteThread(threadId): Delete + cache invalidation + emitarchiveThread(threadId): Archive + emitrestoreThread(threadId): Restore + emit
Message CRUD:
addMessage(threadId, messageData): Auto-selects main branch if none, cache invalidationgetMessages(threadId, options): Cached fetchupdateMessage(messageId, updates): Update + cache invalidationdeleteMessage(messageId): Delete + cache invalidation
Branch ops:
createBranch(threadId, options): Create + cache invalidation + emitlistBranches(threadId): Cached listgetBranch(branchId): Direct storageswitchToBranch(threadId, branchId): Returns{ branch, messages }updateBranch(branchId, updates)deleteBranch(branchId)
Fork/Merge:
forkThread(sourceThreadId, forkPointMessageId, options): Fork + emitgetForkTree(threadId): Cached treemergeThreads(targetId, sourceId, options): Merge + cache invalidation + emitgetMergeHistory(threadId)
Compare/Search:
compareBranches(threadId, branchAId, branchBId)compareThreads(threadAId, threadBId): Returns similarity score + message countssearchThreads(query, options)
Export/Import:
exportThread(threadId, format): Supported format: “json”importThread(data, options)
Stats:
getThreadStats(threadId): Cached per-thread statsgetGlobalStats(): Cached global stats
Events:
on(event, handler): Subscribe to events (threadCreated, threadUpdated, threadDeleted, messageAdded, branchCreated, threadForked, threadMerged)off(event, handler): UnsubscribeclearCache(): Wipe cache
getThreadManager(): ThreadManager
Purpose: Returns singleton instance (lazy-creates on first call).
resetThreadManager(): void
Purpose: Clears cache and destroys singleton instance.
Convenience exports (manager.js)
Direct exports that call singleton methods:
createThread, getThread, listThreads, updateThread, deleteThread, archiveThread, restoreThread, addMessage, getMessages, forkThread, mergeThreads, searchThreads, exportThread, importThread, getThreadStats
Key Data Structures
| Structure | Fields | Purpose |
|---|---|---|
| ThreadObject | thread_id, title, model, created_at, updated_at, metadata, archived, parent_thread_id, fork_point_message_id | Thread entity |
| MessageObject | message_id, thread_id, role, content, tokens, timestamp, metadata, branch_id, parent_message_id | Message entity |
| BranchObject | branch_id, thread_id, name, parent_message_id, created_from_branch_id, created_at | Branch entity |
| MergeResult | target_id, source_id, strategy, messages_merged, messages_skipped?, conflicts?, merged_messages | Merge output |
DB Tables Used
threadsthread_messagesthread_branchesthread_relationships(stores fork + merge relationships)
External Dependencies
../../db/index.js—getDb(),beginTransaction(),commitTransaction(),rollbackTransaction()- No Anthropic SDK calls — this is pure local storage
Notes for Rewrite
- The “smart” strategy uses only first 100 chars for duplicate detection — not hash-based.
prependhas a minor bug: timestamp constructionnew Date(now + sequence++)is string concatenation not addition.- Cache TTL is hardcoded at 5 minutes in ThreadManager.
squashBranchwith no summary produces a naive[role]: contentconcatenation.mergeBranchon BranchManager only supports append/prepend, not the full MergeStrategies enum.