Install

Ursula is currently installed from source. Pre-built release binaries are on the way. The build is plain Rust plus the standard C toolchain that Cargo expects — no embedded KV dependency.

Ursula ships two binaries you will use side by side:

  • ursula — the server daemon. Runs on every node in the cluster.
  • ursulactl — the operator CLI. Lives on your control machine and talks to each node's HTTP surface. See ursulactl for the verbs it exposes.

Prerequisites

Required:

  • the pinned Rust nightly toolchain from rust-toolchain.toml and Cargo
  • a C compiler (for transitive native crates)
  • pkg-config

On macOS, install rustup so Cargo selects the pinned nightly from rust-toolchain.toml:

brew install rustup pkg-config
rustup-init -y

On Debian or Ubuntu:

sudo apt-get update
sudo apt-get install -y build-essential pkg-config curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Clone and build

git clone https://github.com/tonbo-io/ursula.git
cd ursula
cargo build --release -p ursula -p ursula-ctl

The resulting binaries land at target/release/ursula and target/release/ursulactl. Ship ursula to every node; keep ursulactl wherever you run operational tooling (laptop, CI runner, bastion host).

To work on the whole workspace:

cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings

cargo build --workspace compiles every crate. For just the server use cargo build -p ursula; for just the CLI use cargo build -p ursula-ctl.

Verify

./target/release/ursula --help
./target/release/ursulactl --help

Both should print supported CLI flags. From the repository root, ./target/release/ursula --preset default still performs config-file discovery and will load ./ursula.toml when present. Use that command when you want the bundled ./ursula.toml with the default preset; for a true no-file smoke test, run from a directory with no Ursula config file or temporarily move/rename ./ursula.toml first.

./target/release/ursula --preset default &

For a single local node, ursulactl needs a one-node manifest to talk to:

cat > /tmp/local.json <<'JSON'
{"nodes": [{"id": 1, "http_url": "http://127.0.0.1:4437", "host": "127.0.0.1"}]}
JSON

./target/release/ursulactl status --config /tmp/local.json

Or, for a quick eyeball without writing a manifest, hit the HTTP surface directly:

curl -X PUT http://127.0.0.1:4437/demo
curl -X PUT http://127.0.0.1:4437/demo/hello
curl -X POST -H 'Content-Type: text/plain' --data 'hi' http://127.0.0.1:4437/demo/hello
curl 'http://127.0.0.1:4437/demo/hello?offset=-1'

Kill the background process when you're done.

Next