Paper to experiment
Skill thematteroftime/agentic-md-for-dummies/.claude/skills/paper-to-experiment
Paper-driven molecular-dynamics framework with an AI skill that turns physics papers into runnable Taichi simulations.
npx -y skills add thematteroftime/agentic-md-for-dummies --skill paper-to-experimentAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when reproducing a physics paper (or part of one) in this MD framework. Walks a paper PDF through the design template + registry, validates against the schema, registers any new force/analyzer/visualizer in the framework's forwarding station, and emits a runnable configs/plan_*.json. Used at the start of any new reproduction campaign.
SKILL.md
16.9 KB, as published. Nobody here has run it
Paper → Experiment Skill
Turn a physics paper into a validated configs/plan_<topic>.json that python scripts/run_experiment.py can launch directly. The output of one run of this skill is a campaign that — when run end-to-end — produces a report.md and at least one figure per run dir. Anything less is incomplete.
This skill is a gate, not a free-form writer. You follow the template, the schema, and the registry. You don't invent fields. You surface ambiguity to the user before writing JSON.
Hard rules (no exceptions)
-
Registry first. Open
references/force_types.mdANDtools/registry.py(the framework's forwarding station for forces / lattices / analyzers / plotters / aggregators / visualizers) BEFORE proposing any field. The skill works only with registered strings — for any extension, you must walk through §"Adding a new force type" 8-step process and register the new class intools/registry.py:_REGISTRYAND in the matching package's local__init__.py. -
Paper PDF on disk. Step 2 requires a real PDF under
papers/<slug>.pdf. If the user only has an abstract / link / mental model, stop and ask them to put the PDF inpapers/. Abstract-only reproduction is unsupported — it has produced bad reproductions in the past. -
Citations are mandatory. Every observable in §1 of the design doc must cite a paper Eq. or Fig. number. If a number isn't in the paper, mark it with
*and explain in §11. No bare claims like "expected to converge." -
Smoke before production. Every config you emit must have
pipeline.smoke=trueandsmoke_steps ≥ 100unless the user explicitly asks otherwise (and you note the override in_comment). -
Validation gate. Before announcing the config is ready, run
python scripts/validate_config.py <path> --strict. If it returns non-zero, fix the issues and re-run; do not hand off a failing config. -
Cost budget. If the validator reports
single-run wall > 24 hrorVRAM > 8 GB, propose smallerNorstepsrather than asking the user to approve a 1-day GPU burn. -
No silent invention. If a paper parameter is missing from the source, ASK in §10b (decision log) — don't fill in a "reasonable guess." Acceptable:
T0=0.3because §II of paper says so. Unacceptable:T0=0.3because it worked for E1. -
Reuse before extending. If the paper's force resembles
lennardJones,HertzianNonreciprocal, orERPotential, reuse it. Only propose a new force class if §2 of the design doc cites a paper equation that genuinely cannot be expressed by the existing classes. Reuse-with-degenerate-parameter (e.g.ERPotentialwithMT=0≡ isotropic Yukawa) is forbidden for thesis-quality reproductions — see Anti-patterns below. -
A reproduction is not done until you can see the answer. Pipeline must produce, per run dir, at least
manifest.json(engine wired up) ANDreport.md(analyzer ran) ANDfig*.png(visualizer ran). If your config produces only the first one, you skipped step 7 and/or step 8 of the extension process — analyzer / visualizer were never registered. Go back, register them intools/analyzers/<paper>.py,tools/plotters/<paper>.py(or visualizers), thentools/registry.py:_REGISTRY, then point your config'saggregation.classandpipeline.visualize.classat them. Do not declare the campaign successful with manifest-only output.
Process flow
1. Acknowledge → 2. Read paper + registry → 3. Fill design doc → 4. User approves
↓
7. Hand off ← 6. Validate ← 5. Emit JSON ← (extension step if needed)
Step 1 — Acknowledge
Announce: "Using paper-to-experiment skill. Will walk through the fixed template, then emit a validated config."
Confirm with the user where the paper is:
- PDF path under
papers/<slug>.pdf— required (Hard rule #2). - If absent, stop and ask user to populate
papers/. Do not proceed.
Step 2 — Read paper + registry + framework state
Read in this order:
- The paper PDF under
papers/. references/force_types.md(registry — whatforce_typestrings exist).tools/registry.py:_REGISTRY(forwarding station — what classes are wired).- The two existing examples under
references/examples/(worked design docs). - Any prior
docs/specs/<TOPIC>-design.mdif this is a continuation.
Identify:
- which
force_typeto use (or whether a new one is needed → §"Adding a new force type" 8-step) - which physics observables the paper reports as primary results
- which figures of the paper we are claiming to reproduce
- which lattice IC the paper uses (default
square_2dfor ndim=2 /simple_cubic_3dfor ndim=3; override via design doc §3 only when paper specifies) - any analytical fingerprints (dimensionless numbers from appendices) that we can compute pre-simulation
Step 3 — Fill design doc
Copy templates/physics_design.md to docs/specs/YYYY-MM-DD-<topic>-design.md. Replace EVERY <...> placeholder. If a section truly does not apply, write N/A — <reason> (do not delete).
§1 (observables) is the spine. Everything else flows from it: §3 setup must be sufficient to measure §1; §4 sweep must vary the dependence claimed in §1; §6 pass criteria must declare numeric thresholds for §1.
For §2 (force field):
- If existing class works: paste the registry entry's required fields verbatim, then list which simulation parameters from §3 you need.
- If new class needed: complete §2a in full and stop. Surface to user — new force class triggers the 8-step extension process (force class → tests → adapter → dispatcher → schema → registry → analyzer → visualizer) which is the user's call to greenlight.
For §4 (sweep dimensions):
- Total runs ≤ 12 by default. If more needed, split into Plan A / Plan B and emit two configs.
- Each sweep value must be motivated by a paper passage (cite it).
For §3 simulation setup initial_state field:
- Default to
square_2d(ndim=2) orsimple_cubic_3d(ndim=3). - Override only when paper specifies a different lattice (e.g.
triangular_2dfor hexatic-phase studies). - For long-range repulsive forces (Coulomb / Yukawa / hard-core surrogate), random IC is forbidden by
references/force_types.md"Long-range repulsive IC caveat" subsection — random IC + short Langevin produces wrong steady-state temperature.
Step 4 — User approval
Save the design doc and ask the user to review it. Cite the path explicitly. List the §10b open questions if any.
§10 has TWO sub-lists:
- §10a Auto-decisions taken: defaults from registry/examples, granularity choices justified by paper context. AI may take these in auto-mode without blocking.
- §10b Open questions for human (
ASK USER:prefix required): items only the user can resolve.
§0 metadata also includes an "Open questions early checklist" that the agent should fill before filling the rest of the design — surfacing blockers up front.
Approval rules:
- Interactive: do not proceed until user signals approval.
- Auto-mode: proceed if §10b is empty. Any
ASK USER:line stops auto-mode.
Step 5 — Emit JSON
Generate configs/plan_<topic>.json from the approved design doc. Required top-level fields:
{
"_comment": "<one paragraph from §0 + §1 summary>",
"_paper_ref": "<from §0 citation>",
"_paper_pdf": "papers/<slug>.pdf",
"_design_doc": "docs/specs/YYYY-MM-DD-<topic>-design.md",
"_force_type_doc": "<from references/force_types.md §N>",
"_units_doc": "<reduced_lj | macro_dust | reduced_yukawa | ...>",
"campaign": [ /* one entry per run from §4 cross-product */ ],
"pipeline": {
"preflight": true,
"smoke": true,
"smoke_steps": 100,
"production": true,
"analyze": true,
"analyzer_class": "<paper>Analyzer",
"halt_on_fail": true,
"max_parallel": <2 default>,
"visualize": {"enabled": true, "class": "<paper>Plotter"}
},
"aggregation": {
"enabled": true,
"class": "<paper>Aggregator",
"output": "docs/<paper>_campaign_report.md",
"plots": [...]
}
}
Each campaign entry must contain ONLY fields listed in references/force_types.md for the chosen force_type. Add notes field with one-line rationale linked to the design doc §.
pipeline.analyzer_class, pipeline.visualize.class, and aggregation.class MUST point to classes registered in tools/registry.py:_REGISTRY. If the paper requires bespoke analysis, register the new analyzer / plotter / aggregator classes via the 8-step extension process before emitting the config — see Hard rule #9.
Pipeline phases run in this order: preflight → smoke → production → analyze (3.4) → visualize (3.5) → aggregate. Phase 3.4 ANALYZE only fires when both analyze=true AND analyzer_class are set; existing PRX/ER configs that ran the analyzer inline in their adapters omit analyzer_class and skip the phase.
Step 6 — Validate
Run:
python scripts/validate_config.py configs/plan_<topic>.json --strict
If exit 0: proceed to Step 7. If exit 1 or 2: read the errors and warnings, fix the JSON, re-run. Do not hand off until clean.
Cross-check costs against design doc §7: validator's cost estimate line should be within 2× of your design doc §7 estimate. If they differ by >2×, the validator's step-rate model is stale.
Step 7 — Hand off
Tell the user:
- design doc path
- config path
- validation summary (exit code + cost estimate)
- exact launch command:
python scripts/run_experiment.py configs/plan_<topic>.json - expected wall time and disk
- per-run-dir expected outputs:
manifest.json+report.md+ at least onefig*.png
DO NOT launch the campaign yourself unless explicitly asked. The user owns the GPU-burn decision.
Adding a new integrator — 9-step extension process
If the paper requires a time-integration scheme the existing integrators cannot faithfully reproduce — most commonly Wiener-noise (FD-balanced) Langevin for diffusion / viscosity / glass-transition observables, or Bussi NVT — walk the 9-step extension flow in references/force_types.md §5b "Adding a new integrator". Briefly: subclass IntegratorBase, write tests, register in integrators/__init__.py:INTEGRATOR_REGISTRY AND tools/registry.py:_REGISTRY, add to the schema's integrator enum, and document in the §4 "Integrator selection" table. The default baoab_drag is fine for NVE and structural NVT, but plateaus MSD over Langevin runs (no Wiener noise).
If the existing baoab_drag is the wrong tool for the paper's central observable, propose the integrator extension up front in design doc §3 (integrator: <new_scheme>) and stop for user greenlight before walking step 1 — same gate as the 8-step force extension.
Adding a new force type — 8-step extension process
When the paper requires a force / analyzer / visualizer not in the registry, walk through these 8 steps in order. The skill cannot ship a strict-validating, visually-meaningful config until all 8 are merged.
| Step | Action | Files (write + register) |
|---|---|---|
| 1. Force class | Implement <NewForce> subclassing forceField | Write forces/<your_force>.py. Register in forces/__init__.py:FORCE_REGISTRY AND tools/registry.py:_REGISTRY. |
| 2. Tests | Pair tests for force magnitude / symmetry / cutoff | Write tests/test_<class>_<N>cases.py. Run pytest -x until green. |
| 3. Adapter | Per-paper run script (one file per registered run_type) | Write <topic>_run.py at project root, mirroring prx_nonreciprocal_run.py / er_plasma_run.py. Use tools.lattices.LATTICE_REGISTRY[design_doc.initial_state] for IC. |
| 4. Dispatch | Wire the adapter into the campaign runner AND validator | Edit scripts/run_experiment.py:_invoke_md (new branch + EXP_REQUIRED_<TYPE>); edit scripts/run_experiment.py:EXP_DEFAULTS_BY_TYPE; edit scripts/validate_config.py:check_force_type_specific (new elif branch). |
| 5. Schema | Plumb new force_type enum value | Edit templates/plan_config.schema.json (enum + if/then with ndim + units_regime; extend top-level units_regime enum if a new units yaml is needed). |
| 6. Force registry doc | Document the new force_type for the registry | Add ## N. <new_type> section to references/force_types.md with paper ref, fields, compat block (ndim, units_regime), examples, pre-flight rules. |
| 7. Analyzer | Per-run analysis class producing report.md + numeric outputs | Write tools/analyzers/<paper>.py with <Paper>Analyzer.full_analysis(run_dir, **params) -> dict returning fields written to report.md. Register in tools/registry.py:_REGISTRY. |
| 8. Visualizer / aggregator | Plot generation per run + cross-run | Write tools/plotters/<paper>.py with <Paper>Plotter.render(run_dir) writing figN_*.png. Optional tools/aggregators/<paper>.py for cross-run report. Register both in tools/registry.py:_REGISTRY. |
After all 8 steps:
- Config can
pipeline.visualize.class = "<Paper>Plotter"andaggregation.class = "<Paper>Aggregator". - Each production run dir gets
manifest.json+report.md+fig*.pngautomatically. python scripts/validate_config.py --strictpasses.
A reproduction that stops at step 6 has only proved the engine wires up. It has not produced any visible answer. By Hard rule #9, that is incomplete.
Anti-patterns (red flags — STOP and fix)
| Thought | Reality |
|---|---|
| "I'll skip the design doc — it's just one run" | The design doc IS the audit trail. Future-you needs it. |
| "I can guess the paper's φ value from context" | No. Cite or ask. |
| "Smoke wastes 30 seconds, skip it" | Smoke saves 30 minutes when something's broken. Always on. |
| "I'll fix the warnings later" | Validator must be green BEFORE handoff. |
| "Let me launch a quick test of the campaign" | User owns launch. Skill never auto-runs production. |
| "8 sweep dimensions, 64 runs, easy" | Hard cap 12 runs per plan; split if more. |
| "ERPotential with MT=0 is just isotropic Yukawa, reuse it" | The manifest will lie about what ran. Dead anisotropy machinery still allocated. Thesis reproductions need clean force classes — flag as §10b decision. |
| "The pipeline ran fine, manifest.json exists, done" | Hard rule #9: no report.md + no fig*.png = analyzer / visualizer never registered. Step 7 + 8 of the 8-step extension are not optional. |
"I'll register the analyzer in tools/registry.py only — skip the local __init__.py" | Forwarding station and local registry kept in sync is the framework contract. Both registers, or neither. |
| "Random IC is fine, the Langevin will sort it out" | For long-range repulsive forces, random IC + short Langevin under-cools by ~10× (see force_types.md "Long-range repulsive IC caveat"). Use tools/lattices/<lattice> IC instead. |
| "MSD plateaued in my Langevin run, must be a physics finding" | Probably the integrator: baoab_drag has no Wiener noise so caged particles never escape. If the paper's central observable is diffusion / viscosity / glass dynamics, you need a different integrator — walk the 9-step extension in force_types.md §5b "Adding a new integrator". |
| "I'll skip §10b open questions to keep flow" | §10b empty is the auto-mode gate. Lying about it produces wrong physics. |
When to extend (not just use) this skill
If you want to:
- Add a new field to the schema → edit
templates/plan_config.schema.json, thenreferences/force_types.md, then this skill in lockstep. - Add a new force type → walk the 8-step extension above. Do NOT add to schema until force class + tests + adapter + dispatcher + validator updates are merged.
- Change validator rules → edit
scripts/validate_config.py, add a regression test (validate against a known-good config and a known-bad one).
Files in this skill
.claude/skills/paper-to-experiment/
├── SKILL.md # this file
├── templates/
│ ├── physics_design.md # design doc template (§0–§12)
│ ├── plan_config.schema.json # JSON Schema for configs/plan_*.json
│ ├── force_class.py.template # scaffold for new forces/<name>.py
│ └── adapter_run.py.template # scaffold for new <topic>_run.py
└── references/
├── force_types.md # registry of valid force_type values
└── examples/ # finished design docs as exemplars
├── worked_example_PRL2008.md
└── worked_example_PRX2015.md
End of skill.