CLI
Every subcommand and alias, how a notebook path resolves, exit behaviour, and the exact grammar of the success and error reports, their trailers, and their colour.
slivingdoc is a subcommand CLI. The subcommand comes first, before any flag.
Subcommands
| Command | Alias | Effect |
|---|---|---|
serve |
s |
Serve the notebook over MCP stdio. This is the server. |
pull |
p |
Write the current notebook into a directory and exit. |
commit |
c |
Publish the changes at a directory (-m <message>) and exit. |
version |
v |
Print slivingdoc <semver> and exit, touching nothing else. |
A missing or unknown command writes the command listing to stdout and exits nonzero; no server starts.
serve, pull, and commit read the same flags and environment
variables, and -h on any of them prints the same reference to stdout.
commit adds the required -m/--message flag. See
Configuration for the full flag table.
slivingdoc version writes slivingdoc <semver> and one LF to stdout and
exits zero without resolving configuration or loading the native and S3
dependencies. -h on serve, pull, or commit follows the same rule.
Arguments and path resolution
pull and commit take at most one positional notebook path, which may
precede or follow the flags. Resolution is:
- An omitted path uses the workspace root, which is the working
directory unless
--workspace-rootsays otherwise. - A path beginning with
~/resolves against the current user’s home directory. - Any other relative path resolves against the working directory.
- The resolved path must stay at or below the workspace root.
-- ends flag parsing, as it does for any Go flag set. A second
positional argument is an error: “at most one notebook path argument is
accepted”.
pull and commit never take a session directory. They address a
directory you can still open after the process exits. serve with
neither root configured does take one — see
Share a directory with humans.
Exit behaviour
| Outcome | Stream | Exit |
|---|---|---|
| Success | stdout | zero |
| Domain error (the report below) | stdout | nonzero |
Argument refusal: a missing -m, or more than one path |
stderr | nonzero, before any native or network dependency is touched |
| Configuration refusal, including an invalid flag value or a path named by both path settings | stderr, one redacted diagnostic | nonzero |
Startup probe failure (INCOMPATIBLE_STORE) |
stderr, redacted | nonzero, before any tool call |
| Missing or unknown command | stdout (the listing) | nonzero |
pull and commit run the same startup sequence as serve — the pinned
engine check and the S3 compatibility probe — then perform one operation
and exit. Logs always go to stderr; stdout carries only protocol messages
and command output.
serve stops on SIGINT and SIGTERM: it accepts no new requests, cancels
in-flight request contexts, waits at most 30 seconds, closes native and
lock resources, and exits nonzero if that deadline expires.
The success report
A successful subcommand writes the unified result report to stdout and exits zero. Its shape is a status line, one indented line per changed file, a totals trailer, and the path-set trailers:
OK generation 18 /srv/notes
archive/old.md -3
notes/a.md +1 -1
notes/c.md +2
3 files changed, 3 insertions(+), 4 deletions(-)
| Part | Grammar |
|---|---|
| Status line | The OK token, two spaces, generation <n> (the accepted remote generation after the operation), two spaces, the resolved notebook directory. |
| File line | Two spaces, the path, two spaces, then +<insertions> and -<deletions>, separated by one space. A zero-count side is omitted entirely. |
| Totals trailer | <n> files changed, <n> insertions(+), <n> deletions(-). |
| Path trailers | The trailers below, when configured. |
The diffstat answers “what is new to check out”. pull reports the delta
between the visible directory before the pull and the materialised
result, so a file restored under a read-only path shows up there like any
other change. commit reports the increment the publication added over
the remote state it observed. A no-op synchronisation reports an empty
stat: no file lines, and zeros in the totals.
A diffstat line is an LF-terminated run of bytes, with one trailing CR stripped for comparison and counting. A final run without a trailing LF still counts as one line; content ending in LF has no phantom empty final line; empty content has zero lines. A file present only after the change counts every line as an insertion, a file present only before it counts every line as a deletion, and a modified file uses a deterministic line diff.
Note: The example in the tool’s own operator reference abbreviates this report: it omits the resolved directory on the status line. The grammar above is what the binary prints.
The error report
A domain error prints the same status/detail/trailer skeleton to stdout and exits nonzero:
CONTENT_CONFLICT · MERGE_CONFLICT
Resolve the conflict blocks before notes_commit.
notes/today.md conflict lines 12-18, 40-42
next: edit the files, then commit
retryable: false
| Part | Grammar |
|---|---|
| Status line | The error code, a space, a middle dot, a space, then the reason token. |
| Message | One line. Message text can change between releases; the tokens cannot. |
| File line | Two spaces, the path padded to the report’s longest path plus two spaces, the file reason as lower-case words, then lines <start>-<end> pairs joined by , when the file has marker ranges. Ranges are one-based and inclusive. |
next: |
The caller’s next step, worded from the action token. |
retryable: |
true or false. |
recovery: |
stage=<stage> remoteAccepted=<yes|no|unknown> resynchronized=<bool>, only for RECOVERY_FAILURE. |
| Path trailers | The trailers below, when configured. |
File reasons are rendered as words:
| Token | Printed as |
|---|---|
TEXT_CONFLICT |
conflict |
PATH_CONFLICT |
path conflict |
UNRESOLVED_MARKERS |
unresolved markers |
READ_ONLY |
read-only |
INVALID_CONTENT |
invalid content |
And so is the action token, on the next: line:
| Token | Printed as |
|---|---|
FIX_INPUT |
correct the request, then call again |
EDIT_FILES |
edit the files, then commit |
PULL |
pull, then continue |
RETRY |
retry the same call |
OPERATOR |
operator attention needed |
An unknown token of either kind is printed verbatim rather than dropped. Errors lists every code, reason, and action.
Path-set trailers
Both reports end with the same trailers, each printed only when that set is configured:
writable: agents/scout
read-only: docs, faq.md
path-rule: longest match decides
The writable trailer precedes the read-only one, because the writable set
is the frame and the read-only entries are the exceptions inside it. The
path-rule: line appears only when both sets are non-empty, since the
two can then name the same region at different depths. Entries are
normalised, sorted, and joined with , . See
Restrict agents with path policies.
A read-only refusal therefore reads:
INVALID_REQUEST · READ_ONLY_PATH
docs is read-only in this server. Your changes there were discarded and the files reset. Write outside the read-only paths, then commit again.
docs/faq.md read-only
next: edit the files, then commit
retryable: false
read-only: docs
Colour
Colour is presentation-only. The OK token is green, the generation
summary cyan, per-file insertion counts green and deletion counts red;
on an error report the code is red, the reason token dim, a file path
yellow, the file reason word dim, next: cyan, and the three trailer
labels dim.
Colour appears only when stdout is a real terminal: piped or redirected
output stays plain text, and any non-empty NO_COLOR disables it even on
a terminal. Stripped of its escape sequences, a coloured report is
byte-identical to the plain one, and a success report always starts with
the OK token, so scripts can match on it. See
Logging and profiling for NO_COLOR’s effect
on log records.
Next
- Use the CLI without a host — the same commands in practice, including from scripts.
- MCP tools — the same two operations over MCP, with their structured results.
- Configuration — every flag and environment variable.