This library deliberately tries to stay small. The value comes from a stable, high-quality set of atoms that agents can trust and reuse, not from an ever-growing catalog of slightly different variants.
Before proposing a new atom, ask:
- Can the requirement be expressed by composing existing atoms?
- Is the concept truly recurring across many systems, or is it domain-specific?
- Does it have a clear, minimal interface?
If the answer to (1) is yes, prefer composition. If the concept is highly domain-specific, it may belong in a separate domain pack rather than the core table.
Check whether the concept is already covered, including via composesWith:
npm run search -- your-term
npm run search -- your-term --family actions # names can repeat across familiesFive names each exist in two families — Email, Message, Search, Trigger,
Schedule — with distinct symbols. Always resolve a name within its family.
- Update
ontology/periodic-table.jsonwith a stableid,symbol,name,family, anddescription. - Pick an
idinside the family's range. The ranges are declared in the ontology itself (familyRanges) and enforced by the validator, so do not hardcode them. - Add or update the corresponding TypeScript definition under
atoms/. - Prefer pure data + small functions. Avoid framework-specific code in the core atoms.
- Add a test.
npm testcovers the validator, the schema validator, the eval metrics, and the atom implementations. A new atom without a test is incomplete:test/atom-test-coverage.test.tsfails if the module is never imported by a test, and the contribution is expected to assert behaviour, not merely import it.npm run coverageis a different check — it measures whether an implementation exists, not whether it is tested. - Keep the public surface minimal and well-typed.
npm run validate fails on any of these, and test/ontology.test.ts asserts that
it fails on each one:
- Every element matches
ontology/periodic-table.schema.json. idandsymbolare unique.idfalls inside the range declared for its family, and every id in every family range is allocated exactly once — no gaps, no overlaps.familyis one of the six.- Every
composesWithsymbol resolves to a real element. - An element does not compose with itself (a warning, not an error).
npm run coverage additionally cross-checks the two directories against each
other: an atom file with no ontology entry is an orphan, and a mismatch between
an atom's declared symbol/name and the ontology is an error. Renaming a
symbol in one place and not the other will fail CI.
- Objects — nouns with identity.
- Properties — typed fields and common vocabularies.
- Actions — declarative operations (execution is the host's job).
- Interfaces — presentation and interaction surfaces.
- Intelligence — model-backed capabilities with clear contracts.
- Rules — triggers, conditions, permissions, audit.
- TypeScript, strict mode, with
noUncheckedIndexedAccessenabled. Indexing an array or record and gettingundefinedis a type error, not a surprise. - No runtime dependencies in core atoms. The schema validator in
src/jsonschema.tsis hand-written for exactly this reason. - Prefer explicit interfaces over heavy class hierarchies.
- Document the intended composition patterns in comments or short markdown notes.
- Relative imports carry their
.jsextension, so the source runs undertsxand the compiled output runs under plainnode.
If you change composition behaviour or the eval metrics, add a case to
test/metrics.test.ts. Those tests exist because the harness previously had
three defects that silently produced plausible-looking numbers:
planOverlapcounted the characters of a plan's free-textnotesfield.- Acceptance criteria passed on any non-empty plan, because an unmatched criterion fell through to a default.
- A name-to-symbol lookup resolved across families, so an ambiguous name landed in whichever family was declared last.
If you change what a metric means, update docs/EVAL_RESULTS.md and
eval/README.md in the same change. That document records which numbers are
trustworthy and why, including one that had to be withdrawn.
Run the full gate before opening:
npm run ciThis runs validation, the coverage report, lint, type-checking across all three tsconfig projects, the test suite, a build, every example, and the evaluation self-check. The PR template repeats this checklist.