Skip to content

Commit b1cccee

Browse files
Add bounded native SQLite inspection across model tools, CLI and MCP
1 parent 3dbb37b commit b1cccee

34 files changed

Lines changed: 1532 additions & 40 deletions

‎CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
existing profiles, without deleting data or changing existing parent-directory
1313
permissions. Unsafe profile leaves and lock files are rejected. Notifications
1414
keep full text contrast throughout their entrance animation.
15+
- Native SQLite tools, CLI and MCP queries replace the Python built-in reader,
16+
with parameter binding, live WAL support, confined paths, denied SQL writes
17+
and bounded/cancellable results. Bundled SQLite is updated to 3.53.2, including
18+
its WAL-reset corruption fix.
19+
- Required task inspection recognizes successful native database reads. Small
20+
model contexts can use a shorter, enforced response budget while retaining
21+
required input; requests that still cannot fit fail before contacting the model.
1522
- Native goals preserve milestone results, pause and resume, require recorded
1623
inspection/verification for the default checklist, and stop on failed checks.
1724
Goal tasks appear live in the conversation; results and progress are accessible

‎Cargo.lock‎

Lines changed: 11 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ workflows, [managed background processes](docs/NATIVE_BACKGROUND.md), and
1919
[reviewed lifecycle commands](docs/NATIVE_HOOKS.md),
2020
[project inspection and diagnostics](docs/NATIVE_INSPECTION.md),
2121
[project and task notes](docs/NATIVE_MEMORY.md),
22+
[native SQLite inspection](docs/NATIVE_SQLITE.md),
2223
[approved MCP stdio and HTTP tools](docs/NATIVE_MCP.md), a
2324
[native MCP stdio server](docs/NATIVE_MCP.md#connect-another-coding-tool-to-shadowcode), and a
2425
[native CLI](docs/NATIVE_CLI.md) that shares the active desktop engine or runs

‎SECURITY.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ Review applies only current unstaged hunks. A changed diff causes a conflict,
6363
rather than applying a stale client patch. File restores can overwrite later
6464
edits; review the checkpoint and retain independent version-control backups.
6565

66+
[Native SQLite inspection](docs/NATIVE_SQLITE.md) opens existing project
67+
databases read-only and authorizes only queries returning rows. SQL writes,
68+
ATTACH, configuration PRAGMAs and extension loading are denied; a small explicit
69+
allowlist supports read-only schema PRAGMAs. SQLite may maintain its WAL
70+
coordination sidecars. Directory capabilities confine database/sidecar paths;
71+
query work, concurrent readers and output are bounded. Cancellation interrupts
72+
SQLite and releases its connection; an OS filesystem stall may delay return.
73+
6674
## Secrets and transcript content
6775

6876
Keys belong in `~/.config/shadow-agent/secrets.env` with mode 600, or environment

‎docs/NATIVE_CLI.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ uses an exact task in the current project. `--json` exposes content hashes;
4141
string clearing it. See [native memory](NATIVE_MEMORY.md) for persistence,
4242
legacy notes, continuation, branching and export.
4343

44+
`sqlite PATH [SQL]` lists tables or reads an existing project database.
45+
`--params '[100]'` binds positional placeholders; `--limit 50` and
46+
`--timeout-ms 2000` reduce result/work limits. Check `truncated` in the response.
47+
See [SQLite inspection](NATIVE_SQLITE.md) for types, limits and WAL behavior.
48+
4449
`hooks` lists project lifecycle command definitions. Review the command and its
4550
hash, then use `hooks --enable PATH --hash HASH` to enable those exact contents
4651
or `hooks --disable PATH` to remove the registration. Hooks remain inactive in

‎docs/NATIVE_DESKTOP.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ the CLI/MCP server, with bounded continuation context, independent branch copies
6262
and note exports. Approval decisions carry the displayed prompt's conversation
6363
ID so a navigation change cannot send the decision to another task.
6464

65+
[Native SQLite inspection](NATIVE_SQLITE.md) gives models read-only table/query
66+
tools, also available through the CLI and MCP server, with parameter binding,
67+
live WAL support, cancellation and result limits.
68+
6569
Project [lifecycle commands](NATIVE_HOOKS.md) can be reviewed and enabled in
6670
Settings → Hooks or through the same native CLI. Their command gates and
6771
completion checks run inside the native task lifecycle without Python callbacks.

‎docs/NATIVE_MCP.md‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
MCP remains an open [native release gate](NATIVE_MIGRATION.md). The Rust stdio and Streamable HTTP
44
clients now connect to native Settings, CLI registration, project activation,
55
and individually approved agent tool calls. The native stdio server now exposes
6-
tasks, goals, reviews, memory and checkpoints to external clients. Built-in SQLite
7-
compatibility, the remaining server features, and broader interoperability/real-model
6+
tasks, goals, reviews, memory, SQLite inspection and checkpoints to external clients.
7+
The remaining server features and broader interoperability/real-model
88
verification are still being migrated. Neither direction launches Python.
99

1010
## Connect another coding tool to ShadowCode
@@ -46,7 +46,7 @@ client's task or all pending actions. Denying an owned approval does not require
4646
the approval flag. The client is responsible for obtaining the user's agreement
4747
to the displayed action before submitting approval.
4848

49-
The current server exposes sixteen tools:
49+
The current server exposes seventeen tools:
5050

5151
- `shadow_status`, `shadow_models`, `shadow_sessions`, `shadow_review`, and
5252
`shadow_tools` inspect the selected project and native capabilities.
@@ -57,6 +57,9 @@ The current server exposes sixteen tools:
5757
- `shadow_memory` reads, appends or replaces project/task notes. Task scope uses
5858
an exact existing task ID in this project; replacement requires the current
5959
content hash. Changes require write access. See [native memory](NATIVE_MEMORY.md).
60+
- `shadow_sqlite` lists tables or runs one bounded read-only query against an
61+
existing project database. It supports bound parameters and live WAL data;
62+
SQLite may maintain coordination sidecars. See [SQLite inspection](NATIVE_SQLITE.md).
6063
- `shadow_goal` creates, lists, inspects, advances or abandons durable goals.
6164
Creating or advancing a goal here does not start an agent automatically.
6265
- `shadow_run` creates a fresh conversation and returns its job ID. `shadow_jobs`

‎docs/NATIVE_MIGRATION.md‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,9 @@ transports, inert Settings/CLI registration, explicit project/content activation
153153
discovery, individually approved calls, and task-owned process/stream cleanup.
154154
HTTP uses explicit credential references, prevents redirects and automatic call
155155
retries, and supports modern and legacy Streamable HTTP negotiation. The native
156-
stdio server exposes sixteen tools, four resources and two prompts through
156+
stdio server exposes seventeen tools, four resources and two prompts through
157157
the shared engine, with a fixed project, reduced per-task permissions, explicit
158-
approval delegation and connection-owned jobs. Built-in SQLite compatibility,
159-
HTTP serving and broader interoperability/real-model
158+
approval delegation and connection-owned jobs. HTTP serving and broader interoperability/real-model
160159
verification remain open requirements. Private engine-side ownership now cancels
161160
MCP jobs after gateway SIGKILL, including unread submission replies, queued tasks
162161
and active command children; unrelated work continues.
@@ -172,6 +171,11 @@ notes, legacy-file preservation, atomic edits with stale-hash rejection, bounded
172171
continuation context, independent branch archives and complete note exports.
173172
The desktop, CLI and MCP server share this service.
174173

174+
[Native SQLite inspection](NATIVE_SQLITE.md) replaces the Python built-in tools
175+
with confined, bounded read-only queries, typed results, parameter binding,
176+
live WAL coordination and cancellation. Model tools, CLI and MCP share the
177+
reader. The history store also uses the updated bundled SQLite 3.53.2 library.
178+
175179
AppImage extraction now uses a source-pinned runtime patch with private
176180
per-invocation directories, signal forwarding, and checked cleanup. A dedicated
177181
regression exercises concurrent owners/clients, deferred WebKit resources,

‎docs/NATIVE_ROUTING.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ a specific model in the composer overrides the route for that task. The model
1010
note above the response records the actual model, provider, and purpose, and
1111
survives reload. The context meter uses that task's model context limit.
1212

13+
The engine normally reserves a quarter of that window for a response (up to
14+
8,192 tokens). If essential input leaves less room after history compaction,
15+
it can request a shorter response down to 256 tokens. The actual provider
16+
request uses that reduced limit; the configured context window never grows
17+
silently. If input, tools and the minimum response still cannot fit, the task
18+
reports the estimated requirement and stops before sending an oversized request.
19+
1320
Default goal milestones use Plan for inspection, Build for implementation, and
1421
Test for required command verification. Planning and review retain read-only
1522
permissions regardless of the selected model. A different model never grants

‎docs/NATIVE_SQLITE.md‎

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Native SQLite inspection — 0.20 development
2+
3+
The native engine lists tables and queries existing SQLite files inside the
4+
selected project. It replaces the Python built-in reader with bundled SQLite;
5+
no Python, shell, database CLI or external MCP registration is required. The
6+
same reader serves model tools, the CLI, desktop IPC and the MCP server.
7+
8+
## Use it
9+
10+
```sh
11+
shadowcode --workspace /path/to/project sqlite app.db
12+
shadowcode --workspace /path/to/project --json sqlite app.db \
13+
'SELECT id, name FROM users WHERE id > ? ORDER BY id' \
14+
--params '[100]' --limit 50
15+
```
16+
17+
With no SQL, the response includes `tables` and their CREATE TABLE definitions
18+
in `rows`. Queries return `columns`, `rows`,
19+
`truncated`, `limit`, and `read_only`. Check `truncated`; narrow the predicate
20+
or use an ordered keyset query to retrieve further rows. Duplicate column names
21+
are rejected: use `AS` aliases rather than losing a value in a JSON object.
22+
NULL, integers, finite numbers and UTF-8 text retain their types. BLOBs return
23+
`{ "type": "blob", "hex": "00ff", "bytes": 2 }`. Invalid UTF-8 and non-finite
24+
numbers fail explicitly; `hex(column)` can produce a readable representation.
25+
26+
Models use the legacy names `mcp_sqlite_tables(path)` and
27+
`mcp_sqlite_query(path, sql, params?, limit?)`. They are native tools available
28+
in Plan/Review and Build, with durable task results and bounded parallel reads.
29+
External MCP activation is unrelated to these built-ins.
30+
31+
External clients use `shadow_sqlite` with the same arguments, optionally adding
32+
`timeout_ms`. Omit `sql` to list tables. The default read-only server supports it;
33+
the selected project remains fixed. Application clients use `POST /api/sqlite`
34+
with that JSON body through the native service.
35+
36+
## Data safety and live databases
37+
38+
The main file opens read-only and must already exist. SQLite's authorizer
39+
denies data/schema writes, ATTACH/DETACH, configuration PRAGMAs, transactions,
40+
extension loading and file-access functions. A query must be a single statement returning columns;
41+
SELECT, WITH and subqueries work. Read-only metadata PRAGMAs are allowed:
42+
`table_info`, `table_xinfo`, `index_list`, `index_info`, `index_xinfo`,
43+
`foreign_key_list`, and `table_list`, including their table-valued forms.
44+
Parameters are bound separately from SQL.
45+
A bounded preparation pass rejects multiple statements without recursively
46+
walking an arbitrary chain of SQL statements.
47+
48+
Live WAL reads retain SQLite's normal locking and transaction semantics and
49+
see committed WAL data; the connection never asserts `immutable=1`. SQLite may
50+
create or update its `-wal`/`-shm` coordination files, including after a writer
51+
closes or leaves WAL data without shared memory. This bookkeeping does not
52+
grant SQL write access or change database rows/schema. Tests check database and
53+
existing WAL bytes remain unchanged while reading a separate process's commits.
54+
An exclusive lock, inaccessible coordination file, corruption, or recovery that
55+
requires a database write produces an error rather than bypassing SQLite locks.
56+
57+
The Linux reader holds the workspace and every real parent directory open. A
58+
private VFS preserves the directory capability's `/proc/self/fd` path while
59+
delegating locking and I/O to SQLite's bundled Unix VFS. Parent/final symlinks,
60+
special files and existing sidecars with additional hard links are rejected.
61+
This shares the application's same-account trust boundary; it is not an OS
62+
sandbox against another process controlling the user's files.
63+
64+
## Limits and cancellation
65+
66+
- 200 rows by default, maximum 1,000; serialized output is capped at 1 MB.
67+
- Five seconds by default; CLI `--timeout-ms` and API `timeout_ms` accept
68+
1–10,000 ms. Model tools also respect their configured tool timeout.
69+
- Eight simultaneous readers per process; excess requests fail with a retry hint.
70+
- SQL and parameter data each have a 64 KB limit, with at most 128 parameters
71+
and 128 result columns. SQLite values/rows are limited to 1 MB.
72+
- Ten million VM instructions, reduced parser/VM limits, an approximately 2 MB
73+
configured page cache, and no auxiliary SQLite threads. Queries requiring
74+
temporary disk spill fail instead of keeping an unbounded in-memory working
75+
set or creating temporary files. Use indexed or narrower queries.
76+
77+
Cancellation/deadlines use SQLite's interrupt handle and progress callback.
78+
Abandoning a request cancels its worker, which retains its reader permit until
79+
the connection closes. SQLite interruption is cooperative; a stalled kernel
80+
filesystem operation may delay return. Tests check that cancellation releases
81+
locks for a subsequent writer.
82+
83+
The locked native library bundles SQLite 3.53.2, including the upstream
84+
[WAL-reset fix](https://www.sqlite.org/wal.html#walreset). This also updates
85+
ShadowCode's history store; schema 24 and existing migration backups remain.
86+
The implementation follows SQLite's [WAL documentation](https://www.sqlite.org/wal.html),
87+
[VFS contract](https://www.sqlite.org/c3ref/vfs.html), and
88+
[untrusted-SQL guidance](https://www.sqlite.org/security.html).
89+
90+
The [verification record](NATIVE_VERIFICATION.md#real-local-models) includes real
91+
gpt-oss and Qwen runs that discover a disposable database's schema, execute the
92+
correct aggregate query and report its result without changing database bytes.
93+
Successful SQLite reads also count toward required task inspection.

0 commit comments

Comments
 (0)