Intent IR
The Intent IR is the central type in Matrix. Every interaction produces one. It carries the typed source-of-truth (Frame) alongside structured gaps (Unknowns) and grounding references.
The Intent IR is the central type in Matrix. Every interaction produces one. It carries the typed source-of-truth (Frame) alongside structured gaps (Unknowns) and grounding references. Everything downstream operates on this type, never on raw prose.
Source files: ir/intent.go, ir/plan.go, ir/plan_validate.go, ir/encode.go.
Intent
type Intent struct {
ID string `json:"id"` // ULID
Version string `json:"v"` // "mcl/0.1"
Parent string `json:"parent,omitempty"` // parent IntentRef for sub-intents
Actor string `json:"actor"` // who wants this (UserRef or AgentRef)
Agent string `json:"agent"` // who will execute (AgentRef)
Prose string `json:"prose"` // original NL goal (display only)
Frame Frame `json:"frame"` // typed source of truth
Unknowns []Unknown `json:"unknowns,omitempty"` // structured gaps
References []Reference `json:"references,omitempty"` // grounding matrix:// URIs
State string `json:"state"` // IntentState
Confidence float64 `json:"confidence"` // 0..1
Budget *Budget `json:"budget,omitempty"`
Deadline string `json:"deadline,omitempty"` // ISO8601
CreatedAt string `json:"created_at"`
ExpiresAt string `json:"expires_at,omitempty"`
GoalID string `json:"goal_id,omitempty"` // links to parent Goal
SignedBy string `json:"signed_by"` // actor's public key
Hash string `json:"hash"` // sha256 self-hash
CompileMetadata *CompileMetadata `json:"compile_metadata,omitempty"` // D11 trace
}
Intent states
The Intent lifecycle follows a state machine:
| State | Description |
|---|---|
draft | Initial state from intent.draft |
proposed | After compilation (intent.compiled) |
clarifying | While intent.clarify / intent.answer loop is active |
accepted | After user signs off (intent.accept) |
executing | While the executor walks the plan |
completed | After intent.attest with outcome=success |
failed | After intent.fail |
cancelled | After intent.cancel |
Frame
The Frame is the typed source of truth: what gets signed and executed.
type Frame struct {
Verb string `json:"verb"` // D7 closed vocab
Objects []SlotEntry `json:"objects"` // typed referents
Constraints []Constraint `json:"constraints,omitempty"` // hard/soft predicates
SuccessCriteria []Predicate `json:"success_criteria,omitempty"` // completion checks
Preferences []Preference `json:"preferences,omitempty"` // soft tie-breakers
}
SlotEntry
type SlotEntry struct {
Name string `json:"name"` // slot name
Value string `json:"value"` // resolved value or NL text
URI string `json:"uri,omitempty"` // resolved matrix:// URI (post D13)
Type string `json:"type,omitempty"` // type annotation
}
Constraint
Typed predicates that must hold throughout execution:
| Type | Fields | Description |
|---|---|---|
budget | max (AssetAmount) | Spending cap |
deadline | by (ISO8601) | Completion deadline |
jurisdiction | allow, deny (string[]) | Geographic/legal scope |
quality | metric, min (float64) | Quality threshold |
rule | rule (RuleRef) | Rule matrix:// URI |
policy | policy (Argus) | Policy reference |
x:* | schema, data | Custom constraint |
Hard constraints (hard: true) fail the intent if violated.
Predicate
Checkable completion criteria:
| Type | Fields | Description |
|---|---|---|
delivered | artifact | Artifact was delivered |
signed_off | by (UserRef) | User approved |
external | url, check | External verification |
attestation | source, topic | Agent attestation |
x:* | schema, data | Custom predicate |
Preference
Soft tie-breakers that do not fail the intent if violated:
type Preference struct {
Rank string `json:"rank"` // preference dimension
Prefer []string `json:"prefer,omitempty"` // ordered preferences
}
Unknown
A typed gap blocking or delaying execution:
type Unknown struct {
ID string `json:"id"` // local id ("u1", "u2")
Field string `json:"field"` // SlotPath
Type string `json:"type"` // expected type
Severity string `json:"severity"` // "blocking" | "preferred" | "optional"
Rationale string `json:"rationale"` // human-readable why
Default string `json:"default,omitempty"` // suggested fill
Options []string `json:"options,omitempty"` // enum-like choices
SourceHint string `json:"source_hint,omitempty"` // cortex location
}
Blocking unknowns prevent intent.accept until resolved. Preferred unknowns produce clarify questions. Optional unknowns are surfaced in the UI without interrupting flow.
PlanTree
The PlanTree is the typed plan structure produced by skills running under the executor model:
type PlanTree struct {
ID string `json:"id"` // ULID
Version string `json:"v"` // "mcl/0.1"
IntentID string `json:"intent_id"` // back-reference
CreatedAt string `json:"created_at"` // ISO-8601
CreatedBy string `json:"created_by"` // matrix://agent/<did>
SkillRef string `json:"skill_ref"` // version-pinned skill URI
ModelDigest string `json:"model_digest,omitempty"`
Root PlanNode `json:"root"` // entry point
Budget *Budget `json:"budget,omitempty"`
Hash string `json:"hash"` // sha256 self-hash
}
PlanNode
A discriminated union by Kind:
| Kind | Payload | Children | Description |
|---|---|---|---|
sequential | (none) | >= 1 | Runs children in order |
parallel | (none) | >= 1 | Runs children concurrently |
step | Step | 0 | In-skill LLM prompt |
tool_call | ToolCall | 0 | Single tool invocation |
sub_dispatch | SubDispatch | 0 | Sub-skill or sub-agent dispatch |
gate | Gate | 0 | Human-in-loop policy gate |
StepPayload
type StepPayload struct {
PromptName string `json:"prompt_name,omitempty"`
Inputs map[string]string `json:"inputs,omitempty"`
ExpectedOutputs []string `json:"expected_outputs,omitempty"`
Kind string `json:"kind,omitempty"` // "reason", "code", "summarize", etc.
}
The Kind field drives executor-tier model routing. Closed set: reason, code, summarize, write, transform, classify, hard_reason.
ToolCallPayload
type ToolCallPayload struct {
ToolRef string `json:"tool_ref"` // version-pinned matrix:// URI
Args map[string]string `json:"args,omitempty"`
TimeoutMs int `json:"timeout_ms,omitempty"`
SideEffectClass string `json:"side_effect_class,omitempty"` // "read", "write", "network", "shell", "chain"
}
SubDispatchPayload
type SubDispatchPayload struct {
SkillRef string `json:"skill_ref"` // version-pinned sub-skill URI
AgentRef string `json:"agent_ref,omitempty"` // target agent
SubIntent *Frame `json:"sub_intent,omitempty"` // Frame for sub-intent
ScopeURI string `json:"scope_uri,omitempty"` // CortexScope grant
}
Canonical encoding (D11)
The CanonicalJSON function encodes an Intent to canonical JSON with deterministic key ordering at every nesting level. Zero/empty values are omitted. The sha256 hash of this encoding is the Intent's Hash field:
func Hash(intent *Intent) (string, error) {
// Clear self-referential hash field
intent.Hash = ""
canonical, _ := CanonicalJSON(intent)
sum := sha256.Sum256(canonical)
return fmt.Sprintf("%x", sum), nil
}
The same canonical encoding is used for PlanTree hashing via HashPlan.
D7 closed verbs
var D7ClosedVerbs = map[string]bool{
"find": true, "acquire": true, "build": true, "modify": true,
"deliver": true, "analyze": true, "negotiate": true, "schedule": true,
"monitor": true, "delegate": true,
}
The x: namespace is available for custom verbs: any verb starting with x: passes validation.
Plan validation
ValidatePlan enforces 8 structural invariants:
PlanTree.ID,IntentID,SkillRefmust be populated- Every
PlanNodehas a unique non-empty ID within the tree - Every
PlanNode.Kindis inValidNodeKinds - Branch kinds (
sequential,parallel) have >= 1 child and no terminal payload - Terminal kinds (
step,tool_call,sub_dispatch,gate) have no children and exactly the matching typed payload ToolCall.ToolRefandSubDispatch.SkillRefare version-pinned (must contain@)ToolCall.SideEffectClass(if set) is inValidSideEffectClassesGate.Questionis non-empty
