project_update
Update any project by submitting only the fields to change. Use status 'archived' to soft-delete a project.
Instructions
Update a project. Pass only the fields you want to change. Set status to "archived" to soft-delete.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project ID | |
| name | No | ||
| description | No | ||
| status | No | ||
| tags | No |
Implementation Reference
- src/tools/projects.ts:114-128 (handler)The handler function for project_update tool. Fetches existing project by ID, builds an UPDATE SQL via buildUpdate helper (allowing only name/description/status/tags), executes it with RETURNING *, logs field-level changes, and returns the updated row.
function handleProjectUpdate(args: Record<string, unknown>) { const db = getDb(); const id = args.id as number; const oldRow = db.prepare('SELECT * FROM projects WHERE id = ?').get(id) as Record<string, unknown> | undefined; if (!oldRow) throw new Error(`Project ${id} not found`); const update = buildUpdate('projects', id, args, ['name', 'description', 'status', 'tags']); if (!update) throw new Error('No fields to update'); const newRow = db.prepare(update.sql).get(...update.params) as Record<string, unknown>; logEntityUpdate(db, 'project', id, newRow.name as string, oldRow, newRow, ['name', 'status']); return newRow; } - src/tools/projects.ts:48-64 (schema)The tool definition / input schema for project_update. Requires 'id' (integer) and accepts optional 'name', 'description', 'status' (enum), and 'tags' (string array). Annotated as non-destructive and idempotent.
{ name: 'project_update', description: 'Update a project. Pass only the fields you want to change. Set status to "archived" to soft-delete.', annotations: { title: 'Update Project', readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }, inputSchema: { type: 'object', properties: { id: { type: 'integer', description: 'Project ID' }, name: { type: 'string' }, description: { type: 'string' }, status: { type: 'string', enum: ['active', 'on_hold', 'completed', 'archived'] }, tags: { type: 'array', items: { type: 'string' } }, }, required: ['id'], }, }, - src/tools/projects.ts:130-134 (registration)Registration of the project_update handler (handleProjectUpdate) in the handlers map exported from projects.ts. This map is consumed in src/index.ts where ALL_HANDLERS spreads it and dispatches incoming tool calls.
export const handlers: Record<string, ToolHandler> = { project_create: handleProjectCreate, project_list: handleProjectList, project_update: handleProjectUpdate, }; - src/helpers/sql-builder.ts:3-28 (helper)The buildUpdate helper used by handleProjectUpdate. Dynamically constructs an UPDATE SQL with RETURNING * for only the allowedColumns that are present in the fields. For JSON columns (including 'tags'), the value is JSON-stringified. Also sets updated_at to current datetime. Returns null if no fields to update.
export function buildUpdate( table: string, id: number, fields: Record<string, unknown>, allowedColumns: string[] ): { sql: string; params: unknown[] } | null { const updates: string[] = []; const params: unknown[] = []; for (const col of allowedColumns) { if (fields[col] !== undefined) { updates.push(`${col} = ?`); params.push(JSON_COLUMNS.has(col) ? JSON.stringify(fields[col]) : fields[col]); } } if (updates.length === 0) return null; updates.push("updated_at = datetime('now')"); params.push(id); return { sql: `UPDATE ${table} SET ${updates.join(', ')} WHERE id = ? RETURNING *`, params, }; } - src/helpers/activity-logger.ts:19-39 (helper)The logEntityUpdate helper called by handleProjectUpdate to log field-level changes. Tracks 'name' and 'status' fields, creating activity_log entries with action 'status_changed' for status changes or 'updated' for other field changes.
export function logEntityUpdate( db: Database.Database, entityType: string, entityId: number, entityName: string, oldRow: Record<string, unknown>, newRow: Record<string, unknown>, trackedFields: string[] ): void { for (const field of trackedFields) { const oldVal = String(oldRow[field] ?? ''); const newVal = String(newRow[field] ?? ''); if (oldVal !== newVal) { const action = field === 'status' ? 'status_changed' : 'updated'; logActivity( db, entityType, entityId, action, field, oldVal, newVal, `${entityType} '${entityName}' ${field}: ${oldVal} -> ${newVal}` ); } } }