skald / skald-php
Official PHP SDK for Skald API - Knowledge base management with semantic search, AI chat, and document generation
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 2
pkg:composer/skald/skald-php
Requires
- php: ^8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: ^3.7
This package is not auto-updated.
Last update: 2025-11-28 18:43:52 UTC
README
Official PHP SDK for Skald API - A knowledge base management system that automatically processes memos (summarizes, chunks, and indexes them) and provides semantic search, AI chat, and document generation capabilities.
Features
- Memo Management: Create and store memos with automatic processing (summarization, chunking, indexing)
- Semantic Search: Search through your knowledge base using vector search or title matching
- AI Chat: Ask questions about your knowledge base with AI-powered responses and inline citations
- Document Generation: Generate documents based on prompts with context from your knowledge base
- Streaming Support: Real-time streaming for chat and document generation operations
- Type-Safe: Fully typed with PHP 8.1+ features including enums and readonly properties
Requirements
- PHP 8.1 or higher
- cURL extension
- JSON extension
Installation
Install via Composer:
composer require skald/skald-php
Quick Start
<?php require 'vendor/autoload.php'; use Skald\Skald; use Skald\Types\MemoData; use Skald\Types\SearchRequest; use Skald\Types\SearchMethod; use Skald\Types\ChatRequest; // Initialize the client $skald = new Skald('sk_proj_your_api_key'); // Create a memo $result = $skald->createMemo(new MemoData( title: 'Meeting Notes - Q1 Planning', content: 'Discussed quarterly goals, hiring plans, and budget allocation...', tags: ['meeting', 'planning', 'q1'], source: 'notion' )); // Search for memos $results = $skald->search(new SearchRequest( query: 'quarterly goals', searchMethod: SearchMethod::CHUNK_VECTOR_SEARCH, limit: 10 )); foreach ($results->results as $result) { echo "Title: {$result->title}\n"; echo "Summary: {$result->summary}\n"; echo "Relevance: {$result->distance}\n\n"; } // Ask questions about your knowledge base $response = $skald->chat(new ChatRequest( query: 'What are our main goals for Q1?' )); echo $response->response; // "The main Q1 goals are... [[1]]"
API Reference
Client Initialization
$skald = new Skald(string $apiKey, ?string $baseUrl = null);
$apiKey: Your Skald API key (required)$baseUrl: Optional custom API base URL (defaults tohttps://api.useskald.com)
Creating Memos
$response = $skald->createMemo(MemoData $memoData): CreateMemoResponse;
Parameters:
new MemoData( title: string, // Required - memo title (max 255 chars) content: string, // Required - memo content metadata: ?array = null, // Optional - custom JSON metadata reference_id: ?string = null, // Optional - external ID mapping tags: ?array = null, // Optional - array of tags source: ?string = null // Optional - source system (e.g., "notion") );
Example:
$result = $skald->createMemo(new MemoData( title: 'Product Requirements', content: 'The new mobile app should support offline mode...', metadata: ['author' => 'John Doe', 'version' => '1.0'], tags: ['product', 'mobile', 'requirements'], source: 'confluence' )); // Returns: CreateMemoResponse { ok: true }
Updating Memos
$response = $skald->updateMemo( string $memoId, UpdateMemoData $updateData, string $idType = 'memo_uuid', ?string $projectId = null ): CreateMemoResponse;
Update an existing memo with partial or complete changes. All fields are optional - only include the fields you want to update.
Important: When content is updated, the memo is automatically reprocessed by the API (summary, tags, and chunks are regenerated). Other field updates preserve existing processing results.
Parameters:
$memoId(string): The memo UUID or client reference ID$updateData(UpdateMemoData): The fields to update$idType(string, optional): Type of identifier -'memo_uuid'(default) or'reference_id'$projectId(string|null, optional): Project UUID (required when using Token Authentication)
new UpdateMemoData( title: ?string = null, // Optional - memo title (max 255 chars) content: ?string = null, // Optional - memo content (triggers reprocessing) metadata: ?array = null, // Optional - custom JSON metadata client_reference_id: ?string = null, // Optional - external ID mapping (max 255 chars) source: ?string = null, // Optional - source system (max 255 chars) expiration_date: ?string = null // Optional - expiration date (ISO 8601 format) );
Examples:
use Skald\Types\UpdateMemoData; // Update by memo UUID (default) $skald->updateMemo('memo-uuid-here', new UpdateMemoData( title: 'Updated Title' )); // Update by client reference ID $skald->updateMemo('external-id-123', new UpdateMemoData( title: 'Updated via Reference ID' ), 'reference_id'); // Update with project ID (for Token Authentication) $skald->updateMemo('memo-uuid-here', new UpdateMemoData( content: 'New content' ), 'memo_uuid', 'project-uuid-123'); // Update content (triggers automatic reprocessing) $skald->updateMemo('memo-uuid-here', new UpdateMemoData( content: 'New content - this will regenerate summary, tags, and chunks' )); // Update multiple fields $skald->updateMemo('memo-uuid-here', new UpdateMemoData( title: 'Updated Title', metadata: ['updated_at' => time(), 'editor' => 'Jane'], source: 'notion', expiration_date: '2025-12-31T23:59:59Z' )); // Update metadata without triggering reprocessing $skald->updateMemo('memo-uuid-here', new UpdateMemoData( metadata: ['last_viewed' => time(), 'view_count' => 42] ));
Deleting Memos
$skald->deleteMemo( string $memoId, string $idType = 'memo_uuid', ?string $projectId = null ): void;
Delete a memo and all its associated data (content, summary, tags, chunks).
Parameters:
$memoId(string): The memo UUID or client reference ID$idType(string, optional): Type of identifier -'memo_uuid'(default) or'reference_id'$projectId(string|null, optional): Project UUID (required when using Token Authentication)
Examples:
// Delete by memo UUID (default) $skald->deleteMemo('memo-uuid-here'); // Delete by client reference ID $skald->deleteMemo('external-id-123', 'reference_id'); // Delete with project ID (for Token Authentication) $skald->deleteMemo('memo-uuid-here', 'memo_uuid', 'project-uuid-123'); // Delete by reference ID with project ID $skald->deleteMemo('external-id-456', 'reference_id', 'project-uuid-789');
Searching Memos
$response = $skald->search(SearchRequest $searchParams): SearchResponse;
Search Methods:
SearchMethod::CHUNK_VECTOR_SEARCH- Semantic search on memo chunks (returns distance scores 0-2)SearchMethod::TITLE_CONTAINS- Case-insensitive substring match on titlesSearchMethod::TITLE_STARTSWITH- Case-insensitive prefix match on titles
Parameters:
new SearchRequest( query: string, // Required - search query searchMethod: SearchMethod, // Required - search method limit: ?int = null, // Optional - results limit (1-50, default 10) filters: ?array = null // Optional - array of Filter objects );
Example:
use Skald\Types\Filter; use Skald\Types\FilterOperator; // Basic search $results = $skald->search(new SearchRequest( query: 'product requirements', searchMethod: SearchMethod::CHUNK_VECTOR_SEARCH, limit: 5 )); foreach ($results->results as $result) { echo "UUID: {$result->uuid}\n"; echo "Title: {$result->title}\n"; echo "Summary: {$result->summary}\n"; echo "Snippet: {$result->content_snippet}\n"; echo "Distance: {$result->distance}\n\n"; // Lower = more relevant } // Search with filters $results = $skald->search(new SearchRequest( query: 'product requirements', searchMethod: SearchMethod::CHUNK_VECTOR_SEARCH, limit: 5, filters: [ Filter::nativeField('tags', FilterOperator::IN, ['product', 'requirements']), Filter::nativeField('source', FilterOperator::EQ, 'confluence') ] ));
AI Chat (Non-Streaming)
$response = $skald->chat(ChatRequest $chatParams): ChatResponse;
Parameters:
new ChatRequest( query: string, // Required - question to ask );
Example:
$response = $skald->chat(new ChatRequest( query: 'What are the key features of our mobile app?' )); echo $response->response; // Output: "The mobile app has several key features: 1. Offline mode [[1]] // 2. Push notifications [[2]] 3. Biometric authentication [[1]]" // Citations [[1]], [[2]], etc. reference source memos
AI Chat (Streaming)
$stream = $skald->streamedChat(ChatRequest $chatParams): Generator<ChatStreamEvent>;
Example:
$stream = $skald->streamedChat(new ChatRequest( query: 'Summarize our product roadmap' )); foreach ($stream as $event) { if ($event->isToken()) { echo $event->content; // Print each token as it arrives } elseif ($event->isDone()) { echo "\nDone!\n"; break; } }
Document Generation (Non-Streaming)
$response = $skald->generateDoc(GenerateDocRequest $generateParams): GenerateDocResponse;
Parameters:
new GenerateDocRequest( prompt: string, // Required - document generation prompt rules: ?string = null, // Optional - style/format rules );
Example:
$response = $skald->generateDoc(new GenerateDocRequest( prompt: 'Create a product requirements document for the mobile app', rules: 'Use formal business language. Include sections: Overview, Requirements, Timeline' )); echo $response->response; // Outputs a full document with inline citations
Document Generation (Streaming)
$stream = $skald->streamedGenerateDoc(GenerateDocRequest $generateParams): Generator<GenerateDocStreamEvent>;
Example:
$stream = $skald->streamedGenerateDoc(new GenerateDocRequest( prompt: 'Write a technical specification for our API', rules: 'Include Architecture, Endpoints, and Security sections' )); foreach ($stream as $event) { if ($event->isToken()) { echo $event->content; } elseif ($event->isDone()) { echo "\n[Generation complete]\n"; break; } }
Error Handling
All API errors throw Skald\Exceptions\SkaldException:
use Skald\Exceptions\SkaldException; try { $result = $skald->createMemo(new MemoData( title: 'Test', content: 'Content' )); } catch (SkaldException $e) { // Error format: "Skald API error (STATUS_CODE): ERROR_MESSAGE" echo "Error: " . $e->getMessage(); echo "HTTP Status: " . $e->getCode(); }
Type Reference
Enums
SearchMethod
enum SearchMethod: string { case CHUNK_VECTOR_SEARCH = 'chunk_vector_search'; case TITLE_CONTAINS = 'title_contains'; case TITLE_STARTSWITH = 'title_startswith'; }
Request Types
MemoData
title: string- Memo title (max 255 characters)content: string- Memo contentmetadata: ?array- Custom metadatareference_id: ?string- External reference IDtags: ?array- Array of tag stringssource: ?string- Source system identifier
UpdateMemoData
title: ?string- Memo title (max 255 characters)content: ?string- Memo content (triggers reprocessing when updated)metadata: ?array- Custom metadataclient_reference_id: ?string- External reference ID (max 255 characters)source: ?string- Source system identifier (max 255 characters)expiration_date: ?string- Expiration date in ISO 8601 format
SearchRequest
query: string- Search querysearchMethod: SearchMethod- Search method to uselimit: ?int- Results limit (1-50, default 10)filters: ?array- Array of Filter objects to narrow results
ChatRequest
query: string- Question to ask
GenerateDocRequest
prompt: string- Document generation promptrules: ?string- Style/format guidelines
Response Types
CreateMemoResponse
ok: bool- Success status
SearchResponse
results: SearchResult[]- Array of search results
SearchResult
uuid: string- Memo unique identifiertitle: string- Memo titlesummary: string- Auto-generated summarycontent_snippet: string- Content snippetdistance: ?float- Relevance score (0-2 for vector search, null for title searches)
ChatResponse
ok: bool- Success statusresponse: string- AI response with inline citationsintermediate_steps: array- Debug information
GenerateDocResponse
ok: bool- Success statusresponse: string- Generated document with citationsintermediate_steps: array- Debug information
Stream Event Types
ChatStreamEvent & GenerateDocStreamEvent
type: string- Event type ('token' or 'done')content: ?string- Token content (only for 'token' events)isToken(): bool- Check if event is a tokenisDone(): bool- Check if event signals completion
Examples
See the examples/ directory for complete working examples:
create_memo.php- Creating memos with various optionsupdate_memo.php- Updating existing memos (including by reference ID)delete_memo.php- Deleting memos (by UUID or reference ID)search.php- All search methods with exampleschat.php- Non-streaming chatchat_streaming.php- Streaming chat with real-time outputgenerate_doc.php- Document generationgenerate_doc_streaming.php- Streaming document generation
Testing
Run the test suite:
# Install dependencies composer install # Run unit tests composer test # Run with coverage vendor/bin/phpunit --coverage-html coverage # Run static analysis composer phpstan # Check code style composer cs-check # Fix code style composer cs-fix
Integration Tests
Integration tests require a valid Skald API key:
export SKALD_API_KEY=sk_proj_your_api_key composer test
Development
Code Quality Tools
This library uses:
- PHPUnit for testing
- PHPStan (level 8) for static analysis
- PHP_CodeSniffer for PSR-12 compliance
Run all checks:
composer test # Run tests composer phpstan # Static analysis composer cs-check # Code style check
License
MIT License - Copyright (c) 2025 Skald Labs, Inc.
See LICENSE file for details.
Contributing
If you've spotted a bug or want a new feature, feel free to submit a PR.