paper-diff
Skill8 starsChanged 7 months agoMITView on GitHub
Compare simulation output to the original paper's reference figures using Opus 4.7 vision plus deterministic image metrics. Produces structured diff with feature-level present/missing/spurious lists and a similarity score. Run after primitive-generator + execution, before pitch the result to the user. Distinct from science-integrity's figure_diff (which is one of five integrity checks); paper-diff is a USER-facing report.
In this repository9 other files it gives its agents.
- claim-extractorSkill
- narrationSkill
- paper-parserSkill
- physics-interpreterSkill
- primitive-generatorSkill
- science-integritySkill
- simspec-authorSkill
- shader-devSkill
- viz-mapperSkill
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 2 are distinctive, and 7 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.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 136
If ref_path or sim_path is missing, short-circuit Stage 1+2 and emit a fenced JSON with vlm_status + score: 0.0:
- Distinctive: line 147
DO NOT emit narration, summaries, or follow-up questions after the closing fence — they break the orchestrator's downstream consumption and …
- Very specific: line 165
If the VLM call fails (network, rate limit, parse error), the report falls back to Stage 1 only with "vlm_status": "unavailable" plus the …
- Very specific: line 208
Never lie about a match. If similarity_score < 0.80 or any critical feature is missing, the badge is not match regardless of caller framing.
- Very specific: line 210
Never silently downgrade divergent to approx.
- Very specific: line 212
Never invent paths. If ref_path does not exist, short-circuit with vlm_status: "missing-input" and Stage 1 score 0.0.
- Very specific: line 214
Never strip the verbatim source quote from a claim_overlay entry.
- Very specific: line 216
Never call the VLM without temperature: 0.
- Distinctive: line 218
Never bypass the cache for the same input bytes.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 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
paper-diff
1. Purpose and scope
This skill produces the user-facing comparison artifact between the figures of the source paper and the rendered output of a Mobius simulation. It is the visible evidence that the simulation reproduces the physics described in the paper. Its product backs the green "reproduces Figure 3" badge surfaced near the simulator and the side-by-side panel that opens when a user clicks the badge.
The skill runs after primitive-generator has emitted Python code, after the simulation has executed in the Claude Managed Agents sandbox, and after at least one frame per relevant figure has been exported. It runs before the orchestrator pitches the final assembled simulator. It does not run during the live slider loop; the diff is computed once per stable simulation snapshot and cached.
What this skill does NOT do. It does not extract figures from the paper PDF (that is paper-parser), does not decide whether to block the pipeline (that is science-integrity), does not render the side-by-side panels in the browser (that is viz-mapper), and does not invent ground-truth values.
2. Distinction from science-integrity.figure_diff
Load-bearing. Both skills compare images but serve orthogonal purposes.
science-integrity.figure_diff is one of the five deterministic integrity checks (units, CFL, conservation, figure-diff, claim-match). It returns pass | warn | fail, writes into simspec.integrity.checks[], and on fail blocks the pipeline so the orchestrator re-dispatches primitive-generator. It is silent on the user surface.
paper-diff is the user-facing report. It returns a rich structured object enumerating matched features, missing features, spurious features, color and axis agreement, and surviving numerical claims. It is always rendered in the UI and never blocks. Even on catastrophic disagreement, the simulator renders with a red "divergent" badge and a panel listing every divergence verbatim. The bet: an honest "this does not match Figure 3 because the simulation produced 2 peaks where the paper shows 4" is more valuable to a user and a judge than a silently downgraded match.
The two skills share the underlying VLM call shape and the deterministic-metric primitives, but their output schemas, blocking semantics, and rendering pathways are different. science-integrity.figure_diff is a gate; paper-diff is a report.
3. Citation of the SINTEF gap
JutulGPT (arXiv 2603.00214, SINTEF Digital + NTNU, MIT licence) is one intellectual ancestor of Mobius. In Section 6.1 the authors enumerate explicit limitations of their reference implementation. Two are directly relevant:
"the agent does not yet perform structured comparison of simulation outputs"
"systematic multimodal output comparison... remains an important development direction"
These are verbatim from page 11 / 19 of the v1 manuscript. paper-diff exists exactly to occupy this gap. JutulGPT relies on the simulator's internal conservation tolerances as its sole validity certificate - "if it ran, it is physical". Mobius adds a second certificate: "and what came out matches the paper's published figures, structurally and numerically, at the feature level". The pairing is the moat; neither half alone is novel.
This is also the primary citation hook for the hackathon pitch: SINTEF flags multimodal output comparison as future work in February 2026; Mobius ships it in April 2026 with Opus 4.7 vision.
4. Inputs
For each figure id in simspec.paper.figures[] the skill expects three artifacts.
ref_path. The reference PNG extracted from the paper PDF by paper-parser, under artifacts/figures/<figure_id>.png. Resolution is whatever the PDF provides; the skill rescales.
sim_path. The simulation frame for the same figure, exported by the execution stage. The orchestrator picks the frame closest to the figure caption's time anchor ("steady state", "t = 5 ns", "first 100 cycles average"). Multi-panel figures pair frames one-to-one.
claims. The subset of paper.numerical_claims[] whose section anchors to this figure (Fig. 3, Fig. 3a). Each carries value, UCUM unit, confidence, and verbatim source quote. The skill uses them to ground the VLM: rather than "do these look similar", we ask "does the simulation reproduce the quantities this figure claims".
Optional mode flag: "fast" skips the VLM stage (used during the slider loop); "full" is the default.
5. Output
A paper_diff_report object per figure, one entry per panel. The shape:
{
"figure_id": "fig-3",
"similarity_score": 0.82,
"panels": [
{
"label": "panel-a",
"ref_path": "artifacts/figures/fig-3.png",
"sim_path": "artifacts/sim_frames/fig-3_panel-a.png",
"similarity_score": 0.84,
"features": {
"present": ["five interference peaks", "central maximum brightest", "envelope falls off symmetrically"],
"missing": ["axis labels in micrometers"],
"spurious": ["faint vertical banding from FFT aliasing"]
},
"dominant_color_match": true,
"axis_scale_match": true,
"peak_count_match": true,
"claim_overlay": [
{ "claim": "fringe spacing 0.63 mm at 1 m screen distance", "present_in_sim": true, "value_diff_percent": 1.8 },
{ "claim": "first minimum at 0.31 mm from center", "present_in_sim": true, "value_diff_percent": 12.4 }
]
}
],
"summary_md": "Five visible peaks, central maximum brightest, fringe spacing within 2% of paper. First-minimum location off by 12%, likely due to coarser sampling at the aperture edge.",
"badge": "match"
}badge thresholds: "match" (similarity >= 0.80 and no missing critical feature); "approx" (0.60 <= similarity < 0.80 or one missing non-critical feature); "divergent" otherwise. summary_md is short and honest, never marketing.
5.bis Output format (mandatory)
You MUST emit your final output as a single fenced json block at the END
of your reply, with NO prose after the closing fence. The orchestrator parses
that block by regex (`/(?:json)?\s*\n([\s\S]?)\n\s```/`) and ignores
everything else in your text content.
The canonical artifact for paper-diff (consumed by orchestrator.ts Phase
G; the per-figure rich report of §5 is preserved under details[]):
{
"ssim": 0.84,
"vlm_judgment": "consistent",
"diff_score": 0.78,
"score": 0.78,
"details": [
{
"figure_ref": "Fig. 3",
"ssim": 0.84,
"verdict": "match",
"panels": [
{
"label": "panel-a",
"ref_path": "artifacts/figures/fig-3.png",
"sim_path": "artifacts/sim_frames/fig-3_panel-a.png",
"similarity_score": 0.84,
"features": {
"present": ["five interference peaks", "central maximum brightest"],
"missing": [],
"spurious": []
},
"claim_overlay": [
{ "claim": "fringe spacing 0.63 mm", "present_in_sim": true, "value_diff_percent": 1.8 }
]
}
]
}
]
}Required top-level keys: ssim (float in [0, 1]), vlm_judgment (one of
"consistent" | "inconsistent" | "uncertain"), diff_score (float in [0, 1],
1 == identical), score (alias of diff_score consumed by Phase G's
pickArtifact<{ score: number }> extractor — keep them equal). details[]
is recommended and carries the per-figure rich report shape from §5; the UI
renders it verbatim.
If ref_path or sim_path is missing, short-circuit Stage 1+2 and emit a
fenced JSON with vlm_status + score: 0.0:
{
"ssim": 0.0, "vlm_judgment": "uncertain", "diff_score": 0.0, "score": 0.0,
"details": [], "vlm_status": "missing-input",
"error": "sim_path /runs/<id>/scene.png does not exist"
}DO NOT emit narration, summaries, or follow-up questions after the closing fence — they break the orchestrator's downstream consumption and get silently dropped.
6. Two-stage diff
Deterministic first, VLM second. Cheap before expensive, in the order that maximises explainability.
Stage 1: deterministic image metrics. Over the rescaled image pair (512 x 512):
- SSIM via
skimage.metrics.structural_similarityon the luminance channels, mapped to [0, 1]. - Histogram overlap on RGB via
numpy.histogramwith 32 bins per channel, summed per-bin min. Catches dominant-color agreement independently of spatial layout. - Edge IoU via
skimage.feature.canny, intersection over union of edge pixels. Catches axes and dominant outlines.
Stage 1 score = 0.5 * ssim + 0.25 * hist + 0.25 * edges. Bounded, sub-second, never hallucinates.
Stage 2: Opus 4.7 vision. One multimodal call to client.messages.create with two image content blocks (ref and sim, base64-encoded PNG, media_type: "image/png") and a text block carrying the schema and claim list. Model: claude-opus-4-7. Output is strict JSON matching the panel schema.
If the VLM call fails (network, rate limit, parse error), the report falls back to Stage 1 only with "vlm_status": "unavailable" plus the error string. The pipeline never crashes on VLM failure.
7. VLM prompt (verbatim)
The exact system prompt used in Stage 2. ~200 words, no slack:
You are a structural-fidelity comparator for physics simulation outputs. You receive two images: a reference figure from a published paper, and a frame produced by a simulation that claims to reproduce it. Your job is to enumerate, in strict JSON, every structural feature the two images share, every feature present in the reference but missing in the simulation, every feature present in the simulation but spurious. You also report whether dominant colors match, whether axis scales match, and whether the count of dominant peaks or features matches. You compare to a list of numerical claims; for each, mark whether it is present_in_sim and the value_diff_percent if a numerical value can be read from the simulation.
Forbidden: artistic judgment. Do not say "the simulation looks ugly" or "the colors are not as nice". You are not an art critic. You are reporting structural physics fidelity. Forbidden: speculation beyond what the images show. Do not say "this is probably caused by". Forbidden: prose outside the JSON. The response MUST be a single JSON object matching the panel schema in the user message; no preamble, no postscript, no markdown fences.
If you cannot determine a field from the images, set it to null and note it in features.missing with the prefix "uncertain:".
The user message carries the schema fragment, the claim list, and a 30-word context blurb pulled from the figure caption. Temperature is 0; we do not want creativity in a structural diff.
8. Caching
Cache key: sha256(ref_bytes || sim_bytes || claims_canonical_json || prompt_version). Cached entries at /tmp/mobius_paper_diff_cache/<key>.json. A hit short-circuits both stages. prompt_version is bumped manually whenever the system prompt changes, invalidating old entries cleanly.
The cache is content-addressed: sliders changing parameters produce new sim bytes and new cache misses, exactly the desired behavior. Reference figures rarely change within a session.
Eviction: 200 MB or 500 entries, LRU. The directory is gitignored.
9. Visual integration
The report renders as a Ciechanowski-style side-by-side panel:
- Left: paper reference on
--c4rose-tinted matte, 1.5 px stroke, IBM Plex Sans caption. - Right: simulation frame on
--c3blue-tinted matte, identical aspect ratio, caption "Mobius - reproduced". - Center column of annotations, one row per
features.present(green tick--c2),features.missing(orange dash--c1),features.spurious(red cross--c5). Hover highlights the corresponding region in both images. - Bottom:
summary_mdas body-type prose, plus an accordion expanding theclaim_overlaytable.
The badge is a pill inline with the simulator title bar: --c2 match, --c1 approx, --c5 divergent. Click opens the panel as a modal. All easing follows the project's quintic smoothstep x*x*x*(x*(x*6-15)+10).
10. Examples - three worked diff scenarios
Match. Young's double-slit. Paper shows five fringes with brightest central maximum, fringe spacing 0.63 mm at 1 m. Sim reproduces five fringes, fringe spacing 0.642 mm. SSIM 0.91, hist 0.88, edges 0.86. VLM: "five interference peaks, central maximum brightest, envelope symmetric". claim_overlay fringe spacing differs by 1.8%. Badge: match.
Approx. Damped harmonic oscillator. Paper omega_0 = 2.0, gamma = 0.1. Sim 1.94 / 0.097, 3% error from coarser dt. SSIM 0.74. VLM: "correct exponential envelope, period off by 3%". Badge: approx. The user sees the honest "off by 3%" pill.
Divergent. Four-slit grating. Paper shows four primary maxima per order; sim, due to a primitive defaulting slit_count = 2, shows two. SSIM 0.41. VLM: "two primary maxima where four were expected; missing slits 3 and 4". Badge: divergent. The orchestrator may re-dispatch primitive-generator with the diagnostic; the user sees an unedited red pill explaining the gap.
11. Red flags
Never lie about a match. If similarity_score < 0.80 or any critical feature is missing, the badge is not match regardless of caller framing. No override flag.
Never silently downgrade divergent to approx. Every divergence is preserved verbatim in features.missing and features.spurious.
Never invent paths. If ref_path does not exist, short-circuit with vlm_status: "missing-input" and Stage 1 score 0.0. Same for sim_path.
Never strip the verbatim source quote from a claim_overlay entry. The user must be able to trace it back to the paper.
Never call the VLM without temperature: 0. Structural fidelity is not a creative task.
Never bypass the cache for the same input bytes. Same input, same report, every time.
12. Interaction with other skills
paper-parser writes artifacts/figures/<figure_id>.png; paper-diff reads, never modifies.
primitive-generator indirectly produces sim frames via executed code; paper-diff sees only the rendered output.
viz-mapper reads the report and renders the side-by-side panels and badge pill. The report shape is the contract; viz-mapper does not call the VLM.
science-integrity runs in parallel and writes one perceptual-hash check into simspec.integrity.checks[]. The two skills are independent measurements feeding different surfaces.
narration may quote summary_md in an observation cue. The orchestrator wires the dependency; paper-diff does not call narration directly.
The Stage 1 + Stage 2 script lives at scripts/run_diff.py. Invoke as python scripts/run_diff.py <ref_path> <sim_path> [--claims claims.json]; it also exposes run_diff(ref_path, sim_path, claims) for inline orchestrator use.
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.

