Skip to main content

Endpoint

skills.update
This endpoint requires authentication and validates write permissions for the skill’s vault.

Input Schema

id
string
required
UUID of the skill to update
slug
string
New slug identifier (must be unique within the vault)
name
string
New display name (minimum 1 character)
description
string
New description (minimum 1 character)
skillMarkdown
string
New markdown content. When provided, triggers mention validation and link sync.
frontmatter
object
New frontmatter object (completely replaces existing)
metadata
object
New metadata object (completely replaces existing)
sourceUrl
string | null
Update source URL or set to null to clear
sourceIdentifier
string | null
Update source identifier or set to null to clear
resources
array
Array of resource operations: create, update, or delete

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:
  1. Delete: Resources with delete: true and an id are removed
  2. Update: Resources with an id (not marked for deletion) are updated
  3. 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
After successful update:
  1. Deletes old links for updated sources (skill or resources)
  2. Parses mention syntax from new content
  3. Creates new skillLink records
  4. Maintains bidirectional graph relationships
Link sync is incremental: only sources with updated content are re-synced.

TypeScript Examples

Update Metadata Only

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 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\necho "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\necho "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

NOT_FOUND
Skill does not exist
FORBIDDEN
  • User lacks write permission to the skill’s vault
  • Vault is read-only (system_default or enterprise without admin role)
BAD_REQUEST
  • Invalid mention syntax
  • Mention references non-existent skill/resource
  • Mention references inaccessible vault
  • Invalid input schema
INTERNAL_SERVER_ERROR
Database constraint violation (e.g., duplicate slug)
UNAUTHORIZED
No valid session

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

Build docs developers (and LLMs) love