Skip to content

pstack: in Claude Code, poteto-mode cites principles without reading their SKILL.md files #726

Open

Description

@boom-bang

Problem

In Claude Code, /pstack:poteto-mode runs almost never read the files that the skill tells the agent to read. SKILL.md line 11 says to read docs/harness/claude-code.md once per session. Line 17 says to cite only principles whose leaf SKILL.md the agent read this session. The agent skips both reads. It then does one of two things:

  • It names principles from the inline index without reading them. That breaks the "cite only what you read" rule.
  • It names no principles at all, so the Principles section has no visible effect.

From the user's side, poteto-mode follows its principles on some days and ignores them on others.

Evidence

I audited 18 poteto-mode runs across 4 Claude Code sessions (pstack 0.15.25 and 0.15.27, Claude Code 2.1.304, Opus 5.5):

  • Every run injected the full skill body, so the skill loaded correctly.
  • The agent read docs/harness/claude-code.md in 1 run.
  • The agent read a principle-*/SKILL.md file in 0 runs and a playbook file in 0 runs.
  • One session named principles in its replies anyway. The other three named none.
  • One run spawned general-purpose where the adapter maps delegates to pstack:poteto-agent.

poteto-mode, poteto-agent, and the principle-* skills are identical in 0.15.25 and 0.15.27, so the version change did not cause this.

All 24 principle-* skills set disable-model-invocation: true, so the Skill tool refuses them. The only way to load a principle file is to Read it by path. The current wording states the citation rule but never makes the read a step, so the agent treats the inline index as enough.

Proposed fix

Make the reads an explicit first step in the Non-negotiables:

-The Principles section below grounds every trigger. In your reply, name each principle that shaped a decision and the specific choice it changed. Cite only principles whose leaf SKILL.md you read this session.
+The Principles section below grounds every trigger. Before your first reply in a run, `Read` the adapter above if you have not this session, then `Read` `../principle-<name>/SKILL.md` for each principle you expect to shape a decision. The index below is a pointer, not a substitute. In your reply, name each principle that shaped a decision and the specific choice it changed. Cite only principles whose leaf SKILL.md you read this session.

The adapter clause applies only in Claude Code, because line 11 scopes the adapter to Claude Code. In Cursor the change adds only the leaf read, which line 17 already requires.

Test

I applied the patch locally to 0.15.27 and ran:

claude -p "/pstack:poteto-mode avg() in stats.py crashes on an empty list. Propose a fix, don't edit files."

The agent read docs/harness/claude-code.md, then principle-fix-root-causes/SKILL.md and principle-boundary-discipline/SKILL.md. Its reply named both principles and said what each one changed. That is one run, not a benchmark.

Related

Activity

  1. boom-bang commented on Oct 19, 2026

    @boom-bang
    Author

    Tested the proposed sentence against two alternatives on omp, which shares the skill body and the disable-model-invocation leaves. The sentence helps a little. Putting the principle list inside each playbook helps far more.

    Setup

    • 5 arms, 12 prompts, 6 repeats each, 72 runs per arm, shuffled order. Every run had its own agent dir, session dir and copy of the fixtures.
    • pstack 0.15.28. The skill message sent to the model is byte-identical to what omp injects for /skill:poteto-mode (checked on a real session record, 20,703 characters).
    • Prompts are small read-only tasks (bug, feature, refactor, perf, design, tests, review, investigation). "Read a principle" means a read tool call on a principle-* skill file, and it matches a raw grep of the tool calls with 0 mismatches.
    • Pre-registered primary metric: at least one principle file read. Contrasts against base use Fisher exact with a Bonferroni threshold of 0.025.

    Arms

    Arm Change
    base 0.15.28 as shipped
    patched the sentence from this issue, applied to line 17
    checklist a numbered "Before your first reply" block (read the playbook, read principles, open the todolist)
    chain skill body reduced to one line ("read the playbook first, cite only what you read"). Each playbook opens with an unconditional list of the principle skills to read.
    gate omp extension that blocks every tool except playbook and principle reads until one principle is read. Upper bound only.

    Results (all 72 runs per arm)

    Arm Read a principle Cited a principle it never read Mean tool calls
    base 0/72 3 3.5
    patched 7/72 (p=0.013 vs base) 0 3.8
    checklist 27/72 12 5.4
    chain 68/72 (p<0.0001 vs checklist) 4 6.8
    gate 71/72 2 6.8
    • Base never read a principle in 72 runs, which agrees with the audit in this issue.
    • The patched sentence moved 7 of 72 runs, on 5 of 12 prompts. It hurt on none.
    • The checklist read the playbook in 72/72 runs, but only 27/72 read a principle and 12/72 called todo. Compliance fell with each added step.
    • The checklist's conditional wording ("for every principle you expect to shape a decision") failed mostly through the investigation playbook, which names no principles. Of 43 checklist runs that opened it, 8 read one. The bug-fix, feature and refactoring playbooks name principles, and those runs read far more often.
    • Chain beat checklist on 10 of 12 prompts, tied on 1 and lost on 1 (sign test p=0.012). That check treats each prompt as one unit, because repeats on the same prompt are not independent.
    • Chain and gate are indistinguishable (68 vs 71, p=0.37). A plain unconditional instruction in a file the model always opens matches a hard block.

    What this does not show

    • 4 chain runs read no principle. Three ended after 2 to 3 tool calls, and none was blocked. Reaching 72/72 is not realistic with text alone, and a gate cannot force a model to make a call either (one gate run made zero).
    • Reads are not quality. Nobody graded whether replies improved. Chain replies are about 25% longer.
    • Cited-but-unread principles are not eliminated. Chain had 4 and base had 3.
    • One model (Sonnet via omp), headless, tiny fixtures. This issue's audit used Claude Code with Opus. The adapter clause in the proposed sentence applies only in Claude Code and was read in 2 of 72 patched runs, so that half is essentially untested here.
    • 7 chain and gate runs have no final message in the session record. The table above uses all 72 runs and takes the reply text from stdout, so none were dropped.
    • The principle lists I put in the playbooks are my choices (for example investigation reads prove-it-works and attack-the-premise). Other lists were not tried.

    Suggested fix

    Instead of, or alongside, the sentence in this issue:

    1. Add an unconditional "Before step 1, Read these principle skills" line at the top of each playbook, naming that playbook's principles.
    2. Reduce the skill body line to "Read the playbook before anything else. Cite only principles whose SKILL.md you read."
    3. Add a small check that every principle-* named in a playbook exists under skills/, so the lists cannot rot.

    This is a few lines in six playbook files and needs no hook, so it works on every harness. It still needs a retest on Claude Code with Opus before anyone calls it a fix. The harness, per-run sessions and scoring scripts are local and I can share them.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions