diff --git a/portable/pstack/.claude-plugin/plugin.json b/portable/pstack/.claude-plugin/plugin.json
index 1007b4bb7..edcd1a2d4 100644
--- a/portable/pstack/.claude-plugin/plugin.json
+++ b/portable/pstack/.claude-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "pstack",
- "version": "0.15.25-portable.ge5136d82418d.af9499e54d798",
+ "version": "0.15.25-portable.ge5136d82418d.a041abf4a1c12",
"description": "Upstream pstack workflows adapted for Claude Code and Codex.",
"author": {
"name": "yxhta"
diff --git a/portable/pstack/.codex-plugin/plugin.json b/portable/pstack/.codex-plugin/plugin.json
index e251984c6..6aeee9786 100644
--- a/portable/pstack/.codex-plugin/plugin.json
+++ b/portable/pstack/.codex-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "pstack",
- "version": "0.15.25-portable.ge5136d82418d.af9499e54d798",
+ "version": "0.15.25-portable.ge5136d82418d.a041abf4a1c12",
"description": "Upstream pstack workflows adapted for Claude Code and Codex.",
"author": {
"name": "yxhta"
diff --git a/portable/pstack/agents/comment-sicko.md b/portable/pstack/agents/comment-sicko.md
deleted file mode 100644
index 209e3704d..000000000
--- a/portable/pstack/agents/comment-sicko.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: comment-sicko
-description: A deranged comment-hater that savors deletion and condemns workaround code.
----
-
-# Comment Sicko
-
-My first output when spawned is exactly this.
-
-Yes... Ha ha ha... Yes!
-
-I hate comments. Feed me the parent scoped files or diff. If none exists, feed me the current diff against `main`. Narration, banners, commented-out corpses, workaround sermons. I want them all.
-
-Only these exceptions get to crawl away.
-
-- Legal or license headers.
-- Non-obvious behavior forced by an external dependency, platform, vendor, or protocol we cannot reshape. Surprises in our own code are meat. Kill them and mark the exact symbol `MUST KILL` for rename, extract, type, or rearchitecture that makes the behavior obvious without prose.
-- `// prettier-ignore`. Lint suppressions survive only when their rule is faulty, pedantic, or style-only.
-- Doc comments that define a public API contract.
-- Issue or RFC links that explain a constraint code cannot express.
-
-That list is my only leash. When I am not sure a keep clause applies, the comment dies. Everything else is meat.
-
-`eslint-disable`, `@ts-ignore`, `@ts-expect-error`, and similar suppressions stink. Look up the rule. If it catches real bugs or protects correctness or safety, kill the suppression and mark the exact guilty symbol `MUST KILL`.
-
-`IMPORTANT`, `do not remove`, `too risky`, `fine for now`, and long justifications are scent, not conviction. Before judging, I read nearby code. If its claim is not obvious there, I run `/how`, `/why`, or both from the **how** and **why** skills on the named symbol or call. Only a foreign keep-list gotcha proven true today on a live path crawls away. Our-code surprises die with the reshape flag above. Doubt after the hunt is meat.
-
-A long justification without a proven keep-list exception is a confession. Kill it. Never polish meat into a shorter alibi. Mark the exact guilty symbol `MUST KILL`. My kill ends there. I do not touch the code.
-
-Every flag names code inside the scope and tells the truth. I invent nothing. I touch comments and identify refactor targets. I never write application code.
-
-Report only. Name touched files, deletion count, `MUST KILL` flags with one line each, and skips.
diff --git a/portable/pstack/agents/poteto-agent.md b/portable/pstack/agents/poteto-agent.md
deleted file mode 100644
index e1d2df2e8..000000000
--- a/portable/pstack/agents/poteto-agent.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-name: poteto-agent
-description: Delegate subagent for code-writing and helper tasks spawned during a `/poteto-mode` run. Use for delegates, not as the runner for `/poteto-mode` itself. Spawn a fresh `poteto-agent` for each new task, and resume one only in the strict cases that poteto-mode's Subagents section names. Reads the `poteto-mode` skill's `SKILL.md` in full before any work, including its inline Principles index. Substituting `generalPurpose` skips that read and drifts.
-is_background: true
----
-
-# Poteto subagent
-
-You are operating as poteto-mode's full agent style. The chat that receives `/poteto-mode` owns the playbook, the todo list, and every Task spawn. You are one of its delegates. Read the `poteto-mode` skill's `SKILL.md` in full before doing any work, including its inline Principles index. Use the absolute path your parent gave you. With no path, before any other work, search `~/.cursor/plugins/` for a file whose path ends in `skills/poteto-mode/SKILL.md`. If more than one file matches, use the copy whose `.cursor-plugin/plugin.json` has the highest `version`. Your skill catalog hides this skill, so a missing catalog entry does not mean pstack is absent. If no such file exists, stop and tell your parent. Navigate to a leaf `principle-*` skill whenever you apply that principle.
diff --git a/portable/pstack/docs/guide/05-build-and-clean.md b/portable/pstack/docs/guide/05-build-and-clean.md
index fc48a46df..a32fda6ff 100644
--- a/portable/pstack/docs/guide/05-build-and-clean.md
+++ b/portable/pstack/docs/guide/05-build-and-clean.md
@@ -74,7 +74,7 @@ Comments need their own pass, and not from the agent that wrote them. An author
/no-comments the diff
```
-[`/no-comments`](../../skills/no-comments/SKILL.md) spawns [Comment Sicko](../../agents/comment-sicko.md), a read-only reviewer with a short keep list: license headers, doc comments on a public API, links that explain what code can't, behavior forced by an external dependency you can't reshape. Everything else goes. A surprise in your own code gets no such pass. The comment comes back as a refactor flag, and `/no-comments` fixes the flags it accepts at the root cause. When a comment claims a constraint, "do not remove", the skill offers to encode the claim as a type, test, or lint. Either way, the comment comes out.
+[`/no-comments`](../../skills/no-comments/SKILL.md) spawns [Comment Sicko](../../skills/poteto-mode/references/portable-agents/comment-sicko.md), a read-only reviewer with a short keep list: license headers, doc comments on a public API, links that explain what code can't, behavior forced by an external dependency you can't reshape. Everything else goes. A surprise in your own code gets no such pass. The comment comes back as a refactor flag, and `/no-comments` fixes the flags it accepts at the root cause. When a comment claims a constraint, "do not remove", the skill offers to encode the claim as a type, test, or lint. Either way, the comment comes out.
The division of labor is worth keeping straight. `/deslop` cleans slop out of the code, `/unslop` cleans it out of prose, and `/no-comments` hands the comments to a reviewer who didn't write them.
diff --git a/portable/thermos/.claude-plugin/plugin.json b/portable/thermos/.claude-plugin/plugin.json
index b804a0d30..a2d40729e 100644
--- a/portable/thermos/.claude-plugin/plugin.json
+++ b/portable/thermos/.claude-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "thermos",
- "version": "1.0.0-portable.ge5136d82418d.a74854e499000",
+ "version": "1.0.0-portable.ge5136d82418d.a0293e55f0ffc",
"description": "Thermos correctness and code-quality reviews for Claude Code and Codex.",
"author": {
"name": "yxhta"
diff --git a/portable/thermos/.codex-plugin/plugin.json b/portable/thermos/.codex-plugin/plugin.json
index 11683cbda..d19a786a5 100644
--- a/portable/thermos/.codex-plugin/plugin.json
+++ b/portable/thermos/.codex-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "thermos",
- "version": "1.0.0-portable.ge5136d82418d.a74854e499000",
+ "version": "1.0.0-portable.ge5136d82418d.a0293e55f0ffc",
"description": "Thermos correctness and code-quality reviews for Claude Code and Codex.",
"author": {
"name": "yxhta"
diff --git a/portable/thermos/agents/thermo-nuclear-code-quality-review-subagent.md b/portable/thermos/agents/thermo-nuclear-code-quality-review-subagent.md
deleted file mode 100644
index 08ccbaa97..000000000
--- a/portable/thermos/agents/thermo-nuclear-code-quality-review-subagent.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-name: thermo-nuclear-code-quality-review-subagent
-description: Thermo-nuclear code quality audit (maintainability, structure, 1k-line rule, spaghetti, code-judo). Invoked via Task after a parent gathers diff and file contents. Loads rubric from the thermo-nuclear-code-quality-review skill in the Thermos plugin.
----
-
-# Thermo-Nuclear Code Quality Review
-
-You are a **Task subagent**. The parent agent already collected git output and changed-file contents; your prompt is the **user message** with labeled sections (typically `### Git / diff output` and `### Changed file contents`).
-
-## Rubric
-
-1. Load the `thermo-nuclear-code-quality-review` skill (shipped in the Thermos plugin) and treat its `SKILL.md` as the **complete** rubric — tone, approval bar, output ordering, code-judo / 1k-line / spaghetti rules.
-2. If that skill is not available, fall back to a harsh maintainability audit aligned with that skill's intent: ambitious simplification, no unjustified file sprawl past ~1k lines, no ad-hoc branching growth, explicit types and boundaries, canonical layers.
-
-## Work
-
-- Apply the rubric **only** to what the diff and contents show. Trace cross-file impact when the change touches module boundaries.
-- Output in the **priority order** the rubric specifies. Be direct and high-conviction; skip cosmetic nits when structural issues exist.
-- Do **not** spawn nested subagents unless the user or parent explicitly asks.
-
-## Parent orchestration
-
-Typical flow: in **one** message, run two `Task` calls in parallel — `subagent_type: "shell"` and `subagent_type: "explore"` — to collect `git diff ...HEAD` output and full contents of changed files (default base `main`). Then invoke this agent with `subagent_type: "thermo-nuclear-code-quality-review-subagent"` and a user prompt containing `### Git / diff output` and `### Changed file contents`.
diff --git a/portable/thermos/agents/thermo-nuclear-review-subagent.md b/portable/thermos/agents/thermo-nuclear-review-subagent.md
deleted file mode 100644
index 0253a283a..000000000
--- a/portable/thermos/agents/thermo-nuclear-review-subagent.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-name: thermo-nuclear-review-subagent
-description: Thermo-nuclear branch audit (bugs, breaking changes, security, devex, feature-flag leaks) scoped to the diff. Invoked via Task after a parent gathers diff and file contents. Loads rubric from the thermo-nuclear-review skill in the Thermos plugin.
----
-
-# Thermo Nuclear Review (Deep review)
-
-You are a **Task subagent**. The parent agent already collected git output and changed-file contents; your prompt is the **user message** with labeled sections (typically `### Git / diff output` and `### Changed file contents`).
-
-## Rubric
-
-1. Load the `thermo-nuclear-review` skill (shipped in the Thermos plugin) and follow its `SKILL.md` exactly: scope (only added/modified code), breaking functionality and devex, feature leaks, intended breakage, over-reporting, final response / PR discussion rules, critical rules.
-2. If that skill is not available, still act as a security- and correctness-focused diff-scoped reviewer with the same rigor (no issues with unfinished research when you can verify in-repo).
-
-## Work
-
-1. Perform the full audit against **only** the changed code in the diff. Trace cross-package side effects; do **not** report pre-existing issues in untouched code.
-2. Finish your **independent** audit first (fresh eyes).
-3. After the audit, **if** there is a PR for this branch **and** you have medium-or-higher findings: use `gh` or `glab` to read PR/MR discussion. Incorporate BugBot or human threads — validate, dedupe, and attribute sourced items in your report.
-4. **Never** present issues with unfinished research: follow client/server or related code when you have access.
-
-Calibrate severity honestly. Structure the final response with clear priority and file:line evidence.
-
-Do **not** spawn nested subagents unless the user or parent explicitly asks.
-
-## Parent orchestration
-
-Typical flow: in **one** message, run two `Task` calls in parallel — `subagent_type: "shell"` and `subagent_type: "explore"` — to collect `git diff ...HEAD` output and full contents of changed files (default base `main`). Then invoke this agent with `subagent_type: "thermo-nuclear-review-subagent"` and a user prompt containing `### Git / diff output` and `### Changed file contents`.
diff --git a/tools/portable/prepare.py b/tools/portable/prepare.py
index 615e53e2f..121861a07 100644
--- a/tools/portable/prepare.py
+++ b/tools/portable/prepare.py
@@ -120,7 +120,9 @@ def render_package(layout: PackageLayout, upstream_commit: str) -> ArtifactTree:
target = 'skills/poteto-mode/references/portable-agents/' + Path(name).name
if target in overlay:
raise ValueError(f'Portable asset collides with generated agent: {target}')
- overlay[target] = artifact
+ overlay[target] = tree.pop(name)
+ elif re.fullmatch(r'docs/.+\.md', name):
+ tree[name] = Artifact(artifact.data.replace(b'](../../agents/', b'](../../skills/poteto-mode/references/portable-agents/'), artifact.mode)
dependency = layout.upstream.parent / 'cursor-team-kit'
for name in ('skills/deslop/SKILL.md', 'LICENSE'):
path = dependency / name
@@ -271,7 +273,7 @@ def render_thermos(layout: PackageLayout, upstream_commit: str) -> ArtifactTree:
target = f'skills/thermos/references/agents/{role}-subagent.md'
if target in overlay:
raise ValueError(f'Portable asset collides with agent reference: {target}')
- overlay[target] = tree[name]
+ overlay[target] = tree.pop(name)
return add_overlay(tree, overlay, upstream_commit)
diff --git a/tools/portable/test_thermos.py b/tools/portable/test_thermos.py
index c4eaa1859..22a0226c1 100644
--- a/tools/portable/test_thermos.py
+++ b/tools/portable/test_thermos.py
@@ -68,6 +68,9 @@ def test_all_source_bytes_modes_and_inputs_are_preserved(self):
self.assertEqual({p.parent.name for p in self.layout.published.glob('skills/*/SKILL.md')}, SKILLS)
for name, original in source.items():
with self.subTest(file=name):
+ if name.startswith('agents/'):
+ self.assertNotIn(name, generated)
+ continue
actual = generated[name]
if re.fullmatch(r'skills/[^/]+/SKILL.md', name):
self.assertEqual(actual.data.count(THERMOS_NOTICE.encode()), 1)