om-pi-subagents
Opinionated Modular Pi Subagents (OMPS): YAML-mapped personas run as native Pi child processes.
Package details
Install om-pi-subagents from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:om-pi-subagents- Package
om-pi-subagents- Version
0.8.0- Published
- Oct 8, 2026
- Downloads
- 733/mo · 733/wk
- Author
- cmdaltctr
- License
- MIT
- Types
- extension, skill
- Size
- 481.8 KB
- Dependencies
- 1 dependency · 3 peers
Pi manifest JSON
{
"skills": [
"./skills"
],
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
OMPS: Opinionated Modular Pi Subagents
OMPS runs a subagent as a normal Pi child process. You decide the agent names, the persona text, and the tools each agent may use. All of it lives in one YAML file and plain Markdown files. OMPS ships no agents of its own.
- The parent gets the
ompstool,/ompscommands and an operator-only/omps-settingsmenu. - Each run is one child Pi process in the background.
- YAML limits set each parent's direct-child capacity and maximum nesting depth. Both default to one.
- YAML
uisettings set visible rows (default 5), the fleet view (defaultexpanded), list visibility and navigation keys. - The result arrives as a follow-up message when the child finishes. Long results fold in interactive Pi.
The ● Agents tree and the navigation list are adapted from
tintinweb/pi-subagents under its MIT licence.
OMPS does not import or need that package. Its own runtime, settings and inspection stay separate.
Features

The screenshot is a real Pi 1.0.4 session with four real child Pi processes. A local fake model drives
the agents, so the task names and answers are synthetic. scripts/readme-demo.tape records it with
vhs.
- Agent tree. The
● Agentstree above the editor shows each running agent with a spinner, its task, its tool-use count, the elapsed time and what it does now. Finished agents show✓,✗or■for a short time. The tree is adapted from tintinweb/pi-subagents under its MIT licence. - Management list. From an empty focused prompt, press Down to select an agent below the editor. Its navigation keys can be remapped or disabled. Hide the list while keeping the expanded tree.
- Inspector.
/omps inspectopens an agent picker, including nested agents. Enter opens single-column details with themed answers, current activity and saved output. - Isolated children. Each agent runs as its own Pi process. Before the task is sent, OMPS checks that the child loaded its tool guard, its tools, its model and its working directory. The guard refuses any tool the mapping does not approve.
- Limits. YAML limits set how many direct children each parent may run at once and how deep agents may nest.
- Saved runs. Each run keeps its task, events, output and status in a private run folder.
- Folded results. Long result messages show eight answer lines, keeping errors and partial-output warnings visible. Ctrl+Shift+E toggles all OMPS results. Pi's host expansion action also works, with Ctrl+O as its default.
- Settings.
/omps-settingsedits the limits, the fleet view, the shortcuts and the optional capabilities of each agent. - Short agent list.
/omps listshows one line per agent, such asreader: 4 tools (read-only). The model still receives every tool name. - At-mention launch. In Pi's interactive terminal interface, type
@at the start of the first editor line. Completion labels show mapped agent names without descriptions, above Pi's file items. Submit@reader Summarise the READMEto use the/omps runlaunch path without a parent model request for routing. Child model calls and later result delivery stay unchanged. See at-mention launch.


Works with om-pi-todo and OMMS
Both om-pi-todo and OMMS (om-memory-system) are optional.
They are off for every new agent. To turn one on for an agent:
- Run
/omps-settings. - Choose Agent capabilities, then the agent, then Todo or Memory.
- Select Enable.
- Choose an installation if OMPS finds several valid packages.
- Enter an installed path if OMPS offers the fallback prompt.
- Confirm the exact resources and YAML destination.
OMPS checks Pi's personal package list first. One valid installation skips the path prompt. With no usable match, it shows installation guidance and asks for a package folder or published extension entry. Cancelling leaves YAML unchanged. Detection reads metadata without loading the sibling extension. The change applies to the next launch. OMPS installs no package.
Todo. Each child starts with its own empty task list in normal mode. It never sees or changes the parent's tasks, and it never ticks the parent's OpenSpec checkboxes. The parent's todo widget and the OMPS tree both show above the editor without changing each other. After you check a child's saved result, update the parent's tasks yourself.
Memory. OMMS keeps its own recall, tools and capture. OMPS never reads, copies or changes memory
stores. A child gets the memory tool, and the OMMS skill if mapped, only when you enable it. That
child then works in the same project scope as OMMS normally uses, under its own session. The shipped
OMPS skill guides the parent to search memory before it delegates and to pass on only verified context.
What to read
| You want to | Read |
|---|---|
| Install, update or pin a version | How to install |
| Create agents: the YAML file, persona files and where they live | Set up agents |
| Run an agent, read progress and results | How to use |
| Remove OMPS and the files you created | How to uninstall |
A new install has no agents. Read Set up agents before you run anything.
Set up
Install the package:
pi install npm:om-pi-subagentsRun
/reloadin Pi.Run
/omps list. A new install answersNo personas mapped.
Pi supplies its own packages. The one runtime dependency is yaml. To load a
local checkout instead, see installation.
Add your first agent
Each agent needs a Markdown persona and a YAML mapping. Both live in your Pi
agent directory, ~/.pi/agent/, so package updates never touch them. Persona
paths are relative to the mapping file, inside omps/:
~/.pi/agent/omps/
├── config.yaml
├── personas/
│ └── reader.md
└── runs/<session-id>/<run-id>/
Breaking upgrade: move existing settings and personas with the
migration guide.
When only the old registry exists, OMPS blocks listing, launches and settings saves
with migration commands. OMPS_REGISTRY can explicitly select another file.
You create both. The install makes neither the mapping file nor the persona
folder. Keep persona files in ~/.pi/agent/omps/personas/. OMPS
reads only the files that your persona: lines name. For the full explanation,
see Set up agents.
Persona file ~/.pi/agent/omps/personas/reader.md:
You read files and answer questions about them.
Give short answers. Name the file for every claim.
Mapping file ~/.pi/agent/omps/config.yaml:
version: 1
agents:
reader:
persona: ./personas/reader.md
tools: [read, grep, find, ls]
thinking: off
Then run /omps list. The list now shows reader. No reload is needed.
For every field, persona tips and common errors, see Set up agents.
Start a run with /omps run reader Summarise the README, or ask the parent
model to call the omps tool. In the interactive terminal interface, use
@reader Summarise the README.
Pi trims submitted text, so leading spaces still allow launch. Unmapped file-like names such as
@README.md and @src/x.ts retain Pi's file-reference behaviour; unknown bare names show guidance.
Parallel and nested runs
Add limits beside your existing agents mapping. Preserve the agents you already defined.
This empty-mapping example shows four direct slots per parent and a maximum depth of three:
version: 1
limits:
maxConcurrentRuns: 4
maxDepth: 3
agents: {}
The root is depth zero. Depth three allows children, grandchildren and great-grandchildren.
A child can delegate only when its mapping approves the exact omps tool.
Each target keeps its own tools, so delegation can reach write-capable targets.
Limits have no additional fixed ceiling. Four slots through depth three can create
4 + 16 + 64 = 84 descendants. Use separate safe worktrees for concurrent writers.
See configured limits for inherited ceilings and cancellation.
For operational guidance in Pi, run /skill:om-pi-subagents.
Approved children need an explicit skill path; see setup.
Operator settings
Run /omps-settings in Pi, or through an RPC client that supports native dialogs.
/subagents-settings is an alias of the same menu. Select a setting, enter a value,
then confirm the shown value and save destination:
| Setting | Accepted values | Save destination |
|---|---|---|
| Maximum nesting depth | Safe integers of at least 0; root depth 0 | limits.maxDepth in the registry YAML |
| Parallel direct children per parent | Safe integers of at least 1 | limits.maxConcurrentRuns in that YAML |
| Visible agents | Safe integers from 1 to 256; default 5 | ui.maxVisibleAgents in that YAML |
| Fleet view | expanded, collapsed or off; default expanded |
ui.fleetView in that YAML |
| Management list | Show/Hide; default Show | ui.showManagementList in that YAML |
| Management next / enter key | Pi key specification or off; default down |
ui.navigationDownKey in that YAML |
| Management previous key | Pi key specification or off; default up |
ui.navigationUpKey in that YAML |
| Fleet view shortcut | A Pi key specification such as alt+o, or off; default off |
ui.toggleKey in that YAML |
| Inspection shortcut | A Pi key specification such as alt+i, or off; default off |
ui.inspectKey in that YAML |
| Result shortcut | Pi key specification or off; default ctrl+shift+e |
ui.resultKey in that YAML |
OMPS_REGISTRY selects the registry when set. The menu shows its resolved path.
Execution limits and UI settings stay in that one YAML file. OMPS leaves todo preferences
and Pi's settings.json untouched.
Type shortcut text such as ctrl+1; spell out the modifier instead of holding Ctrl in the input dialog.
Common modifiers are ctrl, shift and alt; super is also a valid modifier name.
Settings accepts any letter case and spaces around +. It converts ctr, ctl and control to ctrl,
opt and option to alt, and cmd, command and win to super.
The confirmation shows the converted value and your original text when they differ. YAML stores the converted key.
Manual YAML edits still require strict Pi modifier names; meta is rejected.
Ctrl+I and Tab are refused because legacy terminals send one byte for both.
Settings refuses effective Pi key conflicts before confirmation and saving, with owner-specific guidance.
Registration checks conflicts again after /reload. All keys can be off.
Enabled OMPS keys must differ after modifier normalisation.
Management navigation defaults to Down/Up and requires an empty, focused editor and visible list. Custom navigation keys occupied by Pi stay inactive, with the owning action named. There is no fallback. See modified-arrow setup for manual fullscreen-key remapping. OMPS never rewrites Pi keybindings.
On macOS, Option+O can type ø unless the terminal sends Option as Alt.
Set the terminal's Option behaviour or choose another key; see the terminal settings.
TDR-007 records this existing caveat.
Shortcuts bind when an interactive session starts. A saved shortcut needs /reload before it
becomes active; the menu shows the saved and the active binding until then. Visible-agent and
limit changes take effect without a reload, and the display repaints at once. Management-list visibility
also repaints immediately; hiding it ends selection. Navigation-key edits need /reload.
Older OMPS versions kept visible agents in <config-dir>/pi-subagents/config.json. That file
is now a read-only fallback: when YAML omits ui.maxVisibleAgents, its valid value still applies
and the menu labels its source. The menu offers a confirmed import that writes the value into
YAML. YAML wins once it declares the field. OMPS no longer writes the legacy file.
Cancelling an input or declining confirmation leaves that setting unchanged.
Earlier confirmed saves remain in effect. Creating a missing registry requires confirmation;
it starts with agents: {}. OMPS creates omps/ with mode 0700 and config.yaml
with mode 0600, without creating a persona folder. Malformed files must be corrected before saving.
Conflicting edits are rejected: reopen settings to load the newer values.
Saved limits apply to fresh launches. Existing runs continue, and an existing branch keeps its inherited depth ceiling. Depth zero disables new launches. Raising per-parent capacity can multiply process and provider load. See operator settings for the procedure and write-failure guidance.
Memory and Todo are off for new agent mappings. Existing explicit mappings stay in effect.
In /omps-settings, choose Agent capabilities, then an agent and Memory or Todo.
Select Enable. OMPS reads packages in <agent-dir>/settings.json, using the Pi agent directory
selected by PI_CODING_AGENT_DIR or the default ~/.pi/agent.
It accepts string sources and objects with a string source. Matching npm sources use
<agent-dir>/npm/node_modules/<name>; relative local paths resolve against the agent directory.
Detection offers valid packages even when parent autoload or resource filters disable their resources.
The child's confirmed mapping has its own approvals; parent settings stay unchanged.
One valid package skips the path prompt. Several distinct folders require your choice.
With no usable match, installation guidance precedes the manual path prompt.
Use an absolute installed package folder or published Pi extension entry for unlisted checkouts,
project-only packages and legacy global npm installs. Detection skips ~, file://, git and URL sources;
use their installed filesystem paths in the fallback. Missing or invalid Pi settings also use that prompt.
Review the exact tools, extensions and optional skills changes and destination before confirming.
Detection never imports, executes or loads the sibling extension, and cancellation leaves YAML unchanged.
Memory can also map its shipped skill. Approval for memory covers its whole tool, including write and portability modes.
On (configured) reports mapped resources, not backend health. Partial needs an
explicit correction; inspect the agent's lists before disabling an unrecognised wrapper.
Disable removes the recognised extension, mapped skill and tool for future launches.
No package is installed, no parent extension setting changes, and active children keep
what they started with. See optional child capabilities.
Compact fleet and inspection
The ● Agents tree above the editor shows every running direct agent with no key press.
Its look is adapted from tintinweb/pi-subagents
(MIT; see third-party notices). Each running agent has two lines:
a spinner, the name, the task, the tool-use count and the elapsed time, then what it is doing
now. The tree uses at most 12 lines, running agents first:
● Agents
├─ ⠹ reviewer Map the API · 3 tool uses · 4.2s
│ ⎿ searching…
├─ ⠹ planner Draft the rollout · 1.9s
│ ⎿ thinking…
└─ ✓ explorer List TypeScript files · 2 tool uses · 3.1s
The optional Management list below the editor shows the same runs for navigation. From an empty focused prompt:
- Press Down to select the first agent.
- Press Up or Down to move. Press Enter to inspect the selected agent.
- Press Escape to return to the prompt. The runs continue.
Outside the list, Up and Escape keep their normal Pi actions. Every active root stays
reachable; the list shows ui.maxVisibleAgents rows (default 5) with ↑ N more and
↓ N more markers. /omps inspect still opens runs after they leave both widgets.
Set ui.fleetView to collapsed for the tree heading only, or off to hide both widgets.
/omps fleet switches between expanded and collapsed for the current session.
Choose Management list: Hide in /omps-settings, or set ui.showManagementList: false, for tree-only use.
The tree remains expanded and /omps inspect stays available. Session toggles preserve the saved list preference.
Hints show active navigation keys; saved key edits apply after /reload.
Each launch leaves one compact acknowledgement row in the transcript. Pi's native expansion action,
app.tools.expand with Ctrl+O by default, reveals the acknowledgement text only. It never creates a
second live tree. The complete retained hierarchy lives in the inspection modal:
- Run
/omps inspectto open the picker of retained nodes. - Use Up/Down to select; Left/Right fold branches. Enter opens single-column details.
- Scroll details with Up/Down, PageUp/PageDown or Home/End. Left/Right switches agents.
- Press Escape to return to the picker, then Escape again to close.
/omps inspect <run-id> and management-list inspection open details directly; Escape closes them.
Fullscreen Pi supports picker row clicks and mouse-wheel scrolling over the detail body.
Regular mode uses the keyboard because the terminal owns mouse scrollback.
Reading position stays stable during updates; reaching the bottom follows new content until you scroll upwards.
Live answers remain provisional, capped at 4 KiB. Live and saved Markdown answers keep their readable structure. Supported RPC clients receive bounded text without terminal components.
Only an immediate parent can use status or cancellation for a descendant.
Tasks and outputs can contain sensitive text. Reads are limited to 64 KiB per selected evidence file; truncated output shows its saved location. See inspection.
Result messages
Interactive Pi folds long results after eight answer lines. The heading, files line and Result: label remain visible.
Errors and partial-output notes stay visible too. Short results have no fold hint.
The hint shows the hidden-line count, the active Result shortcut and always the host expansion key as a fallback.
ui.resultKey defaults to ctrl+shift+e; choose another free key or off in /omps-settings, then run /reload.
Fleet and inspection shortcuts retain their off defaults.
Ctrl+Shift+E toggles one session state for every OMPS result, leaving unrelated tool output unchanged.
Pi's app.tools.expand action, Ctrl+O by default, toggles an independent host state and also affects tool output.
Both states must be off to fold a result. Either enabled state also expands new results.
The result key needs extended-key reporting through kitty CSI-u or xterm modifyOtherKeys.
Without confirmed kitty support, OMPS warns that support is unverified and keeps a conflict-free binding active.
Raw Ctrl+E keeps Pi's editor line-end action. Use the host key shown in the hint if your terminal drops Shift.
A key occupied by an effective Pi action stays inactive; OMPS names the conflict and leaves Pi keybindings unchanged.
Folding leaves model-facing text, the 4000-character answer limit, saved output and delivery records unchanged. JSON, print and RPC result content retains its behaviour. See Getting the result for result timing and the complete expansion rules.
YAML fields
| Field | Required | Meaning |
|---|---|---|
version |
yes | Must be 1. |
limits |
no | maxConcurrentRuns and maxDepth; omitted fields default to one. |
agents |
yes | A mapping. Use {} for no agents. |
<name> |
- | The agent name. Use [a-z][a-z0-9-]{0,63}. No name is special. |
persona |
yes | Path to a Markdown file inside this directory. No frontmatter. |
tools |
yes | Exact tool names. [] grants no tools. No wildcards. |
model |
no | provider/id. The default is the parent's model. |
thinking |
yes | off, minimal, low, medium, high, xhigh, or max. |
skills |
no | Paths to SKILL.md files. Paths may start with ~/. |
extensions |
no | Paths to trusted extensions. See "Provider extensions". |
Personas cannot resolve into omps/runs/, including through symbolic links. Run evidence can contain model output.
OMPS rejects unknown fields, duplicate keys, aliases, and custom YAML tags.
A bad file stops every launch until you fix it. OMPS never runs on old
settings after a failed load.
Every agent needs explicit thinking. Add a supported value to older mappings
before launching. OMPS uses that value even when the parent has a different
thinking level. An empty agents: {} registry remains valid.
Edits take effect at the next launch. /omps list reloads the file. A run
that already started keeps the settings it started with.
Tools and MCP
Write each tool by its exact name. Native MCP tools are named
mcp__<server>__<tool>. The server name comes from your mcp.json. On Pi 1.0
and newer, hyphens in the name become underscores. See
Tools.
tools:
- read
- tool_search
- mcp__context7_mcp__resolve_library_id
- mcp__context7_mcp__query_docs
- Add
tool_searchif the agent must find deferred MCP tools. - The old
mcpproxy tool no longer exists. A persona that listsmcpfails before the task reaches a model, and the error names the native form. - Listing a tool does not load it. The server must also be configured and connected in the child.
The permission boundary
Before it sends the task, OMPS checks that the child loaded its guard, that
every approved tool exists, that the model resolves, and that the working
directory is right. It then blocks, at the moment of the call, every tool that
is not on the list. This covers direct calls, tools found with tool_search,
and calls made through another tool. A blocked call fails the run.
Only the parent may prompt a child. The guard refuses any other prompt, such as one a trusted extension sends, before Pi starts a model run. A refused prompt before readiness stops the launch. A refused prompt later fails the run.
This is a rule inside trusted Pi code. It is not an operating-system sandbox.
- A tool name does not prove what the tool does. An MCP tool marked read-only gets no extra trust. Only the names you list are allowed.
bash,powershell,write, andeditcan change files./omps listmarks an agent that has one of them aswrite-capable.- An agent with a write-capable tool runs with your file permissions. Start it in a feature worktree or another directory that is safe to change.
- Sessions have separate direct-child slots. OMPS sets no combined machine or provider budget.
/omps listmarks approvedompstargets asdelegation-capable, including their ability to select write-capable targets.
Provider extensions
A child loads its guard, required Pi built-ins and explicitly mapped resources. OMPS also loads managed delegation or todo setup when those tools are approved. Ambient resources stay disabled. For a custom provider, list the extension that registers it:
model: my-provider/my-model
extensions: [~/.pi/agent/extensions/my-provider/index.ts]
Only list code you trust. It runs in the child with your permissions. If the model is not known to the child, the run fails before the task is sent. OMPS does not choose another model for you.
Reading progress
Run /omps without arguments to see current-session status. Whitespace-only
arguments also show status. A fresh session answers No runs in this session.
Use /omps status <run-id> for one run, or /omps cancel <run-id> to stop it.
The ● Agents tree appears above the editor and the navigation list below it. A completed
run stays in the tree until the next parent turn and for at least 4 seconds. A failed or
cancelled run stays for two parent turns. The list keeps a finished run for 4 seconds.
With ui.fleetView: collapsed, the tree shows only its heading and the running count.
Cancellation sends no automatic result message.
The tree shows task labels, tool-use counts, elapsed times, active tool names and the first
line of the agent's visible answer so far. It never shows tool arguments, raw tool results,
thinking or stderr. Terminal controls are removed from displayed text. The full saved answer
and the result message stay on their existing paths. Clients without widget support can use
/omps or the status line. OMPS opens no extra Orca terminals.
Run files
OMPS saves each run in ~/.pi/agent/omps/runs/<session-id>/<run-id>/. The
directory and the files are private to your user.
| File | Content |
|---|---|
config.json, persona.md |
The settings and persona the run started with, and the task. |
status.json |
State, timestamps, error, child process id, depth, ownership and effective limits. |
events.jsonl, stderr.log |
Streamed evidence. Known credential fields are redacted. |
output.md |
The final answer. Partial text from a failed or cancelled run starts with > PARTIAL OUTPUT. |
notification.json |
Whether the result message reached the parent. |
Personas, tasks, and outputs can hold sensitive text. OMPS never deletes run directories. Remove old ones yourself.
Run states
starting, running, stopping, completed, failed, cancelled.
A run is completed only when all of these are true: the child accepted the
task, it settled, the last assistant message is a normal answer, the output is
saved, the child exited cleanly, and cleanup is confirmed. Output that exists
after an error does not make a run pass.
- Start-up has 30 seconds. A whole run has 30 minutes.
/omps cancel <run-id>stops that owned subtree, including nested agents, without cancelling unrelated siblings.- A delegating child waits for owned runs and result-delivery attempts before final settlement.
om-pi-todoand OMMS are optional and off for new child mappings. Child tasks stay local and never update the parent's OpenSpec checkboxes.- Reload, quit, or a new session stops active runs. No child outlives its parent.
- If OMPS cannot confirm that all processes stopped, the run fails and the session cannot start another until you stop them by hand and reload.
Not supported
These are outside this version:
- Calls to the old
subagenttool and workflow scripts. - Councils, scheduling, remote workers, automatic worktrees, and provider fallback.
- Resuming a run after a restart.
Skills that promise these features need edits before you use them with OMPS.
Remove OMPS
- Stop active runs with
/omps cancel <run-id>, or quit Pi. - Run
pi remove npm:om-pi-subagents. - Run
/reload.
Run files stay in ~/.pi/agent/omps/runs/ until you delete them. Your mapping
in ~/.pi/agent/omps/config.yaml and your persona folder also stay. You
created them, so you remove them. For the steps, see
How to uninstall.
Release (maintainers)
Releases go to npm as om-pi-subagents. Release Please prepares each one. You never edit the version or the changelog by hand.
Write commits and pull request titles in the Conventional Commits style:
feat:,fix:,perf:,docs:. Add!for a breaking change, for examplefeat!:.Merge to
main. Release Please opens or updates a pull request called "chore(main): release X.Y.Z". It bumpsversioninpackage.jsonand writesCHANGELOG.md.Read that pull request. Check the version and the changelog text. Its CI checks run.
release-auto-merge.ymlwaits for successfulCIfrom a same-repositorypull_requestrun, then checks the release output. The release App squash-merges the tested SHA with--match-head-commit. Release Please tags the commit and creates a GitHub release.The publish job runs the full gate on that exact commit, then stages the version on npm. It captures npm's stage UUID and adds the exact approval command to the GitHub release. The version is not installable yet.
As the human maintainer, run
bun run release:approvefrom the repository with two-factor authentication. In Pi, use! bun run release:approve.The helper reads the captured UUID from the release note. If capture failed, the note gives manual-list guidance:
npm stage list om-pi-subagents bun run release:approve <stage-uuid>Select the UUID for that version. You can instead run the note's exact
npm stage approvecommand, or use the Staged tab at https://www.npmjs.com/package/om-pi-subagents. Reject withnpm stage reject <stage-id>.
Guarded release pull request merge
The workflow loads the trusted scripts/release-pr-guard.mjs from main. It never checks out or executes pull request code.
The guard requires the release bot's pull request targeting main, bot-authored commits signed by GitHub, and an unchanged tested head.
Only package.json, .release-please-manifest.json and CHANGELOG.md may change.
Both JSON files must change only their versions and agree; the changelog must contain no deletions.
A guard failure stops the merge. The App token lets the merge start the Release workflow.
GitHub's native allow_auto_merge setting is not required.
After this workflow reaches main, rerun the existing release pull request's pull_request CI run to trigger it.
Leave the pull request source unchanged.
The Release workflow comments on the merged release pull request and mentions the repository owner after staging.
Enable email notifications for GitHub @mentions to receive that comment by email.
If the release fails before staging, it adds a failure notice to the release and comments with the failed run link.
Fix the failed step, then rerun the Release workflow. Human approval with 2FA remains required for npm publication.
Human-run approval helper
Run bun run release:approve from this repository checkout. In Pi, the human can use ! bun run release:approve.
The ! prefix runs a shell command; it is not part of the package script. Agents and CI must never run real approval.
Prerequisites: Bun, GitHub CLI (gh) with repository access, npm 11.15 or newer, and an npm account with approval rights.
Check gh auth status and npm whoami before starting. npm owns login and the two-factor authentication prompt.
The helper is repository tooling and is excluded from the installed npm package.
- Run
bun run release:approveto discover the stage UUID from the newest GitHub release note. - If discovery fails, run
npm stage list om-pi-subagentsand select the matching pending version. - Retry with
bun run release:approve <stage-uuid>. - After confirmed registry visibility, run the printed
pi update npm:om-pi-subagentscommand when ready. - Restart Pi or run
/reloadafter updating.
The helper displays the stage before approval and polls npm with fresh reads, at most 30 attempts.
OMPS_REPO overrides the GitHub repository; OMPS_RELEASE_POLL_SECONDS changes the five-second polling interval.
Failed approval stops before polling and gives login guidance. After a visibility timeout, check npm status before retrying.
An already published version needs no further approval. The helper performs no Pi update or plugin/channel operation.
What each commit type does before version 1.0.0:
| Commit | Version change |
|---|---|
fix:, perf: |
Patch, for example 0.1.0 to 0.1.1 |
feat: |
Minor, for example 0.1.0 to 0.2.0 |
feat!: or a BREAKING CHANGE: footer |
Minor. After 1.0.0 it is major. |
docs:, style:, test:, chore:, ci: |
No release |
One-time setup
No npm token is used. npm trusts the release workflow through OIDC.
Publish the first version by hand, then tag it and create its GitHub release, so Release Please counts from it.
Create the release GitHub App with the manifest helper. It saves
RELEASE_APP_IDandRELEASE_APP_PRIVATE_KEYas repository secrets. No key file is created.Create the
npm-publishenvironment, limited to themainbranch.Add the trusted publisher:
npm trust github om-pi-subagents --file release.yml --repo cmdaltctr/om-pi-subagents --env npm-publish --allow-stage-publishSwitch the workflow on:
gh variable set RELEASE_PLEASE_ENABLED --body true.
Development tooling
Use Bun 1.4.2 and Node.js 22.12 or newer. Run these commands from the repository root:
bun install
bun run setup:host
bun run ci
Oxlint checks code with warnings denied. Oxfmt formats files with tabs and a
120-character print width. Husky installs the pre-push hook through prepare.
Host setup uses Bun to fetch Pi 0.99.1 and typebox 1.3.27 into .pi-host/.
It includes @earendil-works/pi-ai, @earendil-works/pi-coding-agent,
@earendil-works/pi-tui and typebox. Host packages remain outside this
project's node_modules. bunfig.toml sets peer = false to keep them there.
The extension declares its directly used host packages as peers.
Vite is a direct development dependency because Vitest needs it while automatic
peer installation is disabled.
@fission-ai/openspec 1.14.0 is a pinned development dependency for the real
om-pi-todo OpenSpec compatibility tests. bun install supplies its CLI locally;
production installs do not require it.
[!CAUTION] Known high-severity vulnerability in a development dependency OpenSpec 1.14.0 brings in
braces@3.0.3throughfast-globandmicromatch. GHSA-vfj7-8cjw-p6xm allows deeply nested brace patterns to crash the OpenSpec CLI. No patched release exists as of 5 October 2026. Use only trusted schema patterns and repositories. The maintainer accepts this risk for personal development and compatibility tests.bun run auditchecks production dependencies without exceptions, then checks all dependencies with this advisory excluded. Other advisories still fail the audit. Runbun auditto see the accepted finding. Remove the exception when a patched dependency becomes available.
| Purpose | Command |
|---|---|
| Fetch pinned host packages and Pi CLI | bun run setup:host |
| Human approval of a staged release | bun run release:approve |
| Format files | bun run format |
| Check formatting | bun run format:check |
| Lint with warnings denied | bun run lint |
| Apply lint fixes for review | bun run lint:fix |
| Check types | bun run typecheck |
| Run tests | bun run test |
| Check dependency vulnerabilities | bun run audit |
| Format check, lint, types, then tests | bun run ci |
| Check a fresh clone of committed HEAD | bun run ci:clean |
| Install the Husky hooks | bun run prepare |
bun run ci:clean needs a git commit. It installs from the lockfile with
HUSKY=0 in a temporary clone and runs bun run ci. Uncommitted changes are
excluded. Host packages already downloaded locally are reused.
The clone sets OMPS_PI_BIN to the pinned host CLI, matching GitHub Actions.
The executable .husky/pre-push runs host setup followed by bun run ci:clean.
GitHub Actions runs the same checks and a separate audit job on pushes and
pull requests. Its actions use full commit SHA pins.
Tests start real Pi 0.99.1 children with a local fake model and local MCP server. They use no live model or real credential. CLI-dependent suites skip when Pi is missing; independent tests still run.
Tests use OMPS_PI_BIN first, then .pi-host/node_modules/.bin/pi, then pi
on PATH. Set an explicit override only when testing another installation.
OMPS_REGISTRY selects another mapping file, for tests or for a second setup.
Read AGENTS.md before changing the project.