commit 55f82338e086f2fa18cbb51c7bf57ffd5e98ac6c Author: sam Date: Thu Sep 10 09:50:31 2026 +1000 Paseo build docs: README, mermaid diagram, Archify map — Docker on .13, pi provider, OmniRoute diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0c594f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# secrets — never commit +.env +*.env diff --git a/README.md b/README.md new file mode 100644 index 0000000..81d9206 --- /dev/null +++ b/README.md @@ -0,0 +1,138 @@ +# Paseo — Agent Orchestration on the Home Lab + +**Multi-agent orchestration GUI (Paseo 0.7.2) self-hosted in Docker on `.13`, driving real pi +coding agents (0.82.1) through OmniRoute.** + +> Maintained by Sam · Gitea — [sam/paseo](https://gitea.lab.audasmedia.com.au/sam/paseo) · +> interactive map: [maps.lab → Paseo](https://maps.lab.audasmedia.com.au/paseo/docs/system-map.html) + +--- + +## What it is + +[Paseo](https://github.com/getpaseo/paseo) is a client-server orchestration layer for AI coding +agents: one **daemon** manages agent processes and streams their output to desktop, CLI, mobile and +web clients. On this lab it runs **inside Docker on the always-on host `.13`**, with **pi** (the +coding agent) baked into the image and LLM traffic routed through the existing **OmniRoute** proxy +on `.13:20129`. + +- **Local-first** — agents run on our machines/dev environment; no telemetry. +- **Pi is a first-class provider** — the daemon spawns `pi --mode rpc` (pi 0.82.1, no Nix changes). +- **One console** — `paseo ls` / `attach` / `logs` from anywhere: `.27`, `.51`, mobile, web UI. + +## Architecture + +```mermaid +flowchart LR + subgraph CLIENTS["Clients"] + D27[".27 desktop
paseo CLI"] + D51[".51 laptop
paseo CLI"] + M["Mobile / web UI
browser"] + end + subgraph S13["Paseo daemon (.13 — Docker, always-on)"] + D["Paseo daemon 0.7.2
:6767 · auth"] + PI["pi agent 0.82.1
pi --mode rpc
@earendil pi + omni ext"] + CFG["pi config
/home/paseo/.pi"] + W["workspaces
/workspace/demo"] + PWD["PASEO_PASSWORD
.env (600)"] + end + subgraph LLM["LLM routing"] + OR["OmniRoute
.13:20129"] + OP["OpenCode-Go /
OpenRouter / DeepSeek / Gemini"] + end + D27 -->|"PASEO_HOST + password"| D + D51 -->|"PASEO_HOST + password"| D + M -->|"https :6767"| D + D -->|"spawns / manages"| PI + PI -->|"reads settings + models"| CFG + PI -->|"works in"| W + D -->|"protects"| PWD + PI -->|"httpx /v1 (omni provider)"| OR + OR -->|"combo routing"| OP +``` + +## Directory map + +``` +paseo/ +├── README.md ← this file +└── docs/ + ├── system.mmd ← Mermaid source (single source of truth) + ├── system.architecture.json ← Archify source + ├── system-map.html ← interactive Archify map + └── diagrams/ + ├── system.png + └── system.svg +``` + +## Quick start (client) + +```bash +# .27 / .51 (one-time) +npm install -g @getpaseo/cli@0.7.2 + +export PASEO_HOST=192.168.20.13:6767 +export PASEO_PASSWORD= + +paseo status # daemon reachable? +paseo ls # running agents +paseo run --provider pi --model omni/openrouter/qwen/qwen3.7-flash \ + --cwd /workspace/demo "describe this workspace" +paseo logs # full activity timeline +``` + +Web UI: `http://192.168.20.13:6767` (password). Mobile: browser over LAN/Tailscale. + +## Deployment (server, `.13`) + +| Item | Value | +|---|---| +| Compose dir | `/home/sam/Docker/Containers/paseo/` | +| Image | `ghcr.io/getpaseo/paseo:latest` + custom stage | +| Daemon | 0.7.2 · `restart: always` · :6767 | +| pi | `@earendil-works/pi-coding-agent@0.82.1` (baked, `--mode rpc`) | +| Extensions | `omniroute-pi-ext-integration` (baked) | +| Config | `./paseo-home:/home/paseo` (persists pi + paseo config) | +| Workspace | `./workspace:/workspace` (agent project area) | +| LLM | pi → omni provider → `http://192.168.20.13:20129/v1` (OmniRoute) | +| Secrets | `.env` (chmod 600) — `PASEO_PASSWORD`, `OMNIROUTE_API_KEY` | + +**Build note:** base image runs as user `paseo` (uid 1000) with root-owned `/usr/local` — so pi and +the extension are installed at **build time** under `USER root` in the Dockerfile, then dropped back +to `USER paseo` for runtime. + +## Verified end-to-end (2026-09-09) + +``` +$ paseo run --provider pi --model omni/openrouter/qwen/qwen3.7-flash \ + --cwd /workspace/demo --title paseo-demo --background \ + "List files, read HELLO.txt, write DEMO_SUMMARY.md" + +AGENT ID 560ffca0-… STATUS running PROVIDER pi CWD /workspace/demo + ↓ +AGENT ID 560ffca0-… STATUS idle PROVIDER pi/omni/openrouter/qwen/qwen3.7-flash + ↓ → wrote ./workspace/demo/DEMO_SUMMARY.md (correct content) + ↓ → `paseo logs` shows full timeline (user → thought → shell → read) + ↓ → web UI :6767 → HTTP 200 +``` + +## Known findings + +- **OmniRoute combo regression:** the default `default-opencode-go-ds-flash` combo currently returns + `400 missing x-opencode-session` (OpenCode-Go leg) — affects host pi too, not just the container. + Working legs verified: `openrouter/qwen/qwen3.7-flash`, `openrouter/openai/gpt-5.6-sol`, + `aug/claude-haiku-4.5`. Fix the combo/credentials on OmniRoute to restore the default path. +- Paseo is pre-1.0 (0.7.2) — pin the version; expect breaking changes between releases. +- CLI runtime install on `.27` carries 3 low/medium CVEs in transitive deps (`qs`, `uuid`, + `@ai-sdk/provider-utils`) — vet/npq scanned clean, author verified. + +## Why it matters + +- **Proof the stack composes:** Nix pi binary stays untouched; the lab's OmniRoute routing powers a + third-party orchestrator; one always-on Docker host (.13) gives fleet control from any device. +- **A pattern for multi-agent work:** workspaces + `pi --mode rpc` + OmniRoute is a base for + coordinating several pi agents on real projects — exactly the coordination layer the lab needs. + +--- + +*Documentation project — no proprietary code. Secrets never appear in this repo.* \ No newline at end of file diff --git a/docs/diagrams/system.png b/docs/diagrams/system.png new file mode 100644 index 0000000..c10fc12 Binary files /dev/null and b/docs/diagrams/system.png differ diff --git a/docs/diagrams/system.svg b/docs/diagrams/system.svg new file mode 100644 index 0000000..fc989d7 --- /dev/null +++ b/docs/diagrams/system.svg @@ -0,0 +1 @@ +

LLM routing

Paseo daemon (.13 — Docker, always-on)

Clients

PASEO_HOST + password

PASEO_HOST + password

https :6767

spawns / manages

reads settings + models

works in

protects

httpx /v1 (omni provider)

combo routing

.27 desktop
paseo CLI

.51 laptop
paseo CLI

Mobile / web UI
browser

Paseo daemon 0.7.2
:6767 · auth

pi agent 0.82.1
pi --mode rpc
@earendil pi + omni ext

pi config
/home/paseo/.pi

workspaces
/workspace/demo

PASEO_PASSWORD
.env (600)

OmniRoute
.13:20129

OpenCode-Go /
OpenRouter / DeepSeek / Gemini

\ No newline at end of file diff --git a/docs/system-map.html b/docs/system-map.html new file mode 100644 index 0000000..bc1681b --- /dev/null +++ b/docs/system-map.html @@ -0,0 +1,13677 @@ + + + + + + + Paseo on the Home Lab Diagram + + + + + + + + + + + +
+ +
+
+
+

Paseo on the Home Lab

+
+
+ + + + + + +
+ + Paseo on the Home Lab + A architecture diagram generated by Archify. + + + + + + + + + + + + + + + + + + + + + + + + + clients + + + Paseo daemon (.13 Docker) + + + + + + + + + + + + + paseo CLI · .27 / .51 · clients + + + + paseo CLI + .27 / .51 + + + + Web UI / mobile · browser :6767 · clients + + + + Web UI / mobile + browser :6767 + + + + Paseo daemon · 0.7.2 · :6767 · auth · Paseo daemon (.13 Docker) + + + + Paseo daemon + 0.7.2 · :6767 · auth + + + + pi agent · 0.82.1 · --mode rpc · Paseo daemon (.13 Docker) + + + + pi agent + 0.82.1 · --mode rpc + + + + pi config · paseo-home/.pi · Paseo daemon (.13 Docker) + + + + pi config + paseo-home/.pi + + + + workspace · /workspace/demo · Paseo daemon (.13 Docker) + + + + workspace + /workspace/demo + + + + OmniRoute · .13:20129 · Architecture component + + + + OmniRoute + .13:20129 + + + + LLM providers · combo routing · Architecture component + + + + LLM providers + combo routing + + + + + + PASEO_HOST + password + + + + https :6767 + + + + spawns / manages + + + + reads settings + models + + + + works in + + + + omni provider /v1 + + + + combo routing + + + + + Legend + + + Frontend + + + + Backend + + + + Database + + + + External + + + +

+ + + + + + + + +
+ + +
+
+
+
+

Proven end-to-end

+
+
    +
  • • paseo run --provider pi → agent 560ffca0 (pi/omni/openrouter/qwen/qwen3.7-flash)
  • +
  • • Agent read HELLO.txt, wrote DEMO_SUMMARY.md into /workspace/demo
  • +
  • • paseo logs shows full timeline (user → thought → shell → read)
  • +
  • • Web UI http://192.168.20.13:6767 → HTTP 200
  • +
+
+ +
+
+
+

Deployment facts

+
+
    +
  • • Container: /home/sam/Docker/Containers/paseo/ (restart: always)
  • +
  • • pi + omniroute ext baked at build time (USER root) — image runs as paseo (uid 1000)
  • +
  • • pi 0.82.1 in container; host Nix pi untouched
  • +
  • • Secrets only in .env (chmod 600)
  • +
+
+ +
+
+
+

Findings

+
+
    +
  • • OmniRoute default combo (default-opencode-go-ds-flash) → 400 x-opencode-session issue
  • +
  • • Working models: openrouter/qwen/qwen3.7-flash, openrouter/openai/gpt-5.6-sol, aug/claude-haiku-4.5
  • +
  • • Fix combo/credentials on OmniRoute to restore the default path
  • +
+
+
+ +
+ + + + diff --git a/docs/system.architecture.json b/docs/system.architecture.json new file mode 100644 index 0000000..6270f59 --- /dev/null +++ b/docs/system.architecture.json @@ -0,0 +1,164 @@ +{ + "schema_version": 1, + "diagram_type": "architecture", + "meta": { + "title": "Paseo on the Home Lab", + "quality_profile": "showcase", + "viewBox": [1120, 600] + }, + "components": [ + { + "id": "cli", + "type": "frontend", + "label": "paseo CLI", + "sublabel": ".27 / .51", + "pos": [120, 120] + }, + { + "id": "web", + "type": "frontend", + "label": "Web UI / mobile", + "sublabel": "browser :6767", + "pos": [120, 240] + }, + { + "id": "daemon", + "type": "backend", + "label": "Paseo daemon", + "sublabel": "0.7.2 · :6767 · auth", + "pos": [420, 120] + }, + { + "id": "pi", + "type": "backend", + "label": "pi agent", + "sublabel": "0.82.1 · --mode rpc", + "pos": [420, 300] + }, + { + "id": "cfg", + "type": "database", + "label": "pi config", + "sublabel": "paseo-home/.pi", + "pos": [700, 300] + }, + { + "id": "ws", + "type": "database", + "label": "workspace", + "sublabel": "/workspace/demo", + "pos": [700, 440] + }, + { + "id": "omni", + "type": "backend", + "label": "OmniRoute", + "sublabel": ".13:20129", + "pos": [760, 120] + }, + { + "id": "llm", + "type": "external", + "label": "LLM providers", + "sublabel": "combo routing", + "pos": [940, 120] + } + ], + "boundaries": [ + { + "kind": "region", + "label": "clients", + "wraps": ["cli", "web"] + }, + { + "kind": "region", + "label": "Paseo daemon (.13 Docker)", + "wraps": ["daemon", "pi", "cfg", "ws"] + } + ], + "connections": [ + { + "id": "cli-to-daemon", + "from": "cli", + "to": "daemon", + "label": "PASEO_HOST + password", + "labelAt": [270, 60] + }, + { + "id": "web-to-daemon", + "from": "web", + "to": "daemon", + "label": "https :6767" + }, + { + "id": "daemon-to-pi", + "from": "daemon", + "to": "pi", + "label": "spawns / manages", + "labelAt": [480, 205], + "fromSide": "bottom", + "toSide": "top" + }, + { + "id": "pi-to-cfg", + "from": "pi", + "to": "cfg", + "label": "reads settings + models", + "labelAt": [700, 370] + }, + { + "id": "pi-to-ws", + "from": "pi", + "to": "ws", + "label": "works in", + "labelAt": [700, 520] + }, + { + "id": "pi-to-omni", + "from": "pi", + "to": "omni", + "label": "omni provider /v1", + "labelAt": [590, 225], + "fromSide": "right", + "toSide": "bottom" + }, + { + "id": "omni-to-llm", + "from": "omni", + "to": "llm", + "label": "combo routing", + "labelAt": [910, 194] + } + ], + "cards": [ + { + "dot": "cyan", + "title": "Proven end-to-end", + "items": [ + "paseo run --provider pi → agent 560ffca0 (pi/omni/openrouter/qwen/qwen3.7-flash)", + "Agent read HELLO.txt, wrote DEMO_SUMMARY.md into /workspace/demo", + "paseo logs shows full timeline (user → thought → shell → read)", + "Web UI http://192.168.20.13:6767 → HTTP 200" + ] + }, + { + "dot": "emerald", + "title": "Deployment facts", + "items": [ + "Container: /home/sam/Docker/Containers/paseo/ (restart: always)", + "pi + omniroute ext baked at build time (USER root) — image runs as paseo (uid 1000)", + "pi 0.82.1 in container; host Nix pi untouched", + "Secrets only in .env (chmod 600)" + ] + }, + { + "dot": "amber", + "title": "Findings", + "items": [ + "OmniRoute default combo (default-opencode-go-ds-flash) → 400 x-opencode-session issue", + "Working models: openrouter/qwen/qwen3.7-flash, openrouter/openai/gpt-5.6-sol, aug/claude-haiku-4.5", + "Fix combo/credentials on OmniRoute to restore the default path" + ] + } + ] +} \ No newline at end of file diff --git a/docs/system.mmd b/docs/system.mmd new file mode 100644 index 0000000..40f7101 --- /dev/null +++ b/docs/system.mmd @@ -0,0 +1,26 @@ +flowchart LR + subgraph CLIENTS["Clients"] + D27[".27 desktop
paseo CLI"] + D51[".51 laptop
paseo CLI"] + M["Mobile / web UI
browser"] + end + subgraph S13["Paseo daemon (.13 — Docker, always-on)"] + D["Paseo daemon 0.7.2
:6767 · auth"] + PI["pi agent 0.82.1
pi --mode rpc
@earendil pi + omni ext"] + CFG["pi config
/home/paseo/.pi"] + W["workspaces
/workspace/demo"] + PWD["PASEO_PASSWORD
.env (600)"] + end + subgraph LLM["LLM routing"] + OR["OmniRoute
.13:20129"] + OP["OpenCode-Go /
OpenRouter / DeepSeek / Gemini"] + end + D27 -->|"PASEO_HOST + password"| D + D51 -->|"PASEO_HOST + password"| D + M -->|"https :6767"| D + D -->|"spawns / manages"| PI + PI -->|"reads settings + models"| CFG + PI -->|"works in"| W + D -->|"protects"| PWD + PI -->|"httpx /v1 (omni provider)"| OR + OR -->|"combo routing"| OP \ No newline at end of file