Skip to main content

RFC-001: Modal Contract Specification

Status: Draft
Author: Gerold Steiner
Created: 2026-02-01
Version: 0.1.0


Abstract​

This document specifies the Modal Contract format — a cryptographically-verified, append-only log structure for multi-party cooperation. Modal contracts enable agents (human or AI) to negotiate binding agreements with formal verification guarantees.

A modal contract consists of:

  1. An append-only commit log — the single source of truth
  2. A governing model — a labeled transition system (LTS) defining valid transitions
  3. Rules — temporal logic formulas constraining behavior
  4. State — data derived by replaying the commit log

Every commit must satisfy the governing model and all accumulated rules. Verification is mathematical, not reputational.


1. Terminology​

TermDefinition
ContractAn append-only log of signed commits
CommitAn atomic, signed change to the contract
ModelA Kripke structure (LTS) defining valid transitions
RuleA temporal logic formula constraining contract behavior
PredicateA WASM module evaluating conditions (e.g., signed_by)
StateData derived by replaying commits
PartyAn entity identified by an ed25519 public key
HubA coordination service for push/pull of contracts

2. Contract Structure​

A modal contract is represented as a directory:

<contract>/
├── .contract/ # Internal metadata
│ ├── config # Contract configuration
│ ├── HEAD # Current commit hash
│ └── commits/ # Commit objects
│ ├── <hash1>
│ ├── <hash2>
│ └── ...
├── state/ # State files (derived from commits)
│ └── <path>.<type> # e.g., /users/alice.id
├── model/ # Governing model(s)
│ └── default.modality # Primary model
└── rules/ # Rule files
└── <name>.modality # e.g., auth.modality

2.1 Path Types​

State files use typed extensions:

ExtensionTypeDescription
.idIdentityed25519 public key (hex)
.textTextUTF-8 string
.boolBooleantrue or false
.jsonJSONStructured data
.mdMarkdownDocumentation
.dateDateISO 8601 date
.datetimeDateTimeISO 8601 datetime
.wasmWASMWebAssembly module
.modalityModalityModel or rule definition

3. Commit Log​

The commit log is the single source of truth. State is derived by replaying commits.

3.1 Commit Structure​

{
"hash": "<sha256>",
"parent": "<parent_hash>",
"timestamp": "<ISO 8601>",
"author": {
"id": "<ed25519_pubkey_hex>",
"signature": "<signature_hex>"
},
"method": "<METHOD>",
"path": "<path>",
"payload": "<content>",
"action": { ... }
}

3.2 Commit Methods​

MethodDescriptionExample Path
POSTSet state value/users/alice.id
REPOSTSnapshot a value from another contract/reposts/<source_id>/users/alice.id
RULEAdd temporal rule/rules/auth.modality
MODELSet governing model/model/default.modality
ACTIONExecute domain actionn/a (uses action field)

3.3 Commit Validation​

Every commit must pass:

  1. Signature verification — ed25519 signature over commit data
  2. Transition validity — commit action matches a valid model transition
  3. Rule satisfaction — all accumulated rules remain satisfiable
  4. Type validation — path extension matches content type

4. Model Syntax​

Models define valid state transitions using Kripke structures.

4.1 Grammar​

model       ::= "export" "default" "model" "{" model_body "}"
model_body ::= "initial" state_name transition*
transition ::= state_name "->" state_name predicate_list?
predicate_list ::= "[" predicate ("," predicate)* "]"
predicate ::= ("+" | "-") predicate_name "(" path ")"
state_name ::= identifier
path ::= "/" identifier ("/" identifier)*

4.2 Example​

export default model {
initial idle

idle -> deposited [+signed_by(/users/buyer.id)]
deposited -> delivered [+signed_by(/users/seller.id)]
delivered -> released [+signed_by(/users/buyer.id)]
deposited -> refunded [+signed_by(/users/buyer.id), +signed_by(/users/seller.id)]
}

4.3 Predicate Polarity​

  • +predicate — predicate must be TRUE for transition
  • -predicate — predicate must be FALSE for transition

4.4 State Inference​

States are inferred from transitions. No explicit state declaration required.


5. Rule Syntax​

Rules constrain contract behavior using modal mu-calculus.

5.1 Grammar​

rule        ::= "export" "default" "rule" "{" rule_body "}"
rule_body ::= "starting_at" anchor "formula" "{" formula "}"
anchor ::= "$PARENT" | commit_hash
formula ::= bool_formula | modal_formula | temporal_formula | fixed_point
bool_formula ::= "true" | "false" | proposition
| formula "&" formula | formula "|" formula
| "!" formula | formula "->" formula
| "(" formula ")"
modal_formula ::= "[" action "]" formula
| "<" action ">" formula
| "[<" action ">]" formula
| "[]" formula | "<>" formula
temporal_formula ::= "always" "(" formula ")"
| "eventually" "(" formula ")"
| formula "until" formula
| "next" "(" formula ")"
fixed_point ::= "lfp" "(" var "," formula ")"
| "gfp" "(" var "," formula ")"
| var
action ::= ("+" | "-") predicate_call

5.2 Operator Semantics​

OperatorSyntaxMeaning
Box[+A] φAfter ALL A-transitions, φ holds
Diamond<+A> φAfter SOME A-transition, φ holds
Diamondbox[<+A>] φCommitted: can do A AND cannot refuse
Alwaysalways(φ)φ holds on all paths, forever
Eventuallyeventually(φ)φ holds on some path, eventually
Untilp until qp holds on some path until q
LFPlfp(X, φ)Least fixed point (reachability)
GFPgfp(X, φ)Greatest fixed point (invariants)

5.3 Temporal as Fixed Points​

always(f)     ≡ gfp(X, []X & f)
eventually(f) ≡ lfp(X, <>X | f)
until(p, q) ≡ lfp(X, q | (p & <>X))

5.4 Example​

export default rule {
starting_at $PARENT
formula {
always (
!<+RELEASE> true | <+DELIVER> true
)
}
}

This rule uses explicit Boolean form for the conditional: if RELEASE is possible, then DELIVER must also be possible from the same point.


6. Predicates​

Predicates are WASM modules evaluating conditions.

6.1 Standard Predicates​

PredicatePurposeParameters
signed_by(path)Verify ed25519 signatureIdentity path
threshold(n, path)n-of-m multisigThreshold, signers path
oracle_attests(path, claim, value)Oracle attestationOracle path, claim, expected
before(path)Timestamp constraintDatetime path
after(path)Timestamp constraintDatetime path
hash_matches(path)SHA256 commitmentHash path

6.2 Predicate Evaluation​

Predicates return:

{
"valid": true,
"gas_used": 250,
"errors": []
}

6.3 Custom Predicates​

Deploy WASM modules to /_code/custom/<name>.wasm:

modal contract wasm-upload \
--wasm-file ./my_predicate.wasm \
--module-name "/custom/my_predicate"

Reference as +custom_predicate(args) in models/rules.


7. Cryptography​

7.1 Identities​

Identities are ed25519 key pairs.

  • Public key: 32 bytes, hex-encoded
  • Private key: 64 bytes, stored in passfile

7.2 Signatures​

Commits are signed using ed25519:

signature = ed25519_sign(
private_key,
sha256(canonical_commit_bytes)
)

7.3 Commit Hashing​

hash = sha256(
parent_hash ||
timestamp ||
author_id ||
method ||
path ||
sha256(payload)
)

8. Hub Protocol​

The Contract Hub provides HTTP-based coordination.

8.1 Authentication​

Two-tier ed25519 authentication:

  1. Identity key — long-term party identity
  2. Access key — session key for hub access

Registration:

POST /register
{
"identity_pubkey": "<hex>",
"access_pubkey": "<hex>",
"identity_signature": "<hex>"
}

8.2 Endpoints​

MethodEndpointDescription
POST/contractsCreate contract
GET/contracts/:idGet contract metadata
GET/contracts/:id/commitsList commits
POST/contracts/:id/commitsPush commit
GET/contracts/:id/commits/:hashGet commit
POST/contracts/:id/grantGrant access

8.3 Commit Validation​

Hub validates each pushed commit:

  1. Signature verification
  2. Parent exists and matches HEAD
  3. Transition matches governing model
  4. All rules remain satisfiable

Invalid commits are rejected with error details.

8.4 Access Control​

Contracts have access lists:

{
"owner": "<identity_pubkey>",
"writers": ["<pubkey1>", "<pubkey2>"],
"readers": ["<pubkey3>"]
}

9. CLI Reference​

9.1 Contract Commands​

modal contract create              # Create new contract
modal c checkout # Create working directory
modal c status # Show pending changes
modal c commit --all # Commit all changes
modal c commit --sign <passfile> # Signed commit
modal c log # Show commit history
modal c diff # Show pending diff

9.2 Identity Commands​

modal id create --path <file>      # Create identity
modal id create --name <name> # Create named identity
modal id get --name <name> # Get named public key
modal c set-named-id <path> <name> # Bind named identity evidence

9.3 Hub Commands​

modal hub start                    # Start local hub
modal hub register # Register identity
modal c remote add <name> <url> # Add hub remote
modal c push <remote> # Push to hub
modal c pull <remote> # Pull from hub

10. Examples​

10.1 Simple Escrow​

Model:

export default model {
initial init

init -> deposited [+signed_by(/users/buyer.id)]
deposited -> delivered [+signed_by(/users/seller.id)]
delivered -> released [+signed_by(/users/buyer.id)]
deposited -> disputed [+signed_by(/users/buyer.id)]
deposited -> disputed [+signed_by(/users/seller.id)]
disputed -> resolved [+signed_by(/users/arbiter.id)]
}

Rule:

export default rule {
starting_at $PARENT
formula {
always (
!<+RELEASE> true | <+DELIVER> true
)
}
}

10.2 Multi-Sig Treasury​

Model:

export default model {
initial idle

idle -> proposed [+signed_by(/treasury/member.id)]
proposed -> approved [+threshold(3, /treasury/signers)]
approved -> executed [+signed_by(/treasury/executor.id)]
proposed -> rejected [+threshold(3, /treasury/signers)]
}

10.3 Oracle-Gated Release​

Model:

export default model {
initial waiting

waiting -> attested [+oracle_attests(/oracles/delivery, "delivered", "true")]
attested -> released [+signed_by(/users/buyer.id)]
}

11. Security Considerations​

11.1 Key Management​

  • Private keys MUST be stored securely (passfiles with restricted permissions)
  • Session keys SHOULD be rotated regularly
  • Compromised keys require contract migration

11.2 Model Design​

  • Models MUST include terminal states or self-loops
  • Avoid unbounded state spaces
  • Test models with the checker before deployment

11.3 Rule Safety​

  • Rules are cumulative — cannot be removed
  • Test rule satisfiability before committing
  • Contradictory rules will deadlock the contract

11.4 Hub Trust​

  • Hubs validate but don't guarantee liveness
  • Multi-hub replication recommended for critical contracts
  • Ultimately, chain anchoring provides strongest guarantees

12. Conformance​

An implementation conforms to this specification if it:

  1. Correctly parses model and rule syntax
  2. Validates commits against governing models
  3. Verifies ed25519 signatures
  4. Evaluates standard predicates correctly
  5. Derives state by replaying commit logs
  6. Rejects commits that violate accumulated rules

Appendix A: ABNF Grammar​

; Model
model = "export" SP "default" SP "model" SP "{" model-body "}"
model-body = "initial" SP state-name *transition
transition = state-name SP "->" SP state-name [predicate-list]
predicate-list = "[" predicate *("," predicate) "]"
predicate = ("+" / "-") predicate-name "(" path ")"
state-name = identifier
path = "/" identifier *("/" identifier) ["." extension]

; Rule
rule = "export" SP "default" SP "rule" SP "{" rule-body "}"
rule-body = "starting_at" SP anchor "formula" SP "{" formula "}"
anchor = "$PARENT" / commit-hash

; Formula (simplified)
formula = "true" / "false" / proposition
/ formula SP "&" SP formula
/ formula SP "|" SP formula
/ "!" formula
/ formula SP "->" SP formula
/ "[" action "]" SP formula
/ "<" action ">" SP formula
/ "[<" action ">]" SP formula
/ "always" "(" formula ")"
/ "eventually" "(" formula ")"
/ "lfp" "(" var "," formula ")"
/ "gfp" "(" var "," formula ")"
/ "(" formula ")"

; Primitives
identifier = ALPHA *(ALPHA / DIGIT / "_")
extension = "id" / "text" / "bool" / "json" / "md" / "wasm" / "modality"
commit-hash = 64HEXDIG

Appendix B: References​


RFC-001: Trust through verification, not reputation. 🔐