Run Pi packages in OMP without changing a single line of code.
Why · How it works · Installation · Usage
Pi and OMP are forks of the same codebase. Their extension APIs are structurally identical. The only thing stopping Pi packages from running in OMP is the npm scope: Pi imports from @mariozechner/*, OMP resolves from @oh-my-pi/*.
Manually porting extensions means rewriting imports and hoping nothing breaks. It usually does.
pi2omp fixes this. It installs Pi packages into a managed directory, generates thin re-export shims in OMP's auto-discovery paths, and uses npm package aliases to redirect @mariozechner/* imports to @oh-my-pi/* at runtime. Zero source changes. The Pi extension receives OMP's real ExtensionAPI object and just works.
Pi extensions receive ExtensionAPI as a function argument. import type statements are erased at runtime. So the only real problem is runtime imports from @mariozechner/* scoped packages.
pi2omp handles this with two mechanisms:
- Re-export shims -- one-line TypeScript files in OMP's
~/.omp/agent/extensions/(ortools/,skills/, etc.) that re-export the Pi package's entry point:
// ~/.omp/agent/extensions/pi--some-package/index.ts
// Auto-generated by pi2omp. Do not edit.
export { default } from "../../../piport/packages/node_modules/some-package/extensions/index.ts";- npm aliases in the managed
package.jsonthat redirect@mariozechner/*to@oh-my-pi/*:
{
"dependencies": {
"@mariozechner/pi-coding-agent": "npm:@oh-my-pi/pi-coding-agent@*",
"@mariozechner/pi-ai": "npm:@oh-my-pi/pi-ai@*",
"@mariozechner/pi-tui": "npm:@oh-my-pi/pi-tui@*",
"@mariozechner/pi-agent-core": "npm:@oh-my-pi/pi-agent-core@*"
}
}When Bun resolves import { StringEnum } from "@mariozechner/pi-ai", it hits the alias and loads @oh-my-pi/pi-ai instead. The Pi code never knows the difference.
| Resource | OMP discovery path | Method |
|---|---|---|
| Extensions | ~/.omp/agent/extensions/pi--<pkg>/index.ts |
Re-export |
| Tools | ~/.omp/agent/tools/pi--<pkg>--<name>.ts |
Re-export |
| Skills | ~/.omp/agent/skills/pi--<pkg>--<name>/ |
Symlink |
| Prompts | ~/.omp/agent/prompts/pi--<pkg>--<name>.md |
Symlink |
| Themes | ~/.omp/agent/themes/pi--<pkg>--<name>.json |
Symlink |
All shims use a pi-- prefix so they're trivially identifiable and never collide with native OMP resources.
Requires Bun.
git clone https://github.com/sasha-computer/pi2omp.git
cd pi2omp
bun linkNow pi2omp is available globally.
pi2omp install npm:pi-notify # from npm
pi2omp install npm:@foo/[email protected] # pinned version
pi2omp install git:github.com/user/repo # from git
pi2omp install ./my-local-extension # local directorypi2omp listPackage Version Ext Tools Skills Prompts Themes
---------------------------------------------------------------
pi-notify 1.3.0 1 0 0 0 0
pi2omp uninstall pi-notifyRemoves all shims and the package itself. Clean.
pi2omp update # update all non-pinned packages
pi2omp update pi-notify # update a specific packagepi2omp doctorVerifies all shims point to valid targets, aliases are in place, and no orphaned pi--* entries exist in OMP's directories.
✓ Alias @mariozechner/pi-coding-agent -> npm:@oh-my-pi/pi-coding-agent@*
✓ Alias @mariozechner/pi-ai -> npm:@oh-my-pi/pi-ai@*
✓ [pi-notify] Package root exists
✓ [pi-notify] extensions shim OK
✓ No orphaned shims found
done All 5 checks passed
~/.omp/piport/
packages/
package.json # managed deps + @mariozechner aliases
node_modules/ # installed Pi packages
piport.lock.json # tracks installs and shim locations
The lockfile records every shim placement, so uninstall always cleans up completely.
- Pi-specific internal APIs that OMP hasn't implemented will fail at runtime. The public
ExtensionAPIsurface is shared, but undocumented internals may diverge. - TUI extensions using
@mariozechner/pi-tuirendering primitives may break if OMP's TUI API has diverged. - Bundled Pi-to-Pi dependencies resolve
@mariozechner/*from their ownnode_modules/, not from the aliases. May need manual intervention.
Most extensions work out of the box. The common pattern (type-only imports + receiving ExtensionAPI as a parameter) is fully supported.
MIT