| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Browser console and diagnostic chamber for Oh-My-Pi (omp) agent sessions.
Watch, steer and audit autonomous coding sessions from one paper-flat dashboard.
Architecture · Design · Changelog · Issues
The browser view onto a live omp install. It is not a terminal wrapper: the chamber reads omp's own session JSONL, project registry, config and subagent transcripts, folds them into one live view, and writes back through omp's RPC mode.
bun run src/server/index.ts # API + WebSocket + static client on :3000Full-quality recording (MP4, 27s): docs/assets/tour.mp4 · theme cycle in motion: docs/assets/themes.gif
45 palettes in one catalog (src/shared/lib/theme/): the chamber's own three (paper, contrast, one-dark-pro-soft) and 21 light/dark pairs — Catppuccin, Gruvbox, Tokyo Night, Nord, Dracula, Solarized, Kanagawa, Vesper and more. Switching repaints everything, syntax highlighting and Mermaid diagrams included, through one writer (applyDocumentTheme) that sets data-theme and announces it.
OMPChamber is published to npm and runs on Bun, not Node:
Bun only — the server imports bun:sqlite and Bun.YAML, neither of which Node can load. Bun 1.4 or newer is required.
omp required — every live capability (agent sessions, omp config, session state, updates) shells out to the omp binary, so serve refuses to start when it is not on PATH (or set via OMPCHAMBER_OMP_BIN). MOCK=true is the only mode that runs without a real omp install.
bun add -g ompchamber # puts the `ompchamber` command on your PATH
ompchamber serve # start the server on :3000The published tarball carries the source, the CLI and the prebuilt client bundle, so there is no build step after install. npm install -g ompchamber works too — the ompchamber bin is a Bun script, so Bun still has to be on PATH.
git clone https://github.com/rajebdev/ompchamber.git
cd ompchamber
bun install
bun run build # dist/client — the only build artifact
bun run start # NODE_ENV=production bun run src/server/index.ts
bun link # then: ompchamber statusWithout dist/client the server answers 503 with the exact command to run — never a bare 500.
ompchamber update --check # report only: current version, latest release
ompchamber update # install it, then restart a running instance
ompchamber update --force # reinstall even when already up to dateA bun global install is refreshed with bun add -g ompchamber@<version>; a git checkout is fast-forwarded to the release tag and rebuilt. Uncommitted work is never merged over (the update asks you to commit or stash first), and an install owned by another package manager is left alone and told which command to run.
A server OMPChamber did not start is never restarted: bun run dev, bun run start, a manual bun src/server/index.ts and instances owned by a supervisor (systemd, pm2, a container) all record themselves as direct, so the update leaves them running and says so. --no-restart turns the restart off entirely. The console's About → Updates runs the same install and restarts the instance serving that console.
ompchamber [COMMAND] [OPTIONS] — serve is the default command.
| Command | Purpose |
|---|---|
| serve | Start the web server (daemon by default) |
| update | Install the latest version from npm, then restart the instance it started |
| stop | Stop the instances the CLI started — --port/--all to stop any |
| restart | Stop, then start again — leaving servers started from source alone |
| status | Report whether an instance is running |
| logs | Print or follow the server log |
| Option | Purpose |
|---|---|
| -p, --port <port> | Web server port (default 3000); scopes status/stop/restart/logs |
| --host <address> (--hostname) | Bind address (default 127.0.0.1) |
| --lan | Bind to 0.0.0.0 for LAN access (warns when the traffic is unencrypted) |
| --tls | Serve HTTPS from a self-signed certificate, generated once into ~/.ompchamber/tls/ |
| --ui-password [value] | Require a password for the browser UI; generates one when the value is omitted |
| --no-ui-password | Ignore OMPCHAMBER_UI_PASSWORD for this start |
| --prod | Accepted for compatibility — production is the default |
| --dev | Run the dev server from source (HMR, unminified) instead |
| --foreground (--no-daemon) | Run in the foreground (no daemon) |
| --all | Apply the command to every running instance |
| -c, --check | Report whether a newer release exists without installing it |
| --force | Reinstall even when already up to date |
| --no-restart | Do not restart a running instance after updating |
| -f, --follow / -n, --lines <count> | Tail the log, optionally from a line count |
| --json / -q, --quiet | Machine-readable output / suppress non-essential output |
One port is served by exactly one process, and bun run dev, ompchamber serve and the production server all default to 3000. A starting instance never stops another one — if the port is taken by OMPChamber, the newcomer reports who holds it and exits non-zero so you can pick another port:
ompchamber serve --port 3001 # CLI flag
OMPCHAMBER_PORT=3001 ompchamber serve
PORT=3001 bun run dev # or: PORT=3001 bun run startThe server writes ~/.ompchamber/run/<port>.json (pid, host, mode, launchMode, startedAt) once it owns the port, which is how status/stop/logs also see servers started by bun run dev or --foreground. launchMode is derived from the process's argv, never from an environment variable — env is inherited, so a bun run dev started inside an OMPChamber shell would otherwise be replaced by an update. Records left by a killed server are pruned once their PID stops answering.
Environment variables, read from .env (see .env.example):
| Variable | Default | Purpose |
|---|---|---|
| PORT | 3000 | Server port |
| HOST | localhost | Server bind address |
| MOCK | false | true = demo datasets, false = real SQLite + workspace only |
| SYNC_WORKSPACE | true | Seed the workspace list from discovered omp projects — only while the list is still empty (one-time bootstrap; a curated list is never appended to) |
| OMPCHAMBER_DATA_DIR | ~/.ompchamber | CLI registry, logs, database and TLS certificate root |
| OMPCHAMBER_PORT / OMPCHAMBER_HOST | — | Defaults for the CLI when no flag is passed |
| OMPCHAMBER_UI_PASSWORD | — | Require a UI password (see Security); erased from the environment at boot |
| OMPCHAMBER_DB_PATH (DB_PATH) | ~/.ompchamber/db.sqlite | SQLite database path |
| OMPCHAMBER_DEV_SERVER | http://localhost:3100 | Rsbuild asset origin used in dev |
| OMPCHAMBER_BUN | — | Explicit Bun binary for the CLI to spawn |
| PI_CONFIG_DIR / PI_CODING_AGENT_DIR | ~/.omp | Oh-My-Pi config root overrides |
| OMPCHAMBER_OMP_BIN | — | Explicit omp binary path |
| SKILLS_API_URL | https://skills.sh | Skills catalog source |
| NPM_CONFIG_REGISTRY | https://registry.npmjs.org | Registry the update check reads |
Runtime state, sessions and settings live in SQLite (~/.ompchamber/db.sqlite), the single source of truth for persisted settings.
Off by default. A plain bun run dev requires no password, and no file on disk can change that: the password is supplied per run and hashed in memory. Only a session signing secret is persisted (~/.ompchamber/auth.json, mode 0600), so bun run --hot does not sign you out on every save while nothing durable can enable authentication on its own.
ompchamber serve --ui-password my-secret # or OMPCHAMBER_UI_PASSWORD
ompchamber serve --ui-password # generates one and prints it once
ompchamber serve --tls --ui-password … # HTTPS, cookie gains SecureBind to loopback (the default) and reach it over SSH port-forwarding, a VPN, or a tunnel. Exposing the port directly is the option with the least margin for error.
src/
├─ client/ Preact UI — zero React packages
│ ├─ components/ layout, workspace, settings, mobile, common
│ ├─ hooks/ chat, workspace, ui, browser, models, settings
│ ├─ data/ mock datasets, samples, themes, model + agent catalogs
│ └─ tailwind.css theme tokens (--theme-ink, --theme-paper, …)
├─ server/ Bun-only — Elysia routes, SQLite, omp RPC bridge, fs/git/terminal
│ ├─ routes/ one plugin per domain, mounted in routes/index.ts
│ ├─ lib/ omp session/subagent/config, updates, browser runtime, port lifecycle
│ └─ plugins/ SSR shell, static assets, compression, dev assets
├─ shared/ Imported by both — types, chat timeline folding, pure helpers
└─ cli/ ompchamber command (plain ESM, runs under Bun)
Non-obvious invariants worth reading before you edit:
AGENTS.md is the normative reference for all of the above — the invariants behind the panels, the BTW subsystem, the PTY terminal and the build/dev loop.
bun run dev # watched server; the client bundle is built on demand
bun run dev:lan # same, bound to the LANOne process. Bun serves the HTML shell and bundles its assets itself, so there is no separate client watcher to run and no build step before the first request: saving a server file restarts the server, saving a client file is pushed to the browser over HMR (import.meta.hot, wired by Bun).
bun run build produces the production bundle — scripts/build-client.ts writes dist/client, which ompchamber serve runs. The CLI builds it on demand the first time when it is missing, so a source checkout needs no manual build; --dev skips the bundle entirely.
Verification gates, all mandatory:
bun run lint # tsc --noEmit
bunx tsc --noEmit --noUnusedLocals --noUnusedParameters # no dead code
bun run build # production bundle
bun test # bun testThe screenshots, GIFs and the MP4 in docs/assets are captured from a scratch checkout running MOCK=true (PORT=3123) with Playwright, so they contain demo data only — never a real workspace. The three logos in the badge row at the top live in docs/assets/brand — Elysia and Shiki have no Simple Icons slug and shields rejects a remote logo= URL, so each mark is inlined in the badge as a base64 data URI. Their provenance, licences and recolouring are documented beside them, and docs/assets/brand/badges.test.ts fails if a mark and its embedded payload drift apart.
A push to main cuts the release — there is no manual version bump (.github/workflows/release.yml):
What a commit does to the version is one table, in release/release-rules.js, and release/bump.test.js asserts it:
| Commit | Version |
|---|---|
| feat | minor |
| fix, perf, revert | patch |
| feat! / fix! / perf! / refactor!, or a BREAKING CHANGE: footer | major |
| docs, refactor, chore, style, test, build, ci | no release |
Two of those rows exist because the toolchain's own defaults are wrong here: a ! on a type that cannot carry a breaking change (chore!, docs!, an unknown foo!) used to cut a major version through the analyzer's built-in { breaking: true } fallback, and the parser's note regex is case-insensitive, so any body line starting with breaking change — colon optional — counted as a breaking note. The second one is not hypothetical: a docs commit whose body wrapped onto breaking-change (!) footer cut v1.0.0 where the feats in the range asked for v0.9.0, and the changelog printed that prose as its breaking note. Both are fixed in release/release-rules.js, and both are locked by release/bump.test.js.
A BREAKING CHANGE: footer is therefore read only in uppercase, and only where the type allows it.
Two things to set up once and one to never do:
Issues and pull requests both get an automated first pass: a GitHub App runs the omp agent headlessly to triage a new issue and to review a pull request, and its verdict is published as a review:* label.
No license file is included. The source is public on GitHub and published to npm, but all rights are reserved by the author — no license is granted for redistribution or reuse.
See CHANGELOG.md for the release history.
| Back | FazBrowse Home | New Git URL |