Skip to content

openehr-specs: add bmm-authoring skill for writing and checking BMM schemas - #11

Merged
sebastian-iancu merged 7 commits into
mainfrom
feat/openehr-specs-bmm-authoring
Oct 9, 2026
Merged

sebastian-iancu merged 7 commits into
mainfrom
feat/openehr-specs-bmm-authoring

Conversation

@sebastian-iancu

@sebastian-iancu sebastian-iancu commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds bmm-authoring, a skill for writing a component's BMM schema (the P_BMM JSON in computable/BMM/) from scratch or changing one. Until now the plugin only covered generating class tables from a BMM (class-generation).

File Contents
SKILL.md The workflow for changing a schema and for writing a new one, including the empty schema that scaffold creates. Also a quick reference from construct to JSON, how to run the checker, and guardrails, such as editing the JSON in place because the published files mix PHP-style escapes with raw characters.
references/p-bmm-json.md The JSON format. It was checked against the development BMM Persistence spec, the P_BMM classes in the LANG BMM, the published schemas, and what bmm-publisher 0.12.0 reads and renders. It lists what the class tables leave out, the spec features the publisher ignores (indexed containers, ancestor_defs, type_ref value sets) with what to write instead, and how the spec's ODIN and YAML examples map to JSON.
assets/openehr_demo_0.1.0.bmm.json A worked example with one of each common construct. It passes the checker and renders cleanly.
scripts/check_bmm.py A read-only checker in standard-library Python 3.8+.

The checker is there because bmm-publisher exits 0 on modelling mistakes such as these, and renders something else in their place. It reports, for example:

  • a misspelt or missing _type, or a misspelt key such as is_mandatory;
  • a class in no package, or more than four package levels deep, which gets no table;
  • {"lower": 2, "upper": 5} without "upper_unbounded": false, which loses its upper limit;
  • type nestings that render as List<Any>, print nothing, or crash the publisher;
  • a generic argument that does not conform to its parameter's conforms_to_type.

It exits 0 when the check is complete with no errors, 1 on errors, 2 on unreadable input, and 3 when names from an included schema went unchecked because that schema was not passed with -d.

Other changes:

  • class-generation, authoring and scaffold send BMM schema edits to bmm-authoring, and so does the AGENTS.md that scaffold writes. Template set revision 3 is not in a plugin release yet, so it was edited in place and its digest recomputed. Its empty schema now uses 4-space indentation, like the published schemas.
  • The prompting guide (with a new section for a new component's schema), plugin README, AGENTS.md, docs/testing.md and the CHANGELOG are updated.
  • main (with openehr-specs: scaffold a computable/BMM schema in new repositories #9) is merged in.

How it was tested

  • Without the skill, two agents did a from-scratch task and an edit task. The from-scratch agent made 35 tool calls, most of them reading parser and publisher source. The edit agent used the persistence spec's own forms, and three of those forms rendered wrong without a warning. With the skill, neither agent read any source code, the new schema passed the checker on its first run, and the edit avoided all three problems.
  • /pr-review-toolkit:review-pr (code, tests, documentation, silent failures) ran twice. Each finding was checked against the parser and publisher source, or a publisher run, before it was fixed.
  • plugin-dev:skill-reviewer reviewed the skill and its routing in the sibling skills. Fixes made from its findings cover rename and removal, the commit rule, a single schema_revision bump per change set, and the scaffold AGENTS.md routing. A docs-editing prose review covered the CHANGELOG, the docs and this description.
  • scripts/test_check_bmm.py has 107 tests (239 in the whole suite). Every finding the checker can report has a test: disabling any one of them makes at least one test fail. The tests' BASE stub copies the real ancestry and generic constraints. A wrongly typed value at any node of the worked example must produce a finding, not a traceback.
  • The checker was run over the current schema of each component (BASE 1.3.0, RM 1.2.0, AM 1.4.0 and 2.4.0, LANG 1.1.0 and its BMM3 variant, TERM 3.1.0) with their dependencies. Its errors, and one TERM warning, are the defects listed below. BASE also gets one warning, for an undocumented class.

Defects found in published schemas (not fixed here)

  • AM 2.4.0 P_ARCHETYPE_SLOT.includes and excludes: a List with no element type, which the published table shows as List<Any>.
  • AM 2.4.0 c_conforms_to(rmcc) in eight classes: FUNCTION<Boolean, TUPLE2<String, String>>. BASE declares FUNCTION<ARGS, RESULT> and the AOM2 text says FUNCTION<<a_type, other_type: String>, Boolean>, so the arguments are in reverse order.
  • LANG 1.1.0 BMM3 BMM_CLASS.features and flat_features: a result List with no element type.
  • TERM 3.1.0 uses BASE types without listing BASE in includes (a warning).

Checklist

  • python3 scripts/validate.py and python3 -m unittest discover -s scripts -p 'test_*.py' pass (239 tests); claude plugin validate plugins/openehr-specs --strict passes
  • Skill triggering tested locally in Claude Code: not done. Agents read the skill directly; it was not run from an installed plugin
  • Cursor install tested locally: not done
  • Both marketplaces updated when plugin metadata changed: no metadata change
  • CHANGELOG.md updated under Unreleased; no version bump
  • Content grounded in published openEHR specifications: identifiers checked against the persistence spec, the LANG BMM class model and the published schemas; parser and table behaviour checked by running bmm-publisher 0.12.0

🤖 Generated with Claude Code

Add a knowledge skill for writing a component's BMM schema (the P_BMM
JSON in computable/BMM/) from scratch or changing one: header
conventions, includes, how packages set the class-table file names and
{pkg}, every class, property, type and function kind, invariants and
constants, documentation text, what the legacy class tables do not
show, and the persistence-spec features bmm-publisher does not read
(indexed containers, ancestor_defs, type_ref value sets), with the form
to write instead.

bmm-publisher renders most modelling mistakes without a message (a
misspelt _type becomes a property of type Any, unknown keys are
ignored, a class missing from packages gets no table), so the skill
ships a read-only, standard-library checker (scripts/check_bmm.py) and
a worked example that passes it and renders cleanly. CI runs the
checker's unit tests.

class-generation and authoring now route changes to the class model to
bmm-authoring; the prompting guide, plugin README, AGENTS.md and
testing docs list the new skill and script.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@SevKohler

Copy link
Copy Markdown
Contributor

Add exclusions for folders without BMM ITS REST etc.

sebastian-iancu and others added 4 commits October 9, 2026 14:22
# Conflicts:
#	AGENTS.md
#	CHANGELOG.md
Review of #11 found that the checker could pass schemas bmm-publisher
mis-renders, and could crash on malformed input:

- A run without -d for an included schema exits 3 (incomplete) instead
  of 0, also under --strict; the summary counts the unchecked names, and
  names close to a known class are still flagged ("did you mean").
- No traceback on wrongly typed values; a non-UTF-8 file, or a -d file
  that is not a BMM schema, exits 2. Duplicate -d schema ids are merged.
- Type shapes bmm-publisher renders wrongly are errors: a simple type in
  a container's type_def (List<Any>), a non-generic type object in
  generic_parameters (publisher crash), generic_parameters and
  generic_parameter_defs together (defs ignored), a container type in
  generic_parameter_defs (prints nothing).
- Generic arguments bind by position, as bmm-publisher renders them; an
  argument that is the enclosing class's parameter conforms through its
  own constraint.
- An unknown _type is reported and the item is still checked, as the
  closest known kind. Lost content is an error: a parent only in
  ancestor_defs, index_type, class keys on enumerations and interfaces.
- Classes in packages deeper than four levels (no table) are errors.
- Corrected: a container parameter's cardinality is optional (the parser
  defaults it), a missing bmm_version is a warning, class_definitions is
  optional, void is accepted only as a function result, and only
  lower-case {attribute} references are flagged.

Tests cover every finding the checker can report (a mutation run that
disables each one in turn leaves no test green), use a slice of the real
BASE ancestry and constraints, and put a wrongly typed value at every
node of the worked example.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the checker

- The reference now follows the development BMM Persistence spec, which
  names JSON as bmm-publisher's primary format and covers functions,
  constants and invariants (P_BMM 2.4): corrected chapter names, the
  procedure rule (no result, written as void in the published schemas),
  class_definitions as optional, aliases as written, constant values,
  invariant and condition tags, and the documentation escaping rules.
- It documents what bmm-publisher renders wrongly and how to avoid it:
  simple element types, type objects in generic_parameters, both
  generic-parameter forms at once, containers in generic_parameter_defs,
  binding by position, the four-level package limit, enumeration values,
  and which maps keep their keys.
- Corrected: a document can have several top-level packages; ITS-BMM
  republishes only from repos that carry its notify workflow; a
  container parameter's cardinality is optional; lifecycle values for an
  unreleased schema are a suggestion to confirm.
- SKILL.md: compare checker output before and after with diff, treat
  exit 3 as an incomplete check, report a schema as unchecked without
  python3, and replace the scaffold starter's root package.
- scaffold routes filling a new repository's empty schema to
  bmm-authoring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A class with an unknown _type has its keys checked as the plain class
  bmm-publisher reads it as, so a near-miss such as P_BMM_INTERFACES no
  longer reports its properties as lost.
- While an included schema is not loaded, a name close to a local class
  (ARCHETYPE_ID next to ARCHETYPED) is counted as unchecked, with the
  suggestion in the INFO line, instead of a false warning.
- The "incomplete" notice and the unchecked count are printed whatever
  the exit status, so a run with errors still says it was incomplete.
- Input nested too deeply to read or check exits 2 without a traceback.
- An empty ancestor_defs loses no parent and is no longer an error.
- Reference: maps keyed by name versus a type's generic_parameter_defs,
  the Required legend, nested container types, binding order, condition
  tags, and constant values as the P_BMM model types them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sebastian-iancu and others added 2 commits October 9, 2026 17:00
…plain-language pass on the docs

Split the long bmm-authoring CHANGELOG entry into short sub-bullets and
use one term, "BMM schema edits", for the routing. Give the new-component
prompt its own prompting-guide section, say what Claude does after each
BMM prompt, and keep testing.md and the README to what the tests and the
skill actually cover.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…outing

bmm-authoring: imperative wording without "you"; a description that also
routes archetype work away and triggers on fixing a .bmm.json; one
schema_revision bump per change set; a step for renames and removals;
source changes committed together; exit 0 no longer called clean; the
reference sections named instead of repeated; the from-scratch steps
say which release and what to do when no :pkg: is set yet.

scaffold template set revision 3 (unreleased, resealed): the AGENTS.md
task table and build region send BMM schema edits to bmm-authoring, and
the empty schema uses 4-space indentation like the published schemas.

class-generation runs the checker first after a hand edit; authoring's
related-skill line matches it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sebastian-iancu
sebastian-iancu merged commit 093328a into main Oct 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants