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/kutlHomebrew 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-relayThe 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-relaySee 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-projectThis 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 startYou 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 startIf 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 syncThis pushes local changes, pulls remote changes, and exits. Useful for CI pipelines or scripts.
Next steps
- Concepts : how spaces, relays, and CRDTs fit together
- CLI Reference : every command and flag
- Self-Hosting a Relay : production deployment with authentication
- Conflict Behavior : how concurrent edits and renames are resolved
- Troubleshooting : common issues and how to fix them