Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,32 @@ jobs:
- name: Extension tests
working-directory: plugins/pstack
run: bun test ./extensions/potetomode/index.test.js ./extensions/pstackpolicy/index.test.js

smoke:
# A real omp loads plugins/pstack: every skill directory must register as a command, and the
# pin extension must record and reload its state. omp-port/smoke-plugin.mjs names each check.
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.2
- name: Install pinned omp
# can1357/oh-my-pi release v18.12.6, asset omp-linux-x64, sha256
# 85d9daf3a05fc76e8cd425ae1904eb576af8d21cc85fcf4690742626e07ccfa4. That is the digest
# `gh api repos/can1357/oh-my-pi/releases/latest` reports for the asset and the sha256 of the
# downloaded file, checked 2026-10-22. A bump changes the tag and the digest together.
env:
OMP_TAG: v18.12.6
OMP_SHA256: 85d9daf3a05fc76e8cd425ae1904eb576af8d21cc85fcf4690742626e07ccfa4
run: |
dir="$RUNNER_TEMP/omp"
mkdir -p "$dir"
curl -fsSL --retry 3 -o "$dir/omp" \
"https://github.com/can1357/oh-my-pi/releases/download/$OMP_TAG/omp-linux-x64"
echo "$OMP_SHA256 $dir/omp" | sha256sum --check -
chmod +x "$dir/omp"
echo "$dir" >> "$GITHUB_PATH"
- name: Plugin smoke
run: OMP_SMOKE_REQUIRED=1 bun omp-port/smoke-plugin.mjs
6 changes: 3 additions & 3 deletions .omp-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
},
"metadata": {
"description": "pstack, poteto's engineering methodology for Cursor, ported to oh-my-pi. Model and provider agnostic.",
"version": "0.15.25"
"version": "0.15.30"
},
"plugins": [
{
"name": "pstack",
"description": "56 skills, 23 playbooks, 24 principles, the poteto-mode pin, and two agents. Upstream cursor/plugins pstack at e5136d8.",
"version": "0.15.25",
"description": "59 skills, 23 playbooks, 24 principles, the poteto-mode pin, and two agents. Upstream cursor/plugins pstack at 4ec7ffa.",
"version": "0.15.30",
"category": "development",
"license": "MIT",
"source": "./plugins/pstack"
Expand Down
34 changes: 22 additions & 12 deletions PORTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,11 @@ The split is by kind, not by size.
line, a patch that stops matching costs a merge.
- Port prose goes in the owned skills, which `install_tree` restores from `HEAD` and which
therefore cannot conflict with upstream at all.
- A patch is for code: control flow, a data shape, a file upstream does not have. Both remaining
patches touch a script, and one of them replaced two interlocking patches that had to be read
together to apply, because one wrote a transcript lookup the other deleted.
- A patch is for code: control flow, a data shape, a file upstream does not have. The patches
touch scripts only. `worktree-audit-omp.patch` is the port's own change. The three `zzz*`
patches carry open upstream PRs (#746 and #769, the check-plan half of #745, and #733 with an
age-limited marker). When upstream merges one, its patch stops applying; delete the patch rather
than resolving it.

Author a patch against **post-rules** text. `rules.sed` runs first, so a hunk quoting the raw
upstream line fails whenever an earlier rule rewrote it. `worktree-audit-omp.patch` deletes a
Expand All @@ -234,8 +236,9 @@ correct tree. They now derive the name the way the preamble tells the agent to.

The gate used to assert that port-authored prose sat *inside* upstream's playbooks, which is the
opposite of mirroring upstream and made every one of those assertions a rule that went stale. Those
checks are gone. What remains is residue detection: Cursor wire fields, model slugs, retired role
keys, install paths, and build integrity.
checks are gone. What remains is residue detection: Cursor wire fields and tool names, Cursor's
transcript layout, model slugs, retired role keys, install paths, a claimed `hub` tool, an unscoped
`omp cleanse --all` recommended as a diagnostic, and build integrity.

`skills/setup-pstack` is port-owned, so the build restores it from `HEAD` and never rebuilds it from
upstream. Upstream's version writes a Cursor rules file with no omp meaning, so the fork is
Expand All @@ -255,8 +258,9 @@ Known deltas the port mirrors faithfully and will not diverge on. The guide says
omp ignores the skill frontmatter keys `mode:` and `reminder:`, which is how Cursor pins
`/poteto-mode` as a Custom Mode (`Opt+Enter`). That is reproduced natively in
`~/.omp/agent/extensions/potetomode/index.js` using the pattern proven by the installed `ponytail`
extension, `appendEntry` to persist, `session_start` plus `getBranch()` to restore,
`before_agent_start` to inject, and `registerCommand` for `/poteto-mode`.
extension, `appendEntry` to persist, `session_start`, `session_switch`, `session_branch`, and
`session_tree` plus `getBranch()` to restore, `before_agent_start` to inject, and `registerCommand`
for `/poteto-mode`.

The injected reminder is a pointer, not the playbook. It tells the agent to read
`skill://poteto-mode` on demand instead of inlining the whole SKILL.md every turn.
Expand Down Expand Up @@ -298,11 +302,17 @@ The injected reminder is a pointer, not the playbook. It tells the agent to read
experiment rather than the answer. This repository neither ships nor requires it.
- **Sibling coordination.** `write agent://<id>` steers or follows up with a running, idle, or parked
worker, `agent://all` broadcasts to visible live peers, `read history://` lists registered agents
with status and parent, and `read proc://` lists background jobs and project services. These are
the sanctioned primitives when workers must coordinate instead of running independent. The
orchestrator uses its own TSV store and `orch inbox` for the queue instead, so sibling messaging
stays unused there. Cross-session messaging does not exist locally and gets no workaround here. It
is tracked upstream and stays open.
with status and parent, `read proc://` lists background jobs and project services, and the `wait`
tool blocks until the next settled job or peer message. These are the sanctioned primitives when
workers must coordinate instead of running independent. There is no `hub` tool. Probe it rather
than trusting this line: `grep -a -A40 'src/tools/builtin-names.ts' "$(readlink -f "$(command -v omp)")"`
prints the binary's builtin tool list, which on 18.12.6 carries `wait` and no `hub`; the binary's
only other `hub` is the `/hub` slash command that opens Agent Hub. An earlier tree read a `hub`
tool with list/send/inbox/wait ops off a stale pi-coding-agent 17.x package, and the gate now
fails any shipped sentence that names one. The orchestrator uses its own TSV store and
`orch inbox` for the queue instead, so sibling messaging stays unused there. Cross-session
messaging does not exist locally and gets no workaround here. It is tracked upstream and stays
open.

## Still missing in omp

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
An omp marketplace carrying one plugin.

`pstack` is Lauren Tan's engineering methodology for Cursor, ported to oh-my-pi and made
model and provider agnostic, 56 skills with 23 playbooks and 24 principle leaves.
model and provider agnostic, 59 skills with 23 playbooks and 24 principle leaves.
Wide parallel runs are a `swarm` dispatch, not a separate plugin.

```
Expand Down
2 changes: 1 addition & 1 deletion omp-port/UPSTREAM
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e5136d82418d2db3165ea1050d17577cd618cc05
4ec7ffa173eaa70d3d9467a627baf0954645a353
105 changes: 65 additions & 40 deletions omp-port/check-port.sh
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,17 @@ fi

runtime_contract() {
local bad label pattern
for label in per-call-model pstack-rule-file task-environment; do
for label in per-call-model pstack-rule-file task-environment unscoped-cleanup history-layout; do
case "$label" in
per-call-model) pattern='subagent_type|run_in_background|`model`:\s*[^f]|Set `model`|set `model` to|with `model` from|omit `model` so' ;;
per-call-model) pattern='subagent_type|run_in_background|generalPurpose|`model`:\s*[^f]|Set `model`|set `model` to|with `model` from|omit `model` so' ;;
pstack-rule-file) pattern='pstack-models\.mdc' ;;
task-environment) pattern='environment:[[:space:]]*"?((local)|(cloud))\b|cloud_base_branch' ;;
# `omp cleanse` detects AND fixes with parallel subagents, and `--all` runs every checker
# repo-wide, so recommending it as a precommit diagnostic edits files outside the diff.
unscoped-cleanup) pattern='omp[[:space:]]+cleanse[[:space:]]+(--all|-a)([[:space:]]|`|$)' ;;
# Cursor's per-project transcript directory and its three layouts. omp writes one layout,
# described in omp-mechanics/references/session-store-on-omp.md.
history-layout) pattern='agent-transcripts|/subagents/|read the first JSONL line|legacy flat|message\.content\[0\]' ;;
esac
bad=$(grep -rInE "$pattern" --include='*.md' --include='*.mjs' --include='*.ts' --include='*.sh' "${SCOPE[@]}" 2>/dev/null || true)
if [ -n "$bad" ]; then
Expand All @@ -174,24 +180,20 @@ runtime_contract() {
report "retired runtime labels" "PASS no abstract role labels, placeholders, or stale process wording"
fi

# `hub` IS a real built-in tool on this harness: sibling messaging, settled-job inspection, and
# supervised services, with ops list/send/inbox/wait/cancel/jobs/start/logs/stop. Verified in the
# installed package -- it is in pi-coding-agent's canonical tool set, and the binary carries the
# HubTool string. It is registered only when tool names are not restricted and IRC is enabled.
#
# This assertion used to be the opposite: it failed any backticked `hub`, enforcing a denial that
# was not true, with a mutation pinning the wrong behaviour. A line that claims hub does not
# exist is now the defect, because that is the sentence that sends an agent away from a live
# primitive. What is required instead is that where the port routes sibling coordination or a
# supervised service, it names the surface that is actually there.
if grep -rqE 'no (programmatic )?`?hub`? tool' --include='*.md' --include='*.mjs' --include='*.ts' \
--include='*.sh' "${SCOPE[@]}" 2>/dev/null; then
# There is no `hub` tool. omp's own builtin tool list, packages/coding-agent/src/tools/builtin-names.ts
# inside the binary, carries `wait` and no `hub`; the binary's only other `hub` is the `/hub`
# slash command that opens Agent Hub, a human-facing TUI. The probe is in PORTING.md under
# "Sibling coordination". An earlier tree claimed a `hub` tool with list/send/inbox/wait/cancel/
# jobs/start/logs/stop ops, read off a stale pi-coding-agent 17.x package, and this assertion
# enforced that claim. A sentence that names `hub` as a tool sends an agent to a primitive that
# is not there; `wait`, `proc://`, `write agent://<id>`, and named `bash` services are.
hub_claim='`hub`|\bhub[` ]+(tool|tools|op|ops|operation|operations)\b'
bad=$(grep -rInE "$hub_claim" --include='*.md' --include='*.mjs' --include='*.ts' --include='*.sh' "${SCOPE[@]}" 2>/dev/null || true)
if [ -n "$bad" ]; then
report "agent hub api" "FAIL"
while read -r line; do violate "denies a live primitive: $line"; done <<<"$(grep -rnE 'no (programmatic )?`?hub`? tool' --include='*.md' --include='*.mjs' --include='*.ts' --include='*.sh' "${SCOPE[@]}" 2>/dev/null)"
elif grep -rqF 'hub' --include='*.md' "${SCOPE[@]}" 2>/dev/null; then
report "agent hub api" "PASS hub is documented as a real conditional built-in"
while read -r line; do violate "claims a hub tool omp does not ship: $line"; done <<<"$bad"
else
report "agent hub api" "SKIP no hub reference in the tree to check"
report "agent hub api" "PASS no hub tool claimed; coordination names wait, proc://, and agent://"
fi

# One install root. A path under any other agent store resolves to nothing on this machine,
Expand Down Expand Up @@ -238,12 +240,14 @@ runtime_contract() {
report "external capability provenance" "PASS the external veto is named and marked unshipped"
fi

bad=$(grep -rInE '`(Read|Grep|Glob|Shell|Task)` (tool calls|prompts|response body)|Tool calls \(Shell,|Use Glob to find|Use Read, Grep|Subagents inherit it' --include='*.md' "${SCOPE[@]}" 2>/dev/null || true)
# omp's tools are lowercase. A capitalised `Task` names Cursor's spawn tool, and in a reviewer
# template it makes the lens grep a transcript for a tool that was never called.
bad=$(grep -rInE '`(Read|Grep|Glob|Shell)` (tool calls|prompts|response body|of)|`Task`|\bTask (tool|subagent|spawn|call|schema)s?\b|[Tt]ool calls? \(Shell,|Use Glob to find|Use Read, Grep|Subagents inherit it' --include='*.md' "${SCOPE[@]}" 2>/dev/null || true)
if [ -n "$bad" ]; then
report "cursor tool names" "FAIL"
while read -r line; do violate "$line"; done <<<"$bad"
else
report "cursor tool names" "PASS no prompt template names a Cursor tool"
report "cursor tool names" "PASS no Cursor tool name, capitalised Task included"
fi

# Derived from the tree, not from a list: a hand-kept list of names is a list that forgets.
Expand Down Expand Up @@ -332,6 +336,31 @@ runtime_contract() {
}
runtime_contract

# Claims the published guide (Pt.1 and Pt.2) makes about pstack, verified as present. Tree-local,
# so it runs before the contracts-only exit and the fixture mutations can reach it. The playbook
# count the guide states is asserted by `playbook parity`, from the index, not restated here.
unclaimed=""
guide_skills=(create-verification-skill maintain-verification-skill swarm poteto-mode teach how why recall technical-writing unslop architect)
guide_files=(skills/poteto-mode/playbooks/prototype.md skills/poteto-mode/playbooks/multi-phase-plan.md skills/poteto-mode/scripts/check-plan.mjs)
for s in "${guide_skills[@]}"; do
[ -f "skills/$s/SKILL.md" ] || unclaimed="$unclaimed""guide names /$s, not installed"$'\n'
done
for f in "${guide_files[@]}"; do
[ -f "$f" ] || unclaimed="$unclaimed""guide names $f, not shipped"$'\n'
done
grep -qi 'features' skills/create-verification-skill/SKILL.md 2>/dev/null ||
unclaimed="$unclaimed""create-verification-skill must build the Feature Map (references/features)"$'\n'
# Upstream removed `mode: true` on purpose (b93e811) and omp never modelled it, so asserting that
# key only asserted a deleted line. The extension is what registers the command.
grep -q 'registerCommand("poteto-mode"' extensions/potetomode/index.js 2>/dev/null ||
unclaimed="$unclaimed""the potetomode extension must register /poteto-mode"$'\n'
if [ -n "$unclaimed" ]; then
report "guide claims" "FAIL"
while read -r c; do [ -n "$c" ] && violate "$c"; done <<<"$unclaimed"
else
report "guide claims" "PASS ${#guide_skills[@]} skills, prototype and multi-phase-plan playbooks, check-plan.mjs, Feature Map, pin"
fi

if [ "${CHECK_PORT_CONTRACTS_ONLY:-}" = 1 ]; then
echo
if [ "$fail" -eq 0 ]; then echo "check-port contracts: PASS"; else echo "check-port contracts: FAIL"; fi
Expand All @@ -347,14 +376,29 @@ if [ "${CHECK_PORT_SKIP_MUTATIONS:-}" = 1 ]; then
else
mutation_log=$(mktemp)
if bash "$PORT_DIR/test-gate-mutations.sh" >"$mutation_log" 2>&1; then
report "gate mutations" "PASS ownership, alias, effort, and per-file lever mutations rejected"
report "gate mutations" "PASS $(grep -c 'rejected$' "$mutation_log") fixture mutations rejected, each by its own check"
else
report "gate mutations" "FAIL"
while read -r line; do [ -n "$line" ] && violate "$line"; done <"$mutation_log"
fi
rm -f "$mutation_log"
fi

# The patched worktree-audit.sh is a script, so its behaviour needs a run, not a grep. Its test
# lives beside this gate and is cwd-independent.
if [ -f "$PORT_DIR/test-worktree-audit.sh" ]; then
audit_log=$(mktemp)
if bash "$PORT_DIR/test-worktree-audit.sh" >"$audit_log" 2>&1; then
report "worktree audit" "PASS omp-port/test-worktree-audit.sh"
else
report "worktree audit" "FAIL"
while read -r line; do [ -n "$line" ] && violate "$line"; done <"$audit_log"
fi
rm -f "$audit_log"
else
report "worktree audit" "SKIP omp-port/test-worktree-audit.sh not present"
fi

missing=""
while read -r p; do
[ -e "skills/poteto-mode/$p" ] || missing="$missing $p"
Expand Down Expand Up @@ -451,25 +495,6 @@ if [ -f "$ALLOW" ]; then
fi
fi

# Claims the published guide makes about pstack, verified as present.
unclaimed=""
for s in create-verification-skill maintain-verification-skill swarm poteto-mode; do
[ -f "skills/$s/SKILL.md" ] || unclaimed="$unclaimed""guide names /$s, not installed"$'\n'
done
grep -qi 'features' skills/create-verification-skill/SKILL.md ||
unclaimed="$unclaimed""create-verification-skill must build the Feature Map (references/features)"$'\n'
# Upstream removed `mode: true` on purpose (b93e811) and omp never modelled it, so asserting that
# key only asserted a deleted line. The extension is what registers the command.
grep -q 'registerCommand("poteto-mode"' extensions/potetomode/index.js ||
unclaimed="$unclaimed""the potetomode extension must register /poteto-mode"$'\n'
if [ -n "$unclaimed" ]; then
report "guide claims" "FAIL"
while read -r c; do [ -n "$c" ] && violate "$c"; done <<<"$unclaimed"
else
report "guide claims" "PASS verification skill, Feature Map, swarm, pin"
fi


bad=""
for d in skills/*/; do
n=$(basename "$d")
Expand Down
Loading
Loading