feat(#85): add OMP (Oh My Pi) as a 4th delivery format - #86
Merged
Merged
Conversation
.omp-plugin/ mirrors the Codex reuse pattern rather than OpenCode's full TypeScript port: OMP's hooks are in-process pi.on() event handlers, so hooks/post/throughline.ts is a thin shim that translates OMP's own event shapes into the JSON the existing hooks/*.sh scripts already jq-parse, then shells out to them. No capture/redaction logic is duplicated. Skills are auto-discovered via .omp-plugin/skills, a symlink to the shared skills/ directory - zero extra step, same as .omp-plugin/hooks -> ../hooks. Verified against OMP's actual TypeScript source (installed locally via `npm install @oh-my-pi/pi-coding-agent`), not just its docs: the real pi.on() event names/payload shapes, the omp-plugins/claude-plugins discovery providers, and the omp plugin link mechanism for installing a monorepo subdirectory. A bun-based integration test suite (.omp-plugin/) fires synthetic OMP events at the real shim and asserts on the resulting hooks/*.sh output, rather than mocking child_process - the same principle tests/run.sh already applies to the Claude Code hooks, and the layer that would have caught the two silent bugs .opencode-plugin's full port shipped. Live verification against a real OMP session (tool_result field-shape confirmation for web_search/task, session_shutdown reliability on a clean exit, sendMessage reaching the model on turn 1) is still open - tracked in issue #85, not closed by this commit. Also updates CI (.github/workflows/ci.yml, .local-ci.json) with a 4th manifest in the version-agreement check and a new omp-plugin job, and documents OMP as a delivery format in README.md, docs/INSTALL.md, and docs/index.html. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Review of PR #86 (pr-review-toolkit:code-reviewer) found: - Critical: child.stdin had no 'error' listener. Every hooks/*.sh script guard-clause exits 0 before reading stdin when inactive/disabled/no-jq, and a payload large enough to exceed the pipe buffer then hit EPIPE on the write - an uncaught error event that killed the host OMP process. Reproduced live on Bun 1.3.8 with a 50KB prompt under THROUGHLINE_DISABLE=1. Fixed with a no-op error listener before the write; added a regression test with a 5MB prompt under the same condition. - Important: the task branch's `description ?? input.prompt` used `??`, which only falls through on null/undefined - an empty-string description suppressed the prompt fallback and silently dropped the delegated intent. session-capture.sh's own jq filter guards against exactly this (empty-aware `select`), so the shim needs the same `||` semantics. Fixed; added a regression test. - Also wrapped every registered handler in a swallow-and-continue wrapper (matching hooks/*.sh's own "always exit 0, never block" contract - an unexpected event shape from a future OMP version must not crash the session either), hardened the mcp__ prefix check against a missing/non-string toolName, and corrected a comment overclaiming that the `edit` tool's field names were confirmed against source (only bash/write/grep were). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7 tasks
Member
Author
|
Live-verified against a real OMP session (brew-installed `omp` 18.2.6, Jason's Dynamic LLM gateway model). All previously-open items from #85 now confirmed working except web_search/task field names (untested, low risk, degrades gracefully):
Details in #85. Ready to merge from my side. |
jsirish
added a commit
that referenced
this pull request
Sep 19, 2026
…egression Code review on this PR found that the existing CI/local-ci manifest checks only assert `.name and .version` on .omp-plugin/package.json - they stayed green through both #85 and #86 while the plugin silently had zero working hooks/skills for exactly the reason this PR fixes. Extend both checks to require `.omp` as well, so dropping that field again fails CI instead of shipping silently broken. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
jsirish
added a commit
that referenced
this pull request
Sep 19, 2026
A plain omp plugin link .omp-plugin followed by an ordinary omp session (no --plugin-dir override) never fired any throughline hook. Every "live verified" test in #85/#86 had gone through --plugin-dir, which bypasses OMP's enabled-plugins resolution entirely and was masking this. Root cause (extensibility/plugins/loader.ts::collectPluginsAtRoot in @oh-my-pi/pi-coding-agent): a linked/installed plugin is silently excluded from getEnabledPlugins() - and therefore from every hooks/skills discovery surface - unless its package.json has an omp or pi field. omp plugin doctor's "No omp/pi manifest (not an omp plugin)" warning is that exact functional gate, not cosmetic. Added a minimal omp: { name, description } field. Re-verified live: a plain omp --print session (no CLI override) against a real model now correctly captures a prompt and a bash tool call in the shared buffer. Also hardens the CI/local-ci manifest-validation checks to require the omp key (they previously only checked name/version and would have stayed green through this exact regression). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.omp-plugin/as a 4th throughline delivery format, targeting OMP (Oh My Pi) - a TypeScript coding-agent harness with its own plugin/hook/skill/MCP system.pi.on()event handlers, not subprocess hooks, sohooks/post/throughline.tsis a thin shim that translates OMP's own event shapes into the JSON the existinghooks/*.shscripts alreadyjq-parse, then shells out to them. No capture/redaction logic is duplicated in TypeScript..omp-plugin/skills, a symlink to the sharedskills/directory - same pattern as.omp-plugin/hooks -> ../hooks. Zero extra files, zero drift risk.git clone+omp plugin link .omp-plugin(a live checkout, not a package install -git pullto update).How this differs from the initial plan
The plan (session notes, not committed) assumed OMP's hook API surface based on docs alone. Installing the real package locally (
npm install @oh-my-pi/pi-coding-agent) and reading its actual TypeScript source corrected several assumptions:hooks/pre|post/are bound through OMP's Extensions runtime (ExtensionAPI), not the separate, unused-at-runtimeHookAPImodule the docs and initial research implied.pi.exec()has no stdin option, so the shim callsnode:child_processdirectly.omp plugin link <path>(notomp plugin install <git-url>) is the mechanism that installs a subdirectory of a monorepo - this is what makes.omp-plugin/viable at all without a standalone npm package.bash/write/grepusecommand/path/pattern, confirmed againstsrc/tools/*.ts) needed translating into Claude Code's tool-shape (Bash/Edit/Write/Grepwithtool_input.*) forsession-capture.shto parse correctly.What's verified vs. still open
Verified (against real OMP source + a bun-based integration test suite that fires synthetic events at the real shim and asserts on real
hooks/*.shoutput, not a mockedchild_process):session_startsends the onboarding markdown viapi.sendMessage.tool_resultcorrectly capturesbash/edit/write/grep/mcp__*, skipsread/glob(matching Claude Code's own exclusion), and drops unrecognized non-MCP tools rather than guessing a shape.session_before_compact/session_compactstamp the compaction boundary and re-inject the buffer tail (OMP splits Claude Code's single re-firedSessionStart(source=compact)into two events).session_shutdownstamps the buffer as ended.Still open, tracked in #85 (needs a real OMP session, not just static/simulated verification):
web_search/tasktool inputs (best-effort mapping in place; falls back to empty fields rather than crashing if wrong).session_shutdownreliability on a clean exit (/quit/EOF) vs. only SIGINT/SIGTERM.pi.sendMessage()atsession_startactually reaches the model on turn 1, not just the TUI.I don't have a configured OMP+model setup in this environment to complete that last-mile verification myself - #85 stays open for it.
Test plan
bun testin.omp-plugin/- 9/9 pass (integration tests against the real shim + real hook scripts)bun run typecheckin.omp-plugin/- cleansh tests/run.sh- 186/186 pass, no regressionlocal-ci.sh --strict- all checks PASS (shellcheck, manifest validation, plugin version agreement, hook tests, typography, opencode plugin, omp plugin)🤖 Generated with Claude Code