Skip to content

Repository files navigation

omp-plugins

Installable oh-my-pi (omp) plugin bundle. It extends an omp agent with context-cost controls, durable memory, dangerous-command guards, and a project skill — all loadable into any omp profile.

What's included

Piece Path Loaded by omp via
Integration extension — engram memory auto-save + turn-start retrieval, receipt carriage, GPG/SSH hard-stop guards, global /receipt /verify /recall /find-work /finalize /bookkeep /worktree /wt /ticket commands plugins/oh-my-pi-integration/extensions/index.ts (+ guards/, receipt/, commands/) package.json → omp.extensions
Universal project rules — harness behavior, tool-routing discipline, strict review standards, docs-and-planning audit, parallel-safe tests, config merge precedence, safe-command guards plugins/oh-my-pi-integration/rules/ ~/.omp/agent/rules/ and ~/.omp/rules/ (both; root-level is picked up directly by omp)
omp-specific universal agent rules (receipt contract) — one canonical document; each profile's AGENTS.md is an installer-managed symlink AGENTS.md agent/AGENTS.md + per-profile symlinks
Agent config scaffold (no credentials) agent/config.yml agent/config.yml

The bundle also ships a .omp-plugin/marketplace.json catalog so the contained plugin can be installed directly with omp plugin install.

What the extension does

  • Engram memory persistence — buffers notable mutations each turn and saves them to engram at turn end and session shutdown, so later sessions can reuse recorded solutions.
  • Turn-start retrieval — when enabled, distills the user prompt into a keyword query and injects prior project memories back into the agent loop (best-effort, bounded, never blocking).
  • Receipt carriage — when <project>/.omp/receipt.toml exists, each turn carries the small TOML job ledger ([[job]] / [[issue]] entries with state fields) into the agent loop as an invisible footer, and applies chores: bumps the [carriage] n counter, stamps finished jobs with done_at, prunes finished jobs after 3 receipts, and drops empty entries — line-oriented, so comments and unknown keys survive. Each carry also records a session_artifacts = [...] key listing paths written under .tmp/ during the session (in-process write tracker), surfaced in the footer as a one-line artifacts: N. Fail-open throughout; opt out with PI_RECEIPT_DISABLE=1.
  • /find-work command — discovers open work items across the receipt ledger, .plan/ docs (labels read from YAML frontmatter labels:, **Labels:**, or **Tags:** headers drive kind/priority/domain; the **Epic:** binding feeds connected-item search), GitHub (gh), git-issue, and the repo's own dirty working tree (a PATCH review item scoped to a performance & bughunting pass), and presents them as a flat list (1,2,3, A,B,C, P1,P2,P3, or B1,F1,E1 schemes, with batches grouping and bug/feature/epic/task filters), a markdown table, or an interactive ask dialog grouped by domain; ask filters dialog candidates by the topic when a directive matches tickets and hands the selected batch (and any trailing directive, e.g. /find-work ask propose the next batch of fixes) to an agent turn. jira/glab are resolved inside that turn. git-issue sources request open tickets explicitly (ls --state=open); .plan/ and giwt-run artifacts older than 30 days (ARTIFACT_STALE_DAYS, or a newer verified-at: marker) stop surfacing. Independent sources fetch concurrently; live tool findings (lint/typecheck/tests/knip/jscpd, via giwt doctor check when available) share a bounded wall budget (TOOL_CLUSTER_BUDGET_MS, 120s) — on repos where they cannot finish in budget the roster still presents, with a warning naming the direct command. Flags: -s <search> runs a tiered search over the roster (direct tag/id/phrase hits, then fuzzy title candidates, then potential connections via the **Epic:** binding, bare TASK-* refs in .plan/epics/*, and shared tags) appended after the main results with match: … annotations; -m/-d <directive> carries an explicit user directive + approach recommendation into the dispatched turn (distinct from the positional filter text); --fast skips the live tool findings entirely (-s implies it).
  • GPG & SSH hard-stop guards — when a commit signing or ssh-agent/socket failure needs a human (locked GPG key, stale SSH agent), substitutes an imperative hard-stop directive and blocks the agent's usual self-recovery commands (gpgconf, gpg-agent, ssh-agent lifecycle, socket reassignment, passphrase bypass).
  • Destructive-git guard — notifies (never blocks) when a git command would destroy work (reset --hard, clean -f, push -f, branch -D, stash, checkout --, …) so the agent sees the risk before committing.
  • Post-edit lint feedback — after a successful edit/write of a TS file, runs the project's biome on that file and surfaces diagnostics in the tool result (best-effort, bounded; resolves the repo-local biome from node_modules/.bin, falling back to PATH).
  • Native tool reroute pre-hook (hooks/pre/lean-ctx-native-reroute.ts) — blocks the eval tool outright (both kernels are disabled in config; the sanctioned workflow is a re-executable .tmp/ script run via bash) and escalates in-root edit/write/glob to the lean-ctx MCP (ctx_patch anchored, hash-validated edits and creation; ctx_glob for globs). Native write stays allowed for .tmp/ scratch at any depth and is blocked outside the project root and for ssh:// targets. read/grep, out-of-root paths, internal URIs (except ssh:// writes), and binary/document/archive paths keep the native tools — fail-open exemptions, never a dead end.
  • Compaction preservation — on session.compacting, injects the in-flight mutation buffer into the compaction summary so no uncommitted work is lost across a compaction (harness-evasion-guard pre-hook additionally blocks agent attempts to bypass the read-only harness tools in the shell).

All guards live as pure, unit-tested logic in extensions/guards/: they take command/output strings and return decisions, so behavior is auditable without a harness.

Universal project rules

Rules live in plugins/oh-my-pi-integration/rules/ and are installed to both <target>.omp/agent/rules/ (agent-scoped, backward-compat) and <target>.omp/rules/ (root-level, picked up directly by omp). Each rule has YAML frontmatter:

---
name: <filename-stem>
description: "<one-line purpose>"
condition: ["<regex-with-lookahead-AND-facets>"]
scope: ["text", "thinking"]
---
<imperative steering content>

Condition semantics — AND across facets

The ttsr engine compiles each condition: array element into an independent RegExp and triggers when any one matches (OR). To express AND (all facets must co-appear in the assistant's stream), each rule's condition is a single regex using lookahead chains:

^(?=[\s\S]*facet1)(?=[\s\S]*facet2)(?=[\s\S]*facet3)...

This fires only when the assistant's streamed text/thinking contains all facets. A rule with a single facet is unchanged.

Always anchor the chain with ^. Without it the zero-width lookahead regex has no anchor, so on non-matching input .test() re-runs the greedy [\s\S]* scan at every stream position — O(n²) ReDoS (measured ~2.3 s across 75 rules on an 8 KB non-match vs ~1.2 ms anchored). Anchoring is semantically identical: each facet's [\s\S]* already scans the whole stream from position 0. scripts/check-regex-safety.ts (wired into bun run verify) errors on any unanchored lookahead chain and on unbounded .*.

Scope conventions

Scope Fires on Use for
text assistant prose reminders about approach, quality, conventions
thinking assistant internal reasoning same as text, for thinking blocks
tool:bash bash tool-call composition preventing specific commands or tool misuse
tool:edit / tool:write edit/write tool calls file-content rules

Rules about preventing specific commands (e.g. git status during implementation) should scope to tool:bash only — scoping to text causes them to fire during review/discussion where the commands are legitimate.

Install

# install into an isolated omp profile root (default target)
bun scripts/install.ts

# explicit target (PREFIX or --target)
PREFIX=/tmp/omp-test bun scripts/install.ts
bun scripts/install.ts --target /tmp/omp-test

# overwrite an existing install; or preview without writing
bun scripts/install.ts --force
bun scripts/install.ts --dry-run

# sweep installer-parked .bak backups (owned paths only; strays survive)
bun scripts/install.ts --target ~/.omp --live --clean-bak

# update your live profile directly (e.g. AGENTS.md, rules, extensions)
bun scripts/install.ts --target "$HOME/.omp" --live

The installer lays the payloads into:

  • TARGET/.omp/agent/ — AGENTS.md, config.yml, extensions/, hooks/pre/
  • TARGET/.omp/agent/rules/ — universal project rules (agent-scoped, backward-compat)
  • TARGET/.omp/rules/ — universal project rules (root-level, picked up directly by omp)
  • TARGET/.omp/profiles/<name>/agent/ — per-profile config from profiles/<name>/agent/ in the repo: config.fragment.yml is deep-merged over agent/config.yml (the base) into a complete config.yml; a shipped config.yml is installed verbatim instead (full override). AGENTS.md is a symlink to the canonical agent/AGENTS.md — the universal document ships once with zero per-profile drift
  • TARGET/.omp/plugins/ — plugin registry

When TARGET is itself a profile root (e.g. ~/.omp), the bundle is laid down directly under it without nesting a second .omp. It writes only bundle-owned files and never touches databases, sessions, caches, or memories. It refuses to run against your live home profile unless you pass --live (use an isolated target such as /tmp/omp-test by default), then point a scratch profile at it with omp --profile test.

Re-runs are safe and manifest-driven: an ownership ledger records every file the installer wrote. On re-run, installer-owned files are updated in place (rules added, changed, or renamed synchronize without --force), files that no longer ship are removed, and files you modified locally (or never installed) are kept with a notice — never clobbered without --force, which overwrites them while keeping the previous copy as <dst>.bak. Symlinked destinations are never followed; every touched path is checked to stay inside TARGET.

Extension runtime options

Environment variable Effect
PI_INTEGRATION_DISABLE=1 Disable the whole integration extension
PI_INTEGRATION_RETRIEVE=1 At turn start, retrieve prior engram memories for the project and inject a bounded context block
PI_RETRIEVE_EVERY_TURN=1 Re-retrieve every turn (default: once per session)

Development

Requires bun — the omp runtime runs on bun and @oh-my-pi/pi-coding-agent is consumed as raw TypeScript via its exports map.

bun install        # install toolchain (@oh-my-pi/pi-coding-agent, biome, typescript)
bun run verify     # lint + typecheck + test
bun run hooks:install  # activate .githooks/pre-commit (core.hooksPath)

The pre-commit hook runs the typecheck + lint + test gate when TS/config/shell files are staged (the gate is fast enough that the full run IS the fast path). giwt manages the repo lifecycle: giwt.toml sets the finalize gates (check bun run verify, test bun run test, no --diff-base append) and the fork-base branch; worktrees created via giwt inherit .githooks/ automatically. /wt and /finalize detect giwt on PATH and prefer it over the legacy scripts/worktree CLI; the giwt finalize prompt names failing gates from the run record's meta.json (outcome.failedGates) instead of re-running blind. /bookkeep gained a bare audit scratchpad cross-reference report and a scratch subcommand (pure-fs .tmp hygiene summary: bytes, orphans, oldest artifact, top globs). /ticket advises ([status-vocab advisory], fail-open) when a body **Status:** value falls outside the provisional vocabulary.

Script What it runs
verify lint → typecheck → test → check:rules → check:ship
lint / lint:fix Biome check, then the console-log gate (scripts/check-no-console.ts) — lint:fix also applies safe fixes + import sorting
typecheck tsc --noEmit over plugins/**/*.ts and scripts/**/*.ts
test bun test — guard/hook tests in plugins/**/__tests__/ and installer/checker tests in scripts/__tests__/
check:rules scripts/check-rules-sync.ts — validates every rule's frontmatter (name == filename, description/condition non-empty, valid scope) and syncs against the installer laydown
check:ship scripts/check-shipment.ts — installs into a temp target and asserts no __tests__/ dirs ship, no .bak/.original files, and only index.ts at top of agent/extensions/
install:test bun scripts/install.ts --target /tmp/omp-test
check:coverage scripts/check-coverage.ts — runs the suite under lcov and fails when global line coverage drops below the pinned ratchet (93% at landing; target 100%)
check:rules scripts/check-rules-sync.ts — validates every rule's frontmatter (name == filename, description/condition non-empty, valid scope) and syncs against the installer laydown
Linting, types, tests, and the rules bundle are all exercised together by
bun run verify, which is the standard pre-commit / CI gate for this
repository.

Note on Biome and regex guards. noUselessStringRaw is disabled in biome.json because the guard modules build regexes from String.raw literals that contain regex escapes (\s, \d). Biome's rule only checks JavaScript escape sequences (\n, \t, \\, …) and would propose removing String.raw from literals whose backslash-escapes are meaningful to the regex — silently changing \s into s. Keeping the rule on would invite a corrupting fix on security-critical enforcement code.

Layout

├── .omp-plugin/marketplace.json   catalog for `omp plugin install`
├── AGENTS.md                      universal agent rules: receipt contract
│                                  (installed to <target>.omp/agent/AGENTS.md;
│                                  profiles get installer-managed symlinks to it)
├── agent/APPEND_SYSTEM.md         harness routing norm, appended to the system prompt
│                                  (installed to <target>.omp/agent/; profiles link it)
├── agent/config.yml               agent config scaffold (credential-free)
├── plugins/oh-my-pi-integration/  the plugin package (extensions/hooks/rules)
│   └── rules/                     universal project rules (installed to both
│                                  <target>.omp/agent/rules/ and <target>.omp/rules/)
├── profiles/                      per-profile scaffolds (installed to <target>.omp/profiles/<name>/agent/)
│   ├── glm/agent/config.fragment.yml      zai GLM-5.3 profile fragment (deep-merged over the base)
│   └── minimax/agent/
│       └── config.fragment.yml    MiniMax profile fragment (deep-merged over the base)
├── scripts/install.ts             installer for an isolated omp profile
├── biome.json                     lint/format config
├── tsconfig.json                  TS config (moduleResolution: bundler)
├── package.json / bun.lock        bun dev tooling (typecheck, lint, test)
└── LICENSE

Profiles

OMP supports multiple named profiles under ~/.omp/profiles/. Each profile has its own agent/config.yml (model, provider, memory backend); agent/AGENTS.md is universal — the installer symlinks every profile to the canonical ~/.omp/agent/AGENTS.md, so the same document loads once under any profile. Profile settings override the base ~/.omp/agent/ defaults.

The bundle ships a profiles/ directory in the repo; the installer scaffolds any profile it finds there (currently minimax and glm). Profile configs are developed as fragments: profiles/<name>/agent/config.fragment.yml holds only the per-profile deltas (model roles, theme, provider quirks, compaction), and the installer deep-merges each fragment over agent/config.yml (the base) to serve a complete config.yml into the live profile. Map keys merge recursively; lists replace wholesale; scalars override. Shipping a config.yml in the profile dir instead bypasses assembly entirely (full override). To add a new profile:

  1. Create profiles/<name>/agent/config.fragment.yml in the repo — model roles and any per-profile overrides (or a full config.yml to opt out of the base merge).
  2. Optionally add profiles/<name>/agent/config.yml for a full config override (agent rules are universal — the installer links the profile to the canonical AGENTS.md automatically).
  3. Bootstrap it with omp --profile <name> -p "" (omp creates ~/.omp/profiles/<name>/agent/ on first invocation), then run bun scripts/install.ts --target ~/.omp --live — the profile is scaffolded automatically.

Switch profiles at runtime:

omp --profile glm         # zai GLM-5.3
omp --profile minimax     # MiniMax-M3
omp --profile default     # base profile

License

AGPL-3.0 — see LICENSE for the full text. (The plugin manifest in plugins/oh-my-pi-integration/package.json declares AGPL-3.0-or-later.)

About

Collection of useful oh-my-pi plugins

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages