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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ node_modules/
*~

.migration-backup/

__pycache__/
*.pyc
48 changes: 28 additions & 20 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,43 @@
## Layout and sources of truth

- Installable skills live under `skills/<name>/SKILL.md` and follow the Agent Skills layout used by skills.sh.
- Shared runtime contracts live under `skills/pstack/references/{capability-contract.md,adapters/,agents/}`.
- `skills/poteto-mode/playbooks/` is the canonical playbook directory. Mirror it to `skills/pstack/playbooks/` after edits.
- `skills/pstack/references/adapters/` is the canonical adapter directory. Mirror it to `skills/poteto-mode/references/adapters/` after edits.
- `skills/pstack/references/capability-contract.md` is canonical. Keep the copy under `skills/poteto-mode/references/` byte-identical.
- Agent rubrics and `principles-summary.md` exist only under `skills/pstack/references/`; they are not mirrored into `poteto-mode`.
- Shared runtime contracts live under `skills/pstack/references/{capability-contract.md,adapters/,agents/,host-lifecycle.md,model-override.schema.json}`.
- `skills/poteto-mode/playbooks/` is the canonical playbook directory.
- `skills/pstack/references/adapters/` is the canonical adapter directory.
- `skills/pstack/references/capability-contract.md` is canonical.
- Agent rubrics, `principles-summary.md`, `host-lifecycle.md`, and the model-override schema exist only under `skills/pstack/references/`.

Do not edit both sides of a mirror independently. The portable audit rejects drift.

## Re-port helpers

After pulling newer upstream Cursor pstack sources:
## Import and mirrors

```bash
# Copy upstream skills, then run the mechanical passes.
python3 scripts/port_to_portable.py
python3 scripts/port_pass2.py

# Refresh mirrors from their canonical directories.
rsync -a --delete skills/poteto-mode/playbooks/ skills/pstack/playbooks/
rsync -a --delete skills/pstack/references/adapters/ skills/poteto-mode/references/adapters/
cp skills/pstack/references/capability-contract.md \
skills/poteto-mode/references/capability-contract.md
# Preferred: import an upstream checkout, run both passes, refresh mirrors.
python3 scripts/import_upstream.py --upstream-root /path/to/cursor/plugins/pstack \
--upstream-commit <sha>

# Or refresh mirrors only after local playbook/adapter edits.
python3 scripts/sync_mirrors.py

# Mechanical first pass only (targeted phrases; no bare-word Task replace).
python3 scripts/port_to_portable.py --report /tmp/port-report.json
python3 scripts/port_to_portable.py --check-idempotent
```

Adapters, `setup-pstack`, and portable entry skills are hand-maintained. Do not blindly overwrite them from upstream.
Hand-maintained entry skills and adapters are listed in `UPSTREAM_MANIFEST.json`. Do not overwrite them from upstream.

After import, complete `scripts/fixtures/semantic/REVIEW_CHECKLIST.md` before merging.

## Required audit

Run this before every pull request:

```bash
python3 -m compileall -q scripts
python3 scripts/sync_mirrors.py
python3 scripts/audit_portability.py
python3 scripts/audit_portability.py --strict --changed-from origin/main
python3 scripts/validate_model_override.py scripts/fixtures/model-override/valid.json
```

The baseline audit checks:
Expand All @@ -52,9 +55,10 @@ The baseline audit checks:
- the complete playbook and adapter inventories;
- byte-identical playbook, adapter, and capability-contract mirrors;
- Cursor-only frontmatter keys;
- portability smells such as concrete Cursor model slugs, `subagent_type`, `AskQuestion`, Cursor transcript paths, and ambiguous mechanical-rewrite wording.
- portability smells (vendor fields, Cursor paths/control surfaces, thin mechanical blocks, rewrite artifacts);
- regression fixtures under `scripts/fixtures/portability/` for every portability pattern.

The non-strict repository-wide scan reports existing portability debt as warnings. The strict changed-file scan prevents a pull request from adding or preserving those patterns in files it touches.
Repository-wide non-strict audit should stay at `0 error(s), 0 warning(s)` unless a finding is intentionally introduced and tracked. The strict changed-file scan rejects regressions in files a PR touches.

## Semantic review after mechanical porting

Expand All @@ -69,6 +73,10 @@ Regex passes are only the first step. Review every changed skill for meaning:

A mechanically valid sentence can still be semantically wrong. Phrases such as “`explore` / `implement` helper” are a sign that the port has not chosen the actual capability.

## Host conformance

Live host results belong in `scripts/fixtures/conformance/HOST_MATRIX.md`. CI does not run remote agents; fill the matrix after smoke tests on each supported host.

## skills.sh

- The `description` frontmatter field is the trigger surface and must stay quoted for reliable parsing.
Expand Down
21 changes: 15 additions & 6 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

Use this portable pack on every Agent Skills–compatible coding agent **except** Cursor (keep Cursor’s official pstack plugin there).

## Recommended: skills.sh global install
## Recommended: GitHub global install

```bash
npx skills add https://skills.sh/p/3EVEFJjSrRBr1mI4 -g -s '*' -y
npx skills add Go7hic/pstack -g -s '*' -y
```

Add `-a` for specific agents if you do not want every discovered agent:

```bash
npx skills add https://skills.sh/p/3EVEFJjSrRBr1mI4 -g \
npx skills add Go7hic/pstack -g \
-a claude-code -a codex -a opencode -a factory-droid \
-s '*' -y
```
Expand All @@ -28,12 +28,21 @@ npx skills add https://skills.sh/p/3EVEFJjSrRBr1mI4 -g \

After install, restart or reload the agent so it rescans skills.

## Optional: skills.sh pack URL

If you already have a published skills.sh pack for this repo, you can install from that URL instead. Prefer the GitHub install above when the pack page is stale or the URL does not resolve to a valid skill archive.

```bash
# Replace with your current pack URL only after confirming it installs cleanly.
npx skills add https://skills.sh/p/<pack-id> -g -s '*' -y
```

## Optional: wire more agents from the install tree

If the CLI already installed into one global tree and you need another agent that was not selected, symlink from that install location (not from this git checkout):

```bash
# After skills.sh -g, the shared tree is usually:
# After a global install, the shared tree is usually:
SRC=~/.agents/skills
# If your install only landed under one agent, point SRC there instead, e.g.:
# SRC=~/.claude/skills
Expand All @@ -55,7 +64,7 @@ Do **not** use `~/workspace/pstack/skills` as `SRC` unless you are developing th

### Codex cutover checklist

1. Prefer `npx skills add -g -a codex` (or symlink from `SRC` above).
1. Prefer `npx skills add Go7hic/pstack -g -a codex` (or symlink from `SRC` above).
2. Delete the old pack if present: `rm -rf ~/.codex/skills/codex-pstack`
3. Point model overrides at `~/.codex/rules/pstack-models.md` (see `adapters/codex-models.md`).
4. Smoke-test: `/pstack` or `/how` and confirm the agent reads `adapters/codex.md` and spawns via `multi_agent_v1` (or current Codex multi-agent tools).
Expand Down Expand Up @@ -90,4 +99,4 @@ Local checkout only when editing the pack:
SRC=~/workspace/pstack/skills # or your clone path
```

Day-to-day use should go through the skills.sh install path above.
Day-to-day use should go through the GitHub install path above.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ It preserves the same engineering system—principles, playbooks, `how`, `why`,
Use this portable pack on Agent Skills-compatible coding agents other than Cursor. Cursor users should keep the official pstack plugin.

```bash
npx skills add https://skills.sh/p/3EVEFJjSrRBr1mI4 -g -s '*' -y
npx skills add Go7hic/pstack -g -s '*' -y
```

See [INSTALL.md](./INSTALL.md) for per-agent selection, model override paths, migration notes, and smoke tests. After global installation, skills usually land under an agent-specific directory such as `~/.claude/skills/`, `~/.codex/skills/`, or the shared `~/.agents/skills/` tree.
See [INSTALL.md](./INSTALL.md) for per-agent selection, optional skills.sh install, model override paths, migration notes, and smoke tests. After global installation, skills usually land under an agent-specific directory such as `~/.claude/skills/`, `~/.codex/skills/`, or the shared `~/.agents/skills/` tree.

## What is included

Expand Down Expand Up @@ -49,11 +49,12 @@ The repository contains a structural and portability audit:
```bash
python3 scripts/audit_portability.py
python3 scripts/audit_portability.py --strict --changed-from origin/main
python3 scripts/sync_mirrors.py
```

GitHub Actions runs the structural audit on `main` and on pull requests. It also rejects new vendor leakage in changed files, including concrete Cursor model slugs, Cursor-only tool fields, transcript paths, and drift between mirrored playbooks or adapters.
GitHub Actions runs the structural audit on `main` and on pull requests. It also rejects new vendor leakage in changed files, including concrete Cursor model slugs, Cursor-only tool fields, transcript paths, thin mechanical portability blocks, rewrite artifacts, and drift between mirrored playbooks or adapters.

See [CONTRIBUTING.md](./CONTRIBUTING.md) before syncing a newer upstream revision. Mechanical regex porting is followed by a semantic review; capability verbs must describe the actual job rather than merely replacing vendor vocabulary.
See [CONTRIBUTING.md](./CONTRIBUTING.md) and [UPSTREAM_MANIFEST.json](./UPSTREAM_MANIFEST.json) before syncing a newer upstream revision. Mechanical regex porting is followed by a semantic review; capability verbs must describe the actual job rather than merely replacing vendor vocabulary.

## Not bundled

Expand Down
29 changes: 29 additions & 0 deletions UPSTREAM_MANIFEST.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"schema_version": 1,
"upstream": {
"repository": "https://github.com/cursor/plugins",
"path": "pstack",
"commit": "UNPINNED",
"synced_at": null,
"notes": "Pin commit SHA on each upstream import. Do not auto-merge sync PRs."
},
"portable": {
"patch_version": "0.2.0",
"capability_contract_version": "1.0.0",
"hand_maintained_skills": [
"pstack",
"poteto-mode",
"how",
"why",
"architect",
"arena",
"swarm",
"interrogate",
"reflect",
"recall",
"automate-me",
"show-me-your-work",
"setup-pstack"
]
}
}
6 changes: 3 additions & 3 deletions docs/guide/01-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The official plugin has native mode metadata and Cursor-specific integrations th
Install the portable pack globally:

```bash
npx skills add https://skills.sh/p/3EVEFJjSrRBr1mI4 -g -s '*' -y
npx skills add Go7hic/pstack -g -s '*' -y
```

To install only for selected agents, add one or more `-a` flags as described in [INSTALL.md](../../INSTALL.md). Restart or reload the coding agent after installation so it rescans its skill directories.
Expand Down Expand Up @@ -80,10 +80,10 @@ On a broad subsystem, confirm the adapter fans out several read-only explorers.

## Understand mode lifetime

Cursor's official plugin can provide native sticky-mode behavior. Other coding agents vary:
See `skills/pstack/references/host-lifecycle.md` for the host-by-host matrix.

- When the host preserves skill state, `/poteto-mode` can remain active across turns in the current conversation.
- When the host does not provide persistent mode state, invoke `/pstack` or `/poteto-mode` again after a new session, context reset, or compaction.
- The playbooks and engineering principles remain the same; only the lifecycle mechanism changes.
- Never claim sticky mode on a host that cannot enforce it.

Next: [Route work through `/poteto-mode`](./02-poteto-mode.md).
105 changes: 104 additions & 1 deletion scripts/audit_portability.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

ROOT = Path(__file__).resolve().parents[1]
SKILLS = ROOT / "skills"
FIXTURES = ROOT / "scripts" / "fixtures" / "portability"

PLAYBOOKS = {
"investigation.md",
Expand Down Expand Up @@ -71,9 +72,27 @@
("Cursor-only background flag", re.compile(r"\brun_in_background\s*:")),
("runtime-specific readonly flag", re.compile(r"\breadonly\s*:")),
("Cursor AskQuestion API", re.compile(r"\bAskQuestion\b")),
("Cursor project-history path", re.compile(r"~/\.cursor/projects/")),
(
"Cursor filesystem path assumption",
re.compile(r"~/\.cursor/(?:projects|skills|plugins)/"),
),
("Cursor built-in workflow", re.compile(r"Cursor(?:'s)? built-in", re.I)),
("cursor-team-kit dependency", re.compile(r"cursor-team-kit", re.I)),
(
"Cursor control-surface dependency",
re.compile(r"\bcontrol-(?:cli|ui)\b", re.I),
),
(
"Cursor transcript directory assumption",
re.compile(r"\bagent-transcripts\b"),
),
(
"Cursor cloud/dashboard workflow",
re.compile(
r"\bCursor cloud(?: agent)?\b|\bCursor dashboard\b|\bCursor restart\b",
re.I,
),
),
(
"ambiguous generated helper wording",
re.compile(r"adapter\s+`?explore`?\s*/\s*`?implement`?\s+helpers?", re.I),
Expand All @@ -82,6 +101,26 @@
"ambiguous generated model role",
re.compile(r"model_role:fast_explore\s*/\s*feature_impl", re.I),
),
(
"thin mechanical portability block",
re.compile(r"Translate upstream Cursor mechanics through the adapter"),
),
(
"doubled loop rewrite artifact",
re.compile(r"long-runlong-run"),
),
(
"doubled matching-surface rewrite artifact",
re.compile(r"matching surface on the matching"),
),
(
"Cursor app support path",
re.compile(r"Application Support/Cursor"),
),
(
"Cursor restart trigger wording",
re.compile(r"restart Cursor", re.I),
),
)

SCAN_EXCLUDES = (
Expand Down Expand Up @@ -216,6 +255,68 @@ def check_skills(findings: list[Finding]) -> None:
findings.append(Finding("WARN", rel, "missing the standard portability block"))


def match_labels(text: str) -> set[str]:
labels: set[str] = set()
for label, pattern in PORTABILITY_PATTERNS:
if pattern.search(text):
labels.add(label)
return labels


def check_fixtures(findings: list[Finding]) -> None:
bad_dir = FIXTURES / "bad"
good_dir = FIXTURES / "good"
if not bad_dir.is_dir() or not good_dir.is_dir():
findings.append(
Finding("ERROR", relative(FIXTURES), "bad/ and good/ fixture directories required")
)
return

bad_files = sorted(path for path in bad_dir.glob("*.md") if path.is_file())
if not bad_files:
findings.append(Finding("ERROR", relative(bad_dir), "expected at least one bad fixture"))

covered_labels: set[str] = set()
for path in bad_files:
labels = match_labels(read_text(path))
if not labels:
findings.append(
Finding(
"ERROR",
relative(path),
"bad fixture matched no portability pattern",
)
)
continue
covered_labels.update(labels)

expected_labels = {label for label, _ in PORTABILITY_PATTERNS}
for label in sorted(expected_labels - covered_labels):
findings.append(
Finding(
"ERROR",
relative(bad_dir),
f"no bad fixture covers pattern {label!r}",
)
)

good_files = sorted(path for path in good_dir.glob("*.md") if path.is_file())
if not good_files:
findings.append(
Finding("ERROR", relative(good_dir), "expected at least one good fixture")
)
for path in good_files:
labels = match_labels(read_text(path))
if labels:
findings.append(
Finding(
"ERROR",
relative(path),
"good fixture matched: " + ", ".join(sorted(labels)),
)
)


def changed_paths(base_ref: str) -> set[str]:
completed = subprocess.run(
["git", "diff", "--name-only", f"{base_ref}...HEAD"],
Expand Down Expand Up @@ -291,6 +392,8 @@ def run(strict: bool, changed_from: str | None) -> list[Finding]:
Finding("ERROR", "capability-contract.md", "shared reference mirror has drifted")
)

check_fixtures(findings)

selected = changed_paths(changed_from) if changed_from else None
scan_portability(findings, selected=selected, strict=strict)
return findings
Expand Down
17 changes: 17 additions & 0 deletions scripts/fixtures/conformance/HOST_MATRIX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Host conformance matrix

These are smoke expectations for portable pstack. Mark results only after a live host run. In-repo CI does not execute remote agents.

| Case | Claude Code | Codex | OpenCode | Droid | Generic + spawn | Generic no spawn |
| --- | --- | --- | --- | --- | --- | --- |
| `/how` simple: no unnecessary fan-out | | | | | | |
| `/how` complex: 2–4 explorers | | | | | | |
| `/arena`: isolated candidates, cross-judge, graft, verify | | | | | | |
| `/interrogate`: independent reviewers + lead judgment | | | | | | |
| Feature: disjoint worker scope + lead diff review | | | | | | |
| Bug fix: reproduce, root cause, fix, same-surface verify | | | | | | |
| Denied model selection degrades to parent model | | | | | | |
| Denied spawn collapses to lead and is stated | | | | | | |
| No invented tool params from another host | | | | | | |

Fill cells with `pass`, `pass-degraded:<note>`, or `fail:<note>`.
Loading
Loading