Quarry API
The QuarryAPI is the core data interface for Stoneforge. It manages elements (tasks, documents, entities, etc.), dependencies, plans, workflows, channels, and sync operations. The Orchestrator API extends this with agent-specific capabilities.
Initialization
import { createQuarryAPI } from '@stoneforge/quarry';import { createStorage, initializeSchema } from '@stoneforge/storage';
const storage = createStorage({ path: '.stoneforge/stoneforge.db' });initializeSchema(storage);const api = createQuarryAPI(storage);CRUD operations
Create
const task = await api.create({ type: 'task', createdBy: entityId, title: 'Implement feature', priority: 2, taskType: 'feature',});Required fields for all elements: type, createdBy. Each element type has its own additional fields — see Core Types.
Read
const task = await api.get(taskId);
// With hydration (resolve document references)const hydrated = await api.get(taskId, { hydrate: { description: true, content: true, attachments: true },});Update
const updated = await api.update(taskId, { status: 'in_progress', assignee: entityId,});Delete
Soft-delete (tombstone). The element is marked as deleted but not removed.
await api.delete(taskId);Query operations
List with filters
const tasks = await api.list({ type: 'task', status: 'open', // Exact match priority: 2, tags: ['urgent'], // AND logic (all required) tagsAny: ['frontend', 'backend'], // OR logic (any matches)});
// Arrays for OR matchingconst tasks = await api.list({ type: 'task', status: ['open', 'in_progress'], // Either status priority: [1, 2], // Either priority});Paginated list
const result = await api.listPaginated({ type: 'task', status: 'open', limit: 20, offset: 0,});// result.items, result.total, result.hasMoreDocument filtering
// By categoryconst specs = await api.list({ type: 'document', category: 'spec' });
// By status (default: 'active' only)const archived = await api.list({ type: 'document', status: 'archived' });
// Paginated with both filtersconst result = await api.listPaginated({ type: 'document', category: 'prd', status: 'active', limit: 20,});Search
const results = await api.search('keyword', { type: ['task', 'document'], // Accepts ElementType or ElementType[]});Full-text document search (FTS5)
const results = await api.searchDocumentsFTS('search query', { category: 'spec', // Optional category filter status: 'active', // Optional (default: 'active') hardCap: 50, // Max results before adaptive filtering elbowSensitivity: 1.5, // Adaptive top-K sensitivity minResults: 1, // Minimum results to return});Uses FTS5 with BM25 ranking, snippet generation, and adaptive elbow detection for top-K filtering.
Channel search
const channels = await api.searchChannels('channel-name');Task operations
Ready tasks
Tasks that are unblocked, open, not in draft plans, and not future-scheduled.
const ready = await api.ready();const withEphemeral = await api.ready({ includeEphemeral: true });ready() excludes:
- Blocked tasks
- Tasks in draft plans
- Future-scheduled tasks (
scheduledFor > now) - Ephemeral workflow tasks (unless
includeEphemeral: true)
Backlog tasks
const backlog = await api.backlog();const filtered = await api.backlog({ priority: 1 });Blocked tasks
const blocked = await api.blocked();Dependency operations
Add / remove
await api.addDependency({ blockedId: taskA, blockerId: taskB, type: 'blocks', actor: actorId, // Optional, falls back to blocked element's createdBy});
await api.removeDependency(blockedId, blockerId, 'blocks');Query
// What this element depends onconst deps = await api.getDependencies(elementId, types?);
// What depends on this elementconst dependents = await api.getDependents(elementId, types?);
// Full treeconst tree = await api.getDependencyTree(elementId);Gate satisfaction
await api.satisfyGate(blockedId, blockerId, actor);await api.recordApproval(blockedId, blockerId, approverId);await api.removeApproval(blockedId, blockerId, approverId);Plan operations
// Add/remove tasksawait api.addTaskToPlan(taskId, planId); // taskId first!await api.removeTaskFromPlan(taskId, planId, actor?);await api.createTaskInPlan(planId, { title: 'Task', priority: 2, createdBy: actorId });
// Queryconst tasks = await api.getTasksInPlan(planId);const progress = await api.getPlanProgress(planId);
// Bulk operationsawait api.bulkClosePlanTasks(planId, { closeReason: 'Done' });await api.bulkDeferPlanTasks(planId, { filter: { status: 'open' } });await api.bulkReassignPlanTasks(planId, newAssigneeId);await api.bulkTagPlanTasks(planId, { addTags: ['v2'], removeTags: ['v1'] });Workflow operations
const tasks = await api.getTasksInWorkflow(workflowId);const ready = await api.getReadyTasksInWorkflow(workflowId);const ordered = await api.getOrderedTasksInWorkflow(workflowId); // Topological sortconst progress = await api.getWorkflowProgress(workflowId);await api.deleteWorkflow(workflowId); // Hard deleteGarbage collection
await api.garbageCollectWorkflows({ maxAgeMs: 7 * 24 * 60 * 60 * 1000 });await api.garbageCollectTasks({ maxAgeMs: 7 * 24 * 60 * 60 * 1000 });Channel operations
// Find or create direct channelconst { channel, created } = await api.findOrCreateDirectChannel(entityA, entityB, actor);
// Membershipawait api.addChannelMember(channelId, entityId);await api.removeChannelMember(channelId, entityId);await api.leaveChannel(channelId, actor);
// Merge channelsconst result = await api.mergeChannels(sourceId, targetId, { newName: 'merged-channel', actor: actorEntityId,});// result.target, result.sourceArchived, result.messagesMovedEntity operations
const entity = await api.lookupEntityByName('agent-name');await api.setEntityManager(entityId, managerId, actor);await api.clearEntityManager(entityId, actor);const reports = await api.getDirectReports(managerId);const chain = await api.getManagementChain(entityId);const orgChart = await api.getOrgChart(rootEntityId?);Send direct message
Convenience method — finds or creates a direct channel and sends a message in one call.
const result = await api.sendDirectMessage(senderEntityId, { recipient: recipientEntityId, contentRef: documentId, // Must create the Document first attachments: [docId1], // Optional tags: ['urgent'], // Optional});// result.channel, result.message, result.channelCreatedDocument operations
Archive / unarchive
await api.archiveDocument(docId);await api.unarchiveDocument(docId);// Equivalent: api.update(docId, { status: 'archived' })Embedding service
Register an embedding service for automatic semantic indexing:
import { EmbeddingService, LocalEmbeddingProvider } from '@stoneforge/quarry/services';
const provider = new LocalEmbeddingProvider('/path/to/model');const embeddingService = new EmbeddingService(storage, { provider });
// Auto-embed on create/update, auto-remove on deleteapi.registerEmbeddingService(embeddingService);Reindex FTS
const result = api.reindexAllDocumentsFTS();// result.indexed, result.errorsHistory & timeline
const events = await api.getEvents(elementId);const allEvents = await api.listEvents({ eventType: 'created' });const count = await api.countEvents({ elementId });
// Document versioningconst version = await api.getDocumentVersion(docId, versionNum);const history = await api.getDocumentHistory(docId);
// Time travelconst snapshot = await api.reconstructAtTime(elementId, timestamp);const timeline = await api.getElementTimeline(elementId);Sync operations
Export
await api.export();await api.export({ outputPath: './export.jsonl' });await api.export({ includeDeleted: true });ExportOptions
| Parameter | Type | Default | Description |
|---|---|---|---|
format | string | jsonl | Export format. |
types | ElementType[] | — | Element types to export (default: all). |
modifiedAfter | Timestamp | — | Only elements modified after this time. |
includeDeleted | boolean | — | Include soft-deleted elements. |
includeDependencies | boolean | — | Export dependencies. |
includeEvents | boolean | — | Export events. |
outputPath | string | — | Output file path (returns string if omitted). |
Import
await api.import({ inputPath: './export.jsonl' });await api.import({ data: jsonlString });await api.import({ inputPath: './data.jsonl', dryRun: true });ImportOptions
| Parameter | Type | Default | Description |
|---|---|---|---|
inputPath | string | — | Input file path. |
data | string | — | Raw JSONL data (alternative to inputPath). |
conflictStrategy | string | error | Conflict resolution: 'skip', 'overwrite', or 'error'. |
validateFirst | boolean | — | Validate all data before importing. |
dryRun | boolean | — | Validate without importing. |
System
const stats = await api.stats();Common patterns
Task with description
// 1. Create description documentconst desc = await api.create({ type: 'document', createdBy: actorId, title: 'Task Description', content: '# Requirements\n\n...', contentType: 'markdown',});
// 2. Create task referencing the descriptionconst task = await api.create({ type: 'task', createdBy: actorId, title: 'Implement feature', descriptionRef: desc.id, priority: 2, taskType: 'feature',});Check if a task is blocked
// Via APIconst blockedTasks = await api.blocked();const isBlocked = blockedTasks.some(t => t.id === taskId);
// Via BlockedCacheService (O(1) lookup)import { createBlockedCacheService } from '@stoneforge/quarry';const blockedCache = createBlockedCacheService(storage);const isBlocked = blockedCache.isBlocked(taskId);Multi-filter query
const tasks = await api.list({ type: 'task', status: ['open', 'in_progress'], priority: [1, 2], assignee: agentId, tags: ['urgent'],});