Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

159 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OMP Studio

Status: Active development — OMP Studio is early, pre-1.0 software under heavy iteration. Expect rapid changes, rough edges, and breaking churn: the UI, internal APIs, and on-disk/settings formats are not yet stable.

A sleek desktop cockpit for the Oh My Pi (omp) coding-agent harness — live agent chat, dashboards, and browsers for everything omp knows about, in one native window.

OMP Studio wraps the omp command-line harness in an Electron desktop app. It drives real agent turns over the omp --mode rpc protocol, reads your local ~/.omp/agent state, and surfaces your GitHub context through the gh CLI — so you can run, inspect, and manage agent work without living in a terminal.

Features

  • Dashboard — a single pane that aggregates recent sessions, model and provider counts, configured MCP servers, available skills, bundled agents, and the current GitHub repository.
  • Live agent chat — full agent turns over the omp RPC protocol, with streaming assistant text, thinking blocks, live tool-call rendering, steering, and follow-ups, each session backed by its own omp child process.
  • Workspaces — first-class project workspaces with a sidebar switcher, an add-workspace dialog, and pinning. Selecting a workspace points new chats at its directory; live sessions keep their own working directory.
  • Subagent drill-in — expand a session's subagent workflow tree and open any node in an inspector to follow its live progress, tool calls, and transcript.
  • Sessions browser — browse and replay past session transcripts read directly from the on-disk omp session log.
  • Skills & Commands — discover project, user, and bundled skills, browse the active session's available slash commands (pin favorites, drop them into a chat), and view a reference of TUI-only commands.
  • MCP servers — inspect the Model Context Protocol servers configured for your user and project.
  • Bundled agents — explore the task agents shipped with omp, including their models and spawn relationships.
  • Models / Providers — review the model catalog and which providers are authenticated.
  • GitHub — view the current repository, its issues and pull requests, and your owned repositories.
  • Linear — connect a Linear API key (stored in the OS keychain, never in settings) to browse your teams, projects, and issues; the key and all HTTP stay in the main process.
  • Terminal — an opt-in embedded terminal running a real shell in the active workspace via node-pty (off by default).
  • Browser — an opt-in embedded web browser rendered in a separate, sandboxed view isolated from the privileged app window (off by default).
  • Draggable layout — resizable sidebar and chat panels, with reorderable, collapsible, and hideable rail panels and nav items, persisted across launches.

Requirements

  • Node.js >= 20
  • omp installed and authenticated (the harness OMP Studio drives). Verify with omp --version.
  • gh (GitHub CLI) installed and authenticated for the GitHub features. Verify with gh auth status.
  • macOS, Linux, or Windows.

OMP Studio probes the common install locations for omp and gh (Homebrew, ~/.bun/bin, ~/.local/bin) so it works even when launched as a packaged app with a minimal PATH. Set the OMP_BINARY environment variable to override the omp binary location.

Quick start

npm install
npm run dev

npm run dev launches the app in development mode with hot-reloading renderer and main processes via electron-vite.

Build

# Type-check both the node and web TypeScript projects
npm run typecheck

# Bundle main, preload, and renderer into out/
npm run build

# Build distributable installers into release/ (dmg / AppImage / nsis)
npm run dist

npm run dist:mac targets macOS only. Distributable packaging uses electron-builder and downloads platform Electron binaries, so it runs locally or in the release workflow rather than in CI.

Releases

Releases are cut from main and published by CI. The flow is one command plus a tag push:

# 1. Bump the version + stamp the CHANGELOG's [Unreleased] section into a dated
#    release section, then commit and create the vX.Y.Z tag locally.
npm run release -- 0.1.0          # explicit version (use for the first release)
npm run release -- patch          # or bump patch/minor/major
npm run release -- patch --dry-run  # preview the version + release notes only

# 2. Push the branch and the tag. Pushing the tag triggers the Release workflow.
git push && git push origin v0.1.0

On a v* tag, .github/workflows/release.yml:

  1. verifies package.json's version matches the tag (fails otherwise),
  2. builds and boot-smoke-tests the app on macOS/Linux/Windows,
  3. packages installers (.dmg / .AppImage / .exe) with electron-builder, and
  4. cuts a single GitHub Release for the tag whose notes are the matching CHANGELOG.md section (npm run release:notes -- <version> prints them).

macOS code-signing / notarization is intentionally deferred (it needs Apple account credentials), so the macOS build is currently unsigned.

Testing

# RPC bridge integration test (handshake only; live model turn needs RPC_LIVE=1)
npm run test:rpc

# Electron end-to-end smoke against the built app (launch / render / navigation)
npm run build && npm run test:e2e

npm run test:e2e uses Playwright's _electron API to launch the bundled app from out/main/index.js, so the app must be built first. The smoke suite (e2e/smoke.spec.ts) is non-live and hermetic: it never starts a chat, and it launches the app with omp/gh pointed at a nonexistent binary and the agent-state dir at an empty temp dir, so the data services hit their graceful-degrade path and no omp/gh child is spawned. The result is identical whether or not omp/gh are installed. It asserts the window title, the sidebar navigation, the Dashboard, and that every browse view (Sessions, Skills, MCP, Agents, GitHub, Settings) navigates without a renderer crash.

Electron needs a display server even for a smoke launch, so on headless Linux CI wrap the command with xvfb:

xvfb-run -a npm run test:e2e

Live, paid end-to-end scenarios (a real chat turn, D1 approval approve/deny and input/select round-trips, D3 restart/resume, and D2 two-session concurrency) live in e2e/live.spec.ts and are gated behind STUDIO_E2E_LIVE=1 (mirroring RPC_LIVE=1). They are skipped by defaultnpm run test:e2e and CI never spawn a paid turn. Unlike the smoke, they launch against the installed omp (no hermetic OMP_BINARY/GH_BINARY overrides), isolate the studio's settings in a temp --user-data-dir, run each chat in a throwaway project dir, and keep prompts tiny. Run them locally with a configured omp:

npm run build && STUDIO_E2E_LIVE=1 npm run test:e2e

Architecture

OMP Studio follows the standard Electron three-process split. The renderer never touches Node or Electron directly; it calls a typed window.omp bridge that the preload script exposes, which forwards to ipcMain handlers in the main process. The main process owns the omp RPC child processes and all data services.

flowchart LR
  subgraph Renderer["Renderer (React)"]
    UI["Views and components"]
    API["window.omp (OmpApi)"]
  end
  subgraph Preload["Preload"]
    Bridge["contextBridge -> ipcRenderer"]
  end
  subgraph Main["Main process"]
    IPC["ipcMain handlers"]
    Data["Data services"]
    RPC["RPC session bridge"]
  end
  subgraph External["External"]
    OMP["omp --mode rpc"]
    State["~/.omp/agent state"]
    GH["gh CLI"]
  end

  UI --> API
  API --> Bridge
  Bridge -->|invoke / on| IPC
  IPC --> Data
  IPC --> RPC
  RPC <-->|JSONL stdio| OMP
  Data --> State
  Data --> GH
  RPC -->|evt:rpc / evt:lifecycle| Bridge
Loading

For the full process model, RPC protocol bridge, data sources, shared type contract, IPC channel map, and security notes, see docs/ARCHITECTURE.md.

Project layout

omp-studio/
├─ src/
│  ├─ main/                 Electron main process
│  │  ├─ index.ts           App bootstrap, window, IPC registration
│  │  ├─ paths.ts           Binary + omp state path resolution
│  │  ├─ omp/               RPC session bridge + registry
│  │  ├─ services/          Read-only data services (sessions, mcp, ...)
│  │  └─ ipc/               chat.ts + data.ts ipcMain handlers
│  ├─ preload/
│  │  └─ index.ts           Exposes the typed window.omp bridge
│  ├─ renderer/
│  │  ├─ index.html
│  │  └─ src/               React app (views, components, store, lib)
│  └─ shared/               Frozen cross-process contract
│     ├─ ipc.ts             Channel map (CH) + OmpApi surface
│     ├─ rpc.ts             omp RPC protocol + message types
│     └─ domain.ts          App-level domain types
├─ docs/ARCHITECTURE.md
├─ electron.vite.config.ts
└─ package.json

How chat works (RPC)

Each chat is backed by its own omp --mode rpc --cwd <dir> child process, spawned and tracked by the session registry in the main process. The bridge writes newline-delimited JSON commands (prompt, steer, follow_up, abort, get_state, ...) to the child's stdin and reads JSONL frames from its stdout. The first frame is {"type":"ready"}; subsequent frames are either command responses (echoing the command id) or unsolicited event frames (message_update, tool_execution_*, agent_end, and so on).

A prompt is acknowledged immediately; the turn completes later with an agent_end frame. The bridge forwards every frame to the renderer over the evt:rpc channel and reports session lifecycle changes over evt:lifecycle, so the chat view renders streaming output as it arrives. The bridge also auto-responds to extension_ui_request frames so omp never blocks waiting on UI that the desktop app does not present. When the renderer disposes a session, the bridge closes stdin and the omp process exits cleanly.

Contributing

Contributions are welcome. Before opening a pull request:

  1. Run npm run typecheck and ensure it passes.
  2. Run npm run build to confirm the app bundles.
  3. Run npm run test:rpc for the RPC bridge tests.
  4. Run npm run build && npm run test:e2e for the Electron smoke suite.

Keep changes focused, follow the existing TypeScript and component conventions, and update CHANGELOG.md under ## [Unreleased]. Issue and pull request templates are provided under .github/.

License

MIT © 2026 Dylan McCavitt.

About

Sleek desktop cockpit for the Oh My Pi (omp) coding-agent harness: live agent chat, dashboards, sessions, skills, MCP, agents, GitHub.

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages