On this page
Custom verbs
The 14 verbs are fixed in v1. Adding a verb follows the same path as custom kinds, with one extra step: the L3 checker needs to know what to do with it.
When to add a verb
Most domain-specific relationships fit one of the 14 (especially
related and see-also as escape hatches). Add a verb only
if:
- The relationship has operational semantics the runtime should react to (e.g. a verb that triggers contract resolution).
- The relationship has validation semantics L3 should check (e.g. "kind X must point to kind Y for this verb").
The 5 files to patch
1. Verb literal — packages/types/src/ast.ts
export type EdgeVerb =
| 'related' | 'requires' | 'enhances' | 'validates-with'
| 'contradicts' | 'specializes' | 'conflicts' | 'extends'
| 'derived-from' | 'compatible' | 'supplies-to'
| 'see-also' | 'includes' | 'relationships'
| 'measures'; // ← your new verb 2. Field name in lexer — packages/parser/src/lexer.ts
// Verb names are recognised as field names in atom bodies.
const EDGE_VERBS = new Set<EdgeVerb>([
// ...
'measures',
]); 3. L1 verb-shape check — packages/compiler/src/checker-l1.ts
Allowed source/target kinds for the verb:
const VERB_KIND_RULES: Record<EdgeVerb, KindRule> = {
// ...
'measures': {
sourceKinds: ['metric'],
targetKinds: ['fact', 'rule', 'pattern'],
description: 'A metric measures the property described by an atom.',
},
}; 4. L3 graph reasoning — packages/compiler/src/checker-l3-cross.ts
// Add a check for your verb's specific invariants.
function checkMeasuresInvariants(graph: EdgeGraph): Diagnostic[] {
const ds: Diagnostic[] = [];
for (const e of graph.edgesByVerb('measures')) {
const target = graph.atomById(e.target);
if (!target) continue;
if (!target.fields.has('measurable-property')) {
ds.push({
level: 'warning',
message: `measures ${e.target} but target has no measurable-property field`,
});
}
}
return ds;
} 5. Fixture + test
// packages/compiler/test/fixtures/measures.prime
metric Latency {
id: "@perf/metric-latency"
...
measures: [@perf/rule-fast-response]
} What the L3 checker does
For your new verb, you decide what L3 catches. Examples:
- Cardinality: "every
metricmust have at least onemeasuresedge." - Reachability: "every atom referenced via
measuresmust have an inverse edge from the target." - Domain match: "
measuressource and target must share a domain."
RFC process
Same Tier-2 RFC as for custom kinds. See Custom kinds for the workflow.