Declarative YAML language for building constraint pipelines in the SuperInstance ecosystem.
constraint-dsl lets you define musical constraint graphs as YAML documents — specifying lattice snapping, funnel resolution, tempo grids, Laman rigidity, and multi-agent consensus — then compile and execute them as directed acyclic graphs. It's the glue between constraint-theory-core and higher-level SuperInstance components.
The pipeline has three stages:
- Parse — YAML document →
Pipelineobject (nodes + edges) - Compile —
Pipeline→ConstraintGraph(typed executable nodes with cycle detection) - Execute —
ConstraintGraph→RuntimeResult(topological data-flow walk)
YAML → Parser → Pipeline → Compiler → ConstraintGraph → Runtime → RuntimeResult
A DSL document is a YAML file with four top-level keys:
name: "My Pipeline"
description: "What it does"
params: # shared parameters (optional)
bpm: 120
key_root: 60
constraints: # list of constraint nodes
- id: my_snap
kind: snap
config:
lattice: A2
epsilon: 0.15
- id: my_tempo
kind: tempo
config:
bpm: 120
grid: 16
edges: # directed connections between nodes (optional)
- from: my_snap
to: my_tempo
channel: point # optional: route specific output field
weight: 1.0 # optional: edge weightEach constraint has:
| Field | Required | Description |
|---|---|---|
id |
✅ | Unique identifier |
kind |
✅ | Constraint type (see below) |
config |
❌ | Type-specific configuration |
inputs |
❌ | Input port names |
outputs |
❌ | Output port names |
| Field | Required | Description |
|---|---|---|
from |
✅ | Source node ID |
to |
✅ | Target node ID |
channel |
❌ | Route a specific output field |
weight |
❌ | Edge weight (default 1.0) |
Snaps 2D coordinates to a lattice (A2 by default) with configurable epsilon tolerance.
- id: tuning
kind: snap
config:
lattice: A2
epsilon: 0.15Runtime output: point, error, safe, epsilon, lattice
Applies a temporal agent that resolves values through phases (search → lock → deadband).
- id: phrase
kind: funnel
config:
target: 60
gravity: 0.7
decay: exponential # exponential | linear | slowRuntime output: phase, error, deadband, snapped_a, snapped_b
Creates a metronome with configurable BPM, grid subdivision, and allowed drift.
- id: timekeeper
kind: tempo
config:
bpm: 180
grid: 16
drift: 0.02Runtime output: phase, tick_count, converged, epsilon, anomaly_count
Builds a Laman rigidity graph (using Henneberg construction) to enforce structural constraints.
- id: structure
kind: laman
config:
num_nodes: 8
rigid: trueRuntime output: n, edges, rigid, is_rigid
Sets up a multi-agent metronome for ensemble synchronization with configurable voting method.
- id: ensemble
kind: consensus
config:
voices: 3
method: majority
threshold: 0.6Runtime output: correction, converged, phase, epsilon
name: "Jazz Solo Constraints"
description: "Bebop solo pipeline: lattice snap, funnel resolution, tempo grid"
params:
key_root: 60
bpm: 180
constraints:
- id: lattice
kind: snap
config:
lattice: A2
epsilon: 0.15
- id: phrase
kind: funnel
config:
target: 60
gravity: 0.7
decay: exponential
- id: timekeeper
kind: tempo
config:
bpm: 180
grid: 16
drift: 0.02
- id: structure
kind: laman
config:
num_nodes: 8
rigid: true
edges:
- from: lattice
to: phrase
channel: pointname: "String Quartet Constraints"
params:
bpm: 90
constraints:
- id: time
kind: tempo
config: { bpm: 90, grid: 16, drift: 0.005 }
- id: form
kind: laman
config: { num_nodes: 4, rigid: true }
- id: tuning
kind: snap
config: { lattice: A2, epsilon: 0.05 }
edges:
- from: tuning
to: formname: "Trap Beat Constraints"
params:
bpm: 140
constraints:
- id: grid
kind: tempo
config: { bpm: 140, grid: 32, drift: 0.01 }
- id: ensemble
kind: consensus
config: { voices: 3, method: majority, threshold: 0.6 }
- id: rigidity
kind: laman
config: { num_nodes: 3, rigid: true }
edges:
- from: rigidity
to: ensemble
channel: edgespip install constraint-dslRequires Python ≥ 3.10, PyYAML ≥ 6.0, and constraint-theory-core.
from constraint_dsl import load, compile_pipeline, Runtime
# Parse a DSL file
pipeline = load("examples/jazz_solo.yaml")
# Compile to executable graph
graph = compile_pipeline(pipeline)
# Execute with inputs
runtime = Runtime(graph)
result = runtime.execute({"x": 0.5, "y": 0.3, "t": 0.1})
# Access outputs
print(result.outputs) # leaf node outputs
print(result.execution_order) # topological order
print(result.node_outputs) # all node outputsfrom constraint_dsl import parse, compile_pipeline, Runtime
yaml_str = """
name: "Simple"
constraints:
- id: snap
kind: snap
config: { lattice: A2, epsilon: 0.1 }
"""
pipeline = parse(yaml_str)
graph = compile_pipeline(pipeline)
result = Runtime(graph).execute({"x": 1.5, "y": 2.3})from constraint_dsl import register
@register("my_constraint")
def compile_my_constraint(config, params):
return {"custom_data": config.get("value", 0)}| Function | Description |
|---|---|
parse(text) |
Parse YAML string → Pipeline |
load(path) |
Load YAML file → Pipeline |
| Type | Description |
|---|---|
Pipeline |
Parsed document: name, description, params, constraints, edges |
ConstraintNode |
Node: id, kind, config, inputs, outputs |
ConstraintEdge |
Edge: source, target, weight, channel |
| Function | Description |
|---|---|
compile_pipeline(pipeline) |
Compile → ConstraintGraph |
register(kind) |
Decorator to register custom constraint kinds |
| Class | Description |
|---|---|
Runtime(graph) |
Executor for a compiled graph |
.execute(inputs) |
Run graph → RuntimeResult |
| Field | Description |
|---|---|
RuntimeResult.outputs |
Leaf node outputs |
RuntimeResult.node_outputs |
All node outputs |
RuntimeResult.execution_order |
Topological execution order |
| Exception | Stage |
|---|---|
ParseError |
YAML parsing / validation |
CompileError |
Compilation / cycle detection |
RuntimeError |
Graph execution |
- constraint-toolkit — Core constraint theory library (lattice snap, Laman rigidity, metronome, funnel)
- superinstance-live — Live session controller using DSL pipelines
- plato-client — Client for the Plato optimization backend
- flux-genome — Genetic algorithm framework for evolving traditions
MIT