Describe
Keep types, relationships, derived values, and rules in one description.
A semantic modeling language
Values, relationships, and rules.
One executable model.
View larger
View largerThis Service Graph describes two services and a link between them. Defaults fill
their ports, expressions derive their addresses, and a rule prevents self-links.
The services form a tree; ref<Service> connects them without copying their values.
// Values, derived meaning, and relationships in one model.type Service = { name: /[a-z][a-z0-9-]*/ port?: 1024..65535 = 8080 endpoint = `${name}:${port}` inbound_count = std.array.count($referrers(Link, "target"))}
type Link = { source: ref<Service> target: ref<Service>
assert different_services: source != target else error `a service must not link to itself`}
type Topology = { services: Service[], links: Link[] }
export output demo: Topology = { services: [{ name: "gateway" }, { name: "auth", port: 9001 }] links: [{ source: services[0], target: services[1] }]}
// External JSON documents use exactly the same model.input deployed: Topology{ "demo": { "services": [ { "name": "gateway", "port": 8080, "endpoint": "gateway:8080", "inbound_count": 0 }, { "name": "auth", "port": 9001, "endpoint": "auth:9001", "inbound_count": 1 } ], "links": [ { "source": "$.services[0]", "target": "$.services[1]" } ] }}The output includes the resolved values and relationships: auth has one incoming
link, and each endpoint is a path to a service. Change the model in the playground
to see its output and diagnostics update.
Values describe content. References preserve identity. Two services can have identical settings. A reference says which one a link reaches.
Not for mutation. For identity and relationships.
Give two services the same port: 8080, then connect the first to the second. Their content is equal; their places in the model are distinct.
References compare canonical target paths; ordinary values compare content. Moving an entity to a different key or index changes its identity in the model.
Explore identity and relationships →{ "same_content": true, "same_entity": false, "target_port": 8080, "target_path": "graph.services[1]"}Use the same model for the data you create and the documents you receive.
Describe
Keep types, relationships, derived values, and rules in one description.
Generate
Resolve defaults and derived values. Produce JSON, YAML, or text from the model.
Validate
Check external documents against those same rules. Get diagnostics that name the failed rule and its place in the data.
The same core describes ports, connections, propagated widths, and rules across connected components. The Hardware Interconnect example puts these relationships to work in a 2×2 crossbar, with runnable source and evaluated output.
More models and examples: configuration, test generation, and the evidence behind each case.
Immutable values. Pure evaluation. Deterministic results. A terminating core. Decl focuses on describing the meaning of data; the host application handles I/O and workflows. Read why Decl is shaped this way.
Applications can use that meaning too. Decl for AI agents and conceptual models shows how existing models and diagnostics can guide another tool’s work.
Install the implementation that fits your environment. All three share the same specified behavior and ship the CLI, formatter, and language server.
npm install -g decl-langTypeScript reference implementation. Node.js ≥ 22.
pip install decl-langNative Python implementation and Python API.
cargo install decl-langNative Rust implementation.
brew install luuvish/tap/decl-langThe npm package through the Homebrew tap.
Installation and editor setup covers the next steps.
© 2026 Luuvish. Decl is open source under the MIT License.
Type: Literata and IBM Plex, under the SIL Open Font License. Built with Astro Starlight.