# omnidev Dev tooling for Omnigent, in one binary with two independent capabilities: 1. A per-repo dev **pod supervisor** (bare `omnidev`) — the default. 2. **Install management** (`omnidev install`/`update`/`check`) — install and keep a git-based omnigent up to date. See [Managing your omnigent install](#managing-your-omnigent-install). These subcommands need no checkout and run anywhere. ## Pod supervisor A per-repo dev **pod** supervisor, as a single long-running terminal UI. It replaces the three-terminal local dev flow (`omnigent server`, `omnigent host`, `npm run dev`) with one process that: - runs each checkout in an **isolated pod** — its own state dir, database, artifacts, logs, and auto-allocated ports — so multiple worktrees never collide; - **supervises** the backend server, the host daemon, and the Vite frontend, restarting any that crash (with backoff); - **reloads the backend** (server → host) when you edit `omnigent/**/*.py`; the frontend self-reloads through Vite HMR; - gives you **scrollable per-process log panes** plus a combined view. ## Build & run Requires the repo's usual dev prerequisites (`uv` for Python, `npm` for the web UI) plus a Rust toolchain. ```bash cd dev/omnidev cargo run # launches the TUI for the surrounding checkout ``` Run it from anywhere inside the checkout — it walks up to the repo root (the `.jj`/`.git` marker) and requires `omnigent/` and `web/` to be present. Build a release binary with `cargo build --release` (lands at `target/release/omnidev`). ## What it starts | Process | Command | Notes | |---|---|---| | server | `uv run omnigent server --host 127.0.0.1 --port

--database-uri … --artifact-location …` | Waited on via `GET /health`. | | host | `uv run omnigent host --server http://127.0.0.1:

` | Started once the server is healthy. | | vite | `npm run dev -- --host --port

--strictPort` (cwd `web/`) | `OMNIGENT_URL` points its proxy at the pod's server. | Before Vite starts (and on a manual Vite restart), omnidev runs `npm install` in `web/` when needed — `node_modules/` is missing, or `package.json` / `package-lock.json` is newer than it — so a fresh checkout or a new dependency doesn't make Vite fail its dependency scan. Output streams into the `vite` pane. Open the UI at the `ui` URL shown in the header (the Vite dev server). ## Isolation Only Omnigent's own state is isolated per pod — enough that concurrent pods never share a database, server pidfile, or `config.yaml` — via `OMNIGENT_DATA_DIR`, `OMNIGENT_DATABASE_URI`, `OMNIGENT_URL`, and `OMNIGENT_CONFIG_HOME`. Everything else (your real `HOME`, credentials, and uv/npm caches) is inherited, because the agents Omnigent runs need it. This is deliberately lighter than the hermetic `scripts/backend-smoke.sh` sandbox, which repoints `HOME`/`XDG_*` to touch nothing real. Each pod gets its own `config.yaml` under `/config/`, pointed to by `OMNIGENT_CONFIG_HOME`. On first create it's **seeded** from your real `~/.omnigent/config.yaml` (if present) so the pod works out of the box — it keeps your providers — after which the two are independent: server-config edits inside a pod (via the UI or `omnigent config`) don't touch your real config. `--clean` wipes the pod dir, so the next run re-seeds from your real config. The pod dir defaults to `${XDG_CACHE_HOME:-~/.cache}/omnidev/-/`, keyed to the canonical checkout path. Per-process logs are written through to `/logs/{server,host,vite}.log` for inspection outside the TUI. ## Options ``` --server-port Force the backend port (default: probe from 6767) --vite-port Force the Vite port (default: probe from 5173) --vite-host Vite bind host (default: 127.0.0.1; use 0.0.0.0 for LAN access) --trust-lan-origins Trust this machine's LAN origins (for device testing) --pod-dir Use a specific pod dir instead of the per-repo default --no-vite Backend + host only (no frontend) --clean Wipe the pod dir before starting ``` `--vite-host 0.0.0.0` exposes the Vite dev server on all interfaces for device testing. Vite still proxies API traffic to the pod backend through `127.0.0.1`. ### Testing from a phone or tablet `--vite-host 0.0.0.0` alone lets a device load the UI, but the backend runs in single-user local mode, where its CSRF/CSWSH guard trusts only loopback origins. A device loads the UI at `http://:`, so its browser stamps that non-loopback origin on every request — and the guard then rejects multipart uploads (403) and refuses the live WebSocket stream. `--trust-lan-origins` fixes that: omnidev enumerates this machine's LAN IPv4 addresses and trusts the matching `http://:` origins via the server's `OMNIGENT_WS_ALLOWED_ORIGINS` allowlist (merged with any value you already export). It stays exact-match — only those origins are trusted, nothing is disabled — so it's for dev pods, not deployed servers. The trusted origins are printed in the combined log at startup. ```bash omnidev --vite-host 0.0.0.0 --trust-lan-origins ``` This covers IPv4 LAN addresses; mDNS `.local` hostnames and HTTPS origins are not auto-trusted (add those to `OMNIGENT_WS_ALLOWED_ORIGINS` yourself). ## Keys | Key | Action | |---|---| | `1` / `2` / `3` / `0` | Focus server / host / vite / combined pane | | `Tab` | Cycle panes | | `↑` `↓` `PgUp` `PgDn` | Scroll (detaches from tail) | | `f` | Toggle follow-tail | | `r` | Restart the focused process (server/host restart as a pair) | | `R` | Restart the backend (server then host) | | `c` | Clear the focused pane | | `q` / `Ctrl-C` | Quit and tear down all processes | ## Managing your omnigent install For people who *run* omnigent (installed from git via `uv tool install`) rather than develop it. This wraps the fiddly PEP 508 install syntax and adds a daily update check — filling a gap, since omnigent's own update notice only works for PyPI-wheel installs and skips git installs. These subcommands manage the global tool and work from **any directory** (no checkout needed). ``` omnidev install # uv tool install omnigent from git (databricks extra, main) omnidev update # reinstall the latest of the tracked ref/extras omnidev check # check for an update; prompt to update on a TTY omnidev refresh # refresh the check cache from the network (usually detached) omnidev shell-hook # print the daily-check snippet for your shell rc ``` `install` options: `--ref ` (default `main`), `--extra ` (repeatable; defaults to `databricks`), `--no-default-extra` (install with no extras), `--repo `. The choice is saved to `${XDG_CONFIG_HOME:-~/.config}/omnidev/install.toml` so `update` reuses it. Installing from git **builds the web UI from source**, so Node 22+/npm must be on PATH (the PyPI wheel ships the UI prebuilt; the git install does not). `omnidev install` fails early with a clear message if `uv` or `npm` is missing. ### Daily update check Append the hook to your shell rc once to be told, at most once a day, when a newer `main` commit is available — and be offered to update on the spot: ```bash omnidev shell-hook >> ~/.zshrc # or ~/.bashrc ``` The snippet itself guards on `command -v omnidev`, so it's a no-op in shells where omnidev isn't on PATH — nothing to fail. (Appending the snippet is preferred over `eval "$(omnidev shell-hook)"`: the latter would run omnidev on every shell startup and print a "command not found" error whenever omnidev is absent.) On each interactive shell it runs `omnidev check --quiet`, which reads a cached result (`${XDG_CACHE_HOME:-~/.cache}/omnidev/omnigent-check.json`) and, when stale (>24h), refreshes it in a detached background process — so shell startup never blocks on the network. When a newer commit is available it prints a notice and, on a terminal, prompts `Update omnigent now? [y/N]`; on yes it runs `omnidev update` in the foreground. Declining suppresses that same commit until a newer one lands. Set `OMNIGENT_NO_UPDATE_CHECK` in your environment if you want to silence omnigent's own separate notice.