diff --git a/README.md b/README.md index 39bfaed25..bf8a45675 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ - [Session Management](#session-management) - [Context Compaction](#context-compaction) - [Branching](#branching) - - [Autonomous Memory](#autonomous-memory) + - [Memory](#memory) - [Configuration](#configuration) - [Project Context Files](#project-context-files) - [Custom System Prompt](#custom-system-prompt) @@ -51,11 +51,13 @@ - [Skills](#skills) - [Hooks](#hooks) - [Custom Tools](#custom-tools) + - [Marketplace](#marketplace) - [CLI Reference](#cli-reference) - [Tools](#tools) - [Programmatic Usage](#programmatic-usage) - [SDK](#sdk) - [RPC Mode](#rpc-mode) + - [ACP Mode](#acp-mode) - [HTML Export](#html-export) - [Philosophy](#philosophy) - [Development](#development) @@ -78,23 +80,22 @@ AI-powered conventional commit generation with intelligent change analysis: - **Legacy mode**: `--legacy` flag for deterministic pipeline when preferred - Run via `omp commit` with options: `--push`, `--dry-run`, `--no-changelog`, `--context` -### + Python Tool (IPython Kernel) +### + Eval Tool (Multi-Language Code Execution)

- python + eval

-Execute Python code with a persistent IPython kernel and rich helper prelude: +Persistent multi-language REPL for the agent. One tool, two backends, a shared helper prelude — replaces the previous standalone Python tool: -- **Streaming output**: Real-time stdout/stderr with image and JSON rendering -- **Prelude helpers**: File I/O, search, find/replace, line operations, shell, and text utilities built into the kernel -- **Line operations**: `lines()`, `insert_at()`, `delete_lines()`, `delete_matching()` and related helpers for precise edits -- **Shared gateway**: Resource-efficient kernel reuse across sessions (`python.sharedGateway` setting) -- **Custom modules**: Load extensions from `.omp/modules/` and `~/.omp/agent/modules/` -- **Rich output**: Supports `display()` for HTML, Markdown, images, and interactive JSON trees -- **Markdown rendering**: Python cell output with Markdown content renders inline -- **Mermaid diagrams**: Renders mermaid code blocks as inline graphics in iTerm2/Kitty terminals -- Install dependencies via `omp setup python` +- **Cell header format**: One header per cell — `*** Cell :"" [t:<duration>] [rst]`. `lang` is `py` or `js`; `t:` sets a per-cell timeout, `rst` wipes the cell's own language kernel before running +- **Python backend**: Spawns one `python -u runner.py` subprocess per kernel speaking NDJSON over stdin/stdout. Cancellation sends `SIGINT` (real `KeyboardInterrupt`); the same subprocess is reused across cells in session mode. No Jupyter dependency +- **JavaScript backend**: Worker-pool runtime with `process`, Web APIs, `Buffer`, `fs/promises`, and `Bun` globals; top-level `await` works, static ESM imports are rewritten to resolve against the session cwd +- **Shared prelude**: `read`, `write`, `display`, `tree`, `diff`, `env`, `output`, plus `tool.<name>(args)` to invoke any session tool (read, write, edit, github, …) from inside a cell +- **Browser-tab JS shares the runtime**: `browser` tool `run` cells expose the same helper globals and ESM rewriting as `eval` JS cells +- **Magics without IPython**: `%pip`, `%cd`, `%env`, `%time`, `%timeit`, `%%bash`, `%%capture`, `%%writefile`, `!shell`, … work natively in the subprocess backend +- **Markdown / image rendering**: `display()` accepts text, JSON, dataframes, figures, images; `text/markdown` output renders inline; mermaid fences render as graphics in iTerm2 / Kitty +- Toggle backends via `eval.py` / `eval.js` settings; install Python with `omp setup python` ### + LSP Integration (Language Server Protocol) @@ -104,14 +105,28 @@ Execute Python code with a persistent IPython kernel and rich helper prelude: Full IDE-like code intelligence with automatic formatting and diagnostics: -- **11 LSP operations**: `diagnostics`, `definition`, `type_definition`, `implementation`, `references`, `hover`, `symbols`, `rename`, `code_actions`, `status`, `reload` +- **13 LSP operations**: `diagnostics`, `definition`, `type_definition`, `implementation`, `references`, `hover`, `symbols`, `rename`, `rename_file`, `code_actions`, `request`, `capabilities`, `status`, `reload` - **Format-on-write**: Auto-format code using the language server's formatter (rustfmt, gofmt, prettier, etc.) - **Diagnostics on write/edit**: Immediate feedback on syntax errors and type issues after every file change - **Workspace diagnostics**: Check entire project for errors with `lsp` action `diagnostics` (without a file) - **40+ language configs**: Out-of-the-box support for Rust, Go, Python, TypeScript, Java, Kotlin, Scala, Haskell, OCaml, Elixir, Ruby, PHP, C#, Lua, Nix, and many more +- **File renames**: `rename_file` routes through `workspace/willRenameFiles` / `didRenameFiles` so import updates land before the disk move; `apply: false` previews edits +- **Arbitrary requests**: `request` invokes any LSP method with auto-built `textDocument`/`position` params or raw JSON payload - **Local binary resolution**: Auto-discovers project-local LSP servers in `node_modules/.bin/`, `.venv/bin/`, etc. - **Symbol disambiguation**: `occurrence` parameter resolves repeated symbols on the same line +### + DAP Integration (Debug Adapter Protocol) + +Drive a real debugger from the agent — set breakpoints, step through code, inspect threads/stack/variables, and pause runaway processes — instead of bisecting with `printf`: + +- **27 debug operations**: `launch`, `attach`, `set_breakpoint` / `remove_breakpoint` (source or function, with optional `condition`), `set_instruction_breakpoint`, `data_breakpoint_info` / `set_data_breakpoint`, `continue`, `step_over` / `step_in` / `step_out`, `pause`, `evaluate` (`context: "repl"` for raw debugger commands), `stack_trace`, `threads`, `scopes`, `variables`, `disassemble`, `read_memory` / `write_memory`, `modules`, `loaded_sources`, `output` (captured stdout/stderr), `custom_request`, `terminate`, `sessions` +- **14 bundled adapters**: `gdb`, `lldb-dap`, `codelldb`, `debugpy`, `dlv`, `js-debug-adapter`, `netcoredbg`, `kotlin-debug-adapter`, `rdbg` (Ruby), `php-debug-adapter`, `bash-debug-adapter`, `dart-debug-adapter`, `flutter-debug-adapter`, `elixir-ls-debugger` +- **Auto-selection**: Adapter is inferred from program path / extension + workspace root markers (`Cargo.toml`, `go.mod`, `pyproject.toml`, …); override with `adapter: "lldb-dap"` when you want a specific debugger +- **Local + remote**: `pid` for local attach, `port` for remote attach where the adapter supports it +- **Pause runaway code**: `pause` interrupts a running program so the agent can inspect threads / stack / variables before deciding to `continue` or `terminate` +- **Single active session**: One debug session at a time per agent; `terminate` cleans up; `sessions` lists tracked sessions +- Gated by `debug.enabled` (default `true`); the adapter binary must be reachable on `PATH` (or the program's project dir) at launch time + ### + Time Traveling Streamed Rules (TTSR) <p align="center"> @@ -147,19 +162,109 @@ Structured code review with priority-based findings: <img src="https://github.com/can1357/oh-my-pi/blob/main/assets/task.webp?raw=true" alt="task"> </p> -Parallel execution framework with specialized agents and real-time streaming: +Parallel execution framework with specialized agents, live peer messaging, and real-time streaming: -- **6 bundled agents**: explore, plan, designer, reviewer, task, quick_task -- **Parallel exploration**: Reviewer agent can spawn explore agents for large codebase analysis +- **7 bundled agents**: `explore`, `plan`, `designer`, `reviewer`, `librarian`, `task`, `quick_task` +- **IRC peer messaging**: Subagents see live siblings + parent in their `# IRC Peers` block and can DM each other mid-flight via the `irc` tool, so a serial waterfall can become parallel with one round-trip clarification - **Real-time artifact streaming**: Task outputs stream as they're created, not just at completion -- **Full output access**: Read complete subagent output via `agent://<id>` resources when previews truncate -- **Isolation backends**: `isolated: true` runs tasks in git worktrees, Unix fuse-overlay filesystems, or Windows ProjFS (`fuse-projfs`), with patch or branch merge strategies -- **Async background jobs**: Background execution with configurable concurrency (up to 100 jobs) and `poll` tool for blocking on results +- **Full output access**: Read complete subagent output via `agent://<id>` resources (or extract a JSON field via `agent://<id>/path`) when previews truncate +- **Isolation backends**: `task.isolation.mode` selects from `auto`, `apfs`, `btrfs`, `zfs`, `reflink`, `overlayfs`, `projfs`, `block-clone`, `rcopy` (PAL-backed copy-on-write filesystems), with patch or branch merge strategies +- **Async background jobs**: Background execution with configurable concurrency (up to 100 jobs); the unified `job` tool handles `poll`, `cancel`, and `list` with per-agent ownership scoping - **Agent Control Center**: `/agents` dashboard for managing and creating custom agents - **AI-powered agent creation**: Generate custom agent definitions with the architect model - **Per-agent model overrides**: Assign specific models to individual agents via swarm extension - User-level (`~/.omp/agent/agents/`) and project-level (`.omp/agents/`) custom agents +### + IRC Peer Messaging + +Live agent-to-agent messaging across parent and subagent sessions — no file polling, no orchestrator round-trips: + +- **`irc` tool**: `op: "list"` enumerates visible peers (`0-Main`, task ids like `0-AuthLoader`); `op: "send"` delivers a DM or `to: "all"` broadcast +- **Synchronous side-channel**: The recipient generates a prose reply on an ephemeral turn even while its main loop is mid-tool-call; the exchange is injected into both transcripts on the next turn +- **Live in-chat rendering**: The main agent's UI relays every peer exchange so the human sees coordination happen +- **`AgentRegistry`**: Process-global registry pre-registers each subagent before its system prompt is built, so initial `# IRC Peers` blocks reflect siblings spawned in the same batch +- Gated by `irc.enabled` (default `true`) + +### + GitHub as Virtual Filesystem + +Issues, PRs, and diffs are addressable as virtual markdown files. The agent doesn't learn a new tool surface to browse GitHub — it just `read`s a URL, the same way it reads any other file. No copy-pasting issue bodies into prompts, no scraping PR pages, no separate "github" subcommand to remember: + +- **Read an issue**: `read issue://1234` — rendered as markdown with title, author, labels, body, and threaded comments +- **Read a PR**: `read pr://1234` (append `?comments=0` to skip the discussion). Each PR view points the agent at the matching diff URL +- **Read a diff**: `read pr://1234/diff` (changed-file listing), `read pr://1234/diff/3` (third file only), `read pr://1234/diff/all` (full unified diff). Hashline anchors work on diff slices, so the agent can quote a hunk by anchor without reproducing whitespace +- **Browse**: bare `read issue://` or `read pr://` lists recent items; filter with `?state=open|closed|merged|all`, `?author=`, `?label=`, `?limit=` +- **Cross-repo**: `read issue://owner/repo/N` works the same way for repositories outside the current checkout +- **Background refresh**: A soft TTL serves recent fetches instantly; a hard TTL serves stale-but-readable while a background fetch refreshes the cache, so the agent never blocks on a network round-trip to re-read the same issue mid-session + +The complementary `github` tool covers the operations a URL can't model: `pr_create`, `pr_checkout`, `pr_push`, `run_watch`, and the `search_*` family (issues, PRs, code, commits, repos) with relative-time filters like `since: "3d"` / `until: "1w"`. Search calls `gh api` directly so multi-qualifier queries (`is:merged is:pr`) reach GitHub verbatim instead of getting silently re-quoted by `gh search`. + +### + Hindsight Memory + +Opt-in long-term memory backend that records facts, retrieves them on relevant turns, and curates project-level mental models: + +- **Three tools**: `retain` (queue a memory write — non-blocking, batched up to 16 items / 5s), `recall` (search prior memories), `reflect` (post-session summarization) +- **Scoping modes**: `hindsight.scoping` is `global`, `per-project`, or `per-project-tagged` (default — global + project memories merge on recall via tags) +- **Mental models**: Bank-level curated summaries injected as `<mental_models>` developer instructions. Built-in seeds for user preferences, project conventions, and project decisions; manage via `/memory mm list|show|refresh|history|seed|reload|delete` +- **First-turn recall**: Auto-injects relevant memories as a `<memories>` block before the opening user message +- **Retention hygiene**: `<mental_models>` and recall blocks are stripped before storing transcripts so curated context never feeds back as new memory +- **Backend selector**: `memory.backend` is `off`, `local`, or `hindsight`; subagents persist into the parent's bank + +### + ACP Mode (Agent Client Protocol) + +Run omp as an ACP server over stdio so any compliant editor or harness can drive it: + +- **`omp acp` subcommand**: Launches with the same stdout-quiet semantics as `--mode rpc` so no banner leaks into the JSON-RPC channel +- **Client bridge**: When the client advertises capabilities, `bash` routes through `terminal/*`, `read`/`write` route through `fs/read_text_file` / `fs/write_text_file` (surfacing unsaved editor buffers), and `bash`/`edit`/`write`/`ast_edit` are gated by `session/request_permission` (with `allow_always` / `reject_always` decisions remembered for the session) +- **Slash-command parity**: ACP equivalents for `/jobs`, `/changelog`, `/dump`, `/copy`, `/hotkeys`, `/extensions`, `/agents`, `/model`, `/plan`, `/loop`, `/btw`, `/login`, `/logout`, `/resume`, `/tree`, `/branch`, `/new`, `/drop`, `/handoff`, `/fork`, `/export`, `/share`, `/todo`, `/memory`, `/move`, `/mcp`, `/ssh`, `/marketplace`, `/plugins`, plus `/skill:<name>` +- **Plan mode advertised as ACP mode**: `session/new`/`load`/`resume`/`fork` expose a `plan` mode alongside `default`; `session/set_mode` toggles plan-mode for the next turn +- **Rich tool reporting**: Edit results emit `diff` `ToolCallContent` (per-file `oldText` / `newText`); `tool_call_update` `locations` refresh from in-flight args; `StopReason` differentiates `end_turn`, `max_tokens`, `refusal`, `cancelled` +- **Custom extension methods** are prefixed `_omp/*` per the ACP `_`-prefix requirement for non-spec methods + +### + Loop Mode + +`/loop [count|duration]` re-issues the last user prompt automatically: + +- **Bounded by count or time**: `/loop 10` stops after 10 iterations; `/loop 10m` / `/loop 10min` stops after the duration; bare `/loop` toggles unbounded mode +- **Configurable per-iteration action**: Repeat the last prompt, run a stored prompt, or fire a custom action +- **Status line**: Enabled status surfaces the configured limit and remaining budget +- **Strict argument parsing**: Malformed counts or durations surface a usage error instead of silently enabling unbounded loop + +### + Conflict Resolution + +First-class git merge-conflict workflow inside `read` and `write`: + +- **`read` detection**: Each fully-formed column-0 marker block (`<<<<<<<` … `>>>>>>>`) is registered with a session-stable `#N` id and a warning badge (`⚠ N`) on the read tool UI. `read <path>:conflicts` returns a one-line-per-block index of every unresolved conflict +- **Inspect sides**: `read conflict://<N>` shows the recorded region; `read conflict://<N>/ours|theirs|base` shows one side with original-file line alignment +- **Resolve with content tokens**: `write({ path: "conflict://<N>", content })` splices the recorded marker region. `content` may be replacement text or any combination of shorthand tokens `@ours`, `@theirs`, `@base`, `@both` +- **Bulk resolve**: `write({ path: "conflict://*", content })` expands tokens per conflict across every registered block in one call +- **Safe splice**: Validates the live file still contains the recorded markers before splicing, and re-locates the block by exact marker content if line numbers have shifted out-of-band + +### + Internal URL Read Schemes + +`read` is the single entry point for everything the agent might need to inspect — files, URLs, and a family of internal schemes: + +- **`local://`** — session-shared artifacts (`local://PLAN.md`, briefs passed to subagents) +- **`agent://<id>` / `agent://<id>/<json.path>`** — full subagent output, with optional JSON field extraction +- **`artifact://<id>`** — spilled tool output truncated in the live transcript +- **`memory://root`** — project memory summary +- **`issue://<N>` / `pr://<N>`** — GitHub issues, PRs, and diffs as virtual markdown files (see GitHub as Virtual Filesystem) +- **`mcp://<uri>`** — MCP resource fetched via the active manager +- **`skill://<name>` / `skill://<name>/<path>`** — skill instructions and files +- **`rule://<name>`** — rule details +- **`conflict://<N>`** — merge-conflict regions captured by a prior read + +Resolution is process-global so parents and subagents see each other's outputs without explicit wiring. + +### + Recipe Tool (Project Task Runner) + +Run project tasks through one tool that auto-detects every common runner in the working directory: + +- **Auto-detection**: `package.json` scripts (including workspace packages), `Cargo.toml` bin/example/test targets, `Justfile`, `Makefile`, `Taskfile.yml` +- **Single `op` argument**: `op: "test"` or `op: "build --release"`; monorepo namespacing uses `/` (`pkg-a/test`, `crate/bin/server`) +- **Runner-qualified syntax**: `runnerId:task` disambiguates identical task names across multiple runners +- **Auto-availability**: Requesting `bash` automatically pulls in `recipe` when a supported manifest is detected; `bash` stays independently available +- **Unified output**: Same shape as `bash` — exit code, stdout/stderr merged, artifact spillover for long output + ### + Model Roles <p align="center"> @@ -171,6 +276,8 @@ Configure different models for different purposes with automatic discovery: - **Role-based routing**: `default`, `smol`, `slow`, `plan`, and `commit` roles - **Configurable discovery**: Role defaults are auto-resolved and can be overridden per role - **Role-based selection**: Task tool agents can use `model: pi/smol` for cost-effective exploration +- **Generic OpenAI-compat discovery**: Any provider exposing `/v1/models` (llama.cpp, Ollama, LM Studio, vLLM, OpenRouter forks) is auto-enumerated; keyless-by-design providers are treated as authenticated +- **Explicit prefixes are honored**: `<provider>/<id>` no longer silently falls back to a different provider when the exact pair isn't in the bundled catalog - CLI args (`--smol`, `--slow`, `--plan`) and env vars (`PI_SMOL_MODEL`, `PI_SLOW_MODEL`, `PI_PLAN_MODEL`) - Configure roles interactively via `/model` selector and persist assignments to settings @@ -178,13 +285,15 @@ Configure different models for different purposes with automatic discovery: Structured task management with phased progress tracking: -- **Phased task lists**: Organize work into named phases with ordered tasks -- **5 operations**: `replace` (setup), `add_phase`, `add_task`, `update` (status changes), `remove_task` +- **Phased task lists**: Organize work into named phases with ordered tasks; the renderer numbers phases visually (Ⅰ. Ⅱ. Ⅲ. …) +- **Content-addressed identity**: Tasks are identified by their `content` text and phases by their `name` — no synthetic IDs +- **5 operations**: `init` (setup), `add_phase`, `add_task`, `update` (status changes), `remove_task`, plus `note` for follow-up text - **4 task states**: `pending`, `in_progress`, `completed`, `abandoned` - **Auto-normalization**: Ensures exactly one task is `in_progress` at all times - **Persistent panel**: Todo list displays above the editor with real-time progress +- **`/todo` slash command**: `edit`, `copy`, `start`, `done`, `drop`, `rm`, `append`, `replace`, `export`, `import` operations with fuzzy phase/content matching +- **Markdown export/import**: `/todo export [path]` and `/todo import [path]` round-trip through `TODO.md` - **Completion reminders**: Agent warned when stopping with incomplete todos (`todo.reminders` setting) -- **Toggle visibility**: `Ctrl+T` expands/collapses the todo panel ### + Ask Tool (Interactive Questioning) @@ -197,6 +306,7 @@ Structured user interaction with typed options: - **Multiple choice questions**: Present options with descriptions for user selection - **Multi-select support**: Allow multiple answers when choices aren't mutually exclusive - **Multi-part questions**: Ask multiple related questions in sequence via `questions` array parameter +- **No default timeout**: `ask.timeout` defaults to `0` (wait indefinitely); set to a non-zero seconds value to auto-select the recommended option ### + Custom TypeScript Slash Commands @@ -239,6 +349,7 @@ Full Model Context Protocol support with external tool integration: - **OAuth support**: Explicit `clientId` and `callbackPort` in MCP server config, manual OAuth callbacks via slash commands - **Browser server filtering**: Automatically filters browser-type MCP servers to prevent conflicts with built-in browser tool - **Automatic Exa filtering**: Extracts Exa API keys and prefers the native Exa integration +- **Stable tool ordering**: Reconnects no longer reshuffle the tools array, preserving Anthropic prompt caching across MCP transport flaps - **Config schema + setup guide**: [`docs/mcp-config.md`](./docs/mcp-config.md) and [`packages/coding-agent/src/config/mcp-schema.json`](./packages/coding-agent/src/config/mcp-schema.json) - Plugin CLI (`omp plugin install/enable/configure/doctor`) - Hot-loadable plugins from `~/.omp/plugins/` with npm/bun integration @@ -264,23 +375,26 @@ Remote command execution with persistent connections: - **Project discovery**: Reads SSH hosts from `ssh.json` / `.ssh.json` in your project - **Host management**: Add, remove, and list hosts via `omp ssh` CLI or `/ssh` slash command -- **Persistent connections**: Reuses SSH connections across commands for faster execution +- **Persistent connections**: Reuses SSH connections across commands for faster execution; OpenSSH `%C` ControlMaster sockets so different user/port/jump-host combos don't share a master - **OS/shell detection**: Automatically detects remote OS and shell type - **SSHFS mounts**: Optional automatic mounting of remote directories -- **Compat mode**: Windows host support with automatic shell probing +- **Compat mode**: Windows host support with automatic shell probing; native Windows callers skip multiplexing (Win32-OpenSSH does not support it) ### + Browser Tool (Puppeteer with Stealth) Headless browser automation with 14 stealth scripts to evade bot detection: -- **Automation actions**: Navigate, click, type, fill, scroll, drag, screenshot, evaluate JS, and extract readable content -- **Accessibility snapshots**: Observe interactive elements via the accessibility tree with numeric IDs for reliable targeting -- **14 stealth plugins**: Custom scripts covering toString tampering, WebGL fingerprinting, audio context, screen dimensions, font enumeration, plugin/mime-type mocking, hardware concurrency, codec availability, iframe detection, locale spoofing, worker detection, and more -- **User agent spoofing**: Removes `HeadlessChrome` identifier, generates proper Client Hints brand lists, applies overrides via CDP Network and Emulation domains +- **`open` / `run` / `close` flow**: Named tabs survive across `run` calls and across subagents; `run` executes async JavaScript with `page`, `browser`, `tab`, `display`, `assert`, `wait` in scope +- **Shared runtime with `eval`**: Tab JS exposes the same helper globals (`read`, `write`, `display`, `tool.<name>`) and supports top-level `await` plus static ESM imports rewritten against the session cwd +- **Tab helpers**: `tab.observe()` accessibility snapshot with stable element ids, `tab.id(n)`, `tab.click`, `tab.fill`, `tab.type`, `tab.select`, `tab.uploadFile`, `tab.drag`, `tab.scrollIntoView`, `tab.waitForUrl`, `tab.waitForResponse`, `tab.evaluate`, `tab.screenshot`, `tab.extract` +- **Drive Electron desktop apps**: Same tool, same selectors — point it at any CDP-enabled Electron binary and the agent can click buttons, fill forms, run JS in the renderer, screenshot, and observe the accessibility tree. `app.path: "/Applications/Cursor.app/Contents/MacOS/Cursor"` spawns (or reuses) the app with `--remote-debugging-port`; `app.cdp_url: "http://127.0.0.1:9222"` attaches to an already-running instance; `app.target: "Settings"` substring-matches a `BrowserWindow` title/URL when the app exposes several. Used in practice to debug VS Code, Cursor, Slack, Discord, Spotify, and any Electron / NW.js / CEF wrapper that exposes CDP +- **14 stealth plugins**: toString tampering, WebGL fingerprinting, audio context, screen dimensions, font enumeration, plugin/mime-type mocking, hardware concurrency, codec availability, iframe detection, locale spoofing, worker detection, and more +- **User agent spoofing**: Removes `HeadlessChrome`, generates proper Client Hints brand lists, applies overrides via CDP Network and Emulation domains - **Selector flexibility**: CSS, `aria/`, `text/`, `xpath/`, `pierce/` query handlers for Shadow DOM piercing -- **Reader mode**: `extract_readable` action uses Mozilla Readability for clean article extraction +- **Reader mode**: `tab.extract()` uses Mozilla Readability for clean article extraction - **Headless/visible toggle**: Switch modes at runtime via `/browser` command or `browser.headless` setting -- **NixOS support**: Automatically detects NixOS (`/etc/NIXOS`) and resolves a system Chromium (`chromium` on PATH, `~/.nix-profile/bin/chromium`, or `/run/current-system/sw/bin/chromium`) since Puppeteer's bundled binary cannot run on a non-FHS system +- **One-command Chromium fetch**: `omp setup browser` downloads a known-good Chromium; prebuilt binaries embed the tab worker entry via `with { type: "file" }` so single-file binaries no longer fail with `Timed out initializing browser tab worker` +- **NixOS support**: Automatically detects NixOS (`/etc/NIXOS`) and resolves a system Chromium since Puppeteer's bundled binary cannot run on a non-FHS system ### + Cursor Provider @@ -299,6 +413,7 @@ Distribute load across multiple API keys: - **Usage-aware selection**: For OpenAI Codex, checks account limits before credential selection - **Automatic fallback**: Switches credentials mid-session when rate limits are hit - **Consistent hashing**: FNV-1a hashing ensures stable credential assignment per session +- **Disable events**: Extensions can subscribe to `credential_disabled` to react when an OAuth token is soft-disabled (e.g. `invalid_grant`) without regex-matching error messages ### + Image Generation @@ -318,18 +433,32 @@ Modern terminal interface with smart session management: - **Powerline footer**: Model, cwd, git branch/status, token usage, context % - **LSP status**: Shows which language servers are active and ready - **Hotkeys**: `?` displays shortcuts when editor empty -- **Persistent prompt history**: SQLite-backed with `Ctrl+R` search across sessions +- **Persistent prompt history**: SQLite-backed with `Ctrl+R` search across sessions; substring fallback for FTS5-missed infix queries - **Grouped tool display**: Consecutive Read calls shown in compact tree view - **Streaming text preview**: Real-time delta updates during agent output +- **`/context` panel**: Estimated context-usage breakdown for the active session - **Overlay UI**: Custom hooks can display components as bottom-centered overlays - **Configurable tab width**: `display.tabWidth` setting with `.editorconfig` integration +- **Ctrl+D draft persistence**: Pressing Ctrl+D with editor text saves it as a per-session draft; resuming the session restores it - **Scrollback preservation**: Uses home+erase-below instead of clear-screen - **Emergency terminal restore**: Crash handlers prevent terminal corruption +- **Power assertions**: macOS `power.preventIdleSleep` / `preventSystemSleep` / `declareUserActive` / `preventDisplaySleep` settings keep the machine awake only while a prompt is in flight -### + Hashline Edits +### + Hashline Edits (v3) Hashline gives every line a short content-hash anchor. The model references anchors instead of reproducing text — no whitespace reproduction, no "string not found", no ambiguous matches. If the file changed since the last read, hashes won't match and the edit is rejected before anything gets corrupted. +Hashline v3 adds: + +- **Atom mode**: Compact patch language with `+`/`-`/`=`/`<` ops, range-delete (`-LidA..LidB`), range-replace (`LidA..LidB=TEXT`), and continuation lines (`\TEXT` / `\`) for multi-line replacements +- **`splice_block`**: Bracketed `(anchor)`, `[anchor]`, `[anchor`, `anchor]` locators target whole nodes or block bodies with auto-inferred delimiters (`{` for C-family, `(` for Lisp-family) +- **Structural ordinals**: Anchor a single repeated symbol on a line via ordinal disambiguation +- **Multiline sed**: `sed` as an object (`{pat, rep, g?, i?}`) with sequential chaining when multiple `sed` ops target the same anchor; global by default +- **Stale-anchor recovery**: When anchors no longer match, edits replay against a session-scoped read/search snapshot and 3-way-merge onto the current file; success output flags when recovery was used +- **Brace-shape heuristics**: Auto-absorb of duplicated structural-closing lines (`}`, `);`, `]`) when keeping them would unbalance brackets; warnings when `@Lid` lands on an opener at sibling indent (likely off-by-one foot-gun) +- **Inline syntax**: `< ANCHOR>TEXT` and `+ ANCHOR>TEXT` (separator configurable via `PI_HL_SEP`, default `>`) for one-line prepends/appends without a payload block +- **`\*** Abort` recovery marker\*\*: Stream corruption mid-patch aborts safely instead of applying partial edits + Benchmarked across 16 models, 180 tasks, 3 runs each: - **Grok Code Fast 1**: 6.7% → 68.3% — a _tenfold_ improvement hidden behind mechanical patch failures @@ -340,43 +469,60 @@ Benchmarked across 16 models, 180 tasks, 3 runs each: ### + Native Engine (Rust N-API) -~7,500 lines of Rust compiled to a platform-tagged N-API addon, providing performance-critical operations without shelling out to external commands: +~27,000 lines of Rust across three crates (`pi-natives`, `pi-shell`, `pi-ast`) compiled to a platform-tagged N-API addon, providing performance-critical operations without shelling out to external commands: -| Module | Lines | What it does | Powered by | -| ------------- | -----: | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | -| **grep** | ~1,300 | Regex search over files and in-memory content, parallel/sequential modes, glob/type filtering, context lines, fuzzy find for autocomplete | `grep-regex`, `grep-searcher`, `grep-matcher` (ripgrep internals) | -| **shell** | ~1,025 | Embedded bash execution with persistent sessions, streaming output, timeout/abort, custom builtins | [brush-shell](https://github.com/reubeno/brush) (vendored) | -| **text** | ~1,280 | ANSI-aware visible width, truncation with ellipsis, column slicing, text wrapping that preserves SGR codes across line breaks — all UTF-16 optimized | `unicode-width`, `unicode-segmentation` | -| **keys** | ~1,300 | Kitty keyboard protocol parser with legacy xterm/VT100 fallback, modifier support, PHF perfect-hash lookup | `phf` | -| **highlight** | ~475 | Syntax highlighting with 11 semantic color categories, 30+ language aliases | `syntect` | -| **glob** | ~340 | Filesystem discovery with glob patterns, type filtering, mtime sorting, `.gitignore` respect | `ignore`, `globset` (ripgrep internals) | -| **task** | ~350 | Blocking work scheduler on libuv thread pool, cooperative/external cancellation, timeout, profiling hooks | `tokio`, `napi` | -| **ps** | ~290 | Cross-platform process tree kill and descendant listing — `/proc` on Linux, `libproc` on macOS, `CreateToolhelp32Snapshot` on Windows | `libc` | -| **prof** | ~250 | Always-on circular buffer profiler with folded-stack output and optional SVG flamegraph generation | `inferno` | -| **image** | ~150 | Decode/encode PNG/JPEG/WebP/GIF, resize with 5 sampling filters | `image` | -| **clipboard** | ~95 | Text copy and image read from system clipboard — no `xclip`/`pbcopy` needed | `arboard` | -| **html** | ~50 | HTML-to-Markdown conversion with optional content cleaning | `html-to-markdown-rs` | +| Module | Lines | What it does | Powered by | +| -------------- | -----: | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | +| **grep** | ~1,900 | Regex search over files and in-memory content, parallel/sequential modes, glob/type filtering, context lines, fuzzy find for autocomplete | `grep-regex`, `grep-searcher`, `grep-matcher` (ripgrep internals) | +| **shell** | ~3,700 | Embedded bash execution with persistent sessions, streaming output, timeout/abort, custom builtins, command minimizer (`pi-shell` crate) | [brush-shell](https://github.com/reubeno/brush) (vendored) | +| **text** | ~1,450 | ANSI-aware visible width, truncation with ellipsis, column slicing, text wrapping that preserves SGR codes across line breaks — all UTF-16 optimized | `unicode-width`, `unicode-segmentation` | +| **keys** | ~1,490 | Kitty keyboard protocol parser with legacy xterm/VT100 fallback, modifier support, PHF perfect-hash lookup | `phf` | +| **summarize** | ~1,040 | Tree-sitter structural source summaries with configurable body / comment elision; backs `read`'s default code summary output (`pi-ast` crate) | `tree-sitter`, `ast-grep-core` | +| **ast** | ~1,000 | ast-grep pattern matching and structural rewrites driving the `ast_edit` / `ast_grep` tools | `ast-grep-core` | +| **fs_cache** | ~840 | Mtime-keyed file cache shared by read/grep/lsp so repeated reads of the same file are zero-IO | — | +| **highlight** | ~470 | Syntax highlighting with 11 semantic color categories, 30+ language aliases | `syntect` | +| **pty** | ~455 | Native PTY allocation for `bash` `pty: true` (sudo, ssh interactive prompts) | `portable-pty` | +| **workspace** | ~385 | Workspace tree walker with gitignore + AGENTS.md discovery in one pass | `ignore`, `git2` | +| **glob** | ~410 | Filesystem discovery with glob patterns, type filtering, mtime sorting, `.gitignore` respect | `ignore`, `globset` (ripgrep internals) | +| **appearance** | ~270 | Mode 2031 detection + native macOS dark/light appearance via CoreFoundation FFI | `core-foundation` | +| **power** | ~270 | macOS power-assertion API for idle/system/display-sleep prevention during in-flight prompts | `IOKit` FFI | +| **task** | ~260 | Blocking work scheduler on libuv thread pool, cooperative/external cancellation, timeout, profiling hooks | `tokio`, `napi` | +| **iso** | ~245 | ISO 8601 / RFC 3339 datetime parsing and formatting | `time` | +| **prof** | ~240 | Always-on circular buffer profiler with folded-stack output and optional SVG flamegraph generation | `inferno` | +| **fd** | ~250 | Filesystem walker for `find`-tool replacement | `ignore` | +| **ps** | ~195 | Cross-platform process tree kill and descendant listing — `/proc` on Linux, `libproc` on macOS, `CreateToolhelp32Snapshot` on Windows | `libc` | +| **image** | ~190 | Decode/encode PNG/JPEG/WebP/GIF, resize with 5 sampling filters | `image` | +| **clipboard** | ~80 | Text copy and image read from system clipboard — no `xclip`/`pbcopy` needed | `arboard` | +| **tokens** | ~65 | O200k / Cl100k BPE token counting for context budgets; both tables embedded | `tiktoken-rs` | +| **html** | ~50 | HTML-to-Markdown conversion with optional content cleaning | `html-to-markdown-rs` | Supported platforms: `linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64`, `win32-x64`. ### ... and many more +- **`omp acp` subcommand**: Run as an Agent Client Protocol server over stdio - **`omp config` subcommand**: Manage settings from CLI (`list`, `get`, `set`, `reset`, `path`) -- **`omp setup` subcommand**: Install optional dependencies (e.g., `omp setup python` for Jupyter kernel) -- **`omp stats` subcommand**: Local observability dashboard for AI usage (requests, cost, cache rate, tokens/s) +- **`omp setup` subcommand**: Install optional dependencies (`omp setup python`, `omp setup browser`) +- **`omp stats` subcommand**: Local observability dashboard for AI usage (requests, cost, cache rate, tokens/s) with input/output token totals +- **`omp jupyter` was removed**: the Python `eval` backend now runs as a subprocess (no Jupyter dependency) - **`xhigh` thinking level**: Extended reasoning for Anthropic models with increased token budgets +- **Hide-thinking toggle**: `Ctrl+T` instructs the provider to omit reasoning summaries entirely, not just hide them client-side - **Background mode**: `/background` detaches UI and continues agent execution - **Completion notifications**: Configurable bell/OSC99/OSC9 when agent finishes - **65+ built-in themes**: Catppuccin, Dracula, Nord, Gruvbox, Tokyo Night, Poimandres, and material variants - **Automatic dark/light switching**: Mode 2031 terminal detection, native macOS appearance via CoreFoundation FFI, COLORFGBG fallback - **Auto environment detection**: OS, distro, kernel, CPU, GPU, shell, terminal, DE in system prompt - **Git context**: System prompt includes branch, status, recent commits +- **Workspace tree in system prompt**: Recency-sorted depth-≤3 tree of recent files / directories with truncation notices +- **AGENTS.md context discovery**: gitignore-aware walk that surfaces directory-scoped AGENTS.md and forwards results to subagents (no redundant rescans on spawn) - **Bun runtime**: Native TypeScript execution, faster startup, all packages migrated - **Centralized file logging**: Debug logs with daily rotation to `~/.omp/logs/` -- **Bash interceptor**: Optionally block shell commands that have dedicated tools -- **Per-command PTY control**: Bash tool supports `pty: true` for commands requiring a real terminal (sudo, ssh) +- **Bash interceptor**: Optionally block shell commands that have dedicated tools — checks the original command before `cd …&&` normalization +- **Per-command PTY control**: `bash` tool supports `pty: true` for commands requiring a real terminal (sudo, ssh) - **@file auto-read**: Type `@path/to/file` in prompts to inject file contents inline - **AST tools**: `ast_grep` and `ast_edit` for syntax-aware code search and codemods via ast-grep +- **Plan mode**: ExitPlanMode offers three approvals — execute (purge), keep full transcript, or compact context (re-anchors plan on a fresh cache breakpoint) +- **`/btw` ephemeral turns**: One-shot model query that doesn't pollute the session transcript - **Sampling controls**: `topP`, `topK`, `minP`, `presencePenalty`, `repetitionPenalty` settings for fine-grained model tuning --- @@ -422,7 +568,7 @@ Examples: curl -fsSL https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/install.sh | sh -s -- --source # Install release tag via binary -curl -fsSL https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/install.sh | sh -s -- --binary --ref v3.20.1 +curl -fsSL https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/install.sh | sh -s -- --binary --ref v15.0.0 # Install branch/commit via source curl -fsSL https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/install.sh | sh -s -- --source --ref main @@ -430,7 +576,7 @@ curl -fsSL https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/insta ```powershell # Install release tag via binary -& ([scriptblock]::Create((irm https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/install.ps1))) -Binary -Ref v3.20.1 +& ([scriptblock]::Create((irm https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/install.ps1))) -Binary -Ref v15.0.0 # Install branch/commit via source & ([scriptblock]::Create((irm https://raw.githubusercontent.com/can1357/oh-my-pi/main/scripts/install.ps1))) -Source -Ref main ``` @@ -485,12 +631,14 @@ return config | Mistral | `MISTRAL_API_KEY` | | Groq | `GROQ_API_KEY` | | Cerebras | `CEREBRAS_API_KEY` | +| Fireworks (`fireworks`) | `FIREWORKS_API_KEY` | | Hugging Face (`huggingface`) | `HUGGINGFACE_HUB_TOKEN` or `HF_TOKEN` | | Synthetic | `SYNTHETIC_API_KEY` | | NVIDIA (`nvidia`) | `NVIDIA_API_KEY` | | NanoGPT (`nanogpt`) | `NANO_GPT_API_KEY` | | Together (`together`) | `TOGETHER_API_KEY` | | Ollama (`ollama`) | `OLLAMA_API_KEY` _(optional)_ | +| Ollama Cloud (`ollama-cloud`) | `OLLAMA_CLOUD_API_KEY` | | LiteLLM (`litellm`) | `LITELLM_API_KEY` | | LM Studio (`lm-studio`) | `LM_STUDIO_API_KEY` _(optional)_ | | llama.cpp (`llama.cpp`) | `LLAMA_CPP_API_KEY` _(optional)_ | @@ -498,12 +646,23 @@ return config | Moonshot (`moonshot`) | `MOONSHOT_API_KEY` | | Venice (`venice`) | `VENICE_API_KEY` | | Kilo Gateway (`kilo`) | `KILO_API_KEY` | -| GitLab Duo (`gitlab-duo`) | _OAuth only_ | +| GitLab Duo (`gitlab-duo`) | `GITLAB_TOKEN` _(or OAuth)_ | +| Cursor (`cursor`) | _OAuth only_ | +| Antigravity (`google-antigravity`) | _OAuth only_ | | Jina (`jina`, web search) | `JINA_API_KEY` | +| Kagi (`kagi`, web search) | `KAGI_API_KEY` | +| Tavily (`tavily`, web search) | `TAVILY_API_KEY` | +| Parallel (`parallel`, web search) | `PARALLEL_API_KEY` | | Perplexity | `PERPLEXITY_API_KEY` or `PERPLEXITY_COOKIES` | | xAI | `XAI_API_KEY` | | OpenRouter | `OPENROUTER_API_KEY` | +| OpenCode Go (`opencode-go`) | `OPENCODE_API_KEY` | +| OpenCode Zen (`opencode-zen`) | `OPENCODE_API_KEY` | | Z.AI | `ZAI_API_KEY` | +| ZenMux (`zenmux`) | `ZENMUX_API_KEY` | +| MiniMax Coding Plan (`minimax-code`) | `MINIMAX_CODE_API_KEY` | +| MiniMax Coding Plan CN (`minimax-code-cn`) | `MINIMAX_CODE_CN_API_KEY` | +| Alibaba Coding Plan (`alibaba-coding-plan`) | `ALIBABA_CODING_PLAN_API_KEY` | | Qwen Portal (`qwen-portal`) | `QWEN_OAUTH_TOKEN` or `QWEN_PORTAL_API_KEY` | | vLLM (`vllm`) | `VLLM_API_KEY` | | Cloudflare AI Gateway (`cloudflare-ai-gateway`) | `CLOUDFLARE_AI_GATEWAY_API_KEY` | @@ -514,47 +673,57 @@ See [Environment Variables](docs/environment-variables.md) for the full list. **Option 2: `/login` (interactive auth / API key setup)** -Use `/login` with supported providers: +Use `/login` with supported providers (alphabetical): +- Alibaba Coding Plan (`alibaba-coding-plan`) - Anthropic (Claude Pro/Max) -- ChatGPT Plus/Pro (Codex) -- GitHub Copilot -- Google Cloud Code Assist (Gemini CLI) -- Antigravity (Gemini 3, Claude, GPT-OSS) -- Cursor -- Kimi Code -- Perplexity -- NVIDIA (`nvidia`) -- NanoGPT (`nanogpt`) -- Hugging Face Inference (`huggingface`) -- OpenCode Zen -- Kilo Gateway (`kilo`) +- Antigravity (`google-antigravity`, Gemini 3 / Claude / GPT-OSS) +- Cerebras (`cerebras`) +- ChatGPT Plus/Pro (Codex, `openai-codex`) +- Cloudflare AI Gateway (`cloudflare-ai-gateway`) +- Cursor (`cursor`) +- Fireworks (`fireworks`) +- GitHub Copilot (`github-copilot`) - GitLab Duo (`gitlab-duo`) -- Qianfan (`qianfan`) -- Ollama (local / self-hosted, `ollama`) +- Google Cloud Code Assist (Gemini CLI, `google-gemini-cli`) +- Hugging Face Inference (`huggingface`) +- Kagi (`kagi`) +- Kilo Gateway (`kilo`) +- Kimi Code (`kimi-code`) +- LiteLLM (`litellm`) - LM Studio (local / self-hosted, `lm-studio`) - llama.cpp (local / self-hosted, `llama.cpp`) -- vLLM (local OpenAI-compatible, `vllm`) -- Z.AI (GLM Coding Plan) -- Synthetic -- Together (`together`) -- LiteLLM (`litellm`) -- Xiaomi MiMo (`xiaomi`) +- MiniMax Coding Plan (International, `minimax-code`) +- MiniMax Coding Plan (China, `minimax-code-cn`) - Moonshot (Kimi API, `moonshot`) -- Venice (`venice`) -- MiniMax Coding Plan (International / China) +- NanoGPT (`nanogpt`) +- NVIDIA (`nvidia`) +- Ollama (local / self-hosted, `ollama`) +- Ollama Cloud (`ollama-cloud`) +- OpenCode Go (`opencode-go`) +- OpenCode Zen (`opencode-zen`) +- Parallel (`parallel`, web search) +- Perplexity +- Qianfan (`qianfan`) - Qwen Portal (`qwen-portal`) -- Cloudflare AI Gateway (`cloudflare-ai-gateway`) +- Synthetic +- Tavily (`tavily`, web search) +- Together (`together`) +- Venice (`venice`) - Vercel AI Gateway (`vercel-ai-gateway`) +- vLLM (local OpenAI-compatible, `vllm`) +- Xiaomi MiMo (`xiaomi`) +- Z.AI (GLM Coding Plan) +- ZenMux (`zenmux`) -For `ollama`, API key is optional. Leave it unset for local no-auth instances, or set `OLLAMA_API_KEY` for authenticated hosts. -For `llama.cpp`, API key is optional. Leave it unset for local no-auth instances, or set `LLAMA_CPP_API_KEY` for authenticated hosts. -For `lm-studio`, API key is optional. Leave it unset for local no-auth instances, or set `LM_STUDIO_API_KEY` for authenticated hosts. -For `vllm`, paste your key in `/login` (or use `VLLM_API_KEY`). For local no-auth servers, any placeholder value works (for example `vllm-local`). -For `nanogpt`, `/login nanogpt` opens `https://nano-gpt.com/api` and prompts for your `sk-...` key (or set `NANO_GPT_API_KEY`). Login validates the key via NanoGPT's models endpoint (not a fixed model entitlement). -For `cloudflare-ai-gateway`, set provider base URL to -`https://gateway.ai.cloudflare.com/v1/<account_id>/<gateway_id>/anthropic` -(for example in `~/.omp/agent/models.yml`). +**Provider-specific login notes:** + +- **`ollama`** — API key optional. Leave unset for local no-auth instances; set `OLLAMA_API_KEY` for authenticated hosts. +- **`llama.cpp`** — API key optional. Leave unset for local no-auth instances; set `LLAMA_CPP_API_KEY` for authenticated hosts. +- **`lm-studio`** — API key optional. Leave unset for local no-auth instances; set `LM_STUDIO_API_KEY` for authenticated hosts. +- **`vllm`** — paste your key in `/login` (or use `VLLM_API_KEY`). For local no-auth servers, any placeholder value works (for example `vllm-local`). +- **`nanogpt`** — `/login nanogpt` opens `https://nano-gpt.com/api` and prompts for your `sk-...` key (or set `NANO_GPT_API_KEY`). Validates the key via NanoGPT's models endpoint, not a fixed model entitlement. +- **`cloudflare-ai-gateway`** — set the provider base URL to `https://gateway.ai.cloudflare.com/v1/<account_id>/<gateway_id>/anthropic` (for example in `~/.omp/agent/models.yml`). ```bash omp @@ -610,6 +779,19 @@ Run `/extensions` and: - Inspect each item source (`via <provider>` + file path) - Disable full providers or specific items you don't want (`Space`) +#### 5) Manage subagents via `/agents` + +Open the Agent Control Center to inspect, configure, and toggle subagents (the `task` tool's dispatch targets). + +Run `/agents` and: + +- Browse discovered agents (built-in, project, user, and marketplace-installed) +- Inspect each agent's source file, model, tools, and system prompt +- Enable/disable agents per project, or scope-toggle to user/project +- Open the underlying agent definition for editing + +--- + --- ## Usage @@ -617,37 +799,54 @@ Run `/extensions` and: ### Slash Commands These are **in-chat slash commands** (not CLI subcommands). -| Command | Description | -| ------- | ----------- | -| `/settings` | Open settings menu | -| `/plan` | Toggle plan mode | -| `/model` (`/models`) | Open model selector | -| `/export [path]` | Export session to HTML | -| `/dump` | Copy session transcript to clipboard | -| `/share` | Upload session as a secret gist | -| `/session` | Show session info and usage | -| `/usage` | Show provider usage and limits | -| `/hotkeys` | Show keyboard shortcuts | -| `/extensions` (`/status`) | Open Extension Control Center | -| `/changelog` | Show changelog entries | -| `/tree` | Navigate session tree | -| `/branch` | Open branch selector (tree or message selector, based on settings) | -| `/fork` | Fork from a previous message | -| `/resume` | Open session picker | -| `/new` | Start a new session | -| `/compact [focus]` | Compact context manually | -| `/handoff [focus]` | Hand off context to a new session | -| `/browser [headless\|visible]` | Toggle browser mode | -| `/mcp ...` | Manage MCP servers | -| `/memory ...` | Inspect/clear/rebuild memory state | -| `/move <path>` | Move current session to a different cwd | -| `/background` (`/bg`) | Detach UI and continue in background | -| `/debug` | Open debug tools | -| `/copy` | Copy last agent message | -| `/login` / `/logout` | OAuth login/logout | -| `/exit` (`/quit`) | Exit interactive mode | -Bundled custom slash commands include `/review` (interactive code review launcher). +| Command | Description | +| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `/settings` | Open settings menu | +| `/plan [prompt]` | Toggle plan mode | +| `/model` (`/models`) | Open model selector | +| `/fast [on\|off\|status]` | Toggle OpenAI service-tier fast mode | +| `/loop [count\|duration]` | Toggle loop mode (re-submits next prompt after each yield) | +| `/export [path]` | Export session to HTML | +| `/dump` | Copy session transcript to clipboard | +| `/share` | Upload session as a secret GitHub gist | +| `/copy [last\|code\|all\|cmd]` | Copy last agent message / code block(s) / last bash or python command | +| `/todo <subcommand>` | View/edit todo list (`edit`, `copy`, `export`, `import`, `append`, `start`, `done`, `drop`, `rm`) | +| `/session [info\|delete]` | Show session info or delete the current session | +| `/usage` | Show provider usage and limits | +| `/jobs` | Show async background jobs status | +| `/changelog [full]` | Show changelog entries | +| `/hotkeys` | Show keyboard shortcuts | +| `/tools` | Show tools currently visible to the agent | +| `/context` | Show estimated context usage breakdown | +| `/extensions` (`/status`) | Open Extension Control Center dashboard | +| `/agents` | Open Agent Control Center dashboard | +| `/tree` | Navigate session tree (switch branches) | +| `/branch` | Branch from a previous message (tree or message selector) | +| `/fork` | Fork from a previous message into a new session | +| `/resume` | Open session picker | +| `/new` | Start a new session | +| `/drop` | Delete current session and start a new one | +| `/compact [focus]` | Manually compact session context | +| `/handoff [focus]` | Hand off context to a new session | +| `/btw <question>` | Ephemeral side question using the current context | +| `/retry` | Retry the last failed agent turn | +| `/rename <title>` | Rename the current session | +| `/move <path>` | Move session to a different working directory | +| `/background` (`/bg`) | Detach UI and continue running in background | +| `/browser [headless\|visible]` | Toggle browser headless/visible mode | +| `/mcp <subcommand>` | Manage MCP servers (`add`, `list`, `remove`, `test`, `reauth`, `unauth`, `enable`, `disable`, `smithery-search`, `smithery-login`, `smithery-logout`, `reconnect`, `reload`, `resources`, `prompts`, `notifications`) | +| `/ssh <subcommand>` | Manage SSH hosts (`add`, `list`, `remove`) | +| `/memory <subcommand>` | Inspect/clear/rebuild memory (`view`, `clear`/`reset`, `enqueue`/`rebuild`, `mm list\|show\|refresh\|history\|seed\|delete\|reload`) | +| `/marketplace <subcommand>` | Manage marketplace sources and plugins (`add`, `remove`, `update`, `list`, `discover`, `install`, `uninstall`, `installed`, `upgrade`) | +| `/plugins [list\|enable\|disable]` | View and manage installed plugins (npm + marketplace) | +| `/reload-plugins` | Reload skills, commands, hooks, tools, agents, and MCP | +| `/force <tool> [prompt]` | Force the next turn to use a specific tool | +| `/debug` | Open debug tools selector | +| `/login` / `/logout` | OAuth login/logout | +| `/exit` (`/quit`) | Exit interactive mode | + +Installed skills are dispatchable as `/skill:<name>`. Bundled custom commands include `/review` (interactive code review launcher). ### Editor Features @@ -657,6 +856,8 @@ Bundled custom slash commands include `/review` (interactive code review launche **Drag & drop:** Drag files from your file manager into the terminal. +**Paste images (Ctrl+V):** Paste images from the clipboard alongside drag-and-drop attachment. + **Multi-line paste:** Pasted content is collapsed in preview but sent in full. **Message queuing:** Submit messages while the agent is working; queue behavior is configurable in `/settings`. @@ -684,23 +885,23 @@ Bundled custom slash commands include `/review` (interactive code review launche **Other:** -| Key | Action | -| --------------------- | --------------------------------------------------------- | -| Tab | Path completion / accept autocomplete | -| Escape | Cancel autocomplete / abort streaming | -| Ctrl+C | Clear editor (first) / exit (second) | -| Ctrl+D | Exit (when editor is empty) | -| Ctrl+Z | Suspend to background (use `fg` in shell to resume) | -| Shift+Tab | Cycle thinking level | -| Ctrl+P / Shift+Ctrl+P | Cycle role models (slow/default/smol), temporary on shift | -| Alt+P | Select model temporarily | -| Ctrl+L | Open model selector | -| Alt+Shift+P | Toggle plan mode | -| Ctrl+R | Search prompt history | -| Ctrl+O | Toggle tool output expansion | -| Ctrl+T | Toggle todo list expansion | -| Ctrl+G | Edit message in external editor (`$VISUAL` or `$EDITOR`) | -| Alt+H | Toggle speech-to-text recording | +| Key | Action | +| --------------------- | ----------------------------------------------------------- | +| Tab | Path completion / accept autocomplete | +| Escape | Cancel autocomplete / abort streaming | +| Ctrl+C | Clear editor (first) / exit (second) | +| Ctrl+D | Exit (when editor is empty) | +| Ctrl+Z | Suspend to background (use `fg` in shell to resume) | +| Shift+Tab | Cycle thinking level | +| Ctrl+P / Shift+Ctrl+P | Cycle role models (slow/default/smol), temporary on shift | +| Alt+P | Select model temporarily | +| Ctrl+L | Open model selector | +| Alt+Shift+P | Toggle plan mode | +| Ctrl+R | Search prompt history | +| Ctrl+O | Toggle tool output expansion | +| Ctrl+T | Toggle thinking mode (hide reasoning summaries server-side) | +| Ctrl+G | Edit message in external editor (`$VISUAL` or `$EDITOR`) | +| Alt+H | Toggle speech-to-text recording | ### Bash Mode @@ -755,7 +956,7 @@ omp -r omp --resume <id-prefix> # Resume by session ID prefix omp --resume <path> # Resume by explicit .jsonl path omp --session <value> # Alias of --resume -omp --no-session # Ephemeral mode (don't save) +omp --no-session # Ephemeral mode (don't save) ``` Session IDs are Snowflake-style hex IDs (not UUIDs). @@ -771,6 +972,8 @@ Long sessions can exhaust context windows. Compaction summarizes older messages - **Overflow recovery**: model returns context overflow; compact and retry. - **Threshold maintenance**: context exceeds configured headroom after a successful turn. +**Plan mode:** when approving a plan, `Approve and compact context` distills the plan-mode discussion into a summary and starts execution in the same session — a middle ground between `Approve and execute` (fresh context) and `Approve and keep context` (full history preserved). + **Configuration** (`~/.omp/agent/config.yml`): ```yaml @@ -793,20 +996,33 @@ See [docs/compaction.md](docs/compaction.md) for internals and hook integration. **Create new session (`/branch` / `/fork`):** Branch to a new session file from a selected previous message. -### Autonomous Memory +### Memory -When enabled, the agent extracts durable knowledge from past sessions and injects it at startup. The pipeline runs in the background and never blocks the active session. +omp ships two memory backends, selected via `memory.backend` (`off | local | hindsight`). -Memory is isolated per project (working directory) and stored under `~/.omp/agent/memories/`. At session start, a compact summary is injected into the system prompt. The agent can read deeper context via `memory://root/MEMORY.md` and `memory://root/skills/<name>/SKILL.md`. +**Legacy local backend (`memory.backend: local`)** + +The agent extracts durable knowledge from past sessions and injects a compact summary at startup. The pipeline runs in the background and never blocks the active session. Memory is isolated per project (working directory) and stored under `~/.omp/agent/memories/`. The agent can pull deeper context via `memory://root/MEMORY.md` and `memory://root/skills/<name>/SKILL.md`. Manage via the `/memory` slash command: - `/memory view` — show current injection payload -- `/memory clear` — delete all memory data and artifacts -- `/memory enqueue` — force consolidation at next startup +- `/memory clear` (or `/memory reset`) — delete all memory data and artifacts +- `/memory enqueue` (or `/memory rebuild`) — force consolidation at next startup > See [Memory Documentation](docs/memory.md). +**Hindsight backend (`memory.backend: hindsight`)** + +Opt-in remote memory backed by [Hindsight](https://hindsight.vectorize.io) (Cloud or self-hosted). Instead of injecting a static summary, Hindsight surfaces three tools to the agent — `retain` (store durable facts), `recall` (search prior memories), and `reflect` (synthesise an answer across many memories) — and runs an auto-recall on the first turn so prior context lands before the model speaks. + +- **Per-session state**: each session aliases a bank; subagents reuse the parent's bank so retains/recalls persist to the same place. +- **Bank scoping**: `hindsight.scoping` selects `global` (one shared bank), `per-project` (isolated per cwd), or `per-project-tagged` (shared bank with `project:<cwd>` tags so global + project memories merge on recall). +- **Mental models**: long-running curated summaries (user preferences, project conventions) are seeded once per bank and refreshed automatically after consolidations; an `<mental_models>` block is spliced into the system prompt. +- **Maintenance**: `/memory mm list|show|refresh|history|seed|delete|reload` from the TUI; `/memory view|clear|enqueue` still apply. + +Configure via `hindsight.apiUrl`, `hindsight.apiToken`, `hindsight.bankId`, and `hindsight.scoping` in `config.yml`. + --- ## Configuration @@ -833,7 +1049,8 @@ Replace the default system prompt by creating `SYSTEM.md`: 1. **Project-local:** `.omp/SYSTEM.md` (takes precedence) 2. **Global:** `~/.omp/agent/SYSTEM.md` (fallback) - `--system-prompt` overrides both files. Use `--append-system-prompt` to append additional instructions. + +`--system-prompt` overrides both files. Use `--append-system-prompt` to append additional instructions. ### Custom Models and Providers @@ -881,6 +1098,8 @@ equivalence: Canonical ids are official upstream model ids such as `claude-sonnet-4-6` or `gpt-5.3-codex`. Use `equivalence.overrides` to map custom provider variants into those canonical groups while keeping explicit `provider/model` selection available. +**Path-scoped model config:** `modelRoles` and other model selectors can be overridden per working directory by nesting a `paths:` map under the setting — useful for pinning a heavier model on one repo without changing the global default. See [docs/models.md](docs/models.md). + ### Settings File Global settings are stored in: @@ -942,6 +1161,10 @@ compaction: enabled: true reserveTokens: 16384 keepRecentTokens: 20000 + autoContinue: true + +memory: + backend: local # off | local | hindsight skills: enabled: true @@ -949,12 +1172,34 @@ skills: terminal: showImages: true +display: + tabWidth: 4 # Tab rendering width (.editorconfig integration) + topP: -1 # Nucleus sampling (0-1, -1 = provider default) topK: -1 # Top-K tokens (-1 = provider default) minP: -1 # Minimum probability (0-1, -1 = provider default) -display: - tabWidth: 4 # Tab rendering width (.editorconfig integration) +tools: + discoveryMode: all # off | mcp-only | all + +eval: + py: true + js: true + +recipe: + enabled: true + +irc: + enabled: true + +github: + cache: + enabled: true + softTtlSec: 300 + hardTtlSec: 86400 + +plan: + enabled: true async: enabled: false @@ -963,8 +1208,12 @@ async: task: eager: false isolation: - mode: none # none | worktree | fuse-overlay | fuse-projfs + # auto lets the native PAL pick the best CoW backend; explicit values + # pin to one of: apfs | btrfs | zfs | reflink | overlayfs | projfs | + # block-clone | rcopy | none + mode: none merge: patch # patch | branch + commits: generic # generic | ai ``` `modelRoles` may use either canonical ids or explicit `provider/model` selectors. `modelProviderOrder` decides which provider backs a canonical model when multiple equivalent variants are available. @@ -974,6 +1223,10 @@ Legacy migration notes: - `settings.json` → `config.yml` - `queueMode` → `steeringMode` - flat `theme: "..."` → `theme.dark` / `theme.light` +- `memories.enabled: true|false` → `memory.backend: local|off` +- `task.isolation.enabled` + legacy modes (`worktree`, `fuse-overlay`, `fuse-projfs`) → `task.isolation.mode` enum (`auto`, `apfs`, `btrfs`, `zfs`, `reflink`, `overlayfs`, `projfs`, `block-clone`, `rcopy`, `none`) + +--- --- @@ -1003,6 +1256,7 @@ Define reusable prompt commands as Markdown files: - Global: `~/.omp/agent/commands/*.md` - Project: `.omp/commands/*.md` +- Also discovered: `~/.claude/commands/`, `.claude/commands/`, `~/.codex/commands/`, `.codex/commands/` ```markdown --- @@ -1023,7 +1277,7 @@ Argument placeholders: - `$1`, `$2`, ... positional arguments - `$@` and `$ARGUMENTS` for all arguments joined -TypeScript custom commands are also supported: +TypeScript custom commands are also supported — drop an `index.ts` into a per-command folder and default-export a factory: - `~/.omp/agent/commands/<name>/index.ts` - `.omp/commands/<name>/index.ts` @@ -1064,19 +1318,25 @@ Hook locations: - Global: `~/.omp/agent/hooks/pre/*.ts`, `~/.omp/agent/hooks/post/*.ts` - Project: `.omp/hooks/pre/*.ts`, `.omp/hooks/post/*.ts` -- CLI: `--hook <path>` +- CLI: `--hook <path>` (treated as an alias for `--extension`) ```typescript -import type { HookAPI } from "@oh-my-pi/pi-coding-agent/hooks"; +import type { HookAPI } from "@oh-my-pi/pi-coding-agent/extensibility/hooks"; export default function (omp: HookAPI) { - omp.on("tool_call", async (event, ctx) => { - if (event.toolName === "bash" && /sudo/.test(event.input.command as string)) { - const ok = await ctx.ui.confirm("Allow sudo?", event.input.command as string); - if (!ok) return { block: true, reason: "Blocked by user" }; - } - return undefined; - }); + omp.on("tool_call", async (event, ctx) => { + if ( + event.toolName === "bash" && + /sudo/.test(event.input.command as string) + ) { + const ok = await ctx.ui.confirm( + "Allow sudo?", + event.input.command as string, + ); + if (!ok) return { block: true, reason: "Blocked by user" }; + } + return undefined; + }); } ``` @@ -1086,7 +1346,7 @@ Inject messages from hooks with: omp.sendMessage(message, { triggerTurn: true }); ``` -> See [Hooks Documentation](docs/hooks.md) and [examples/hooks/](packages/coding-agent/examples/hooks/). +> See [Hooks Documentation](docs/hooks.md) and [examples/hooks/](packages/coding-agent/examples/hooks/). For richer integrations (tools + commands + events from one module) prefer `ExtensionAPI`. ### Custom Tools @@ -1101,22 +1361,41 @@ Auto-discovered locations: import { Type } from "@sinclair/typebox"; import type { CustomToolFactory } from "@oh-my-pi/pi-coding-agent"; const factory: CustomToolFactory = () => ({ - name: "greet", - label: "Greeting", - description: "Generate a greeting", - parameters: Type.Object({ - name: Type.String({ description: "Name to greet" }), - }), - async execute(_toolCallId, params) { - const { name } = params as { name: string }; - return { content: [{ type: "text", text: `Hello, ${name}!` }] }; - }, + name: "greet", + label: "Greeting", + description: "Generate a greeting", + parameters: Type.Object({ + name: Type.String({ description: "Name to greet" }), + }), + async execute(_toolCallId, params) { + const { name } = params as { name: string }; + return { content: [{ type: "text", text: `Hello, ${name}!` }] }; + }, }); export default factory; ``` > See [Custom Tools Documentation](docs/custom-tools.md) and [examples/custom-tools/](packages/coding-agent/examples/custom-tools/). +### Marketplace + +omp ships a Claude-compatible plugin marketplace: discover, install, and manage plugins (skills, commands, hooks, MCP/LSP servers) from Git-hosted catalogs or local directories. + +A **marketplace** is a Git repo (or directory) with a `.claude-plugin/marketplace.json` catalog. A **plugin** is identified as `name@marketplace` (e.g. `code-review@claude-plugins-official`) and can be installed at **user** scope (default, `~/.omp/plugins/`) or **project** scope (`.omp/plugins/`, shadows user installs). + +```text +/marketplace add anthropics/claude-plugins-official +/marketplace discover # browse catalogs +/marketplace install code-review@claude-plugins-official +/marketplace list | remove | update | uninstall | upgrade | installed +/plugins list # all installed plugins (npm + marketplace) +/plugins enable|disable <name@marketplace> +``` + +Or just type `/marketplace` with no arguments to open the interactive browser. The same operations are available via `omp plugin ...` from the CLI. + +> See [Marketplace Documentation](docs/marketplace.md). + --- ## CLI Reference @@ -1141,19 +1420,21 @@ omp <command> [args] [flags] | `--api-key <key>` | API key (overrides environment/provider lookup) | | `--system-prompt <text\|file>` | Replace system prompt | | `--append-system-prompt <text\|file>` | Append to system prompt | -| `--mode <mode>` | Output mode: `text`, `json`, `rpc` | +| `--mode <mode>` | Output mode: `text`, `json`, `rpc`, `acp`, `rpc-ui` | | `--print`, `-p` | Non-interactive: process prompt and exit | | `--continue`, `-c` | Continue most recent session | | `--resume`, `-r [id\|path]` | Resume by ID prefix/path (or open picker if omitted) | | `--session <value>` | Alias of `--resume` | | `--session-dir <dir>` | Directory for session storage and lookup | | `--no-session` | Don't save session | +| `--fork <id>` | Fork from a specific message ID | | `--tools <tools>` | Restrict to comma-separated built-in tool names | | `--no-tools` | Disable all built-in tools | | `--no-lsp` | Disable LSP integration | | `--no-pty` | Disable PTY-based interactive bash execution | | `--extension <path>`, `-e` | Load extension file (repeatable) | | `--hook <path>` | Load hook/extension file (repeatable) | +| `--plugin-dir <path>` | Load plugin from directory (repeatable) | | `--no-extensions` | Disable extension discovery (`-e` paths still load) | | `--no-skills` | Disable skills discovery and loading | | `--skills <patterns>` | Comma-separated glob patterns to filter skills | @@ -1168,17 +1449,22 @@ omp <command> [args] [flags] `omp` also ships dedicated subcommands: -- `commit` -- `config` -- `grep` -- `jupyter` -- `plugin` -- `search` (alias: `q`) -- `setup` -- `shell` -- `ssh` -- `stats` -- `update` +| Command | Description | +| -------------- | ---------------------------------------------------------------- | +| `acp` | Run as an Agent Client Protocol server (editor integration) | +| `agents` | Manage agent definitions (e.g. `omp agents unpack`) | +| `commit` | Generate and apply git commits with the agentic commit pipeline | +| `config` | Inspect or edit settings (`config.yml`) | +| `grep` | Standalone content search using the in-tree ripgrep wrapper | +| `grievances` | Review queued tool-issue / autoqa grievances | +| `plugin` | Manage npm-installed plugins | +| `read` | CLI inspector for files, archives, tool outputs, and `*://` URIs | +| `search` (`q`) | Run the multi-provider web-search tool from the shell | +| `setup` | First-run setup (Python kernel, OAuth, model defaults) | +| `shell` | Spawn an interactive shell session through omp's bash runtime | +| `ssh` | Manage SSH host definitions used by the `ssh` tool | +| `stats` | Inspect session/usage statistics | +| `update` | Update the installed omp binary | ### File Arguments @@ -1197,31 +1483,46 @@ Text files are wrapped in `<file ...>` blocks. Images are attached. ```bash # Interactive mode omp -# Non-interactive + +# Non-interactive prompt omp -p "List all .ts files in src/" + +# Continue / resume omp -c "What did we discuss?" -# Resume by ID prefix omp -r abc123 +# Restrict toolset for a read-only review +omp --tools read,search,find -p "Review the architecture" + +# Editor integration (ACP server, stdio transport) +omp acp + +# Agentic commit on staged changes +omp commit + +# Inspect a tool output by artifact URI +omp read 'artifact://abc123' + # Model cycling with patterns omp --models "sonnet:high,haiku:low" -# Restrict toolset for read-only review -omp --tools read,grep,find -p "Review the architecture" -# Export session +# Export a session to HTML omp --export session.jsonl output.html ``` ### Environment Variables -| Variable | Description | -| ------------------------------------------------- | ------------------------------------------------------- | -| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc. | Provider credentials | -| `PI_CODING_AGENT_DIR` | Override agent data directory (default: `~/.omp/agent`) | -| `PI_PACKAGE_DIR` | Override package directory resolution | -| `PI_SMOL_MODEL`, `PI_SLOW_MODEL`, `PI_PLAN_MODEL` | Role-model overrides | -| `PI_NO_PTY` | Disable PTY-based bash execution | -| `VISUAL`, `EDITOR` | External editor for Ctrl+G | +| Variable | Description | +| ------------------------------------------------- | -------------------------------------------------------- | +| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc. | Provider credentials | +| `PI_CODING_AGENT_DIR` | Override agent data directory (default: `~/.omp/agent`) | +| `PI_PACKAGE_DIR` | Override package directory resolution | +| `PI_SMOL_MODEL`, `PI_SLOW_MODEL`, `PI_PLAN_MODEL` | Role-model overrides | +| `PI_NO_PTY` | Disable PTY-based bash execution | +| `PI_PY`, `PI_JS` | Gate the python / JavaScript backends of the `eval` tool | +| `PI_HL_SEP` | Override the hashline payload separator (single char) | +| `OMP_GITHUB_CACHE_DB` | Override the GitHub view cache database path | +| `VISUAL`, `EDITOR` | External editor for Ctrl+G | See [Environment Variables](docs/environment-variables.md) for the complete reference. @@ -1233,39 +1534,65 @@ Use `--tools <list>` to restrict available built-in tools. ### Built-in Tool Names (`--tools`) -| Tool | Description | -| ---------------- | -------------------------------------------------------------- | -| `ask` | Ask the user structured follow-up questions (interactive mode) | -| `bash` | Execute shell commands | -| `python` | Execute Python code in IPython kernel | -| `calc` | Deterministic calculator/evaluator | -| `ssh` | Execute commands on configured SSH hosts | -| `edit` | In-place file editing with anchors | -| `find` | Find files by glob pattern | -| `grep` | Search file content | -| `ast_grep` | Structural code search using AST matching (ast-grep) | -| `ast_edit` | Structural AST-aware code rewrites (ast-grep) | -| `lsp` | Language server actions (11 operations) | -| `notebook` | Edit Jupyter notebooks | -| `read` | Read files/directories (default text cap: 3000 lines) | -| `browser` | Browser automation tool (model-facing name: `puppeteer`) | -| `task` | Launch subagents for parallel execution | -| `poll` | Block on async background jobs | -| `todo_write` | Phased task tracking with progress management | -| `fetch` | Fetch and extract URL content | -| `web_search` | Multi-provider web search | -| `write` | Create/overwrite files | -| `generate_image` | Generate or edit images using Gemini image models | +| Tool | Description | +| ------------------ | --------------------------------------------------------------------------------------- | +| `ask` | Ask the user structured follow-up questions (interactive mode) | +| `bash` | Execute shell commands | +| `eval` | Run code in a persistent kernel (Python and JavaScript backends) | +| `calc` | Deterministic calculator/evaluator | +| `ssh` | Execute commands on configured SSH hosts | +| `github` | Op-based wrapper around the GitHub CLI (`repo_view`, `pr_*`, `search_*`, `run_watch`) | +| `recipe` | Run a recipe / target from the project's task runner (bun, just, make, …) | +| `irc` | Send short messages between live agents (main ↔ subagents) | +| `edit` | In-place file editing with anchors | +| `write` | Create/overwrite files | +| `find` | Find files by glob pattern | +| `search` | Search file contents (regex) | +| `ast_grep` | Structural code search using AST matching (ast-grep) | +| `ast_edit` | Structural AST-aware code rewrites (ast-grep) | +| `lsp` | Language server actions (multi-operation) | +| `debug` | Debugger access via DAP (launch/attach, breakpoints, stepping, threads/stack/variables) | +| `read` | Read files, directories, archives, SQLite, PDFs, notebooks, URLs | +| `inspect_image` | Extract image content with a vision model | +| `render_mermaid` | Render Mermaid diagrams to ASCII or PNG | +| `browser` | Browser automation tool (model-facing name: `puppeteer`) | +| `task` | Launch subagents for parallel execution | +| `job` | Manage async background jobs (poll, cancel, list) | +| `todo_write` | Phased task tracking with progress management | +| `web_search` | Multi-provider web search | +| `search_tool_bm25` | Tool-discovery search over hidden built-in / MCP / extension tools | +| `generate_image` | Generate or edit images using Gemini image models | +| `checkpoint` | Save a workspace checkpoint | +| `rewind` | Rewind the workspace to a previous checkpoint | +| `retain` | Persist a memory note (hindsight backend) | +| `recall` | Recall memory notes (hindsight backend) | +| `reflect` | Trigger memory consolidation (hindsight backend) | Notes: -- Some tools are setting-gated (`calc`, `browser`, etc.) -- `ask` requires interactive UI -- `ssh` requires configured SSH hosts +- `ask` requires interactive UI. +- `ssh` requires configured SSH hosts. +- Some tools are setting-gated and are excluded from the active toolset unless enabled: + - `calc` ← `calc.enabled` + - `browser` ← `browser.enabled` + - `github` ← `github.enabled` + - `recipe` ← `recipe.enabled` + - `irc` ← `irc.enabled` (and only attached to the main agent when `async.enabled` is true) + - `inspect_image` ← `inspect_image.enabled` + - `render_mermaid` ← `renderMermaid.enabled` + - `web_search` ← `web_search.enabled` + - `find` / `search` ← `find.enabled` / `search.enabled` + - `ast_grep` / `ast_edit` ← `astGrep.enabled` / `astEdit.enabled` + - `lsp` ← `lsp.enabled` (and `--no-lsp` is not set) + - `checkpoint` / `rewind` ← `checkpoint.enabled` + - `debug` ← `debug.enabled` + - `search_tool_bm25` ← `tools.discoveryMode !== "off"` (or legacy `mcp.discoveryMode`) + - `retain` / `recall` / `reflect` ← `memory.backend === "hindsight"` + - `eval` python/JS backends individually gated by `eval.py` / `eval.js` (or the `PI_PY` / `PI_JS` env vars) Example: -`omp --tools read,grep,find -p "Review this codebase"` +`omp --tools read,search,find -p "Review this codebase"` For adding new tools, see [Custom Tools](#custom-tools). @@ -1278,19 +1605,27 @@ For adding new tools, see [Custom Tools](#custom-tools). For embedding omp in Node.js/TypeScript applications, use the SDK: ```typescript -import { ModelRegistry, SessionManager, createAgentSession, discoverAuthStorage } from "@oh-my-pi/pi-coding-agent"; +import { + ModelRegistry, + SessionManager, + createAgentSession, + discoverAuthStorage, +} from "@oh-my-pi/pi-coding-agent"; const authStorage = await discoverAuthStorage(); const modelRegistry = new ModelRegistry(authStorage); await modelRegistry.refresh(); const { session } = await createAgentSession({ - sessionManager: SessionManager.inMemory(), - authStorage, - modelRegistry, + sessionManager: SessionManager.inMemory(), + authStorage, + modelRegistry, }); session.subscribe((event) => { - if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { - process.stdout.write(event.assistantMessageEvent.delta); - } + if ( + event.type === "message_update" && + event.assistantMessageEvent.type === "text_delta" + ) { + process.stdout.write(event.assistantMessageEvent.delta); + } }); await session.prompt("What files are in the current directory?"); ``` @@ -1313,6 +1648,8 @@ For embedding from other languages or process isolation: ```bash omp --mode rpc --no-session +# or, for embedders that want to drive the TUI (tool cards, dialogs, selectors) over the protocol: +omp --mode rpc-ui --no-session ``` Send JSON commands on stdin: @@ -1320,12 +1657,49 @@ Send JSON commands on stdin: ```json {"id":"req-1","type":"prompt","message":"List all .ts files"} {"id":"req-2","type":"abort"} +{"id":"req-3","type":"get_login_providers"} +{"id":"req-4","type":"login","providerId":"anthropic"} +{"id":"req-5","type":"handoff"} ``` -Responses are emitted as `type: "response"`; session events stream on stdout as they occur. +Responses are emitted as `type: "response"`; session events and extension UI requests stream on stdout as they occur. + +Available command families (non-exhaustive): `prompt` / `steer` / `follow_up` / `abort` / `abort_and_prompt`, `new_session` / `switch_session` / `branch` / `handoff`, `get_state` / `get_messages` / `get_session_stats`, `set_model` / `cycle_model` / `get_available_models`, `set_thinking_level`, `compact` / `set_auto_compaction`, `bash` / `abort_bash`, `set_host_tools` (register host-side tools the agent can call back into), `get_login_providers` / `login`, `export_html`. + +`--mode rpc-ui` adds full UI plumbing on top of the same protocol: tool execution cards, selectors, dialogs, and other interactive surfaces are streamed as `extension_ui_request` frames that the embedder must answer with `extension_ui_response`. `--mode rpc` keeps it headless (no UI requests). > See [RPC Documentation](docs/rpc.md) for the full protocol. +### ACP Mode + +For embedding in editors that speak the [Agent Client Protocol](https://github.com/zed-industries/agent-client-protocol) (e.g. Zed): + +```bash +omp acp +# equivalent to: omp --mode acp +``` + +ACP mode starts a JSON-RPC server over stdio. It does **not** require a configured model at startup — the client can drive `initialize` and `authenticate` (including `/login`) before any model is selected. A `terminal` auth method is advertised when the client opts in via `clientCapabilities.auth.terminal` and falls back to an embedded interactive login flow. + +When the client advertises capabilities at `initialize`, the agent routes tool I/O through them via the `ClientBridge` abstraction (`packages/coding-agent/src/session/client-bridge.ts`): + +- `bash` → `terminal/create` + `terminal/output` (per-call client-side terminals) +- `read` → `fs/read_text_file` (so unsaved editor buffers and in-memory edits are visible) +- `write` → `fs/write_text_file` (writes go through the editor and let it track agent changes) +- `bash`, `edit`, `write`, and `ast_edit` are gated behind `session/request_permission` when the client supports it; `allow_always` / `reject_always` decisions are remembered per tool for the session lifetime + +Slash commands available to ACP clients reach feature parity with the TUI for non-interactive flows, including `/model`, `/plan`, `/loop`, `/login`, `/logout`, `/agents`, `/extensions`, `/plugins`, `/marketplace`, `/mcp`, `/ssh`, `/session`, `/branch`, `/fork`, `/new`, `/resume`, `/drop`, `/handoff`, `/move`, `/memory`, `/todo`, `/jobs`, `/changelog`, `/dump`, `/copy`, `/hotkeys`, `/btw`, `/tree`, `/export`, `/share`, plus all `/skill:<name>` commands. The full set is registered in `packages/coding-agent/src/slash-commands/acp-builtins.ts`. + +Beyond stock ACP methods, the agent exposes a small set of `_omp/*` extension methods for omp-aware clients (renamed from `omp/*` in 15.0.0 to match the ACP spec's `_`-prefix requirement for non-spec methods): + +- `_omp/sessions/listAll` — paginated cross-cwd session index +- `_omp/projects/list` — discovered project cwds with session counts +- `_omp/chats/byCwd` — sessions filtered by working directory +- `_omp/usage` — token/cost rollup for active sessions +- `_omp/extensions` / `_omp/extensions/toggle` — list and toggle discovered extensions + +Mode-aware notifications are also wired up: `session/set_mode` and `session/set_session_config_option("mode", …)` both emit `current_mode_update`; `/model` emits `config_option_update` after a model switch so client config selectors stay in sync; `tool_call_update.locations` is kept fresh from in-flight tool args so editors can "follow along" multi-file edits. + ### HTML Export ```bash @@ -1374,11 +1748,14 @@ For architecture and contribution guidelines, see [packages/coding-agent/DEVELOP ### Rust Crates -| Crate | Description | -| ------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -| **[pi-natives](crates/pi-natives)** | Core Rust native addon used by `@oh-my-pi/pi-natives` | -| **[brush-core-vendored](crates/brush-core-vendored)** | Vendored fork of [brush-shell](https://github.com/reubeno/brush) for embedded bash execution | -| **[brush-builtins-vendored](crates/brush-builtins-vendored)** | Vendored bash builtins (cd, echo, test, printf, read, export, etc.) | +| Crate | Description | +| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| **[pi-natives](crates/pi-natives)** | Core Rust native addon (N-API `cdylib`) used by `@oh-my-pi/pi-natives`; aggregates the crates below | +| **[pi-shell](crates/pi-shell)** | Embedded shell / PTY / process management split out of `pi-natives` (wraps `brush-*`) | +| **[pi-ast](crates/pi-ast)** | tree-sitter-based code summarizer and AST utilities (50+ language grammars) | +| **[pi-iso](crates/pi-iso)** | Task isolation backend resolver: APFS clones, btrfs/zfs reflinks, overlayfs, projfs, rcopy | +| **[brush-core-vendored](crates/brush-core-vendored)** | Vendored fork of [brush-shell](https://github.com/reubeno/brush) for embedded bash execution | +| **[brush-builtins-vendored](crates/brush-builtins-vendored)** | Vendored bash builtins (cd, echo, test, printf, read, export, etc.) | ---