handoff_load
Load conversation context by key to transfer chat history between AI sessions. Retrieve full dialogue content for continuity across projects.
Instructions
Load a specific handoff by key. Returns full conversation content.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | The key of the handoff to load | |
| max_messages | No | Optional: limit number of messages to return |
Implementation Reference
- src/index.ts:387-450 (handler)Main MCP tool handler for handoff_load. Registers the tool with name 'handoff_load' and description 'Load a specific handoff by key. Returns full conversation content.' The handler accepts a 'key' parameter (required string) and 'max_messages' parameter (optional number), retrieves the handoff from storage using storage.load(), logs the tool call for auditing, and returns formatted output with title, metadata, summary, and conversation content along with structured content containing key, title, summary, conversation, from_ai, from_project, and created_at fields.// handoff_load server.tool( "handoff_load", "Load a specific handoff by key. Returns full conversation content.", { key: z.string().describe("The key of the handoff to load"), max_messages: z.number().optional().describe("Optional: limit number of messages to return"), }, async ({ key, max_messages }) => { const audit = getAuditLogger(); const timer = audit.startTimer(); const { storage } = await getStorage(); const result = await storage.load(key, max_messages); audit.logTool({ event: "tool_call", toolName: "handoff_load", durationMs: timer.elapsed(), success: result.success, error: result.error, }); if (!result.success || !result.data) { return { content: [ { type: "text", text: `❌ ${result.error}\n\nUse handoff_list to see available handoffs.`, }, ], }; } const handoff = result.data; return { content: [ { type: "text", text: `# Handoff: ${handoff.title} **From:** ${handoff.from_ai}${handoff.from_project ? ` (${handoff.from_project})` : ""} **Created:** ${handoff.created_at} ## Summary ${handoff.summary} ## Conversation ${handoff.conversation}`, }, ], structuredContent: { key: handoff.key, title: handoff.title, summary: handoff.summary, conversation: handoff.conversation, from_ai: handoff.from_ai, from_project: handoff.from_project, created_at: handoff.created_at, }, }; } );
- src/index.ts:391-394 (schema)Zod schema definition for handoff_load tool parameters. Defines 'key' as a required string with description 'The key of the handoff to load' and 'max_messages' as an optional number with description 'Optional: limit number of messages to return'.{ key: z.string().describe("The key of the handoff to load"), max_messages: z.number().optional().describe("Optional: limit number of messages to return"), },
- src/index.ts:387-450 (registration)Tool registration for handoff_load using server.tool() method. The registration includes the tool name, description, parameter schema, and the async handler function that executes the tool logic.// handoff_load server.tool( "handoff_load", "Load a specific handoff by key. Returns full conversation content.", { key: z.string().describe("The key of the handoff to load"), max_messages: z.number().optional().describe("Optional: limit number of messages to return"), }, async ({ key, max_messages }) => { const audit = getAuditLogger(); const timer = audit.startTimer(); const { storage } = await getStorage(); const result = await storage.load(key, max_messages); audit.logTool({ event: "tool_call", toolName: "handoff_load", durationMs: timer.elapsed(), success: result.success, error: result.error, }); if (!result.success || !result.data) { return { content: [ { type: "text", text: `❌ ${result.error}\n\nUse handoff_list to see available handoffs.`, }, ], }; } const handoff = result.data; return { content: [ { type: "text", text: `# Handoff: ${handoff.title} **From:** ${handoff.from_ai}${handoff.from_project ? ` (${handoff.from_project})` : ""} **Created:** ${handoff.created_at} ## Summary ${handoff.summary} ## Conversation ${handoff.conversation}`, }, ], structuredContent: { key: handoff.key, title: handoff.title, summary: handoff.summary, conversation: handoff.conversation, from_ai: handoff.from_ai, from_project: handoff.from_project, created_at: handoff.created_at, }, }; } );
- src/storage.ts:227-256 (helper)LocalStorage.load() method implementation that retrieves a handoff from the in-memory Map by key. Returns an error if the handoff is not found. If maxMessages parameter is provided and greater than 0, it splits the conversation into messages using splitConversationMessages() and returns only the last N messages with a truncation notice. Otherwise returns the full handoff data./** * Load a specific handoff by key. * @param key - Unique identifier of the handoff * @param maxMessages - Optional limit on number of messages to return * @returns Result with full handoff data or error if not found */ async load(key: string, maxMessages?: number): Promise<StorageResult<Handoff>> { const handoff = this.handoffs.get(key); if (!handoff) { return { success: false, error: `Handoff not found: "${key}"` }; } // Apply message truncation if requested if (maxMessages && maxMessages > 0) { const messages = splitConversationMessages(handoff.conversation); if (messages.length > maxMessages) { const truncatedConversation = messages.slice(-maxMessages).join(""); return { success: true, data: { ...handoff, conversation: `[... truncated to last ${maxMessages} messages ...]\n\n${truncatedConversation}`, }, }; } } return { success: true, data: handoff }; }
- src/validation.ts:305-336 (helper)splitConversationMessages() utility function that splits a conversation string into individual messages using a regex pattern that supports various AI formatting styles (## User/## Assistant, # User/# Assistant, **User:**/**Assistant:**, User:/Assistant:, and alternatives like Human/Claude/AI). Returns an array of message strings, or the whole conversation as a single message if no delimiters are found./** * Common conversation delimiter patterns for splitting messages. * Supports various formats that AIs might use: * - ## User / ## Assistant (Markdown H2) - recommended * - # User / # Assistant (Markdown H1) * - ### User / ### Assistant (Markdown H3) * - **User:** / **Assistant:** (Bold with colon) * - User: / Assistant: (Simple colon format) * Also supports alternative role names: Human, Claude, AI */ const MESSAGE_DELIMITER = /(?=(?:^|\n)(?:#{1,3}\s+|\*\*)?(?:User|Assistant|Human|Claude|AI)(?:\*\*)?(?::|(?=\s*\n)))/gi; /** * Split a conversation string into individual messages. * Handles various common formats used by different AIs. * @param conversation - The conversation text to split * @returns Array of message strings */ export function splitConversationMessages(conversation: string): string[] { // Reset regex state (global flag) MESSAGE_DELIMITER.lastIndex = 0; const messages = conversation.split(MESSAGE_DELIMITER).filter((msg) => msg.trim().length > 0); // If no delimiters found, return the whole conversation as one message if (messages.length === 0) { return [conversation]; } return messages; }