Endpoint
This endpoint requires authentication and validates write permissions for the skill’s vault.
UUID of the skill to update
New slug identifier (must be unique within the vault)
New display name (minimum 1 character)
New description (minimum 1 character)
New markdown content. When provided, triggers mention validation and link sync.
New frontmatter object (completely replaces existing)
New metadata object (completely replaces existing)
Update source URL or set to null to clear
Update source identifier or set to null to clear
Array of resource operations: create, update, or delete Show Resource Update Input
UUID of existing resource to update. Omit for new resources.
File path within the skill namespace
One of: "reference", "script", "asset", "other"
File content (can include mention syntax)
Resource-specific metadata
Set to true to delete this resource. Requires id field.
Output Schema
Returns the complete updated skill object (same format as skills.getById). See the Get Skill documentation for the full response schema.
Behavior
Partial Updates
Only fields provided in the input are updated:
Omitted fields → no change
Provided fields → update to new value
null values for sourceUrl/sourceIdentifier → clear the field
Resource Management
When resources array is provided:
Delete : Resources with delete: true and an id are removed
Update : Resources with an id (not marked for deletion) are updated
Create : Resources without an id are created as new
If resources is omitted, existing resources remain unchanged.
Mention Validation
Before updating:
Validates all mention syntax in updated skillMarkdown and resource content
Mentions must reference existing, accessible skills/resources
Invalid mentions throw BAD_REQUEST
Link Synchronization
After successful update:
Deletes old links for updated sources (skill or resources)
Parses mention syntax from new content
Creates new skillLink records
Maintains bidirectional graph relationships
Link sync is incremental : only sources with updated content are re-synced.
TypeScript Examples
import { createTRPCClient , httpBatchLink } from '@trpc/client' ;
import type { AppRouter } from '@better-skills/api' ;
const client = createTRPCClient < AppRouter >({
links: [
httpBatchLink ({
url: 'http://localhost:3000/trpc' ,
headers: {
authorization: `Bearer ${ token } ` ,
},
}),
],
});
// Update just the description and metadata
const updated = await client . skills . update . mutate ({
id: skillId ,
description: 'Updated description with new information' ,
metadata: {
lastReviewed: new Date (). toISOString (),
reviewedBy: userId ,
},
});
console . log ( 'Updated:' , updated . name );
Update Content and Trigger Link Sync
// Update markdown content (triggers mention validation and link sync)
const updated = await client . skills . update . mutate ({
id: skillId ,
skillMarkdown: `
# Docker Best Practices
See also:
- @[Docker Compose]( ${ composeSkillId } )
- @[Kubernetes Deployment]( ${ k8sSkillId } )
## New Section
Additional content...
` . trim (),
});
console . log ( 'Links synchronized for new mentions' );
Add New Resources
// Fetch existing skill to preserve current resources
const skill = await client . skills . getById . query ({ id: skillId });
// Add a new resource while keeping existing ones
const updated = await client . skills . update . mutate ({
id: skillId ,
resources: [
// Keep existing resources by including their data
... skill . resources . map ( r => ({
id: r . id ,
path: r . path ,
kind: r . kind ,
content: r . content ,
metadata: r . metadata ,
})),
// Add new resource
{
path: 'scripts/deploy.sh' ,
kind: 'script' ,
content: '#!/bin/bash \n\n echo "Deploying..." \n ' ,
metadata: { executable: true },
},
],
});
console . log ( `Now has ${ updated . resources . length } resources` );
Update and Delete Resources
const skill = await client . skills . getById . query ({ id: skillId });
const updated = await client . skills . update . mutate ({
id: skillId ,
resources: [
// Update existing resource
{
id: existingResourceId ,
path: 'scripts/setup.sh' ,
kind: 'script' ,
content: '#!/bin/bash \n\n # Updated content \n echo "Setup v2" \n ' ,
metadata: { version: '2.0' },
},
// Delete a resource
{
id: resourceToDeleteId ,
path: 'old-file.txt' , // path required but ignored for deletes
kind: 'other' ,
content: '' , // content required but ignored for deletes
delete: true ,
},
// Keep other resources unchanged
... skill . resources
. filter ( r => r . id !== existingResourceId && r . id !== resourceToDeleteId )
. map ( r => ({
id: r . id ,
path: r . path ,
kind: r . kind ,
content: r . content ,
metadata: r . metadata ,
})),
],
});
Clear Source Tracking
// Remove source URL and identifier
const updated = await client . skills . update . mutate ({
id: skillId ,
sourceUrl: null ,
sourceIdentifier: null ,
});
console . log ( 'Source tracking cleared' );
Rename Skill
// Update name and slug together
const updated = await client . skills . update . mutate ({
id: skillId ,
slug: 'docker-production-guide' ,
name: 'Docker Production Guide' ,
description: 'Complete guide for running Docker in production' ,
});
console . log ( `Renamed to: ${ updated . name } ` );
Error Handling
User lacks write permission to the skill’s vault
Vault is read-only (system_default or enterprise without admin role)
Invalid mention syntax
Mention references non-existent skill/resource
Mention references inaccessible vault
Invalid input schema
Database constraint violation (e.g., duplicate slug)
Notes
Updates are partial : only provided fields are changed
Mention validation occurs before any database changes
Resource operations are processed in order: delete → update → create
Link sync is incremental: only modified sources trigger re-sync
Updating skillMarkdown deletes old skill-level links and creates new ones
Updating resource content deletes old resource-level links and creates new ones
If validation or sync fails, all changes are rolled back
Foreign key constraints automatically cascade resource deletions to related links