update_tiddler
Updates an existing tiddler in a TiddlyWiki wiki, showing a diff of changes and requesting approval before applying. Preserves metadata like created timestamp and supports custom fields.
Instructions
Update an existing tiddler. Shows a diff of changes and requests approval before applying. Preserves metadata like created timestamp. Supports arbitrary custom fields beyond the standard ones (e.g., caption, summary, author, or any TiddlyWiki field).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Title of the tiddler to update | |
| text | No | New text content (optional) | |
| tags | No | New tags as space-separated string (optional) | |
| type | No | Content type like "text/markdown" or "text/vnd.tiddlywiki" (optional) |
Implementation Reference
- src/tools/update-tiddler.ts:77-117 (handler)The main handler function for the update_tiddler tool. Parses input via UpdateTiddlerInput schema, fetches current tiddler, applies updates (text, tags, type, custom fields), generates a diff, and saves the tiddler.
export async function handleUpdateTiddler(args: unknown): Promise<ToolResult> { const input = UpdateTiddlerInput.parse(args); // Get current tiddler const current = await getTiddler(input.title); if (!current) { return { content: [ { type: 'text', text: JSON.stringify({ error: `Tiddler not found: ${input.title}` }, null, 2), }, ], isError: true, }; } // Build updated tiddler - include all custom fields from input const { title: _title, text, tags, type, ...customFields } = input; const updates: Partial<Tiddler> = { ...customFields }; if (text !== undefined) updates.text = text; if (tags !== undefined) updates.tags = tags; if (type !== undefined) updates.type = type; const updated = updateTiddlerObject(current, updates, getAuthUser()); // Generate diff const diff = generateTiddlerDiff(current, updated); // Apply the change await putTiddler(updated); return { content: [ { type: 'text', text: `## Updated: "${input.title}"\n\n${diff}`, }, ], }; } - src/tools/types.ts:72-81 (schema)Zod schema for the update_tiddler input. Defines title (required), text, tags, type as optional fields, with passthrough() to allow arbitrary custom fields.
export const UpdateTiddlerInput = z .object({ title: z.string().describe('Title of the tiddler to update'), text: z.string().optional().describe('New text content'), tags: z.string().optional().describe('New tags (space-separated)'), type: z.string().optional().describe('Content type (e.g., text/markdown)'), }) .passthrough(); // Allow additional custom fields export type UpdateTiddlerInputType = z.infer<typeof UpdateTiddlerInput>; - src/index.ts:154-248 (registration)Registration of the update_tiddler tool: name/description/inputSchema in the server definition (line 154) and routing in the switch statement (line 247-248).
name: 'update_tiddler', description: 'Update an existing tiddler. Shows a diff of changes and requests approval before applying. Preserves metadata like created timestamp. Supports arbitrary custom fields beyond the standard ones (e.g., caption, summary, author, or any TiddlyWiki field).', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Title of the tiddler to update', }, text: { type: 'string', description: 'New text content (optional)', }, tags: { type: 'string', description: 'New tags as space-separated string (optional)', }, type: { type: 'string', description: 'Content type like "text/markdown" or "text/vnd.tiddlywiki" (optional)', }, }, additionalProperties: { type: 'string', description: 'Any additional TiddlyWiki field (e.g., caption, summary, author)', }, required: ['title'], }, }, { name: 'create_tiddler', description: 'Create a new tiddler. Shows a preview and requests approval before creating. Supports arbitrary custom fields beyond the standard ones (e.g., caption, summary, author, or any TiddlyWiki field).', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Title of the new tiddler', }, text: { type: 'string', description: 'Text content', }, tags: { type: 'string', description: 'Tags as space-separated string (optional, e.g., "Journal" or "Journal OYS")', default: '', }, type: { type: 'string', description: 'Content type (default: text/markdown)', default: 'text/markdown', }, }, additionalProperties: { type: 'string', description: 'Any additional TiddlyWiki field (e.g., caption, summary, author)', }, required: ['title', 'text'], }, }, { name: 'delete_tiddler', description: 'Delete a tiddler. Shows current content and requests approval before deleting.', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Title of the tiddler to delete', }, }, required: ['title'], }, }, ], }; }); // Tool implementation handler server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'search_tiddlers': return await handleSearchTiddlers(args, getToolDependencies()); case 'update_tiddler': return await handleUpdateTiddler(args); - src/tiddlywiki-http.ts:361-380 (helper)Helper function that merges updates onto the current tiddler while preserving created/creator/title fields, setting modified/modifier timestamp, and stripping server-managed fields.
export function updateTiddlerObject( current: Tiddler, updates: Partial<Tiddler>, modifier: string ): Tiddler { return { ...current, ...updates, // Always preserve these fields from the current tiddler title: current.title, created: current.created, creator: current.creator, // Set modification metadata modified: generateTimestamp(), modifier, // Remove server-managed fields revision: undefined, bag: undefined, }; } - src/tools/update-tiddler.ts:18-71 (helper)Helper function that generates a human-readable diff between the old and new tiddler, including text diff (using createTwoFilesPatch) and metadata changes (tags, type).
function generateTiddlerDiff(oldTiddler: Tiddler, newTiddler: Tiddler): string { const lines: string[] = []; // Text diff const oldText = oldTiddler.text || ''; const newText = newTiddler.text || ''; if (oldText !== newText) { const patch = createTwoFilesPatch( oldTiddler.title, newTiddler.title, oldText, newText, 'Before', 'After', { context: 1 } // Reduce context to 1 line for more compact diffs ); // Add a concise summary const oldLines = oldText.split('\n').length; const newLines = newText.split('\n').length; const delta = newLines - oldLines; const summary = delta > 0 ? `+${delta} line${delta === 1 ? '' : 's'}` : delta < 0 ? `${delta} line${delta === -1 ? '' : 's'}` : 'modified'; lines.push(`**Content:** ${summary}`); lines.push('```diff'); lines.push(patch); lines.push('```'); } // Metadata changes const metadataChanges: string[] = []; if (oldTiddler.tags !== newTiddler.tags) { metadataChanges.push(` tags: "${oldTiddler.tags || ''}" → "${newTiddler.tags || ''}"`); } if (oldTiddler.type !== newTiddler.type) { metadataChanges.push(` type: "${oldTiddler.type}" → "${newTiddler.type}"`); } if (metadataChanges.length > 0) { lines.push(''); lines.push('**Metadata:**'); lines.push(...metadataChanges); } return lines.join('\n'); }