Web UI app for oh-my-pi (omp) coding agent.
English | 简体中文 | 日本語 | Русский
ompweb provides a browser workspace for your local omp runtime: session browsing with branch navigation and forking, real-time chat over the omp RPC protocol, model / MCP / skill management, Git worktree switching, and rich file previews. Skill conflicts and redundant installations appear above the composer when an omp session starts; × dismisses the notice for that session until the report changes, and Turn off and Settings → Skill startup notices disable it.
📸 I believe screenshots sometimes describe better than words
The project is primarily adapted to run inside Docker (Linux): the docker-compose.yaml at the repository root builds the image, mounts the repository, and maps the launcher ports. Start it with a single command:
docker compose up -d --buildthen open http://127.0.0.1:6767 (see Environment variables below for the password).
Note: the compose file binds c:/users/dev/.omp to /root/.omp inside the container by default — please update this source: path to the .omp store of your own user (~/.omp on Linux, or c:/users/{user}/.omp on Windows) before starting the container, so that the container uses your existing credentials, sessions, and settings.
The mobile web version is a full-featured PWA: add it to your phone's home screen and it behaves like a native app. Building and running it as a standalone Windows / Linux / macOS application is equally supported. Forking the project and extending it is explicitly encouraged.
The launcher probes the sibling ports SIBLING_PORTS = [30177, 30178, 30179] (hardcoded in bin/omp-web.js); docker-compose.yaml maps all three into the container. Use these ports when an agent starts a dev server inside the container and you want to reach / debug it from a browser on the host.
The compose file ships a default OMP_WEB_PASSWORD_HASH — the hash of the dev
password asdf1234. Use that password at the login screen, or generate your
own (ompweb hash-password) and set OMP_WEB_PASSWORD_HASH in a .env file
next to the compose file (.env values are literal; only an inline compose
default needs its $ written as $$). A legacy plaintext OMP_WEB_PASSWORD
still works: the container entrypoint hashes it once, persists the hash under
the bound .omp store and clears the plaintext, so restarts keep sign-ins.
omp-web no longer hands a plaintext password to the server: every omp
session inherits the server's environment, so an agent running env could
print the password into its transcript and off to the model provider.
ompweb hashes a lone OMP_WEB_PASSWORD at startup, keeps the plaintext out
of the server's environment, and warns with the OMP_WEB_PASSWORD_HASH to set
instead. --password was removed, and setting both variables stops ompweb;
remove OMP_WEB_PASSWORD. Generate a hash with:
ompweb hash-password # prompts twice, input hidden
echo "a-long-random-password" | ompweb hash-password # or pipe it in
OMP_WEB_PASSWORD_HASH='scrypt$15$8$1$…' ompwebompweb hash-password reads the password from stdin — never from a command
line argument — so it stays out of your shell history and out of ps. The
hash is scrypt (N = 2^15, r = 8, p = 1) with a fresh 16-byte salt, printed as
scrypt$<ln>$<r>$<p>$<salt>$<digest>; anyone who reads it can neither sign in
with it nor turn it back into the password. Sessions are not signed with the
hash: a random per-installation key at
~/.omp/agent/omp-web/web-auth-secret.json (mode 0600) is mixed with it, so
a copied hash cannot forge a session and changing the password still signs
every browser out.
omp-web cannot see the client's address itself, so it leaves the decision to
your reverse proxy. The proxy sends a secret in the X-Omp-Web-Auth header,
and omp-web holds only that secret's SHA-256 digest in
OMP_WEB_TRUSTED_HEADER_SHA256. A request whose header hashes to that digest
is treated as signed in; everyone else still signs in with the password.
Without a configured password hash there is nothing to skip and the header is
ignored. Keep omp-web bound to 127.0.0.1 so only the proxy reaches it.
Generate the secret without typing it on a command line, so it never lands in shell history — this writes it into an nginx include and prints only the digest:
secret=$(openssl rand -hex 32)
printf 'map $ompweb_trusted $ompweb_auth {\n 1 "%s";\n default "";\n}\n' "$secret" \
| sudo install -m 0640 -o root -g www-data /dev/stdin /etc/nginx/ompweb-auth.conf
printf %s "$secret" | sha256sum | cut -d' ' -f1
unset secretSet the printed digest as OMP_WEB_TRUSTED_HEADER_SHA256. Always generate a
long random secret this way: omp-web stores only an unsalted SHA-256 digest,
which is safe only against dictionary attacks on a random value. In nginx,
pick the trusted clients with geo and always set the header — the empty
value replaces any X-Omp-Web-Auth a client sends itself:
# http {} context
geo $ompweb_trusted {
default 0;
10.0.0.0/16 1;
}
include /etc/nginx/ompweb-auth.conf; # the map written above
# the location that proxies to omp-web
proxy_set_header X-Omp-Web-Auth $ompweb_auth;Serve omp-web only under an explicit server_name, with a default_server
block answering every other hostname with return 444; — otherwise any site a
trusted browser visits can point its own domain at your nginx (DNS rebinding)
and have it add the secret. geo checks $remote_addr; when clients reach
nginx through another proxy (Cloudflare, Cloudflare Tunnel, …), use the
realip module
(set_real_ip_from the provider's published ranges + real_ip_header CF-Connecting-IP for Cloudflare) so the geo check sees the real client
address.
When the repository is mounted into the container (the compose default), a ompweb-rebuild-restart.sh script is registered in the Script schedulers settings as a manual-launch scheduler — a convenient way to rebuild and redeploy ompweb after your agent has modified the source. Only a page refresh is needed afterwards to pick up the new build. Once a fresh build is deployed and OmpWeb has started, you receive an in-UI notification offering a Refresh page button. Note: a concurrently running ompweb dev server instance may occasionally make the main instance's build stale.
The bundled multi-agent Agent MCP server is disabled by default. Enable it (Settings → Extensions & Tools → MCP) if you intend to let the OMP agent spawn and coordinate different agents.
The project incorporates improvements originally contributed by the kahme247 and 37chengshan forks, elegantly merged into the codebase with only the useful features retained; the majority of fixes were provided by Splinterjke. Selected improvements:
- Major bugs with files exploring, scrollbar weird behaviour and so on mostly solved, but some left specifically for you, hehe
- Configurable Context Compaction settings and priority
- A large set of new themes and palettes (Monokai family, Omarchy Monokai, Catppuccin, Rosé Pine, Harbor, omp Midnight, Oatmeal Latte an many others) with corrected surface tokens and themed text selection
- Git Graph modal — visual repository history with per-commit file diff browsing
- Improved RPC / IPC communication, including session restoration and turn continuation after server restarts
- OmpWeb rebuild & restart fixes: refresh notification with an explicit refresh button, loopback
/api/ui/refreshexemption, manual scheduler seeding - Chat minimap / scrollbar improvements: full-height rail, gradient accent beam, rail-height-bounded thumb, larger hover tooltips
- Clockwise gradient border beam on the chat input
- Unified, generalized font-size settings across the interface
- Expandable and resizable sections in the left sidebar, plus resizable sidebar / workbench panes
- Script schedulers functionality (interval, daily, weekly, cron, manual) with a dedicated settings panel
- Chat event actions — named automations (notification, HTTP request, bash command, scheduled script) triggered by chat lifecycle events, with event data variables in the payload
- Improved Skill Hub and Agents pages in Settings - Skill hub and Agents show instances not only from active workspace, but from each one
- Better new-session composer with workspace picker, plus-menu attachments, and context ring
- Expandable thinking and detail blocks with inline expansion of complete tool inputs
- 3-zone top bar with a center workspace / session breadcrumb, session-info popover, and sub-agents hub in the composer
- Removal of unnecessary extras, with layout / gutter and performance cleanups
To install the web app, sign in first and use your browser's installation menu.
The single manifest link requests /api/manifest with credentials; that endpoint
uses the existing web-password guard and private, revalidating caching. Its
192×192 and 512×512 PNG icons are embedded from the packaged favicon set because
Android's native installer fetches ordinary icon URLs without authentication
cookies. The app still launches at / with scope /.
No public manifest exception is needed; /api/manifest stays behind the same
password guard as every other API route. This does not add offline support.
Turn on notifications in Settings → Notifications. Each browser keeps its own settings: which events notify (task finished, waiting for input, run failed, model switched automatically) and what happens while you use omp-web in another tab (an in-app toast, or always a system notification). Nothing is shown for the session you are viewing. Clicking a notification opens its session.
- Push reaches the browser even when no omp-web tab is open. It needs a
secure context (HTTPS through your reverse proxy, or
localhost), and the omp-web server needs outbound HTTPS access to the browser vendors' push services. omp-web generates its push (VAPID) keys on first use and stores them with the device list in~/.omp/agent/omp-web/notifications.json(mode 0600). - On iPhone and iPad (iOS 16.4 or later), push works only in the app added to the Home Screen.
- In a secure context without push support, system notifications appear while an omp-web tab is open. Over plain HTTP on a non-localhost address, browsers allow no system notifications: only the in-app toasts shown while you use omp-web remain.
- Desktop browsers show notifications through the operating system's notification center. Push delivery needs the browser process running.
Completion notifications use omp's prompt_result and session_settled RPC
frames (omp 18.3.1 or later).
| Variable | Description | Default / Example |
|---|---|---|
PORT / -p / --port |
Server port | 6767 |
OMP_WEB_HOSTNAME / -H / --hostname |
Bind hostname | 127.0.0.1 |
OMP_WEB_PASSWORD_HASH |
Scrypt hash of the web sign-in password, from ompweb hash-password; required for a non-loopback bind (compose ships a default hash for the dev password asdf1234 — replace it for real deployments) |
(None / disabled) |
OMP_WEB_TRUSTED_HEADER_SHA256 |
SHA-256 hex digest of the secret a trusted reverse proxy sends in X-Omp-Web-Auth to skip the password for that request; see Skipping the password on trusted networks |
(None / disabled) |
OMP_WEB_ALLOWED_HOSTS |
Comma-separated non-loopback hosts allowed to reach the app | (empty — loopback only) |
OMP_WEB_NO_OPEN |
Skip opening browser automatically | 0 (1 to skip) |
OMP_WEB_DISABLE_AUTOUPDATE |
Set to 1 to disable update checks and in-app updates; restart after changing |
0 |
OMP_WEB_NAME |
Name shown in browser tabs and installed-app names. url, host or domain (any case) uses the hostname the browser connected to, without port; localhost and IP addresses keep omp web. Any other value is used as-is. Restart after changing |
omp web |
OMP_WEB_OMP_BIN |
Absolute path to omp binary |
Resolved from PATH |
OMP_WEB_DEV_ORIGIN |
Additional allowed hostname for the development server (no scheme or port); ignored in production | None |
OMP_WEB_STT_ENDPOINT |
OpenAI-compatible transcription endpoint URL | None (disabled) |
OMP_WEB_STT_KEY |
Optional API key for the STT endpoint | None |
OMP_WEB_STT_MODEL |
Optional model name for the STT endpoint | None |
PI_CODING_AGENT_DIR |
OMP agent home directory | ~/.omp/agent |
HTTP_PROXY / HTTPS_PROXY |
Proxies for server-side requests | (System default) |
OMP_WEB_NAME and installed apps. An installed app (PWA) is usually named after the page it was installed from. If you later change OMP_WEB_NAME, or reach omp-web through a different address while OMP_WEB_NAME is url, host or domain, your operating system may rename the installed app as well. Leave OMP_WEB_NAME empty, or set a name that identifies this omp-web server whatever domain name or address is used to reach it.
The development server allows loopback and RFC1918 private IPv4 origins
(10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16). When using a tunnel
or reverse proxy with a custom hostname, set it without editing next.config.ts:
OMP_WEB_DEV_ORIGIN=dev.example.com npm run devFor a persistent setup, set the variable in your local environment or service
configuration and restart the dev server. This does not change the bind address
or enable authentication. Next.js hostname patterns cannot express IPv6 CIDRs;
a private IPv6 origin must be supplied explicitly (for example, [fd00::1]).
Licensed under the MIT License.











































































































