simulation-failure-triage — Claude Code skill: triage failed runs
Sorts out a failed LAMMPS, VASP, QE or MOOSE run and lays out a retry plan that changes one thing at a time.
npx skills add HeshamFS/materials-simulation-skills --skill simulation-failure-triage -a claude-codeWhat simulation-failure-triage does
Reach for this skill the moment a simulation dies or starts acting odd. It reads the failure signature: nonconvergence, NaN/Inf, exploding energy, an unstable timestep, pressure blow-up, a missing potential or pseudopotential, memory exhaustion, a process crash, corrupted output, an incomplete run. You get likely causes, immediate actions, a retry ladder and stop conditions.
Everything runs through scripts/failure_triage.py. Feed it the code, the stage, the symptoms, the last change you made and the log text. Python 3.10+ is required, there are no external dependencies, and it works on Linux, macOS and Windows. Copy your logs and input decks before rerunning anything, or the original failure stops being reproducible.
Each rung of the retry ladder holds one change. Lower the timestep, swap the preconditioner and touch the barostat in the same pass, and the result starts depending on arbitrary stabilizers — that trips a stop condition. Triage only gets the job running again. Conservation checks and physical bounds are somebody else's job: hand off to simulation-validator.
What it helps with
- work out why a run died with NaN or Inf
- tell a setup mistake apart from numerical instability
- keep logs and input decks before rerunning
- pick one change instead of a pile of tweaks
- stop retrying once the result stops meaning anything
Example prompts for the agent
- Triage this LAMMPS crash: symptoms nan,pressure-blowup, I just raised the timestep
- VASP failed with ZBRENT — here's the log, what next?
- The MOOSE job got OOM-killed, build me a retry ladder
How to install simulation-failure-triage
1Skills CLI (Vercel)
npx skills add HeshamFS/materials-simulation-skills --skill simulation-failure-triage -a claude-code2Manually: put the files in place
~/.claude/skills/simulation-failure-triage/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/simulation-failure-triage/
1Skills CLI (Vercel)
npx skills add HeshamFS/materials-simulation-skills --skill simulation-failure-triage -a codex2Manually: put the files in place
.agents/skills/simulation-failure-triage/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add HeshamFS/materials-simulation-skills --skill simulation-failure-triage -a cursor2Manually: put the files in place
.cursor/skills/simulation-failure-triage/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install HeshamFS/materials-simulation-skills simulation-failure-triage2Manually: put the files in place
.github/skills/simulation-failure-triage/SKILL.md1Skills CLI (Vercel)
npx skills add HeshamFS/materials-simulation-skills --skill simulation-failure-triage -a gemini-cli2Platform CLI
gemini skills install https://github.com/HeshamFS/materials-simulation-skills --path skills/robustness/simulation-failure-triageManually: put the files in place
.devin/skills/simulation-failure-triage/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add HeshamFS/materials-simulation-skills --skill simulation-failure-triage -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about simulation-failure-triage
How do I install simulation-failure-triage in Claude Code?
Run npx skills add HeshamFS/materials-simulation-skills --skill simulation-failure-triage -a claude-code. The skill lands at ~/.claude/skills/simulation-failure-triage/SKILL.md.
What does simulation-failure-triage do?
It classifies a simulation failure and returns likely causes, immediate actions, a retry ladder and stop conditions. It is meant as the first response to a failed or suspicious run.
How is it different from simulation-validator?
This skill only restores execution. Conservation, physical bounds and the question of whether the numbers can be trusted belong to simulation-validator.
Source text
SKILL.md · Apache-2.0
---
name: simulation-failure-triage
description: >
First-response triage for cross-code (LAMMPS/VASP/QE/MOOSE) simulation
failures: classifies the failure signature (nonconvergence, NaN/Inf,
exploding energy, unstable timestep, pressure blow-up, missing
potentials/pseudopotentials, memory exhaustion, process crash/segfault,
corrupted output, incomplete runs) and proposes a SAFE one-change-at-a-time
RETRY LADDER with explicit STOP CONDITIONS, prioritizing evidence
preservation. Use as the immediate first response to a failed or suspicious
run. For deep per-stage validation, conservation/physical-bounds checks, and
"can I trust these results" analysis, defer to the simulation-validator skill.
allowed-tools: Read, Bash, Write, Grep, Glob
metadata:
last_deterministic_eval: "2026-10-20"
agent_evaluation_status: "not_revalidated"
author: HeshamFS
standards:
- "SchedMD Slurm sbatch specification (--mem / --mem-per-cpu memory request flags)"
- "POSIX signal semantics (SIGSEGV / signal 11, core dump) for crash classification"
- "GNU GDB, Valgrind, and AddressSanitizer (ASan) memory-fault debugging tools"
- "LAMMPS / VASP / Quantum ESPRESSO / MOOSE solver error diagnostics (e.g. 'Lost atoms', ZBRENT nonconvergence)"
- "Zeller (2009), Why Programs Fail: delta debugging / one-change-at-a-time minimal reproducing case"
version: "1.1.3"
security_tier: high
security_reviewed: true
tested_with:
- claude-code
last_evaluated: "2026-06-23"
eval_cases: 3
last_reviewed: "2026-06-24"
---
# Simulation Failure Triage
## Goal
Classify common simulation failure signatures and return immediate actions, retry ladders, and stop conditions.
## Requirements
- Python 3.10+
- No external dependencies
- Works on Linux, macOS, and Windows
## Inputs to Gather
| Input | Description | Example |
|-------|-------------|---------|
| Code | Simulation code | `LAMMPS`, `VASP`, `MOOSE`, `QE` |
| Stage | Setup, runtime, postprocess | `runtime` |
| Symptoms | Failure signs | `nan,pressure-blowup` |
| Log text or file | Error evidence | `Lost atoms`, `ZBRENT` |
| Recent change | Last modified setting | `larger timestep` |
## Decision Guidance
- First preserve evidence: logs, inputs, executable version, and scheduler output.
- Separate setup errors from numerical instability and physical model issues.
- Retry with a single controlled change.
- Stop retrying when the result becomes scientifically meaningless or a required model input is missing.
## Script Outputs
`scripts/failure_triage.py` emits:
- `likely_causes`
- `immediate_actions`
- `retry_ladder`
- `stop_conditions`
- `evidence`
## Workflow
```bash
python3 skills/robustness/simulation-failure-triage/scripts/failure_triage.py \
--code LAMMPS \
--stage runtime \
--symptoms nan,pressure-blowup \
--recent-change "increased timestep" \
--json
```
## Error Handling
Invalid stages or oversized log files stop with exit code 2. Unknown symptoms are retained as custom evidence.
## Limitations
This skill gives first-response triage. It does not guarantee that a failed simulation can be repaired.
## Verification checklist
- [ ] Recorded the preserved-evidence set BEFORE any rerun: copied logs, input decks, scheduler output, and the executable/version string (per the first `immediate_actions` item) so the original failure is reproducible.
- [ ] Quoted the FIRST warning/error from the run, not just the final crash line, and confirmed `evidence.log_excerpt` (first 500 chars, original casing) captures it; re-run with `--log-file`/`--log-text` if the excerpt misses the root signature.
- [ ] Logged every `likely_causes` entry with its `symptom`, `category`, and `first_action`, and verified no real signature landed in the `category: custom` bucket because its keyword was absent from `LOG_HINTS`/`PATTERNS`.
- [ ] Confirmed the failure category is correct rather than mislabeled: a segfault/SIGSEGV/signal 11/core-dumped maps to `crash` (not `corrupted-output`), and an OOM/`bad_alloc`/`oom-kill` maps to `out-of-memory` (not `incomplete-run`).
- [ ] Applied the `retry_ladder` strictly one change at a time, recording the single parameter changed and its effect at each rung (including the memory rung when memory-bound).
- [ ] Checked every `stop_conditions` entry and halted the retry loop instead of stacking arbitrary stabilizing tweaks when any condition is met (e.g. unverifiable potential/pseudopotential, results dependent on arbitrary stabilizers).
- [ ] After any numerical recovery, handed off to the `simulation-validator` skill for conservation / physical-bounds / "can I trust these results" checks rather than declaring success here.
## Common pitfalls & rationalizations
| Tempting shortcut | Why it's wrong / what to do |
|-------------------|-----------------------------|
| "The last line of the log is the error, so I'll fix that." | The final crash line is often a downstream symptom; the script's second `immediate_actions` item exists because the FIRST warning/error is the real cause. Capture it in `evidence.log_excerpt` and triage from there. |
| "It segfaulted, so it's a corrupted-output / disk issue." | A `crash` (SIGSEGV/signal 11/core dumped) is a memory-fault category pointing at out-of-bounds/null-pointer/ABI bugs and a gdb/valgrind/ASan repro — not I/O. Do not treat it as `corrupted-output`. |
| "The job got killed, so I'll just bump the walltime." | `killed` alone is genuinely ambiguous and stays `incomplete-run`; an OOM signature (`bad_alloc`, `oom-kill`, "out of memory") is a distinct `out-of-memory` cause needing memory reduction / `--mem` increase, not more walltime. |
| "I'll lower dt AND change the preconditioner AND adjust the barostat to get it running." | The retry ladder is one controlled change per rung; stacking fixes makes results "depend on arbitrary stabilizing changes" — an explicit `stop_conditions` trigger. Change one parameter, record its effect, then proceed. |
| "I added the missing PAIR coeff path and it ran, so the physics is fine." | A clean run after fixing `missing-potential`/`bad-pseudopotential` resolves setup, not validity; species mapping, valence, or functional may still be wrong. Run completion is not correctness. |
| "It runs now, triage is done." | Triage only restores execution. Conservation, physical bounds, and convergence are out of scope here — defer to `simulation-validator` before trusting any number. |
## Security
### Input Validation
- `--stage` is checked against a fixed allowlist (`setup`, `runtime`, `postprocess`, `unknown`); any other value exits with code 2.
- `--code` must be non-empty and at most 100 characters; an empty or oversized value exits with code 2.
- `--symptoms` are split on commas and capped at 50 entries, each at most 100 characters; exceeding either limit exits with code 2.
- Unknown symptoms are not rejected; they are retained as `custom` evidence rather than silently dropped.
- There are no numeric arguments, so no finite/positive checks apply.
- All input-validation failures (and log read errors) are caught and exit with code 2 and a stderr message.
### File Access
- The only file read is the optional `--log-file` path; when omitted, the script reads no files.
- Before reading, the log file's size is checked via `stat`; if it exceeds the 10 MB cap (`MAX_LOG_SIZE`) the script raises and exits with code 2. Both file content and `--log-text` are then truncated to 10 MB.
- The script writes no files; all results go to stdout (JSON with `--json`, otherwise plain text).
- Path-sandboxing caveat: the log path is not restricted to a working directory, so the script can read any file the invoking process has permission to read; only pass trusted paths.
### Tool Restrictions
- `allowed-tools` is `Read, Bash, Write, Grep, Glob`.
- `Bash` runs only the bundled `scripts/failure_triage.py`.
- `Read` opens the skill's own files and a user-provided log to inspect failure evidence; `Grep`/`Glob` locate log files, inputs, and prior output; `Write` records triage notes or preserved evidence at the user's direction. The bundled script itself does not write files.
### Safety Measures
- No `eval`/`exec` and no dynamic code execution; log text is treated as data and never run.
- The script spawns no subprocesses and runs no external solvers.
- Output is structured JSON (`--json`), making results machine-checkable.
- DoS caps bound resource use: 10 MB log size/text limit, 50 symptoms, and 100-character limits on `code` and each symptom.
## References
- See `references/failure_patterns.md` for common failure signatures and retry ladders.
## Version History
- 1.1.3: Add `Verification checklist` (evidence-based checks tied to `failure_triage.py` outputs — preserved-evidence set, first-error excerpt, category-mislabel guards, one-change retry ladder, stop conditions, simulation-validator handoff) and `Common pitfalls & rationalizations` table covering last-line-only triage, segfault-as-I/O, OOM-vs-walltime, stacked stabilizing changes, and "it ran so it's valid".
- 1.1.1: Strengthen evals to be discriminating — each case now pins the exact `failure_triage.py` JSON output via `script_checks` (specific `category`/`first_action` strings, log-hint symptom inference, fixed retry-ladder/stop-condition text, recent-change immediate action), so the suite measures the skill's actual output rather than generic triage knowledge.
- 1.1.0: Add dedicated `out-of-memory` and `crash` (segfault) classifications; segfaults and OOM are no longer mislabeled as I/O or interrupted-execution. Preserve original-case log excerpt. Add input-validation caps (symptoms, code length). Sharpen description to defer deep validation to simulation-validator. Fix `missing-potential` eval token.
- 1.0.0: Initial cross-code simulation failure triage skill.
© HeshamFS · Apache-2.0 · HeshamFS/materials-simulation-skills