Skip to content

fix: avoid inline-shell false trigger in TS patterns - #111

Closed
iap wants to merge 0 commit into
masterfrom
fix/ts-pattern-inline-shell-v2
Closed

iap wants to merge 0 commit into
masterfrom
fix/ts-pattern-inline-shell-v2

Conversation

@iap

@iap iap commented Oct 31, 2026

Copy link
Copy Markdown
Owner

Fixes issue #107 - replace problematic ! pattern with non-null assertions.

@github-actions github-actions Bot added documentation Documentation tooling Converter, validator, CI tooling skills Workflow/mode skill changes pstack-core Core manifest/config changes principles Principle skill changes labels Oct 31, 2026
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Move pstack to a root-level Hermes plugin and fix a TS scan trigger

✨ Enhancement 🐞 Bug fix 📝 Documentation ⚙️ Configuration changes 🧪 Tests 🕐 40+ Minutes


AI Description

• Move the Hermes plugin from pstack/ to the repository root and remove Cursor dual-load files.
• Retarget conversion, validation, CI, publishing, and installation instructions to the new layout.
• Reword a TypeScript example to avoid an inline-shell false trigger.
Diagram

graph TD
  U["Pinned upstream"] --> C["Converter"] --> P["Root plugin"] --> V["Validator"] --> CI["CI checks"] --> D["Dist and releases"]
  P --> S["Skills and config"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep generated output in a separate dist root
  • ➕ Preserves the boundary between source tooling and installable files.
  • ➕ Allows package-tree replacement without modifying repository tooling.
  • ➖ Retains two layouts and separate publishing paths.
  • ➖ Does not enable direct root installation from the development repository.

Recommendation: The root package simplifies installation, but its build contract needs reconciliation. In the checked-out code, convert.py still writes plugin.json while the committed package and validator use plugin.yaml; root-scoped CI hashing and artifact upload also need a defined package-file boundary. Resolve those integration points if proceeding with the root layout.

Files changed (150) +442 / -357

Enhancement (2) +61 / -66
convert.pyBuild package files into the repository root +42/-50

Build package files into the repository root

• Defaults output to root, stops copying Cursor agents and manifest, revises generated install text, and copies built files into place for root output.

tools/convert.py

validate.pyValidate root YAML package layout +19/-16

Validate root YAML package layout

• Defaults to repository root, parses 'plugin.yaml', and rejects the former agents and Cursor-manifest directories.

tools/validate.py

Bug fix (1) +1 / -1
patterns.mdAvoid literal exclamation-mark scan trigger +1/-1

Avoid literal exclamation-mark scan trigger

• Replaces a standalone '!' example in explanatory prose with “non-null assertions” to avoid an inline-shell false trigger.

skills/typescript-best-practices/references/patterns.md

Refactor (113) +0 / -0
SKILL.mdRelocate architect skill +0/-0

Relocate architect skill

• Moves the architect skill into root-level 'skills/'.

skills/architect/SKILL.md

design-red-flags.mdRelocate design red flags +0/-0

Relocate design red flags

• Moves an architect reference under root-level 'skills/'.

skills/architect/references/design-red-flags.md

rationale-template.mdRelocate rationale template +0/-0

Relocate rationale template

• Moves an architect reference under root-level 'skills/'.

skills/architect/references/rationale-template.md

runner-prompt.mdRelocate runner prompt +0/-0

Relocate runner prompt

• Moves an architect reference under root-level 'skills/'.

skills/architect/references/runner-prompt.md

SKILL.mdRelocate arena skill +0/-0

Relocate arena skill

• Moves the arena skill to root-level 'skills/'.

skills/arena/SKILL.md

SKILL.mdRelocate automate-me skill +0/-0

Relocate automate-me skill

• Moves the automate-me skill to root-level 'skills/'.

skills/automate-me/SKILL.md

SKILL.mdRelocate blast-radius skill +0/-0

Relocate blast-radius skill

• Moves the blast-radius skill to root-level 'skills/'.

skills/blast-radius/SKILL.md

SKILL.mdRelocate bro skill +0/-0

Relocate bro skill

• Moves the bro skill to root-level 'skills/'.

skills/bro/SKILL.md

SKILL.mdRelocate verification-skill creator +0/-0

Relocate verification-skill creator

• Moves the skill to root-level 'skills/'.

skills/create-verification-skill/SKILL.md

README.mdRelocate feature-map example overview +0/-0

Relocate feature-map example overview

• Moves the verification-skill example with its parent skill.

skills/create-verification-skill/references/feature-map-example/README.md

create-note.mdRelocate create-note example +0/-0

Relocate create-note example

• Moves the verification-skill example with its parent skill.

skills/create-verification-skill/references/feature-map-example/create-note.md

search.mdRelocate search example +0/-0

Relocate search example

• Moves the verification-skill example with its parent skill.

skills/create-verification-skill/references/feature-map-example/search.md

SKILL.mdRelocate figure-it-out skill +0/-0

Relocate figure-it-out skill

• Moves the skill to root-level 'skills/'.

skills/figure-it-out/SKILL.md

SKILL.mdRelocate hermesbot skill +0/-0

Relocate hermesbot skill

• Moves the Hermes-native control-surface skill to root-level 'skills/'.

skills/hermesbot/SKILL.md

SKILL.mdRelocate how skill +0/-0

Relocate how skill

• Moves the skill to root-level 'skills/'.

skills/how/SKILL.md

explainer-prompt.mdRelocate explainer prompt +0/-0

Relocate explainer prompt

• Moves the how-skill reference with its parent skill.

skills/how/references/explainer-prompt.md

explorer-prompt.mdRelocate explorer prompt +0/-0

Relocate explorer prompt

• Moves the how-skill reference with its parent skill.

skills/how/references/explorer-prompt.md

SKILL.mdRelocate interrogate skill +0/-0

Relocate interrogate skill

• Moves the skill to root-level 'skills/'.

skills/interrogate/SKILL.md

code-quality-review.mdRelocate code-quality review reference +0/-0

Relocate code-quality review reference

• Moves the interrogate reference with its parent skill.

skills/interrogate/references/code-quality-review.md

lead-judgment.mdRelocate lead-judgment reference +0/-0

Relocate lead-judgment reference

• Moves the interrogate reference with its parent skill.

skills/interrogate/references/lead-judgment.md

reviewer-prompt.mdRelocate reviewer prompt +0/-0

Relocate reviewer prompt

• Moves the interrogate reference with its parent skill.

skills/interrogate/references/reviewer-prompt.md

rubric.mdRelocate review rubric +0/-0

Relocate review rubric

• Moves the interrogate reference with its parent skill.

skills/interrogate/references/rubric.md

SKILL.mdRelocate verification maintenance skill +0/-0

Relocate verification maintenance skill

• Moves the skill to root-level 'skills/'.

skills/maintain-verification-skill/SKILL.md

SKILL.mdRelocate no-comments skill +0/-0

Relocate no-comments skill

• Moves the skill to root-level 'skills/'.

skills/no-comments/SKILL.md

comment-sicko.mdRelocate Comment Sicko reference +0/-0

Relocate Comment Sicko reference

• Keeps the inlined agent reference with the root-level no-comments skill.

skills/no-comments/references/comment-sicko.md

SKILL.mdRelocate poteto-mode router +0/-0

Relocate poteto-mode router

• Moves the routing skill to root-level 'skills/'.

skills/poteto-mode/SKILL.md

authoring-a-skill.mdRelocate skill-authoring playbook +0/-0

Relocate skill-authoring playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/authoring-a-skill.md

autonomous-run.mdRelocate autonomous-run playbook +0/-0

Relocate autonomous-run playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/autonomous-run.md

autopilot-full.mdRelocate full-autopilot playbook +0/-0

Relocate full-autopilot playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/autopilot-full.md

autopilot-stack.mdRelocate stack-autopilot playbook +0/-0

Relocate stack-autopilot playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/autopilot-stack.md

babysit.mdRelocate babysit playbook +0/-0

Relocate babysit playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/babysit.md

bug-fix.mdRelocate bug-fix playbook +0/-0

Relocate bug-fix playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/bug-fix.md

eval.mdRelocate evaluation playbook +0/-0

Relocate evaluation playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/eval.md

feature.mdRelocate feature playbook +0/-0

Relocate feature playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/feature.md

hillclimb.mdRelocate hillclimb playbook +0/-0

Relocate hillclimb playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/hillclimb.md

investigation.mdRelocate investigation playbook +0/-0

Relocate investigation playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/investigation.md

multi-phase-plan.mdRelocate multi-phase planning playbook +0/-0

Relocate multi-phase planning playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/multi-phase-plan.md

opening-a-pr.mdRelocate PR-opening playbook +0/-0

Relocate PR-opening playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/opening-a-pr.md

orchestrate.mdRelocate orchestration playbook +0/-0

Relocate orchestration playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/orchestrate.md

pause-safely.mdRelocate pause-safely playbook +0/-0

Relocate pause-safely playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/pause-safely.md

perf-issue.mdRelocate performance playbook +0/-0

Relocate performance playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/perf-issue.md

prototype.mdRelocate prototype playbook +0/-0

Relocate prototype playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/prototype.md

refactoring.mdRelocate refactoring playbook +0/-0

Relocate refactoring playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/refactoring.md

runtime-forensics.mdRelocate runtime-forensics playbook +0/-0

Relocate runtime-forensics playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/runtime-forensics.md

session-pickup.mdRelocate session-pickup playbook +0/-0

Relocate session-pickup playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/session-pickup.md

shipping.mdRelocate shipping playbook +0/-0

Relocate shipping playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/shipping.md

trace-forensics.mdRelocate trace-forensics playbook +0/-0

Relocate trace-forensics playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/trace-forensics.md

visual-parity.mdRelocate visual-parity playbook +0/-0

Relocate visual-parity playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/visual-parity.md

worktree-cleanup.mdRelocate worktree-cleanup playbook +0/-0

Relocate worktree-cleanup playbook

• Moves the playbook with poteto-mode.

skills/poteto-mode/playbooks/worktree-cleanup.md

bugbot-triage.mdRelocate bugbot triage reference +0/-0

Relocate bugbot triage reference

• Moves the reference with poteto-mode.

skills/poteto-mode/references/bugbot-triage.md

bootstrap.tsRelocate TypeScript bootstrap +0/-0

Relocate TypeScript bootstrap

• Moves the poteto-mode script to its root-level skill directory.

skills/poteto-mode/scripts/bootstrap.ts

check-plan.mjsRelocate plan checker +0/-0

Relocate plan checker

• Moves the poteto-mode script to its root-level skill directory.

skills/poteto-mode/scripts/check-plan.mjs

orch.tsRelocate orchestration script +0/-0

Relocate orchestration script

• Moves the script with poteto-mode.

skills/poteto-mode/scripts/orch/orch.ts

store.tsRelocate orchestration store +0/-0

Relocate orchestration store

• Moves the script with poteto-mode.

skills/poteto-mode/scripts/orch/store.ts

cli.tsRelocate PR-watcher CLI +0/-0

Relocate PR-watcher CLI

• Moves the script with poteto-mode.

skills/poteto-mode/scripts/watch-pr/cli.ts

github.tsRelocate GitHub watcher integration +0/-0

Relocate GitHub watcher integration

• Moves the script with poteto-mode.

skills/poteto-mode/scripts/watch-pr/github.ts

policy.tsRelocate watcher policy +0/-0

Relocate watcher policy

• Moves the script with poteto-mode.

skills/poteto-mode/scripts/watch-pr/policy.ts

render.tsRelocate watcher renderer +0/-0

Relocate watcher renderer

• Moves the script with poteto-mode.

skills/poteto-mode/scripts/watch-pr/render.ts

types.tsRelocate watcher types +0/-0

Relocate watcher types

• Moves the script with poteto-mode.

skills/poteto-mode/scripts/watch-pr/types.ts

watch-prRelocate PR-watcher launcher +0/-0

Relocate PR-watcher launcher

• Moves the launcher with poteto-mode.

skills/poteto-mode/scripts/watch-pr/watch-pr

worktree-audit.shRelocate worktree audit script +0/-0

Relocate worktree audit script

• Moves the script with poteto-mode.

skills/poteto-mode/scripts/worktree-audit.sh

SKILL.mdRelocate attack-the-premise principle +0/-0

Relocate attack-the-premise principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-attack-the-premise/SKILL.md

SKILL.mdRelocate boundary-discipline principle +0/-0

Relocate boundary-discipline principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-boundary-discipline/SKILL.md

SKILL.mdRelocate build-the-lever principle +0/-0

Relocate build-the-lever principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-build-the-lever/SKILL.md

SKILL.mdRelocate encode-lessons principle +0/-0

Relocate encode-lessons principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-encode-lessons-in-structure/SKILL.md

SKILL.mdRelocate design-space principle +0/-0

Relocate design-space principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-exhaust-the-design-space/SKILL.md

SKILL.mdRelocate experience-first principle +0/-0

Relocate experience-first principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-experience-first/SKILL.md

SKILL.mdRelocate root-causes principle +0/-0

Relocate root-causes principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-fix-root-causes/SKILL.md

SKILL.mdRelocate foundational-thinking principle +0/-0

Relocate foundational-thinking principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-foundational-thinking/SKILL.md

SKILL.mdRelocate context-window principle +0/-0

Relocate context-window principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-guard-the-context-window/SKILL.md

SKILL.mdRelocate laziness-protocol principle +0/-0

Relocate laziness-protocol principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-laziness-protocol/SKILL.md

SKILL.mdRelocate idempotence principle +0/-0

Relocate idempotence principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-make-operations-idempotent/SKILL.md

SKILL.mdRelocate API-migration principle +0/-0

Relocate API-migration principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md

SKILL.mdRelocate reader-load principle +0/-0

Relocate reader-load principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-minimize-reader-load/SKILL.md

SKILL.mdRelocate domain-modeling principle +0/-0

Relocate domain-modeling principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-model-the-domain/SKILL.md

SKILL.mdRelocate nonblocking principle +0/-0

Relocate nonblocking principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-never-block-on-the-human/SKILL.md

SKILL.mdRelocate outcome-oriented principle +0/-0

Relocate outcome-oriented principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-outcome-oriented-execution/SKILL.md

SKILL.mdRelocate verification principle +0/-0

Relocate verification principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-prove-it-works/SKILL.md

SKILL.mdRelocate redesign principle +0/-0

Relocate redesign principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-redesign-from-first-principles/SKILL.md

SKILL.mdRelocate shared-state principle +0/-0

Relocate shared-state principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-separate-before-serializing-shared-state/SKILL.md

SKILL.mdRelocate verifiable-units principle +0/-0

Relocate verifiable-units principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-sequence-verifiable-units/SKILL.md

SKILL.mdRelocate subtract-first principle +0/-0

Relocate subtract-first principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-subtract-before-you-add/SKILL.md

SKILL.mdRelocate behavioral-testing principle +0/-0

Relocate behavioral-testing principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-test-behavior-not-implementation/SKILL.md

SKILL.mdRelocate type-discipline principle +0/-0

Relocate type-discipline principle

• Moves this principle skill to root-level 'skills/'.

skills/principle-type-system-discipline/SKILL.md

SKILL.mdRelocate recall skill +0/-0

Relocate recall skill

• Moves the skill to root-level 'skills/'.

skills/recall/SKILL.md

SKILL.mdRelocate reflect skill +0/-0

Relocate reflect skill

• Moves the skill to root-level 'skills/'.

skills/reflect/SKILL.md

divergent-reviewer.mdRelocate divergent-reviewer prompt +0/-0

Relocate divergent-reviewer prompt

• Moves the reference with reflect.

skills/reflect/references/divergent-reviewer.md

judgment-reviewer.mdRelocate judgment-reviewer prompt +0/-0

Relocate judgment-reviewer prompt

• Moves the reference with reflect.

skills/reflect/references/judgment-reviewer.md

synthesizer.mdRelocate synthesizer prompt +0/-0

Relocate synthesizer prompt

• Moves the reference with reflect.

skills/reflect/references/synthesizer.md

tooling-reviewer.mdRelocate tooling-reviewer prompt +0/-0

Relocate tooling-reviewer prompt

• Moves the reference with reflect.

skills/reflect/references/tooling-reviewer.md

SKILL.mdRelocate setup-pstack skill +0/-0

Relocate setup-pstack skill

• Moves the onboarding skill to root-level 'skills/'.

skills/setup-pstack/SKILL.md

SKILL.mdRelocate show-me-your-work skill +0/-0

Relocate show-me-your-work skill

• Moves the skill to root-level 'skills/'.

skills/show-me-your-work/SKILL.md

decision-log-template.tsvRelocate decision-log template +0/-0

Relocate decision-log template

• Moves the reference with its parent skill.

skills/show-me-your-work/references/decision-log-template.tsv

log.shRelocate decision-logging script +0/-0

Relocate decision-logging script

• Moves the script with its parent skill.

skills/show-me-your-work/scripts/log.sh

SKILL.mdRelocate swarm skill +0/-0

Relocate swarm skill

• Moves the skill to root-level 'skills/'.

skills/swarm/SKILL.md

SKILL.mdRelocate TDD skill +0/-0

Relocate TDD skill

• Moves the skill to root-level 'skills/'.

skills/tdd/SKILL.md

SKILL.mdRelocate teach skill +0/-0

Relocate teach skill

• Moves the skill to root-level 'skills/'.

skills/teach/SKILL.md

SKILL.mdRelocate technical-writing skill +0/-0

Relocate technical-writing skill

• Moves the skill to root-level 'skills/'.

skills/technical-writing/SKILL.md

SKILL.mdRelocate TypeScript practices skill +0/-0

Relocate TypeScript practices skill

• Moves the skill to root-level 'skills/'.

skills/typescript-best-practices/SKILL.md

SKILL.mdRelocate unslop skill +0/-0

Relocate unslop skill

• Moves the skill to root-level 'skills/'.

skills/unslop/SKILL.md

SKILL.mdRelocate why skill +0/-0

Relocate why skill

• Moves the skill to root-level 'skills/'.

skills/why/SKILL.md

epistemics.mdRelocate epistemics reference +0/-0

Relocate epistemics reference

• Moves the reference with why.

skills/why/references/epistemics.md

investigator-prompt.mdRelocate investigator prompt +0/-0

Relocate investigator prompt

• Moves the reference with why.

skills/why/references/investigator-prompt.md

source-playbook.mdRelocate source playbook +0/-0

Relocate source playbook

• Moves the reference with why.

skills/why/references/source-playbook.md

code-archaeology.mdRelocate code-archaeology source guide +0/-0

Relocate code-archaeology source guide

• Moves the source guide with why.

skills/why/references/sources/code-archaeology.md

databricks.mdRelocate Databricks source guide +0/-0

Relocate Databricks source guide

• Moves the source guide with why.

skills/why/references/sources/databricks.md

datadog.mdRelocate Datadog source guide +0/-0

Relocate Datadog source guide

• Moves the source guide with why.

skills/why/references/sources/datadog.md

incident-postmortem.mdRelocate postmortem source guide +0/-0

Relocate postmortem source guide

• Moves the source guide with why.

skills/why/references/sources/incident-postmortem.md

linear.mdRelocate Linear source guide +0/-0

Relocate Linear source guide

• Moves the source guide with why.

skills/why/references/sources/linear.md

notion.mdRelocate Notion source guide +0/-0

Relocate Notion source guide

• Moves the source guide with why.

skills/why/references/sources/notion.md

sentry.mdRelocate Sentry source guide +0/-0

Relocate Sentry source guide

• Moves the source guide with why.

skills/why/references/sources/sentry.md

slack.mdRelocate Slack source guide +0/-0

Relocate Slack source guide

• Moves the source guide with why.

skills/why/references/sources/slack.md

synthesizer-prompt.mdRelocate why synthesizer prompt +0/-0

Relocate why synthesizer prompt

• Moves the reference with why.

skills/why/references/synthesizer-prompt.md

Tests (11) +10 / -14
orch.test.tsRelocate orchestration tests +0/-0

Relocate orchestration tests

• Moves the tests alongside the root-level orchestration scripts.

skills/poteto-mode/scripts/orch/orch.test.ts

cli.test.tsRelocate PR-watcher CLI tests +0/-0

Relocate PR-watcher CLI tests

• Moves the tests alongside the root-level watcher.

skills/poteto-mode/scripts/watch-pr/cli.test.ts

fakes.test-helper.tsRelocate PR-watcher test fakes +0/-0

Relocate PR-watcher test fakes

• Moves test helpers alongside the root-level watcher.

skills/poteto-mode/scripts/watch-pr/fakes.test-helper.ts

github.test.tsRelocate GitHub watcher tests +0/-0

Relocate GitHub watcher tests

• Moves the tests alongside the root-level watcher.

skills/poteto-mode/scripts/watch-pr/github.test.ts

policy.test.tsRelocate watcher policy tests +0/-0

Relocate watcher policy tests

• Moves the tests alongside the root-level watcher.

skills/poteto-mode/scripts/watch-pr/policy.test.ts

types.compile.tsRelocate watcher type checks +0/-0

Relocate watcher type checks

• Moves compile-time checks alongside the watcher.

skills/poteto-mode/scripts/watch-pr/types.compile.ts

test_bans.pyUpdate vocabulary exemption fixture +1/-4

Update vocabulary exemption fixture

• Removes fixtures for the former Cursor dual-load surfaces.

tools/tests/test_bans.py

test_check_pins.pyUpdate required pin-workflow fixture +1/-1

Update required pin-workflow fixture

• Removes the deleted upstream watcher from the expected workflow list.

tools/tests/test_check_pins.py

test_panel_location.pyUse YAML manifest in panel-location fixture +1/-1

Use YAML manifest in panel-location fixture

• Updates the expected manifest filename in a model-panel location test.

tools/tests/test_panel_location.py

test_release_delivery.pyTest root YAML release payload +6/-7

Test root YAML release payload

• Changes release fixtures from a nested JSON manifest to a root YAML manifest and adjusts a subprocess environment.

tools/tests/test_release_delivery.py

test_workflow_review_guards.pyStop checking removed upstream watcher +1/-1

Stop checking removed upstream watcher

• Retains the model-drift watcher as the sole workflow in this guard fixture.

tools/tests/test_workflow_review_guards.py

Documentation (6) +126 / -243
AGENTS.mdRevise contributor guidance for root layout +5/-27

Revise contributor guidance for root layout

• Removes some dual-load and upstream-watch guidance and revises release instructions.

AGENTS.md

CHANGELOG.mdRevise historical migration references +6/-6

Revise historical migration references

• Changes several historical path and manifest references in the release history.

CHANGELOG.md

CONTRIBUTING.mdRevise conversion and pinning guidance +4/-4

Revise conversion and pinning guidance

• Describes generation without the 'pstack/' output path and edits the upstream-pin instructions.

CONTRIBUTING.md

LICENSEUse the root plugin license text +0/-4

Use the root plugin license text

• Removes the separate port-contributors copyright paragraph from the root license.

LICENSE

README.mdMake the root plugin README the repository README +110/-199

Make the root plugin README the repository README

• Replaces the development-oriented README with package installation, usage, adaptation, and limitations guidance.

README.md

after-install.mdSimplify reinstall guidance +1/-3

Simplify reinstall guidance

• Removes the legacy subdirectory-install instructions and points users to pinned reinstall guidance.

after-install.md

Other (17) +244 / -33
.build-provenance.txtRefresh root build provenance +4/-4

Refresh root build provenance

• Records a new conversion timestamp and converter digest for the relocated package.

.build-provenance.txt

.gitattributesMark root package paths as generated +12/-4

Mark root package paths as generated

• Replaces the 'pstack/**' rule with rules for root-level plugin files and directories.

.gitattributes

action.ymlDefault builds to the repository root +1/-1

Default builds to the repository root

• Changes the shared build action’s default package path from 'pstack' to '.'.

.github/actions/build-package/action.yml

labeler.ymlAdjust plugin label patterns +2/-2

Adjust plugin label patterns

• Changes a manifest glob and removes the Cursor-manifest glob; other patterns still refer to 'pstack/'.

.github/labeler.yml

ci.ymlRetarget CI to root-level package paths +8/-8

Retarget CI to root-level package paths

• Changes checkout, build, script-test, artifact, and provenance paths from the package subdirectory to root-level paths.

.github/workflows/ci.yml

publish-dist.ymlPublish selected root plugin files +1/-1

Publish selected root plugin files

• Copies the manifest, skills, config, assets, and package documentation into the dist tree instead of copying 'pstack/'.

.github/workflows/publish-dist.yml

release.ymlPackage root-level release payload +5/-5

Package root-level release payload

• Compares root provenance and packages selected root files for the release ZIP.

.github/workflows/release.yml

logo.pngRelocate plugin logo +0/-0

Relocate plugin logo

• Moves the package logo asset to the root-level 'assets/' directory.

assets/logo.png

models.jsonRelocate shipped model defaults +0/-0

Relocate shipped model defaults

• Moves the plugin’s model-role configuration to root-level 'config/'.

config/models.json

plugin.yamlAdd root Hermes manifest +18/-0

Add root Hermes manifest

• Declares the pstack identity, version, attribution, and keywords in a root YAML manifest.

plugin.yaml

pyproject.tomlStop excluding the former package directory +1/-1

Stop excluding the former package directory

• Removes 'pstack' from Ruff’s exclusion list.

pyproject.toml

bun.lockRelocate Bun dependency lockfile +0/-0

Relocate Bun dependency lockfile

• Moves the script lockfile with poteto-mode.

skills/poteto-mode/scripts/bun.lock

package.jsonRelocate script package metadata +0/-0

Relocate script package metadata

• Moves the Bun package metadata with poteto-mode.

skills/poteto-mode/scripts/package.json

tsconfig.jsonRelocate watcher TypeScript config +0/-0

Relocate watcher TypeScript config

• Moves the compiler configuration with the watcher.

skills/poteto-mode/scripts/watch-pr/tsconfig.json

bans.pyScope ban scans for a mixed root tree +15/-6

Scope ban scans for a mixed root tree

• Removes Cursor-surface vocabulary exemptions and excludes selected repository tooling and documentation from package text scanning.

tools/bans.py

check_pins.pyRemove deleted watcher from pin checks +0/-1

Remove deleted watcher from pin checks

• No longer requires an upstream pin declaration in the removed drift-watch workflow.

tools/check_pins.py

validate.py.bakAdd validator backup file +177/-0

Add validator backup file

• Adds a backup snapshot of validation code to 'tools/'; it is not part of the intended plugin payload.

tools/validate.py.bak

@qodo-code-review

qodo-code-review Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (12) 📘 Rule violations (0) 📎 Requirement gaps (2) 🔗 Cross-repo conflicts (1) 📜 Skill insights (0)



🔴 High

1. Release workflow fails before publishing 🔴 High 🐞 Bug ☼ Reliability
Description
The release verification step runs cp -a with multiple sources but never creates its destination,
$RUNNER_TEMP/release-built; unlike the previous single-source copy, this requires an existing
directory. On a fresh runner, cp fails under set -euo pipefail, so tagged releases stop before
the comparison, ZIP creation, or GitHub release.
Code

.github/workflows/release.yml[R61-63]

+          cp -a plugin.yaml skills config assets README.md after-install.md LICENSE .build-provenance.txt "$RUNNER_TEMP/release-built"
          rm -f "$RUNNER_TEMP/release-built/.build-provenance.txt"
          diff -qr "$RUNNER_TEMP/release-built" "$published"
Relevance

●●● Strong

The matching multi-source release copy failure was accepted in PR #110.

PR-#110

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The step creates $published (release-dist) but does not create $RUNNER_TEMP/release-built
before using it as the destination of a multiple-source cp -a command. That command therefore
fails on a fresh runner before verification can continue.

.github/workflows/release.yml[39-65]
.github/workflows/release.yml[43-47]
.github/workflows/release.yml[60-69]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Release verification copies multiple package entries into `$RUNNER_TEMP/release-built` without creating that directory first, causing the release job to stop before comparison and packaging.

## Fix Focus Areas
- .github/workflows/release.yml[60-63]

## Recommended Fix
Add `mkdir -p "$RUNNER_TEMP/release-built"` before the copy, and include the real manifest (`plugin.json`) in the source list. Run the verification script with a fresh temporary directory to confirm the copy and subsequent steps succeed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


2. Rebuilds leave published metadata stale 🔴 High 🐞 Bug ≡ Correctness
Description
check_manifest() now reads plugin.yaml, but convert.py still generates plugin.json and does
not regenerate the checked-in YAML file. On a root rebuild, validation and publication consume the
old YAML metadata even if the pinned upstream manifest changes; a build into a fresh directory
instead fails validation because YAML is absent.
Code

tools/validate.py[R159-161]

+    p = pkg / "plugin.yaml"
+    if not p.is_file():
+        p = pkg / "plugin.yaml"
Relevance

●●● Strong

Validator and converter use inconsistent manifest formats, breaking fresh builds and risking stale
metadata.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The converter writes out / "plugin.json", whereas the changed validator checks plugin.yaml
twice. The root-output copy loop replaces only generated items, leaving a pre-existing YAML file
untouched.

tools/convert.py[1805-1809]
tools/convert.py[2020-2035]
tools/validate.py[158-173]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The converter writes `plugin.json`, while the validator and publisher consume an unrelated, checked-in `plugin.yaml`.

## Fix Focus Areas
- tools/validate.py[158-173]
- tools/convert.py[1805-1809]
- .github/workflows/publish-dist.yml[49-52]

## Recommended Fix
Use the same Hermes-supported manifest file for conversion, validation, and publication. Verify both a fresh-directory build and a root rebuild after changing upstream manifest metadata.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


3. Hermes cannot install the plugin 🔴 High 🔗 Cross-repo conflict ≡ Correctness
Description
The root plugin.yaml sends this skills-only package through Hermes’ native plugin loader, which
requires a loadable entry point, while the portable skills loader expects a root plugin.json.
Installs from the checked-in root, published dist tree, or release ZIP cannot register the skills;
even if conversion adds plugin.json, the root YAML takes precedence and reaches the same
native-loader failure.
Code

plugin.yaml[R1-2]

+$schema: https://agent-plugins.org/schemas/1.0.0/plugin.schema.json
+name: pstack
Relevance

●●● Strong

This is an obvious stale-path correction in relocated generated documentation.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR adds a root plugin.yaml and changes validation, dist publication, and release packaging to
use it, while tools/convert.py still generates plugin.json. Hermes selects native validation
when root YAML is present and requires a native entry point there; its separate portable Agent
Plugins loader probes for root plugin.json. Thus the published tree lacks the manifest needed for
portable discovery, and adding the generated JSON without removing YAML would not change which
loader Hermes selects.

pstack-hermes -> hermes-agent
plugin.yaml[1-3]
tools/convert.py[1805-1809]
tools/validate.py[158-173]
tools/convert.py[1805-1810]
.github/workflows/publish-dist.yml[49-53]
tools/validate.py[158-176]
plugin.yaml[1-18]
.github/workflows/publish-dist.yml[49-52]
External repo: iap/hermes-agent, hermes_cli/plugin_validate.py [516-545]
External repo: iap/hermes-agent, hermes_cli/plugin_validate.py [578-593]
External repo: iap/hermes-agent, hermes_cli/plugins_loader.py [549-557]
External repo: iap/hermes-agent, hermes_cli/plugins_loader.py [718-739]
🌐 _validate_manifest sets manifest_path = root / "plugin.json" and raises AgentPluginError("plugin.json must be a regular file within the plugin root") if it is missing.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The skills-only package is published with a root `plugin.yaml`, which selects Hermes’ native plugin loader rather than the portable loader that discovers skills through `plugin.json`. The converter still generates JSON, but publication omits it, and keeping YAML alongside it would still select the wrong loader.

## Fix Focus Areas
- plugin.yaml[1-18]
- tools/convert.py[1805-1809]
- tools/validate.py[158-176]
- tools/validate.py[301-303]
- .github/workflows/publish-dist.yml[49-53]
- .github/workflows/release.yml[61-69]

## Recommended Fix
Remove the root `plugin.yaml` and commit the converter-generated root `plugin.json`. Restore JSON parsing in `check_manifest` and `check_layout`, remove the unused `yaml` import, and make dist publishing and release copy and ZIP lists include `plugin.json` instead of `plugin.yaml`. Test a normal Hermes install without force and confirm skill discovery from the exact published tree.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


4. The inline-shell fix has no parser-safety proof 🔴 High 📎 Requirement gap ⛨ Security
Description
tools/validate.py only parses the YAML manifest and checks package layout, with no cases for
accidental prose, intentional inline-shell syntax, TypeScript postfix assertions, or isolated
operator mentions. A validation run therefore cannot demonstrate that the original phrase reaches
the real parser without execution while the adapted phrase does not.
Code

skills/typescript-best-practices/references/patterns.md[94]

+Strengthen when the loose type forces a lie at a use site. The tells are non-null assertions, `arr[0] as T`, and a "should never happen" throw:
Relevance

●●● Strong

Parser-safety tests directly support this PR's stated inline-shell false-trigger fix.

PR-#110

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed content is the phrase under test, but the validation diff only replaces JSON manifest
parsing with YAML parsing and updates layout checks; no inline-shell parser, command-execution
guard, or acceptance cases are added.

Validate content-only skills against inline-shell execution
skills/typescript-best-practices/references/patterns.md[94-94]
tools/validate.py[159-177]
tools/tests/test_bans.py[16-24]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR adapts a phrase that reportedly triggers Hermes inline-shell parsing, but the validator and test changes provide no parser proof or execution guard for the affected content.

## Fix Focus Areas
- skills/typescript-best-practices/references/patterns.md[94-94]
- tools/validate.py[159-177]
- tools/tests/test_bans.py[16-24]

## Recommended Fix
Add validator tests covering accidental prose, intentional inline-shell DSL, ordinary TypeScript postfix assertions, and an isolated operator mention. Invoke the real upstream parser on the original and adapted phrases, assert only the original matches, and ensure the proof uses a harmless stub or equivalent guard so no command can execute.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


5. Generated TypeScript guidance can drift from its converter 🔴 High 📎 Requirement gap ⚙ Maintainability
Description
patterns.md changes the warning by hand, but tools/convert.py has no anchored transform or
audited provenance entry for the phrase. When CI, publish-dist, or release rebuilds from the pinned
source, the root-mode copy replaces skills/ with upstream content, restoring the ! phrase that
triggers Hermes’ inline-shell DSL and causing the tracked-file check to fail.
Code

skills/typescript-best-practices/references/patterns.md[94]

+Strengthen when the loose type forces a lie at a use site. The tells are non-null assertions, `arr[0] as T`, and a "should never happen" throw:
Relevance

●● Moderate

Generated-content provenance concerns are plausible, but no closely matching historical decision was
found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The generated reference contains the adapted wording, but the converter changes only output layout
and copy behavior, with no transform for the phrase or corresponding provenance entry. The build
action runs convert.py --out .; its root-mode copy deletes and re-copies skills/ from upstream,
so a rebuild restores the original phrase and changes the tracked file.

Adapt the TypeScript prose without changing code examples
skills/typescript-best-practices/references/patterns.md[94-94]
tools/convert.py[1753-1767]
.build-provenance.txt[8-33]
.github/actions/build-package/action.yml[89-94]
tools/convert.py[2022-2035]
.build-provenance.txt[26-35]
.github/workflows/publish-dist.yml[49-53]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The generated TypeScript reference was hand-edited to remove a phrase that triggers Hermes’ inline-shell DSL. Rebuilds from the pinned source restore that phrase because the converter does not implement or audit the adaptation.

## Fix Focus Areas
- skills/typescript-best-practices/references/patterns.md[94-94]
- tools/convert.py[1750-1767]
- .build-provenance.txt[8-33]

## Recommended Fix
Add an exact, anchor-audited transform in `convert.py` that replaces the upstream text ``The tells are `!`, `arr[0] as T`,`` with ``The tells are non-null assertions, `arr[0] as T`,``. Record a `fixes:` entry in `.build-provenance.txt`, rebuild from pin c47b128, and commit the generated output. Keep the remainder of the warning, the cast example, and the TypeScript samples byte-for-byte unchanged. Add a validator check that fails when a `!` code span is followed by another backtick span in skill content.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


6. CI reproducibility gate can never pass 🔴 High 🐞 Bug ☼ Reliability
Description
With PACKAGE_PATH: ., hash_git_tree() runs git ls-tree -r HEAD -- . and hashes the entire
committed repository, while hash_dir_tree() hashes only the converter output, which contains
plugin.json rather than plugin.yaml. On a clean PR or push run, tracked tooling, workflows, and
documentation have no counterpart in the rebuild, so the comparison fails on both OS legs regardless
of package contents.
Code

.github/workflows/ci.yml[68]

+          PACKAGE_PATH: .
Evidence
The PACKAGE_PATH value selects every tracked file for git ls-tree, but the rebuilt hash walks a
separate, fresh package-only directory. Repository tooling and other non-package files therefore
appear only in the committed-tree hash; the differing plugin manifest names also need to be handled
when comparing the package paths.

.github/workflows/ci.yml[64-105]
.github/workflows/ci.yml[65-68]
.github/workflows/ci.yml[76-100]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The reproducibility gate compares a whole-repository committed-tree hash with a package-only rebuild hash, causing clean runs to fail.

## Fix Focus Areas
- .github/workflows/ci.yml[64-105]

## Recommended Fix
Enumerate the same explicit package paths on both sides (`plugin.json`, `skills`, `config`, `assets`, `README.md`, `after-install.md`, and `LICENSE`), excluding `.build-provenance.txt`. Pass the committed package paths to `git ls-tree -r HEAD -- <paths>`, account for the `plugin.yaml`/`plugin.json` name difference, and normalize names identically before hashing the corresponding rebuilt paths. Exercise the gate on an otherwise clean checkout.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗



🟠 Medium

7. Plan authors cannot run the required check 🟠 Medium 🐞 Bug ≡ Correctness
Description
The relocated multi-phase playbook still instructs agents to execute `node
pstack/skills/poteto-mode/scripts/check-plan.mjs <plan.md>`. From the new repository root, that
pstack/ path no longer exists, so following the mandatory step fails before the plan can be
checked.
Code

skills/poteto-mode/playbooks/multi-phase-plan.md[10]

+6. Run `node pstack/skills/poteto-mode/scripts/check-plan.mjs <plan.md>` and fix every line it prints (the **encode-lessons-in-structure** principle skill).
Relevance

●●● Strong

The PR explicitly targets this wording, but the converter lacks a corresponding generated-file
transform.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The playbook retains the old pstack/skills/ prefix, but the moved checker is in the root skills/
tree.

skills/poteto-mode/playbooks/multi-phase-plan.md[6-11]
skills/poteto-mode/scripts/check-plan.mjs[1-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The relocated playbook retains a command targeting the removed package subdirectory.

## Fix Focus Areas
- skills/poteto-mode/playbooks/multi-phase-plan.md[10-10]
- tools/convert.py[1678-1690]

## Recommended Fix
Change the generated playbook command through its upstream adaptation source to point to the shipped checker at `skills/poteto-mode/scripts/check-plan.mjs`, then rebuild and verify the command.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


8. Security ban scan skips any tools or docs folder 🟠 Medium 🐞 Bug ⛨ Security
Description
is_generated_dependency_path() treats tools, docs, and .github as generated dependency
directories wherever they appear in a path, rather than exempting only repository-level directories.
When recursively copied upstream skills contain paths such as skills/<name>/tools/install.sh or
skills/<name>/docs/reference.md, those packaged files bypass security-ban checks in validation and
the scanner gate, as well as encoding and conflict-marker checks.
Code

tools/bans.py[33]

+GENERATED_DEPENDENCY_DIRS: frozenset[str] = frozenset({"node_modules", "tools", "docs", ".github"})
Relevance

●●● Strong

Nested packaged tools/docs paths can bypass security scans; this is a concrete validation
vulnerability.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The converter recursively copies skill contents, but `any(part in GENERATED_DEPENDENCY_DIRS for part
in path.parts)` excludes matching directory names at any depth. Both local ban-checking entry points
use the filtered iterator, and the same helper gates the validation encoding and conflict-marker
scans, so nested files can ship without receiving those checks.

tools/bans.py[43-76]
tools/validate.py[275-283]
tools/convert.py[238-257]
tools/bans.py[32-59]
tools/scanner_gate.py[22-32]
tools/validate.py[476-481]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Directory-name exemptions for `tools`, `docs`, and `.github` also suppress checks of files inside packaged skills.

## Fix Focus Areas
- tools/bans.py[32-57]

## Recommended Fix
Keep `GENERATED_DEPENDENCY_DIRS = {"node_modules"}` and add a separate `EXEMPT_TOP_LEVEL_DIRS = {"tools", "docs", ".github", ".git", ".venv"}` that applies only when `rel.parts[0]` matches. Add a regression case proving nested skill references remain in the scanned file set. Consider running the scan on the package file list rather than the repository root.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


9. Lint fails on an unused import in the converter 🟠 Medium 🐞 Bug ⚙ Maintainability
Description
import yaml was added to convert.py among the stdlib imports but is never used, since the
converter still emits JSON. Ruff's select = ["E4","E7","E9","F","I","UP","B"] flags it as F401
(unused) and I001 (third-party import inside the stdlib block), so the ruff check tools CI step
fails.
Code

tools/convert.py[36]

+import yaml
Relevance

●●● Strong

Unused yaml import deterministically triggers configured Ruff F401 and import-order checks.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Searching convert.py finds no yaml. usage, and ruff selects the F and I rule families.

pyproject.toml[25-33]
tools/convert.py[33-42]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An unused third-party import in the stdlib block breaks ruff (F401, I001).

## Fix Focus Areas
- tools/convert.py[33-42]

## Recommended Fix
Delete `import yaml` from `tools/convert.py`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


10. Comment Sicko reference can ship with CRLF 🟠 Medium 🐞 Bug ≡ Correctness
Description
comment_sicko is now read from the upstream source and written with
write_bytes(comment_sicko.read_bytes()), skipping copy_file/normalize_text. Before, it came
from the normalized out/agents copy. On a checkout with core.autocrlf=true (the Windows CI leg;
the provenance shows this build fixed 124 CRLF files),
skills/no-comments/references/comment-sicko.md keeps CRLF/BOM, which fails check_encoding and
diverges from the Linux build.
Code

tools/convert.py[1764]

+    comment_sicko = source / "agents" / "comment-sicko.md"
Relevance

●●● Strong

Raw copying bypasses normalization and can publish CRLF or BOM content rejected by validation.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
copy_file is the only path that strips BOM and CRLF. The new code bypasses it, and the provenance
shows the source tree used for this build had CRLF in 124 files.

tools/convert.py[1764-1771]
tools/convert.py[191-235]
.build-provenance.txt[29-33]
tools/validate.py[275-297]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Comment Sicko persona is copied byte-for-byte from the source, with no LF/BOM normalization.

## Fix Focus Areas
- tools/convert.py[1764-1771]

## Recommended Fix
Replace the `write_bytes(comment_sicko.read_bytes())` call with `copy_file(comment_sicko, no_comments_refs / "comment-sicko.md", st)`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


11. Package changes lose their review labels 🟠 Medium 🐞 Bug ⚙ Maintainability
Description
The labeler's manifest glob now names pstack/plugin.yml, while the migrated manifest is
plugin.yaml at the repository root and the other package globs still start with pstack/. When a
later pull request changes root skills, config, or the manifest, the corresponding package, skills,
and principles labels do not match.
Code

.github/labeler.yml[10]

+      - any-glob-to-any-file: "pstack/plugin.yml"
Relevance

●●● Strong

Exact root-layout label-glob precedent was accepted in PR #110.

PR-#110

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The label rules match only pstack/ package paths, whereas the PR puts the package manifest and
skills at the root.

.github/labeler.yml[8-19]
plugin.yaml[1-4]
tools/convert.py[44-47]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The automatic package labels still point to deleted subdirectory paths and a nonexistent manifest name.

## Fix Focus Areas
- .github/labeler.yml[8-19]

## Recommended Fix
Match the root manifest and root `config/**` and `skills/**` paths, including the principles subset. Verify label matches against representative changed-file paths.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


12. Agent rules contradict the new root layout 🟠 Medium 🐞 Bug ⚙ Maintainability
Description
AGENTS.md still tells agents that pstack/ is the generated never-hand-edit tree and that agents/
is generated and should be left as-is. Now the generated tree is skills/, config/, etc. at the
root, and validate.py fails if agents/ exists. The PR also deletes the hard rules "Anchors
audited", "Converter changes are tracked in issues" and "Excluded upstreams stay excluded" and
leaves a dangling "this migration merges." fragment, so agents lose the guardrail against
hand-editing generated skills (the exact mistake in this PR).
Code

AGENTS.md[135]

+| `agents/` | generated; inert on hermes | agent personas; leave as-is |
Relevance

●● Moderate

Copyright preservation is plausible, but no closely matching acceptance or rejection precedent was
found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The table entry at line 134 still names pstack/ as generated, line 135 says agents/ is
generated, while check_layout now fails on agents/. The removed hard rules are what forbade
hand-edits and required converter-tracked adaptations.

AGENTS.md[130-140]
AGENTS.md[183-192]
tools/validate.py[317-320]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Agent-governing docs reference the old `pstack/` and `agents/` layout and drop the rules that prevent hand-editing generated content.

## Fix Focus Areas
- AGENTS.md[130-140]
- AGENTS.md[183-192]

## Recommended Fix
Mark the root `skills/`, `config/`, `assets/`, `plugin.json`, `README.md`, `after-install.md`, `LICENSE` and `.build-provenance.txt` as generated (never hand-edit). Remove the `agents/` row. Restore the Anchors-audited, converter-change-tracking and excluded-upstreams rules, and fix the dangling sentence.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


13. Port contributors' copyright removed from LICENSE 🟠 Medium 🐞 Bug ⚙ Maintainability
Description
Because DEFAULT_OUT is now the repo root, the converter's generated LICENSE (upstream MIT plus
ADAPTATION_LINE) overwrote the repository LICENSE. The paragraph granting "Copyright (c) 2026 the
pstack-hermes-port contributors" for the converter, validator, CI and fork patches is gone. The
repo's own hand-written tooling now carries only the upstream author's notice, and any future manual
restore would be wiped on the next rebuild.
Code

LICENSE[L24-27]

-
-Port modifications for the Hermes Agent platform (converter, validator, CI,
-fork patches, discovery and delegation rewrites):
-Copyright (c) 2026 the pstack-hermes-port contributors
Relevance

●● Moderate

Installation behavior is a significant cross-repository semantic concern without decisive historical
precedent.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The converter builds LICENSE from the upstream text plus a single adaptation line, and root-mode
output now replaces the repo LICENSE wholesale.

tools/convert.py[1812-1822]
tools/convert.py[2022-2035]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The in-place root build overwrites the repository LICENSE and drops the port contributors' copyright.

## Fix Focus Areas
- tools/convert.py[1812-1822]
- LICENSE[21-27]

## Recommended Fix
Have the converter append the port-modifications copyright paragraph after `ADAPTATION_LINE` so the generated LICENSE keeps it, then rebuild.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗



🟡 Low

14. Dist line-ending check aborts on the repo root 🟡 Low 🐞 Bug ☼ Reliability
Description
dist_checkout_check.py --package . now finds the repository's own .gitattributes (which has
linguist-generated rules) at the package root. stage_tree raises "package .gitattributes differs
from dist.gitattributes" whenever that file is not byte-identical to
tools/assets/dist.gitattributes (two lines). The --source-tree exemption only applies when no
.gitattributes exists, so this CI step fails on every run. If it got further, it would also stage
.venv/, tools/ and the rest of the repo as if they were dist contents.
Code

.github/workflows/ci.yml[56]

+        run: uv run --frozen tools/dist_checkout_check.py --package . --source-tree
Relevance

● Weak

Closely matching root-staging and .gitattributes findings were explicitly rejected in PR #110.

PR-#110

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The root .gitattributes adds linguist-generated lines, while dist.gitattributes holds only `*
text=auto eol=lf and *.png binary. stage_tree` raises on any mismatch whenever the tree carries
its own attributes file.

tools/dist_checkout_check.py[97-142]
.gitattributes[1-20]
tools/assets/dist.gitattributes[1-2]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Running the dist checkout check with `--package .` picks up the repo `.gitattributes` and the whole repo tree, and fails the attributes equality check.

## Fix Focus Areas
- .github/workflows/ci.yml[54-56]
- tools/dist_checkout_check.py[97-142]

## Recommended Fix
Stage the package file list into a temp dir, mirroring publish-dist: copy the files and add `tools/assets/dist.gitattributes`. Then run the check on that dir without `--source-tree`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


15. Cross-platform determinism check always diverges 🟡 Low 🐞 Bug ☼ Reliability
Description
The upload step now sends path: ./ with include-hidden-files: true, so each OS leg uploads the
whole workspace, including the uv-created .venv/, .pytest-tmp, .git contents and repo tooling.
verify-determinism hashes these trees file by file. The Windows .venv (Scripts/*.exe) and Linux
.venv (bin/) can never match, so the job fails regardless of whether the converter is
deterministic.
Code

.github/workflows/ci.yml[R131-132]

+          path: ./
          include-hidden-files: true
Relevance

● Weak

The identical whole-workspace artifact finding was explicitly rejected in PR #110.

PR-#110

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
tree_hash covers every file under the artifact except provenance. Platform-specific virtualenv
files and other workspace contents are now part of the artifact.

.github/workflows/ci.yml[126-170]
pyproject.toml[25-28]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The artifact upload now covers the whole workspace, so the determinism comparison includes platform-specific `.venv` and tooling files.

## Fix Focus Areas
- .github/workflows/ci.yml[127-135]

## Recommended Fix
List the package paths explicitly in `path:` (plugin.json, skills/, config/, assets/, README.md, after-install.md, LICENSE, .build-provenance.txt), or stage them into a dedicated directory and upload that.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗



Context sources
✅ Cross-repo context — repo relationships
  Explored: repo: iap/hermes-agent (sha: 9bcffa29) — View relationship
Review mode: Auto: 🚀 Fast: Localized repository metadata change with no runtime behavior or meaningful blast radius.

⚠️ Warning | Comment size exceeded, non finding content trimmed Learn more

Powered by Qodo

```

Strengthen when the loose type forces a lie at a use site. The tells are `!`, `arr[0] as T`, and a "should never happen" throw:
Strengthen when the loose type forces a lie at a use site. The tells are non-null assertions, `arr[0] as T`, and a "should never happen" throw:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 High

5. Generated typescript guidance can drift from its converter 📎 Requirement gap ⚙ Maintainability

patterns.md changes the warning by hand, but tools/convert.py has no anchored transform or
audited provenance entry for the phrase. When CI, publish-dist, or release rebuilds from the pinned
source, the root-mode copy replaces skills/ with upstream content, restoring the ! phrase that
triggers Hermes’ inline-shell DSL and causing the tracked-file check to fail.
Agent Prompt
## Issue description
The generated TypeScript reference was hand-edited to remove a phrase that triggers Hermes’ inline-shell DSL. Rebuilds from the pinned source restore that phrase because the converter does not implement or audit the adaptation.

## Fix Focus Areas
- skills/typescript-best-practices/references/patterns.md[94-94]
- tools/convert.py[1750-1767]
- .build-provenance.txt[8-33]

## Recommended Fix
Add an exact, anchor-audited transform in `convert.py` that replaces the upstream text ``The tells are `!`, `arr[0] as T`,`` with ``The tells are non-null assertions, `arr[0] as T`,``. Record a `fixes:` entry in `.build-provenance.txt`, rebuild from pin c47b128, and commit the generated output. Keep the remainder of the warning, the cast example, and the TypeScript samples byte-for-byte unchanged. Add a validator check that fails when a `!` code span is followed by another backtick span in skill content.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

```

Strengthen when the loose type forces a lie at a use site. The tells are `!`, `arr[0] as T`, and a "should never happen" throw:
Strengthen when the loose type forces a lie at a use site. The tells are non-null assertions, `arr[0] as T`, and a "should never happen" throw:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 High

1. The inline-shell fix has no parser-safety proof 📎 Requirement gap ⛨ Security

tools/validate.py only parses the YAML manifest and checks package layout, with no cases for
accidental prose, intentional inline-shell syntax, TypeScript postfix assertions, or isolated
operator mentions. A validation run therefore cannot demonstrate that the original phrase reaches
the real parser without execution while the adapted phrase does not.
Agent Prompt
## Issue description
The PR adapts a phrase that reportedly triggers Hermes inline-shell parsing, but the validator and test changes provide no parser proof or execution guard for the affected content.

## Fix Focus Areas
- skills/typescript-best-practices/references/patterns.md[94-94]
- tools/validate.py[159-177]
- tools/tests/test_bans.py[16-24]

## Recommended Fix
Add validator tests covering accidental prose, intentional inline-shell DSL, ordinary TypeScript postfix assertions, and an isolated operator mention. Invoke the real upstream parser on the original and adapted phrases, assert only the original matches, and ensure the proof uses a harmless stub or equivalent guard so no command can execute.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread tools/validate.py Outdated
Comment on lines +159 to +161
p = pkg / "plugin.yaml"
if not p.is_file():
p = pkg / "plugin.yaml"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 High

2. Rebuilds leave published metadata stale 🐞 Bug ≡ Correctness

check_manifest() now reads plugin.yaml, but convert.py still generates plugin.json and does
not regenerate the checked-in YAML file. On a root rebuild, validation and publication consume the
old YAML metadata even if the pinned upstream manifest changes; a build into a fresh directory
instead fails validation because YAML is absent.
Agent Prompt
## Issue description
The converter writes `plugin.json`, while the validator and publisher consume an unrelated, checked-in `plugin.yaml`.

## Fix Focus Areas
- tools/validate.py[158-173]
- tools/convert.py[1805-1809]
- .github/workflows/publish-dist.yml[49-52]

## Recommended Fix
Use the same Hermes-supported manifest file for conversion, validation, and publication. Verify both a fresh-directory build and a root rebuild after changing upstream manifest metadata.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread .github/labeler.yml Outdated
pstack-core:
- changed-files:
- any-glob-to-any-file: "pstack/plugin.json"
- any-glob-to-any-file: "pstack/plugin.yml"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium

8. Package changes lose their review labels 🐞 Bug ⚙ Maintainability

The labeler's manifest glob now names pstack/plugin.yml, while the migrated manifest is
plugin.yaml at the repository root and the other package globs still start with pstack/. When a
later pull request changes root skills, config, or the manifest, the corresponding package, skills,
and principles labels do not match.
Agent Prompt
## Issue description
The automatic package labels still point to deleted subdirectory paths and a nonexistent manifest name.

## Fix Focus Areas
- .github/labeler.yml[8-19]

## Recommended Fix
Match the root manifest and root `config/**` and `skills/**` paths, including the principles subset. Verify label matches against representative changed-file paths.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread .github/workflows/release.yml Outdated
Comment on lines 61 to 63
cp -a plugin.yaml skills config assets README.md after-install.md LICENSE .build-provenance.txt "$RUNNER_TEMP/release-built"
rm -f "$RUNNER_TEMP/release-built/.build-provenance.txt"
diff -qr "$RUNNER_TEMP/release-built" "$published"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 High

3. Release workflow fails before publishing 🐞 Bug ☼ Reliability

The release verification step runs cp -a with multiple sources but never creates its destination,
$RUNNER_TEMP/release-built; unlike the previous single-source copy, this requires an existing
directory. On a fresh runner, cp fails under set -euo pipefail, so tagged releases stop before
the comparison, ZIP creation, or GitHub release.
Agent Prompt
## Issue description
Release verification copies multiple package entries into `$RUNNER_TEMP/release-built` without creating that directory first, causing the release job to stop before comparison and packaging.

## Fix Focus Areas
- .github/workflows/release.yml[60-63]

## Recommended Fix
Add `mkdir -p "$RUNNER_TEMP/release-built"` before the copy, and include the real manifest (`plugin.json`) in the source list. Run the verification script with a fresh temporary directory to confirm the copy and subsequent steps succeed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread .github/workflows/ci.yml
env:
UPSTREAM_CLONE: ${{ steps.build.outputs.upstream-clone-path }}
PACKAGE_PATH: pstack
PACKAGE_PATH: .

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 High

6. Ci reproducibility gate can never pass 🐞 Bug ☼ Reliability

With PACKAGE_PATH: ., hash_git_tree() runs git ls-tree -r HEAD -- . and hashes the entire
committed repository, while hash_dir_tree() hashes only the converter output, which contains
plugin.json rather than plugin.yaml. On a clean PR or push run, tracked tooling, workflows, and
documentation have no counterpart in the rebuild, so the comparison fails on both OS legs regardless
of package contents.
Agent Prompt
## Issue description
The reproducibility gate compares a whole-repository committed-tree hash with a package-only rebuild hash, causing clean runs to fail.

## Fix Focus Areas
- .github/workflows/ci.yml[64-105]

## Recommended Fix
Enumerate the same explicit package paths on both sides (`plugin.json`, `skills`, `config`, `assets`, `README.md`, `after-install.md`, and `LICENSE`), excluding `.build-provenance.txt`. Pass the committed package paths to `git ls-tree -r HEAD -- <paths>`, account for the `plugin.yaml`/`plugin.json` name difference, and normalize names identically before hashing the corresponding rebuilt paths. Exercise the gate on an otherwise clean checkout.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread tools/convert.py
# cron/loop jobs in Phase 4.
agents_n = copy_tree(source / "agents", out / "agents", st)
comment_sicko = out / "agents" / "comment-sicko.md"
comment_sicko = source / "agents" / "comment-sicko.md"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium

9. Comment sicko reference can ship with crlf 🐞 Bug ≡ Correctness

comment_sicko is now read from the upstream source and written with
write_bytes(comment_sicko.read_bytes()), skipping copy_file/normalize_text. Before, it came
from the normalized out/agents copy. On a checkout with core.autocrlf=true (the Windows CI leg;
the provenance shows this build fixed 124 CRLF files),
skills/no-comments/references/comment-sicko.md keeps CRLF/BOM, which fails check_encoding and
diverges from the Linux build.
Agent Prompt
## Issue description
The Comment Sicko persona is copied byte-for-byte from the source, with no LF/BOM normalization.

## Fix Focus Areas
- tools/convert.py[1764-1771]

## Recommended Fix
Replace the `write_bytes(comment_sicko.read_bytes())` call with `copy_file(comment_sicko, no_comments_refs / "comment-sicko.md", st)`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread tools/convert.py Outdated
import argparse
import hashlib
import json
import yaml

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium

10. Lint fails on an unused import in the converter 🐞 Bug ⚙ Maintainability

import yaml was added to convert.py among the stdlib imports but is never used, since the
converter still emits JSON. Ruff's select = ["E4","E7","E9","F","I","UP","B"] flags it as F401
(unused) and I001 (third-party import inside the stdlib block), so the ruff check tools CI step
fails.
Agent Prompt
## Issue description
An unused third-party import in the stdlib block breaks ruff (F401, I001).

## Fix Focus Areas
- tools/convert.py[33-42]

## Recommended Fix
Delete `import yaml` from `tools/convert.py`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread tools/bans.py Outdated
VOCAB_EXEMPT_PREFIXES: tuple[str, ...] = ("agents/", ".cursor-plugin/", ".build-provenance.txt")
GENERATED_DEPENDENCY_DIRS: frozenset[str] = frozenset({"node_modules"})
VOCAB_EXEMPT_PREFIXES: tuple[str, ...] = (".build-provenance.txt",)
GENERATED_DEPENDENCY_DIRS: frozenset[str] = frozenset({"node_modules", "tools", "docs", ".github"})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium

11. Security ban scan skips any tools or docs folder 🐞 Bug ⛨ Security

is_generated_dependency_path() treats tools, docs, and .github as generated dependency
directories wherever they appear in a path, rather than exempting only repository-level directories.
When recursively copied upstream skills contain paths such as skills/<name>/tools/install.sh or
skills/<name>/docs/reference.md, those packaged files bypass security-ban checks in validation and
the scanner gate, as well as encoding and conflict-marker checks.
Agent Prompt
## Issue description
Directory-name exemptions for `tools`, `docs`, and `.github` also suppress checks of files inside packaged skills.

## Fix Focus Areas
- tools/bans.py[32-57]

## Recommended Fix
Keep `GENERATED_DEPENDENCY_DIRS = {"node_modules"}` and add a separate `EXEMPT_TOP_LEVEL_DIRS = {"tools", "docs", ".github", ".git", ".venv"}` that applies only when `rel.parts[0]` matches. Add a regression case proving nested skill references remain in the scanned file set. Consider running the scan on the package file list rather than the repository root.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread LICENSE Outdated
Comment on lines -24 to -27

Port modifications for the Hermes Agent platform (converter, validator, CI,
fork patches, discovery and delegation rewrites):
Copyright (c) 2026 the pstack-hermes-port contributors

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium

12. Port contributors' copyright removed from license 🐞 Bug ⚙ Maintainability

Because DEFAULT_OUT is now the repo root, the converter's generated LICENSE (upstream MIT plus
ADAPTATION_LINE) overwrote the repository LICENSE. The paragraph granting "Copyright (c) 2026 the
pstack-hermes-port contributors" for the converter, validator, CI and fork patches is gone. The
repo's own hand-written tooling now carries only the upstream author's notice, and any future manual
restore would be wiped on the next rebuild.
Agent Prompt
## Issue description
The in-place root build overwrites the repository LICENSE and drops the port contributors' copyright.

## Fix Focus Areas
- tools/convert.py[1812-1822]
- LICENSE[21-27]

## Recommended Fix
Have the converter append the port-modifications copyright paragraph after `ADAPTATION_LINE` so the generated LICENSE keeps it, then rebuild.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread AGENTS.md
|---|---|---|
| `pstack/` | **generated** (`linguist-generated`) | never hand-edit; review as build output |
| `pstack/.cursor-plugin/`, `pstack/agents/` | generated; inert on hermes | dual-load surface; leave as-is |
| `agents/` | generated; inert on hermes | agent personas; leave as-is |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium

13. Agent rules contradict the new root layout 🐞 Bug ⚙ Maintainability

AGENTS.md still tells agents that pstack/ is the generated never-hand-edit tree and that agents/
is generated and should be left as-is. Now the generated tree is skills/, config/, etc. at the
root, and validate.py fails if agents/ exists. The PR also deletes the hard rules "Anchors
audited", "Converter changes are tracked in issues" and "Excluded upstreams stay excluded" and
leaves a dangling "this migration merges." fragment, so agents lose the guardrail against
hand-editing generated skills (the exact mistake in this PR).
Agent Prompt
## Issue description
Agent-governing docs reference the old `pstack/` and `agents/` layout and drop the rules that prevent hand-editing generated content.

## Fix Focus Areas
- AGENTS.md[130-140]
- AGENTS.md[183-192]

## Recommended Fix
Mark the root `skills/`, `config/`, `assets/`, `plugin.json`, `README.md`, `after-install.md`, `LICENSE` and `.build-provenance.txt` as generated (never hand-edit). Remove the `agents/` row. Restore the Anchors-audited, converter-change-tracking and excluded-upstreams rules, and fix the dangling sentence.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread plugin.yaml Outdated
Comment on lines +1 to +2
$schema: https://agent-plugins.org/schemas/1.0.0/plugin.schema.json
name: pstack

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 High

4. Hermes cannot install the plugin 🔗 Cross-repo conflict ≡ Correctness

The root plugin.yaml sends this skills-only package through Hermes’ native plugin loader, which
requires a loadable entry point, while the portable skills loader expects a root plugin.json.
Installs from the checked-in root, published dist tree, or release ZIP cannot register the skills;
even if conversion adds plugin.json, the root YAML takes precedence and reaches the same
native-loader failure.
Agent Prompt
## Issue description
The skills-only package is published with a root `plugin.yaml`, which selects Hermes’ native plugin loader rather than the portable loader that discovers skills through `plugin.json`. The converter still generates JSON, but publication omits it, and keeping YAML alongside it would still select the wrong loader.

## Fix Focus Areas
- plugin.yaml[1-18]
- tools/convert.py[1805-1809]
- tools/validate.py[158-176]
- tools/validate.py[301-303]
- .github/workflows/publish-dist.yml[49-53]
- .github/workflows/release.yml[61-69]

## Recommended Fix
Remove the root `plugin.yaml` and commit the converter-generated root `plugin.json`. Restore JSON parsing in `check_manifest` and `check_layout`, remove the unused `yaml` import, and make dist publishing and release copy and ZIP lists include `plugin.json` instead of `plugin.yaml`. Test a normal Hermes install without force and confirm skill discovery from the exact published tree.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 8c19fa4

@iap iap closed this Oct 31, 2026
@iap
iap force-pushed the fix/ts-pattern-inline-shell-v2 branch from 8c19fa4 to 336cc57 Compare October 31, 2026 15:09
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 336cc57

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Documentation principles Principle skill changes pstack-core Core manifest/config changes skills Workflow/mode skill changes tooling Converter, validator, CI tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant