From geant4-claude
Use when the user wants to turn a natural-language detector description (shapes, materials, sizes, sensitive volumes, optical radiators) into a validated standalone GDML file under geometries/. Validates in-container before declaring success. Requires geant4-init to have run.
How this skill is triggered — by the user, by Claude, or both
Slash command
/geant4-claude:geant4-detectorThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Turn a natural-language detector description (e.g. "1×1×10 cm lead block in
Turn a natural-language detector description (e.g. "1×1×10 cm lead block in
a 50 cm air world, sensitive") into a syntactically valid GDML file under
geometries/. Validation runs in-container before declaring success.
This skill produces a standalone GDML file. Any Geant4 application
that calls G4GDMLParser::Read("geometries/<name>.gdml") can consume it.
The optional <auxiliary auxtype="sensitive" auxvalue="true"/> tag is a
hint — the example main shipped by the geant4-example skill reads it to
auto-attach a sensitive detector, but the tag is harmless to other
applications that ignore it.
--name <slug> → output file is geometries/<slug>.gdml
(default: det.gdml; auto-suffix with _2, _3, … if the file exists
and --force was not passed).--optical → force the optical-photon GDML path even if the
free-text spec doesn't name Cherenkov/scintillation. The path is also
auto-selected when the spec mentions Cherenkov, scintillation, or
optical photons.Resolve the engine (every skill starts with this; written by geant4-init):
G4C="$PWD"; while [ "$G4C" != "/" ] && [ ! -d "$G4C/.g4c" ]; do G4C="$(dirname "$G4C")"; done
[ -f "$G4C/.g4c/env" ] && . "$G4C/.g4c/env"; G4RUN="${G4RUN:-$G4C/.g4c/g4run}"
If .g4c/ is missing, stop and tell the user to run the geant4-init skill
first.
Parse the spec. Extract:
G4_Pb, G4_AIR, G4_WATER, G4_Cu,
G4_PLASTIC_SC_VINYLTOLUENE, G4_lAr, etc.),--optical,
or mentions Cherenkov/scintillation/optical photons) and the user has not
supplied a refractive index n (a single value, or an n-vs-energy/wavelength
table), stop and ask before writing any GDML: request n, or an
n(λ) table as energy[eV] n pairs. A NIST material carries no optical
properties, so generating without a user-supplied index would silently
produce zero photons. Do not guess n.When in doubt, ask the user before generating. Don't guess geometry that's load-bearing for physics.
Consult the skill geant4-geometry for GDML syntax (units,
structure, NIST materials, the optional <auxiliary auxtype="sensitive" auxvalue="true"/> convention used by the example main). Don't
reinvent the schema.
Write the GDML to geometries/<name>.gdml. Required structure:
<?xml version="1.0" encoding="UTF-8"?>
<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd">
<!-- <define> … </define> (optional: matrices, e.g. RINDEX for optical) -->
<solids> … </solids>
<structure>
<volume name="..._lv">
<materialref ref="G4_..."/>
<solidref ref="..._solid"/>
<auxiliary auxtype="sensitive" auxvalue="true"/> <!-- only on sensitive volumes -->
</volume>
<volume name="world_lv">
<materialref ref="G4_AIR"/>
<solidref ref="world_solid"/>
<physvol> <volumeref ref="..._lv"/> <position .../> </physvol>
</volume>
</structure>
<setup name="Default" version="1.0">
<world ref="world_lv"/>
</setup>
</gdml>
Conventions:
_solid, logical-volume names end in _lv.G4_AIR, large enough to
enclose all daughter volumes with a margin).<box>, <tubs>, etc. carry lunit="mm".auxiliary tag.Optical path (Cherenkov / scintillation / --optical). This branch applies when --optical is passed or the spec mentions Cherenkov, scintillation, or optical photons. When the
spec involves optical photons, the radiator material needs a RINDEX
optical property or G4OpticalPhysics produces zero photons. For an
optical spec:
Define the radiator as an explicit <material> in a <materials>
block (NIST materials carry no optical properties), with a
RINDEX matrix in <define> and a <property> linking it.
Energies use the explicit *eV form:
<define>
<matrix name="RAD_RINDEX" coldim="2"
values="1.5*eV <n_lo> 6.2*eV <n_hi>"/>
</define>
<materials>
<material name="<radmat>" formula="...">
<D value="<density>" unit="g/cm3"/>
<composite n="..." ref="..."/>
<property name="RINDEX" ref="RAD_RINDEX"/>
</material>
</materials>
Use the user-specified refractive index; for a non-dispersive
radiator repeat the same n at both energies.
The <composite> form above defines a molecular material by atom count
(right for a gas like CO₂); for a mixture or aerogel use mass
<fraction> instead. tests/fixtures/optical/radiator.gdml is a
complete, CI-validated worked example of an optical radiator (CO₂ +
RINDEX) — mirror its structure.
Tag the radiator sensitive (<auxiliary auxtype="sensitive" auxvalue="true"/> on the radiator volume). This is mandatory for
a Cherenkov/scintillation yield spec (the default): the
Frank-Tamm closure test counts photons as produced, inside the
radiator where they are born and where RINDEX exists. OpticalSD
already filters to optical photons only, so the beam primary is
never recorded regardless of where the SD sits — the
forward-flux concern (geometry-sanity gate 1) does not apply
to optical-photon counting; do not move the sensor off the
radiator to "avoid the beam".
Only if the spec is explicitly about photon collection /
ring imaging (RICH-style — "photon hit pattern on a detector
plane", not "how many photons are produced"), add a downstream
sensitive plane after the radiator with a gap, and give every
volume the photons traverse a flat transport RINDEX (n = 1.0
at both energies: world, the gap, the detector plane material).
Optical photons are killed at the first boundary into a
RINDEX-less medium, so without this they never leave the
radiator. A collection geometry is not Frank-Tamm-closable
(it measures production × acceptance × losses); say so in the
plan and skip the closure step for it.
Post-write consistency check. After writing, confirm the radiator
material actually carries both its <matrix> and a
<property name="RINDEX" .../>, and that the --rindex-material name
you'll cite downstream matches the <material name="..."/> you wrote.
The primary protection is the parse-time index gate in step 2 (never
generate optical GDML without a user-supplied n); this is a
defense-in-depth double-check. If it fails, stop, name the exact
material missing RINDEX, and do not report success.
The optical run also needs a main with G4OpticalPhysics + a
photon-aware SD — that is src/main.cc regenerated from the recipe
in skills/geant4-physics-list/SKILL.md, not the canned
geant4-example main. Surface that in the next-step suggestion.
Validate.
"${G4RUN}" validate-gdml geometries/<name>.gdml
If xmllint reports an error, fix the file and re-run validation. Do
not declare success until validation passes.
Show the user the path to the GDML and a one-line summary of what
was written (shapes, materials, sensitive volumes). Suggest the next
step, depending on how their main.cc consumes geometry:
--exe build/geant4_claude_main -- geometries/<name>.gdml macros/<name>.mac {run_dir}/hits.root;G4GDMLParser::Read("geometries/<name>.gdml").skills/geant4-physics-list/SKILL.md
(§ "Recipe: regenerating an optical-photon main") directly to the
existing workspace main src/geant4_claude_main.cc — edit it in place
in the three spots the recipe specifies (physics list, SD class, runtime
RINDEX guard); do not emit a new file. Then build, run, and use the
geant4-validate skill:
cherenkov runs/<id> --rindex-from-gdml geometries/<name>.gdml --rindex-material <radmat> --radiator-length <L>
(substitute <radmat> with the <material name="..."/> you wrote).geometries/<name>.gdml — well-formed GDML. NIST material refs,
lunit-tagged dimensions, optional <auxiliary auxtype="sensitive" auxvalue="true"/> on volumes meant to be scored.| Symptom | Likely cause | Fix |
|---|---|---|
.g4c/ missing | Workspace not initialized. | Run the geant4-init skill first. |
xmllint: parser error | Hand-written GDML is malformed. | Re-read the error; fix; re-validate. |
G4GDML: WARNING: material '...' not found (only seen at run time) | A non-NIST material name was used. | Switch to a NIST name (G4_<symbol>) or add a <materials> block defining the custom material. |
| Volume not scored at run time | Missing <auxiliary auxtype="sensitive" auxvalue="true"/>. | Add the aux tag inside the <volume> element. |
| Optical run produces zero photons | Radiator material has no RINDEX property. | The RINDEX gate should have stopped generation; if you hit this at run time the GDML was hand-edited — add a <matrix> + <property name="RINDEX"> to the radiator material. |
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub zhaozhiwen/geant4_claude --plugin geant4-claude