# 03 · Hello, local stack

"Your laptop is a Lakeshore." Brings the whole stack up on `localhost`
so you can iterate without touching a hosted control plane.

For a server setup with authentication and a DreamLake connection, follow [Setting Up Lakeshore Service](https://docs.dreamlake.ai/lakeshore/setting-up-lakeshore-service).

## Exercises

- Mongo via `docker compose` (the `db` pane).
- Control-plane boot — `pnpm dev` inside `lakeshore-controlplane`.
- Nymph registration over `POST /v1/daemon/hello`.
- A `lakeshore daemon list` round trip, proving CLI → control plane →
  daemon.

## Requires

- Docker running.
- The container repo cloned with submodules.
- `pnpm`, `uv`, and `mprocs` on `PATH` (`brew install mprocs`).
- `lakeshore-controlplane/.env` present, or the mprocs `lakeshore` pane's
  built-in defaults. The pane sources `.env` when it exists and then
  fills in `DATABASE_URL` /`MONGODB_URI` defaults for anything unset *or
  empty* — the `.env.example` placeholders are empty strings, which would
  otherwise leak through and break Prisma.

## Verifies

The control plane and one Rust daemon are alive and talking, both
reachable from the CLI on `localhost:8080`.

## Run

```bash
git clone --recurse-submodules \
  https://github.com/dreamlake-ai/lakeshore-workspace.git
export LAKESHORE_WORKSPACE=~/lakeshore-workspace

cd $LAKESHORE_WORKSPACE
mprocs
# `db` autostarts. Press `s` on the `lakeshore` pane, then on `nymph`.
```

Then, in another shell:

```bash
export LAKESHORE_URL=http://localhost:8080
lakeshore daemon list
```

> **Warning:** `LAKESHORE_SERVER` is read only by the `lakeshore auth` commands. Every
> other command — including `daemon list` — resolves the control plane
> from `LAKESHORE_URL`, and sends no bearer token when it is set.

## Expected output

```text
✓ 1 daemon in 'default':

label         state   runners  queues  tags        version  seen  machine_id
Datium.local  active  process  —       host=local  0.1.4    2s    Datium.local
```

One row, state `active`, `seen` measured in seconds. `queues` shows `—`
because an empty membership array means the default queue — there is no
literal `"default"` entry.

## Then smoke it

```bash
LAKESHORE_URL=http://localhost:8080 ./scripts/smoke-exec.sh
```

Ten sections covering stdout, stderr separation, exit codes, env
passthrough, stdin, workdir writes, the timeout sentinel, a long-poll
that spans multiple windows, and host Python. It bails on the first
failure and prints the expected-versus-actual pair.

## Alternative: no TUI

```bash
./scripts/dev-up.sh      # background processes; logs in /tmp/lakeshore-dev/
./scripts/dev-down.sh
```

Idempotent — re-running skips anything already up.

## If it fails

| Symptom | Likely cause |
| ------- | ------------ |
| `db` pane: "container name already in use" | A stale standalone `dreamlake-udf-mongo` container. Run the `mongo-clear` pane, then restart `db`. |
| Control-plane pane: `DATABASE_URL is required` | `.env` exists but sets `DATABASE_URL=""`, and something overrode the pane's default. Unset it or give it a real value. |
| `nymph` pane fails with `gcc-11 not found` | A stale `CC` export. The pane forces `CC=clang`; if you are running cargo by hand, `unset CC` first. |
| `daemon list` returns no rows | Nymph started but never reached the control plane. Check the nymph pane's `--server` flag and that the control plane is listening on 8080. |
| `daemon list` returns 401 | The control plane has `LAKESHORE_ADMIN_TOKEN` set, so it is not in open mode. Either clear it in `.env` for local dev, or mint a token — see [15 · Token lifecycle](/cli/happy-paths/15-token-lifecycle.md). |
| `daemon list` says "server not configured" | Neither `LAKESHORE_URL` nor a saved `auth login` is present. |

## Status

Manual.

## Next

→ [04 · Smoke-exec cascade](/cli/happy-paths/04-smoke-exec-cascade.md)
