All guides

SQLite CLI for AI agents: tables become verbs with JSON output

The sqlite3 shell is built for a person: free-form SQL in, a text table out, and no exit code that tells a program what went wrong. declick compiles a SQLite file into a CLI built for an agent. Every table and view becomes list-<table>, get-<table>, insert-<table>, update-<table> and delete-<table> verbs, a read-only query verb with --sql and repeatable --param covers the rest, and every call returns the same JSON envelope with the same five exit codes as an API or an MCP server compiled by the same tool.

source sqlite:<path> or data.dbverbs per table 5plus querynode >=24

Written by Wes Sander, who built declick. Updated 2026-09-04. The engine table and the output contract on this page are the ones in the README for declick 0.6.2.

How do I turn a SQLite database into a CLI?

Point declick add at the file. A path ending in .db routes to the sqlite engine on its own, and the sqlite: prefix makes it explicit for any other name. declick introspects the schema, writes one manifest with the table verbs and the query verb, a launcher, and a SKILL.md into every agent skills directory on the machine. The engine is built in, so there is no native module to compile and no runtime dependency to install.

$ declick add sqlite:./crm.db --name crm
$ declick describe crm
describe lists every table's five verbs plus query, under 2,000 charactersexit 0

How does an agent read rows without flooding its context?

It trims on the command line instead of in SQL. --where k=v filters a list before anything else and takes =, !=, ~re for a case-insensitive regex, >, >=, <, <= and =* for present and not null. --fields a,b keeps named columns, --limit N caps the rows at 50 by default, and --max-bytes N caps data at 8,192 bytes, reporting meta.capped with a hint when it does. meta.where reports how many rows matched out of how many, so the agent knows what it did not see. --cache <s> answers a read from a stored response younger than that many seconds.

$ declick run crm list-customers --where status=open --fields id,name,email --limit 10
$ declick run crm get-customers 7
$ declick run crm query --sql "select count(*) as n from tickets where opened > ?" --param 2026-09-01
filter, project and cap a list; one row by primary key; a read-only query with one bound parameterexit 0

How are writes kept safe?

Every write verb previews. insert, update and delete accept --dry-run, print what they would do, set meta.dryRun: true, and change nothing. The manifest marks each verb mutating: true or false, and when DASHCLAW_API_KEY is set every mutating call goes through the DashClaw guard first, with the decision recorded in meta.governance and exit 3 on a block. A local policy.json with allow, warn and block rules works with no service at all. Every invocation writes one line to ~/.declick/audit.jsonl, and declick audit --sum adds it up by adapter.

$ declick run crm update-tickets 12 --status closed --dry-run
$ declick run crm delete-tickets 12
$ declick audit --adapter crm --failed
preview, then the real call, then the log of what ran and what governance decidedexit 0

Can one verb run over many rows?

Yes. --each file runs a verb once per item in a file of inputs, or from stdin with -, in order, and returns one envelope: data holds one entry per item and meta carries count, failed and each: true. Exit 0 when every item is ok, otherwise the exit of the first that was not. Each item is guarded and shaped on its own, a failing item does not stop the rest, and --dry-run previews every item.