linkml-scala-action

September 1, 2026 ยท View on GitHub

A GitHub Action to validate and generate from LinkML schemas in CI, powered by linkml-scala.

  • ๐Ÿš€ Pure Node.js โ€“ no Docker, no JVM, no Python, no binary download. Uses the @neverblink/linkml npm package.
  • ๐Ÿ–ฅ๏ธ Runs everywhere โ€“ Linux, macOS, and Windows runners.
  • ๐Ÿท๏ธ Inline annotations โ€“ schema problems posted as GitHub annotations (on the PR "Files changed" tab and the check summary), pinned to a line and column when the engine reports one.
  • โšก Fast โ€“ validating a schema is a few milliseconds after Node starts up.

Quick start

Validate every schema in your repo on each push:

name: linkml
on: [push, pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: NeverBlink-OSS/linkml-scala-action@v0.15.1
        with:
          files: "schemas/**/*.yaml"

Generate JSON Schema and commit/upload it as an artifact:

      - uses: NeverBlink-OSS/linkml-scala-action@v0.15.1
        with:
          command: generate
          generator: json-schema
          files: "schemas/**/*.yaml"
          output: build/json-schema
      - uses: actions/upload-artifact@v4
        with:
          name: json-schema
          path: build/json-schema

Fail the build on warnings too:

      - uses: NeverBlink-OSS/linkml-scala-action@v0.15.1
        with:
          files: "schemas/**/*.yaml"
          strict: true

See CHANGELOG.md for what changed between releases.

Inputs

InputDefaultDescription
commandvalidatevalidate or generate.
filesrequiredSchema files. Space/newline-separated; globs incl. ** supported.
strictfalseTreat warnings as failures. Errors always fail; warnings only with this on.
generatorโ€“generate: json-schema, shacl, rdfs, linkml, frictionless, graphql, or scala.
outputโ€“generate: output directory (one file per input schema). If omitted, output is printed to the job log.
openfalsegenerate json-schema/shacl: allow additional properties (open shapes).
formatttlgenerate shacl/rdfs: RDF serialization โ€“ ttl (Turtle, prefixed and pretty-printed) or nt (N-Triples).
packagelinkmlgenerate scala: target package name.
pruning-modeskipgenerate frictionless: which classes become tables โ€“ treeRoot (only those reachable from the tree_root class), schema (only those reachable from a class defined in the root schema), or skip (every class).
tree-rootโ€“generate frictionless: tree root class name to use instead of the schema's own tree_root. Only has an effect with pruning-mode: treeRoot.
skip-classes-without-identifierfalsegenerate frictionless: skip classes with no identifier slot. Such a table gets no primary key and nothing can reference it.
importsโ€“Directory of extra .yaml schemas made available to imports: (keyed by path, relative to working-directory).
ignoreโ€“Newline-separated issue type names to silence, one per line.
annotationstrueEmit GitHub error/warning annotations.
working-directory.Base directory for resolving files, imports, and output.

Outputs

OutputDescription
problemsTotal number of problems found across all schemas.
filesNumber of schema files processed.
linkml-versionThe bundled linkml-scala version.

Behavior

Loading a schema validates it, so both commands report the same problems. Each has a severity:

SeverityMeaningEffect
FATALThe schema could not be loaded at all (unparseable YAML, an unresolvable import, an unknown class reference).Fails the step. Nothing is generated from the schema.
ERRORThe schema loaded but is invalid (e.g. two tree_root classes, a non-unique name).Fails the step. Generation still runs, so the output is there to inspect.
WARNINGAdvisory (e.g. no tree_root class).Reported only; fails the step when strict: true.
  • Generators write one output file per input schema into output, named after the schema (person.yaml โ†’ person.schema.json). The scala and frictionless generators emit multiple files per schema, so those go under output/<schema-name>/ (for frictionless, a datapackage.json plus one schemas/<table>.json per table).
  • Imports: if your schemas use imports: [shared], point imports at a directory containing shared.yaml. Files are keyed by filename.
  • ignore silences problems by issue type. Every problem the engine reports is tagged with the class it belongs to in the validation report.

Resolving imports โ€“ example

      - uses: NeverBlink-OSS/linkml-scala-action@v0.15.1
        with:
          command: generate
          generator: shacl
          files: "schemas/main.yaml"        # e.g. imports: [common/types]
          imports: "schemas"                # dir holding schemas/common/types.yaml
          output: build/shacl

Versioning

The linkml-scala engine version is bundled into each release of this action, so the action version tracks the engine version. Pin an exact tag:

      - uses: NeverBlink-OSS/linkml-scala-action@v0.15.1

New engine releases are picked up automatically by the track-linkml-scala workflow, which bumps the bundled engine, rebuilds, re-runs the test suite against it, updates the examples above, and โ€“ only if that passes โ€“ cuts the matching vX.Y.Z release. It runs daily and can also be triggered manually (with an optional target version and a dry-run mode).

Development

npm ci
npm run build   # bundles src/ + @neverblink/linkml into dist/index.cjs (committed)
npm test        # simulates the Actions runtime and asserts behavior

The bundled dist/ is committed so the action needs no install step at runtime; CI verifies it stays in sync with src/.

License

Apache-2.0.

This project is being developed and maintained by NeverBlink. For any inquiries, please reach out to us via email.