@silo-ai/silo
v0.1.17
Published
> Give agents durable, strictly typed SQLite state scoped to a Git repository without hiding SQLite’s constraints or query model.
Readme
Silo
Give agents durable, strictly typed SQLite state scoped to a Git repository without hiding SQLite’s constraints or query model.
Silo resolves the current repository to one local database. Repository-local selection state lives in .git/silo.json: automatic selection uses the normalized origin URL when available and a persistent local UUID otherwise. An authoritative logical schema records semantic types, comments, constraints, indexes, and policies; SQLite STRICT tables, checks, and triggers enforce the physical contract.
Install
pnpm add --global @silo-ai/siloSilo requires Node.js 24.10.0 or newer with SQLite 3.37.0 or newer, and a Git worktree.
Create the first table
Define a table through JSON on stdin:
silo table create <<'JSON'
{
"name": "issues",
"comment": "One actionable repository issue; read before planning work and update as its disposition changes.",
"columns": [
{
"name": "id",
"type": "text/uuid",
"nullable": false,
"comment": "Stable Silo-generated issue identifier."
},
{
"name": "title",
"type": "text",
"nullable": false,
"comment": "Short actionable issue summary."
}
],
"primary_key": ["id"],
"policies": [
{ "type": "generated_identity", "column": "id", "strategy": "uuid" }
]
}
JSONThe first schema mutation creates the database. Inspect the resulting logical schema with silo schema show, then use silo row add issues to write rows.
Run silo --help and silo <group> <command> --help for the authoritative command syntax and examples. The self-contained skills/silo/ package includes both agent operating practices and the exact JSON request contracts it references.
To make the packaged guidance discoverable without installing a separate agent skill, add this rule to your global AGENTS.md:
- When told to “use Silo” or do something with Silo, run
silo skilland follow its instructions. Read any referenced task guide or JSON Schema withsilo skill <relative-path>.
silo skill prints the main skill. Its relative links can be read from any directory, for example with silo skill tasks/create-table.md or silo skill schemas/row-write.schema.json.
Import a schema template
Import the bundled agent-first task schema into the current repository:
silo schema import tasksTemplate imports are additive. Repeat schema import for other templates whose table names and default report slugs do not conflict. Each import copies its tables and attributed agent instructions into the local authoritative schema and saves its declared default reports; later template edits do not change the local copy.
Synchronize explicitly
Synchronization is optional. With Litestream 0.5.12 or newer installed and standard AWS credentials available, connect the local database to an S3-compatible remote:
silo sync init s3://my-bucket/silo/project
silo pushOn another machine, run the same sync init command to restore the remote database. Thereafter, use silo pull before work and silo push when the local changes are ready to share. Silo merges non-conflicting row transactions and stops on conflicts; it never chooses a last writer automatically.
See Synchronize a database for setup and recovery, and Synchronization model for durability and concurrency guarantees.
Save a typed query
Turn a repeated read into a repository-defined command with semantic parameter validation:
silo query put <<'JSON'
{
"name": "blocked-work",
"description": "Tasks waiting on an incomplete dependency for one lifecycle state.",
"sql": "SELECT task.id, task.title, task.state, task.priority, task.rank, dependency.title AS dependency, dependency.state AS dependency_state FROM task_dependencies AS edge JOIN tasks AS task ON task.id = edge.task_id JOIN tasks AS dependency ON dependency.id = edge.depends_on_task_id WHERE task.state = :state AND dependency.state <> 'completed' ORDER BY CASE task.priority WHEN 'high' THEN 0 WHEN 'normal' THEN 1 WHEN 'low' THEN 2 ELSE 3 END, task.rank, task.updated_at, task.id, dependency.id",
"parameters": [
{
"name": "state",
"type": "text/enum",
"type_options": {
"values": ["proposed", "approved", "in_progress", "completed", "rejected", "canceled"]
},
"description": "Task lifecycle state to inspect."
}
]
}
JSON
silo query blocked-work --state approvedNamed parameters become CLI options. Positional definitions use declared order and SQLite ? or ?N placeholders. silo query <name> --help shows the stored types, defaults, and descriptions.
Saved query definitions synchronize explicitly with other durable Silo state; execution remains read-only and does not create a pending transaction. Report scripts can call a saved query with typed bindings, so one read can serve CLI callers and refreshable briefs. See Run saved queries for parameter styles, management commands, and safety boundaries.
Publish a refreshable report
Reports run trusted synchronous JavaScript and store the last successful Markdown rendering. Reuse the blocked-work query above:
silo report put <<'JSON'
{
"slug": "execution-brief",
"title": "Project execution brief",
"script": "const blocked = silo.query('blocked-work', { state: 'approved' })\n\nreturn [\n '# Project execution brief',\n '## Approved work waiting on dependencies',\n blocked.rows.length ? markdown.table(blocked) : '_No approved work is waiting on dependencies._',\n].join('\\n\\n')"
}
JSONreport put runs the script before atomically publishing the definition and its initial rendering. Report scripts are trusted code with the Silo process's operating-system authority. They must return Markdown synchronously.
Open the packaged viewer for a human reader:
silo report open execution-briefThe command starts a foreground HTTP server on a random loopback port and opens the default browser. The server-rendered page shows the last successful result immediately, refreshes after opening and whenever the page regains focus, and leaves stale output visible if a refresh fails. Interrupt the command to stop the server.
The viewer renders GitHub-flavored Markdown without executing HTML returned by the script. Refresh requests remain local and require the page's origin and per-server token; the server is not intended for remote hosting. Opening or refocusing a report executes its trusted script.
See Publish a refreshable report for the complete authoring, viewer, refresh, synchronization, and recovery workflow.
Boundaries
The active database remains local and synchronization is always explicit: Silo has no background daemon, automatic push or pull, branches, or user-visible history. Saved-query and report mutations join the same pending transaction stream as row mutations and are shared only on silo push. Silo automatically moves an unsynchronized detached database when origin is first added and the destination is empty; other identity changes require an explicit silo switch --move. Silo does not accept raw SQL mutations, provide audit history, or claim that CLI-only validation survives direct external writes. Its bounded mutation journal is operational invalidation metadata for a local consumer, not an audit trail. Raw and saved SQL run through read-only boundaries. Report scripts are trusted local code and may use Node APIs outside those boundaries. Reports do not provide schedules, remote hosting, or an authentication boundary.
Databases use WAL with a five-second busy timeout and synchronous=NORMAL. Keep active database files on local storage rather than network or cloud-synchronized folders.
