Tutorial: Building a Music Touring Performance Deal (Step by Step)
DANGER
This is not correct, it's more of a placeholder
This tutorial walks you through constructing a Music Touring Performance Deal in the DealModel DSL. We’ll start small (header), add inputs (via JSON Schema), then layer in variables, operators, events, clauses, clause blocks, a type, and computations. By the end, you’ll have a clean, working model you can validate in the ANTLR Lab.
Tip: in the ANTLR Lab, always Generate after pasting your grammar, then Run your input with Start rule set to
model. Keep the version unquoted (e.g.,1.0.0, not"1.0.0").
1. Start with the Model Header
Every model begins with a header that declares its deal type and version.
model { deal_type: "Music Touring Performance Deal", version: 1.0.0 }| Field | Type | Description |
|---|---|---|
deal_type | TEXT or STRING | Human-readable identifier for the deal type. |
version | SEMVER | Unquoted semantic version (e.g., 1.0.0). |
2. Add Inputs
Your model references a JSON Schema to describe the exact shape of the data that deal instances will provide. Think of this schema as describing the specific inputs for a particular deal. Using schema in this manner keeps the DSL grammar clean while allowing different deals to carry different data structures.
You can read the docs for JSON Schema in the link above to help you design your schema.
You can also use schema design tools to help you build your schema.
Reference your schema (recommended):
inputs { ref: "https://schemas.example.com/models/music-touring/performance/1.0.0.json" }Or inline a small schema during prototyping:
inputs {
schema: """{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object" }"""
}Example: schema fragment for a deal-specific simple clause
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"simple_clauses": {
"type": "object",
"properties": {
"headline_billing": {
"type": "string",
"minLength": 1,
"description": "Deal-specific text for headline billing."
}
},
"additionalProperties": false
}
}
}3. Selectors (optional, but helpful)
Selectors assign readable names to JSON paths so your expressions are cleaner.
selectors {
show_revenue: "$.shows[*].revenue"
fees_path: "$..fees[*]"
}You’ll use these in computations (e.g., sum(show_revenue)).
4. Variables
Declare instance-bound variables (and optional derived ones).
var performance_date
var venue_name
var guarantee_amount
var pct_nbor
var nbor
var nbor_threshold_value
var payout_schedule_id5. Operators
Operators describe how clauses (or blocks) combine. We’ll use a standard versus operator (or).
operator { name: versus display: "vs" type: or }| Field | Description |
|---|---|
name | Identifier used in expressions. |
display | Label used in UI or templates. |
type | and (additive) or or (exclusive / versus). |
6. Events
Events are boolean conditions that gate financial clauses or blocks.
event {
name: nbor_threshold
description: "NBOR meets or exceeds the required threshold"
condition: nbor >= nbor_threshold_value
}Event conditions support arithmetic, comparisons, logical operators (&&, ||, !), and function calls like input(path).
7. Add a Simple Clause (pure text from inputs)
Simple clauses are often deal-specific prose provided in instance inputs. Render that text via input() in the template.
clause {
name: headline_billing
kind: simple
description: "Deal-specific headline billing text"
template: """
{{ input("/simple_clauses/headline_billing") }}
"""
}8. Add a Guarantee Clause (financial)
Guarantees are paid when active (they can still depend on a deliverable event if you choose to add a when:).
clause {
name: base_guarantee
kind: guarantee
description: "Minimum guaranteed payment to the Artist"
amount: guarantee_amount
payable: on performance_date
template: """
Artist shall be paid a guaranteed fee of {{ money(guarantee_amount, "USD") }}
for the performance on {{ date(performance_date) }} at {{ input("/venue_name") }}.
"""
}9. Add a Contingent Clause (financial, event-guarded)
This clause only contributes if the event is true.
clause {
name: nbor_share
kind: contingent
description: "Artist share of Net Box Office Receipts"
when: nbor_threshold
amount: pct_nbor * nbor
payable: by_schedule payout_schedule_id
template: """
Artist shall be paid {{ percent(pct_nbor) }} of the Net Box Office Receipts (“NBOR”)
for the performance on {{ date(performance_date) }} at {{ input("/venue_name") }}.
"""
}10. Clause Block (compose the financial logic)
Clause blocks compose clauses (or other blocks). A versus block chooses the greater amount.
block {
name: payout
expr: base_guarantee versus nbor_share
template: """
Artist shall be paid the greater of {{ money(guarantee_amount, "USD") }}
or {{ percent(pct_nbor) }} of NBOR (“Versus Deal”) for the performance on
{{ date(performance_date) }} at {{ input("/venue_name") }}.
"""
}11. Type (top-level composition)
The type defines the root composition to evaluate and render.
type {
name: touring_performance
compose: payout
template: """
The parties agree to the Performance Deal terms as set forth herein.
"""
}12. Computations (metrics & outputs)
Define derived metrics and final outputs. Use your selectors here for clean aggregations.
computations {
metric total_show_revenue = sum(show_revenue)
metric total_fees = sum(fees_path)
metric nbor_share_amount = pct_nbor * nbor
output guarantee_value = amount(base_guarantee)
output versus_value = amount(payout)
output total_payout = max(guarantee_value, versus_value)
}Intrinsics supported in expressions include
amount(name),input(path),sum(path),count(path),min(path),max(path), andplugin(name, ...).
13. Full, Copy-Pasteable Model
Paste this into the ANTLR Lab Input pane and run (with your grammar generated):
model { deal_type: "Music Touring Performance Deal", version: 1.0.0 }
inputs { ref: "https://schemas.example.com/models/music-touring/performance/1.0.0.json" }
selectors {
show_revenue: "$.shows[*].revenue"
fees_path: "$..fees[*]"
}
var performance_date
var venue_name
var guarantee_amount
var pct_nbor
var nbor
var nbor_threshold_value
var payout_schedule_id
operator { name: versus display: "vs" type: or }
event {
name: nbor_threshold
description: "NBOR meets or exceeds the required threshold"
condition: nbor >= nbor_threshold_value
}
clause {
name: headline_billing
kind: simple
description: "Deal-specific headline billing text"
template: """
{{ input("/simple_clauses/headline_billing") }}
"""
}
clause {
name: base_guarantee
kind: guarantee
description: "Minimum guaranteed payment to the Artist"
amount: guarantee_amount
payable: on performance_date
template: """
Artist shall be paid a guaranteed fee of {{ money(guarantee_amount, "USD") }}
for the performance on {{ date(performance_date) }} at {{ input("/venue_name") }}.
"""
}
clause {
name: nbor_share
kind: contingent
description: "Artist share of Net Box Office Receipts"
when: nbor_threshold
amount: pct_nbor * nbor
payable: by_schedule payout_schedule_id
template: """
Artist shall be paid {{ percent(pct_nbor) }} of the Net Box Office Receipts (“NBOR”)
for the performance on {{ date(performance_date) }} at {{ input("/venue_name") }}.
"""
}
block {
name: payout
expr: base_guarantee versus nbor_share
template: """
Artist shall be paid the greater of {{ money(guarantee_amount, "USD") }}
or {{ percent(pct_nbor) }} of NBOR (“Versus Deal”) for the performance on
{{ date(performance_date) }} at {{ input("/venue_name") }}.
"""
}
type {
name: touring_performance
compose: payout
template: """
The parties agree to the Performance Deal terms as set forth herein.
"""
}
computations {
metric total_show_revenue = sum(show_revenue)
metric total_fees = sum(fees_path)
metric nbor_share_amount = pct_nbor * nbor
output guarantee_value = amount(base_guarantee)
output versus_value = amount(payout)
output total_payout = max(guarantee_value, versus_value)
}14. Testing & Common Pitfalls
| Issue | Symptom | Fix |
|---|---|---|
| Version quoted | mismatched input '"1.0.0"' | Remove quotes; use unquoted 1.0.0. |
| Hidden spaces | Token errors at colons or braces | Re-type lines by hand; invisible Unicode spaces may exist. |
| Duplicate keywords | guarantee or contingent used both as name & kind | Rename clause IDs to base_guarantee etc. |
15. Next Steps
- Expand your JSON Schema to include deal-specific structures (schedules, deliverables, royalty ladders).
- Add more events and contingent clauses to model participation bonuses, caps, or escalators.
- Generate code from the IR to evaluate amounts, validate inputs, and render contract text.
Congratulations — you’ve built your first comple