1. Start with one server
Documentation/Start here
1. Start with one server5 min read

1. Start with a minimal server

On this page

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:

sh
scribe-ctl --version

In 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:

sh
umask 077
mkdir scribe-demo
cd scribe-demo

All 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:

sh
scribe-ctl --config scribe-cluster.toml setup --variant storage --plan
text
Scribe · 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:

sh
scribe-ctl --config scribe-cluster.toml setup --variant storage
scribe-ctl --config scribe-cluster.toml up
text
Scribe · 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-20260927T124201

up 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.toml describes the cluster: one storage server named storage-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-a is the authoritative store for every repository this server holds: history, file contents, and metadata. Setup ran scribe-server init once to create it empty. Nothing ever initializes it again; up only opens it, and one process at a time owns it.

  • The binary set. Setup copied the executables it found beside scribe-ctl into cluster-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 with upgrade.

  • The summary. CLUSTER-INFO.txt lists every file the cluster uses and what it is for, the endpoints, and the next commands. scribe-ctl --config scribe-cluster.toml where prints 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

sh
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 alice

The 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:

sh
(
  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
)
text
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 hero

A 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

sh
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:

text
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 hero

Both 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

sh
scribe-ctl --config scribe-cluster.toml down
scribe-server usage --data-dir ./data/storage-a
scribe-server doctor --data-dir ./data/storage-a --quick

down 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:

text
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 ms

The 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.

Source docs/tutorials/01-minimal-server.mdSnapshot 2b8dcccb