Documentation Index
Fetch the complete documentation index at: https://docs.useskald.com/llms.txt
Use this file to discover all available pages before exploring further.
Node.js client library for the Skald API.
Installation
npm install @skald-labs/skald-node
Requirements
Usage
Initialize the client
import { Skald } from '@skald-labs/skald-node';
const skald = new Skald('your-api-key-here');
Memo Management
Create a Memo
Create a new memo that will be automatically processed (summarized, tagged, chunked, and indexed for search):
const result = await skald.createMemo({
title: 'Meeting Notes',
content: 'Full content of the memo...',
metadata: {
type: 'notes',
author: 'John Doe'
},
reference_id: 'external-id-123',
tags: ['meeting', 'q1'],
source: 'notion',
expiration_date: '2024-12-31T23:59:59Z'
});
console.log(result); // { memo_uuid: '550e8400-e29b-41d4-a716-446655440000' }
Required Fields:
title (string, max 255 chars) - The title of the memo
content (string) - The full content of the memo
Optional Fields:
project_id (string) - Project UUID (required when using Token Authentication)
metadata (object) - Custom JSON metadata
reference_id (string, max 255 chars) - An ID from your side that you can use to match Skald memo UUIDs with e.g. documents on your end
tags (array of strings) - Tags for categorization
source (string, max 255 chars) - An indication from your side of the source of this content, useful when building integrations
expiration_date (string) - ISO 8601 timestamp for automatic memo expiration
Create a Memo from File Upload
Upload a document file (PDF, DOC, DOCX, PPTX) that will be processed asynchronously and converted into a memo:
import * as fs from 'fs';
const fileBuffer = fs.readFileSync('./document.pdf');
const result = await skald.createMemoFromFile({
file: fileBuffer,
filename: 'document.pdf',
metadata: {
type: 'report',
department: 'engineering'
},
tags: ['report', '2024'],
source: 'google-drive',
reference_id: 'external-file-123'
});
console.log(result); // { ok: true, memo_uuid: '550e8400-e29b-41d4-a716-446655440000' }
// Poll for processing status
const status = await skald.checkMemoStatus(result.memo_uuid);
console.log(status.status); // 'processing' | 'processed' | 'error'
Supported File Types:
- PDF (.pdf)
- Microsoft Word (.doc, .docx)
- Microsoft PowerPoint (.pptx)
- Maximum file size: 100MB
Required Fields:
file (Buffer | Blob) - The file content
filename (string) - The name of the file including extension
Optional Fields:
reference_id (string, max 255 chars) - Your external reference ID
metadata (object) - Custom JSON metadata
tags (array of strings) - Tags for categorization
source (string, max 255 chars) - Source system identifier
Note: File processing is asynchronous. Use checkMemoStatus() to monitor the processing status.
Check Memo Processing Status
Monitor the processing status of a memo, especially useful after uploading files:
// Check status by UUID
const status = await skald.checkMemoStatus('550e8400-e29b-41d4-a716-446655440000');
console.log(status.status); // 'processing' | 'processed' | 'error'
if (status.status === 'error') {
console.error('Processing failed:', status.error_reason);
}
// Check by reference ID
const status2 = await skald.checkMemoStatus('external-id-123', 'reference_id');
// Poll until processing completes
while (true) {
const status = await skald.checkMemoStatus(memoUuid);
if (status.status === 'processed') {
console.log('Processing complete!');
break;
} else if (status.status === 'error') {
console.error('Processing failed:', status.error_reason);
break;
}
// Wait 2 seconds before checking again
await new Promise(resolve => setTimeout(resolve, 2000));
}
Status Values:
processing - The memo is currently being processed (parsed, summarized, chunked, indexed)
processed - Processing completed successfully, memo is ready to use
error - An error occurred during processing, check error_reason for details
Parameters:
memoId (string, required) - The memo UUID or client reference ID
idType (string, optional) - Either 'memo_uuid' or 'reference_id' (default: 'memo_uuid')
Get a Memo
Retrieve a memo by its UUID or your reference ID:
// Get by UUID
const memo = await skald.getMemo('550e8400-e29b-41d4-a716-446655440000');
// Get by reference ID
const memo = await skald.getMemo('external-id-123', 'reference_id');
console.log(memo.title);
console.log(memo.content);
console.log(memo.summary);
console.log(memo.tags);
console.log(memo.chunks);
The getMemo() method returns complete memo details including content, AI-generated summary, tags, and content chunks.
List Memos
List all memos with pagination:
// Get first page with default page size (20)
const memos = await skald.listMemos();
// Get specific page with custom page size
const memos = await skald.listMemos({ page: 2, page_size: 50 });
console.log(`Total memos: ${memos.count}`);
console.log(`Results: ${memos.results.length}`);
console.log(`Next page: ${memos.next}`);
Parameters:
page (number, optional) - Page number (default: 1)
page_size (number, optional) - Results per page (default: 20, max: 100)
Update a Memo
Update an existing memo by UUID or reference ID:
// Update by UUID
await skald.updateMemo('550e8400-e29b-41d4-a716-446655440000', {
title: 'Updated Title',
metadata: { status: 'reviewed' }
});
// Update by reference ID and trigger reprocessing
await skald.updateMemo('external-id-123', {
content: 'New content that will be reprocessed'
}, 'reference_id');
Note: When you update the content field, the memo will be automatically reprocessed (summary, tags, and chunks regenerated).
Updatable Fields:
title (string)
content (string)
metadata (object)
client_reference_id (string)
source (string)
expiration_date (string)
Delete a Memo
Permanently delete a memo and all associated data:
// Delete by UUID
await skald.deleteMemo('550e8400-e29b-41d4-a716-446655440000');
// Delete by reference ID
await skald.deleteMemo('external-id-123', 'reference_id');
Warning: This operation permanently deletes the memo and all related data (content, summary, tags, chunks) and cannot be undone.
Search Memos
Search through your memos using semantic search:
// Basic semantic search
const results = await skald.search({
query: 'quarterly goals',
limit: 10
});
// Search with filters
const filtered = await skald.search({
query: 'python tutorial',
filters: [
{
field: 'source',
operator: 'eq',
value: 'notion',
filter_type: 'native_field'
},
{
field: 'level',
operator: 'eq',
value: 'beginner',
filter_type: 'custom_metadata'
}
]
});
console.log(`Found ${filtered.results.length} results`);
filtered.results.forEach(memo => {
console.log(`- ${memo.title} (distance: ${memo.distance})`);
});
Search Parameters
query (string, required) - The search query
limit (integer, optional) - Maximum results to return (1-50, default 10)
filters (array, optional) - Array of filter objects to narrow results (see Filters section below)
Search Response
interface SearchResponse {
results: Array<{
memo_uuid: string;
chunk_uuid: string;
memo_title: string;
memo_summary: string;
content_snippet: string;
distance: number | null;
}>;
}
memo_uuid - Unique identifier for the memo
memo_uuid - Unique identifier for the chunk
memo_title - Memo title
memo_summary - Auto-generated summary for the memo
content_snippet - A snippet containing the beginning of the chunk content.
distance - A decimal from 0 to 2 determining how close the result was deemed to be to the query when using semantic search (chunk_vector_search). The closer to 0 the more related the content is to the query. null if using title_contains or title_startswith.
Chat with Your Knowledge Base
Ask questions about your memos using an AI agent. The agent retrieves relevant context and generates answers with inline citations.
Non-Streaming Chat
const result = await skald.chat({
query: 'What were the main points discussed in the Q1 meeting?'
});
console.log(result.response);
// "The main points discussed in the Q1 meeting were:
// 1. Revenue targets
// 2. Hiring plans
// 3. Product roadmap"
console.log(result.ok); // true
Streaming Chat
For real-time responses, use streaming chat:
const stream = skald.streamedChat({
query: 'What are our quarterly goals?'
});
for await (const event of stream) {
if (event.type === 'token') {
// Write each token as it arrives
process.stdout.write(event.content);
} else if (event.type === 'done') {
console.log('\nDone!');
}
}
Chat Parameters
query (string, required) - The question to ask
system_prompt (string, optional) - A system prompt to guide the AI’s behavior
filters (array, optional) - Array of filter objects to focus chat context on specific sources (see Filters section below)
project_id (string, optional) - Project UUID (required when using Token Authentication)
Chat Response
Non-streaming responses include:
ok (boolean) - Success status
response (string) - The AI’s answer
intermediate_steps (array) - Steps taken by the agent (for debugging)
Streaming responses yield events:
{ type: 'token', content: string } - Each text token as it’s generated
{ type: 'done' } - Indicates the stream has finished
Filters
Filters allow you to narrow down results based on memo metadata. You can filter by native fields or custom metadata fields. Filters are supported in search(), chat(), generateDoc(), and their streaming variants.
See Filters for complete documentation.
Filter Structure
interface Filter {
field: string; // Field name to filter on
operator: FilterOperator; // Comparison operator
value: string | string[]; // Value(s) to compare against
filter_type: 'native_field' | 'custom_metadata';
}
Native Fields
Native fields are built-in memo properties:
title - Memo title
source - Source system (e.g., “notion”, “confluence”)
client_reference_id - Your external reference ID
tags - Memo tags (array)
You can filter on any field from the metadata object you provided when creating the memo.
Filter Operators
eq - Equals (exact match)
neq - Not equals
contains - Contains substring (case-insensitive)
startswith - Starts with prefix (case-insensitive)
endswith - Ends with suffix (case-insensitive)
in - Value is in array (requires array value)
not_in - Value is not in array (requires array value)
Filter Examples
// Filter by source
{
field: 'source',
operator: 'eq',
value: 'notion',
filter_type: 'native_field'
}
// Filter by multiple tags
{
field: 'tags',
operator: 'in',
value: ['security', 'compliance'],
filter_type: 'native_field'
}
// Filter by title containing text
{
field: 'title',
operator: 'contains',
value: 'meeting',
filter_type: 'native_field'
}
// Filter by custom metadata field
{
field: 'department',
operator: 'eq',
value: 'engineering',
filter_type: 'custom_metadata'
}
// Exclude specific sources
{
field: 'source',
operator: 'not_in',
value: ['draft', 'archive'],
filter_type: 'native_field'
}
Combining Multiple Filters
When you provide multiple filters, they are combined with AND logic (all filters must match):
const results = await skald.search({
query: 'security best practices',
filters: [
{
field: 'source',
operator: 'eq',
value: 'security-docs',
filter_type: 'native_field'
},
{
field: 'tags',
operator: 'in',
value: ['approved', 'current'],
filter_type: 'native_field'
},
{
field: 'status',
operator: 'neq',
value: 'draft',
filter_type: 'custom_metadata'
}
]
});
Filters with Chat
Focus chat context on specific sources:
const result = await skald.chat({
query: 'What are our security practices?',
filters: [
{
field: 'tags',
operator: 'in',
value: ['security', 'compliance'],
filter_type: 'native_field'
}
]
});
Scopes
Scopes provide strict data isolation for multi-tenant applications.
Creating Memos with Scopes
await skald.createMemo({
title: 'Memo title',
content: 'Scoped content',
scopes: { organizationId: '123', admin: 'true' }
});
Querying with Scopes
When using chat() or search(), provide the same scopes to access scoped content:
const response = await skald.chat({
query: 'what was discussed in the meeting on 2026-01-25?',
scopes: { organizationId: '123', admin: 'true' }
});
Only memos that were created with matching scope values will be included in the context.
If you don’t provide any scopes, chat will query all memos for its context. However, if you pass any scopes, only memos that match exactly the scopes will be included in the context.
You must include all relevant scopes in order for them to have effect. Scopes operate on an AND basis.
For example, a memo with scopes: { organizationId: '123', admin: 'true' } will behave as follows:
- If the query includes
{ organizationId: '123', admin: 'true' }, the memo will be included in the context.
- If the query includes
{ organizationId: '123' }, the memo will be included in the context.
- If the query includes
{ admin: 'true' }, the memo will be included in the context.
- If the query includes
{ organizationId: '123', admin: false }, the memo will not be included in the context.
Error Handling
try {
const result = await skald.createMemo({
title: 'My Memo',
content: 'Content here'
});
console.log('Success:', result);
} catch (error) {
console.error('Error:', error.message);
}
TypeScript Support
This package includes TypeScript type definitions out of the box.
import {
Skald,
MemoData,
CreateMemoResponse,
MemoFileData,
CreateMemoFromFileResponse,
MemoStatus,
MemoStatusResponse,
Memo,
ListMemosResponse,
UpdateMemoData,
UpdateMemoResponse,
IdType,
Filter,
FilterOperator,
FilterType,
SearchRequest,
SearchResponse,
ChatRequest,
ChatResponse,
ChatStreamEvent
} from '@skald-labs/skald-node';
const skald = new Skald('your-api-key-here');
// Create a memo with types
const memoData: MemoData = {
title: 'My Memo',
content: 'Content here',
tags: ['tag1', 'tag2'],
metadata: { department: 'engineering' }
};
const createResponse: CreateMemoResponse = await skald.createMemo(memoData);
// Get memo with types
const memo: Memo = await skald.getMemo('550e8400-e29b-41d4-a716-446655440000');
const memoByRef: Memo = await skald.getMemo('external-id-123', 'reference_id' as IdType);
// List memos with types
const memos: ListMemosResponse = await skald.listMemos({ page: 1, page_size: 20 });
// Update memo with types
const updateData: UpdateMemoData = {
title: 'Updated Title',
metadata: { status: 'reviewed' }
};
const updateResponse: UpdateMemoResponse = await skald.updateMemo(
'550e8400-e29b-41d4-a716-446655440000',
updateData
);
// Delete memo
await skald.deleteMemo('550e8400-e29b-41d4-a716-446655440000');
// Upload a file
import * as fs from 'fs';
const fileBuffer = fs.readFileSync('./document.pdf');
const fileData: MemoFileData = {
file: fileBuffer,
filename: 'document.pdf',
metadata: { type: 'report' },
tags: ['document'],
source: 'local'
};
const uploadResponse: CreateMemoFromFileResponse = await skald.createMemoFromFile(fileData);
// Check processing status
const statusResponse: MemoStatusResponse = await skald.checkMemoStatus(uploadResponse.memo_uuid);
const status: MemoStatus = statusResponse.status; // 'processing' | 'processed' | 'error'
// Search with filters and types
const filters: Filter[] = [
{
field: 'source',
operator: 'eq' as FilterOperator,
value: 'notion',
filter_type: 'native_field' as FilterType
},
{
field: 'department',
operator: 'eq' as FilterOperator,
value: 'engineering',
filter_type: 'custom_metadata' as FilterType
}
];
const searchRequest: SearchRequest = {
query: 'quarterly goals',
limit: 10,
filters
};
const searchResponse: SearchResponse = await skald.search(searchRequest);
// Chat with filters and types
const chatResponse: ChatResponse = await skald.chat({
query: 'What are our quarterly goals?',
filters
});
// Streaming chat with types
const stream = skald.streamedChat({
query: 'What are our quarterly goals?',
filters
});
for await (const event of stream) {
const typedEvent: ChatStreamEvent = event;
if (typedEvent.type === 'token') {
process.stdout.write(typedEvent.content || '');
}
}