Files

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. 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.

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 <p> --database-uri … --artifact-location … Waited on via GET /health.
host uv run omnigent host --server http://127.0.0.1:<p> Started once the server is healthy.
vite npm run dev -- --host <host> --port <p> --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 <pod>/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/<repo-name>-<hash>/, keyed to the canonical checkout path. Per-process logs are written through to <pod>/logs/{server,host,vite}.log for inspection outside the TUI.

Options

--server-port <N>   Force the backend port (default: probe from 6767)
--vite-port <N>     Force the Vite port (default: probe from 5173)
--vite-host <ADDR>  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 <PATH>    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://<your-lan-ip>:<vite-port>, 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://<ip>:<vite-port> 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.

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 <branch/tag/sha> (default main), --extra <name> (repeatable; defaults to databricks), --no-default-extra (install with no extras), --repo <url>. 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:

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.