Reference / @silo Ai
@silo-ai/silo
Functions
resolveWorkspace
Resolve a Git worktree to its Silo database.
export function resolveWorkspace(cwd?: string): Workspace;
Remarks
Repository-local state is stored in .git/silo.json under the common Git directory.
Auto selection uses origin when present and otherwise uses the persisted detached UUID.
Parameters
cwd: Directory inside the Git worktree to resolve. Defaults to the current directory.
Returns
The Git root, workspace identity, origin marker, and local database path.
Classes
SiloDatabase
export class SiloDatabase {
readonly workspace: Workspace;
private readonly database;
private readonly db;
private readonly releaseWriterLock;
private closed;
private transactionActive;
private observedDataVersion;
private observedJournalSequence;
private constructor();
static open(workspace: Workspace, writable?: boolean, allowSyncLock?: boolean): SiloDatabase;
/**
* Create a local database with its schema and optional default read surfaces.
* Queries are installed before reports so report scripts can execute them.
* Invalid queries or reports roll back creation and remove the new database.
*/
static createWithSchema(workspace: Workspace, schema: LogicalSchema, reports?: ReportDefinition[], queries?: SavedQueryDefinition[]): SiloDatabase;
close(): void;
getMetadata(): DatabaseMetadata;
getSchema(): LogicalSchema;
/**
* Read SQLite's data-version counter for this connection.
*
* @returns The current `PRAGMA data_version` value.
* @remarks The counter detects commits made by other connections but does not attribute them
* to a resource. `readMutationJournal()` includes this value and compares it with the previous
* read for the same long-lived `SiloDatabase` instance.
*/
getDataVersion(): number;
/**
* Read committed local mutation entries after a database-local sequence cursor.
*
* @param afterSequence The last sequence already consumed. Use `0` to read from the beginning
* of the retained window.
* @param limit The requested page size. The response is always capped at
* `MUTATION_JOURNAL_READ_LIMIT`.
* @returns Journal entries, retention bounds, and fallback state for the observing connection.
* @throws {SiloError} If the cursor or limit is not a valid non-negative or positive safe
* integer, respectively.
* @remarks Reuse the same `SiloDatabase` instance for polling. A data-version advance without
* a matching journal window sets `unknown_change`, which means the consumer must invalidate
* globally rather than attributing the change to the returned resource tags.
*/
readMutationJournal(afterSequence?: number, limit?: number): MutationJournalRead;
private readSavedQuery;
getSavedQuery(name: string): StoredQuery;
listSavedQueries(): SavedQuerySummary[];
putSavedQuery(input: unknown): StoredQuery;
private installTemplateQueries;
private putSavedQueryInTransaction;
runSavedQuery(name: string, input: Record<string, unknown> | unknown[]): QueryResult;
deleteSavedQuery(name: string): void;
private readReport;
getReport(slug: string): StoredReport;
listReports(): ReportSummary[];
private installTemplateReports;
private putReportInTransaction;
/**
* Validate and run a report definition without persisting report state.
*
* @param input The candidate report definition.
* @returns The parsed definition after its script or legacy queries succeed.
* @throws {SiloError} If the definition or execution fails.
* @remarks This does not save a rendered snapshot, update refresh metadata, or create mutation
* journal and synchronization entries. A trusted script can still cause external side effects.
*/
validateReport(input: unknown): ReportDefinition;
putReport(input: unknown): StoredReport;
refreshReport(slug: string): StoredReport;
deleteReport(slug: string): void;
getSyncState(): SyncState | undefined;
configureSync(remoteUrl: string, databaseId?: string): SyncState;
pendingTransactions(): PendingTransaction[];
setSyncConflict(transactionId: string | null): void;
markSynchronized(generation: string, etag: string): void;
backupCanonical(path: string, generation: string): Promise<void>;
backupRecovery(path: string): Promise<void>;
rebasePending(pending: PendingTransaction[], generation: string, etag: string, discardTransactionId?: string): string | undefined;
private recordMutationJournal;
private assertTransactionInactive;
private runMutation;
private mutateRows;
private prepareSchemaMutation;
private recordSchemaMutation;
private replaceSchema;
createTable(input: unknown): TableDefinition;
addRelation(input: unknown): RelationDefinition;
getRelation(tableName: string, name: string): RelationDefinition;
listRelations(): RelationDefinition[];
removeRelation(tableName: string, name: string): void;
importTemplate(name: string, template: TemplateSchema): LogicalSchema;
alterTable(name: string, input: unknown): TableDefinition;
dropTable(name: string): void;
private verify;
table(name: string): TableDefinition;
/**
* Run several validated row mutations as one atomic database transaction.
*
* @param callback A synchronous callback that uses only the scoped user-table methods provided to
* it. The callback may read and mutate multiple user tables, and its return value is returned
* unchanged. Direct mutable `SiloDatabase` methods are rejected while the callback is active.
* @param options Optional structured operation metadata for the mutation journal and, when
* synchronization is configured, the corresponding outbox transaction.
* @returns The callback's return value after the transaction commits.
* @throws {SiloError} If validation, a constraint, an optimistic-revision check, or a direct
* mutable API call fails. Every mutation and its journal/synchronization metadata are rolled
* back together on failure.
* @remarks A successful callback creates one journal entry and at most one synchronization
* outbox entry. The generated operation metadata includes `command: 'row.batch'` by default,
* the touched `tables`, and compact `mutations` metadata. A supplied `operation.command` is
* preserved. Use `getRow()` or `listRows()` for reads within the transaction and
* `_expected_revision` in `updateRow` requests for compare-and-set updates. An error thrown by
* the callback is rethrown unchanged after the transaction rolls back.
* @example
* ```ts
* database.transaction(
* (transaction) => {
* const [change] = transaction.addRows('changes', { kind: 'completed' })
* transaction.updateRow('summaries', summaryId, {
* state: 'complete',
* _expected_revision: summaryRevision,
* })
* return change
* },
* { operation: { command: 'change.apply' } },
* )
* ```
*/
transaction<T>(callback: (transaction: SiloTransaction) => T, options?: SiloTransactionOptions): T;
addRows(name: string, input: unknown, upsert?: boolean): Record<string, unknown>[];
private addRowsInTransaction;
private readPersistedRow;
private findPersistedRow;
private prepareRow;
private keyWhere;
getRow(name: string, key: unknown): Record<string, unknown>;
listRows(name: string, limit: number, offset: number): Record<string, unknown>[];
private renderRow;
updateRow(name: string, key: unknown, input: unknown): number;
private updateRowInTransaction;
deleteRow(name: string, key: unknown): number;
private deleteRowInTransaction;
query(sql: string): {
columns: string[];
rows: unknown[][];
};
ddl(): string;
}
SiloError
export class SiloError extends Error {
readonly exitCode: number;
readonly code: string;
readonly path: string;
constructor(exitCode: number, code: string, message: string, path?: string);
}
Constants
MUTATION_JOURNAL_READ_LIMIT
Maximum number of local mutation entries returned by one journal read.
export const MUTATION_JOURNAL_READ_LIMIT = 100;
🔍 MUTATION_JOURNAL_READ_LIMIT on GitHub
MUTATION_JOURNAL_RETENTION
Maximum number of newest local mutation entries retained per database.
export const MUTATION_JOURNAL_RETENTION = 1000;
🔍 MUTATION_JOURNAL_RETENTION on GitHub
Types
CheckDefinition
interface CheckDefinition {
name?: string;
expression: string;
comment?: string;
}
ColumnDefinition
interface ColumnDefinition {
name: string;
type: string;
type_options?: Record<string, unknown>;
nullable?: boolean;
default?: DefaultValue;
comment: string;
collate?: string;
generated?: {
expression: string;
storage?: 'VIRTUAL' | 'STORED';
};
}
DatabaseMetadata
interface DatabaseMetadata {
identity: string;
original_origin: string;
created_at: string;
updated_at: string;
format_version: number;
tool_version: string;
}
DefaultValue
interface DefaultValue {
literal?: Literal;
expression?: string;
}
ForeignKeyDefinition
interface ForeignKeyDefinition {
columns: string[];
references: {
table: string;
columns: string[];
};
on_update?: string;
on_delete?: string;
deferrable?: boolean;
initially_deferred?: boolean;
}
🔍 ForeignKeyDefinition on GitHub
IndexDefinition
interface IndexDefinition {
name?: string;
columns: IndexPart[];
unique?: boolean;
where?: string;
comment?: string;
}
IndexPart
interface IndexPart {
column?: string;
expression?: string;
direction?: 'ASC' | 'DESC';
collate?: string;
}
InlineReportQueryDefinition
interface InlineReportQueryDefinition extends ReportQueryBase {
sql: string;
}
🔍 InlineReportQueryDefinition on GitHub
LegacyReportDefinition
interface LegacyReportDefinition {
slug: string;
title: string;
markdown: string;
queries: ReportQueryDefinition[];
}
Deprecated. Use {@link ScriptedReportDefinition}.
🔍 LegacyReportDefinition on GitHub
Literal
type Literal = string | number | boolean | null | Literal[] | {
[key: string]: Literal;
};
LogicalSchema
interface LogicalSchema {
format_version: 1;
registry_version: 1;
revision: number;
tables: TableDefinition[];
relations?: RelationDefinition[];
template_imports?: Array<{
name: string;
imported_at: string;
}>;
agent_instructions?: Array<{
source: string;
content: string;
}>;
}
MutationJournalEntry
One committed, attributed mutation retained by the local invalidation journal.
export interface MutationJournalEntry {
sequence: number;
transaction_id: string;
committed_at: string;
operation: Record<string, unknown>;
resource_tags: string[];
}
Properties
sequenceDatabase-local monotonic sequence assigned to this journal entry.transaction_idUnique transaction identity, shared with synchronization state when configured.committed_atISO timestamp recorded at the mutation's commit boundary.operationStructured operation context; this metadata is not a replay command.resource_tagsOpaque consumer resource tags;*means that every resource may be stale.
🔍 MutationJournalEntry on GitHub
MutationJournalRead
A bounded journal page and observer state returned by readMutationJournal.
export interface MutationJournalRead {
entries: MutationJournalEntry[];
oldest_sequence: number | null;
latest_sequence: number;
next_sequence: number;
full_refresh_required: boolean;
data_version: number;
unknown_change: boolean;
}
Properties
entriesEntries after the requested cursor, capped by the journal read limit.oldest_sequenceOldest sequence still retained, ornullwhen the journal is empty.latest_sequenceLatest sequence currently retained.next_sequenceCursor for the next page, or the latest sequence after a full refresh.full_refresh_requiredThe requested cursor is outside the retained window or the journal is unavailable.data_versionCurrent SQLite data version observed on this connection.unknown_changeA data-version advance without a matching journal window requires global invalidation.
🔍 MutationJournalRead on GitHub
PendingTransaction
interface PendingTransaction {
sequence: number;
transaction_id: string;
kind: 'data' | 'schema';
base_generation: string | null;
schema_revision: number;
operation: Record<string, unknown>;
changeset: Uint8Array;
created_at: string;
}
🔍 PendingTransaction on GitHub
PolicyDefinition
interface PolicyDefinition {
type: 'generated_identity' | 'timestamps' | 'optimistic_revision' | 'immutable_rows' | 'immutable_columns' | 'append_only' | 'natural_key_upsert';
[key: string]: unknown;
}
QueryParameterStyle
type QueryParameterStyle = 'named' | 'positional';
🔍 QueryParameterStyle on GitHub
QueryResult
interface QueryResult {
columns: string[];
rows: unknown[][];
truncated: boolean;
}
RelationDefinition
interface RelationDefinition {
from: RelationEndpoint & {
name: string;
};
to: RelationEndpoint;
inverse_name?: string;
comment: string;
inverse_comment?: string;
}
🔍 RelationDefinition on GitHub
RelationEndpoint
interface RelationEndpoint {
table: string;
columns: string[];
}
ReportDefinition
type ReportDefinition = ScriptedReportDefinition | LegacyReportDefinition;
ReportQueryBase
interface ReportQueryBase {
name: string;
empty_markdown?: string;
}
ReportQueryDefinition
type ReportQueryDefinition = InlineReportQueryDefinition | SavedReportQueryDefinition;
🔍 ReportQueryDefinition on GitHub
ReportSummary
interface ReportSummary {
slug: string;
title: string;
refreshed_at: string;
last_refresh_attempt_at: string;
last_refresh_error: string | null;
}
SavedQueryDefinition
interface SavedQueryDefinition {
name: string;
description: string;
sql: string;
parameter_style: QueryParameterStyle;
parameters: SavedQueryParameter[];
}
🔍 SavedQueryDefinition on GitHub
SavedQueryParameter
interface SavedQueryParameter {
name: string;
type: string;
type_options?: Record<string, unknown>;
description: string;
default?: unknown;
}
🔍 SavedQueryParameter on GitHub
SavedQuerySummary
interface SavedQuerySummary {
name: string;
description: string;
parameter_style: QueryParameterStyle;
parameters: number;
updated_at: string;
}
SavedReportQueryDefinition
interface SavedReportQueryDefinition extends ReportQueryBase {
saved_query: string;
parameters?: Record<string, unknown> | unknown[];
}
🔍 SavedReportQueryDefinition on GitHub
ScriptedReportDefinition
interface ScriptedReportDefinition {
slug: string;
title: string;
script: string;
}
Properties
scriptA synchronous JavaScript function body. The script receivessilo,markdown, andrequirearguments and must return the rendered Markdown string.
🔍 ScriptedReportDefinition on GitHub
SiloTransaction
Validated user-table methods available inside SiloDatabase.transaction().
The callback is synchronous and must use this scoped surface for every read or write that belongs to the transaction. It does not expose SQLite handles, SQL execution, or Silo's internal catalog tables.
export interface SiloTransaction {
getRow(name: string, key: unknown): Record<string, unknown>;
listRows(name: string, limit: number, offset: number): Record<string, unknown>[];
addRows(name: string, input: unknown, upsert?: boolean): Record<string, unknown>[];
updateRow(name: string, key: unknown, input: unknown): number;
deleteRow(name: string, key: unknown): number;
}
Properties
getRowRead one keyed user row from the transaction's current snapshot.listRowsList user rows from the transaction's current snapshot.addRowsInsert one row or an array of rows into a user table.updateRowUpdate one keyed row, optionally using_expected_revisionfor a CAS.deleteRowDelete one keyed row from a user table.
SiloTransactionOptions
Options for one atomic multi-table row mutation transaction.
export interface SiloTransactionOptions {
operation?: Record<string, unknown>;
}
Properties
operationStructured context stored in the mutation journal and synchronization outbox. Silo adds the actual touchedtablesand compactmutationsfields, replacing any values with those names.
🔍 SiloTransactionOptions on GitHub
StoredQuery
interface StoredQuery extends SavedQueryDefinition {
created_at: string;
updated_at: string;
}
StoredReport
type StoredReport = ReportDefinition & StoredReportMetadata;
StoredReportMetadata
interface StoredReportMetadata {
rendered_markdown: string;
created_at: string;
updated_at: string;
refreshed_at: string;
last_refresh_attempt_at: string;
last_refresh_error: string | null;
}
🔍 StoredReportMetadata on GitHub
SyncState
interface SyncState {
database_id: string;
remote_url: string;
base_generation: string | null;
base_etag: string | null;
conflict_transaction_id: string | null;
}
TableDefinition
interface TableDefinition {
name: string;
comment: string;
columns: ColumnDefinition[];
primary_key?: string[];
foreign_keys?: ForeignKeyDefinition[];
unique_constraints?: Array<{
name?: string;
columns: string[];
}>;
indexes?: IndexDefinition[];
checks?: CheckDefinition[];
policies?: PolicyDefinition[];
strict?: boolean;
without_rowid?: boolean;
}
TemplateSchema
interface TemplateSchema {
format_version?: 1;
agent_instructions?: string;
tables: TableDefinition[];
relations?: RelationDefinition[];
queries?: SavedQueryDefinition[];
reports?: ReportDefinition[];
}
Workspace
Resolved Git identity and local database path used to open a Silo database.
export interface Workspace {
root: string;
identity: string;
origin: string;
databasePath: string;
selection?: WorkspaceSelection;
}
Properties
originConfigured Git origin, or adetached:<uuid>marker before an origin exists.selectionRepository-local selection used to resolve this workspace.
WorkspaceSelection
Repository-local rule for selecting a detached or Git-remote workspace identity.
type WorkspaceSelection = {
kind: 'auto';
} | {
kind: 'detached';
} | {
kind: 'remote';
name: string;
};