# `scribe` CLI reference

Version-control client.

`scribe` manages repositories and local working copies: add, edit, move, submit,
sync, branch, merge/cherry-pick, inspect history, and manage locks. Project commands
coordinate selected mounted workspaces. The client connects to a storage server
or gateway. It also manages client login sessions and remembered TLS trust.
Workspace commands find the workspace root (`.scribe/_state/SCRIBE_FORMAT`) by
walking up from the current directory.
Paths for workspace edits must stay inside that workspace. `get` takes a
repository-relative historical path and an explicit local destination; downloads
and exports can be written outside the workspace.

For a first round trip, read the [tutorial](/docs/tutorials/01-minimal-server.md). For daily work, use the
[client guide](/docs/client-usage.md) and [branch and merge guide](/docs/branches.md).

[scribe-server](/docs/reference/cli/scribe-server.md) | [scribe-auth](/docs/reference/cli/scribe-auth.md) | [scribe-ctl](/docs/reference/cli/scribe-ctl.md) | [scribe-gateway](/docs/reference/cli/scribe-gateway.md) | [scribe-runner](/docs/reference/cli/scribe-runner.md)

## Reading this reference

Command synopses below come from this checkout’s built `--help` output.
Angle brackets denote values, square brackets optional arguments, and `...`
repeatable arguments. `[OPTIONS]` includes the global options below and any
command-specific options. Global options work before or after a subcommand;
parent-group options also apply to their child commands. Use `--` to end option
parsing when passing a positional path that starts with a dash.

Run `scribe -h` for the workflow overview, `scribe COMMAND -h` for a command
summary, and `scribe COMMAND --help` for its full options. Use `scribe --version`
for the build version. The command sections below cover every public action.

## Help and version

`-h` shows common options; `--help` also includes advanced connection, trust,
and diagnostic options. Both work at every command level. `-V` / `--version`
is a top-level option; place it directly after the executable name.

## Global options

| Argument or option | Meaning |
| --- | --- |
| `--server <URL>` | Server URL (`tcp://` or `tls://`); selection order is documented below |
| `--transfer-compression <none\|lz4>` | Object transfer compression (overrides the workspace preference for this command) |
| `--transfer-jobs <N>` | Maximum parallel data transfers, 1–8 (default 4; or SCRIBE_TRANSFER_JOBS). Use 1 for serial transfers |
| `--tls-ca <TLS_CA>` | CA certificates for a tls:// server (or SCRIBE_TLS_CA) |
| `--config-dir <CONFIG_DIR>` | Override the shared per-user configuration root (or SCRIBE_CONFIG_DIR) |
| `--trust-fingerprint <TRUST_FINGERPRINT>` | Approve first-use trust, trust replace or trust forget only when this full BLAKE3: fingerprint matches |
| `--credential-file <CREDENTIAL_FILE>` | Machine credential file from `scribe-auth credentials create` (or SCRIBE_CREDENTIAL_FILE); never stored in workspace state |
| `--anonymous` | Use anonymous TLS access; ignore saved sessions and SCRIBE_CREDENTIAL_FILE |
| `--json` | Machine-readable JSON on stdout |
| `--global-ignore <FILE>` | Global ignore file (lowest precedence) |
| `--timings` | Report nested phase timings to the diagnostic sink (text or --log-format json) |
| `--log-level <LEVEL>` | off\|error\|warn\|info\|debug\|trace (default warn); diagnostics go to stderr |
| `--log-filter <FILTER>` | Target filter, e.g. 'warn,scribe_client=debug' (or SCRIBE_LOG) |
| `--log-format <FORMAT>` | text\|json |
| `-v, --verbose...` | -v for debug, -vv for trace |
| `-q, --quiet` | Errors only, no progress |

## Defaults and configuration

Server selection is `--server`, then `SCRIBE_SERVER`, then the workspace's
recorded endpoint, then `tcp://127.0.0.1:7447`. Both `tcp://` and `tls://` URLs
are supported. Every `tls://` connection uses TLS 1.3 with the hybrid
post-quantum key exchange `X25519MLKEM768`; a server or proxy that cannot offer
it fails the handshake. The client proves its identity with a short-lived
access certificate for its own device key, presented only inside a handshake
with a verified server; no password or reusable secret reaches a storage server.

Login defaults to `SCRIBE_USERNAME` for the username and `SCRIBE_AUTH` for the
auth service URL. Explicit login arguments override these defaults; unset or
empty variables require the corresponding argument. Later commands reuse the
saved session.

Parallel transfers automatically use up to four data connections when enough
work is queued. `--transfer-jobs` overrides `SCRIBE_TRANSFER_JOBS`; both accept
1–8. See [parallel transfers](/docs/parallel-transfers.md) for scheduling and
resource bounds.

Transfer compression is `--transfer-compression`, then the saved workspace
preference, then `none`. Both `none` and `lz4` are supported. A command override
does not change the saved preference, except that workspace creation saves its
initial selection. `workspace config --compression` changes it persistently in
`.scribe/_state/state.redb`. Repository storage compression is a separate, immutable
creation policy.

`--credential-file` or `SCRIBE_CREDENTIAL_FILE` selects a machine credential
file instead of the saved login session; `--anonymous` conflicts with
`--credential-file` and ignores `SCRIBE_CREDENTIAL_FILE`. The file holds the
auth endpoint, the CA of the auth service's certificate, a device key, and its
credential certificate; on Unix it must not be readable by other accounts, and
its directory must not be writable by them. The access certificate fetched for
it is cached under `credentials/` in the configuration root. See
[credential files](/docs/auth.md#credential-files).
`--tls-ca` or `SCRIBE_TLS_CA` selects explicit trust instead of remembered trust.
`--trust-fingerprint` conflicts with `--tls-ca`.
`--config-dir`, then `SCRIBE_CONFIG_DIR`, overrides the per-user configuration
root. Defaults are `~/Library/Application Support/Scribe` on macOS,
`%LOCALAPPDATA%\Scribe` on Windows, and `$XDG_CONFIG_HOME/scribe` or
`~/.config/scribe` on Linux. Trust and sessions live in `trust/` and `sessions/`
under that root, outside workspaces. Scripts and `--json` never prompt for trust.
The root holds device keys: an override must be a location only you can read.
A root Scribe creates is private on every platform (on Windows, a protected
access list for your account, SYSTEM and Administrators); one that already
exists keeps its permissions, so keep `--config-dir` or `SCRIBE_CONFIG_DIR`
user-private, as the default `%LOCALAPPDATA%` is.

Logging defaults to `warn`, on stderr. `SCRIBE_LOG` supplies a target filter.
`--log-filter` overrides it; `--log-level` and `--log-filter` cannot be combined.
`-v`/`--verbose` selects debug, repeated twice selects trace;
`-q`/`--quiet` selects errors only and conflicts with verbose.
`--timings` independently enables phase timings and requires a build with the
`timings` feature (enabled by default). `--log-format` accepts `text` or `json`;
it controls diagnostics independently of `--json` command results.

`--verbose` and `--quiet` also conflict with explicit `--log-level` or
`--log-filter`. Choose one verbosity/filter selection. Text diagnostics are the
default; redirected output is plain and `NO_COLOR=1` disables terminal colors.

## Command index

Start with `scribe -h` for commands grouped by workflow and common options.
`scribe --help` adds connection, trust, and diagnostic options. At every level,
`scribe COMMAND --help` explains that command's arguments and available actions.

| Workflow | Commands |
| --- | --- |
| Everyday work | [status](/docs/reference/cli/scribe.md#status), [sync](/docs/reference/cli/scribe.md#sync), [edit](/docs/reference/cli/scribe.md#edit), [add](/docs/reference/cli/scribe.md#add), [delete](/docs/reference/cli/scribe.md#delete), [move](/docs/reference/cli/scribe.md#move), [revert](/docs/reference/cli/scribe.md#revert), [diff](/docs/reference/cli/scribe.md#diff), [submit](/docs/reference/cli/scribe.md#submit) |
| Inspect and recover | [diagnostics](/docs/reference/cli/scribe.md#diagnostics), [log](/docs/reference/cli/scribe.md#log), [describe](/docs/reference/cli/scribe.md#describe), [info](/docs/reference/cli/scribe.md#info), [scan](/docs/reference/cli/scribe.md#scan), [reconcile](/docs/reference/cli/scribe.md#reconcile), [resolve](/docs/reference/cli/scribe.md#resolve), [get](/docs/reference/cli/scribe.md#get), [export](/docs/reference/cli/scribe.md#export) |
| Branches | [branch list](/docs/reference/cli/scribe.md#branch-list), [branch create](/docs/reference/cli/scribe.md#branch-create), [branch rename](/docs/reference/cli/scribe.md#branch-rename), [branch --continue](/docs/reference/cli/scribe.md#branch---continue), [switch](/docs/reference/cli/scribe.md#switch), [merge](/docs/reference/cli/scribe.md#merge), [cherry-pick](/docs/reference/cli/scribe.md#cherry-pick) |
| Access and repositories | [login](/docs/reference/cli/scribe.md#login), [logout](/docs/reference/cli/scribe.md#logout), [whoami](/docs/reference/cli/scribe.md#whoami), [trust add](/docs/reference/cli/scribe.md#trust-add), [trust show](/docs/reference/cli/scribe.md#trust-show), [trust forget](/docs/reference/cli/scribe.md#trust-forget), [trust replace](/docs/reference/cli/scribe.md#trust-replace), [repo create](/docs/reference/cli/scribe.md#repo-create), [repo list](/docs/reference/cli/scribe.md#repo-list), [repo info](/docs/reference/cli/scribe.md#repo-info), [import](/docs/reference/cli/scribe.md#import) |
| Working copies | [workspace create](/docs/reference/cli/scribe.md#workspace-create), [workspace info](/docs/reference/cli/scribe.md#workspace-info), [workspace config](/docs/reference/cli/scribe.md#workspace-config), [workspace list](/docs/reference/cli/scribe.md#workspace-list), [workspace register](/docs/reference/cli/scribe.md#workspace-register), [workspace remove](/docs/reference/cli/scribe.md#workspace-remove), [workspace trust-history](/docs/reference/cli/scribe.md#workspace-trust-history) |
| File selection | [workspace profiles](/docs/reference/cli/scribe.md#workspace-profiles), [workspace view show/set/add/remove](/docs/reference/cli/scribe.md#workspace-view), [workspace mounts](/docs/reference/cli/scribe.md#workspace-mounts) |
| Assembled projects | [project status/sync/update/publish](/docs/reference/cli/scribe.md#project) |
| File policies | [lock acquire](/docs/reference/cli/scribe.md#lock-acquire), [lock release](/docs/reference/cli/scribe.md#lock-release), [lock list](/docs/reference/cli/scribe.md#lock-list), [lock rules](/docs/reference/cli/scribe.md#lock-rules), [ignore explain](/docs/reference/cli/scribe.md#ignore-explain) |
| Retained files | [recovery list](/docs/reference/cli/scribe.md#recovery-list), [recovery prune](/docs/reference/cli/scribe.md#recovery-prune) |

For ordinary work, create a workspace, sync it, open intended files with `edit`
or `add`, inspect `status`, and `submit -m "Description"`. Additional commands
support specific workflows; they are not prerequisites for submitting a change.

| When you need to… | Use |
| --- | --- |
| Inspect opened work without changing it | `scribe status` |
| Discover unopened modifications and untracked files | `scribe status --scan` (or `scribe scan`) |
| Check offline intent and acquire required locks | `scribe reconcile` |
| Also open discovered tracked edits | `scribe reconcile --scan`; use explicit `add`/`delete` for new/missing files |
| Inspect the parent and mounted working copies | `scribe project status --scan` at the project root |
| Publish children and then record their pins in the parent | `scribe project publish -m "Description"` |

`status` and `submit` operate on the current workspace. `sync` also follows its
selected mounts at recorded pins; `project sync` uses the same workflow at the
project root. Project publication is a sequence of accepted submissions: a child
can succeed before the parent. `--continue` resumes the saved publication;
`--abort` resolves transmitted outcomes and preserves already accepted changes.

Recovery follows the pending operation shown by `status`, and every workflow
spells it the same way: `--continue` resumes and `--abort` abandons. That is
`branch --continue` for branch creation/rename (no abort: the saved intent may
already be accepted), `move --continue` / `--abort`, `merge --continue` /
`--abort`, `cherry-pick --continue` / `--abort`, `resolve --continue` /
`--abort`, `workspace view --continue` / `--abort` for a view transition, and
`project publish --continue` / `--abort`. `sync` also finishes an interrupted
sync or view transition. The earlier subcommand spellings `branch continue` and
`workspace view cancel` still parse as hidden aliases so existing scripts keep
working; new scripts should use the flags.

## diagnostics

Show offline client versions, endpoints, configuration sources, and paths.

```text
scribe diagnostics [OPTIONS]
```

```sh
scribe diagnostics
scribe diagnostics --json
scribe --server tls://host:7447 diagnostics
```

Works inside or outside a workspace. Reports the client version, the storage
protocol versions it speaks (`tcp_protocol`, 2, on a plaintext `tcp://`
connection; `tls_protocol`, 4, on a mutual-TLS `tls://` connection),
local workspace schema, OS and architecture, executable and
current directory, effective storage endpoint and its source, transfer
compression, the parallel transfer-jobs limit, credential selection, and local
session status. An invalid `SCRIBE_TRANSFER_JOBS` value is reported in `issues`.
The saved session's auth endpoint is separate from `SCRIBE_AUTH`, which
configures a future login. Server software versions, connectivity, and
server-side session revocation are not checked.

Paths include the configuration root, trust and session directories, selected
server's session directory, selected credential/CA files, global ignore file, workspace
root, `.scribe/_state` descriptor/database/lock/cache/temporary/recovery/local-ignore
locations, and repository configuration and root ignore files. Paths are absolute
locations; reporting one does not imply that it exists. Nested `.scribeignore`
files are not enumerated. An anonymous selection suppresses the credential file.

Inspection does not connect, create configuration or lock files, open the object
cache, recover a database, or clear temporaries. Credential and CA file contents
are not read; saved session keys and certificates are never included in output. Workspace or
session inspection failures appear in `issues` and cause exit status 1 with
`ok: false`. Other available information remains in the report; an unreadable
workspace never silently selects the default server. `null` means unavailable or
not configured. No log file is created: CLI diagnostics normally go to stderr.

## login

Log in with a username and password; save a reusable session outside workspaces (with --admin, an administrator credential file)

```text
scribe login [OPTIONS] [USERNAME]
```

| Argument or option | Meaning |
| --- | --- |
| `[USERNAME]` | Username registered by the auth administrator (or SCRIBE_USERNAME) |
| `--auth <URL>` | Auth service URL (tls://host:port; or SCRIBE_AUTH) |
| `--password-file <FILE>` | Read password from this file instead of prompting with hidden input |
| `--auth-ca <FILE>` | Auth service CA PEM; otherwise approve remembered TLS trust |
| `--discard` | Drop an unfinished login so another username or auth service can be used (retry first if it may have succeeded); with --admin, the unfinished sign-in for --out |
| `--admin` | Sign in as an auth administrator: write a short-lived administrator credential file (--out) for scribe-auth --admin-credential or the web administration page; no session is saved and no storage server is needed |
| `--out <FILE>` | With --admin: the new credential file (mode 0600 on Unix), outside any .scribe directory; an existing file is refused |

Without `--password-file`, login requires a terminal and reads hidden input.
Login generates a new device key and credential id, saves both with the
pending operation before anything is sent, and sends the username, password,
and public key to the auth service, which answers with a credential
certificate. The private key never leaves the session directory. Sessions are
saved for the selected storage endpoint under
`sessions/` in the per-user configuration root, never in `.scribe/`. A file
given with `--auth-ca` is copied into the session directory as `auth-ca.pem`
and reused by later renewals and `logout`. Success prints
`Logged in as USER; session valid for N days.`

Logging in again while a session is active revokes the previous session first.
If that revocation fails, the client logs `session.revoke_failed` and the old
session stays valid until it expires. A login whose answer was lost is retried
by running the same command again, which resolves the saved operation without
creating a second session; `--discard` takes no other login arguments and
forgets only the local intent (see
[auth](/docs/auth.md#user-login-and-session-lifetime)).

Later commands present a one-hour access certificate fetched from auth with the
session's credential certificate. The client renews it once half its lifetime
has elapsed by local elapsed time, so a wrong wall clock does not cause
hourly failures; parallel commands wait while one renews.

`scribe login --admin --out FILE` is administrator sign-in. It takes the same
username, password and trust arguments, but saves no session and needs no
storage server: auth checks the password as for login and, for an enabled auth
administrator, certifies a new device key as an administrator credential that
lives for the hours auth is configured with (8 by default; see
[`scribe-auth serve --admin-session-hours`](/docs/reference/cli/scribe-auth.md#serve)). FILE is
the same credential file `scribe-auth credentials create` writes, holding the
auth endpoint, the one CA that verified it (so remembered trust with more than
one CA needs `--auth-ca`), the device key and its certificate. It is created
with mode 0600, never inside `.scribe`, and an existing FILE is refused. Use it
with `scribe-auth --admin-credential FILE` or load it on the web
administration page. The key and the pending operation are saved under
`admin-sign-in/` in the per-user configuration root before anything is sent,
so rerunning the same command after a lost answer writes the credential auth
already issued instead of a second one; `--admin --discard --out FILE` forgets
an unfinished one. Success prints `Signed in as USER (auth administrator);
administrator credential saved to FILE (valid for N hours, until TIME). Use it
with scribe-auth --admin-credential FILE or load it on the web administration
page.`; with `--json`, `{"username", "credential_file", "credential",
"expires_ms"}`.

## whoami

Show local login status for the selected server (does not verify server-side revocation)

```text
scribe whoami [OPTIONS]
```

Works inside a workspace or with `--server tls://HOST:PORT` outside one. Reports
saved username and expiry, no saved session, expired session, an unfinished
login, pending logout, anonymous access, a selected credential file, or
plaintext access. Corrupt session state is an error. It does not contact the
server: a saved session may have been revoked, and a selected credential file
is not read or validated (`Credential file selected; its identity is in the
file.`).

`--json` returns `server`, `status`, `username`, `expires_ms`, and `verified`
(always `false`). Status is one of `active`, `none`, `expired`, `login_pending`,
`logout_pending`, `anonymous`, `credential_file`, or `plaintext`. Unavailable
identity and expiry are `null`.
Successful inspection exits 0 even when not logged in; scripts should inspect
`status`. Credentials are never printed.

## logout

Revoke the saved user session and remove it locally; retry after connection failures

```text
scribe logout [OPTIONS]
```

| Argument or option | Meaning |
| --- | --- |
| `--auth-ca <FILE>` | Auth service CA PEM; otherwise the file given at login, or remembered TLS trust |

Revocation must succeed before the local session is removed: the client
authenticates to auth with the session's credential certificate and revokes
that credential, then deletes the device key and certificates. A failed
connection retains the pending logout; repeat the command to finish it. Auth
answers success for a credential it already revoked, so a retry always
completes. A trust failure before the request retains nothing. A session whose
credential has already expired is removed locally without contacting auth.
With an unfinished login saved, logout refuses until that login is retried or
discarded. Without a saved session the command reports `not logged in at
SERVER` and exits 1. Success prints `Logged out; session revoked.`

## trust

Manage remembered TLS server trust, without sending credentials

```text
scribe trust [OPTIONS] <COMMAND>
```

Subcommands: [add](/docs/reference/cli/scribe.md#trust-add), [show](/docs/reference/cli/scribe.md#trust-show), [forget](/docs/reference/cli/scribe.md#trust-forget), [replace](/docs/reference/cli/scribe.md#trust-replace).

Saved trust holds one or more CAs per server. A CA handover (the server
presents its new certificate with a handover certificate signed by the CA you
already trust) is followed without a prompt: the new CA is saved beside the
old one, and the old one is dropped once the server no longer uses it. Any
other change of a server's CA is refused before anything is sent:

```text
The CA of tls://scribe.example:7557 changed.
  trusted: BLAKE3:…
  now:     BLAKE3:…
If your administrator confirms this change, run: scribe --server tls://scribe.example:7557 trust replace
```

## trust add

Approve trust for an unknown server; presents no credential

```text
scribe trust add [OPTIONS]
```

No command-specific options; global and parent-group options still apply.

## trust show

Show saved trust for the selected server, without connecting

```text
scribe trust show [OPTIONS]
```

No command-specific options; global and parent-group options still apply.

## trust forget

Remove saved trust. Requires --trust-fingerprint matching a saved value

```text
scribe trust forget [OPTIONS]
```

No command-specific options; global and parent-group options still apply.

It removes the server's whole saved record, every CA in it; the next
connection asks for trust again. A record from an older Scribe version, which
cannot be read as trust, is removed without `--trust-fingerprint`.

## trust replace

Replace the saved CA of a server whose CA changed; presents no credential

```text
scribe trust replace [OPTIONS]
```

| Option | Description |
|---|---|
| `--auth-ca <FILE>` | Replace the sign-in service CA file saved with this server's session (from `login --auth-ca`) with FILE, instead of the server's own trust |

Use only after your administrator confirmed the change. The command connects
without credentials; if saved trust still verifies the server (including through
a CA handover, which it follows), it prints `Nothing was replaced` and changes
nothing. Otherwise it shows the saved and the new fingerprints and asks you to
type `replace`; with `--trust-fingerprint` the new fingerprint must match
instead, and `--json` or a non-interactive terminal never prompts. All saved
CAs of that server are replaced by the one it presents.

`--server` names the server whose trust is replaced; for a sign-in service
trusted through the shared trust store, that is the sign-in service's own
address (the refusal names the exact command). With `--auth-ca FILE`, the CA
file saved at `login --auth-ca` for the selected server's session is replaced
by FILE after FILE verifies the sign-in service; `--trust-fingerprint` must then
match a certificate in FILE.

```text
scribe --server tls://scribe.example:7557 trust replace
scribe --server tls://scribe.example:7557 --trust-fingerprint FP trust replace
scribe --server tls://scribe.example:7557 trust replace --auth-ca new-auth-ca.pem
```

## branch

Create, list, and rename branches (stable identities)

```text
scribe branch [OPTIONS]
scribe branch <COMMAND>
```

| Argument or option | Meaning |
| --- | --- |
| `--continue` | Resolve the saved outcome of an interrupted create or rename |

Subcommands: [list](/docs/reference/cli/scribe.md#branch-list), [create](/docs/reference/cli/scribe.md#branch-create), [rename](/docs/reference/cli/scribe.md#branch-rename).
`--continue` conflicts with a subcommand; with neither, the command explains
what it expects and exits 1. See [branch --continue](/docs/reference/cli/scribe.md#branch---continue).

## branch list

List branches with their heads

```text
scribe branch list [OPTIONS]
```

No command-specific options; global and parent-group options still apply.

## branch create

Create a branch from a source branch's head or a pinned change

```text
scribe branch create [OPTIONS] <NAME>
```

| Argument or option | Meaning |
| --- | --- |
| `<NAME>` | New branch name (unique ignoring case and Unicode normalization) |
| `--from <BRANCH>` | Source branch (default: the workspace branch) |
| `--revision <CHANGE>` | Start from this change on the source branch instead of its head |

## branch rename

Rename a branch; its id, history, workspace bindings, and locks are unchanged

```text
scribe branch rename [OPTIONS] <OLD> <NEW>
```

| Argument or option | Meaning |
| --- | --- |
| `<OLD>` | Current name (main cannot be renamed) |
| `<NEW>` | New name |

## branch --continue

Continue an interrupted create or rename by resolving its saved outcome.

```text
scribe branch --continue [OPTIONS]
```

The saved operation id is resolved on the server, never re-sent as new intent.
There is no `--abort` for branch operations: the server may already have
accepted the saved intent, and an unknown outcome is only ever resolved by
asking. `scribe branch continue` remains a hidden alias. Without a saved
operation the command reports that nothing is pending and exits 1.

## switch

Switch the workspace to another branch (requires no opened files, pending submit, or held locks)

```text
scribe switch [OPTIONS] <BRANCH>
```

| Argument or option | Meaning |
| --- | --- |
| `<BRANCH>` | Branch name |

The branch is resolved before anything changes, so an unknown name is refused
without touching the workspace. Text output names the destination first
(`switched to BRANCH (branch ID)`) and then prints the ordinary sync summary;
`--json` returns the sync report with `branch` (id) and `branch_name` added.

## merge

Merge a source branch into the workspace branch; submit after resolving

```text
scribe merge [OPTIONS] [SOURCE]
```

| Argument or option | Meaning |
| --- | --- |
| `[SOURCE]` | Source branch name (omit with --continue or --abort) |
| `--revision <CHANGE>` | Merge the source as of this change instead of its head |
| `--base <CHANGE>` | Merge base to use when more than one best base exists |
| `--continue` | Resume the pending merge without changing its pinned source |
| `--abort` | Abandon the pending merge; displaced local files are kept in .scribe/_state/recovery |

Omit SOURCE with `--continue` or `--abort`. `--continue` conflicts with
`--abort`. Start a merge with no opened files; full and partial workspace views
are supported. Like `cherry-pick`, the command exits 1 while any path remains
unresolved and the report ends with the `scribe resolve` step to take; the
report is still printed and no error object is appended. See
[partial-view integration](/docs/partial-view-merging.md) for excluded
conflicts.

Resolve conflicts, then submit; preparation alone does not accept history.
Recorded renames are matched before content merging; competing names,
rename/delete cases, and occupied destinations are reported as groups. See
[rename-aware merging](/docs/client-usage.md#rename-aware-merging).

## cherry-pick

Apply one ordinary accepted change from another branch; submit after resolving.

```text
scribe cherry-pick [OPTIONS] [CHANGE]
```

| Argument or option | Meaning |
| --- | --- |
| `[CHANGE]` | Repository change number to apply |
| `--from <FROM>` | Source branch name or ID that accepted the selected change |
| `--continue` | Resume the pinned cherry-pick without selecting new intent |
| `--abort` | Abandon the pending cherry-pick and retain displaced files in recovery |

Starting requires both CHANGE and `--from`; omit both with `--continue` or
`--abort`. Resume and abort are mutually exclusive. Start with no opened files
or unfinished sync. Full and partial workspace views are supported. Resolve any
conflicts, review the result, then use ordinary `scribe submit` to accept it.
The command returns a nonzero exit status when paths remain unresolved.

Merge commits and cherry-pick commits cannot be selected as sources. Repeating
a source already in the target ancestry or recorded as picked reports it as
already applied. The resulting commit records source provenance without adding
a merge parent. See [cherry-pick](/docs/cherry-pick.md) for backports, later whole
branch merges, web/SDK use, and recovery; see
[partial-view integration](/docs/partial-view-merging.md) for excluded conflicts.

## resolve

Inspect or resolve branch and stale-file conflicts

```text
scribe resolve [OPTIONS] [PATHS]...
```

| Argument or option | Meaning |
| --- | --- |
| `[PATHS]...` | Paths to resolve (rename groups are chosen together); with no flags, list unresolved paths |
| `--ours` | Take the workspace branch's version for the given paths (or --all) |
| `--theirs` | Take the source branch's (or server's) version for the given paths (or --all) |
| `--working` | Accept the file as it is now in the working copy after manual editing |
| `--update` | Refresh stale opened files against the server head before resubmitting |
| `--abort` | Abandon the pending resolution (same as merge --abort) |
| `--continue` | Resume the pending resolution workflow (same as merge --continue) |
| `--all` | Apply the chosen side to every path in the plan instead of the listed paths |
| `--export <EXPORT>` | Export base/ours/theirs into an empty directory for external tools |

Choose one of `--ours`, `--theirs`, `--working`, `--update`, `--abort`,
`--continue`, or `--export`. `--all` applies a side selection to the entire
plan. With no action, list unresolved paths. `--abort` and `--continue` are
equivalent to `merge --abort` and `merge --continue` (`--continue` is refused
when no resolution is pending); `--export` requires an empty destination.

Selecting a member of a rename group selects the entire group. With an agreed
destination, `--ours`/`--theirs` choose contents there; with conflicting names
they choose a layout. For `--working`, write the resolved content at the agreed
destination, or arrange the displayed group paths when names conflict. Grouped
merges and partial-view integrations must be aborted and restarted if their
target advances; `--update` does not replan them. Choices that include excluded
paths are refused until those paths are in the view. This also applies to
`--all`, which selects the entire plan; name only included paths when resolving
their conflicts separately. During a merge or cherry-pick, `workspace view add`
includes missing paths without discarding completed resolutions. Expansion
retains the pinned revisions; resume an interrupted view transition with `sync`.

## repo

Repository administration

```text
scribe repo [OPTIONS] <COMMAND>
```

Subcommands: [create](/docs/reference/cli/scribe.md#repo-create), [list](/docs/reference/cli/scribe.md#repo-list), [info](/docs/reference/cli/scribe.md#repo-info).

## repo create

Create an empty repository with a main branch

```text
scribe repo create [OPTIONS] <NAME>
```

| Argument or option | Meaning |
| --- | --- |
| `<NAME>` | Letters, digits, '-', '_', '.'; not starting with '.'; at most 128 bytes |
| `--storage-compression <none\|lz4>` | Permanent repository storage policy; cannot be changed after creation [default: none] |

Storage compression accepts `none` (default) or `lz4` and cannot be changed after creation. Authenticated repository creation requires namespace administration.

## repo list

List repositories you can access

```text
scribe repo list [OPTIONS]
```

No command-specific options; global and parent-group options still apply.

## repo info

Show a repository's id, main branch, head, and incarnation

```text
scribe repo info [OPTIONS] <REPO>
```

| Argument or option | Meaning |
| --- | --- |
| `<REPO>` | Repository name or id |

## workspace

Manage one repository working copy, its view, and shared view presets

```text
scribe workspace [OPTIONS] <COMMAND>
```

Subcommands: [list](/docs/reference/cli/scribe.md#workspace-list), [remove](/docs/reference/cli/scribe.md#workspace-remove),
[create](/docs/reference/cli/scribe.md#workspace-create), [config](/docs/reference/cli/scribe.md#workspace-config),
[register](/docs/reference/cli/scribe.md#workspace-register), [info](/docs/reference/cli/scribe.md#workspace-info),
[profiles](/docs/reference/cli/scribe.md#workspace-profiles), [view](/docs/reference/cli/scribe.md#workspace-view),
[mounts](/docs/reference/cli/scribe.md#workspace-mounts), [trust-history](/docs/reference/cli/scribe.md#workspace-trust-history).

## workspace list

List your active server registrations; without auth, list every registration

```text
scribe workspace list [OPTIONS]
```

| Argument or option | Meaning |
| --- | --- |
| `--repo <REPO>` | Repository name or id; mutually exclusive with `--all-repos` |
| `--all-repos` | List across every accessible repository, including through a gateway |
| `--everyone` | Include other owners; requires Maintainer in each selected repository with auth |
| `--tag <NAME[=VALUE]>` | Only registrations carrying this tag; NAME matches any value, NAME=VALUE exactly (repeatable, all must match) |

Columns are `WORKSPACE`, `REPOSITORY`, `OWNER`, `LABEL`, `TAGS`, `CREATED`,
and `LOCKS`, sized to their contents so header and rows line up. The label is
the one recorded at registration: `AUTHOR@HOST` for a workspace the CLI
created. `TAGS` lists the registration's tags comma-separated, `-` for none;
`--tag runner` keeps the workspaces runners made, `--tag runner-id=<id>` one
runner's. Filtering happens in the CLI after the pages are fetched.
Without a repository selection, use the current workspace repository if present,
otherwise all accessible repositories. Authenticated listing defaults to the
current principal's registrations. Anonymous public access cannot list them;
without auth, all registrations in the selected repositories are visible.
An authorization failure in any selected repository fails the command rather
than producing a partial admin inventory.

Use global `--server URL` to select a storage endpoint or gateway and `--json`
for [structured inventory](/docs/json-output.md#workspace-administration).
No local checkout is required. See [workspace administration](/docs/workspace-administration.md).

## workspace remove

Permanently retire a server registration; preserve local files and accepted history

```text
scribe workspace remove [OPTIONS] <WORKSPACE>
```

| Argument or option | Meaning |
| --- | --- |
| `<WORKSPACE>` | Full workspace id from `workspace list`; held locks must be released first |
| `--repo <REPO>` | Repository name or id; required outside a workspace |

With auth, an owner needs repository read access to remove their registration;
removing another owner's registration requires Maintainer. Without auth, any
connected client may remove a registration. The same rules apply through a gateway.

Removal affects only the selected registration, frees its active-workspace quota
slot, and has no undo. Retired identities cannot register again, acquire locks,
or publish new work. Other registrations, project mount pins, local files, and
accepted history remain intact. Held locks must be explicitly released first;
removal does not force-unlock them.

Repeat the command with the same per-user configuration directory after a
connection failure to resolve its saved outcome safely. See
[workspace administration](/docs/workspace-administration.md) for lock release
and recovery from an old computer.

## workspace create

Create a workspace for a repository in a directory

```text
scribe workspace create [OPTIONS] <REPO> <DIRECTORY>
```

| Argument or option | Meaning |
| --- | --- |
| `<REPO>` | Repository name or id |
| `<DIRECTORY>` | Directory to hold the working copy (must not already contain a workspace) |
| `--view <PREFIX>` | Inclusion prefixes (repeatable); with --profile, add local inclusions to that profile |
| `--profile <NAME>` | Named profile from the repository's accepted .scribe/config.toml file |
| `--author <AUTHOR>` | Author label for submits; --author overrides the default (the logged-in user, then $SCRIBE_AUTHOR, then the OS user name) |
| `--readonly` | Mark unopened tracked files read-only (Perforce convention) |
| `--tag <NAME[=VALUE]>` | Tag the registration (repeatable, at most 16); a tag is NAME or NAME=VALUE and never changes afterwards |
| `--preset <art>` | Start the repository configuration from a preset: writes .scribe/config.toml and opens it for add; submit to apply |

`--view` is repeatable. Change an existing selection with `workspace view`.
`--profile` reads the accepted definition at the main branch head; `--view`
adds local inclusions when used with a profile. `--author` overrides the
default label, which is the logged-in username when a session is saved for
the server, then `SCRIBE_AUTHOR`, then the OS username; authenticated
attribution on the server comes from the credential regardless. The
registration label is `AUTHOR@HOST`. `--tag` adds `name` or `name=value`
markers to the registration beside the label — what made the workspace and
why, for `workspace list --tag` and the web inventory to filter on. A name is
1–63 lowercase ASCII letters, digits, `-`, `_` or `.` starting with a letter
or digit, a value printable ASCII without spaces, the whole tag at most 64
bytes, names unique, at most 16 per workspace. Tags are fixed by the first
registration: there is no command to change them, and the server refuses a
re-registration that names different ones. (A runner tags its workspaces
`runner` and `runner-id=<id>`.) The selected transfer compression is saved
for future connections. The report names the branch (`main` for a new
workspace) and `--json` includes `branch_name` and `tags`.

`--preset art` writes a starting `.scribe/config.toml` (`kind = "art"` plus
lock rules for binary art formats) into the new working copy and opens it for
add. Nothing is submitted: review the file, then run `scribe submit`. The
command is refused before anything is created when `main` already has an
accepted `.scribe/config.toml`, or when the `--view` prefixes (without
`--profile`) exclude it. See
[repository configuration](/docs/repository-config.md#starting-from-a-preset).

## workspace config

Set the workspace preference for compression on subsequent connections

```text
scribe workspace config [OPTIONS] --compression <none|lz4>
```

| Argument or option | Meaning |
| --- | --- |
| `--compression <none\|lz4>` | Compression for uploads and downloads; independent of repository storage |

Run inside the workspace. `--compression` is required and accepts `none` or `lz4`. This updates the saved transfer preference; it does not change repository storage compression.

## workspace register

Register an anonymous working copy under the logged-in writer, preserving local edits.

```text
scribe workspace register [OPTIONS]
```

| Option | Meaning |
| --- | --- |
| `--tag <NAME[=VALUE]>` | Tag the registration (repeatable, at most 16); a tag is NAME or NAME=VALUE and never changes afterwards |

Run in the anonymous working copy after login. `--tag` sets the tags the
registration is made with, as `workspace create --tag` does; an anonymous copy
has none until then. Requires repository write permission.
Persists a fresh identity before transmission; interrupted registration can be
retried. Files and opened edits remain in place. See
[public repositories](/docs/public-repositories.md).

## workspace info

Show the current workspace

```text
scribe workspace info [OPTIONS]
```

No command-specific options; global and parent-group options still apply.
Works offline. The `branch` line shows the name the working copy last learned
from the server with the id in parentheses; `workspace create`, `switch`, and
`status --remote` record it, and `branch list` always shows the server's current
names.

## workspace profiles

List accepted workspace profiles at the current branch head.

```text
scribe workspace profiles [OPTIONS]
```

Works even if `.scribe/config.toml` is outside the current view. Definitions come
from accepted history; local unsubmitted edits are not read.

## workspace view

Inspect or safely change which repository paths are materialized.

```text
scribe workspace view [OPTIONS]
scribe workspace view <COMMAND>
scribe workspace view show [OPTIONS]
scribe workspace view add [OPTIONS] <PREFIXES>...
scribe workspace view remove [OPTIONS] <PREFIXES>...
```

| Subcommand or option | Behavior |
| --- | --- |
| `show` | Show the active selection and any pending transition; no network required |
| `set` | Replace the selection; active integrations allow expansion at their pinned target |
| `add <PREFIXES>...` | Add local inclusion prefixes and sync missing content |
| `remove <PREFIXES>...` | Remove selected prefixes and selected descendants |
| `--continue` | Resume an interrupted view change (same as `scribe sync`); refused when none is pending |
| `--abort` | Safely reconcile back to the active selection after an interrupted change |

`--continue` and `--abort` conflict with each other and with a subcommand.
`scribe workspace view cancel` remains a hidden alias of `--abort`.

The `set` usage from `--help` is:

```text
scribe workspace view set [OPTIONS] <--view <PREFIX>|--profile <NAME>|--all>
```

| Option | Meaning |
| --- | --- |
| `--view <PREFIX>` | Inclusion prefix; repeat to select multiple paths, or extend a profile |
| `--profile <NAME>` | Apply a named profile from the accepted .scribe/config.toml file |
| `--all` | Select the entire repository; conflicts with --view and --profile |

At least one selection option is required. `--profile` and `--view` can be
combined. `remove` cannot carve an exception from a broader inclusion or remove
the last prefix. The active selection and watermark advance only after the
transition completes. Resume an interrupted transition with `scribe sync` or
`workspace view --continue`; opened exclusions must be reverted or the
transition abandoned with `workspace view --abort`. Displaced files are
retained in recovery, including clean files, and each is announced on stderr
as `preserved PATH at RECOVERY`. See [views and profiles](/docs/workspace-views.md).

## workspace mounts

List versioned repository mounts at the current branch head without probing targets

```text
scribe workspace mounts [OPTIONS]
```

No command-specific options; global and parent-group options still apply.

Lists versioned mount declarations at the current branch head without contacting
target repositories. Selection follows the saved workspace view. Use `scribe sync`
to materialize selected mounts and check target access. See
[repository mounts](/docs/repository-mounts.md).

## workspace trust-history

Establish a new history anchor after inspecting a restored or replaced repository

```text
scribe workspace trust-history [OPTIONS] --accept-current
```

| Argument or option | Meaning |
| --- | --- |
| `--accept-current` | Explicitly trust the currently connected repository head; local files are preserved |

Explicitly trust the connected repository's current history for this workspace
branch after inspecting a restore or replacement authority. This persists a new
commit/incarnation anchor and invalidates the old verified baseline. It changes
no working files or sync watermark. Subsequent sync proves the replacement state
and preserves local work through normal recovery rules.

Ordinary workspace creation establishes first-contact trust. Sync and workspace
head checks refuse rollback, incarnation changes and parent chains that do not
reach the saved anchor. A check processes at most 4,096 envelopes, saves progress,
and asks you to retry if more remain. Backward sync changes materialized state
without moving the trusted head backward. Proof pages shrink automatically to fit
bounds; an unprovable single-entry page fails explicitly before applying files.

## project

Coordinate a parent workspace and its selected repository mounts

```text
scribe project [OPTIONS] <COMMAND>
scribe project status [OPTIONS]
scribe project sync [OPTIONS]
scribe project update [OPTIONS] <NAME>
scribe project publish [OPTIONS]
```

| Command and option | Behavior |
| --- | --- |
| `status` | Offline component status from working-copy mount declarations |
| `status --scan` | Include tracked and untracked discovery in each local component |
| `status --verify` | Hash bytes; implies `--scan` |
| `status --remote` | Check selected repositories independently; report heads and locks |
| `sync --revision <REVISION>` | Optional exact parent revision; otherwise use ordinary sync's saved target/head rules |
| `update <NAME> --revision <REVISION>` | Stage this mount's pin; default is its local sync/submission revision, never remote head |
| `publish -m, --message <MESSAGE>` | Prepare opened work, submit selected children, then submit the parent with confirmed pins |
| `publish --continue` | Recover the saved publication using its original operation IDs |
| `publish --abort` | Resolve transmitted outcomes and release unsent work; preserve accepted history and local edits |

Publication requires exactly one of `--message`, `--continue`, or `--abort`.
Pin update edits the parent's tracked `.scribe/config.toml` under ordinary lock
rules; it does not submit. Pending publication blocks ordinary participant
mutations until root recovery finishes. Unselected children need no remote access.
See [project workflows](/docs/project-workflows.md) for precise preparation,
selection, rejection, restore, and unknown-outcome behavior.

## edit

Open tracked files for edit; acquire required locks unless --offline

```text
scribe edit [OPTIONS] [PATHS]...
```

| Argument or option | Meaning |
| --- | --- |
| `[PATHS]...` | Files inside the workspace |
| `--offline` | Open locally without a server connection; reconcile locks and revisions later |

See [offline work and reconciliation](/docs/client-usage.md#offline-work-and-reconciliation).
Refused while a merge or other conflict resolution is active; see
[opening files](/docs/client-usage.md#opening-files).

An online `edit` also looks at the current lock holders once the files are
opened: a path another workspace holds, whether or not the policy requires a
lock there, is reported on stderr as `warning: PATH is locked by AUTHOR
(workspace ID); submit will be refused until it is released`. The file stays
opened; the warning exists so the refusal does not first appear at submit.
`--offline` makes no such check.

## reconcile

Check opened files against server revisions and acquire required locks

```text
scribe reconcile [OPTIONS]
```

| Argument or option | Meaning |
| --- | --- |
| `--scan` | Verify tracked contents and open discovered edits; report missing and untracked paths |

File contents and baselines are preserved. Exit 0 means all opened paths passed
at the checked revisions; exit 1 returns a per-path report of blockers. The
server rechecks on submit. See the [workflow guide](/docs/client-usage.md#offline-work-and-reconciliation).

## move

Move a tracked file or folder to an exact new path, preserving history

```text
scribe move [OPTIONS] [SOURCE] [DESTINATION]
```

| Argument or option | Meaning |
| --- | --- |
| `[SOURCE]` | Existing file or folder, including destinations of earlier pending moves |
| `[DESTINATION]` | Exact destination path (must not already exist) |
| `--id <ID>` | Select a pending move from status (otherwise interrupted, then latest) |
| `--continue` | Resume an interrupted move |
| `--abort` | Undo an unsubmitted move, preserving current file contents |
| `--after` | Record a rename already done outside Scribe: SOURCE is gone and DESTINATION holds the file, edited or not |
| `--detect` | Pair missing tracked files with untracked files holding exactly their recorded bytes, and record each pair as a move |
| `--dry-run` | With `--detect`, report the pairs without recording them |

Provide both SOURCE and DESTINATION for a new move. Omit them with `--continue`, `--abort`, or `--detect`; those actions are mutually exclusive. `--id` requires `--continue` or `--abort`. Destination must be an exact, absent path. Moves remain pending until submit.

With `--after`, SOURCE must be a tracked file that is already gone and DESTINATION an untracked regular file that is present; its bytes may differ from SOURCE's. It prints `Recorded move A -> B (1 tracked files, move ID)`.

`--detect` prints `would move A -> B` (dry run) or `moved A -> B (move ID)` per
pair and `unpaired PATH: reason` for every missing tracked file it could not
pair uniquely, then suggests `move --after` for those; `--json` returns `dry_run`, `moves` (`source`, `destination`,
`size`, `id` once recorded), `unpaired` (`path`, `reason`) and `hashed`. See
[moving files](/docs/client-usage.md#move-files-and-folders).

## add

Open new files for add (directories recurse, honoring ignore rules)

```text
scribe add [OPTIONS] [PATHS]...
```

| Argument or option | Meaning |
| --- | --- |
| `[PATHS]...` | Files or directories inside the workspace |
| `--force` | Add even if ignored (does not override containment or the reserved .scribe/_state) |
| `--offline` | Record the add locally without contacting the server or acquiring locks |

Refused while a merge or other conflict resolution is active; see
[opening files](/docs/client-usage.md#opening-files).

The add is recorded locally first. The paths just opened are then checked as
`reconcile` would check them, for those paths only: a lock the policy requires
is acquired, as `edit` acquires it, and a file already at that path on the
server is reported. Findings are printed as warnings and leave the exit status
alone; `submit` enforces them either way. A server that cannot be reached, a
missing session, or a pending submit skips the check with its reason, and the
add stands as pending reconciliation. `--offline` records the add without
trying the server, so it never waits on one that is down or behind a lost VPN.

A file named on the command line that is skipped (ignored, already tracked,
already opened, outside the view, a link) is reported as `skipped PATH: reason`
and the command exits 1 after printing the report. Files skipped while
recursing into a named directory are the documented ignore behavior and leave
the exit status 0.

## delete

Open tracked files for delete and remove them locally

```text
scribe delete [OPTIONS] [PATHS]...
```

| Argument or option | Meaning |
| --- | --- |
| `[PATHS]...` | Tracked files inside the workspace |
| `--force` | Delete even if locally modified (a copy is kept under .scribe/_state/recovery) |
| `--offline` | Record the deletion locally without contacting the server or acquiring locks |

Refused while a merge or other conflict resolution is active; see
[opening files](/docs/client-usage.md#opening-files). The deletion is recorded
locally first, then checked as for [add](/docs/reference/cli/scribe.md#add): a lock the policy requires is
acquired, as `edit` acquires it, and a newer revision of the file on the server
is reported. `--offline` records the deletion without trying the server.

The opened deletion is recorded before the local file is removed (to
`.scribe/_state/recovery`, including files that equal the recorded base), so an
interrupted delete can be completed by repeating it or undone with `revert`. A
locally modified file is refused without `--force` and reported under `skipped`
while the other paths are still opened. A copy kept in recovery is announced on
stderr as `preserved PATH at RECOVERY`, the same notice `revert` and `sync`
print (summarized to a count above ten files); stdout carries only the
command's report. `scribe recovery list` maps entries back to their paths.

## revert

Restore opened files to their workspace base

```text
scribe revert [OPTIONS] [PATHS]...
```

| Argument or option | Meaning |
| --- | --- |
| `[PATHS]...` | Opened files; their local contents are kept under .scribe/_state/recovery first |

The local file being replaced is kept in recovery whether or not it was
modified. A preserved copy is announced on stderr as `preserved PATH at RECOVERY`.

## diff

Show unified diffs of opened text files against their baseline or a revision

```text
scribe diff [OPTIONS] [PATHS]...
```

| Argument or option | Meaning |
| --- | --- |
| `[PATHS]...` | Files inside the workspace (default: every opened file) |
| `--revision <CHANGE>` | Compare against this accepted change on the workspace branch instead of the file's baseline |

Read-only: nothing is opened, locked, or written, and the working copy's
baseline, opened intent, and sync watermark are untouched. Without paths every
opened file is compared; a named path must be opened or tracked unless
`--revision` selects accepted history for it. The baseline bytes come from the
server (through the local object cache), so the command needs a connection.
Files opened for add compare against `/dev/null`, deletions against the
baseline. A pending move compares the destination with its origin's baseline.

Output is the usual unified format, three lines of context, one `--- a/PATH` /
`+++ b/PATH` header per changed file; unchanged files print nothing. A file on
either side above the review bound (2 MiB) prints `PATH: too large to diff`; a
file with a NUL byte in its first 8 KiB prints `Binary files a/PATH and b/PATH
differ`. The exit status is 0 whether or not differences exist; a path that is
neither opened nor tracked is a usage error. `--json` lists every compared
file with `status`, `added`, `removed`, and the hunks in `diff`; see
[JSON output](/docs/json-output.md#diffs).

```sh
scribe diff
scribe diff Source/Player.cpp
scribe diff --revision 41 Source/Player.cpp
```

## status

Inspect changes and unfinished work in the current workspace

```text
scribe status [OPTIONS]
```

| Argument or option | Meaning |
| --- | --- |
| `--remote` | Also query branch head, active main-branch lock rules, and current holders |
| `--scan` | Also report tracked-but-unopened modifications, deletions, and untracked files |
| `--verify` | Hash contents instead of trusting fingerprints (implies --scan) |

Default status is local and limits file inspection to opened/workflow paths.
`--scan` widens discovery. Rows combine local state, moves, reconciliation,
resolution groups, deferred updates, and optional locks. `--remote` failure
retains the local report, marks remote state unavailable, and exits 1. Local
inspection or ignore-rule problems also exit 1; changes/conflicts alone do not.
See [unified status](/docs/client-usage.md#status-and-scanning).

The header names the workspace, repository, and branch, the sync watermark, and
what was scanned (`scanned: opened paths only ...` without `--scan`). The
branch is shown by name with `--remote`, which asks the server; the local
report shows the id, since a workspace stores only that. After the rows, a
`Summary:` line counts paths by intent (`3 opened for add, 1 opened for
edit, ...`) and `Next:` lines suggest the following step: `scribe submit` when
files are opened and no workflow is pending, `scribe reconcile` only when an
edit was opened offline, otherwise the pending workflow's `--continue` /
`--abort` command.

## scan

Discover changes across the workspace (same as status --scan)

```text
scribe scan [OPTIONS]
```

| Argument or option | Meaning |
| --- | --- |
| `--verify` | Hash contents instead of trusting fingerprints |

## submit

Submit opened file changes together as one changeset (default: all opened files)

```text
scribe submit [OPTIONS] --message <MESSAGE> [PATHS]...
```

| Argument or option | Meaning |
| --- | --- |
| `-m, --message <MESSAGE>` | Change description |
| `--keep-locks` | Retain locks on submitted files after a successful submit |
| `[PATHS]...` | Exact opened files to submit; omit to submit all. Moves include their complete group |

`--message` / `-m` is required. If the outcome is unknown, keep the pending state and rerun submit to resolve it; do not invent a replacement operation.

```sh
scribe submit -m "Fix movement" -- Source/Player.cpp Source/Movement.cpp
```

Paths are relative to the current directory (absolute paths inside the workspace
also work). Each must name an exact opened file, including a deleted file's former
path. Directories and unopened paths are refused before publishing anything;
duplicates are collapsed. Unselected files retain their contents, opened state,
baselines, locks, and pending moves. Paths cannot cross into a mounted workspace.

Selecting either endpoint of a move includes its entire move group, including
folder moves and dependent rename chains. A merge, cherry-pick, or active conflict
resolution must be submitted in full: omit paths. After an unknown outcome, any
new message or path selection is ignored while the original saved candidate is
resolved; that invocation does not start another submission.

A submit above the server's per-submit change-set cap is refused with
`limit_exceeded`, naming the entry count, the cap, and the configuration key.
For a first population of a repository, use [import](/docs/reference/cli/scribe.md#import); the cap is not
raised for ordinary work, because a single acceptance holds the repository
publication gate for its whole duration.

A successful submit releases your locks on submitted paths by default. Rejected
submits and locks on other paths are unchanged. Recovery uses the saved choice.

## import

Populate a repository from an existing tree as a sequence of changes, each within the server's per-submit cap

```text
scribe import [OPTIONS] --message <MESSAGE>
```

| Argument or option | Meaning |
| --- | --- |
| `-m, --message <MESSAGE>` | Description recorded on every change this import creates |
| `--batch-size <N>` | Entries per change (default: the cap the server advertises) |
| `--dry-run` | Report how many changes the import would create, without submitting |

Open the tree first with `scribe add`, then run `import`. It submits the opened
adds in path order as a sequence of changes, each no larger than the server's
`max_submit_entries`, which it reads from the server handshake rather than
assuming. A batch the server still refuses as oversize is halved and re-sent
under a fresh operation id, so a lower cap or a gateway default cannot strand
the import. Every change carries the message verbatim.

`import` accepts only adds. An opened edit, delete, keep, or move destination is
refused, naming the path: splitting a change set that contains a rename could
publish an intermediate change in which the moved file exists nowhere, and
rename pairs can be arbitrarily large, so no batch size makes that safe. Submit
such work with [submit](/docs/reference/cli/scribe.md#submit), which stays atomic. This is also why there is
no `submit --split`.

Each batch is an ordinary submit, so its operation id is persisted before
transmission and an unknown outcome is resolved by asking the server, never
guessed. Re-run `import` after any interruption: it resolves the batch that was
in flight, then continues with the paths the server has not accepted. A run with
nothing left to import succeeds and reports that it is already complete, so the
command is safe to repeat until it does.

The plan — file count, change count and batch size — is written to stderr before
the first change is sent, and each accepted change as it lands. `--dry-run`
reports the same plan and sends nothing.

## sync

Sync the workspace and selected mounts (default: head, mounts at recorded pins)

```text
scribe sync [OPTIONS]
```

| Argument or option | Meaning |
| --- | --- |
| `--revision <CHANGE>` | Pinned change number, including an older revision |

Defaults to the verified branch head. Older revisions use verified backward
changes when a verified baseline is available; otherwise sync proves a full
snapshot. Opened paths are deferred; displaced files go to `.scribe/_state/recovery`.
The sync watermark and applied proof binding advance together only when the
journal is fully applied. The trusted history pin remains at the newest verified
head. Restored incarnations require [explicit acceptance](/docs/reference/cli/scribe.md#workspace-trust-history).

## get

Download one file at a pinned revision without changing workspace state

```text
scribe get [OPTIONS] --revision <CHANGE> --to <FILE> <PATH>
```

| Argument or option | Meaning |
| --- | --- |
| `<PATH>` | Exact repository-relative path at the requested revision (independent of current directory) |
| `--revision <CHANGE>` | Pinned changeset number on the selected branch |
| `--to <FILE>` | New destination file; parent directory must exist; existing entries are never replaced |
| `--repo <REPO>` | Repository name or id (required outside a workspace; defaults to the workspace repository) |
| `--branch <BRANCH>` | Branch name or id (defaults to workspace branch, or main with --repo) |

See [downloading one historical file](/docs/client-usage.md#downloading-one-historical-file)
for revision selection, verification, and interruption behavior.

## export

Export a pinned change into an empty directory (no workspace state)

```text
scribe export [OPTIONS] --revision <CHANGE> --to <DIR>
```

| Argument or option | Meaning |
| --- | --- |
| `--revision <CHANGE>` | Change number to export |
| `--to <DIR>` | Empty destination directory |
| `--repo <REPO>` | Repository name or id (default: the current workspace's) |
| `--view <PREFIX>` | Restrict to these directory prefixes |

`--revision` and `--to` are required. Outside a workspace, also select `--repo`. Repeat `--view` for multiple prefixes. The destination must be empty; export creates no workspace state.

## log

Show history (of a path when given)

```text
scribe log [OPTIONS] [PATH]
```

| Argument or option | Meaning |
| --- | --- |
| `[PATH]` | Restrict history to this path |
| `--first-parent` | Exclude merge-source history for this path (branch origins are retained) |
| `--all-branches` | Discover related revisions on every branch, including unmerged work |
| `--at <CHANGE>` | Pin all-branch history to this repository change (reuse history_snapshot when paging) |
| `--limit <LIMIT>` | Maximum entries, newest first [default: 20] |
| `--before <CHANGE>` | Only changes strictly before this change number |
| `--after-path <AFTER_PATH>` | Continue after this historical path within --before (use the last log row) |

`--first-parent` and `--all-branches` require PATH and conflict with each other.
`--at` requires `--all-branches`. The all-branch view selects the file incarnation
at that snapshot and labels each row by commit ancestry. Reuse its reported
`history_snapshot` with `--at` for stable continuation. See
[cross-branch history](/docs/client-usage.md#cross-branch-file-history).
`--after-path` requires both PATH and `--before`; pass the last row’s change and historical path together to retain tied history entries. `--limit` defaults to 20.

Each row shows the change's current description: the message it was submitted
with, or the latest correction recorded with [`describe`](/docs/reference/cli/scribe.md#describe), marked
with who revised it and when. `--json` carries both as `message` and `note`
(null when never corrected) and reports `notes_available`, which is false
against a server that predates descriptions.

## describe

Correct the description of an accepted change, or show its revisions

```text
scribe describe [OPTIONS] <CHANGE>
```

| Argument or option | Meaning |
| --- | --- |
| `<CHANGE>` | Change number |
| `-m`, `--message <TEXT>` | New description; the change keeps its submitted message |
| `--expect <REVISION>` | Only apply when the description is still at this revision (default: the current one, read first) |
| `--history` | List every recorded description of the change instead |

The commit and its message are never rewritten: a description is appended to
the change's journal on the server, `log` shows the latest one in place of the
message, and `--history` lists every revision with its author and time. The
server attributes each revision to the signed-in principal. A writer may
describe their own changes; anyone else's need a maintainer. `--expect` refuses
with `note_revision_stale` when someone described the change in the meantime,
so a retry after a lost reply never records a duplicate. Servers older than
the description journal refuse the command as `unsupported_version`.

## info

Show local and server state of a path

```text
scribe info [OPTIONS] <PATH>
```

| Argument or option | Meaning |
| --- | --- |
| `<PATH>` | File inside the workspace |

## lock

Acquire, release, and inspect repository-wide file locks and rules

```text
scribe lock [OPTIONS] <COMMAND>
```

Subcommands: [acquire](/docs/reference/cli/scribe.md#lock-acquire), [release](/docs/reference/cli/scribe.md#lock-release),
[list](/docs/reference/cli/scribe.md#lock-list), [rules](/docs/reference/cli/scribe.md#lock-rules). Ordinary `edit` already acquires required
locks; use `lock acquire` when reserving a path explicitly.

## lock acquire

Acquire exclusive locks across all branches, held until explicitly released

```text
scribe lock acquire [OPTIONS] <PATHS>...
```

| Argument or option | Meaning |
| --- | --- |
| `<PATHS>...` | Files to lock, including new paths that will be added |

## lock release

Release locks held by this workspace, or force release with permission

```text
scribe lock release [OPTIONS] <PATHS>...
```

| Argument or option | Meaning |
| --- | --- |
| `<PATHS>...` | Locked files; with --repo, exact repository-relative paths |
| `--repo <REPO>` | Repository name or id for remote administration; requires --force |
| `--force` | Release a lock held by another workspace |

`--repo <REPO>` permits forced unlock without a local workspace and requires
`--force`. Paths are then exact repository-relative paths. Maintainer permission
is required on authenticated servers, even for the caller's own lost workspace;
without auth, any connected client may force-unlock. Generation checks still
apply. See [workspace administration](/docs/workspace-administration.md).

## lock rules

Show active main-branch lock rules, or explain one path

```text
scribe lock rules [OPTIONS] [PATH]
```

| Argument or option | Meaning |
| --- | --- |
| `[PATH]` | Optional file path to explain under the server's active policy |

## lock list

List current lock holders

```text
scribe lock list [OPTIONS]
```

| Argument or option | Meaning |
| --- | --- |
| `--repo <REPO>` | Repository name or id; permits listing without a local workspace |
| `--prefix <DIR>` | Only locks below this directory prefix [default: ""] |

`--repo <REPO>` lists locks without a local workspace. Otherwise the current
workspace selects the repository. Listing requires repository read access with
auth. Remote administration works directly or through a gateway.

## ignore

Ignore-rule tools

```text
scribe ignore [OPTIONS] <COMMAND>
```

Subcommands: [explain](/docs/reference/cli/scribe.md#ignore-explain).

## ignore explain

Explain why a path is or is not ignored

```text
scribe ignore explain [OPTIONS] <PATH>
```

| Argument or option | Meaning |
| --- | --- |
| `<PATH>` | Path inside the workspace |

## recovery

List and prune files retained under .scribe/_state/recovery

```text
scribe recovery [OPTIONS] <COMMAND>
```

Subcommands: [list](/docs/reference/cli/scribe.md#recovery-list), [prune](/docs/reference/cli/scribe.md#recovery-prune).

Sync, revert, delete and resolution move every local file they replace or
remove into `.scribe/_state/recovery`, even when its bytes equal the recorded
base. Nothing is pruned automatically.

## recovery list

List retained entries with their original path, reason, and time

```text
scribe recovery list [OPTIONS]
```

## recovery prune

Remove retained entries; intent archives and unreadable entries are kept

```text
scribe recovery prune [OPTIONS]
```

| Argument or option | Meaning |
| --- | --- |
| `--older-than <DURATION>` | Only entries retained longer ago than this (for example 30m, 12h, 7d, 2w) |
| `--all` | Every retained entry regardless of age |

One of `--older-than` or `--all` is required. Entries kept are named with the
reason: an intent archive, an unreadable index, or an entry newer than the
cut-off.

## Use cases

### Change the transfer preference

Inside an existing workspace:

```sh
scribe workspace config --compression lz4
scribe --transfer-compression none sync
scribe workspace info
```

The override affects only this sync; the saved preference stays LZ4.

### Inspect history

```sh
scribe log Assets/Hero.uasset --limit 10
scribe log Assets/Hero.uasset --all-branches --limit 10
scribe get Assets/Hero.uasset --revision 42 --to ./Hero-at-42.uasset
```

Use a revision and historical path from your repository. To continue a
cross-branch history page, retain its snapshot and cursor; see
[file history](/docs/client-usage.md#cross-branch-file-history).

For a complete creation/submit/sync exercise, follow the
[minimal-server tutorial](/docs/tutorials/01-minimal-server.md). The
[auth tutorial](/docs/tutorials/02-add-auth.md) adds login and grants.

## Output and exit codes

| Exit | Meaning |
| --- | --- |
| 0 | Success |
| 1 | User or semantic error |
| 2 | Invalid CLI arguments or refusal to destroy local data |
| 3 | Submit outcome unknown; preserve pending state and retry submit |
| 4 | Integrity failure |
| 5 | Transport or storage failure |

Status/scan return 1 with their available report when local inspection or
discovery is incomplete. `status --remote` also returns 1 with the local report
and remote state `unavailable` when enrichment fails, including transport
failures. Changes or conflicts alone do not cause a nonzero status exit.
Reconciliation returns 1 when its report contains blockers. `merge` and
`cherry-pick` return 1 with their report while paths remain unresolved. `add`
returns 1 after its report when a file named on the command line was skipped.
In each of these cases the report is the only stdout document; no error object
follows it. See the [status workflow](/docs/client-usage.md#status-and-scanning).

Notices about preserved local contents (`preserved PATH at RECOVERY`) and
warnings such as a foreign lock observed by `edit` go to stderr without the
`scribe:` error prefix; stdout is reserved for the command's result.

A failure prints one `scribe: MESSAGE` line on stderr. A server-side refusal
shows its detail followed by the stable code name in parentheses, for example
`scribe: permission denied (forbidden)`; the numeric code appears only in the
`--json` error object (`"error": "forbidden (9): permission denied"`,
`"code": "forbidden"`). See [JSON output](/docs/json-output.md#errors-help-and-exit-codes).

`--json` selects machine-readable stdout results; diagnostics stay separate.
See [JSON output](/docs/json-output.md) for schemas, help, and error behavior, and
[logging](/docs/logging.md) for filters, sinks, timing events, and build features.
