1. Your First Profile in eunomia.profiles/v1
Learn how to author an OdrlProfile and SpaceProfile in YAML, validate N1–N5 rules, and generate deterministic artifacts with alexandriac.
Tutorial 1: Authoring & Compiling Your First Profile (alexandriac)
In a sovereign dataspace, participants never hand-edit SHACL shapes, JSON-LD contexts, JSON Schemas, and Cedar schemas separately—doing so inevitably leads to semantic drift across validation engines. Instead, you author a single source of truth in the eunomia.profiles/v1 YAML language, and the alexandriac compiler generates every artifact deterministically.
In this first tutorial, you will:
- Build the
alexandriaccommand-line compiler. - Author an
OdrlProfileand aSpaceProfilein YAML. - Validate the profile across the 5 normative levels (
N1–N5). - Compile and inspect the generated artifacts (
vocab.ttl,context.jsonld,shapes.ttl,schema.json,cedar.schema,spec.html, andspace-lock.json). - Trigger and understand compiler diagnostics when a breaking change violates lifecycle rules (
N4).
Step 1: Build the alexandriac Compiler
From the root of the repository, build bin/alexandriac:
go build -o bin/alexandriac ./cmd/alexandriacVerify the CLI usage:
./bin/alexandriac
# usage: alexandriac validate|compile [-o dir] [-vendor dir] [-previous file]... file.yaml...Step 2: Inspect an OdrlProfile Document
An OdrlProfile defines domain-specific policy terms (action, left_operand, right_operand), adopts standard ODRL 2.2 terms, and optionally declares runtime Cedar enforcement bindings.
Let's validate the built-in colors.profile.yaml located in internal/dsl/testdata/colors.profile.yaml:
./bin/alexandriac validate internal/dsl/testdata/colors.profile.yamlOutput:
ok: 1 documents validNow compile it into /tmp/colors-build:
./bin/alexandriac compile -o /tmp/colors-build internal/dsl/testdata/colors.profile.yamlOutput:
/tmp/colors-build/profiles/odrl/colors/0.1.0/cedar-mapping.json
/tmp/colors-build/profiles/odrl/colors/0.1.0/cedar.schema
/tmp/colors-build/profiles/odrl/colors/0.1.0/context.jsonld
/tmp/colors-build/profiles/odrl/colors/0.1.0/prof.ttl
/tmp/colors-build/profiles/odrl/colors/0.1.0/schema.json
/tmp/colors-build/profiles/odrl/colors/0.1.0/shapes.ttl
/tmp/colors-build/profiles/odrl/colors/0.1.0/spec.html
/tmp/colors-build/profiles/odrl/colors/0.1.0/vocab.ttlBecause the color left operand in colors.profile.yaml declares an enforcement block (cedar_path: context.color, pdp_level: PDP-4), alexandriac automatically generates cedar-mapping.json and cedar.schema alongside the RDF, SHACL, and JSON Schema artifacts!
Step 3: Create a Complete Space Bundle (OdrlProfile + SpaceProfile)
A dataspace combines one or more profiles into a SpaceProfile, which binds each slot (odrl, dcat, dsp, dcp) to a profile version, an obligation (mandatory or recommended), and the validation gates (policy_intake, dsp_message, catalog_entry, agreement_admission) where each artifact role applies.
Create a file /tmp/my-space-v1.yaml containing both an OdrlProfile and a SpaceProfile separated by ---:
cat << 'EOF' > /tmp/my-space-v1.yaml
dsl: eunomia.profiles/v1
kind: OdrlProfile
profile:
id: https://example.com/odrl/profile/mobility
version: 1.0.0
title:
en: Mobility Data Usage Profile
publisher: GING-DIT, Universidad Politécnica de Madrid
license: https://creativecommons.org/licenses/by/4.0/
base_url: https://example.com/odrl/profile/mobility
namespaces:
mob: https://example.com/ns/mobility#
adopted:
left_operands:
- term: odrl:dateTime
signature:
datatype: xsd:dateTime
operators: [eq, lt, lteq, gt, gteq]
terms:
- id: aggregateTelemetry
kind: action
included_in: odrl:use
label: { en: Aggregate Telemetry }
definition: { en: Compute anonymized fleet telemetry aggregates. }
- id: minFleetSize
kind: left_operand
label: { en: Minimum Fleet Size }
definition: { en: Minimum number of vehicles required in an aggregation window. }
signature:
datatype: xsd:integer
operators: [gt, gteq]
---
dsl: eunomia.profiles/v1
kind: SpaceProfile
space:
id: https://example.com/spaces/mobility
version: 1.0.0
title:
en: Mobility Sovereign Dataspace
operator: https://example.com/party/mobility-authority
base_url: https://example.com/spaces/mobility
lifecycle:
grace_window: P30D
freshness:
ttl: PT24H
max_staleness: P7D
degraded:
policy_intake: continue
dsp_message: continue
bindings:
- slot: odrl
profile: https://example.com/odrl/profile/mobility
source: internal
version: "=1.0.0"
obligation: mandatory
conformance:
- { role: json-schema, applies_to: policy_intake }
- { role: shacl, applies_to: policy_intake }
EOFValidate and compile your space bundle:
./bin/alexandriac validate /tmp/my-space-v1.yaml
./bin/alexandriac compile -o /tmp/mobility-out /tmp/my-space-v1.yamlOutput:
ok: 2 documents valid
/tmp/mobility-out/profiles/odrl/mobility/1.0.0/context.jsonld
/tmp/mobility-out/profiles/odrl/mobility/1.0.0/prof.ttl
/tmp/mobility-out/profiles/odrl/mobility/1.0.0/schema.json
/tmp/mobility-out/profiles/odrl/mobility/1.0.0/shapes.ttl
/tmp/mobility-out/profiles/odrl/mobility/1.0.0/spec.html
/tmp/mobility-out/profiles/odrl/mobility/1.0.0/vocab.ttl
/tmp/mobility-out/space/prof.ttl
/tmp/mobility-out/space/shacl-union.ttl
/tmp/mobility-out/space/space-lock.json
/tmp/mobility-out/space/spec.htmlStep 4: Inspect space/space-lock.json and schema.json
Inspect the generated space/space-lock.json, which records the resolved version, SHA-256 digests of every artifact, gate bindings, and lifecycle configuration:
cat /tmp/mobility-out/space/space-lock.jsonNotice how profiles/odrl/mobility/1.0.0/schema.json is a self-contained JSON Schema Draft 2020-12 (no external network $refs) that validates compact ODRL offers and enforces:
- Allowed actions (
odrl:use,mob:aggregateTelemetry). - Operator and datatype constraints on
mob:minFleetSize(gt,gteqwith integerrightOperand) andodrl:dateTime(xsd:dateTime).
Step 5: Test Cross-Release Evolution Rules (N4 Validation)
The eunomia.profiles/v1 specification enforces strict governance over vocabulary evolution (N4):
- You cannot delete a term from a profile (
TERM_REMOVED). - You cannot retire an active term directly without first deprecating it in an intermediate release (
TERM_RETIRED_WITHOUT_DEPRECATION).
Let's see N4 in action! Try creating /tmp/my-space-bad-v2.yaml where aggregateTelemetry jumps directly from active (in 1.0.0) to status: retired without an intermediate deprecated release:
sed 's/version: 1.0.0/version: 2.0.0/g; s/"=1.0.0"/"=2.0.0"/g; s/kind: action/kind: action\n status: retired/' \
/tmp/my-space-v1.yaml > /tmp/my-space-bad-v2.yaml
./bin/alexandriac compile -o /tmp/mobility-v2 -previous /tmp/my-space-v1.yaml /tmp/my-space-bad-v2.yamlalexandriac immediately rejects the invalid transition with a precise N4 diagnostic and exits with status 1:
error TERM_RETIRED_WITHOUT_DEPRECATION my-space-bad-v2.yaml#1:17 /terms/0 term "aggregateTelemetry" was active in 1.0.0 and is retired in 2.0.0 without an intermediate deprecated release
alexandriac: 1 errorsTo retire a term properly (as done in conformance/f6/drafts/v2.0.0.yaml), include the intermediate 1.1.0 OdrlProfile marking the term status: deprecated alongside the 2.0.0 OdrlProfile marking it status: retired.
Next Tutorial
Now that you know how to author and compile profiles with alexandriac, proceed to Tutorial 2: Publishing & Governing Vocabularies on alexandria-server to manage the full draft -> candidate -> release lifecycle over HTTP.
Incremental Tutorials
Step-by-step hands-on learning path for Alexandria, the eunomia.profiles/v1 DSL, Vocabulary Hub (alexandria-server & alexandria-client), and Sovereign Wallets.
2. Publishing & Governance on alexandria-server
Step-by-step tutorial on running alexandria-server, creating drafts, proposing candidates, approving signed releases, and dereferencing /pub artifacts.