CLI reference

Skiff has three project-scoped commands. Every command discovers the nearest skiff.toml from the current directory upward and prepares the complete reviewed plan before acting.

Commands

Command Result
skiff check Validate configuration and files, require credentials, and test every source connection
skiff refresh Refresh non-incremental tables fully and append incremental tables past their stored watermarks
skiff refresh --full Ignore all watermarks and rebuild every table from scratch
skiff refresh --since A --until B Replace [A, B) in incremental tables; rebuild non-incremental tables normally
skiff mcp Serve the frozen automatic refresh as one no-argument MCP tool

Global help and version:

skiff --help
skiff --version
skiff COMMAND --help

Refresh bounds

--since and --until are required together and cannot be combined with --full.

Accepted bounds:

The two values must be the same kind and since must be earlier than until.

Manifest structure

version = 1

[[sources]]
name = "reporting"
host = "sql.example.com"
port = 1433
database = "Reporting"
user = "skiff_reader"
password_env = "REPORTING_DB_PASS"
trust_cert = false
snapshot = false

[output]
file = "data/reporting.duckdb"

[limits]
max_rows = 500000
timeout_secs = 60

[[queries]]
source = "reporting"
file = "queries/incidents.sql"
table = "incidents"
incremental_key = "opened_at"

[[checks]]
name = "incident ids are unique"
file = "checks/incident_ids.sql"

Field rules and defaults

Field Rule
version Required; currently 1
sources At least one; names are unique case-insensitively
sources.port Defaults to 1433
sources.trust_cert Defaults to false
sources.snapshot Defaults to false
output.file Relative repo-confined path ending in .duckdb
limits.max_rows Optional; defaults to 500000; use -1 to disable the row limit, otherwise must be greater than zero
limits.timeout_secs Optional; defaults to 60, must be greater than zero
queries At least one; each source must exist and each table must be unique
queries.file Relative repo-confined path ending in .sql
queries.table Letters, digits, and underscores only
queries.incremental_key Optional integer or timestamp output column; letters, digits, and underscores only
checks Optional; names must be unique and files must be repo-confined .sql paths

Unknown manifest fields are errors.

Output files

The published DuckDB uses owner-only file mode and contains every configured user table plus _skiff_refresh.

_skiff_refresh records the generation identifier, start and completion timestamps, table count, and total row count for the current publication.

Beside the output, Skiff uses:

Path Purpose
.<output-name>.skiff.lock Coordinates Skiff refreshes and records the current owner
.<output-name>.skiff-refresh-<pid>/ Private generation directory removed after completion or failure

MCP report

The no-argument MCP refresh returns JSON with:

generation, file, started_at, completed_at, elapsed_ms,
rows, tables[], schema_changes[]

Each table report contains source, table, rows loaded during this run, total_rows after assembly, and elapsed_ms.

Errors

CLI errors include a message and Action: guidance. Publication errors also state whether anything changed. MCP returns the same information as message, changed, and human_action.