Skip to content

Commit 0a76654

Browse files
committed
feat: lpb-config setup wizard + lpb SSH key auto-detection
- lpb-config setup: first-run wizard (URL + health check, model selection, auth.json, memory prefill, idempotent re-runs) - lpb.py: SSH key auto-detection from ~/.ssh profile, explicit key (literal or path), --ssh-password, env passthrough - start.sh: first-boot setup hook - tests: test_lpb_ssh.py, test_localpibox_config_setup.py - docs: README, lpb-cli, lpb-config, env-vars, .env.example
1 parent 00c37cd commit 0a76654

12 files changed

Lines changed: 810 additions & 48 deletions

‎.env.example‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ LPB_AGENT_BROWSER_IDLE_TIMEOUT_MS=300000
7979
# 0.20 → 262K context → 52.4K max tokens
8080
# LPB_MAX_TOKENS_CONTEXT_RATIO=0.06
8181

82+
# SSH port for `lpb --ssh` (default: 2222)
83+
# LPB_SSH_PORT=2222
84+
8285
# ─── Persistence ─────────────────────────────────────────────────────────────
8386

8487
# Persist gh CLI auth to ~/.config/gh inside container, stored in

‎README.md‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@ lpb # resumes your last project (or ~)
2626
```
2727

2828
On the **first run** the container pulls the image, clones the config preset,
29-
generates `settings.json`, and installs the extensions — then Pi starts.
30-
You'll be asked to connect a model:
29+
generates `settings.json`, and installs the extensions. Before Pi starts, the
30+
**first-run setup wizard** walks you through connecting your Lemonade server:
3131

32-
```
33-
/login lemonade # connect to the local Lemonade server (must be running on the host)
34-
/model # pick a model (e.g. the Qwen3.6-35B reasoning model)
35-
```
32+
1. server URL (pre-filled from `LEMONADE_BASE_URL`, health-checked)
33+
2. API key (a placeholder like `lemonade` is fine for a local server)
34+
3. default model (picked from the server's model list)
35+
4. lpb-memory configuration
36+
37+
After that Pi starts fully configured. Re-run it any time inside the
38+
container with `lpb-config setup --reconfigure`.
3639

3740
### Common commands
3841

@@ -119,7 +122,8 @@ CI tags images per pipeline: `:0.0.x-lpb[-dev]-cli/web` (versioned),
119122
| `lpb /path` | Pi CLI session (foreground); no path → last project or `~` |
120123
| `lpb --web /path` | VSCodium (background); `--port 8080` to change the port |
121124
| `lpb --shell /path` | Interactive bash inside the container |
122-
| `lpb --ssh [pubkey] /path` | sshd server in the container for remote login |
125+
| `lpb --ssh [pubkey\|path] /path` | sshd server in the container for remote login (key auto-detected from `~/.ssh` when omitted) |
126+
| `lpb --ssh --ssh-password [pw]` | SSH password login (random if omitted, shown once; can combine with a key) |
123127
| `lpb --stop` / `--remove` / `--logs` | Stop / stop+remove+state cleanup / stream logs |
124128
| `lpb --update` | Self-update launcher + pull latest image for the selected pipeline |
125129
| `lpb /path -- <pi-args>` | Pass args to Pi, e.g. `lpb /path -- -p "summarize this repo"` |

‎doc/env-vars.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ If a value from `.env` doesn't seem to apply, check shell env first:
3838
| `LPB_EDITOR_HOST` | `0.0.0.0` | Editor listen host (`127.0.0.1` for local-only) |
3939
| `LPB_CONNECTION_TOKEN` | *(random per start)* | OpenVSCode token — set for a stable token |
4040
| `LPB_LEMONADE_BASE_URL` | `http://127.0.0.1:13305/v1` | Local model server endpoint |
41+
| `LPB_LEMONADE_API_KEY` | *(none)* | Lemonade server API key — used by the first-run setup wizard (`lpb-config setup`); a placeholder is fine for local servers |
4142
| `LPB_MAX_TOKENS_CONTEXT_RATIO` | `0.06` | max_tokens as fraction of context window (Qwen thinking headroom) |
4243
| `LPB_AGENT_BROWSER_SESSION` | `$PI_WORKTREE_ID` | Browser session isolation id |
4344
| `LPB_AGENT_BROWSER_MAX_OUTPUT` | `4000` | Max chars for browser snapshot output |
@@ -99,6 +100,7 @@ These select **what goes into the image** (build time) and which pipeline
99100
| `PI_CODING_AGENT_DIR` | Same dir, as Pi expects it |
100101
| `LPB_AGENT_GIT` | Extension clones dir (default `$AGENT_DIR/git/github.com/lpb-stack`) |
101102
| `LEMONADE_BASE_URL` | Model API endpoint (`http://127.0.0.1:13305/v1`) |
103+
| `LEMONADE_API_KEY` | Lemonade server API key (bridged from `LPB_LEMONADE_API_KEY`) |
102104
| `AGENT_BROWSER_SESSION` | Browser session isolation id |
103105
| `AGENT_BROWSER_MAX_OUTPUT` | Max chars for snapshot output |
104106

‎doc/lpb-cli.md‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ Installs (no sudo required) into `~/.local/bin`:
2626
| `lpb [/path/to/project]` | Start a **Pi CLI session** (foreground). No path → last project, or `~` if none yet |
2727
| `lpb --web [/path]` | Start **VSCodium** (background), prints the connection URL |
2828
| `lpb --shell [/path]` | Interactive bash shell inside the container |
29-
| `lpb --ssh [pubkey\|path] [/path]` | Start an sshd server in the container for remote login |
29+
| `lpb --ssh [pubkey\|path] [/path]` | Start an sshd server in the container for remote login (key auto-detected from `~/.ssh` when omitted) |
30+
| `lpb --ssh --ssh-password [pw]` | SSH password login (random if omitted, shown once; can combine with key auth) |
3031
| `lpb --stop` | Stop the container |
3132
| `lpb --remove` | Stop + remove container + state dirs |
3233
| `lpb --logs` | Stream container logs |
@@ -58,6 +59,24 @@ lpb /myproject -- --thinking high # pass any pi flag
5859
--without-token hide the token in the printed URL
5960
```
6061

62+
### SSH mode (`--ssh`)
63+
64+
- **Key auto-detection**: `lpb --ssh` with no argument scans the *host* user
65+
profile (`~/.ssh/*.pub`). One key → used (confirmed on a TTY); several →
66+
numbered menu; none → error with a hint. Non-interactive: one key is used
67+
automatically, several → explicit selection required.
68+
- **Explicit key still wins**: `lpb --ssh <pubkey|path>` (literal key or file).
69+
- **Password login**: `lpb --ssh --ssh-password` (random, printed once) or
70+
`lpb --ssh --ssh-password <pw>` (user-chosen). The container user's password
71+
is set at start (`chpasswd`) and `PasswordAuthentication` is enabled in the
72+
generated `sshd_config`. Key auth remains the default — password auth is
73+
opt-in (the container runs `network=host`, so a password is reachable from
74+
the LAN).
75+
- **authorized_keys is append+dedup**: keys added manually (or in a previous
76+
session) survive container recreation.
77+
- **`LPB_SSH_PORT`** (default `2222`): forwarded to the container; the
78+
connect line (`ssh -p <port> lpb@<host>`) is printed when the server starts.
79+
6180
## Image Selection
6281

6382
Two image flavours are published to `ghcr.io/lpb-stack/devstack`:

‎doc/lpb-config.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ see [lpb-devstack reference](lpb-devstack.md).
3434
| `lpb-config memory show` | Display current lpb-memory configuration |
3535
| `lpb-config memory setup` | Interactive wizard to configure lpb-memory |
3636

37+
### First-Run Setup
38+
39+
| Command | Description |
40+
|---|---|
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 (used on TTY-less first boots) |
43+
3744
### Pipeline Override
3845

3946
`--tag dev|main` is accepted on any command (validates the value) for
@@ -59,6 +66,8 @@ Example pin: `git:github.com/lpb-stack/pi-subagents@0.0.57-lpb-dev`
5966
Same template-driven pattern:
6067

6168
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)
6271
2. No model override — uses the main model until user configures
6372
3. Tune: `lpb-config memory setup` (interactive wizard)
6473
4. Review: `lpb-config memory show`

0 commit comments

Comments
 (0)