Your First Contract in 5 Minutes
1. Create a Contract
mkdir my-escrow && cd my-escrow
modal contract create
This creates a .contract/ directory to track commits.
2. Create Identities
modal id create --path alice.passfile
modal id create --path bob.passfile
3. Initialize State
modal c checkout
mkdir -p state rules
# Add party identities
modal c set /parties/alice.id $(modal id get --path ./alice.passfile)
modal c set /parties/bob.id $(modal id get --path ./bob.passfile)
4. Define the Witness Model
Create model/escrow.modality:
model escrow {
initial q0
q0 -> q1 [+DEPOSIT +signed_by(/parties/alice.id)]
q1 -> q2 [+DELIVER +signed_by(/parties/bob.id)]
q2 -> q3 [+RELEASE +signed_by(/parties/alice.id)]
q1 -> q4 [+REFUND +signed_by(/parties/bob.id)]
}
q0, q1, and the other node ids are opaque witness nodes. The contract
meaning is carried by labels such as +DEPOSIT and predicates such as
+signed_by(...).
5. Add Protection Rules
Rules constrain which labeled transitions and commits remain acceptable. Create rules/buyer-protection.modality:
export default rule {
starting_at $PARENT
formula {
signed_by(/parties/alice.id) | signed_by(/parties/bob.id)
}
}
This says: "Every commit must be signed by Alice or Bob."
For authorization based on recorded contract data:
export default rule {
starting_at $PARENT
formula {
// Only buyer can commit while the delivered flag is false.
!bool_true(/status/delivered.bool) -> signed_by(/parties/buyer.id)
}
}
6. Commit and Verify
# Commit all changes
modal c commit --all --sign alice.passfile -m "Initial escrow setup"
# Check status
modal c status
What's Next?
- Core Concepts — Understand the theory
- CLI Reference — All commands explained
- Language Reference — Model and rule syntax