Skip to content

Agent workflows ​

中文

New in 0.4.0

Everything on this page shipped in v0.4.0. If ducklocal check --help doesn't list --restricted, your copy is older; update to use it.

An agent can already query files, build a dashboard and read your comments with the CLI. These additions cover what happens around that work: limiting SQL it did not write, knowing what the window did with a request, letting you approve a change, and recording how an answer was reached.

Limit SQL you did not write ​

--restricted is for SQL copied from data, and for a dashboard someone else wrote. Read-only mode alone doesn't cover this: it protects the database file, while COPY can still write anywhere you can and FROM 'https://...' can still send a request.

bash
ducklocal query --restricted --allow-read ./data --sql "SELECT * FROM 'data/sales.csv'"
ducklocal check report.dash --restricted --allow-read ./data
The SQL tries toResult
Read a file under --allow-readAllowed
Read any other file, by path, glob or ..Denied
Write a file, even under --allow-readDenied
ATTACH a database, or create oneDenied
Reach http, https, s3 or any other URLDenied
INSTALL or LOAD an extensionDenied
Change a setting, including these limitsDenied
Run longer than --timeout (default 60 seconds)Interrupted, kind timeout
Use more than --memory-limit (default 2GB)Fails, kind resource_limit

With no --allow-read, no files are readable, and that includes a dashboard's own folder. A denied statement exits 1 with kind policy_denied and never falls back to running unrestricted. EXPLAIN, PRAGMA and a top-level PIVOT are refused too, because the statement must be one SELECT.

This is not a sandbox. The limits are DuckDB's own, and DuckLocal applies no operating-system isolation on any platform. They bind the SQL, not whoever chooses the flags: an agent with a shell can drop --restricted. To contain an agent you don't trust, run the agent itself in a container or VM. schema, profile, project check and open --run don't run restricted, and neither does the window when it opens a dashboard.

What limits agent-run SQL has the full threat model and what was tested on each platform.

Stay in step with the window ​

ducklocal open used to report delivery and nothing more. Two flags now report how a request ended, and guard against acting on a window that has changed.

bash
ducklocal open --state --active                  # note `revision`
ducklocal open --if-revision REV --run --wait \
  --title "Revenue by channel" --sql "SELECT ..."
  • --wait waits up to 5 minutes and adds status, tab_id, result_status, error and revision to the output.
  • --if-revision REV opens nothing if the window no longer shows that revision, and exits 1 with kind stale. Read the state again before trying again. A person typing in another tab also makes it stale, on purpose.

--state now also reports:

FieldMeaning
schema_version, revisionThe contract's version, and a token for what the window shows
actionsWhat became of recent requests: stale, queued, running, opened, succeeded or failed
limitsThe bounds on previews. A read never returns a whole result
connectionsS3's endpoint and region, and each attached database's name, kind, location and address. Never a key
result.reachlocal, remote or unknown, read from the SQL alone, and whether it used your S3 key
sql_withheldtrue when a tab's SQL may hold a credential, and the text is replaced
scope, on each plotHow much of its query the plot draws

reach can only see what the SQL names, so a local view over remote data reads as local. Reading any of this makes no network request, so location: "remote" says where a database is, not that it still answers.

An agent can see that S3 is configured without seeing the key, but SQL it runs with open --run can still use that key.

The handoff contract lists every field and error kind, and the JSON schema describes the state.

Propose a dashboard change ​

When you want to approve a change, an agent can propose it instead of editing the file:

bash
ducklocal propose sales.dash --status                  # note current_hash
ducklocal propose sales.dash --from new.dash --note "Split revenue by region" --based-on HASH
ducklocal propose sales.dash --status                  # pending, applied or rejected

The spec stays as it is, and the dashboard tab shows that a change is waiting. Click Review to run the proposed SQL and see the diff and checks, then click Apply or Reject.

  • Only you can apply a proposal, in the window. There is no command for it.
  • Applying keeps the old version as sales.dash.bak, and is refused if the spec changed since the proposal.
  • Rejecting leaves the spec untouched.
  • Clicking Review runs the proposed SQL, so a proposal you don't trust can reach whatever the dashboard's SQL can. Run check --restricted on it first.

Record how an analysis got here ​

Set DUCKLOCAL_SESSION, and query, check, propose and open each record what they did:

bash
export DUCKLOCAL_SESSION=analysis.session.jsonl
ducklocal session note --text "EU revenue fell 12%" --refs 3,4
ducklocal session show --last 20

Nothing is recorded without that variable. The file holds SQL and spec text, each source's size and modification time, and each result's shape, never its rows. Errors are kept up to 500 characters and can quote values, so keep the file out of shared folders unless you mean to share them.

Each step and conclusion has doubts, worked out when you read the file: what failed, was cut off or has changed since. An empty list means nothing is known against it, not that it is right.

SQL that may hold a credential is left out. That check goes by words such as secret, token and access_key, so a column with one of those names hides its query too.

Keep an analysis movable ​

bash
ducklocal project init             # write ducklocal-project.json
ducklocal project check            # what a move would break
ducklocal project relink --source orders --to data/2026/orders.csv

A ducklocal-project.json is optional. It lists a folder's dashboards and what they need; data is referenced, never copied. Opening it in the window opens those dashboards.

project check reports ok, portable, problems (each with a hint) and limitations, and exits 0 whatever it finds, so read the output. It never reaches the network or installs anything. Passing doesn't prove the data is the same. project relink changes your dashboards and keeps each old one as NAME.dash.bak.

A worked example ​

A leaked key, investigated by an agent and a person walks a made-up week of CloudTrail from the first query to a reviewed dashboard. A test runs the agent's half on every change. Nobody has yet clicked through the window's half of this example, and its README says which steps those are.

Released under the Apache-2.0 License.