Skip to main content
The QuarryAPI provides the foundational CRUD operations for all Stoneforge elements. It connects the type system to the SQLite storage layer and implements filtering, pagination, hydration, and FTS search.

Overview

The QuarryAPI is implemented in packages/quarry/src/api/quarry-api.ts and provides:
  • CRUD operations (create, read, update, delete)
  • Filtering and pagination
  • Hydration (expanding references)
  • Full-text search
  • Dependency management
  • Event tracking
  • Import/export (JSONL)

Installation

import { QuarryAPIImpl } from '@stoneforge/quarry';
import { createStorageBackend } from '@stoneforge/storage';

const backend = await createStorageBackend({ dbPath: '.stoneforge/stoneforge.db' });
const api = new QuarryAPIImpl(backend);

Core CRUD Operations

get()

Retrieves a single element by ID.
id
ElementId
required
Element ID
options
GetOptions
element
T | null
The element or null if not found
// Simple get
const task = await api.get<Task>(taskId);

// Get with hydration
const hydratedTask = await api.get<HydratedTask>(taskId, {
  hydrate: { dependencies: true, blockers: true }
});
console.log(hydratedTask.blockers); // Array of blocking tasks

list()

Lists elements matching filter criteria (unpaginated).
filter
ElementFilter
elements
T[]
Array of matching elements
// Get all open tasks
const openTasks = await api.list<Task>({
  type: 'task',
  status: 'open',
});

// Get all tasks with 'bug' tag
const bugs = await api.list<Task>({
  type: 'task',
  tags: ['bug'],
});

listPaginated()

Lists elements with pagination support.
filter
ElementFilter
Same as list() plus pagination fields:
result
ListResult<T>
const result = await api.listPaginated<Task>({
  type: 'task',
  status: ['open', 'in_progress'],
  orderBy: 'priority',
  orderDir: 'desc',
  limit: 20,
  offset: 0,
});

console.log(`Page 1 of ${Math.ceil(result.total / result.limit)}`);
console.log(`Showing ${result.items.length} of ${result.total} tasks`);

create()

Creates a new element.
input
Record<string, unknown> & { type: ElementType; createdBy: EntityId }
required
Element data (should be created using factory functions like createTask, createDocument, etc.)
element
T
The created element
import { createTask, createDocument, ContentType } from '@stoneforge/core';

// Create a task
const taskData = await createTask({
  title: 'Implement feature X',
  status: 'open',
  priority: 3,
  createdBy: operatorId,
  tags: ['feature'],
});
const task = await api.create<Task>(taskData);

// Create a document
const docData = await createDocument({
  contentType: ContentType.MARKDOWN,
  content: '# Feature X\n\nImplementation notes...',
  createdBy: operatorId,
});
const doc = await api.create<Document>(docData);

update()

Updates an existing element.
id
ElementId
required
Element ID
updates
Partial<T>
required
Fields to update (partial)
options
UpdateOptions
element
T
The updated element
// Update task status
const updated = await api.update<Task>(taskId, {
  status: 'in_progress',
  assignee: workerId,
});

// Update with optimistic locking
const task = await api.get<Task>(taskId);
const updated = await api.update<Task>(taskId, 
  { priority: 5 },
  { expectedUpdatedAt: task.updatedAt }
);

delete() / softDelete()

Deletes an element (soft delete creates tombstone).
id
ElementId
required
Element ID
options
DeleteOptions
success
boolean
True if element was deleted
// Soft delete (creates tombstone)
await api.delete(taskId);

// Hard delete (permanent)
await api.delete(taskId, { hard: true });

// Soft delete with actor
await api.softDelete(taskId, operatorId);

Task-Specific Methods

getTasksForPlan()

Retrieves all tasks belonging to a plan.
planId
ElementId
required
Plan element ID
hydrate
HydrationOptions
Hydration options
tasks
Task[]
Array of tasks in the plan
const tasks = await api.getTasksForPlan(planId, {
  hydrate: { dependencies: true }
});

getReadyTasks()

Retrieves tasks that are ready to work on (open, not blocked).
hydrate
HydrationOptions
Hydration options
tasks
Task[]
Array of ready tasks
const readyTasks = await api.getReadyTasks();

getBlockedTasks()

Retrieves tasks that are blocked by dependencies.
blockedTasks
BlockedTask[]
Array of blocked tasks with blocker info
const blocked = await api.getBlockedTasks();
blocked.forEach(({ task, blockers }) => {
  console.log(`${task.title} is blocked by:`);
  blockers.forEach(b => console.log(`  - ${b.reason}`));
});

Dependency Management

addDependency()

Adds a dependency between elements.
input
DependencyInput
required
dependency
Dependency
The created dependency
// Task B blocks Task A (A cannot start until B is done)
await api.addDependency({
  blockedId: taskAId,
  blockerId: taskBId,
  type: 'blocks',
  createdBy: operatorId,
});

removeDependency()

Removes a dependency.
blockedId
ElementId
required
Blocked element ID
blockerId
ElementId
required
Blocker element ID
type
DependencyType
required
Dependency type
actor
EntityId
required
Entity performing removal
success
boolean
True if dependency was removed
await api.removeDependency(taskAId, taskBId, 'blocks', operatorId);

getDependencies()

Gets dependencies from an element.
blockedId
ElementId
required
Blocked element ID
type
DependencyType
Optional filter by type
dependencies
Dependency[]
Array of dependencies
const blockingDeps = await api.getDependencies(taskId, 'blocks');

getDependents()

Gets elements that depend on an element (reverse lookup).
blockerId
ElementId
required
Blocker element ID
type
DependencyType
Optional filter by type
dependents
Dependency[]
Array of dependent relationships
const dependents = await api.getDependents(taskId, 'blocks');

searchDocuments()

Searches documents using FTS5 full-text search.
query
string
required
Search query
options
FTSSearchOptions
result
FTSSearchResult
const results = await api.searchDocuments('authentication', {
  contentType: ContentType.MARKDOWN,
  tags: ['docs'],
  limit: 10,
});

results.documents.forEach(doc => {
  console.log(`${doc.title}: ${doc.content.substring(0, 100)}...`);
});

Import/Export

exportElements()

Exports elements to JSONL format.
options
ExportOptions
required
result
ExportResult
Export statistics
const result = await api.exportElements({
  outputDir: '.stoneforge',
  full: true,
  includeEphemeral: false,
});

console.log(`Exported ${result.elementsExported} elements`);

importElements()

Imports elements from JSONL format.
options
ImportOptions
required
result
ImportResult
const result = await api.importElements({
  inputDir: '.stoneforge',
  dryRun: true,
});

console.log(`Would import ${result.elementsImported} elements`);
if (result.conflicts.length > 0) {
  console.log(`Found ${result.conflicts.length} conflicts`);
}

Build docs developers (and LLMs) love