CLI
The graft CLI is the repository control plane for local development,
scripting, application integration, demos, and manual operations. It calls the
repository service directly; it does not route commands through SQLite
PRAGMAs.
Global Options
Section titled “Global Options”graft sql --db path/to/data.sqlite "SELECT 1;"--db names the SQLite database path for SQLite-specific commands such as
graft sql. Repository commands discover .graft/ from the current directory
and operate on the repository as a whole. switch and merge --continue do
not need a database selector. Pass --db when merge, conflicts, or resolve
should open a specific SQLite database for row-aware analysis or resolution.
SQL Runner
Section titled “SQL Runner”graft sql --db data.sqlite "SELECT 1;"graft sql --db data.sqlite "CREATE TABLE t(id INTEGER PRIMARY KEY); INSERT INTO t DEFAULT VALUES;"cat script.sql | graft sql --db data.sqlitegraft sql opens a normal physical SQLite worktree file. Other database tools
and application libraries can open that file with their ordinary SQLite
connections.
It requires an explicit --db path and an existing .graft/ repository. Use graft init once in the worktree before creating or modifying a database through the CLI.
Repository Commands
Section titled “Repository Commands”| Command | Purpose |
|---|---|
graft init [--json] | Create .graft/ in the current worktree. |
graft clone [--json] <remote> [branch] | Clone a remote repository into the current worktree. |
graft status [--json] [--kind kind] | Show branch, HEAD, staged, unstaged, and conflict state. |
graft audit [--json] [--repair [remote]] | Verify repository objects and external payloads; --repair hydrates missing artifact payloads from a remote. |
graft gc [--json] [--dry-run|--force] | Preview or delete unreachable SQLite storage; defaults to dry-run. |
graft payload fetch [--json] [--remote remote] [rev] | Hydrate missing external payloads for a revision; defaults to HEAD and the current upstream remote, then origin. |
graft payload status [--json] [rev] | Show present, missing, and invalid local external payloads for a revision; defaults to HEAD. |
graft payload prune [--json] [--dry-run|--force] | Preview or delete unreferenced local external payloads; defaults to dry-run. |
graft ls-files [--json] [--details|--stage|--others] [--kind kind] | List tracked SQLite databases, text files, or binary files; --details includes artifact hashes and payload presence, while --others lists untracked worktree candidates that can be added. |
graft add [--json] [--all [--kind kind]] [path] | Stage all worktree changes, optionally filtered by kind, or one repo-relative path. |
graft rm [--json] [--cached] [path] | Stage removal of a tracked database or file; --cached keeps worktree contents. |
graft commit [--json] -m <message> | Create a repository commit from the index. |
graft upgrade | Download and install the latest stable CLI release for the current platform. |
graft log [--json] [--limit n] [--after oid] | Show repository history; pagination requires JSON output. |
graft show [--json] <rev> | Show one repository commit. |
graft diff [--json] [--rows] [--content [--max-content-bytes n]] [--kind kind] [--staged] [from] [to] [path] | Compare worktree, index, or revisions, optionally filtered by kind. |
graft diff --no-index [--json] [--rows] <from.sqlite> <to.sqlite> | Compare two physical SQLite files without a repository. |
graft delta create --base <base.sqlite> --target <target.sqlite> --output <file> [--json] | Create a portable, self-validating SQLite page delta. |
graft delta apply --base <base.sqlite> --delta <file> --output <target.sqlite> [--json] | Apply a delta to its exact base without overwriting an existing output. |
graft delta inspect <file> [--json] | Validate and describe a delta without applying it. |
graft checkout [--json] [-f] <rev> [path] | Check out a revision or restore one path from a revision. |
graft restore [--json] [--staged] [--source rev] <path>graft restore [--json] --staged --all [--kind kind] | Restore a worktree path, one staged path, or all staged paths optionally filtered by kind. |
graft export [--json] [--source rev] --output <file> [path] | Write a Graft database snapshot as a physical SQLite file. |
graft reset [--json] [--soft|--mixed|--hard] <rev> | Move the current branch or HEAD. |
Interactive graft log uses Git-style commit blocks and opens the configured
pager (GIT_PAGER, then PAGER, or less by default). Piped, redirected, and
JSON output are written directly.
When graft add stages a physical SQLite path, it takes a consistent online
backup and compares 4 KiB Graft storage chunks with the current staged or
committed snapshot. Committed WAL frames are included. Only changed chunks
extend Graft storage, and an unchanged file creates no new storage commit. The
physical SQLite database may use a larger legal page size, such as 8 KiB; that
does not change Graft’s 4 KiB storage granularity.
graft diff --rows expands modified SQLite database snapshots into table and
row changes:
graft diff --rows HEAD~1 HEAD data.sqlitegraft diff --rows --staged data.sqlitegraft log --jsongraft log --json --limit 50graft diff --json --rows HEAD~1 HEAD data.sqlitegraft diff --json --content --max-content-bytes 65536 HEAD~1 HEAD notes.mdgraft diff --no-index --rows old.sqlite new.sqlitediff --no-index captures both physical files as consistent SQLite snapshots,
including committed WAL frames. It accepts exactly two SQLite database files
and cannot be combined with repository-only selectors or --db.
The delta command group is also repository-independent and cannot be combined
with --db. Create and apply use consistent SQLite images, bind the delta to
exact base and target SHA-256 digests, process data page-by-page, and never
overwrite an existing output. See the
SQLite Page Delta specification
for the GRAFTD01 layout and failure rules.
diff --content returns bounded content for one changed UTF-8 text
artifact. It requires --json, cannot be combined with --rows or --staged,
and uses 1 MiB when --max-content-bytes is omitted.
For paginated history, pass the exact last commit id from one page back as
--after on the next request:
graft log --json --limit 50 --after <commit-id>add --json, rm --json, commit --json, checkout --json,
restore --json, and reset --json return structured path changes and the
current repository position when available. commit --json also reports
materialized SQLite database paths when snapshots are written back to the
worktree.
init --json, clone --json, and export --json return lifecycle metadata
such as repository paths, current branch/head, remote info, materialized paths,
and exported output files.
add --all --kind, restore --staged --all --kind, diff --kind,
status --kind, and ls-files --kind accept sqlite_database, text_file,
or binary_file; aliases such as sqlite, db, text, and binary are
accepted by the CLI. JSON path entries also include storage
(sqlite_snapshot, inline, or external) so apps can distinguish content
type from storage strategy.
graft payload fetch makes external payloads present for HEAD or the selected
revision without moving refs, changing the index, or touching worktree files.
It reads payloads from the selected remote and reports which content hashes were
already present or fetched.
graft payload status is the read-only companion for cache-aware app panels. It
checks the external payloads referenced by HEAD or the selected revision and
reports present, missing, and invalid payloads without fetching or deleting
anything.
graft payload prune scans .graft/store/files for local external payloads that
are no longer referenced by the index, branches, remote-tracking branches, tags,
or reachable commits. It is a dry-run unless --force is passed. JSON output
uses operation: "payload_prune" and reports referenced, candidate, pruned, and
byte counts plus candidate file hashes and store paths.
graft gc scans repository reachability for internal SQLite storage. It is a
dry-run unless --force is passed. This is separate from payload prune, which
only manages the external file-payload cache.
Exporting Physical SQLite Files
Section titled “Exporting Physical SQLite Files”graft export --output data.inspect.sqlite data.sqlitegraft export --source HEAD --output data.head.sqlite data.sqlitegraft export --source HEAD~1 --output data.previous.sqlite data.sqliteWithout --source, graft export writes the current worktree database state for the requested path. With --source, it writes the database snapshot stored in that revision. The output is a normal SQLite database that can be opened by standard tools.
If you edit a materialized or exported SQLite file with ordinary SQLite tooling, commit the transaction and stage the physical path. Manual WAL checkpointing is not required:
sqlite3 data.sqlite "INSERT INTO notes(body) VALUES ('external edit');"graft add data.sqliteClose database connections before commands that replace worktree files, such as checkout, switch, restore, or hard reset. Graft obtains SQLite locks, normalizes WAL state, and rejects replacement while another writer is active.
Branches And Tags
Section titled “Branches And Tags”| Command | Purpose |
|---|---|
graft branch [--json] | List local branches. |
graft branch [--json] -r | List remote-tracking branches. |
graft branch [--json] -a | List local and remote-tracking branches. |
graft branch [--json] <name> [start-point] | Create a branch. |
graft branch [--json] -d <name> | Delete a fully merged branch. |
graft branch [--json] -D <name> | Force-delete a branch. |
graft branch [--json] -m [old] <new> | Rename a branch. |
graft branch [--json] -u <remote>/<branch> [branch] | Set upstream. |
graft branch [--json] --unset-upstream [branch] | Remove upstream config. |
graft switch [--json] <branch> | Switch branches. |
graft switch [--json] -c <branch> [start-point] | Create and switch. |
graft tag [--json] | List tags. |
graft tag [--json] <name> [rev] | Create a lightweight tag. |
graft tag [--json] -a <name> [-m message] [rev] | Create an annotated tag. |
graft tag [--json] -d <name> | Delete a tag. |
graft branch --json returns current_head, current_branch, branches,
and remote_branches. Branch mutation JSON returns operation and the affected
branch.
graft switch --json returns the switch operation, current repository
position, target branch/head, and materialized path changes.
Switching branches materializes all affected tracked worktree paths. No database option is required:
graft switch maingraft switch -c feature/searchgraft tag --json returns current_head, current_branch, and tags.
Tag create/delete JSON returns the affected tag and operation.
Remotes
Section titled “Remotes”| Command | Purpose |
|---|---|
graft remote add [--json] <name> <uri> | Add a remote. |
graft remote list [--json] | List remotes. |
graft remote get-url [--json] <name> | Print a remote URL. |
graft remote set-url [--json] <name> <uri> | Update a remote URL. |
graft remote rename [--json] <old> <new> | Rename a remote. |
graft remote remove [--json] <name> | Remove a remote. |
graft remote prune [--json] <name> | Delete stale remote-tracking refs. |
graft ls-remote [--json] <remote> | List refs advertised by a remote. |
graft fetch [--json] [--all] [remote] [branch] | Fetch remote branches. |
graft pull [--json] [remote] [branch] | Fast-forward or enter merge state. |
graft push [--json] [--all] [--force] [remote] [branch] | Push local refs. |
Remote JSON commands include current_head and current_branch when
available. remote list --json returns remotes; ls-remote --json returns
advertised refs.
fetch --json, pull --json, and push --json return structured sync
outcomes with the current repository position when available.
Configuration
Section titled “Configuration”graft config list --jsongraft config set user.name "Mayne"graft config get --json files.inline_text_thresholdgraft config set --json files.inline_text_threshold 8 MBgraft config set --json files.external_paths "assets/**, attachments/**"graft config get --json files.external_pathsgraft config unset --json files.inline_text_thresholdgraft config unset --json files.external_pathsgraft config list --json returns the app-facing wrapper with current_head,
current_branch, and entries. The JSON forms of get, set, and unset
return current_head, current_branch, and the affected config entry; mutation
responses also include operation.
Merge And Conflict Commands
Section titled “Merge And Conflict Commands”graft --db data.sqlite merge <rev>graft merge --abortgraft merge --continue -m "merge message"graft conflictsgraft --db data.sqlite conflicts --jsongraft --db data.sqlite resolve --ours data.sqlitegraft --db data.sqlite resolve --theirs data.sqlitegraft --db data.sqlite resolve --manual data.sqlitegraft --db data.sqlite merge --json <rev>graft --db data.sqlite resolve --json --theirs data.sqlitegraft --db data.sqlite resolve --json --theirs --row docs 42 data.sqlitegraft --db data.sqlite resolve --json --theirs --row docs '{"space_id":"space-1","id":"doc-1"}' data.sqliteConflicts are stored in the index as staged conflict entries. Graft can
auto-merge non-conflicting row changes in tracked SQLite databases and stage
the results directly when merge opens the database with --db. Same-row,
schema, add/delete, and opaque-table conflicts still require resolution. After
resolving all paths, commit with graft merge --continue.
The JSON forms return current repository position, path rollups, conflict
analysis, and remaining conflict counts for app-side merge UIs.
graft resolve accepts exactly one of --ours, --theirs, or --manual;
--row <table> <identity> narrows the resolution to one SQLite row conflict.
Use an integer rowid for an ordinary rowid table, or a JSON object containing
the declared primary-key columns for a WITHOUT ROWID table. BLOB key parts
use { "$blob": "00ff" }.