Getting Started

Install kutl, create a space, and start syncing files between machines. This takes about five minutes.

1. Install kutl

brew install kutl-io/tap/kutl

Homebrew is the recommended install. The source option builds the CLI from a clone and requires a Rust toolchain. Either way you get the kutl CLI. The relay is a separate component (the kutl-relay binary, built on its own, or the published Docker image), covered in the next step.

2. Start a relay

The relay is the server that coordinates sync between participants. Authentication is always on: the relay only admits DIDs listed in its authorized-keys file, a plain text file you edit like SSH's authorized_keys, one DID per line, live-reloaded. Clients prove their DID automatically, so there is no login step. An empty file is fine to boot with (your identity doesn't exist until step 3; you'll allowlist it there):

export KUTL_RELAY_AUTHORIZED_KEYS_FILE=~/kutl-relay/authorized_keys
mkdir -p ~/kutl-relay && touch $KUTL_RELAY_AUTHORIZED_KEYS_FILE
kutl-relay

The relay binds to loopback and listens on ws://127.0.0.1:9100/ws by default. That is also the URL kutl init and kutl join connect to, so no --relay flag is needed during development. See Self-Hosting a Relay for network-reachable and production deployment.

Prefer Docker? A multi-arch image is published at ghcr.io/kutl-io/kutl-relay:

# your DID is printed by `kutl status`
echo 'did:key:z6Mk...' >> ./authorized_keys

docker run --rm -p 9100:9100 \
  -e KUTL_RELAY_AUTHORIZED_KEYS_FILE=/etc/kutl/authorized_keys \
  -v "$PWD/authorized_keys:/etc/kutl/authorized_keys:ro" \
  ghcr.io/kutl-io/kutl-relay

See Running in Docker for compose files, persistent volumes, and network-reachable deployment.

3. Initialize a space

A space is a named sync context: a directory whose contents sync with the relay. Create one inside your project:

cd /path/to/your/project
kutl init --name my-project

This creates a .kutlspace file (team config, safe to commit), a .kutl/ directory (local state), a .gitignore that keeps the space's synced files out of git, and your DID identity at ~/.kutl/identity.json if you don't have one yet. Inside a git repo, init prompts for a subfolder name (default kutl, or pass --subfolder) so synced documents stay separate from your code.

The --name flag registers a human-readable name with the relay. Other users will use this name to join. If you omit it, a name is generated automatically.

Now that your identity exists, allowlist it on the relay:

did=$(kutl status --format json | jq -er .identity.did) \
  && echo "$did" >> "$KUTL_RELAY_AUTHORIZED_KEYS_FILE"

The relay live-reloads the file, so you don't need to restart it.

4. Start the daemon

The daemon watches your files and syncs changes with the relay in the background:

kutl daemon start

You can also run it in the foreground with kutl daemon run to see logs directly. Check status with kutl status.

5. Join from another machine

On a second machine (or in a second directory), join the space by name, then allowlist that machine's identity:

kutl join my-project --relay ws://relay.example.com:9100/ws
# joining minted this machine its own DID — read it, then append it
# to the authorized-keys file on the RELAY host:
kutl status --format json | jq -r .identity.did

kutl daemon start

If the relay is running on localhost, you can omit the --relay flag since it defaults to ws://127.0.0.1:9100/ws.

Each machine authenticates as its own DID. Joining works before the allowlist entry exists (space discovery is open); syncing starts once the DID line lands. The file is live-reloaded, so the relay does not need a restart.

6. Edit and sync

Create or edit files inside the space directory. Changes sync automatically through the daemon. Any editor, script, or agent that reads and writes files becomes a sync participant. You never commit, push, or merge by hand.

One-shot sync

If you don't want a background daemon, you can sync once and exit:

kutl sync

This pushes local changes, pulls remote changes, and exits. Useful for CI pipelines or scripts.

Next steps