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
24 changes: 12 additions & 12 deletions .github/workflows/upstream-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,26 +96,26 @@ jobs:
skill's `agents/openai.yaml` (policy: allow_implicit_invocation:
false) and keep its implicit_allowed false in
tools/skill-trigger-cases.json. When upstream removes it, delete
that file, add the skill to AUTO_INVOCABLE in
tools/test_skill_invocation_policy.py, and set its
implicit_allowed to true. Write every incoming load of another
skill as "Use the **x** skill" with the bare name, per the
PORTING.md row for sibling-skill loads, never as `/x` or `$x`.
A passage that quotes what the user types goes in USER_FACING in
tools/test_skill_references.py. When a skill directory is added,
renamed, or removed, update each list that names skills:
that file and set its implicit_allowed to true. Write every
incoming load of another skill as "Use the **x** skill" with the
bare name, per the PORTING.md row for sibling-skill loads, never
as `/x` or `$x`. A passage that quotes what the user types goes
in USER_FACING in tools/skill-references.py. When a skill
directory is added, renamed, or removed, update each list that
names skills:
- PSTACK_SKILLS in skills/setup-pstack/scripts/skill-listing.py.
- The skill's row in tools/skill-trigger-cases.json.
- A row in README.md's "all skills" table, which
evals/promises/test_static.py checks against the skill
directories.
- In evals/promises/test_static.py, PLAYBOOK_FILES for a
poteto-mode playbook, PRINCIPLE_RULES for a principle-*
skill, and GUIDE_SLASH_SKILLS when docs/guide names the
skill as /x. A playbook added or removed also changes the
two `25` counts in test_twenty_five_playbooks, the
twenty-five-playbooks promise in evals/promises/ledger.json,
twenty-five-playbooks promise in evals/promises/ledger.json
and the "twenty-five" in README.md and
docs/guide/02-poteto-mode.md.
- For a skill with no agents/openai.yaml gate, AUTO_INVOCABLE
in tools/test_skill_invocation_policy.py and the "A skill
- For a skill with no agents/openai.yaml gate, the "A skill
didn't load on its own" row in skills/poteto-help/SKILL.md.
4. Every SKILL.md frontmatter `name:` must equal its directory
name. Verify after editing.
Expand Down
10 changes: 6 additions & 4 deletions PORTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ Upstream is the source of truth for the workflows themselves. This file records
| Cursor `/loop` | Claude Code `/loop`; in a CLI without one, re-prompt on an interval or run a watcher subagent |
| Cursor automations / `api2.cursor.sh` webhooks (benny) | any scheduled agent runner (Claude Code scheduled agents, cron-driven CI job) exposing a webhook or schedule; paths move from `.cursor/automations/` to `.agents/automations/` |
| `.cursor-plugin/plugin.json`, and the root Agent Plugins `plugin.json` that upstream #576 added | removed; `npx skills` discovers `skills/*/SKILL.md` directly |
| `disable-model-invocation: true` in the frontmatter of a skill under `skills/` | dropped. The skill keeps or gains `agents/openai.yaml` with `policy.allow_implicit_invocation: false`, which gates it on Codex and puts it in setup-pstack's Claude Code name-only listing. Keep its `implicit_allowed` false in `tools/skill-trigger-cases.json`. When upstream removes the flag, delete the policy file, add the skill to `AUTO_INVOCABLE` in `tools/test_skill_invocation_policy.py`, and set its `implicit_allowed` to true, unless a port divergence keeps it gated |
| A sibling-skill load written as "run the **x** skill", "per the **x** skill", "via the **x** skill", a backticked `x`, `/x`, or `$x` | "Use the **x** skill" as its own sentence or step, with the bare skill name. The **pstack-harness** skill defines using a skill on each CLI. A playbook step keeps its opening sentence, and the load follows as the next sentence, because recorded worklists and the canon chain tests match a step by its first five words. The exception is a step whose opening clause carries the load, as in Autonomous run step 5, Hillclimb step 3, and Investigation step 4, whose first words changed. Feature also keeps every skill name as spelled, because the canon chain tests count its pointers. Elsewhere a principle pointer may now spell the full `principle-` name, as in Autonomous run step 3, Perf issue step 3, and Refactoring step 8. figure-it-out's Start keeps "read the Principles section of the **poteto-mode** skill", because "Use the **poteto-mode** skill." there sent Codex leads back to pick an Autonomous run worklist. Principle citations after a rule the sentence already states, ownership statements, descriptions, and Bug fix step 2's measured how and why spawn keep upstream's wording. The owner lifecycle lists in Autopilot-full step 2 and Autopilot-stack step 1, and the **swarm** attribution in Multi-phase plan's verification block, are such statements. `tools/test_skill_references.py` fails on a `/x` or `$x` spelling of a pstack skill under `skills/` outside its `USER_FACING` passages, which quote what the user types or text shown to the user, outside its `MODE_REMINDERS` passage, poteto-mode's `reminder:` line, which reaches the model but names the mode already on, and outside poteto-help, whose `USER_FACING_SKILLS` entry exempts the whole skill because it answers users. The evidence is in `docs/skill-cross-reference-phrasing.md` and `evals/promises/results/2026-10-10-use-the-skill.md` |
| `disable-model-invocation: true` in the frontmatter of a skill under `skills/` | dropped. The skill keeps or gains `agents/openai.yaml` with `policy.allow_implicit_invocation: false`, which gates it on Codex and puts it in setup-pstack's Claude Code name-only listing. Keep its `implicit_allowed` false in `tools/skill-trigger-cases.json`. When upstream removes the flag, delete the policy file and set its `implicit_allowed` to true, unless a port divergence keeps it gated |
| A sibling-skill load written as "run the **x** skill", "per the **x** skill", "via the **x** skill", a backticked `x`, `/x`, or `$x` | "Use the **x** skill" as its own sentence or step, with the bare skill name. The **pstack-harness** skill defines using a skill on each CLI. A playbook step keeps its opening sentence, and the load follows as the next sentence, because recorded worklists and the canon chain tests match a step by its first five words. The exception is a step whose opening clause carries the load, as in Autonomous run step 5, Hillclimb step 3, and Investigation step 4, whose first words changed. Feature also keeps every skill name as spelled, because the canon chain tests count its pointers. Elsewhere a principle pointer may now spell the full `principle-` name, as in Autonomous run step 3, Perf issue step 3, and Refactoring step 8. figure-it-out's Start keeps "read the Principles section of the **poteto-mode** skill", because "Use the **poteto-mode** skill." there sent Codex leads back to pick an Autonomous run worklist. Principle citations after a rule the sentence already states, ownership statements, attributions, descriptions, and Bug fix step 2's measured how and why spawn keep upstream's wording. The owner lifecycle lists in Autopilot-full step 2 and Autopilot-stack step 1 are ownership statements, and the **swarm** attribution in Multi-phase plan's verification block is an attribution. `tools/test_skill_references.py` runs `violations()` and `stale_exemptions()` from `tools/skill-references.py`. `violations()` fails on a `/x` or `$x` spelling of a pstack skill under `skills/` outside four exemptions. A skill's own `/x` inside its frontmatter `description:` value, folded continuation lines included, is exempt. The `USER_FACING` passages quote what the user types or text shown to the user. The `MODE_REMINDERS` passage is poteto-mode's `reminder:` line, which reaches the model but names the mode already on. poteto-help's `USER_FACING_SKILLS` entry exempts the whole skill because it answers users. A passage that no longer matches a spelling fails `stale_exemptions()`. The evidence is in `docs/skill-cross-reference-phrasing.md` and `evals/promises/results/2026-10-10-use-the-skill.md` |
| Origin forge CLI (`origin pr ...`, upstream's optional alternative to `gh` for PR create/view/merge) | kept verbatim. Every use is gated on `command -v origin` succeeding, with `gh` as the stated default, so the text is a no-op on hosts without Origin. Graphite (`gt`) remains optional only for Orchestrate frontier discovery. `orch frontier set` uses `gh` for a same-repository linear stack and runs `gt` only with `--graphite`. Never restore a hard Graphite requirement during sync. |
| Cursor `Task` semantics (`subagent_type`, `model`, `readonly`, `environment: "cloud"`) assumed everywhere | a new **pstack-harness** skill (`skills/pstack-harness/`) maps spawning, per-subagent models, parallelism, read-only posture, structured questions, loops, and transcript access to Claude Code (`Task` tool), Codex (`spawn_agent`, with `codex exec` subprocesses as the fallback), Hermes (delegation toolset, `hermes -z` subprocesses, `hermes sessions export`), and Grok Build (`spawn_subagent`, `grok -p` subprocesses, per-session directories); fan-out skills point to it |
| "Open a todolist ..." and "add the phases below as todos" (architect, arena, figure-it-out, swarm, and poteto-mode's "task-specific todos"), "into the todo list" (poteto-help), and "Add its steps to the todolist" (figure-it-out) | "Open a worklist ...", "items", "into the worklist", and "Add its steps to the worklist". The **pstack-harness** skill's worklist adapter defines ordered items and their states, not a tool name |
| arena Phase C: "Prefer a different model family from the parent's." | "Prefer a different model family or capability tier from the parent's." The default pool is `fable`, `opus`, and `sonnet`, which are one family, so a different tier is often the only difference available |

## Port additions beyond substitution

Expand All @@ -47,8 +49,8 @@ Upstream is the source of truth for the workflows themselves. This file records

So step 0d treats a live session as the answer and config as signals. It offers an edit only when a session confirms `spawn_agent` is missing, and only for a possible cause a config file shows. On sync, keep step 0d of setup-pstack and the setup guide's sentences.
- The **pstack-harness** skill owns the three-root runtime contract. `PSTACK_SKILLS_ROOT` comes from the logical path of the loaded harness skill and works without Git or network access. `PSTACK_SOURCE_ROOT` accepts only the configured HTTPS or SSH identity for `mdsmithaustin/pstack`. Physical symlink ancestry is only a source candidate. A copied install creates a private shallow clone when a fresh trunk read needs one, and the program removes only a generated directory with its ownership marker. `PROJECT_ROOT` stays separate for consumer control skills. A source resolution, identity, clone, fetch, or object failure stops the trunk read. Installed files are never its fallback. The skill-ci content check, through the retired text in `tools/skill-content-conventions.json`, rejects both runtime substitutions from upstream in every raw skill Markdown line, including fenced templates. Keep this contract and lint during future syncs.
- Every skill that must not load from its description ships `agents/openai.yaml` with `policy.allow_implicit_invocation: false`. Codex honors it as installed. On Claude Code, setup-pstack step 0c runs `skills/setup-pstack/scripts/skill-listing.py`, which derives the `skillOverrides` name-only set from the same files. No skill under `skills/` sets `disable-model-invocation`, because Claude Code's Skill tool refuses such a skill when a pstack skill names it. `tools/test_skill_invocation_policy.py` enforces three rules. It fails on the flag, on any skill without the policy file that its `AUTO_INVOCABLE` set does not name, and when `PSTACK_SKILLS` in `skill-listing.py` differs from the `skills/` directories. Adding, renaming, or removing a skill directory updates `PSTACK_SKILLS`, and `AUTO_INVOCABLE` too when the skill has no policy file. `tests/skills/setup-pstack/scripts/test_skill_listing.py` derives the gated inventory from the same files and checks selected gated and ungated names as literal anchors. On sync, keep setup-pstack step 0c and `skill-listing.py`.
- Deliberate divergence from upstream #300: **how**, **why**, and **unslop** stay auto-invocable in this port (no `agents/openai.yaml`, named in `AUTO_INVOCABLE`), because they own high-value automatic triggers in the maintainer's roster ("how does X work", motivation questions, prose cleanup). The port-owned **deslop** skill is auto-invocable for the same reason: the guide tells readers to say `deslop it`, and a gated skill never fires on that phrase. Do not reapply upstream's gating to these four on future syncs; `typescript-best-practices` and `make-bot-ui` keep it. Guide page 5 says `typescript-best-practices` "doesn't load from its description" once `/setup-pstack` sets the Claude Code skill listing, where upstream says it doesn't load on its own. The Hermes and Grok Build caveat lives on guide page 1 and records that they loaded it anyway in `evals/promises/results/2026-10-03.md`.
- Every skill that must not load from its description ships `agents/openai.yaml` with `policy.allow_implicit_invocation: false`. Codex honors it as installed. On Claude Code, setup-pstack step 0c runs `skills/setup-pstack/scripts/skill-listing.py`, which derives the `skillOverrides` name-only set from the same files. No skill under `skills/` sets `disable-model-invocation`, because Claude Code's Skill tool refuses such a skill when a pstack skill names it. `tools/test_skill_invocation_policy.py` enforces two rules. It fails on the flag and when `PSTACK_SKILLS` in `skill-listing.py` differs from the `skills/` directories. `skill-ci check` fails when a skill's `implicit_allowed` row in `tools/skill-trigger-cases.json` disagrees with its policy file. Adding, renaming, or removing a skill directory updates `PSTACK_SKILLS` and the skill's trigger row. `tests/skills/setup-pstack/scripts/test_skill_listing.py` derives the gated inventory from the same files and checks selected gated and ungated names as literal anchors. On sync, keep setup-pstack step 0c and `skill-listing.py`.
- Deliberate divergence from upstream #300: **how**, **why**, and **unslop** stay auto-invocable in this port (no `agents/openai.yaml`, `implicit_allowed: true` in `tools/skill-trigger-cases.json`), because they own high-value automatic triggers in the maintainer's roster ("how does X work", motivation questions, prose cleanup). The port-owned **deslop** skill is auto-invocable for the same reason: the guide tells readers to say `deslop it`, and a gated skill never fires on that phrase. Do not reapply upstream's gating to these four on future syncs; `typescript-best-practices` and `make-bot-ui` keep it. Guide page 5 says `typescript-best-practices` "doesn't load from its description" once `/setup-pstack` sets the Claude Code skill listing, where upstream says it doesn't load on its own. The Hermes and Grok Build caveat lives on guide page 1 and records that they loaded it anyway in `evals/promises/results/2026-10-03.md`.
- **poteto-help** (upstream #502, #506, #507, #509) ports with the substitution map applied: install through `npx skills`, the models config at `~/.agents/pstack-models.md`, `/poteto-teach` and `/poteto-tdd`, `/deslop` as a pstack skill, and no cloud agents. Upstream #506 made it typed-only, so it carries `agents/openai.yaml` in place of upstream's `disable-model-invocation`, and its row in `tools/skill-trigger-cases.json` sets `implicit_allowed: false`. `npx skills` ships only skill directories, so its README and guide links point at this repository's public copy instead of `../../`. Its skill table adds rows for the port-owned skills. Its list of skills that load from the user's words names every ungated skill a user types, and `test_poteto_help_lists_every_ungated_skill` in `evals/promises/test_static.py` fails when the gating and the list disagree. That list names Claude Code and Codex, and the README row and guide index say the skill "doesn't load from its description" once `/setup-pstack` sets the Claude Code skill listing, as guide page 5 says of `typescript-best-practices`. The Hermes and Grok Build caveat lives on guide page 1 and records that they loaded a gated skill in `evals/promises/results/2026-10-03.md`. The paragraph on harnesses replaces upstream's "built for Cursor" paragraph and restates rules 3 and 4 of setup-pstack's models config reference, so a change to either rule must update it. The "review this pr" phrase under Playbooks is a port addition for the Code review playbook. Deliberate divergence: #502 replaced "`/poteto-mode` is sticky" in the README, guide pages 1 and 2, and the skill with Cursor's Custom Mode instructions (Option+Enter, the Agents Window). The port's harnesses have no Custom Modes and keep an invoked skill in the conversation, so the port keeps the sticky wording, which the `poteto-mode-sticky` live case passed on Claude Code, Codex, and Hermes in `evals/promises/results/2026-10-03.md`. On sync, do not reapply the Custom Mode wording.
- Four sites carry a conditional GitNexus nudge, active only when `.gitnexus/` exists in the repo and the `gitnexus` CLI is on `PATH`: the **how** skill (SKILL.md and `references/explorer-prompt.md`) seeds exploration with `gitnexus query`/`context`/`trace`; **blast-radius** seeds the change map with `gitnexus detect-changes`/`impact`; the **refactoring** playbook enumerates callers with `gitnexus impact`/`context` before a migration wave; and the Code review playbook's review lens lists a shared symbol's callers with `gitnexus impact`. Freshness-first policy: an existing index is refreshed with `gitnexus analyze --index-only` (incremental, no-op when up to date) before the graph is consulted — by the lead only, never from parallel arms (concurrent analyzes can corrupt the KuzuDB store). Creating a first index stays suggest-only. The code itself remains the source of truth: the index reflects the last analyzed commit and never sees uncommitted edits. No-op on hosts and repos without GitNexus.
- The GitHub watcher treats a PR whose head has no checks as having no CI (port addition, 2026-09). An empty GraphQL rollup proves it, so the watcher reads `ci-clean` instead of throwing `ChecksUnavailable`. It still throws that retryable error when an earlier commit on the PR had checks, because the head's checks may not be registered yet. So a later push that never gets checks in a repo with CI, such as a path-filtered or `[skip ci]` commit, still ends at the error cap. Upstream throws whenever both check sources are empty. Keep this on sync.
Expand Down
Loading
Loading