scribe-server [logging options] <command> [options]Logging options on every command: --log-level off|error|warn|info|debug|trace,
--log-filter 'warn,scribe_server=info', --log-format text|json, -v,
-vv, -q. SCRIBE_LOG holds a filter. Default level info. Precedence:
flag, SCRIBE_LOG, [logging].filter in the configuration, default.
Every command except serve and restore accepts either --config FILE or
--data-dir DIR to find the data root. All maintenance commands take the
same exclusive lock as serve, so they refuse to run beside a live server.
init
scribe-server init --data-dir ./server-data --config-out ./server.toml [--listen tcp://127.0.0.1:7447] [--force]Creates an empty data root (descriptor, catalog, repos/, lock file) and
writes a configuration whose paths are relative to the configuration file.
Refuses a non-empty data directory, and refuses to overwrite an existing
configuration without --force.
serve
scribe-server serve --config ./server.toml \
[--data-dir DIR] [--log-dir DIR] [--runtime-dir DIR] [--listen tcp://HOST:PORT] [--allow-non-loopback] \
[--auth HOST:PORT --auth-namespace NS --auth-ca ca.pem --auth-token-file server.token --tls-cert server.pem --tls-key server-key.pem]SCRIBE_SERVER_CONFIG may name the configuration file; flags override it,
and flag paths are relative to the current directory. Startup opens the
descriptor, refuses unknown or newer formats, takes the lock, opens the
catalog and every ready repository (discarding interrupted creations), logs
every resolved path and limit, binds, writes <runtime-dir>/scribe-server.pid
and <runtime-dir>/listen (the bound address, useful with port 0), then
accepts connections.
Two modes:
- Plaintext TCP (no
--authoptions). Anyone who can reach the port can act as anyone. The server refuses a non-loopback listen address unless--allow-non-loopbackorallow_non_loopback = trueis set, and logsserver.plaintext_exposedwhen it is. - TLS with shared authentication. All six auth settings are required
together, and the data root must have been prepared with
auth-init. The socket then serves TLS 1.3 only,listenreportstls://host:port, and every request is authorized per repository. Setup is in auth.md.
Stop with SIGINT, SIGTERM, or touch <runtime-dir>/shutdown-request.
Admission stops and idle connections close. In-flight requests get up to
drain_timeout_secs for network I/O; after that, sockets are interrupted and
started storage jobs finish before exit. A stalled disk can extend shutdown. A forced kill is safe: acknowledged work is durable and the
next start cleans staging and unreferenced pack tails.
Configuration file
[server]
data_dir = "server-data" # relative to this file
log_dir = "logs" # omit for stderr
runtime_dir = "run" # default <data_dir>/run
listen = "tcp://127.0.0.1:7447"
allow_non_loopback = false # plaintext mode only; read docs/operations.md first
[logging]
filter = "info" # or "warn,scribe_server=info,scribe_objects=debug"
format = "text" # or "json" (newline-delimited)
keep_files = 14 # daily files retained in log_dir
[limits]
max_connections = 256
storage_workers = 16 # blocking mutations/transfers; >=2
query_workers = 4 # reserved read queries; >0; total workers <=1024
transfer_workers = 8 # >0 and <storage_workers; reserves control capacity
staging_budget_mib = 512 # bytes admitted into quarantine across all connections
inactivity_timeout_secs = 300
handshake_timeout_secs = 10
drain_timeout_secs = 30
small_object_threshold = 262144 # envelopes at or below this go to packs
pack_seal_mib = 256
[auth] # optional; all six keys together
endpoint = "127.0.0.1:7443"
namespace = "studio"
ca = "ca.pem"
token_file = "storage-a.token"
tls_cert = "server.pem"
tls_key = "server-key.pem"certs
scribe-server certs init-ca --out ./studio-ca [--days 3650]
scribe-server certs issue --ca ./studio-ca --out ./storage-tls --dns vcs.example [--dns ...] [--ip ...] [--days 365]Creates a private CA, or issues a server certificate and key signed by it,
using an OpenSSL 3 executable (--openssl PATH to choose one). Output
directories must be new. scribe-auth certs is the same tool. Lifetimes,
renewal, and what to keep offline are in auth.md.
auth-init, users, permissions
scribe-server auth-init --data-dir ./server-data --namespace studio
scribe-server users --auth HOST:PORT --auth-ca ca.pem --admin-token-file admin.token add|list|disable|enable ...
scribe-server permissions --auth HOST:PORT --auth-ca ca.pem --admin-token-file admin.token set|revoke|list ...auth-init runs offline once per data root: it marks the root with a
required feature so older binaries refuse it, and creates
auth-state.redb, which records workspace and operation ownership. A marked
root can no longer be served in plaintext mode.
users and permissions are conveniences that talk to the auth service
with an administrator token; they are the same commands as scribe-auth users and scribe-auth grants. The storage server's own service token
cannot administer users.
Maintenance
scribe-server doctor --data-dir DIR [--quick] [--threads N] [--repo NAME] [--json] # alias: scan
scribe-server usage --data-dir DIR [--repo NAME] [--json] # alias: df
scribe-server verify --data-dir DIR [--full] [--repo NAME] [--json]
scribe-server backup --data-dir DIR --to EMPTY_DIR
scribe-server restore --from BACKUP_DIR --to EMPTY_DIR
scribe-server export-metadata --data-dir DIR --repo NAME --to FILE.scmx
scribe-server import-metadata --data-dir DIR --repo NAME --from FILE.scmx
scribe-server migrate --data-dir DIR [--dry-run] [--branches | --rollback]- doctor is the routine health check. Read-only, exit 0 healthy, 1
problems found, 2 could not run (for example the root is in use). By
default it re-hashes every object across all cores;
--quickchecks headers and lengths and hashes only manifests, change sets, and commits. It also checks the commit chain, operation records, every live path's manifest and chunks, every historical manifest, both collision indexes,change_pathsagainsthistory, and every pack end to end, and reports interrupted-publication leftovers as warnings. Nothing is ever modified. Run it after any unclean shutdown and before every backup. - usage is the inventory: one line per repository with head change,
live paths, branches, indexed objects, loose/packed/metadata sizes, total
size, and last commit; then the data-root total and the filesystem's free
space. It reads only directory metadata and table lengths, so it finishes
in milliseconds. Interrupted creations, missing or unreadable repositories,
directories the catalog does not know, and staging leftovers get their own
line.
--jsonadds history rows, workspaces, locks, operations, and pack counts. - verify is the single-threaded structural check, kept for scripts;
--fullre-hashes every object.doctorsupersedes it for routine use. - backup copies every durable file with a verified checksum manifest into an empty directory. restore verifies the backup, copies it, assigns new incarnations, and runs structural verification; clients reconcile fully on their next sync.
- export-metadata and import-metadata move one repository's tables
through an engine-neutral checksummed container; import requires the
repository directory to have its objects but no
metadata.redb. - migrate upgrades older repository schemas generation by generation
with checkpoints.
--branchesconverts schema 1 or 2 repositories to schema 3, which serving requires.--rollbackreturns a schema-0-to-1 migration to its retained previous generation only if nothing was accepted since.--dry-runreports without writing.
Procedures and file layouts: migration-backup-restore.md.
Operating notes
- Keep data, logs, and runtime directories separate; only the data directory
needs backup, and it includes
auth-state.redbwhen auth is enabled. - Run one server per data root; a second process fails on the lock.
- Watch
submit.committed,submit.rejected,objects.published, andserver.stopped(which reports dropped diagnostic events) in the logs. Logs are never needed for recovery. - Test builds only:
SCRIBE_FAULT=<point>=crash|failarms fault injection when the binary was built with--features fault-injection.
For TOML-based local cluster startup, pepper provisioning, and idempotent user bootstrap, see the cluster guide.
An optional scribe-gateway can provide one client endpoint for several existing storage instances. Standalone operation remains supported.