AI-powered development environment with the Pi coding agent, VSCodium editor, and agent-browser automation — all containerized.
# Install the `lpb` launcher (adds it to ~/.local/bin/)
curl -fsSL https://raw.githubusercontent.com/lpb-stack/devstack/main/scripts/install.sh | bash
# Run devstack for your project
lpb /path/to/your/project
# Or start VSCodium with a welcome screen (user picks project)
lpb
# Common commands
lpb --stop # Stop the container
lpb --logs # View logs
lpb --remove # Remove everything
lpb --config # Show config file
lpb --help # Full usage# Pull the latest image
podman pull ghcr.io/lpb-stack/devstack:latest
# Run with a project folder
podman run -d --name lpb-stack --network host --userns keep-id \
-v /path/to/your/project:/home/lpb/workspace/myproject:Z \
-v ~/.lpb-stack/state:/home/lpb/.pi:Z \
-v ~/.lpb-stack/agent-browser:/home/lpb/.agent-browser:Z \
-e ED_PORT=3000 \
ghcr.io/lpb-stack/devstack:latest
# Open browser to http://localhost:3000 (token: devsession)# Run and get a shell inside the container
podman run -it --name lpb-stack --network host --userns keep-id \
-v /path/to/your/project:/home/lpb/workspace/myproject:Z \
-v ~/.lpb-stack/state:/home/lpb/.pi:Z \
-v ~/.lpb-stack/agent-browser:/home/lpb/.agent-browser:Z \
-e ED_PORT=3000 \
ghcr.io/lpb-stack/devstack:latest# Inside the running container
podman exec -it lpb-stack update --extensionsflowchart TB
subgraph Host
H1["~/projects/myproject/"]
H2["~/.lpb-stack/state/"]
H3["~/.lpb-stack/agent-browser/"]
H4["Lemonade (:13305)"]
end
subgraph Image["Image: ghcr.io/lpb-stack/devstack:latest"]
direction TB
I1["Ubuntu 26.04 + Node.js 24"]
I2["Pi monorepo (built, patched)"]
I3["VSCodium server (headless, port 3000)"]
I4["Chrome (agent-browser automation)"]
I5["Extensions: lemonade, memory, mcp-adapter, subagents"]
I6["Config: settings, mcp, skills, agents"]
end
H1 -->|bind mount| I1
H2 -->|bind mount| I2
H3 -->|bind mount| I3
H4 -->|host network| I4
Mount structure:
- Host:
$PROJECT → /home/lpb/workspace/myproject/ - Host:
~/.lpb-stack/state → /home/lpb/.pi(persistent agent state) - Host:
~/.lpb-stack/agent-browser → /home/lpb/.agent-browser(browser sessions) - Host:
Lemonade (:13305) → 127.0.0.1:13305(host network mode)
Once the container is running, these commands are available:
| Command | Description |
|---|---|
pi |
Start Pi CLI |
update --extensions |
Update extensions to latest |
update --patches |
Apply Pi source patches |
exit |
Stop the server and exit |
# Update extensions to latest release
podman exec -it lpb-stack update --extensions
# Patches are baked into the image — to update, rebuild the container
# with updated fork branches in lpb.stack.env.# Run with any project folder
podman run -d --name lpb-stack --network host --userns keep-id \
-v /home/user/projects/myproject:/home/lpb/workspace/myproject:Z \
-v ~/.lpb-stack/state:/home/lpb/.pi:Z \
-v ~/.lpb-stack/agent-browser:/home/lpb/.agent-browser:Z \
ghcr.io/lpb-stack/devstack:latestThe project mounts at /workspace/myproject/ so tools see the correct project name (not "workspace").
# First project
podman run -d --name lpb-stack --network host --userns keep-id \
-e ED_PORT=3000 \
-v /path/to/project-a:/home/lpb/workspace/project-a:Z \
-v ~/.lpb-stack/state:/home/lpb/.pi:Z \
-v ~/.lpb-stack/agent-browser:/home/lpb/.agent-browser:Z \
ghcr.io/lpb-stack/devstack:latest
# → http://localhost:3000
# Stop and run another
podman stop lpb-stack
podman rm lpb-stack
podman run -d --name lpb-stack --network host --userns keep-id \
-e ED_PORT=3001 \
-v /path/to/project-b:/home/lpb/workspace/project-b:Z \
-v ~/.lpb-stack/state:/home/lpb/.pi:Z \
-v ~/.lpb-stack/agent-browser:/home/lpb/.agent-browser:Z \
ghcr.io/lpb-stack/devstack:latest
# → http://localhost:3001flowchart LR
subgraph Source["Source"]
G["GitHub\n(your code)"]
end
subgraph Pipeline["CI/CD Pipeline"]
CI["GitHub Actions\n(push / weekly)"]
end
subgraph Registry["Registry"]
GHCR["GHCR\nghcr.io/lpb-stack/devstack:latest"]
end
subgraph Runtime["Runtime (host)"]
PODMAN_PULL["podman pull\n(image)"]
PODMAN_RUN["podman run\n(launch)"]
UPDATE["update\n--extensions\n(at boot)"]
end
G -->|push to main| CI
CI -->|build & push| GHCR
GHCR -->|pull| PODMAN_PULL
PODMAN_PULL --> PODMAN_RUN
PODMAN_RUN --> UPDATE
What gets updated:
| Component | How | Frequency |
|---|
| Component | How | Frequency |
|---|---|---|
| Base image | CI/CD on push to main | Every code change |
| Extensions | pi update --extensions (at boot) |
Every container start |
| Chrome/VSCodium | Base image rebuild | Monthly or on-demand |
| lpb launcher | lpb --update self-update |
Every code change |
Note: Pulls may take a while on slow connections — lpb --update uses
non-blocking streaming so you'll see real-time progress (no timeouts).
Fork URLs and branches are tracked in lpb.stack.env at the repo root. Each
LocalPibox fork carries its lpb-stack work as a single squashed commit on
top of upstream (or as its own root commit for independent projects), so the
delta vs upstream is always one clean patch.
| Repo | Upstream | Upstream latest | LocalPibox work | Update policy |
|---|---|---|---|---|
| pi | earendil-works/pi |
release v0.83.0 | Qwen reasoning + context-overflow patches | rebase lpb patch onto upstream on releases only |
| lemonade-pi-plugin | lemonade-sdk/lemonade-pi-plugin |
no stable release | Qwen thinking + vision support | follow upstream main; check periodically |
| pi-subagents | tintinweb/pi-subagents |
release v0.14.3 | centralized subagent model registry | branch & follow master releases; submit upstream if clean |
| lpb-memory | (independent — full refactor) | — | Pi memory extension (subprocess provider) | no upstream to track |
| config | — | — | preset: settings, skills, agents | own |
| devstack | — | — | this stack | own |
One squashed patch commit on lpb (packages/ai, packages/agent, …):
| Patch | What it does | File |
|---|---|---|
reasoning_effort |
Send reasoning_effort (high/medium/low) for Qwen models via the qwen / qwen-chat-template thinking formats |
packages/ai/src/api/openai-completions.ts |
reasoning_budget_tokens |
Add reasoning-budget token support/typing for Qwen to prevent runaway thinking | packages/ai/src/types.ts, generate-models.ts, ai tests |
| Case 4 context overflow | Add Case 4 to isContextOverflow: Qwen/Llama.cpp reasoning overflow (stopReason=length + output>0 + input ≥ 90% window) |
packages/ai/src/utils/overflow.ts |
| compaction tuning | Adjust compaction for Qwen thinking windows | packages/agent/src/harness/compaction/compaction.ts |
| reasoning wiring | reasoning_effort field plumbing in coding-agent config |
packages/coding-agent/src/config.ts |
Update: rebase the patch onto the next upstream release (after v0.83.0).
One squashed patch commit on lpb (extensions/index.ts, +287/-49): API-key
auth type registration, Qwen thinking-format support (thinkingLevelMap),
vision-capability detection, and reasoning-format handling. Update policy: no
stable release upstream yet — check periodically and rebase onto upstream
main.
One squashed patch commit on master (src/index.ts, src/settings.ts,
src/agent-runner.ts, src/default-agents.ts): a centralized subagent model
registry (remove Anthropic-heavy defaults; make all subagents inherit the
session model), plus removal of a workflow file (OAuth scope limitation). If
this patch proves clean and generally useful, submit it upstream.
Original Hermes base was fully refactored and is now an independent project (no upstream to track). Provides the Pi memory extension: subprocess-based background reviews, model-override propagation, memory store + handlers.
Patches are candidate upstream contributions: they go upstream only if generally useful and not too opinionated for this stack's specific configuration. Local-workaround-specific patches or ones that diverge from upstream design direction stay on the LocalPibox fork branch.
You can fork this repo, personalize it, and repoint it at your own managed set of repositories (Pi core, config preset, and extensions) instead of the LocalPibox originals.
| Component | URL / ref lives in | Effort | Repoint path |
|---|---|---|---|
| Extensions (lemonade-pi-plugin, lpb-memory, pi-subagents, …) | runtime config ~/.pi/agent/settings.json → packages |
🟢 trivial, no rebuild | edit the packages array, or pi install git:<fork>/<repo>; applied at next startup via pi update --extensions |
| Config preset (lpb-stack/config) | lpb.stack.env → LPB_CONFIG_FORK / LPB_CONFIG_REF |
🟡 one rebuild, or no rebuild at runtime | rebuild --build-arg CONFIG_FORK=..., or git -C ~/.pi/agent/ remote set-url origin <fork> (no rebuild) |
| Pi core (lpb-stack/pi) | lpb.stack.env → LPB_PI_FORK / LPB_PI_REF |
🔴 image rebuild | fork lpb-stack/pi, set engine + LPB_IMAGE_CLI, rebuild |
-
Fork the repos you care about (e.g.
lpb-stack/pi,lpb-stack/config). -
Clone this repo (devstack) and edit
lpb.stack.envat the root to point at your forks:export LPB_PI_FORK=https://github.com/<you>/pi.git export LPB_PI_REF=main # your branch export LPB_CONFIG_FORK=https://github.com/<you>/config.git export LPB_CONFIG_REF=main # your branch export LPB_IMAGE_CLI=ghcr.io/<you>/devstack:cli export LPB_IMAGE_WEB=ghcr.io/<you>/devstack:web export LPB_CONTAINER_NAME=mybox # avoid colliding with lpb-stack
(Or pass them as
docker build --build-arg PI_FORK=... --build-arg CONFIG_FORK=...without editing the file.) -
Build and push the image (locally, or via the GitHub Actions workflow, which reads
lpb.stack.env). -
Install/run
lpb— it reads the samelpb.stack.envfor image/container names, so it picks up your fork automatically. -
Point the launcher at your image
~/.lpb-stack/devstack/config→export LPB_IMAGE_NAME="ghcr.io/<you>/devstack:latest", or let the forkedlpbhandle it.
The config preset is a git clone at ~/.pi/agent/ (container). After
first boot you can repoint it live — no image rebuild needed:
podman exec -it lpb-stack bash
cd ~/.pi/agent/
git remote set-url origin https://github.com/<you>/config.git
git pull --ff-only origin <your-branch>
# re-seed the runtime copy from your preset
# Config repo IS ~/.pi/ — managed by start.sh at container startupExtensions are not baked in; they are installed on first boot from
settings.json#packages. Repoint them from the running container:
podman exec -it lpb-stack pi remove git:github.com/lpb-stack/lemonade-pi-plugin
podman exec -it lpb-stack pi install git:github.com/<you>/lemonade-pi-plugin@<your-branch>
podman exec -it lpb-stack pi update --extensionsChanges apply at the next pi startup (or /reload in a running session
for config).
Built automatically on GitHub Actions when:
- Push to
main(Dockerfile, support/, lpb.stack.env) - Weekly (Monday 3am UTC) — keeps image fresh
- Manual dispatch with flags
actions/checkout@v6docker/build-push-action@v7docker/setup-buildx-action@v4docker/setup-qemu-action@v4docker/login-action@v4docker/metadata-action@v6actions/upload-artifact@v7
# Check who's using the port
lsof -i :3000
# Stop existing container
podman stop lpb-stack
podman rm lpb-stack
# Run with new port
podman run -d --name lpb-stack --network host --userns keep-id \
-e ED_PORT=8080 \
-v /path/to/project:/home/lpb/workspace/myproject:Z \
-v ~/.lpb-stack/state:/home/lpb/.pi:Z \
-v ~/.lpb-stack/agent-browser:/home/lpb/.agent-browser:Z \
ghcr.io/lpb-stack/devstack:latest
# → http://localhost:8080# Login in the editor (Ctrl+Shift+P → "Pi: Login")
# Or via CLI
podman exec -it lpb-stack pi loginpodman exec -it lpb-stack update --extensions# Pull from GHCR (newer build)
podman pull ghcr.io/lpb-stack/devstack:latest
podman stop lpb-stack && podman rm lpb-stack
podman run -d --name lpb-stack --network host --userns keep-id \
-v /path/to/project:/home/lpb/workspace/myproject:Z \
-v ~/.lpb-stack/state:/home/lpb/.pi:Z \
-v ~/.lpb-stack/agent-browser:/home/lpb/.agent-browser:Z \
ghcr.io/lpb-stack/devstack:latestclassDiagram
class devstack {
+Dockerfile
+lpb.stack.env
+lpb.conf.env
+.env.example
+.env
}
class scripts {
+lpb (bash wrapper)
+lpb.py (Python launcher)
+install.sh
}
class doc {
+ARCHITECTURE.md
+BRANCH-STRATEGY.md
+*.md
}
class support {
+entrypoint-cli.sh
+entrypoint-web.sh
+install-browser.sh
+install-openspec.sh
+start.sh
+validate.sh
}
class workspace {
+pi/
+config/
+lemonade-pi-plugin/
+lpb-memory/
+pi-subagents/
}
devstack --> scripts : contains
devstack --> doc : contains
devstack --> support : contains
devstack --> workspace : contains
- lpb-stack/pi — Forked Pi monorepo with Qwen reasoning support
- lpb-stack/lemonade-pi-plugin — Lemonade provider plugin
- lpb-stack/config — Pi configuration (settings, mcp, skills)
- lpb-stack/lpb-memory — Persistent memory + session search extension
- lpb-stack/lpb-stack — Project overview & stack reference
- lpb-stack/lpb-stack.github.io — Project site (GitHub Pages)