Phase 17 — pip Packaging + local2 CLI ✅ COMPLETE

Make LoCAL2 installable as a standard Python package. The install story goes from "clone repo, manage paths manually" to pip install local2.

✅ Complete — commits c3780bc → 5ed4b4e (2026-06-10), version 0.1.9

Motivation

Phase 16 delivered the web UI. The remaining friction to sharing LoCAL2 was the install story: users had to clone the repo, set PYTHONPATH, and figure out SearXNG setup themselves. Phase 17 resolves this with a proper pyproject.toml, a local2 CLI entry point that handles first-run setup, and a data directory (~/.local2/) that stores user config outside the repo.

Install story after Phase 17: pip install local2local2 setuplocal2 → open browser

Milestones

17.1 — pyproject.toml + hatchling build

Replace setup.py / requirements.txt with a pyproject.toml using hatchling as the build backend. All runtime dependencies declared. The React frontend/dist/ bundle is included as a build artifact so it ships with the wheel.

Dependencies declared

ollama, fastapi, uvicorn, websockets, pydantic, pyzmq, PySide6,
PyYAML, httpx, python-multipart, beautifulsoup4, chromadb, pypdf

Files

17.2 — Data directory (~/.local2/)

User config, SearXNG docker-compose, and generated secrets live in ~/.local2/ — not inside the repo or install path. This lets the package be updated without clobbering user settings.

Files

17.3 — local2 CLI entry point

A single local2 command handles all startup modes and first-run setup. Delegates to src/local/run.py for the main runtime.

local2                       # web UI, opens browser
local2 --headless            # web server only (no browser pop)
local2 --panels              # web UI + Qt observer panels
local2 --desktop             # legacy PySide6 UI
local2 setup                 # init config + pull Ollama models
local2 setup --models-only   # re-pull models only
local2 setup --config-only   # re-init config only
local2 searxng up            # start SearXNG in Docker
local2 searxng down          # stop SearXNG
local2 searxng status        # show container status

Files

17.4 — File attachments in web UI

Paperclip button in the web chat interface. Files are uploaded via POST /api/attachments, stored server-side for the duration of the query, and passed through the WebSocket → session → bus pipeline to the GeneratorAgent.

Files

17.5 — Remote-bus mode (--web-only / --ipaddress)

Enables a split deployment where the web server runs on one machine and the agent bus runs on another (LAN use case). The web server connects to a remote ZMQ proxy rather than starting its own.

Files

File Map

FileStatusNotes
pyproject.tomlnewhatchling build, all deps, local2 entry point, frontend/dist artifact
src/local/cli.pynewlocal2 CLI: setup, searxng subcommands; delegates to run.py
src/local/run.pynewmain runtime moved from run_local.py; --web-only/--ipaddress flags
src/local/data_dir.pynewget_data_dir() → ~/.local2/; LOCAL2_DATA_DIR override
src/local/api/gateway.pymodifiedPOST /api/attachments endpoint; python-multipart dep
frontend/src/components/MessageInput.tsxmodifiedpaperclip button, attachment chip display
run_local.pykeptthin shim delegating to src/local/run.py for dev-mode runs

Run Modes After Phase 17

# Standard (pip install)
pip install local2
local2 setup        # first run: write config, pull models
local2              # open browser → localhost:8080

# Dev (repo checkout)
python run_local.py              # same as local2
python run_local.py --headless   # no browser
python run_local.py --panels     # Qt observer panels alongside web UI
python run_local.py --desktop    # legacy PySide6 UI

# Remote / LAN split
local2 --ipaddress 192.168.1.42 --web-only   # web layer only, bus on remote machine

# SearXNG
local2 searxng up      # start Docker container
local2 searxng status  # check it's running
local2 searxng down    # stop it

Acceptance Criteria

What's Next