Skip to content

Commit 7adb26f

Browse files
author
lpb-docs
committed
refactor(setup): unified initial setup wizard for all modes
The first-boot configuration was three fragmented, mode-dependent mechanisms: a host prompt (ssh/web only), an in-container wizard (first boot only, TTY-dependent) and one-shot env passthrough. Errors were swallowed (start.sh '||' + .initialized touched anyway), a 401 on the keyless /models probe killed non-interactive setup even when the key was correct, and nothing ever validated credentials before pi ran. Now there is ONE wizard (localpibox.setup) for every mode: lpb setup host-side wizard: config repo -> server URL -> API key -> default model -> lpb-memory (full memory wizard: mode, transport, background model, limits). Every step is validated with live HTTP probes; failures loop with the raw error visible ('a' = start anyway, flagged; 'q' = abort, nothing written). Writes auth.json/settings.json/ lpb-memory-config.json directly into the state dir, so configuration is persisted BEFORE first use. lpb doctor read-only checklist (repo, settings, creds, live probe, runtime, image). preflight before EVERY fresh start (cli/shell/ssh/web): healthy provider -> silent; missing/broken + TTY -> wizard; non-TTY -> env passthrough + visible note. Validation is live, so a moved server / changed key re-offers the wizard instead of going silently stale. lpb-config setup/check/memory setup delegate to the same wizard; start.sh keeps only the infra bootstrap and a non-interactive fallback with a prominent failure banner + every-boot reminder. Also: probe is auth-aware (Bearer key sent; 401/403 reported as 'key rejected', distinct from unreachable); wizard no longer crashes on non-integer memory limits; memory wizard prefills CURRENT values; self-update now ships lpb-config/lpb-devstack/localpibox; docs + tests updated (80/80 lpb family, all 15 localpibox suites).
1 parent 081b837 commit 7adb26f

16 files changed

Lines changed: 2308 additions & 734 deletions

README.md

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,28 +25,33 @@ lpb --web /path/to/your/project # VSCodium editor (background, prints a URL)
2525
lpb # resumes your last project (or ~)
2626
```
2727

28-
On the **first run** the container pulls the image, clones the config preset,
29-
generates `settings.json`, and installs the extensions. First-run setup then
30-
connects your Lemonade server:
31-
32-
- **`--ssh` / `--web`** (background): `lpb` prompts in its own terminal for
33-
the server URL (health-checked — type the real host if
34-
`127.0.0.1:13305` is unreachable) and API key, then the container finishes
35-
setup non-interactively: default model (from the server's model list) and
36-
lpb-memory configuration.
37-
- **Foreground Pi / shell**: the **first-run setup wizard** (`lpb-config
38-
setup`) walks you through it inside the container, pre-filled from
39-
`LPB_LEMONADE_BASE_URL` / `LPB_LEMONADE_API_KEY` env or `lpb.conf.env`. Re-run it any time inside the
40-
container with `lpb-config setup --reconfigure`.
28+
On the **first run** — in every mode (`lpb`, `--shell`, `--ssh`, `--web`) —
29+
`lpb` checks the model-provider state (stored credentials + a live probe of
30+
the Lemonade server). If it's missing or broken and you're on a terminal,
31+
the **setup wizard** runs before the container starts: config repo, server
32+
URL, API key, default model (from the server's live model list) and
33+
lpb-memory config — every step validated, with errors shown and re-asked
34+
until they're right. The configuration is written straight into the state
35+
volume, so it's persisted **before first use**; the launch summary ends with
36+
a model status line.
37+
38+
- **Non-TTY** (hosts/CI) or `lpb --non-interactive`: no wizard — the env
39+
(`LPB_LEMONADE_BASE_URL` / `LPB_LEMONADE_API_KEY` / `lpb.conf.env`) is
40+
passed through and the container runs a non-interactive fallback.
41+
- Re-run any time (all modes): `lpb setup` (wizard) and `lpb doctor`
42+
(read-only validation). Inside the container the same wizard is
43+
`lpb-config setup` (and `lpb-config check`).
4144

4245
### Common commands
4346

4447
```bash
4548
lpb --stop # stop the container
4649
lpb --logs # stream container logs
4750
lpb --update # update the launcher + pull the latest image
51+
lpb setup # initial setup wizard (server, key, model, memory)
52+
lpb doctor # validate the installation (read-only)
4853
lpb --remove # stop, remove container + state dirs
49-
lpb --config # show config file location
54+
lpb --config # show config file location + model status
5055
lpb --help # full usage
5156
```
5257

@@ -156,6 +161,8 @@ podman exec -it lpb-stack bash
156161
| `pi update --extensions` | Update unpinned packages (tag-pinned packages are skipped — move a pin with `pi install git:github.com/lpb-stack/<repo>@<new-tag>`) |
157162
| `lpb-devstack validate` | Validate stack alignment (repos, branches, pins) |
158163
| `lpb-devstack bump` | Bump VERSION + commit (the release trigger for CI build/tag) |
164+
| `lpb-config setup` | Initial setup wizard (provider, model, memory) — the in-container twin of `lpb setup` |
165+
| `lpb-config check` | Validate the installation (read-only) |
159166
| `lpb-config memory setup` | Interactive wizard for the memory extension |
160167

161168
Inside the Pi TUI: `/login <provider>`, `/model`, `/settings` (thinking
@@ -236,11 +243,12 @@ publishes versioned tags plus the `:dev-*`, `:main-*`, `:latest-*` floats.
236243
Let `lpb` resolve the tag (`lpb --tag dev|main|<version>`), or pull e.g.
237244
`ghcr.io/lpb-stack/devstack:latest-web` explicitly.
238245

239-
### No model available / login fails
246+
### No model available / setup failed
240247

241-
The Lemonade server on the host must be running before Pi can list models:
242-
start it, then in the Pi TUI run `/lemonade refresh` (or `/login lemonade`
243-
again).
248+
The Lemonade server on the host must be running before the setup wizard can
249+
validate it: start it, then re-run `lpb setup` (or `lpb doctor` to see what
250+
is wrong). Inside a running session, `/lemonade refresh` re-syncs the model
251+
list once the provider is configured.
244252

245253
### Port already in use
246254

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.0.63-lpb-dev
1+
0.0.64-lpb-dev

doc/config-repo.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,12 @@ The settings file is **template-driven**, not git-tracked:
4444

4545
1. **Template**: `settings.json.template` ships in the config repo with
4646
`__LPB_VERSION__` placeholders
47-
2. **Boot**: `start.sh` generates `settings.json` by replacing placeholders
48-
3. **No model preconfigured**: user runs `/login lemonade` to set up the provider
47+
2. **Boot**: the setup wizard (`lpb setup` / `lpb-config setup`) renders
48+
`settings.json` by replacing placeholders (fallback: `start.sh` via
49+
`lpb-config render`)
50+
3. **Model configured interactively**: the setup wizard writes
51+
`defaultProvider` + `defaultModel` with live validation (no `/login`
52+
needed for lemonade)
4953
4. **Persistence**: `settings.json` lives on the host volume — it survives
5054
container rebuilds
5155
5. **Validation**: `lpb-devstack validate` checks settings.json pins match

doc/lpb-cli.md

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Installs (no sudo required) into `~/.local/bin`:
1414

1515
- `lpb` — bash wrapper
1616
- `lpb.py` — Python engine
17+
- `lpb-config`, `lpb-devstack` + the shared `localpibox` package
18+
(the setup wizard behind `lpb setup` / `lpb doctor`)
1719

1820
…and copies the stack config files (`lpb.stack.env`, `lpb.conf.env`,
1921
`VERSION`) to `~/.lpb-stack/devstack/`. Make sure `~/.local/bin` is on your
@@ -31,13 +33,15 @@ Installs (no sudo required) into `~/.local/bin`:
3133
| `lpb --stop` | Stop the container |
3234
| `lpb --remove` | Stop + remove container + state dirs |
3335
| `lpb --logs` | Stream container logs |
34-
| `lpb --update` | Self-update the launcher + pull the latest image(s) |
35-
| `lpb --config` | Show config file location |
36+
| `lpb --update` | Self-update the launcher + stack tools + pull the latest image(s) |
37+
| `lpb setup` | Run the **initial setup wizard** (server, key, model, memory) — any time, all modes |
38+
| `lpb doctor` | Validate the installation (read-only checklist) |
39+
| `lpb --config` | Show config file location + model provider status |
3640
| `lpb --version` | Show installed launcher version |
3741
| `lpb --help` | Full usage |
3842

3943
Positional aliases (no `--` needed): `lpb logs`, `lpb stop`, `lpb update`,
40-
`lpb remove`, `lpb config`, `lpb version`, `lpb help`.
44+
`lpb remove`, `lpb config`, `lpb setup`, `lpb doctor`, `lpb version`, `lpb help`.
4145

4246
### Pi passthrough
4347

@@ -77,27 +81,42 @@ lpb /myproject -- --thinking high # pass any pi flag
7781
- **`LPB_SSH_PORT`** (default `2222`): forwarded to the container; the
7882
connect line (`ssh -p <port> lpb@<host>`) is printed when the server starts.
7983

80-
### First-boot Lemonade prompt (`--ssh` / `--web`)
81-
82-
On the **first boot of a fresh state volume** (no `~/.pi/.initialized` in
83-
`LPB_STATE_DIR`), detached-server modes run the container's setup
84-
non-interactively — so `lpb` resolves your Lemonade server on the host side
85-
first:
86-
87-
1. URL from `LPB_LEMONADE_BASE_URL` / `LEMONADE_BASE_URL` env or
88-
`lpb.conf.env` (default `http://127.0.0.1:13305` when unset).
89-
2. Health probe (`GET <url>/api/v1/models`, 3 s). Unreachable on a TTY →
90-
you're offered to type the real host (re-probed until it answers or you
91-
press Enter to keep the current one); reachable → silent.
92-
3. API key is asked with the configured value (or `lemonade`) as default.
93-
94-
The resolved URL + key are passed to the container
95-
(`LPB_LEMONADE_BASE_URL` / `LPB_LEMONADE_API_KEY`), where the first-boot
96-
hook (`lpb-config setup --non-interactive`) writes `auth.json` + default
97-
model. Foreground Pi/shell modes skip the host prompt — the in-container
98-
interactive wizard handles it, pre-filled from the same env. Non-TTY
99-
(hosts/CI) and already-initialized volumes: no prompt, static passthrough
100-
only. Reconfigure any time inside the container with
84+
### Initial setup — one wizard for all modes
85+
86+
Before the **first container start — in every mode (cli, shell, ssh, web)**
87+
`lpb` validates the model-provider configuration. The provider state is
88+
checked live (stored credentials in `LPB_STATE_DIR/agent/auth.json` + a real
89+
HTTP probe of the Lemonade server), not a one-shot first-boot flag:
90+
91+
- **healthy** → silent; the stored URL/key are passed to the container.
92+
- **missing or broken + TTY** → the **setup wizard** runs (config repo →
93+
server URL → API key → default model → lpb-memory config). Every step is
94+
validated live (real HTTP probes) and failures loop back with the raw
95+
error visible; `a` continues anyway (flagged), `q` aborts (nothing is
96+
written, no container starts). The wizard writes `auth.json`,
97+
`settings.json` and `lpb-memory-config.json` directly into the state dir,
98+
so the configuration is **persisted before the first use**.
99+
- **missing or broken + non-TTY** (or `lpb --non-interactive`) → env
100+
passthrough (`LPB_LEMONADE_BASE_URL` / `LPB_LEMONADE_API_KEY` / `lpb.conf.env`)
101+
with a visible note; the container runs a non-interactive fallback.
102+
103+
Because validation is live, a server that moves or a key that changes is
104+
detected on the next start and re-offers the wizard — configuration is never
105+
silently stale. The launch summary always ends with a model status line
106+
(✓ provider / ⚠ fix with `lpb setup`).
107+
108+
On-demand commands (any mode, any time):
109+
110+
- `lpb setup` — run the wizard interactively (the way to correct a bad
111+
configuration; current values are pre-filled).
112+
- `lpb doctor` — read-only checklist: config repo, rendered config, provider
113+
credentials, live server probe, container runtime, image.
114+
115+
Inside the container the same wizard is available as `lpb-config setup`
116+
(and `lpb-config check` for the checklist); `start.sh` runs it
117+
non-interactively as a fallback on boots where the host wizard did not run,
118+
and a missing provider is reported in the container logs on **every boot**
119+
until fixed — not swallowed. Reconfigure any time with
101120
`lpb-config setup --reconfigure`.
102121

103122
## Image Selection

doc/lpb-config.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ see [lpb-devstack reference](lpb-devstack.md).
3838

3939
| Command | Description |
4040
|---|---|
41-
| `lpb-config setup` | Interactive first-run setup: lemonade provider (auth.json), default model (settings.json), lpb-memory config. Runs automatically on first boot (start.sh); idempotent — re-run with `--reconfigure` to change server/model |
42-
| `lpb-config setup --non-interactive` | Same, no prompts — `LEMONADE_BASE_URL` / `LEMONADE_API_KEY` env + defaults. On TTY-less first boots the `lpb` launcher passes them in (first-boot prompt in `--ssh`/`--web` modes, see `lpb-cli.md`) |
41+
| `lpb-config setup` | The **same wizard** as `lpb setup` on the host: config repo, lemonade provider (auth.json), default model (settings.json), lpb-memory config. Every step is validated live (HTTP probes); failures loop with the error visible. Re-run any time to correct a bad configuration — current values are pre-filled. `--reconfigure` forces a re-run |
42+
| `lpb-config setup --non-interactive` | Same, no prompts — `LEMONADE_BASE_URL` / `LEMONADE_API_KEY` env + defaults. First failure aborts with a precise error and writes nothing. This is the `start.sh` fallback for boots where the host wizard did not run |
43+
| `lpb-config check` | Validate the installation (read-only checklist: config repo, settings, credentials, live server probe) — the in-container twin of `lpb doctor` |
4344

4445
### Pipeline Override
4546

@@ -52,8 +53,12 @@ regardless of pipeline.
5253
Settings.json is **template-driven**, not git-tracked:
5354

5455
1. Config repo ships `settings.json.template` with `__LPB_VERSION__` placeholders
55-
2. First boot: `start.sh` generates `settings.json` (replaces placeholders)
56-
3. No model/provider preconfigured — user runs `/login lemonade`
56+
2. Before the first start, the setup wizard (`lpb setup` on the host, or
57+
`lpb-config setup` in a shell) renders `settings.json` and writes the
58+
lemonade provider + default model — `start.sh` re-renders on first boot
59+
as a fallback (`lpb-config render`)
60+
3. Model/provider are configured interactively with live validation — see
61+
the First-Run Setup section above (no `/login` needed for lemonade)
5762
4. Pin sync: `lpb-devstack workspace sync-pins` (main pipeline reads
5863
stable version from devstack `origin/main`)
5964
5. `lpb-devstack validate` checks pins match the current stack version
@@ -65,11 +70,12 @@ Example pin: `git:github.com/lpb-stack/pi-subagents@0.0.57-lpb-dev`
6570

6671
Same template-driven pattern:
6772

68-
1. First boot: `start.sh` copies `lpb-memory-config.json.template` → config
69-
(or `lpb-config setup` configures it interactively during the first-run
70-
wizard, pre-filling the model override with the selected default model)
71-
2. No model override — uses the main model until user configures
72-
3. Tune: `lpb-config memory setup` (interactive wizard)
73+
1. The setup wizard configures it (mode, transport, background model,
74+
context limits) — pre-filling the model override with the selected
75+
default model; `start.sh` falls back to a plain template copy when the
76+
wizard did not run
77+
2. Non-interactive mode uses the template + the default-model override
78+
3. Tune any time: `lpb-config memory setup` (same wizard step, standalone)
7379
4. Review: `lpb-config memory show`
7480

7581
## Quick Reference
@@ -93,4 +99,8 @@ lpb-config align
9399
# Check / configure the memory extension
94100
lpb-config memory show
95101
lpb-config memory setup
102+
103+
# Run / validate the initial setup
104+
lpb-config setup
105+
lpb-config check
96106
```

scripts/install.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ for tool in lpb-config lpb-devstack; do
4949
chmod +x "${INSTALL_DIR}/${tool}"
5050
done
5151
mkdir -p "${CONFIG_DIR}/localpibox/stack"
52-
for f in __init__.py cli.py env.py log.py run.py; do
52+
for f in __init__.py cli.py env.py log.py run.py setup.py; do
5353
curl -fsSL "https://raw.githubusercontent.com/${OWNER_REPO}/main/scripts/localpibox/${f}" -o "${CONFIG_DIR}/localpibox/${f}"
5454
done
5555
for f in __init__.py gitutil.py repos.py version.py workspace.py validate.py release.py; do
@@ -109,6 +109,8 @@ echo " lpb --logs — View container logs"
109109
echo " lpb --remove — Remove everything"
110110
echo ""
111111
echo "Stack tools:"
112+
echo " lpb setup — Initial setup wizard (server, key, model, memory)"
113+
echo " lpb doctor — Validate the installation"
112114
echo " lpb-config status | update | reset | memory setup — config repo (container/host)"
113115
echo " lpb-devstack bump | tag-repos | workspace | validate | release — DevOps"
114116
echo ""

0 commit comments

Comments
 (0)