# Secrets, modes, tunnels, config, nymph

Part of the [CLI examples cookbook](/cli/examples.md). Auth setup lives on
[Auth + setup](/cli/examples/auth.md).

## Secrets

Server-stored credentials referenced by providers, mounts, storage
entries, and tunnels. Plaintext **only flows on the way in** — `list`
and `show` return metadata.

`--kind` is **required** and must be one of `ssh_key`, `aws_keypair`,
`gcp_sa_json`, or `opaque`.

### `secrets add` — from a file

```bash
lakeshore secrets add my-pem \
  --kind ssh_key \
  --from-file ~/.ssh/id_ed25519 \
  --description "primary dev key"
```

### `secrets add` — from stdin

When `--from-file` is absent the CLI reads piped stdin, which keeps the
plaintext off disk.

```bash
pbpaste | lakeshore secrets add gcp-sa --kind gcp_sa_json          # macOS
cat ~/Downloads/sa.json | lakeshore secrets add gcp-sa --kind gcp_sa_json
```

### `secrets list` / `show` — metadata only

```bash
lakeshore secrets list
lakeshore secrets show my-pem
```

### `secrets rotate` — replace the plaintext

Same input rules as `add`: `--from-file`, or piped stdin.

```bash
lakeshore secrets rotate my-pem --from-file ~/.ssh/id_ed25519.new
```

### `secrets remove`

```bash
lakeshore secrets remove my-pem
```

Secrets are referenced elsewhere by the `$secret` marker — e.g.
`--kwarg 'creds.$secret=aws-prod-keys'` on `storage add` and
`mounts add`, or `--creds aws-prod-keys` as shorthand on `storage add`.

## Modes

A **mode** is a server-stored RunConfig: a named compute target
(provider, resources, tags). The Python API dispatches against modes;
the CLI manages their definitions.

> **Warning:** Every other group's inline override flag is `--kwarg`. `modes add` and
> `modes update` use `--field`. (The generated shell completion still
> advertises `--kwarg` here — that table is stale.)

### `modes add` — from a file

```bash
cat > /tmp/h100.yaml <<'YAML'
provider: my-ec2
resources:
  gpus: 1
  cpus: 8
  memory_gb: 64
tags:
  - gpu:h100
YAML
lakeshore modes add h100 --config-file /tmp/h100.yaml
```

### `modes add` — inline field overrides

Dotted keys nest.

```bash
lakeshore modes add cpu-small \
  --field provider=my-ec2 \
  --field resources.cpus=2 \
  --field resources.memory_gb=8
```

### `modes list` / `show` / `update` / `remove`

`update` merges; `=null` drops a key.

```bash
lakeshore modes list
lakeshore modes show h100

lakeshore modes update h100 --field resources.gpus=2
lakeshore modes update h100 --field tags=null
lakeshore modes update h100 --config-file /tmp/h100.yaml

lakeshore modes remove h100
```

## Tunnels

WireGuard configs the control plane uses to reach providers behind a
VPN. `--kind` defaults to `wireguard`, and `wireguard` is the only
supported value.

### `tunnels add` — from a config file

`--config-file` accepts `.conf` (wg-quick INI), `.yaml`, or `.json`.

```bash
lakeshore tunnels add wg-vpc --config-file /tmp/wg-vpc.conf
```

### `tunnels add --conf` — inline INI

```bash
lakeshore tunnels add wg-vpc --conf "$(cat <<'INI'
[Interface]
PrivateKey = abc123=
Address    = 10.0.0.2/24

[Peer]
PublicKey  = peer-key=
Endpoint   = 1.2.3.4:51820
AllowedIPs = 10.0.0.0/24
INI
)"
```

### `tunnels list` / `show` / `remove`

`remove` refuses while any provider still references the tunnel.

```bash
lakeshore tunnels list
lakeshore tunnels list --json
lakeshore tunnels show wg-vpc --json
lakeshore tunnels remove wg-vpc
```

Attach a tunnel to a provider with `providers update <name> --tunnel
<tunnel>` — see
[Providers and discover](/cli/examples/providers-and-discover.md).

## Nymph binaries

For rolling debug builds at a fleet without cutting an R2 release.
Pair with `daemon update --url`. Both subcommands need an admin token —
`--admin-token`, defaulting to `$LAKESHORE_ADMIN_TOKEN`.

### `nymph push` — upload a binary

`--target <triple>` defaults to a value inferred from the ELF header's
`e_machine`; `--name <label>` labels the upload.

```bash
LAKESHORE_ADMIN_TOKEN=changeme \
  lakeshore nymph push ./target/x86_64-unknown-linux-gnu/release/nymph
```

```text
✓ uploaded nymph (4.1 MB)
  sha256: 3f2a…
  label:  nymph
  target: x86_64-unknown-linux-gnu
  url:    /v1/admin/nymph-releases/3f2a…
  full:   http://localhost:8080/v1/admin/nymph-releases/3f2a…
```

> **Warning:** The `url` field in the `--json` envelope is a path, not an absolute
> URL. Daemons OTA from the fully-qualified address — the `full:` line in
> the human output. Prefix the server origin yourself when scripting.

### `nymph list` — what's stored

```bash
LAKESHORE_ADMIN_TOKEN=changeme lakeshore nymph list --json
```

### Push and roll the fleet

```bash
PUSH=$(LAKESHORE_ADMIN_TOKEN=changeme lakeshore nymph push ./nymph --json)
lakeshore daemon update --all \
  --url "$LAKESHORE_URL$(jq -r '.url' <<<"$PUSH")" \
  --sha256 "$(jq -r '.sha256' <<<"$PUSH")" \
  --yes
```

> **Note:** `nymph push` deliberately has no `--update <daemon...>` flag. Chain it
> to `daemon update --url` as above.

## Config

Diagnostics for the resolved `.dreamrc`. None of the three subcommands
take flags.

```bash
lakeshore config show      # print the resolved DreamRc as YAML
lakeshore config source    # which source it came from
lakeshore config refresh   # force a server pull and update the on-disk cache
```

`config source` prints one of `env`, `workspace`, `home`, `server`,
`cache`, or `none`, matching the resolution order (first hit wins):

1. `--dreamrc <path>` — the CLI's one global option (reported as
   `explicit`).
2. `DREAMRC` env var → `env`.
3. `./.dreamrc`, walking up from cwd → `workspace`.
4. `$HOME/.dreamrc` → `home`.
5. A server pull (needs auth or `LAKESHORE_URL`) → `server`.
6. The on-disk cache from a previous pull → `cache`.
7. Nothing — an empty DreamRc → `none`.

The server pull composes a DreamRc from the namespace's `providers` and
`modes`, and caches it at
`$XDG_CACHE_HOME/lakeshore/<server-host>/<namespace>/dreamrc.yml`
(dir 0700, file 0600). If the pull fails, the CLI falls back to that
cache and prints `⚠ server unreachable, using cached config from <ts>`.

> **Warning:** `.dreamrc` (providers + modes, YAML with `!providers.` tags) is
> **not** the same as `.lakeshore` / `.lakeshore.local` (project defaults
> for `daemon launch`, a top-level `daemon:` block, walked up from cwd
> and stopped at the git root), and neither is `lakeshore.yaml` (the
> compose file for `up` / `down` / `ps` / `status` / `logs`, read from
> cwd only). See [Configuration](/api/configuration.md).

## Completion

```bash
echo 'eval "$(lakeshore completion bash)"' >> ~/.bashrc
echo 'eval "$(lakeshore completion zsh)"'  >> ~/.zshrc
lakeshore completion fish | source
```

Full details — the static tree, the dynamic `__suggest` callback, and
the 30-second cache — at [`/cli/completion`](/cli/completion.md).

## Read next

- [Auth and secrets](/api/auth-and-secrets.md) — the server-side model.
- [Tunnels](/get-started/tunnels.md) · [Configuration](/api/configuration.md)
- [Daemons + exec/run](/cli/examples/daemons-and-exec.md) — where `daemon update --url` lands.
