Artifact 208684b703b258a74cb64f89f01c644defcb26c39c89d2097c8916702022d3a7:
- File
docs/site/content/docs/cli-embedding.md
— part of check-in
[beed361c03]
at
2026-10-19 20:17:37
on branch feat/cli-snapshot
— feat(cli): checkout-free snapshot, per-path log, cat --at and diff --json
repo snapshot commits one file's bytes onto trunk with no checkout, a no-op when they equal the tip. repo log --path lists the check-ins that changed a path, repo cat --at reads a file as a version holds it, and repo diff --json A B [PATH] diffs two versions. Exit 2 means not found. A snapshot re-checks the check-in stamp inside its write transaction and retries, so concurrent processes build one linear trunk.
Tracked in #451 (user: [email protected], size: 3834) [annotate] [blame] [check-ins using]
title: Embedding the CLI
weight: 65
An application that keeps version history in a Fossil repository can run the libfossil binary as a child process: no checkout, no shadow working tree. Four commands make up the interface; their output and exit statuses are stable.
Commands
libfossil -R repo.fossil repo snapshot -m MSG [--user U] --path notes/x.md [--stdin] [--json]
libfossil -R repo.fossil repo log --path notes/x.md [--json] [-n N]
libfossil -R repo.fossil repo cat --at VERSION notes/x.md
libfossil -R repo.fossil repo diff [--json] A B [PATH]
snapshot commits one file's bytes onto trunk and carries every other file forward. The bytes come from stdin with --stdin, otherwise from --path read on disk relative to the working directory. --path must be a clean relative path (notes/x.md; not /x, ../x, ./x, a//b). When the bytes equal the file at the trunk tip, nothing is committed and the existing tip is reported. The first snapshot into an empty repository becomes the root check-in. The check-in time is the current time.
log lists the check-ins that changed the path, newest first, as fossil finfo does. -n caps the count; the default is all.
cat writes the file's bytes as VERSION holds them, as fossil cat -r does. VERSION is anything repo resolve accepts: tip, trunk, a branch, a uuid or a unique prefix of one. Without --at, repo cat still outputs an artifact by uuid.
diff with two versions prints the unified diff between them for PATH, or for every file that differs when PATH is omitted. With one or no version it compares the working directory, as before.
Output
Every JSON document is a single line on stdout. Fields are never renamed or removed; new fields may be added, so parse tolerantly. Times are RFC 3339 in UTC with milliseconds, such as 2026-10-19T08:30:00.123Z. A uuid is the repository's hash of the artifact (40 hex characters for SHA1, 64 for SHA3-256).
snapshot prints the check-in uuid and a newline. With --json:
{"uuid": "9f2c...", "changed": true}
changed is false when the bytes already matched the tip and uuid is that tip.
log --json prints an array, newest first:
[{"uuid": "9f2c...", "time": "2026-10-19T08:30:00.123Z", "user": "dan",
"comment": "edit", "action": "modified", "file_uuid": "ab12...", "prev_name": ""}]
action is added, modified, deleted or renamed. file_uuid is absent for deleted; prev_name is present only for renamed. Without --json, each line is UUID10 TIME USER ACTION COMMENT.
diff --json A B [PATH] prints an array, empty when nothing differs:
[{"name": "notes/x.md", "unified": "--- a/notes/x.md\n+++ b/notes/x.md\n@@ ..."}]
Exit statuses
| Status | Meaning |
|---|---|
| 0 | Success, including a snapshot that changed nothing and a diff with no differences. |
| 1 | Any other failure: a bad --path, an unreadable repository, an ambiguous version prefix, an I/O error. The message is on stderr. |
| 80 | Usage error: an unknown command or flag, or a missing required flag or argument. The command-line parser sets this status. |
| 2 | Not found: the version does not resolve, the file is not in that version (cat), or the path has no history (log). Nothing is written to stdout. |
Concurrency
Processes may snapshot into one repository at the same time. Writers serialize on SQLite's write lock, which waits up to the busy timeout (5 seconds) before failing. A snapshot also checks, inside its write transaction, that no check-in arrived since it read the trunk tip, and starts over if one did, so concurrent snapshots form one linear trunk and none loses another's files. Keep the repository outside any synced folder, and open it from one machine at a time.