Skill Wiki v0.1.0

Docs / extending / custom-verbs

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 metric must have at least one measures edge."
  • Reachability: "every atom referenced via measures must have an inverse edge from the target."
  • Domain match: "measures source and target must share a domain."

RFC process

Same Tier-2 RFC as for custom kinds. See Custom kinds for the workflow.