DreamLake

Install nymph

nymph is the Lakeshore worker daemon: a single static Rust binary that long-polls the control plane, runs the work it is handed, and reports back. It needs no inbound port — everything is outbound HTTPS.

Once installed, running the bare binary (no subcommand) is the daemon. The only subcommand is nymph tui.

One-liner

bash
curl -fsSL https://dreamlake.ai/dreamlake/nymph/install.sh | bash

scripts/install.sh does exactly four things:

  1. Maps uname -s → unknown-linux-gnu / apple-darwin and uname -m → x86_64 / aarch64. Any other OS or arch is a hard error.
  2. Downloads ${BASE_URL}/${VERSION}/nymph-${arch}-${os}.tar.gz and its .sha256 sidecar.
  3. Verifies the checksum with sha256sum -c (or shasum -a 256 -c on macOS).
  4. Untars and moves nymph into /usr/local/bin, escalating with sudo only when that directory is not writable.
Flag / envDefaultMeaning
--version <v>latestRelease directory to pull from.
--dest <dir>/usr/local/binInstall directory.
NYMPH_BASE_URLhttps://pub-c0109e197b4a4d1abe5884ac4dd3a023.r2.dev/dreamlake/nymphRelease bucket base URL.
bash
curl -fsSL https://dreamlake.ai/dreamlake/nymph/install.sh | bash -s -- --version 0.1.4
curl -fsSL https://dreamlake.ai/dreamlake/nymph/install.sh | bash -s -- --dest ~/.local/bin
No --service flag

The install script installs a binary and nothing else — there is no --service flag and no NYMPH_PREFIX variable. Running nymph under a service manager is covered in Run it as a service below.

Published targets

CI builds on a v* tag push for exactly three targets:

  • x86_64-unknown-linux-gnu
  • aarch64-unknown-linux-gnu
  • aarch64-apple-darwin

Intel macOS (x86_64-apple-darwin) was dropped from CI. Each target ships a nymph-<target>.tar.gz (what install.sh consumes) and a raw nymph-<target> binary (what the OTA path consumes), each with a .sha256 sidecar, under dreamlake/nymph/<version>/ in the release bucket.

Build from source

bash
git clone https://github.com/dreamlake-ai/nymph.git
cd nymph
cargo build --release      # target/release/nymph

The crate is publish = false — it is never on crates.io. The release profile is size-tuned (opt-level = "z", fat LTO, symbols stripped, panic = "abort").

The ota-self-replace feature is on by default: after a successful OTA update the daemon exec()s into the freshly installed binary. Build with --no-default-features to install the new binary but keep the old process running until you restart it yourself.

Point it at a control plane

The daemon reads one TOML file at boot and never re-reads it. With no --config, it tries these in order:

  1. /etc/dreamlake/udf-daemon.toml
  2. $HOME/.config/dreamlake/udf-daemon.toml
  3. built-in defaults (http://localhost:8080, process runner)

A minimal working config:

/etc/dreamlake/udf-daemon.tomltoml
[server]
url = "https://api.lakeshore.dreamlake.ai"
token_file = "/etc/dreamlake/token"
namespace = "default"

[daemon]
label = "bos14-login"
tags = ["gpu:h100"]

[runtime]
workdir = "/var/lib/dreamlake/udf"
runners = ["process"]
default_runner = "process"
keep_alive_s = -1
Unknown sections are a hard error

The top-level config struct is #[serde(deny_unknown_fields)]. A stray section — [relay], or a bare top-level key like server_url = "…" — fails the parse and the daemon refuses to boot. The nine valid sections are [server], [daemon], [runtime], [poll], [log], [shutdown], [mounts], [introspect], [identity]. Unknown keys inside a valid section are silently ignored.

Then start it:

bash
nymph                                    # uses the default config search path
nymph --config /etc/dreamlake/udf-daemon.toml

Daemon flags and env vars

FlagEnv varDefaultMeaning
--config <path>LAKESHORED_CONFIGsearch pathPath to udf-daemon.toml.
--server <url>LAKESHORE_SERVERfrom configControl-plane base URL.
--token <tok>LAKESHORE_TOKENfrom configBootstrap bearer used on /hello.
--queue <name>DREAMLAKE_QUEUEdefaultQueue to subscribe to. A trailing * is a prefix match.
--worker-id <id>—derivedOverride the provisional {machine_id}-{ULID} id.

Two more env vars affect logging only: RUST_LOG (full EnvFilter syntax, wins over [log] level) and LAKESHORE_LOG_FORMAT (human or json, wins over [log] format). See Telemetry and introspection.

The config-file env var has a trailing D

It is LAKESHORED_CONFIG, not LAKESHORE_CONFIG. The queue override is DREAMLAKE_QUEUE, not LAKESHORE_QUEUE.

Verify it registered

bash
lakeshore daemon list

The daemon posts /v1/daemon/hello on boot, then long-polls. It shows up as joining on the hello and flips to active on its first poll. See Daemon lifecycle for the full operator surface.

Run it as a service

install.sh does not write a unit file. Two supported paths:

  • Control-plane launch. lakeshore daemon launch renders a cloud-init script that installs the binary at /opt/dreamlake/bin/nymph, writes /etc/dreamlake/udf-daemon.toml, and installs + enables a dreamlake-nymph.service systemd unit (Restart=always, KillMode=mixed, TimeoutStopSec=30, logs appended to /var/log/dreamlake/nymph.log). See Daemon lifecycle → launch.
  • SSH bootstrap. lakeshore daemon install <alias> starts the daemon under setsid nohup (or sbatch with --slurm) in the SSH user's $HOME — no systemd, no sudo. See Bootstrap a daemon on a remote host.

For a hand-rolled unit, mirror the launch path: run as a non-root user that owns the binary and the workdir, KillMode=mixed so SIGTERM reaches the daemon directly (it does its own graceful drain), and a TimeoutStopSec comfortably above [shutdown] grace_s.

Where to next

I want to…Page
Bootstrap nymph on a host over SSHBootstrap a remote daemon
Understand the daemon's runtime and runnersDaemons
Manage daemons from the CLIDaemon lifecycle
Read the wire protocolDaemon protocol
Turn on keypair authDaemon identity and key rotation
Watch a local daemon livenymph tui
Push a debug build without a releaseNymph push (dev)