psalm-repro
Skill5.9k starsChanged yesterdayMITView on GitHub
Use when reproducing a Psalm bug from the CLI, showing a test fails on the base branch, comparing behaviour between a branch, master, 6.x or an old release (e.g. 7.0.0-beta19), or measuring Psalm's speed and memory (self-analysis, WordPress taint benchmark).
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 49
Run each worktree's ./psalm on the same scratch project and diff the outputs.
- Very specific: line 50
Always cd <worktree> && in the same command.
- Distinctive: line 71
Treat a big jump as a regression worth reporting.
- Distinctive: line 72
Run measurements twice, on an idle machine (on a laptop, on AC power: see the platform table in CLAUDE.md), and never alongside another …
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLI repros, version comparisons and measurements
Scratch-project repro
Make a fresh dir in the scratchpad with a
src/and a minimalpsalm.xml:<?xml version="1.0"?> <psalm errorLevel="1" findUnusedCode="false" findUnusedVariablesAndParams="false"> <projectFiles><directory name="src"/></projectFiles> </psalm>- Extension stubs (mongodb, …) need
<enableExtensions><extension name="mongodb"/></enableExtensions>. - A stubbed library goes in
vendor/+<extraFiles>, never in<projectFiles>: stubs don't override project-dir classes. - For taint modes see skill
taint-analysis.
- Extension stubs (mongodb, …) need
- Run
cd <dir> && php /path/to/worktree/psalm --no-cache --output-format=compact(or-c <dir>/psalm.xml --root=<dir>). SuppressClassMustBeFinalnoise. lsthe repro files first: an unmatched glob can abort the rest of the command (zsh) or be passed on literally so the command acts on a nonexistent path (bash), and a missing file looks exactly like "no issue". Empty output means Psalm didn't run.- Grep both
^ERRORand^SECURITY(taint issues), and watch for crashes (exit 11).
To show a new test fails on the base branch, either use a CLI repro or run just that
one test case with phpunit in a base worktree (--filter 'testValidCode@caseName', or
tests/Taint --filter '@caseName' for TaintTest; see CLAUDE.md). Never run the whole
test file.
Comparing versions
- Reference points:
origin/master,origin/6.x, and 7.0.0-beta19, the last release of the eager template model, which is the bar for regressions since type variables (#11875). git worktree add /tmp/psalm-<ref> <ref>, then give it a vendor:cp -R vendor /tmp/psalm-<ref>/(never a symlink: composer's PSR-4 autoloader resolvesPsalm\through the real path and loads the main checkout's classes, "Cannot redeclare class");- or
composer installin the worktree if it will run phpunit, if the mainvendor/may be stale, or for 6.x (its dependencies differ); - bin/ci/test-with-real-projects.sh needs
composer install --no-dev.
- Run each worktree's
./psalmon the same scratch project and diff the outputs. - Always
cd <worktree> &&in the same command. Don't usegit stashto get a "without the change" build: usegit diff > f.patch && git apply -R f.patch, or a second worktree. - For behaviour-preserving refactors, diff full
--monochromeoutput (traces included) before and after.
Measuring time and memory
- "used N MB of memory" is
memory_get_peak_usage()of the main process only. Taint resolution runs there after the workers merge, so it tracks taint cost. For total RSS, wrap./psalmitself (nottimeout) in/usr/bin/time -lon macOS (bytes) or/usr/bin/time -von Linux (kbytes; GNUtime, not the shell builtin). - Self-analysis:
./psalm --no-cachewithpsalm.xml.dist(taint on). Don't pass--threads: Psalm detects the CPU count itself. To measure without taint, setrunTaintAnalysis="false"; removing the attribute isn't enough, it defaults to true. Expect two ComplexMethod errors to appear then, since they depend on taint edges. - Reference numbers (Apple Silicon Mac, 18 GB RAM, 12 CPUs, measured with
--threads=8): 7.0.0-beta24 20 s / 1.2 GB; 6.x ~9 s / 0.43 GB; master mid-October 2026 ~27 s / 2.7 GB with taint, ~15 s / 0.6 GB without. Times don't transfer to other machines; on a different one, measureorigin/masteras the baseline in the same session. Memory figures transfer roughly. Treat a big jump as a regression worth reporting. - Run measurements twice, on an idle machine (on a laptop, on AC power: see the platform table in CLAUDE.md), and never alongside another self-analysis. With swap nearly full, master's self-analysis doesn't finish at all.
- Taint benchmark corpus: a WordPress core clone (errorLevel 8,
allFunctionsGlobal) with--taint-analysis --long-progress. Expect about ±12 findings of run-to-run variance frommt_rand()condition ids inAlgebra::negateFormula()/ CallAnalyzer, even single-threaded.
Reading CI logs
gh run view <id> --log-failed. Usegh run list --commit <sha>rather than--branch, which can be stale.- CircleCI
test-with-real-projects: read the failing action'soutput_urlfrom the v1.1 API (/project/gh/<owner>/psalm/<build>).
In this repository8 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- hack-conformanceSkill
- merge-6x-into-masterSkill
- plugin-api-bcSkill
- pr-descriptionSkill
- purity-capabilitiesSkill
- taint-analysisSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

