Five of the six shipped executables (scribe, scribe-server, scribe-auth,
scribe-gateway, and scribe-ctl) and the development tool scribe-perf
accept global --json, before or after a subcommand. scribe-runner has no
JSON command results apart from build info; it supports
--log-format json for its logs. Read
stdout as one JSON object and also check the process exit status. Diagnostics
and progress stay on stderr (or the configured service log files).
--log-format json independently selects JSON lines for diagnostic logs. It
neither enables JSON command results nor guarantees that every stderr message
is JSON. Do not merge stderr into stdout when parsing command results.
Results
Command results retain their command-specific fields:
| Executable | JSON results |
|---|---|
scribe | Repository, workspace, path, history, transfer, lock, and merge reports; simple confirmations use message. |
scribe-server | Every command, including initialization, certificates, auth administration, backup/restore, metadata import/export, migration, and health/space reports. |
scribe-auth | init paths (data_dir, admin_credential_file, pepper_file, revision_file, trust_domain), certificate paths/fingerprint, migrate schema reports (data_dir, from, to, users, servers, dropped, dry_run), restore results (data_dir, revoked, kept_server_credentials, revision, incarnation, admin_credential_file, admin_credential), admin-credential issue results (data_dir, user, credential_file, credential, expires), and administrative rows arrays. No password, private-key, or pepper contents are returned. |
scribe-gateway | Example TOML in content, initialized data_dir, and the status inventory with observation timestamps. |
scribe-ctl | Command results include command and ok; cluster snapshots (with the active binary set as binaries), setup, add, upgrade, renew and adopt plans and results (a rolled-back upgrade adds rolled_back, failure, rollback, active_set and backups; a renewal adds renewed, per credential holder, credential, file, replaced, replaced_expires_ms, new and expires_ms, certificates, per server certificate service, file, key (the private key file a rekey replaced, else null), change (reissue, handover, rechain or rekey), replaced_expires_ms and expires_ms, and rotation, retired and authority for CA changes, or when rolled back rolled_back, failure, rollback and kept; cluster snapshots add ca_rotations; an adoption plan adds adopt (the old projects with the services that running, the web database volume, was_running), and a rolled-back adoption rolled_back, failure, rollback and projects; nothing to do is unchanged: true), access rows (objects with account, kind, state, scope, access, detail), doctor reports (sections of checks with id, status, detail, fix and for expiries expires, and a summary; see Controller results), bootstrap results (remote, plan, build, target, controller, unchanged, current, steps), summaries (a docker cluster's add docker: project, directory, files, images, command; and with the web interface web: url, tls_dir, tls), and log lines have their own fields. Plan steps name their data root as service (auth, a store, web). A command run on a remote cluster prints the remote scribe-ctl's result unchanged, except doctor, which merges it into its own report. |
scribe-perf | Measurement helper: info returns build/format metadata; workload, probe, and objects return ok and measurement with raw latency samples. The JS scenario harness writes performance reports and compares baselines. |
Administrative rows are arrays of arrays of strings, in the same column order
as text mode's tab-separated rows, including pagination cursors. An empty result
is {"ok":true,"rows":[]}. Secret contents remain in their designated files:
credentials create returns one row [credential id, file], and the device key
and certificate stay in the credential file. migrate counts accounts kept
(users), servers given ids (servers), and token and session records removed
(dropped), or with dry_run what a run would do; from is 3 and to is 4.
A directory already at schema 4 reports from and to 4 and zero counts. restore reports the credentials it disabled, the server
credentials kept with --keep-server-credentials, the new revision and
incarnation (32 hex digits), and the id of the recovery administrator
credential. expires is Unix milliseconds.
scribe whoami --json returns server, status, username, expires_ms, and
verified (always false: the check is local). status is active, expired,
login_pending, logout_pending, anonymous, credential_file (a
--credential-file or SCRIBE_CREDENTIAL_FILE is selected; its identity is in
the file), plaintext, or none. username is set for active, expired,
and login_pending; expires_ms only for active.
scribe diagnostics --json returns ok, offline, versions, platform,
connection, paths, workspace, and issues. versions holds client,
tcp_protocol (2, plaintext tcp://), tls_protocol (4, mutual-TLS tls://),
workspace_schema, and server (always "not checked (offline)").
Unavailable or unconfigured values are null. Inspection problems retain the available report and return
exit status 1; see client diagnostics.
Server maintenance reports use named numeric fields for counts and sizes.
verify, doctor, usage, and rebuild-locator include ok and exit
alongside findings, even when problems are found; they do not append a second
error object. rebuild-locator lists per-repository indexed, packed,
loose, packs, skipped entries (pack, offset, id, detail; pack
and offset are null for a loose file), and verification problems.
backup returns files, bytes, destination, manifest metadata,
catalog_needs_recovery, warnings, and one findings entry per copied
repository. catalog_needs_recovery is true when the root catalog was not
closed cleanly and repositories were listed from the directory instead. Each
finding contains repository, id, nullable open_pack,
uncommitted_tail_bytes, uncommitted_packs, staging_leftovers, and
needs_recovery. needs_recovery is true when the repository database was not
closed cleanly, for example after a killed server; the head is then reported
unknown and the restored server recovers the copy at first start. Nonzero
leftover values describe an interrupted publication that was copied unchanged,
not repaired.
migrate returns ok, dry_run, target, changed, pending, and
repositories. Each repository includes its id in repository, its descriptor
schema before the run, and the ordered steps selected by preflight. pending
means the initial plan contained work; changed means that work was applied
(always false for a dry run). After success, rerunning returns both false and
empty steps for each repository. An interrupted or failed run exits nonzero;
rerun to inspect and resume the durable progress. Incompatible pre-snapshot
development formats are refused.
staging-branches returns data_dir, ok, the total staging count, and
repositories with a staging array of name, branch (id), operations
(pending branch-operation ids), rows (staged metadata rows), nullable
source and source_change, created_change, and nullable age_at_most_ms.
No creation timestamp is recorded for an unfinished branch, so the age is
measured from the commit its snapshot was pinned to and is an upper bound.
abandoned is null for a listing; after --abandon it contains repository,
repository_id, name, branch, operations, and rows_removed, and the
repositories array describes the state the command left behind.
Long-running serve --json commands emit {"ok":true,"state":"stopped"} only
after normal shutdown. Readiness comes from the runtime directory and diagnostic
lifecycle events. Similarly, scribe-ctl up --foreground --json completes its
result after shutdown; use up --daemon --json to return when ready.
The JS check and scenario runners accept repeatable --report FILE outputs;
the extension selects JSON, text, or self-contained HTML. Performance reports
use schema 2 and kind: "performance"; comparison requires complete passing
reports with compatible run metadata and every budgeted metric present. Missing
or invalid required metrics fail comparison. An infinite ratio (nonzero current
value against a zero baseline) is represented as null; its regressed boolean
still reflects the regression policy. See test reports.
Controller results
Each dispatched controller command writes one document with command and ok.
Selected-cluster results include cluster. With multiple clusters and no selector,
status --json returns a clusters array; one cluster or an explicit selector
returns a single snapshot. up, down, and status include status, generation,
services, logs_dir, and warnings: credentials and certificates that expire
within 30 days (or already did), or whose expiry cannot be read, each with what,
path, expires_ms, and message. Service pid and endpoint values may be
historical; inspect lifecycle status before treating them as live.
setup --plan --json returns plan_only: true and plan: operation, cluster,
variant, definition, runtime, endpoints, checks (name, ok, detail),
steps (an action name, its typed fields, why, and any set_aside paths),
notices, resumes (the interrupted run it continues), and ready. A plan that
cannot run has ok: false and exit status 1. A completed setup --json returns
the same plan, results (per step: step, action, messages), and
cluster_info, the summary file it wrote. add auth and add gateway return
the same shapes (operation is add-auth or add-gateway); their plans also
carry definition_diff (lines starting with @ FILE, +, -, a space, or
… between hunks) and afterwards (what clients and operators do next). An add
that finds its service complete returns unchanged: true, an empty results,
and runs nothing. where --json returns endpoints (each tls:// one with the
ca_fingerprints clients verify it by),
sections of files (path, purpose, exists), web_tls, next commands, and
warnings; with several clusters and no selector it returns a clusters array.
doctor --json returns cluster, definition, runtime, remote (the
target of a remote cluster, else null), sections and summary. Each section
has id, title, host (null where the command ran; the remote target for
the sections a remote cluster's own scribe-ctl reported) and checks; each
check has a stable id, a status (ok, info, warn or fail), a
one-line detail, and for most that are not ok a one-line fix. A check
that judged an expiry (expiry.<file>, ca.internal.<purpose>) adds
expires: at (RFC 3339, UTC) and days_left (whole days, negative once
past); a certificate that does not expire has none. summary
counts ok, info, warn and fail, names the worst status, and gives
the exit status: 0, 1 (warnings only) or 3 (a failure). ok is false only
when a check failed. A remote cluster's report is one document: this
machine's sections, then the remote's.
logs includes service and a lines array of original log strings.
example --json includes format: "toml" and the template in content.
Foreground up --json emits its result only after shutdown; daemon mode returns
when ready. Operational errors use ok: false, command, and error alongside
a nonzero exit status.
Errors, help, and exit codes
With --json, argument errors produce a single object containing ok: false,
code: "usage", error, and exit: 2. The message deliberately omits argument
values, which could contain a mistakenly supplied secret. Use text --help for
syntax details. --json --help and supported --json --version requests return
ok: true, content, and exit: 0.
For argument errors to use JSON, an exact --json must occur before the --
end-of-options marker. After that marker, --json is a positional argument.
Runtime failures have error, code, and exit. The client retains its domain
error codes (which may be null), including merge_incomplete for a merge
submission that does not cover every source change; logging setup failures use
logging. For a semantic refusal error keeps the full name (number): detail
form while the text-mode stderr line shows detail (name) without the number. Other
executables use command_failed. Successful client workflows use command-specific result schemas; do not require an ok field in every client result.
- Most commands exit 0 on success and 1 on runtime failure.
scriberetains its documented domain-specific exit codes.scribe-server doctorandusageexit 1 for reported problems and 2 when the check cannot run, including configuration or ownership-lock failures.scribe-server verifyexits 1 for problems or inability to run.scribe-server rebuild-locatorexits 1 when entries were skipped, verification reported problems, or the command could not run.scribe-perfexits 2 for failed measurement gates and 1 when it cannot run.- Argument errors exit 2 for every executable.
The process exit status is authoritative. A failed mutating command can have completed some work before encountering an error; JSON does not change retry, operation-outcome, durability, or recovery semantics.
File log entries include path and nullable moved_from (path, change).
Continue with both fields from the last row: --before <change> --after-path <path>.
With log PATH --all-branches, every row also has history_snapshot (repository
change ceiling) and in_ancestry (boolean). Reuse the snapshot as --at when
paging. true means the revision's accepting commit is in the selected branch's
ancestry, not that its bytes were chosen by a merge; false identifies related
work outside that ancestry. Both fields are null for ordinary logs and info's
latest revision. Branch IDs and historical paths identify the revisions;
branch display names are current, even with a pinned snapshot.
Every log row carries the submitted message and a nullable note
(change, revision, author, text, time): the current description
recorded after acceptance, when there is one. The page's notes_available is
false against a server that predates descriptions; every note is then null.
describe CHANGE -m TEXT returns the recorded note; describe CHANGE --history returns change and notes, oldest first, each in the same shape.
lock rules [path] returns source: "main:.scribe/config.toml", change, text, ordered rules: [{line, pattern}], and
nullable path, required, and rule: {line, pattern}. Revision zero with text: "version = 1\n" means the main config file is absent.
text is the complete accepted TOML configuration; rules contains only the
lock section, with actual TOML source lines. Profile-only edits also advance
the reported config-file revision. info additionally returns
lock_required, lock_policy_change, and nullable lock_rule.
Offline edits return pending_reconciliation, an array of paths, alongside the
usual opened and skipped arrays. Local add/delete reports use the same field,
plus check: null with --offline or when nothing was opened (and always
for edit, whose lock already made the round trip), {skipped: reason} when the
server could not be reached or the check could not run, otherwise head,
ready, and paths in the shape reconcile returns, for the opened paths only.
A check with findings does not change the exit status.
add exits 1 after its report when a file named on the command line appears in
skipped; skips discovered while recursing into a named directory leave the
exit status 0. revert and sync reports carry displaced (path,
recovery) for every local copy moved to .scribe/_state/recovery; the same notice is
printed on stderr in text mode.
Status path entries have boolean needs_reconcile; info has nullable
needs_reconcile (null when not opened). False is not a live ownership guarantee.
reconcile [--scan] returns head, policy_change, ready, exit, paths, and
nullable discovery. Each path has path, action, ready, nullable
base_change and server_change, lock_required, and issues. Issues contain
code and detail; codes are server_changed, locked, missing,
unexpected_file, unresolved, and move_source_blocked.
discovery contains tracked_modified (discovered and opened), tracked_missing,
untracked, ignored, skipped_links, invalid_names (path, reason), and
problems. Missing/untracked discoveries remain outside opened intent.
ready and exit refer to opened paths: exit 0 when all pass, 1 when any are
blocked. A blocked reconciliation emits this single report without an appended
error object. An execution failure instead uses the normal runtime error schema;
local intent and already-acquired locks survive for retry.
get returns repository and branch IDs, the requested revision and path,
file_change (that path's last change at the selected snapshot), absolute
destination, full content digest, size, and bytes_fetched (chunk payload
bytes). Success means the complete file was verified and published. A refusal or
failed download emits only the normal error object; no partial success report is
printed. An existing destination is a protection refusal (exit 2).
merge and cherry-pick exit 1 while any path has applied: false; the
report is still the only stdout document. Merge/resolve path entries include
nullable group, rename, and path_conflict. group identifies paths whose
choices are saved together. rename contains base, ours, and theirs
historical names (a null side means deleted).
path_conflict is rename/rename, rename/delete, or destination collision,
or null for ordinary/content-only resolution. A resolved row retains this
context; inspect choice and applied for its current resolution state.
scribe move --detect --json returns dry_run, moves (each source,
destination, size, and id of the recorded move, null on a dry run),
unpaired (each path and reason) for missing tracked files that no
untracked file could be vouched for, and hashed, the number of untracked
files whose length matched and were hashed.
Build info
scribe, scribe-server, scribe-auth, scribe-gateway, scribe-runner,
and scribe-ctl answer a hidden --build-info flag for tooling that checks a
set of binaries before an upgrade (scribe-ctl upgrade does). It must be the only argument: it prints one
JSON object on stdout and exits 0 without reading configuration, taking locks,
or starting logging. With any other argument it is an ordinary usage error.
$ scribe-gateway --build-info
{"build":"0.1.0","executable":"scribe-gateway","formats":{"auth_protocol":2,"route_store_schema":2,"tcp_protocol":2,"tls_protocol":4},"target":{"arch":"aarch64","os":"macos"},"version":"0.1.0"}version is the package version and build the SCRIBE_BUILD_ID set at
compile time, or the version when none was set. target names the operating
system and architecture the binary was built for, as Rust's
std::env::consts spells them. formats maps each persistent format and
protocol the executable reads and writes to its version, and lists only those
it uses:
| Key | Meaning | Reported by |
|---|---|---|
tcp_protocol, tls_protocol | Storage protocol on tcp:// and mutual-TLS tls:// connections | all but scribe-auth |
auth_protocol | Auth wire protocol (SAU<n>) | all |
workspace_schema | Newest workspace schema (schema 1 is still read) | scribe, scribe-runner |
catalog_schema, repository_schema, object_store, envelope | Data-root formats, as the data-root descriptor records them | scribe-server |
repository_migration | Repository metadata migration level | scribe-server |
auth_schema | Auth store schema | scribe-auth |
route_store_schema | Gateway route store schema | scribe-gateway |
ctl_state | Format of scribe-ctl's binary-set and backup records in its state directory (bin/current, bin/<build>/SET.json, backups/<stamp>/<root>.json) | scribe-ctl |
Unified status
status and scan return workspace (id, repository, repository_name,
branch, branch_name, view, view_profile, pending_view), synced
(local sync watermark), scope (opened, scan, scan+verify), exit, and
one canonical-path-sorted paths array.
branch_name is the branch's name as the working copy last learned it
(recorded at creation and switch, refreshed by --remote and by renames);
it is null only for a working copy that has never learned it. There is
exactly one row per path; the former separate opened, tracked_modified,
tracked_missing, untracked, conflicts, deferred, and lock_status status
lists are replaced directly in this unreleased interface. Other commands retain
their own documented schemas, including reconcile's discovery categories.
Each path contains:
path,tracked, nullableaction(add,edit,delete,keep), nullable localstate(unchanged,modified,missing,present,not_file),untracked, and nullable inspectionproblem. Null state means uninspected or failed inspection.needs_reconcileanddeferred, independently of opened action/local state.- Nullable
moved_from: {path, change},moved_topaths, andmove_operationsIDs. Accepted move provenance stays separate from physical pending operations. - Nullable
resolutioncontainingstate(unresolved,awaiting_application,applied),choice,applied, nullablegroup,path_conflict, andrename, using the merge/resolve meanings above. An applied choice retains its context. - Nullable
lock: null means unknown, never unlocked. On successful remote checks this containsrequired, nullablerule: {line, pattern},ownership(unlocked,ours,other), and nullableholderwithauthor,workspace,branch, andgeneration. Ownership compares workspace IDs.
remote.state is not_checked, available, or unavailable. Available includes
head, policy_change, and incarnation_matches; unavailable includes error.
A failed explicit remote check retains all local rows, supplies no partial lock
observations, and sets exit: 1 with process exit 1. It emits one report, without
an appended error object. Lock-only rows have null local state. These observations
are not an atomic server snapshot or a submit-readiness guarantee.
summary counts paths, opened, unresolved, awaiting_application,
needs_reconcile, and deferred; categories can overlap. workflows contains
nullable project_publication (operation id), nullable resolution
(planning, aborting, conflicts, applying, resolved), boolean
cherry_pick (the active resolution is a cherry-pick rather than a merge),
nullable sync_target, and booleans switching and branch_operation_pending.
pending_submits lists operation IDs with unknown outcomes. moves remains in
operation order, with id, dependencies, source, destination, complete,
aborting, and files (count). hints contains human-readable guidance; use
structured fields, not these strings, for program logic.
ignored, skipped_links, invalid_names (path, reason), problems, and
files_scanned describe discovery. files_scanned counts additional tracked
paths checked by scanning beyond those already inspected for local workflows.
No clean or ready_to_submit claim is made from a partial scan. Local path
inspection or ignore-rule problems produce exit 1 while retaining the report;
changes, conflicts, and pending workflows alone produce exit 0.
Workspace administration
workspace list --json returns a workspaces array, empty when no active
registrations match. Each row contains repository (ID), repository_name,
workspace (ID), branch (ID), nullable owner (principal ID), label,
tags (array of name or name=value strings, possibly empty),
created_ms, and boolean has_locks. IDs are full hexadecimal strings;
created_ms is milliseconds since the Unix epoch. A null owner means an unowned
registration on a server without auth. Labels and creation times are not
last-active or online indicators.
The CLI follows inventory pages internally and returns one combined array.
Repository or permission failures produce the normal error document rather than
a successful partial inventory. --everyone changes owner selection and
--all-repos changes repository selection; JSON does not bypass authorization.
Successful workspace remove --json returns repository, workspace,
operation (all full hexadecimal IDs), and retired_ms (Unix milliseconds).
Rejections, including held locks, use the normal error schema. After a connection
failure, repeat the command with the same per-user configuration directory to
resolve its saved removal intent. See workspace administration.
Repositories and workspaces
repo create and repo info return result ("created" or "info") and a
repository object with id, name, main_branch, head, incarnation,
created, and storage_compression; repo list returns the same objects in
repositories.
workspace create, workspace register, workspace info, workspace config,
and workspace view show return root, workspace_id, repository,
repository_name, branch (id), branch_name, server, view,
view_profile, pending_view, author, tags, readonly_mode,
transfer_compression, synced, and incarnation. branch_name is the name
the working copy last learned from the server: create and register fill it
in, switch and status --remote refresh it, and the offline commands (info,
config, view show) report the stored value, null only when none was ever
learned.
switch returns the sync report with branch and branch_name added.
Workspace views and profiles
workspace info, workspace view show, and workspace creation include
view_profile (nullable originating profile name) and pending_view (null or
an object with view, profile, and target). The view array always describes
the active selection; an empty array means the entire repository. status and
scan include these fields inside their workspace object.
workspace profiles returns revision and a profiles array of {name, view}
objects from the accepted definition at the branch head. Local profile overrides
are reflected in workspace view, not in the shared profile list.
workspace view set/add/remove, workspace view --continue, and
workspace view --abort (alias cancel) return the sync-report schema, including
complete, failed, deferred, and displaced. An incomplete transition exits
1 and emits one report, without appending a second error object. sync --json
has the same behavior for incomplete file application. Use workspace view show
to inspect the saved transition; resume with sync or --continue, or abandon
it with --abort.
Diffs
diff [--revision N] [paths...] returns revision (the pinned change, or null
for the baseline comparison), compared (files examined), changed (files
whose status is not unchanged), and files. Each file has path,
base_path (the origin of a pending move, otherwise the same path), nullable
opened action, status, added and removed line counts, and diff: the
unified hunks (@@ headers and +/-/ lines, without the ---/+++
file header) for a text change, otherwise null. status is unchanged,
modified, added (no base side), deleted (no working-copy file),
missing (neither side), binary (a NUL byte in the first 8 KiB of either
side), or too_large (either side above the 2 MiB review bound). The exit
status is 0 whether or not differences exist.
Controller live inventory
scribe-ctl df (alias usage), repo list, and status --storage emit one
object with command, ok, cluster (the selected name, or null), and clusters.
Each cluster contains cluster, ok, servers, totals, and lifecycle (null
except with status --storage). Each server has name, endpoint, ok, error,
instance, used_bytes, available_bytes, and repositories; repository rows
have id, name, head, and bytes. Size fields and instance are null on
failure, and the repository array is empty. Unknown available space is also null.
Totals contain servers, responding_servers, repositories, used_bytes, and
complete. Available space is never summed across potentially shared filesystems.
Partial inventory retains successful servers, sets ok and complete false,
and exits 1 without emitting a second error object.
Repository mount reports
workspace mounts returns { change, mounts }; each declaration contains name,
path, repository, branch, revision (decimal string), and selected.
It does not resolve target permissions. Sync reports add mounts entries with the
same declaration fields plus state (ready, excluded, unavailable, retained)
and nullable detail. Retained directories have empty identity/pin/name strings
because they no longer have a declaration. Failed selected mounts also appear in
failed, keep complete: false, and return a nonzero command exit status.
Project orchestration reports
project status returns configuration ("working_copy", or
"publication_journal" if interrupted config replacement temporarily left it
missing), exit, components,
and optional publication. Components contain name, path, selected,
problem, optional mount (repository ID, branch ID, decimal revision string),
submitted (decimal revision string or null), and optional local status.
Local status includes repository/branch IDs, decimal-string synced, scope,
remote state (with decimal-string head/policy revisions when available), view and
pending view, per-path status, pending operation IDs, moves, sync target,
resolution, branch operation/switch state, and project ownership. Per-path and
pending-view records reuse ordinary status fields and their existing types.
Only selected components affect the aggregate inspection exit code. Opened work
and pending publication alone are not inspection failures.
project publish (including --continue and --abort) returns id, complete,
aborted, problem, and ordered components. Each participant contains name,
path, repository/branch IDs, decimal-string revision, operation ID, and state:
planned, prepared, outcome_pending, accepted, unchanged, rejected, or
retired_after_restore. The parent has path . and is last. Exit status is nonzero
while incomplete or when cleanup reports a problem. A successful abort preserves
accepted history and returns aborted: true.
project sync uses the existing sync/mount report. project update returns the
normal message confirmation; it stages a pin and does not submit. Ordinary
status.workflows adds nullable project_publication and gives root-level
recovery hints before suggesting ordinary submit retries.
Partial-view integration reports
Partial-view integration reports add outside_view to each resolution path and
to status.paths[].resolution. This flag derives from the saved workspace view.
An applied excluded path represents a saved metadata decision, not a local file.
Unresolved excluded paths block submission just like included conflicts.
Resolution reports also expose the pinned source (branch, change) and
merge_base, or null without an active integration. These identify the exact
selection to restart after expanding a view. For cherry-pick, merge_base is
the selected change's first-parent revision.