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.
Python client library for the Skald API.
Installation
Requirements
Usage
Initialize the client
import asyncio
from skald_sdk import Skald
async def main():
async with Skald('your-api-key-here') as skald:
# Your code here
pass
asyncio.run(main())
Memo Management
Create a Memo
Create a new memo that will be automatically processed (summarized, tagged, chunked, and indexed for search):
result = await skald.create_memo({
'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'
})
print(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:
metadata (dict) - 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 (list 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
Get a Memo
Retrieve a memo by its UUID or your reference ID:
# Get by UUID
memo = await skald.get_memo('550e8400-e29b-41d4-a716-446655440000')
# Get by reference ID
memo = await skald.get_memo('external-id-123', 'reference_id')
print(memo['title'])
print(memo['content'])
print(memo['summary'])
print(memo['tags'])
print(memo['chunks'])
The get_memo() method returns complete memo details including content, AI-generated summary, tags, and content chunks.
Memo Response Fields:
uuid - Unique identifier for the memo
title - Memo title
content - Full memo content
summary - AI-generated summary
pending - Boolean indicating if the memo is still being processed
archived - Boolean indicating if the memo is archived
type - Memo type (“document” or “text”)
metadata - Custom metadata object
tags - List of tag objects
chunks - List of content chunk objects
List Memos
List all memos with pagination:
# Get first page with default page size (20)
memos = await skald.list_memos()
# Get specific page with custom page size
memos = await skald.list_memos({'page': 2, 'page_size': 50})
print(f"Total memos: {memos['count']}")
print(f"Results: {len(memos['results'])}")
print(f"Next page: {memos['next']}")
Parameters:
page (int, optional) - Page number (default: 1)
page_size (int, 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.update_memo('550e8400-e29b-41d4-a716-446655440000', {
'title': 'Updated Title',
'metadata': {'status': 'reviewed'}
})
# Update by reference ID and trigger reprocessing
await skald.update_memo('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 (dict)
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.delete_memo('550e8400-e29b-41d4-a716-446655440000')
# Delete by reference ID
await skald.delete_memo('external-id-123', 'reference_id')
Warning: This operation permanently deletes the memo and all related data (content, summary, tags, chunks) and cannot be undone.
Check Memo Processing Status
After creating or updating a memo (especially when uploading files), it is automatically processed asynchronously (summarized, tagged, and chunked). Use the check_memo_status() method to check processing status:
# Create a memo
result = await skald.create_memo({
'title': 'My Document',
'content': 'Long content that needs processing...'
})
memo_uuid = result['memo_uuid']
# Check processing status
status = await skald.check_memo_status(memo_uuid)
if status['status'] == 'processing':
print('Memo is still being processed...')
elif status['status'] == 'processed':
print('Memo is ready!')
# Now you can retrieve the full memo with summary and tags
memo = await skald.get_memo(memo_uuid)
print(f"Summary: {memo['summary']}")
elif status['status'] == 'error':
print(f"Processing failed: {status['error_reason']}")
# You can also check status by reference ID
status = await skald.check_memo_status('external-id-123', 'reference_id')
Status Response Fields:
memo_uuid - The memo’s UUID
status - Processing state: “processing”, “processed”, or “error”
processing_started_at - ISO timestamp when processing started
processing_completed_at - ISO timestamp when processing completed (if finished)
error_reason - Error message if status is “error”
Note: Most memos are processed within a few seconds, but larger documents may take longer.
File Uploads
Upload documents (PDF, DOC, DOCX, PPTX) to your Skald knowledge base. Files are automatically processed to extract text, then summarized, tagged, chunked, and indexed for search.
Upload a Document
# Upload a document file with optional metadata
result = await skald.create_memo_from_file(
'/path/to/document.pdf',
{
'title': 'Q4 Roadmap Presentation',
'source': 'Product Team',
'reference_id': 'ROADMAP-Q4-2024',
'tags': ['roadmap', 'product', 'q4'],
'metadata': {
'quarter': 'Q4',
'year': '2024',
'department': 'product'
},
'expiration_date': '2024-12-31T23:59:59Z'
}
)
memo_uuid = result['memo_uuid']
print(f"Uploaded document: {memo_uuid}")
# Check processing status
status = await skald.check_memo_status(memo_uuid)
print(f"Processing status: {status['status']}")
# Poll until processing completes
import asyncio
while True:
status = await skald.check_memo_status(memo_uuid)
if status['status'] == 'processed':
print('Processing complete!')
break
elif status['status'] == 'error':
print(f"Error: {status['error_reason']}")
break
await asyncio.sleep(2)
Supported File Types:
- PDF (
.pdf)
- Microsoft Word (
.doc, .docx)
- Microsoft PowerPoint (
.pptx)
File Size Limit: 100MB per file
Parameters:
file_path (string, required) - Path to the file to upload
memo_data (dict, optional) - Optional metadata for the memo:
title (string) - Title for the memo
source (string) - Source system identifier
reference_id (string) - Your external reference ID
tags (list of strings) - Tags for categorization
metadata (dict) - Custom JSON metadata
expiration_date (string) - ISO 8601 timestamp for automatic memo expiration
Note: File processing is asynchronous and may take longer than text-based memos depending on file size and complexity. Use check_memo_status() to monitor processing progress.
Search Memos
Search through your memos using semantic search with optional filters:
# Basic semantic search
results = await skald.search({
'query': 'quarterly goals',
'limit': 10
})
# Search with filters
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'
}
]
})
print(f"Found {len(filtered['results'])} results")
for result in filtered['results']:
print(f"- {result['memo_title']} (distance: {result['distance']})")
Search Parameters
query (string, required) - The search query
limit (integer, optional) - Maximum results to return (1-50, default 10)
filters (list, optional) - List of filter objects to narrow results (see Filters section below)
Search Response
{
'results': [
{
'memo_uuid': str,
'chunk_uuid': str,
'memo_title': str,
'memo_summary': str,
'content_snippet': str,
'distance': float | None
}
]
}
memo_uuid - Unique identifier for the memo
chunk_uuid - Unique identifier for the chunk
memo_title - Memo title
memo_summary - Auto-generated summary for the memo
content_snippet - A snippet containing content from the matching chunk
distance - A decimal from 0 to 2 determining how close the result was deemed to be to the query. The closer to 0 the more related the content is to the query.
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
response = await skald.chat({
'query': 'What were the main points discussed in the Q1 meeting?'
})
print(response['response'])
# "The main points discussed in the Q1 meeting were:
# 1. Revenue targets
# 2. Hiring plans
# 3. Product roadmap"
print(response['ok']) # True
Streaming Chat
For real-time responses, use streaming chat:
async for event in skald.streamed_chat({
'query': 'What are our quarterly goals?'
}):
if event['type'] == 'token':
# Print each token as it arrives
print(event['content'], end='', flush=True)
elif event['type'] == 'done':
print('\nDone!')
Chat Parameters
query (string, required) - The question to ask
filters (list, optional) - List of filter objects to focus chat context on specific sources (see Filters section below)
Chat Response
Non-streaming responses include:
ok (bool) - Success status
response (str) - The AI’s answer
intermediate_steps (list) - Steps taken by the agent (for debugging)
Streaming responses yield events:
{'type': 'token', 'content': str} - 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(), and their streaming variants.
See Filters for complete documentation.
Filter Structure
{
'field': str, # Field name to filter on
'operator': str, # Comparison operator
'value': str | list[str], # 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 (list)
You can filter on any field from the metadata dict 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 list (requires list value)
not_in - Value is not in list (requires list 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):
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:
response = await skald.chat({
'query': 'What are our security practices?',
'filters': [
{
'field': 'tags',
'operator': 'in',
'value': ['security', 'compliance'],
'filter_type': 'native_field'
}
]
})
Error Handling
try:
result = await skald.create_memo({
'title': 'My Memo',
'content': 'Content here'
})
print('Success:', result)
except Exception as e:
print(f'Error: {e}')
Type Hints Support
This package includes full type hints for better IDE support and type checking.
from skald_sdk import Skald
from skald_sdk.types import (
MemoData,
MemoFileData,
UpdateMemoData,
SearchRequest,
ChatRequest,
Filter,
FilterOperator,
FilterType,
MemoStatus,
CreateMemoResponse,
Memo,
ListMemosResponse,
UpdateMemoResponse,
MemoStatusResponse,
IdType,
SearchResponse,
ChatResponse,
ChatStreamEvent
)
async def main():
async with Skald('your-api-key-here') as skald:
# Create a memo with types
memo_data: MemoData = {
'title': 'My Memo',
'content': 'Content here',
'tags': ['tag1', 'tag2'],
'metadata': {'department': 'engineering'}
}
create_response: CreateMemoResponse = await skald.create_memo(memo_data)
# Get memo with types
memo: Memo = await skald.get_memo('550e8400-e29b-41d4-a716-446655440000')
memo_by_ref: Memo = await skald.get_memo('external-id-123', 'reference_id')
# List memos with types
memos: ListMemosResponse = await skald.list_memos({'page': 1, 'page_size': 20})
# Update memo with types
update_data: UpdateMemoData = {
'title': 'Updated Title',
'metadata': {'status': 'reviewed'}
}
update_response: UpdateMemoResponse = await skald.update_memo(
'550e8400-e29b-41d4-a716-446655440000',
update_data
)
# Delete memo
await skald.delete_memo('550e8400-e29b-41d4-a716-446655440000')
# Upload a file with types
file_data: MemoFileData = {
'title': 'Q4 Roadmap',
'source': 'Product Team',
'reference_id': 'ROADMAP-Q4-2024',
'tags': ['roadmap', 'product'],
'metadata': {'quarter': 'Q4', 'year': '2024'}
}
file_response: CreateMemoResponse = await skald.create_memo_from_file(
'/path/to/document.pdf',
file_data
)
# Check memo status with types
status: MemoStatusResponse = await skald.check_memo_status(file_response['memo_uuid'])
memo_status: MemoStatus = status['status'] # "processing", "processed", or "error"
# Search with filters and types
filters: list[Filter] = [
{
'field': 'source',
'operator': 'eq',
'value': 'notion',
'filter_type': 'native_field'
},
{
'field': 'department',
'operator': 'eq',
'value': 'engineering',
'filter_type': 'custom_metadata'
}
]
search_request: SearchRequest = {
'query': 'quarterly goals',
'limit': 10,
'filters': filters
}
search_response: SearchResponse = await skald.search(search_request)
# Chat with filters and types
chat_response: ChatResponse = await skald.chat({
'query': 'What are our quarterly goals?',
'filters': filters
})
print(chat_response['response'])
# Streaming chat with types
async for event in skald.streamed_chat({
'query': 'What are our quarterly goals?',
'filters': filters
}):
typed_event: ChatStreamEvent = event
if typed_event['type'] == 'token':
print(typed_event['content'], end='', flush=True)