scribe-ctl provisions and supervises one optional auth service and any number
(up to 256) of local storage services from TOML. It runs native Scribe binaries;
OpenSSL 3 is needed when generating certificates.
Build with cargo build --release --locked. Keep scribe-ctl, scribe-auth,
and scribe-server together. On macOS, ~/.local/bin is a convenient per-user
installation directory when added to PATH; the client scribe can live there
too. This does not install a launchd job or arrange startup after reboot.
Without --config, the controller reads scribe-cluster.toml beside its
executable. An explicit config is usually easier for separate clusters:
scribe-ctl example > ./scribe-cluster.toml
# Create accounts.toml and its referenced password files before init.
scribe-ctl --config ./scribe-cluster.toml init
scribe-ctl --config ./scribe-cluster.toml up
scribe-ctl --config ./scribe-cluster.toml status
scribe-ctl --config ./scribe-cluster.toml logs auth --lines 50
scribe-ctl --config ./scribe-cluster.toml downThe complete cluster template is example.toml.
All relative paths in it resolve against the config directory. Binary paths
can be overridden with [binaries], using auth and storage keys. Otherwise,
binaries are located beside scribe-ctl.
Accounts and pepper
The separate accounts_file contains password-file references, never inline
passwords. Password paths resolve against the accounts file's directory:
[[users]]
name = "alice"
password_file = "passwords/alice"
administrator = false
[[users]]
name = "operator"
password_file = "passwords/operator"
administrator = trueUse private password files containing 12–1024 UTF-8 bytes; the existing auth
password reader handles a trailing line ending. Keep this file and secrets out
of version control. Omit accounts_file if no account bootstrap is wanted.
init explicitly creates a missing auth database, writing its required pepper
to auth.pepper_file and initial admin token to auth.admin_token_file. It
passes the pepper file to every auth service startup. Existing auth databases
require their original pepper: the controller never regenerates a missing
pepper for an existing database. Retain and back up the pepper separately from
the database as described in auth.md.
init also registers authenticated storage identities and writes their service
tokens, then bootstraps users. Repeat runs skip existing users without reading
their password files or changing their password, administrator status, or enabled
state. The initial admin account is consequently left unchanged too.
scribe-ctl --config ./scribe-cluster.toml bootstrap-usersThis command can add accounts while the cluster runs. When stopped, it starts
auth temporarily and drains it afterward. Bootstrap operation IDs and password
commitments are persisted under state_dir/bootstrap-users before requests are
sent. An interrupted bootstrap resumes the same operations and checks user
identity before setting a password. Preserve those records and the original
password/configuration while an operation is pending. They contain no plaintext
passwords. Account removal and password rotation remain explicit auth admin
operations; removing a user from this file does not delete an account.
The admin token is required for provisioning and account bootstrap; ordinary
up needs the pepper and service tokens, but does not read the admin token.
Certificates and topology
certificates.generate_missing = true permits init or certs to create a
missing CA and missing leaf certificate/key pairs. Existing PEMs are preserved
and leaf pairs are validated. A partial pair is refused: preserve/move the
surviving file before explicitly regenerating the pair. This also applies to
incomplete CA material. Certificates are never silently rotated on up.
scribe-ctl --config ./scribe-cluster.toml certsThis requires the cluster stopped. Default generated SANs cover localhost,
IPv4/IPv6 loopback, and the concrete listen IP. Set dns and/or ip arrays in
a service's tls table for other names; explicit arrays replace these defaults.
auth.ca can select an existing trust bundle; by default the controller uses
certificates.ca_dir/ca.pem.
Auth requires TLS and a fixed, nonzero listen port so bootstrap retries retain
the same endpoint. Authenticated storage requires auth = true, namespace,
token_file, and a tls table. In the current storage adapter TLS is coupled
to auth integration. Standalone storage uses auth = false and no TLS/auth
fields; non-loopback plaintext requires allow_non_loopback = true explicitly.
Storage port zero is allowed, with its assigned endpoint shown by status.
Each data root and the state directory must be distinct and nonoverlapping. Private keys, pepper, and service credentials must be outside data roots. Unknown TOML fields are rejected to catch configuration mistakes.
Lifecycle and diagnostics
init is explicit provisioning; up never initializes data or creates secrets.
daemon = true makes up detach and return once all services report readiness.
The default is foreground. up --daemon and up --foreground override TOML.
In foreground mode, Ctrl-C requests graceful shutdown.
The supervisor starts auth first, followed by storage. It drains storage before
auth during normal shutdown. Startup failures and unexpected service exits
trigger cleanup of the other children. There is no automatic restart policy.
Service output is appended to state_dir/logs/<service>.log; detached supervisor
output is in supervisor.log. logs prints a bounded tail, not a live stream.
These files are not automatically rotated.
status --json returns machine-readable runtime state. Status is read-only.
Exclusive locks prevent duplicate controllers and conflicting data-root owners.
If the supervisor is lost, status reports unmanaged services; down can still
request shutdown using their unique runtime directories. Saved PIDs are only
informational and are never signalled.
startup_timeout_secs defaults to 30 (allowed range 1–300), applies per service
on startup, and bounds how long down waits. A shutdown timeout reports that
services are still draining; it never force-kills a durable commit. Leave the
supervisor running and retry status/down. Configured binaries must implement
Scribe's readiness and cooperative shutdown protocol.
--timings reports controller phases and command duration to stderr;
--log-format json selects structured diagnostics. Service logs remain separate.
Timing support is compiled in by default. Building this executable with
cargo build -p scribe-ctl --no-default-features --locked compiles out its timing
scopes and makes --timings return an error.
An optional scribe-gateway can provide one client endpoint for several existing storage instances. Standalone operation remains supported.