Changelog
All notable changes to this project are documented here. The format follows Keep a Changelog and the project uses Semantic Versioning (pre-1.0: 0.0.x until the first essential release, then 0.x.y).
[1.3.0] - 2026-11-12
Phase 10 makes xtalforge a MOF platform: experimental CIFs can be checked and cleaned, deconstructed into nodes, linkers and a topology, described with the standard geometric and adsorption descriptors, modified, and screened in batches. The public API is additive.
Added
- MOF checking and cleaning:
mof_check(overlaps, fragments, valence, disorder, metal coordination, charge),mof_solvent_removewith the embedded solvent table and the CoRE FSR/ASR policy,mof_disorderandmof_charge_balance. - Framework understanding:
mof_deconstruct(all-node SBU/linker split and contracted quotient net),mof_mofid(canonical unit SMILES, topology,MOFidstring and SHA-256MOFkey),mof_open_metal_sitesandmof_descriptors. - Native porosity:
mof_poreswith periodic union-find PLD, LCD, accessible surface area in m2/g and m2/cm3, accessible volume, void fraction, channel dimensionality and the geometric pore-size distribution. - Adsorption:
mof_guests(TraPPE CO2, N2, CH4, H2, H2O),mof_forcefield(UFF/EQeq host, Lorentz-Berthelot mixing),mof_widom(Henry coefficient and heat of adsorption),mof_gcmc(single-component isotherm),mof_energy_gridandmof_raspainput export. - Modification:
mof_functionalize(NH2/OH/CH3/F),mof_defects(missing linker and cluster defects with formate/water/hydroxide caps),mof_interpenetrate,mof_stack_layersandmof_mixed(ordered orbit or seeded random mixed-metal/linker frameworks). - Screening:
mof_read_databasefor CoRE MOF and QMOF directories,mof_screenfor a resumable descriptor/Henry table with MOFkeys andmof_deduplicate(MOFkey first, structure matcher for ties). - CLI
mofsubcommands (check,solvent-remove,disorder-resolve,charge-balance,deconstruct,mofid,open-metal-sites,descriptors,pores,adsorption,modify,database), Python functions and WASM JSON exports.docs/api/mof.md,docs/guide/mof-workflows.mdand two new algorithm pages document the phase; the parity matrix gains 23 rows. P1Atomdisorder groups, the MOF host-guest data files and the newmof-datafeature flag.
Fixed
- The MOF checker does not report a charge imbalance for a metal-free covalent framework; charge balance is assessed only when metals are present.
[1.2.0] - 2026-11-11
Phase 9 adds the core operations of a standard crystal library beyond the Crystal-Builder parity of 1.1.0. Every capability is available in the Rust API, the CLI, Python and WebAssembly, and the public API is additive.
Added
- Structure comparison:
match_structures(Niggli reduction, integer lattice mapping, supercell matching, species comparators),periodic_rmsd,kabsch_alignmentandgroup_structures. CLIcompareandgroup. - Structure edits:
deform(Voigt strain, deformation gradient, target volume and density), seededrattle,edit_structure(add, remove, replace, move, species maps, partial replacement, sort and wrap) with undoable commands, matchedinterpolateandoptimal_supercell(ASEfind_optimal_cell_shapeobjective). - Local environments: periodic
voronoiwith exact half-space clipping and solid angles,coordinationwith cutoff/Voronoi/CrystalNN strategies and continuous shape measures,bond_valence_sums,oxidation_states(ICSD MAP search with charge balance),radial_distribution(total and partial RDF/PDF, running coordination), bond-angle distributions andstructure_fingerprint. - Surfaces:
unique_miller_indicesunder the detected point group,slab_terminations(symmetric slabs, dipole and polar report, minimal slab), thewulffconstruction andadsorption_siteswithplace_molecule. - Defects and disorder: symmetry-unique
vacancies,substitutionsandinterstitialswith minimum-image supercells,orderingsranked by an in-process Ewald sum,special_quasirandomwith pair/triplet correlation reports,lattice_matchesandstack_slabsheterostructures. - Mechanical and thermodynamic basics:
elastic_tensorfrom analytic stress finite differences with Voigt-Reuss-Hill moduli and a stability flag,eos_fit(Birch-Murnaghan, Vinet, Murnaghan with errors) andconvex_hull(formation energies and a two-phase simplex hull distance). - The CLI gains
compare,group,deformand thefeaturescommand group; Python gains the corresponding functions; WASM gains JSON-returning exports for every operation. - Documentation:
docs/api/features.md, algorithm pages for comparison, local environments, surfaces, defects and mechanics, and a parity matrix with 29 new rows. - Roadmap to
2.0.0: Phases 9-17, focused on MOFs (core features beyond Crystal-Builder parity, the MOF platform, usability audit and 1.x polish, native bindings, ecosystem interoperability, scientific completeness, performance, workflows and the 2.0 redesign), with the 2026-11-11 usability findings.
Fixed
P1Atomcarries the disorder group of its parent site, so orderings and SQS generation can find partial occupancies after the P1 expansion.
[1.1.0] - 2026-11-11
First feature release after 1.0.0, published on 2026-11-11. It adds the 3D playground and the end-to-end audit battery, exposes the scene and text-returning WASM helpers, and folds in the fixes from the functional audit of every surface (Task 8.9). The public API remains backward compatible: the new JSON and object fields are additive.
Added
- The 3D playground in the docs: load, transform and build a structure with the WASM package and inspect the same Rust scene in an orbitable WebGL view.
scene_dataon the WASM, Python and CLI (mesh --scene) surfaces, andn_atomsin the WASM structure summary, so a viewer no longer reconstructs geometry in JavaScript.- Text-returning WASM variants of the symmetry transforms and the carbon/MOF builders (
to_p1_text,primitive_text,standardize_text,asymmetrize_text,set_space_group_text,change_setting_text,reduce_text,lower_to_subgroup_text,build_graphene_text,build_nanotube_text,build_c60_text,build_c20_text,build_mof_text,build_ribbon_text,build_twist_text,build_ztc_text,build_schwarzite_text,build_polymer_text,hydrogens_textandff_optimize_text). - The end-to-end audit battery (
tests/e2e/): 68 Playwright checks against gemmi, spglib, ASE and NumPy references, plus deterministic 3D screenshot goldens, andscripts/e2e.shto run it. The playground UI checks cover the tabbed panels, atom selection, the Brillouin zone, the powder plot, UFF energy, exports, fullscreen, porosity, the MOF builder and all four powder refinement methods. - A guided Tour tab in the playground: seventeen steps that load a sample or run a builder, set the camera and open the tab where the result is read (CIF reading, space group, Brillouin zone, measures, supercell, slab, PXRD, nanotube, twisted bilayer, C60, MOF, disordered carbon, polymer, porosity, force field, powder refinement and export). The powder plot gains a 2θ axis, hkl labels for the strongest lines, I/I0 in the table and recalculates when the structure changes; the structure panel adds the disordered-carbon builder.
build_carbon_texton the WASM surface returns the disordered carbon as CIF for a viewer.
Fixed
PXRD intensities used the Z-based Gaussian form factor
Z exp(-0.5 Z^(2/3) s^2)for every element, so relative intensities were off by up to 50 % (rutile(1 1 1)28 % of(1 1 0)instead of 19 %). The neutral-atom International Tables (1992) coefficients are now embedded for H to Cf and the Si, NaCl, Fe and rutile patterns match an independent calculation to 0.1 %. Rietveld/Le Bail/Pawley stages that start from the calculated pattern inherit the change.commensurate_twistignored the requested angle: it rounded every twist to 0 or 60 degrees, and its "60 degree" variant shifted both layers. It now builds the commensurate moire cell ((2, 1)for 21.79 degrees, 14 atoms per layer) and recordstwist_angleandtwist_indices;n x mrepeats the moire cell.build_polymerpacked the chain into a cube shorter than the chain, so the periodic images overlapped (C-C 0.67 Angstrom, coordination 5-7 for polyethylene). The repeat units are now joined head to tail alongainto a periodic chain and the cross-section sets the density.embed_smileshad no bond-angle term, so rings collapsed (benzene with 1.17 Angstrom 1-3 contacts and non-planar). Angle targets from the hybridization (180, 120, 109.47 degrees) are now part of the relaxation and the default iteration count is 1500.build_carbonplaced carbons at mesh-patch centres without relaxing them, so atoms could sit 0.15 Angstrom apart, and put edge terminations along the sheet normal instead of the free in-plane valence. The dual graph is now relaxed to 1.42 Angstrom bonds and 120 degree angles, terminations follow the free valence, and a termination that would overlap another atom is dropped and reported as a bare edge. Termination and graph bonds that cross the cell boundary now carry their lattice image; before, 71 of the default dia build's bonds were stored without it and drawn 23-33 Angstrom long across the cell.P1Cell::expandandLattice::wrapturned a tiny negative coordinate (such as -1e-32 from a Cartesian round trip of 0) into exactly 1.0. The UFF view then held a duplicated atom, soff vibrationson silicon reported modes of +-14 000 cm^-1 (energy +1028 eV after the Hessian displacements). Coordinates now stay in[0, 1); silicon gives three zero acoustic modes and degenerate optical modes.le_bailandpawleysubtract a SNIP background before extracting intensities andle_bailuses the profile-weighted partition; on rutile with a 50-count baseline R drops from 0.69 to 0.27.MOF nodes are oriented with a Kabsch fit over every connection-to-edge assignment instead of the greedy mean-direction rule, so planar nodes in
srs/hcbno longer force linkers to be stretched 0.55-1.26 times.build_ztcandbuild_schwarzitereturn three-coordinate sp2 carbon (the relaxed dual of the remeshed gyroid/Schwarz P surface, with explicit bonds) instead of mesh vertices with coordination 5-8; their sampled grid now includes the closing plane, soztc_surface_meshandschwarzite_surface_meshare closed across the cell faces.Wyckoff letters are matched on the input coordinates when the input basis is conventional, so they follow the input origin like spglib and the CIF (silicon in origin choice 1 is
8a, not moyo's8b).eeq_chargesis now EEQ2019 (multicharge parameters, coordination-dependent electronegativity, erf-damped Coulomb) instead of a copy of QEq; isolated water gives O -0.598 like the sci-form/dftd4 reference.refine_phasewithrefine_cellstarts from a Pawley cell (new first stagepawley_cell), so a cell 1 % off no longer traps the refinement.build_mofrefuses two metal-free carboxylate blocks, whose oxygens would overlap, instead of returning the overlapping framework.build_ztcrefuses cells below 12 Angstrom andbuild_schwarzitebelow 8 Angstrom, where the surfaces cannot hold three-coordinate carbon.eeq_chargesuses an Ewald sum for the periodic Coulomb term (MOF-5 Zn was +4.4 with the real-space cutoff).Python
ff_chargesand WASMff_charges_infoaccepteeq; the CLIinfoJSON and text carryn_atoms; WASM errors that were bare strings are nowErrorobjects withcode = "invalid_input"; PXRD reflections with equal two-theta are ordered identically on native and WebAssembly builds.A refinement panel in the playground (Powder tab): load the bundled synthetic rutile pattern or a file and run Le Bail, Pawley (with size and strain), Rietveld or the automatic run, with an observed/calculated/ difference plot; the tour has a matching step (seventeen steps).
The automatic powder result exposed only the quick cubic-index edge as its
cell, so the refinement panel and the CLI table showed the indexing candidate as the "best" cell. CLI, Python and WASM now also returnbest_cell: the Pawley-refined cell of the leading candidate, or its indexed cell when the Pawley stage was skipped (rutile automatics report a = 4.5993 Angstrom instead of the indexed 4.5902 Angstrom).Running a builder or transform in the playground left the sample selector on a stale sample id; it now shows "Built or transformed", and the nanotube tour step looks from +x so the tube lies across the view.
Python
powder_lebail, WASMpowder_lebail_infoandpowder_pawley_width_info; WASM Pawley results carrysize,strainand the fittedcalculatedprofile.scripts/check-surfaces.shand the release checklist compare 97 fields across CLI, Python and WASM.fit_phaserefines the constant background with the scale, as documented (the automatic run's phase Rwp on rutile drops from 1.05 to 0.33).The CLI Rietveld uses the library's default iteration count, like Python and WASM, and exits quietly (status 141) when its output pipe closes instead of panicking.
The playground radiation selector was empty: seven static
<option>elements were hoisted into one static block that Vue cannot insert into a<select>. The options are now rendered from a list.The playground twisted-bilayer form called the builder with
m = 0, which is rejected; it now defaults to the(2, 1)cell at 21.79 degrees.Structure::supercellcopied only the asymmetric sites, so a supercell of a symmetric structure lost its symmetry expansion (a2 x 2 x 2silicon supercell had 8 atoms instead of 64, in the CLI and WASM). It now expands the P1 cell first throughStructure::as_p1; the CLI size estimate and the supercell tests use the full-cell count.Structure::is_p1trusted only the Hall symbol, so a CIF with an explicit operation loop and no space-group name was treated as P1 and reported the wrong formula, density and charge. It now also requires every operation to be the identity.The CIF-inspector demo's inline silicon CIF lacked the centring translations and reported one atom and 0.29 g/cm3; it now uses the Hall symbol and shows
Si8and 2.329 g/cm3.The WASM structure summary now includes the P1
n_atoms, matching Python and the whole-cell formula work released in1.0.0.brillouin_zone_for_structuredetects the primitive cell, so silicon and rock salt (fcc), bcc iron and other centred cells no longer return the cube of the conventional reciprocal cell. The clipping now starts from a cube large enough for anisotropic cells, so graphene returns its hexagonal prism instead of a box; the cap ordering also works for non-unit plane normals.
Changed
- The WASM budget moves from 3904 to 3968 KiB for the audit fixes (IT92 table, commensurate twist, periodic polymer, embedder angles, carbon relaxation, ZTC/Schwarz P dual, Le Bail/Pawley background, MOF quaternion fit and
build_carbon_text; 3943 KiB measured). - The WASM release budget moves from 3840 to 3904 KiB for
scene_data,n_atomsand the text-returning builders (3845 KiB measured).
[1.0.0] - 2026-11-10
First stable release, published on 2026-11-10 on crates.io (13 crates), PyPI (7 platform wheels plus an sdist), npm, the GitHub release and GitHub Pages. The public API is frozen and changes follow the SemVer policy in docs/api/stability.md. This release incorporates the fixes accepted during the 1.0.0-rc.1 stabilization period.
Fixed
Structure::formula,cell_contents,cell_mass,density,zandtotal_charge(and thereforeinfo,structure_info, the agentinfoverb, Python and WASM summaries) counted the asymmetric unit, so every structure with symmetry operations reported the wrong formula, density and charge: NaCl read from a CIF showedNa Cland 0.55 g/cm3 instead ofNa4 Cl4and 2.19 g/cm3. They now use the P1 expansion;zis the gcd of the element counts.- The CIF reader records
coincident_atoms_warningwhen atoms of different sites coincide in the P1 cell with total occupancy above one (a file that lists the whole cell under a non-P1 group), and the CLIinfoprints it andsymmetry_warningon standard error. - Writing to a device such as
/dev/nullworks: atomic writes rename the temporary file only for regular files, so devices and FIFOs are written in place. graphene: the atoms were stored with Cartesian coordinates as fractional ones and thebvector usednx/2instead ofny/2, so the sheet was distorted (bonds of 1.07 Angstrom) and not a supercell whennx != ny.nanotube: the strip was not restricted to one circumference, the translation vector usedgcd(n, m)instead ofd_R = gcd(2n + m, 2m + n)and the atoms were not rolled onto a cylinder. (5,5) had 166 atoms and 537 bonds; it now has the 20 atoms and 30 bonds of the chirality formula. The nanotube cell is now2R + vacuumonaandcwith the axis alongb.nanoribbon: the vacuum stretched the strip instead of adding empty space; the bonds are 1.42 Angstrom again.structure_info(and the CLIinfo, Python and WASM equivalents) rejected the versioned{"schema_version", "structure"}envelope that--jsoncommands write, soxtalforge --json supercell ... | xtalforge info -failed; both forms are accepted now.powder index(cubic search): a face-centred pattern indexed on a larger multiple of the true cell (NaCl returned 7.94 Angstrom); the smallest cell among equally good candidates is now chosen.mof build: the topology cell was fixed, so a long linker was squashed (0.45x for stilbene inpcu) and thousands of atoms overlapped; the builder now fits a uniform cell scale to the linker (cell_scalemetadata). A node with the wrong connection count, a linker with more than two arms, a linker scale outside 0.8-1.25 and atom pairs closer than 0.9 Angstrom are reported inwarnings, and the CLI prints them on standard error.powder rietveld --refinealways modelled the Cu K alpha doublet, so a single-wavelength pattern drove the ADP multiplier to its bound; the new--no-doubletflag matches Python'sdoublet=False.powder automatic/run_automatic: the peak search did not subtract the background, so on a noisy pattern with a raised baseline every noise maximum was a peak, the indexing returned a wrong cell (16.5 Angstrom for NaCl) and the run did not finish in five minutes in a release build. It now subtracts a SNIP background and applies a noise-based threshold; the same pattern runs in 2.4 s and returns Fm-3m first.PeakOptions::noise_limitedexposes the same search andpowder index --backgrounduses it (a = 5.614 instead of 16.5).
Tests
- Phonons of fcc argon with UFF (
phonon_argon.rs) and the CLI--no-doubletflag have regression tests. - Regression tests cover the whole-cell properties and the coincident-atoms warning, the versioned
structure_infoenvelope, atomic writes to devices, the graphene/nanotube/ribbon geometry, cubic indexing, the MOF cell fit, background-subtracted peak search and the CLI warning output. xtalforge-wasmhas a browser suite (tests/browser.rs) that runs withwasm-pack test --headless --chrome; the Node suites are unchanged.
Documentation
- Added 29 diagrams with one shared style under
docs/public/diagrams/(animated SVG; every procedure page: lattice, neighbours, supercell, slab, bonding, rings, P1, CIF, formats, prepare, UFF, optimisation, Ewald, PXRD, indexing, Le Bail, Pawley, Rietveld, extinction, symmetry, nets, MOF, carbon builders, vibrations, limits, validation, agent, measures) and embedded them in the matching algorithm pages. - Audited the algorithm and API pages against the code. Corrected the powder instrument description (no wavelength or Caglioti terms), the distance-grid sampling and surface area, the optimiser cell freedom, the ellipsoid scale factors, the error mapping of the CLI and Python bindings, the quick-start version pin and the MOF entry point; recorded the resulting known subsets in the roadmap.
- Corrected the quick-start (
structure_infotakes structure JSON; useStructure.from_cif/read_ciffor CIF), the WASM size figures, the migration table (nomodulesCLI command, no separate powder crate) and the stale Phase 0 status andAGENTS.mdgap list; documented the Pawley profile-mismatch caveat. - Corrected the API examples so every Rust snippet compiles (missing
uselines and theCalculatortrait,ParamSet::with_param,f64supercell matrices), theCommandStack::pushsignature, the error-code tables (limit_exceeded,symmetry), the isosurface algorithm name (marching tetrahedra) and theexternalfeature wording. - Corrected the QEq kernel description (hardness only, truncated 12 Angstrom sum) and stated that EEQ equals QEq at the default dielectric, the duplicated external-validation bullet and the tutorial commands (
powder lebail/pawley,build graphene/nanotubetake positional arguments).
[1.0.0-rc.1] - 2026-11-10
The first release candidate for 1.0.0, published on 2026-11-10 on crates.io (13 crates), PyPI (7 platform wheels plus sdist), npm, the GitHub release and GitHub Pages. The public API is frozen; the stabilization period accepts fixes only, then 1.0.0 follows.
Added
- Phase 8 Task 8.5: distribution metadata. Every published crate has an
includeallow-list (src, its own data bundle, the agent skill), docs.rs metadata, andscripts/check-package.shchecks the tarballs and the 12 MB ceiling. The release workflow builds abi3 wheels for manylinux/musllinux (x86_64, aarch64), macOS (x86_64, arm64) and Windows;xtalforgegainscompletions <shell>andman; crates.io publication includes the agent crate. - Phase 8 Task 8.6: regression benchmarks for symmetry, UFF, PXRD and the distance grid with
scripts/check-bench-budget.sh, determinism tests across threads, a deterministic mutation harness for every text parser and the project archive, and a limits audit at and beyond every budget. - Phase 8 Task 8.7: tutorials for eight end-to-end workflows, the Crystal-Builder migration guide, and consolidated algorithm pages for analysis, builders, the MOF builder, the powder pipeline and modules with a coverage index.
- Phase 8 Task 8.8: the API stability and SemVer page, a compile-time freeze test for representative signatures, and a closed parity matrix with every exception recorded.
- Phase 8 Task 8.4: the machine-learning bridge and model cache. Python
MlCalculatorwraps any ASE calculator (MACE, ORB-v3, MatterSim) and maps energy, forces and stress to eV, eV/Angstrom and GPa;ml_backends()probes the modules. The CLImodels list|fetch|verify|removeandxtalforge_ff::modelsrecord URL, license and SHA-256 in a user cache and never bundle weights. MACE-MP-0 (small) golden data covers H2, water and methane within 1e-6 eV, 1e-5 eV/Angstrom and 1e-6 GPa, with timings. - Phase 8 Task 8.3: open extension registries and a Python plugin surface.
FormatRegistry,ScalarRegistryandStyleRegistryjoin the existing calculator and module registries;examples/pluginis a buildable crate that registers a format, a calculator, a module, a scalar and a style. PythonPluginsregisters callables as modules, calculators and formats, with JSON in/out and typed errors. The draw-style enum stays closed; the open part is the settings preset, recorded indocs/api/plugins.md. - Task 0.9: bundle a 14-structure subset of the QMOF Database (CC BY 4.0, Figshare 13147324 v18) and validate the reader against the tabulated atom count, volume, density and formula; four P1 files recover their QMOF space group at
symprec 0.01 A, and a CIF round-trip preserves the cell. - Task 0.9: bundle an 18-complex subset of tmQM 2024 (MIT, one complex per metal from Sc to Ir) and validate the XYZ reader against the header stoichiometry, the perceived metal coordination and an XYZ round-trip. UFF builds, types and evaluates every metal with finite forces.
- Task 0.9: bundle an 18-structure subset of the CoRE MOF 2019 public archive (CC BY 4.0, Zenodo 14184621) and validate against it. Every file parses, expands to P1 and bonds; four frameworks are checked against their own
_chemical_formula_sum, every declared_cell_volumeis reproduced within 0.05 A^3, CIF round-trips preserve sites and volume, and HKUST-1 and ZIF-8 give bounded PXRD and porosity numbers. - Phase 8 Task 8.2:
xtalforge mcpserves the verb catalogue as MCP tools over stdio (JSON-RPC 2.0, protocol2024-11-05, no external MCP crate), with generated input schemas and aninstructionspayload for chat clients. Fourteen skill documents ship with the CLI (xtalforge skill path|list|show|install) and are published as the automation guide. Calls run under the standard size limits; cancellation is process-level and the window proxy is out of scope, both recorded indocs/algorithms/agent.mdsection 11. - Phase 8 Task 8.1: the
xtalforge-agentcrate: one verb catalogue shared by the Rust, CLI, Python and WASM surfaces (22 verbs), a stateful session whose mutations useOrigin::Agent, inspection and diagnostics (overlap, occupancy, charge, dangling and under-coordinated atoms, unusual coordination, symmetry), command-log change bursts, typed JSON answers and a pure-Rust orthographic renderer to SVG and PNG. CLIcapabilities,renderandagent; PythonAgentSession,agent_run,agent_capabilities,agent_verbs; WASMAgentSession,agent_run,agent_capabilities,agent_verbs. The WASM size budget moves from 3648 to 3840 KiB to carry the new exported surface (3775 KiB). - Phase 0 Task 0.9: external validation suite. EQeq is compared with the authors' program on the COD MOF-5 cell (424 charges within 1e-3 e), UFF with sci-form on methane and stretched water (within 1e-4 kcal/mol), and the DFTB+ parser with a recorded Si SCC output.
docs/algorithms/external-validation.mdrecords the bundled sources, their licences and the data sets still to add. - Phase 5 Task 5.6: bundle the full RCSR 2019-06-01 snapshot in
data/rcsr/and identify nets by coordination sequence and point symbol against all 2,931 entries.RcsrIndex::from_embedded()returnsRcsrIdentificationwith the unique name, an ambiguous set, or the nearest candidates; the 2,909 keyed entries are validated against their canonical keys at index build time. The CGD reader now accepts both RCSR edge dialects. - Phase 6 Task 6.8: the disordered-carbon recipe builder: convolution surface around a periodic net, split/collapse/flip remesh with tangential relaxation and projection, ribbon paths over the triangle graph, a three-coordinate dual and H/F/O edge termination.
CarbonBuildreports density, ratios, ring census, mean C-C, pieces and periodicity; CLIbuild carbon, Pythonbuild_carbon, WASMbuild_carbon_recipe_info. - Phase 7 Task 7.10.1: every leading-cell row now carries
space_groups, the candidates whose general-position systematic absences every indexed reflection obeys. The screen enumerates the cell's crystal system, evaluates the structure factor of two generic points per reflection and ranks by group order; CLI, Python and WASM expose the candidates. - Phase 7 Task 7.10.1: the automatic table now ranks extinction classes by a Le Bail BIC and Pawley-fits every leading (cell, class), as the reference does. A row carries
cell_rank,class_rank,class_symbol,delta_bicand the groups that share the class; the 1 % Rwp tie rule orders the table. - Phase 4 Task 4.9: validate the DFTB+ energy, force, stress and population parser against the recorded
si_scc_detailed.outfixture. The xTB GFN methods remain available in-process throughsci-form(Task 4.10). - Phase 1 Task 1.12:
rings_explicitandring_counts_explicitcensus a builder's stored bonds without distance perception.
Added
- Phase 4 Task 4.10: link the published MIT crate
sci-form2.0.0 behind the optionalsci-formfeature and implementCalculatorfor GFN0, GFN1 and GFN2-xTB. The methods are molecular only (a space-group structure is refused), GFN2 returns central-difference forces, and GFN0/GFN1 refuseenergy_forces. The registry listsgfn0,gfn1andgfn2.
Fixed
- Phase 5 Task 5.4: order the four crossings of a marching-tetrahedra 2-2 split around their quadrilateral. The fan taken in the generation order crossed itself, leaving non-manifold edges and a surface that was not watertight.
- Phase 7 Task 7.6.3: Le Bail extraction returns intensity esds from the profile normal matrix, plus Rwp and the reduced chi-squared; the CLI report includes them.
- Phase 7 Task 7.10.1: the automatic run fits a Pawley model of every leading indexing candidate and returns a table sorted by Pawley Rwp, with the cell esds; CLI, Python and WASM expose the table.
- Phase 7 Task 7.8: run the Rietveld refinement in McCusker order (analytic scale/background, zero shift and free cell numbers, width, then Wyckoff coordinates, isotropic ADPs, occupancies and March-Dollase texture) with a bounded direct search per stage, covariance-based parameter esds and the
stageslist. Coordinates move only along the Wyckoff null space (free_directions), the metric-family cell ties are restored after every move, and the copper K alpha doublet can be placed. A rutile golden pattern from Crystal-Builder validates the recovered position, cell and zero shift. - Phase 7 Task 7.6.2: add the Pawley fit with one intensity per reflection, exact linear covariance and intensity esds, free cell numbers, zero shift and size/strain width model, R-factors and chi-squared; a Python-generated golden pattern validates the recovery.
- Phase 7 Task 7.10: the automatic run indexes the five metric families and adds a Pawley step of the indexed cell; Python
powder_pawleyand WASMpowder_pawley_infoexpose the fit. - Phase 7 Task 7.5.1/7.5.2: add general metric-family indexing (cubic, tetragonal, hexagonal, orthorhombic, monoclinic) with cell refinement, de Wolff M20, Smith-Snyder F_N and a coverage-ranked table; Python
powder_index, WASMpowder_index_infoandpowder index --general. - Phase 7 Task 7.3.1: add the SNIP background envelope, per-line Gaussian plus linear background fitting and
fit_peaks, with--backgroundand--refine-peakson the CLI. - Phase 1 Task 1.15.4: map a non-P1
_geom_bondrow from its site labels, operation code and image to P1 contacts (MIL53 matches the 36 golden contacts), collapsing symmetry-equivalent images by their minimum-image vector. Unmatched records annotate nothing instead of inventing an edge. - Phase 1 Task 1.15.4: warn when a CIF operation loop's count disagrees with the named space group.
- Phase 3 Task 3.6.3: add LAMMPS text dump (element column or type map, orthogonal/triclinic, Cartesian/scaled coordinates) and DFTB+
geo_endreaders to the trajectory dispatcher. - Phase 1 Task 1.15.4: write non-P1 explicit bonds back as a validated P1-index CIF loop and compare the full symmetry-operation set with the named space group, not only its count.
- Phase 4 Task 4.7: choose overlapping disorder components from the declared CIF formula and cell charge, make the planner graph-aware, add hydrogen filling, the close-contact list, the prepared-structure undoable command path and their tests.
- Phase 4 Task 4.9.2/4.9.3: wire
DftbCalculatorandXtbCalculatorto the runner, parsedetailed.out/xTB stdout, validate force counts and support timeout, cancellation and scratch inspection. - Phase 4 Task 4.9.1: add the scratch-folder process runner with wall-clock timeout, cancellation, capped stdout/stderr logs, relative input files and simulated-executable tests.
- Phase 4 Task 4.7: add duplicate merging, disorder-component choice, solvent removal, charge-balance reporting and the prepared-sample golden sanity pass;
PrepareReportnow returns the prepared structure. - Phase 4 Task 4.8.3: add supercell force constants, shortest-image folding, the acoustic sum rule, a Monkhorst-Pack q-mesh, Gaussian phonon DOS and a phonopy spring-model golden comparison. An explicit
q_pathsamples a band path.
Changed
- The workspace version is
1.0.0-rc.1; the facade now forwardssci-formtoxtalforge-ffandxtalforge-agentinstead of declaring a no-op. - The agent crate joins the published set and the crates.io publication order (after the domain crates, before the facade).
- The WASM release budget is 3840 KiB (3767 KiB measured).
- Python wheels are built for manylinux/musllinux (x86_64, aarch64), macOS (x86_64, arm64) and Windows (x86_64), plus an sdist.
[0.0.3] - 2026-11-09
Changed
- Phase 1 Task 1.11.1/1.11.5: perceive bonds with the reference defaults (
scale = 1.15, metal-metal pairs forbidden) and validate the full golden corpus: every available bond set and coordination number matches Crystal-Builder after P1 atom mapping. - Phase 1 Task 1.6/1.15: expand each site on its own duplicate grid, so disorder components at the same position both survive, and resolve a CIF Hall/H-M symbol into operations when the file omits the operation loop.
- Phase 1 Task 1.12: replace the chordless-cycle scan with the periodic Franzblau walk, expose
Ring::path/ring_pathswith lattice images on all four surfaces, and validate counts and paths against the golden corpus. - Phase 1 Task 1.15.4: round-trip Uij (matched by label), disorder group/assembly, the oxidation-number charge fallback and the explicit-bond loop; split the CIF writer and structure extraction under
cif/. - Phase 3 Task 3.6.2/3.6.3: add lazy
XyzIndexframe access and the VASP XDATCAR reader with XYZ/XDATCAR detection in the CLI.
[0.0.2] - 2026-11-09
Changed
- Phase 1 Task 1.10.1/1.10.2: replace the direct periodic pair scan with a linked-cell index in fractional space and exact image enumeration, add the 10^3/10^4/10^5-atom benchmark target and compare it with Crystal-Builder.
- Phase 1 Task 1.10.2: P1 expansion now deduplicates through a fractional grid, removing the quadratic scan that dominated large structures.
- Phase 1 Task 1.7.1: supercell boundary duplicates use the same fractional grid, cutting the 2x2x2 MOF-5 build from 37.5 ms to 5.5 ms.
Fixed
- Rename the Linux desktop entry to the reverse-DNS component ID so
appimagetoolfinds the AppStream metadata; the AppImage build no longer reports the missing-metadata warning, and the.deb/.rpmpayloads carry the matching desktop ID.
[0.0.1] - 2026-11-08
Changed
- Refresh the documentation against the implemented Phase 1-7 surface: the README status, guide, API pages, algorithm pages, validation table, benchmark notes, third-party attribution and roadmap current-status/gap list.
- Record the remaining documented subsets (neighbour acceleration, phonon q-mesh, preparation steps, general indexing and figures of merit, powder profile simplifications) in
docs/roadmap/index.md.
Fixed
- Upgrade
zipto 9.4.2, clearing RUSTSEC-2026-0367, RUSTSEC-2026-0368, RUSTSEC-2026-0369 and RUSTSEC-2026-0429. - Fix the rustdoc intra-doc links that failed
cargo doc -D warnings. - Expose C20, twists, ribbons, ZTC/Schwarz P surfaces and polymers in the CLI, Python and WASM, closing the Phase 6 surface-parity gaps; add regression tests for each surface.
Added
Phase 6 Task 6.1/6.5/6.7/6.8/6.9: SMILES 3D embedding, metal coordination, the sketch model and SMILES writer, commensurate twists, C20/C60 face spirals, gyroid/Schwarz P carbon surfaces and polymer chain packing.
Phase 7 Task 7.1-7.11: the rietx inventory and acceptance metrics, the instrument model, whole-range and structural least-squares refinement, free cell parameters and extinction symbols, the combined objective, the automatic powder run, and the CLI/Python/WASM surfaces.
Phase 6 Task 6.11-6.16: the
xtalforge-mofcrate with six topologies, eight blocks, framework assembly, rods, layers, merged nets, decoration, invented linkers and pore-space partition.Phase 6 Task 6.17:
mofCLI commands, Python/WASM catalogues and builder, and the MOF API page.Phase 4 Task 4.3.3: native EEQ-style charges.
Phase 4 Task 4.6: hydrogen placement.
Phase 4 Task 4.7: the preparation pipeline and report.
Phase 4 Task 4.9: engine probes plus DFTB+, xTB and ORCA input writers and output parsers.
Phase 4 Task 4.10: the sci-form adapter contract and capability limits.
Phase 4 Task 4.12:
ffCLI commands, Python/WASM force-field surfaces and the algorithm pages.Phase 3 Task 3.7: the
.xtalprojZIP container with independentformat_version, readable parts and a newer-version gate.Phase 3 Task 3.8.2:
symmetry,pxrdanduffparameter presets shared by the CLI, Python and WASM schemas.Phase 3 Task 3.10.7:
SetCharges,InterpenetrateandMarkConnectionPointscommands.Phase 3 Task 3.12.3: in-memory workspace archives for WASM and on-disk workspace binding for Python.
Phase 3 Task 3.16:
formats,params,project,trajectoryandscriptCLI commands; PythonDocument/project/workspace bindings; WASMWasmDocumentplus project and workspace exports; the editor demo.Phase 4 Task 4.8: Gamma-point Hessian, vibrational modes, IR spectrum, Gamma-point phonons, harmonic/ideal-gas thermochemistry and the quasi-harmonic free-energy scan.
Phase 4 Task 4.3-4.5: QEq/EQeq charges, per-site charges, Ewald energy and forces, FIRE/L-BFGS optimization (P1/asymmetric, optional cell), equations of state and relaxed scans.
Phase 4 Task 4.1/4.2: Calculator API, registry, run records and the native UFF/UFF4MOF engine with analytic gradients.
Phase 5 Task 5.1-5.3: calculated PXRD with radiation, reflections, structure factors, LP and profiles; periodic distance grids and porosity.
Phase 6 Task 6.5/6.6: graphene sheets/stacks and nanotube roll-up builders.
Phase 3: format registry with capabilities/loss warnings, atomic writes, pymatgen JSON/CSSR/GEN/LAMMPS/SHELX/PDB, CGD nets, Grid3/cube/XY, trajectories, typed parameters, commands/document with undo, selection and tracking, workspace/modules, view data, colormaps and ASCII STL.
Phase 3 Task 3.1-3.3: the format registry with capabilities and loss warnings, atomic writes, and pymatgen JSON, CSSR and DFTB+ GEN readers and writers.
Phase 2 Task 2.8: layer-group detection for slabs, experimental collinear magnetic groups and molecular point groups.
Phase 2 Task 2.10.2-2.10.4: Bravais classification, ASE-derived special points and band paths in the user's reciprocal basis.
Phase 2 Task 2.3.5: change of setting by Hall number.
Project bootstrap:
AGENTS.mdrules and versioning policy, roadmap (phases 0 to 8, verified against the Crystal-Builder, sci-form and moyo sources), rule-check script, and VitePress documentation scaffold.Cargo workspace (Task 0.1.1) with
xtalforge-core,xtalforge-symmetry,xtalforge-io, the facadextalforge,xtalforge-cli,xtalforge-pythonandxtalforge-wasm; shared versions fornalgebra,serde,thiserror,rayon,moyoandflate2.Toolchain, formatting and lint configuration (Task 0.1.2):
rust-toolchain.toml,rustfmt.tomland the workspace lints for unsafe code, missing docs, warnings and panic-prone patterns.Repository hygiene (Task 0.1.3):
.editorconfiganddeny.tomlwith the license allow list, advisory checks, duplicate-version ban and native-build bans.Facade crate (Task 0.1.4) with stable
core,symmetryandiomodule names, a prelude, and theparallel,sci-form,ml,externalandmof-datafeatures documented in the crate and in the guide.Contributor guide (Task 0.1.5) and the Cargo features guide.
Rule-check self-test (Task 0.2.1): positive and negative fixtures and a runner covering the 500-line boundary and the ban on warning-suppression attributes.
Optional Git hook (Task 0.2.2):
scripts/install-hooks.shand a pre-commit hook running the rules, formatting and clippy on touched crates.CI workflow for the repository rules and their self-test (Task 0.2.4), plus blocking formatting and clippy jobs with warnings denied.
Data bundle loader (Task 0.2.3):
xtalforge_core::datawith embedded gzip bundles, SHA-256 verification of the decompressed payload, once-only decompression and JSON decoding throughOnceLock, and lazy external bundles for WASM and large databases.Data policy page and the
data/directory convention, including the gzip fixture and checksum tests for the loader.moyo audit (Task 0.3): requirements matrix, gap decisions, eight-structure spglib comparison at four tolerances, wasm/pyo3 build check, and the report in
docs/algorithms/symmetry-backend.md.sci-form reuse audit (Task 0.4): verified inventory, port quality gate, overlap decisions and the
sci-formfeature policy indocs/algorithms/sci-form-reuse.md.Hello-world slice (Task 0.5):
version()andcell_volume()in the Rust API, CLI, Python wheel and WASM package; shared vectors, API pages, parity check, binding architecture and error mapping.Version and release tooling (Task 0.6):
scripts/sync-version.shwith a self-test, agent-version check, pull request template and release workflow.Documentation site (Task 0.7): edit links, search, repository link, API and algorithm pages, four-surface code groups, KaTeX, and an offline cell-volume WASM demo.
CI workflows (Task 0.8): Rust matrix, Python, WASM, docs, caching and path filters, plus the existing rules job.
Golden-data oracle (Task 0.9): curated
tests/corpus/with provenance, Phase 1 generator and data, Crystal-Builder test-data inventory,xtalforge-testkitand the regeneration policy.Dependency replacement map (Task 0.10): import survey, replacement decisions and license status for every Python dependency.
Mandatory test layout (AGENTS.md section 2.2): Rust tests live in
crates/<crate>/tests/, independent of the source files.Phase 1 Task 1.1: periodic table, deuterium and dummy species, Pyykko radii, symbol parsing,
element_infoin Rust, CLI, Python and WASM, the generated API table and the shared element vectors.Phase 1 Task 1.2:
Latticewith matrix rows, standard orientation, parameters, volume, metric tensor, reciprocal cells, d-spacing and plane normals, coordinate conversions, wrapping, exact minimum-image search, transforms, strain, volume scaling and validation;cell --paramsin the CLI andlattice_info/lattice_minimum_imagein Python and WASM.Phase 1 Task 1.3: the limits model with Standard/Generous/WarnOnly profiles, soft and hard verdicts, drawn/supercell/grid/phonon/Hessian estimates,
Error::LimitExceeded, andlimits_bounds/limits_checkin Rust, Python and WASM.Phase 1 Task 1.4:
Site(label, canonical element, occupancy, Uiso/Uij, charge, disorder group, props),Structure/StructureBuilder, molecule in a padded box, formula/mass/density/charge properties, theinfoCLI bridge andstructure_infoin Python and WASM.Phase 1 Task 1.5:
StructureDocumentwithSCHEMA_VERSION, strict top-level fields, version checks and a versioned fixture.Phase 1 Task 1.6:
SymOpparsing/printing/composition/inversion andP1Cell/P1Atomexpansion with site/operation/lattice provenance and special-position deduplication.Phase 1 Task 1.7: diagonal and general supercells as P1, origin shifts, metadata/site-property preservation and the supercell limit check.
Phase 1 Task 1.8: surface bases for arbitrary Miller planes, slab construction with layers, vacuum and P1 output, and plane angles.
Phase 1 Task 1.9: finite-cell images, Cartesian point transforms, plane fitting/alignment and displacement ellipsoids.
Phase 1 Task 1.10: periodic neighbor search with images, distances and deterministic ordering;
neighborsandneighbors_of.Phase 1 Task 1.11.1/1.11.4: distance-based bond perception with covalent radii, dummy exclusion, bond images and the connectivity graph.
Changed
- License is now
MIT OR Apache-2.0(confirmed by the maintainer, Task 0.1.3), replacing the initial MIT-onlyLICENSEwithLICENSE-MITandLICENSE-APACHE. - The English-only rule is retired (maintainer decision, 2026-11-08). The language checker, allow list, Spanish fixtures and commit-msg hook were removed; no language check runs in CI.
- Workspace lints deny warnings and missing docs.
scripts/check-rules.shrejectsallow/expectattributes for dead code, unused lints and warnings. - Commit discipline adopted (AGENTS.md section 2.1): one directory per commit,
feat(<scope>):orref(<scope>):subjects, and the completed tasks listed from hardest to easiest in the body. The optional pre-commit and commit-msg hooks enforce the directory scope and the message format. - Workspace
unsafe_codechanged fromforbidtodenyso the pyo3 binding crate can relax it locally with a comment, as the roadmap allows. - GitHub Actions workflows are committed but disabled at repository level by maintainer instruction; they have not run yet.