All tutorials · Next: add authentication
You will set up a one-server cluster with scribe-ctl, create a repository,
submit a file from Alice's working copy, and sync it into Bob's. Everything
stays on plaintext loopback; identities here are author labels, not
authenticated users.
Scribe is centralized: submit publishes a durable shared change and sync
brings a working copy up to the server's history. There is no separate push.
1. Install and create the deployment directory
Install the executables from your source checkout (see install) and check that they are on your PATH:
scribe-ctl --versionIn a location for demo data outside the source checkout and any Scribe workspace, create a fresh directory and make everything you create in it private:
umask 077
mkdir scribe-demo
cd scribe-demoAll remaining commands run from this directory. See the terminal and port conventions.
2. Set up the cluster
Look at the plan first. --plan runs every check for real and writes nothing:
scribe-ctl --config scribe-cluster.toml setup --variant storage --planScribe · local · setup plan · storage variant · native runtime
Definition /home/you/scribe-demo/scribe-cluster.toml
Paths below are relative to its directory.
ENDPOINTS
storage-a tcp://127.0.0.1:7447
CHECKS
ok definition setup writes scribe-cluster.toml (storage variant)
ok binaries scribe-ctl, scribe-server 0.1.0 (build 86da462a7d46.dirty-20260927T124201); setup records them as the first binary set in cluster-state/local/bin/86da462a7d46.dirty-20260927T124201
ok permissions 0 existing secret files are private
ok cluster stopped
ok ports 1 listen addresses are free
ok certificates consistent
ok data roots consistent
STEPS
1. Write the cluster definition scribe-cluster.toml
no definition exists yet
2. Install scribe-ctl, scribe-auth, scribe-server, scribe-gateway 0.1.0 (build 86da462a7d46.dirty-20260927T124201) side by side in cluster-state/local/bin/86da462a7d46.dirty-20260927T124201 (from /home/you/.local/bin)
the cluster's executables, kept side by side so an upgrade can return to them
3. Record 86da462a7d46.dirty-20260927T124201 as the active set (bin/current)
the runtime starts services from the set bin/current names
4. Initialize storage storage-a in data/storage-a
no repository store yet
5. Write the cluster summary CLUSTER-INFO.txt
every file the cluster uses, its endpoints and the next commands
Plan only: nothing was written and no lock was taken. Run setup without --plan to apply it.Every check should read ok; a failed one says what it found. Then run it:
scribe-ctl --config scribe-cluster.toml setup --variant storage
scribe-ctl --config scribe-cluster.toml upScribe · local · running
SERVICE STATE PID ENDPOINT
storage-a running 16741 tcp://127.0.0.1:7447
Logs /home/you/scribe-demo/cluster-state/local/logs
Binaries 0.1.0 (build 86da462a7d46.dirty-20260927T124201) · /home/you/scribe-demo/cluster-state/local/bin/86da462a7d46.dirty-20260927T124201up returns once the server is ready; it keeps running in the background under
the controller's supervisor. scribe-ctl --config scribe-cluster.toml status
shows the same table at any time.
What scribe-ctl did for you
-
The definition.
scribe-cluster.tomldescribes the cluster: one storage server namedstorage-a, where it listens, and its data root. Every path in it is relative to the file. It never holds a secret; later stages add to it.toml [clusters.local] variant = "storage" state_dir = "cluster-state/local" daemon = true startup_timeout_secs = 30 [[clusters.local.storage]] name = "storage-a" listen = "127.0.0.1:7447" data_dir = "data/storage-a" auth = false(The file has a comment on every setting.)
-
The data root.
data/storage-ais the authoritative store for every repository this server holds: history, file contents, and metadata. Setup ranscribe-server initonce to create it empty. Nothing ever initializes it again;uponly opens it, and one process at a time owns it. -
The binary set. Setup copied the executables it found beside
scribe-ctlintocluster-state/local/bin/<build>/and records that set as active. The services start from there, so installing a newer build does not disturb a running cluster; stage 4 switches sets withupgrade. -
The summary.
CLUSTER-INFO.txtlists every file the cluster uses and what it is for, the endpoints, and the next commands.scribe-ctl --config scribe-cluster.toml whereprints it, current, at any time.
By hand, the same server is scribe-server init followed by scribe-server serve in a terminal of its own (bare metal, stage 1),
or a container (Docker Compose, stage 1).
3. Create a repository and Alice's working copy
scribe --server tcp://127.0.0.1:7447 repo list
scribe --server tcp://127.0.0.1:7447 repo create game --storage-compression lz4
scribe --server tcp://127.0.0.1:7447 workspace create game ./work/alice-plain --author aliceThe list is empty at first ((no repositories)). game is the repository
name; work/alice-plain is one local working copy. The selected storage
compression is permanent. Network compression is separate and defaults to
none; see the compression guide.
Create and submit a small asset. The parentheses keep your terminal in the deployment directory after these workspace commands finish:
(
cd work/alice-plain
mkdir Assets
printf 'hero mesh v1\n' > Assets/Hero.txt
scribe add Assets/Hero.txt
scribe submit -m "Initial hero"
scribe log
)add Assets/Hero.txt
checked against change 0: ready
submitted change 1 (1 file, 1 of 1 chunks sent, 208 object bytes sent for 13 logical bytes, 3 server flushes)
change 1 branch main 2026-09-27T12:43:32.472Z alice 1 entry
Initial heroA successful submit means the server accepted it durably. If submit reports an unknown outcome, keep the pending workspace state and rerun submit to resolve it.
4. Give Bob a working copy and complete the round trip
scribe --server tcp://127.0.0.1:7447 workspace create game ./work/bob-plain --author bob
(
cd work/bob-plain
scribe sync
cat Assets/Hero.txt
scribe edit Assets/Hero.txt
printf 'hero mesh v2\n' > Assets/Hero.txt
scribe submit -m "Hero v2"
)
(
cd work/alice-plain
scribe sync
cat Assets/Hero.txt
scribe log
)Alice's sync ends like this:
synced change 0 -> 2: 1 updated, 0 deleted, 0 unchanged (13 bytes fetched in 1 batches, 0 chunks from cache, 0 bytes reused locally) [full reconcile]
preserved Assets/Hero.txt at /home/you/scribe-demo/work/alice-plain/.scribe/_state/recovery/1790513013174-1cffdd4024a2ee9afe42f2021ce39c6a
hero mesh v2
change 2 branch main 2026-09-27T12:43:33.029Z bob 1 entry
Hero v2
change 1 branch main 2026-09-27T12:43:32.472Z alice 1 entry
Initial heroBoth copies now contain hero mesh v2. On Alice's sync, the previous local
copy is kept under .scribe/_state/recovery, with its location reported. Keep
recovery contents until you have reviewed them. For how opened paths are
deferred and interrupted updates resume, see
syncing.
5. Stop and check the data root
scribe-ctl --config scribe-cluster.toml down
scribe-server usage --data-dir ./data/storage-a
scribe-server doctor --data-dir ./data/storage-a --quickdown drains the server: it finishes started durable work before exiting.
The offline checks need the data root to themselves, so they run only after
down:
REPOSITORY ID HEAD PATHS BRANCHES OBJECTS LOOSE PACKED METADATA TOTAL LAST COMMIT
game 689a965e479c 2 1 1 8 0 B 1 KiB 612 KiB 623 KiB 2026-09-27T12:43:33Z bob
...
doctor: healthy (1 repositories, 0 problem(s), 0 warning(s)) in 2 msThe check is read-only; it does not repair data. For a full byte check, omit
--quick.
You can stop here: scribe-ctl --config scribe-cluster.toml up starts the same
server again whenever you need it. To share authenticated access, continue with
2. Add authentication; leave the cluster stopped.