Generate Graviola-ready artifacts from LinkML schemas.
Compared to stock LinkML JSON Schema output, the generator:
- emits
@idonly when the class has a LinkML identifier slot; always emits@typewith the class IRI - keeps LinkML identifier slots (e.g.
idwithidentifier: true) as ordinary properties when declared on the class - multivalued inlined class refs are arrays of
$ref, not ID-keyed dicts (no__identifier_optionaldefs) - lists a property under
requiredonly when that slot hasrequired: truein LinkML
The CLI creates:
<schema-stem>.schema.json(Graviola JSON Schema)<schema-stem>.gra.side-schema.json(UI / app side-schema: labels, primary fields, form/detail/table overrides, menu, metadata)<schema-stem>.calc-profile.json(calculated-fields sidecar; viacalc-profileorbundle)<schema-stem>.search-facet.json(fulltext + facets; viasearch-facetorbundle)
The example contract is committed in examples/collective-mind-schema.yml.
It includes:
- relations with inverse declarations (
memberOf<->members,hostBody<->hostedMinds) gra:namespace annotations (gra:label, property-levelgra:primaryLabel)
Generate the outputs exactly as documented:
nix run .#generate -- ./examples/collective-mind-schema.yml -o ./examples/collective-mind.schema.json
nix run .#side-schema -- ./examples/collective-mind-schema.yml -o ./examples/collective-mind.gra.side-schema.json
# or all artifacts:
nix run .#bundle -- ./examples/collective-mind-schema.yml -d ./examplesSource excerpt (examples/collective-mind-schema.yml):
classes:
Individual:
annotations:
gra:label: "Individual Being"
slots: [name, embodiedMind, memberOf]
Collective:
annotations:
gra:label: "Collective"
slots: [title, members]
slots:
name:
annotations:
gra:primaryLabel: true
title:
annotations:
gra:primaryLabel: true
memberOf:
range: Collective
inlined: true
inverse: members
members:
range: Individual
multivalued: true
inlined: trueGenerated excerpt (examples/collective-mind.schema.json):
{
"definitions": {
"Collective": {
"properties": {
"@id": { "type": "string" },
"@type": { "type": "string", "const": "https://example.org/collective-mind/Collective" },
"members": {
"items": { "$ref": "#/definitions/Individual" },
"type": "array"
},
"title": { "type": "string" }
}
},
"Individual": {
"properties": {
"@id": { "type": "string" },
"@type": { "type": "string", "const": "https://example.org/collective-mind/Individual" },
"id": { "type": "string" },
"memberOf": { "$ref": "#/definitions/Collective" },
"name": { "type": "string" }
}
}
}
}Generated excerpt (examples/collective-mind.gra.side-schema.json):
{
"primaryFields": {
"Individual": { "label": "name" },
"Collective": { "label": "title" }
},
"typeNameLabelMap": {
"Individual": "Individual Being",
"Collective": "Collective"
}
}From this repo:
nix run .#generate -- ./examples/collective-mind-schema.yml
nix run .#side-schema -- ./examples/collective-mind-schema.yml
nix run .#calc-profile -- ./tests/fixtures/garden_fee.yaml
nix run .#bundle -- ./tests/fixtures/item_schema_annotated.yamlFrom GitHub:
nix run github:graviola-la/graviola-linkml#generate -- ./model.yaml -o ./model.schema.json
nix run github:graviola-la/graviola-linkml#side-schema -- ./model.yaml -o ./model.gra.side-schema.json
nix run github:graviola-la/graviola-linkml#bundle -- ./model.yaml -d ./outFull CLI help:
nix run . -- --helpuv sync
uv run graviola-linkml --help
uv run graviola-linkml generate ./examples/collective-mind-schema.yml
uv run graviola-linkml side-schema ./examples/collective-mind-schema.ymlgenerate <schema.yaml>-o, --output <path>(default:<schema-stem>.schema.json)--indent <n>(default:2)
side-schema <schema.yaml>-o, --output <path>(default:<schema-stem>.gra.side-schema.json)
calc-profile <schema.yaml>--schema-output <path>/--sidecar-output <path>--indent <n>
search-facet <schema.yaml>-o, --output <path>(default:<schema-stem>.search-facet.json)
bundle <schema.yaml>-d, --output-dir <path>— writes.schema.json,.gra.side-schema.json,.calc-profile.json,.search-facet.json
nix developInside the shell, graviola-linkml, uv, and ruff are available.
uv sync --extra dev
uv run pytest -v
uv run ruff check .
uv run mypy src.github/workflows/publish-schema.yml builds and deploys artifacts from annotation-vocab/graviola-annotations.yaml:
- Turtle (
.ttl) - JSON-LD (
.jsonld) - HTML docs (MkDocs)
- source YAML +
.htaccess