Endpoint
This endpoint requires authentication and only returns skills from vaults the user has access to.
UUID cursor for pagination. Points to the skill ID where the previous page ended.
Number of items to return per page. Must be between 1 and 100.
Optional search filter. Performs case-insensitive pattern matching on skill name and slug.
Output Schema
Array of skill list items. Each item includes:
User ID of the skill owner (null for system skills)
URL-safe identifier for the skill
Display name of the skill
Brief description of the skill
Parsed YAML frontmatter from the skill markdown
Additional metadata key-value pairs
Whether this is a default system skill
Original source URL if imported
Original source identifier if imported
Vault metadata object
One of: "personal", "enterprise", "system_default"
Whether the vault is read-only for the current user
Whether the vault membership is active
Timestamp when the skill was created
Timestamp when the skill was last updated
UUID cursor for the next page, or null if no more results
This endpoint uses cursor-based pagination ordered by createdAt (descending) then id:
- First request: omit the
cursor parameter
- Subsequent requests: use the
nextCursor from the previous response
- When
nextCursor is null, you’ve reached the end
Vault Filtering
Results are automatically filtered to only include skills from vaults where:
- The user has an active membership
- The membership is enabled (
isEnabled: true)
The response includes vault metadata indicating the vault type and permissions.
TypeScript Example
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}`,
},
}),
],
});
// Fetch first page with default limit (20)
const firstPage = await client.skills.list.query({
limit: 20,
});
console.log(`Loaded ${firstPage.items.length} skills`);
firstPage.items.forEach(skill => {
console.log(`${skill.name} (${skill.slug}) - ${skill.vault.name}`);
});
// Fetch next page using cursor
if (firstPage.nextCursor) {
const nextPage = await client.skills.list.query({
cursor: firstPage.nextCursor,
limit: 20,
});
console.log(`Loaded ${nextPage.items.length} more skills`);
}
// Search skills by name or slug
const searchResults = await client.skills.list.query({
search: 'docker',
limit: 10,
});
console.log(`Found ${searchResults.items.length} skills matching "docker"`);
Notes
- List items exclude
originalMarkdown, renderedMarkdown, and resources for performance
- Use
skills.getById or skills.getBySlug to fetch the complete skill with content
- The
search parameter performs partial, case-insensitive matching
- Empty result set returns
{ items: [], nextCursor: null }