Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Checklist

- [ ] `python3 scripts/validate.py` passes
- [ ] `python3 scripts/validate.py` and `python3 -m unittest discover -s scripts -p 'test_*.py'` pass
- [ ] Skill triggering tested locally in Claude Code (see [docs/testing.md](../docs/testing.md))
- [ ] Cursor install tested locally when plugin or manifest content changed (see [docs/install.md](../docs/install.md#cursor))
- [ ] Both marketplaces updated when plugin metadata changed: `.claude-plugin/marketplace.json` and `.cursor-plugin/marketplace.json` (plus matching `plugin.json` files under `plugins/<name>/`)
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: python3 scripts/validate.py
- run: python3 -m unittest discover -s scripts -p 'test_*.py'
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
.DS_Store
Thumbs.db

# Python bytecode (from the scaffold script and its tests)
__pycache__/

# Claude Code local settings
.claude/settings.local.json

Expand Down
15 changes: 9 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@ ai-plugins/
├── .claude-plugin/marketplace.json # Claude Code marketplace manifest
├── .cursor-plugin/marketplace.json # Cursor marketplace manifest
├── docs/ # Contributor and user documentation
├── scripts/validate.py # Manifest and frontmatter validation (CI)
├── scripts/validate.py # Manifest, frontmatter and template-set validation (CI)
├── scripts/test_scaffold.py # Unit tests for the scaffold skill's script (CI)
├── CHANGELOG.md # Release notes per plugin
└── plugins/<plugin-name>/ # One directory per plugin
├── .claude-plugin/plugin.json # Claude Code plugin manifest
├── .cursor-plugin/plugin.json # Cursor plugin manifest
├── README.md # Plugin purpose, install, and component inventory
├── skills/<skill-name>/ # Knowledge/workflow skills; user-only actions set disable-model-invocation: true
│ ├── SKILL.md # Skill definition (YAML frontmatter + body)
│ └── references/ # Optional supplementary content
│ ├── references/ # Optional supplementary content
│ └── assets/, scripts/ # Optional bundled templates and scripts (see `scaffold`)
└── agents/<agent>.md # Autonomous subagents (context-isolated, multi-file)
```

Expand All @@ -30,7 +32,7 @@ Current plugins: `openehr-specs` (skills, including user-only action skills, and
## Key Conventions

- Plugin names: `openehr-<domain>` (mandatory prefix — flat global namespace); skill names: terse activity nouns with no prefix (auto-namespaced as `<plugin>:<skill>`). User-only action skills and subagents follow the same no-prefix rule (`spec-reviewer` is the one exception).
- Component choice follows the *nature of the work*: **skills** = knowledge/workflows (model- or user-invoked); **user-only action skills** (`publish`, `regen-classes`) = user-initiated actions, also in `skills/`, marked `disable-model-invocation: true` so their descriptions stay out of context and they don't compete with knowledge-skill triggering (Claude Code treats `commands/` as the older format, so new actions are skills); **subagents** (`agents/`) = context-heavy, multi-file, or adversarial work that would otherwise pollute the main context. Action skills and agents reference their sibling knowledge skill rather than duplicating it.
- Component choice follows the *nature of the work*: **skills** = knowledge/workflows (model- or user-invoked); **user-only action skills** (`publish`, `regen-classes`, `scaffold`) = user-initiated actions, also in `skills/`, marked `disable-model-invocation: true` so their descriptions stay out of context and they don't compete with knowledge-skill triggering (Claude Code treats `commands/` as the older format, so new actions are skills); **subagents** (`agents/`) = context-heavy, multi-file, or adversarial work that would otherwise pollute the main context. Action skills and agents reference their sibling knowledge skill rather than duplicating it.
- Skill `description` frontmatter is lean (~50–75 words): one what+scope sentence → a few representative triggers → short "Not for …" anti-triggers routing to the right sibling/plugin.
- Keep each `SKILL.md` body a lean overview (quick-reference + pointers); push bulky detail (tables, templates, format specs) into `references/` so it loads only on demand.
- Versions must stay in sync across both plugin manifests (`.claude-plugin/` and `.cursor-plugin/`), both marketplace entries, and the release tag (`{name}--v{version}`).
Expand All @@ -42,21 +44,22 @@ Full details: [docs/skill-authoring.md](docs/skill-authoring.md)

## Development

Pure-content repository (JSON manifests + markdown skills) — no build step, package manager, or test suite.
Pure-content repository (JSON manifests + markdown skills) — no build step or package manager. The one script, the `scaffold` skill's `scripts/scaffold.py`, has unit tests: `python3 -m unittest discover -s scripts -p 'test_*.py'` (runs in CI).

- **Validation**: `python3 scripts/validate.py` (Claude + Cursor manifests, version sync, required skill/agent frontmatter fields, component paths — runs in CI; it does not check description length, inventories, or the release tag)
- **Validation**: `python3 scripts/validate.py` (Claude + Cursor manifests, version sync, required skill/agent frontmatter fields, component paths, and the `scaffold` template set's integrity — runs in CI; it does not check description length, inventories, or the release tag)
- **Local testing**: [docs/testing.md](docs/testing.md); **versioning/releases**: [docs/versioning.md](docs/versioning.md)
- **End-user installation**: [docs/install.md](docs/install.md)
- **Generating/editing AsciiDoc for `specifications-XX` repos**: follow [docs/spec-style-guide.md](docs/spec-style-guide.md); skill bodies must agree with it — when changing one, check the other.

## Component Dependencies

The skills are pure content; the subagents and the `publish` and `regen-classes` action skills rely on external tools and degrade
The skills are pure content; the subagents and the `publish`, `regen-classes` and `scaffold` action skills rely on external tools and degrade
gracefully when one is absent (each says so in its prompt):

- **`spec-reviewer`, `xref-auditor`** — need a `specifications-XX` checkout and (for attribute resolution) the sibling `specifications-AA_GLOBAL`.
- **`xref-auditor`, `identifier-grounding`** — use **WebFetch** to read spec Markdown twins (`.html` → `.md`); `identifier-grounding` additionally prefers the **`openehr-assistant` MCP** (`type_specification_get`) when connected, falling back to the twin.
- **`regen-classes`** — needs **Docker** (`ghcr.io/openehr/bmm-publisher`).
- **`scaffold`** — needs **`python3`** (standard library only) to run its bundled `scripts/scaffold.py`, and says so and stops when it is missing. It writes into the repository it is run in, so it plans first and never overwrites a hand-edited file without being told to.
- **`publish`** — needs **Docker** and sibling `specifications-AA_GLOBAL` and component checkouts. It runs the published `ghcr.io/openehr/asciidoctor` image, which bundles the toolchain and `spec_publish.sh`; the boilerplate and references are still read from the AA_GLOBAL checkout. It checks that each HTML output was rebuilt and that the log has no missing includes, because the script reports success even when it built nothing or dropped the class tables.

None are bundled (the `openehr-assistant` MCP is interactively authenticated, not redistributable); document them, don't assume them.
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ Notable changes to the plugins in this repository. The format follows [Keep a Ch

## Unreleased

### Added

- `scaffold` skill (user-only, `/openehr-specs:scaffold`): initialises a specification repository, or brings an existing one up to the standard file set. It installs `AGENTS.md` (the `openehr-specs@openehr` plugin table, the Docker build invocation, and commit and branch conventions built around the Jira ticket key, `Changes for SPECXX-NN - <what changed>`), `.claude/CLAUDE.md`, `.claude/settings.json` (registers the `openehr` marketplace, enables `openehr-specs` and three other plugins, and pre-approves `git add`, `git commit`, `git diff`, WebFetch on `specifications.openehr.org` and three read-only Atlassian MCP calls, as BASE, RM and ITS-REST do today), `manifest.json`, `.gitignore`, `.asciidoctorconfig`, `LICENSE` (CC BY-SA 3.0, or Apache 2.0 for `ITS-*`) and `README.md`. It plans before it writes, reads the component, title, Jira key, BMM schema and licence from the repo, and never overwrites a hand-edited file without being told to.
- The file set is versioned: `assets/template-set.json` holds a revision, the variables and a strategy per file (seed, whole, JSON merge, ensure-lines, managed regions in `AGENTS.md`), and each repo records its revision and file hashes in `.claude/scaffold.json`, so a later run calculates the migration path from the recorded revision to the latest. `scripts/scaffold.py` needs `python3` (standard library only).

### Changed

- `publish` and `regen-classes` moved from `commands/` to `skills/` as user-only skills (`disable-model-invocation: true`). Claude Code treats `commands/` as the older format, so the plugin no longer ships that directory. The `/openehr-specs:publish` and `/openehr-specs:regen-classes` names are unchanged.
- `scripts/validate.py` also checks the `scaffold` template set (templates exist and render, revisions have migration files, the digest matches), and CI runs the unit tests in `scripts/test_scaffold.py`.
- `scripts/validate.py` no longer checks a `commands/` directory; the user-only skills are validated as skills.
- `publish`, `authoring`, and the release checklist run the published `ghcr.io/openehr/asciidoctor` image instead of `openehr/asciidoctor`, which is only the tag of a local `docker build`.
- `publish` runs only the published image; the local-script branch is gone. That branch ran `spec_publish.sh -f -v` without `-q`, so every `{pkg}` class-table include failed (70 errors on BASE, with about 80% of the table blocks missing from the HTML) while the script still printed "generated" and exited 0. The image's entrypoint passes `-q`; on BASE the same image builds with no errors. The AA_GLOBAL checkout is still required, because the boilerplate and reference definitions are read from it. `authoring` shows the image first and says to pass `-q` with a local toolchain.
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Use [Conventional Commits](https://www.conventionalcommits.org): `type(scope): s
## Pull Request Process

1. Branch from `main`.
2. Run the validation script locally: `python3 scripts/validate.py`
2. Run the checks locally: `python3 scripts/validate.py` and `python3 -m unittest discover -s scripts -p 'test_*.py'`
3. If you changed plugin content, add a line under `## Unreleased` in [CHANGELOG.md](CHANGELOG.md). Do not bump the version; maintainers do that at release ([docs/versioning.md](docs/versioning.md)). If you added, removed, or renamed a skill or subagent, also update the inventories in the plugin's `README.md` and in the root [README.md](README.md).
4. Test skill triggering locally ([docs/testing.md](docs/testing.md)).
5. Open the PR and complete the checklist in the template. CI must pass.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ In Claude Code, skills are namespaced by the plugin and invoked as `/openehr-spe

Type `/openehr` in the slash menu to list the available skills, or describe the task (for example, "review this openEHR spec before release") and Claude loads the matching skill when the request fits its description.

The plugin also ships **subagents** (`spec-reviewer`, `xref-auditor`, `identifier-grounding`) that Claude dispatches for heavy, multi-file, or verification work, and two **user-only action skills** (`/openehr-specs:regen-classes`, `/openehr-specs:publish`) that run only when you type them. The [plugin README](plugins/openehr-specs/README.md) has the full inventory and invocation details.
The plugin also ships **subagents** (`spec-reviewer`, `xref-auditor`, `identifier-grounding`) that Claude dispatches for heavy, multi-file, or verification work, and three **user-only action skills** (`/openehr-specs:regen-classes`, `/openehr-specs:publish`, `/openehr-specs:scaffold`) that run only when you type them. The [plugin README](plugins/openehr-specs/README.md) has the full inventory and invocation details.

## Documentation

Expand Down
3 changes: 2 additions & 1 deletion docs/skill-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Each plugin lives under `plugins/<plugin-name>/` and must contain:
- `.claude-plugin/plugin.json`: Claude Code plugin manifest (name, version, description, author, license, keywords)
- `.cursor-plugin/plugin.json`: Cursor plugin manifest (keep name, version, and metadata in sync with the Claude manifest; declare `skills` as `./skills/`)
- `README.md`: purpose, installation, and component inventory (skills, subagents)
- `skills/`: one subdirectory per skill, each with a `SKILL.md` (YAML frontmatter and markdown body) and an optional `references/` subdirectory for supplementary content
- `skills/`: one subdirectory per skill, each with a `SKILL.md` (YAML frontmatter and markdown body) and optional `references/`, `assets/` and `scripts/` subdirectories for supplementary content, templates and bundled scripts

A plugin may also contain:

Expand All @@ -39,6 +39,7 @@ The plugin manifests, the marketplace entries, and the release tag must all carr
3. **Anti-triggers** — a short "Not for …" that routes each overlapping case to the sibling skill or external plugin that owns it (e.g. archetype work → the `openehr-assistant` plugin).
- Keep skill content factual and grounded in openEHR specifications; do not invent identifiers, paths, or conventions.
- Reference files go in `references/` next to the SKILL.md; keep `SKILL.md` bodies focused (none of the current ones exceeds 300 lines) and push bulky supporting material to `references/`.
- A skill may also bundle `scripts/` and `assets/` (the `scaffold` skill does). Call a script as `${CLAUDE_SKILL_DIR}/scripts/<name>` in the body and in `allowed-tools`, keep it to the standard library, say in the skill what it does when the interpreter is missing, and test it under `scripts/test_*.py` in this repo (CI runs them). A skill that installs versioned content states a revision and a migration path, as `scaffold` does in `assets/template-set.json`.
- Skill bodies that generate or review AsciiDoc must agree with the [spec style guide](spec-style-guide.md) — when changing one, check the other.

## Subagent and Action-Skill Authoring
Expand Down
7 changes: 4 additions & 3 deletions docs/testing.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Testing and Validation

This is a pure-content repository: JSON manifests plus markdown skills (including user-only action skills) and subagents. There is no build step, package manager, or automated test suite. Testing means installing the marketplace locally and validating structure and skill quality.
This is a pure-content repository: JSON manifests plus markdown skills (including user-only action skills) and subagents. There is no build step or package manager, and the only automated tests cover the `scaffold` skill's script. Testing means installing the marketplace locally and validating structure and skill quality.

## Local Testing

Expand All @@ -13,15 +13,16 @@ Install the marketplace from your working copy (inside a Claude Code session):

Then exercise the skills against a checkout of a `specifications-XX` repo: confirm each skill triggers on its documented phrases (see the `description` frontmatter) and does **not** trigger on its anti-trigger cases.

The user-only action skills (`publish`, `regen-classes`) run only when you type them (`/openehr-specs:<skill>`): confirm that a plain request does not start one. Subagents are dispatched when a request matches their `description`, and you can also ask for one by name: confirm both. Both need Docker, and `publish` also needs a sibling `specifications-AA_GLOBAL` checkout (see the [plugin README](../plugins/openehr-specs/README.md)).
The user-only action skills (`publish`, `regen-classes`, `scaffold`) run only when you type them (`/openehr-specs:<skill>`): confirm that a plain request does not start one. Subagents are dispatched when a request matches their `description`, and you can also ask for one by name: confirm both. `publish` and `regen-classes` need Docker, and `publish` also needs a sibling `specifications-AA_GLOBAL` checkout; `scaffold` needs `python3` and writes files into the repository it runs in, so try it in an empty or scratch directory first (see the [plugin README](../plugins/openehr-specs/README.md)).

After editing skill content, reinstall (or restart the session) to pick up changes.

For Cursor, copy `plugins/openehr-specs` to `~/.cursor/plugins/local/openehr-specs`, then restart Cursor or run **Developer: Reload Window** and check **Customize** for the components. Cursor skips a symlink that points outside that folder, and Teams and Enterprise admins can turn local plugin imports off. See [Cursor's local testing steps](https://cursor.com/docs/plugins.md#test-plugins-locally).

## Validation

- **Manifest and frontmatter validation**: `python3 scripts/validate.py` (CI runs it on every PR) checks the Claude and Cursor JSON manifests, name and version sync, declared component paths, and the marketplace `owner.name`. For every skill and subagent it checks that `name` and `description` exist and that `name` matches the directory or file name. It does not check description length, `disable-model-invocation`, the README inventories, or the release tag.
- **Manifest and frontmatter validation**: `python3 scripts/validate.py` (CI runs it on every PR) checks the Claude and Cursor JSON manifests, name and version sync, declared component paths, and the marketplace `owner.name`. For every skill and subagent it checks that `name` and `description` exist and that `name` matches the directory or file name. It also runs the `scaffold` template-set check (`scaffold.py check`: templates exist and render, revisions are contiguous, every revision has a migration file, and the template digest matches the latest revision). It does not check description length, `disable-model-invocation`, the README inventories, or the release tag.
- **Script tests**: `python3 -m unittest discover -s scripts -p 'test_*.py'` (CI runs it on every PR) covers the `scaffold` script: the template engine, each file strategy, variable inference, and the upgrade path across revisions, all in temporary directories. Run it after changing the script or the template set.
- **Built-in manifest check**: `claude plugin validate plugins/openehr-specs` validates the plugin manifest; add `--strict` to treat warnings as errors.
- **Structural validation**: after creating or modifying plugin components, run the `plugin-dev:plugin-validator` agent. It checks `plugin.json`, the marketplace entry, directory layout, and frontmatter. The agent comes from the `plugin-dev` plugin, which this repo enables in `.claude/settings.json`.
- **Skill quality review**: run the `plugin-dev:skill-reviewer` agent (also from `plugin-dev`). It checks description triggering quality, progressive disclosure, and content structure.
Expand Down
Loading
Loading