Skill Wiki v0.1.0

Docs / extending / custom-kinds

On this page

Custom kinds

The 28 kinds are fixed in v1's parser. Adding a new one is a 4-file patch + a Tier-2 RFC. Plan on a 1-week review cycle for a kind to land in the spec.

When to add a kind

Add a kind when:

  1. None of the 28 captures the structure your domain needs.
  2. The structure is general enough to serve more than one corpus.
  3. The L3 checker needs to reason about its specific semantics (otherwise type + tags are enough).

If it's only your corpus, a type atom + an axes entry in domain.yaml is usually the right answer instead.

The 4 files to patch

1. Type definition — packages/types/src/ast.ts

// Add the literal to the union
export type AtomKind =
  | 'fact' | 'term' | 'value' | 'category'
  | 'example' | 'counter-example' | 'source' | 'metric'
  | 'step' | 'check' | 'transform' | 'tool'
  | 'method' | 'rule' | 'taxonomy' | 'pattern'
  | 'anti-pattern' | 'type' | 'constraint'
  | 'collection' | 'scope' | 'tradeoff' | 'principle' | 'feedback'
  | 'persona' | 'voice' | 'template' | 'provocation'
  | 'recipe';   // ←  your new kind

2. Lexer keyword — packages/parser/src/lexer.ts

const KEYWORDS = new Set<AtomKind>([
  'fact', 'term', 'value', 'category',
  // ...
  'recipe',   // ← here
]);

3. L1 schema — packages/compiler/src/checker-l1.ts

const SCHEMAS: Record<AtomKind, FieldSchema> = {
  // ...
  'recipe': {
    required: ['ingredients', 'steps', 'serves'],
    optional: ['source', 'time-minutes'],
  },
};

4. Chunker splitter — packages/compiler/src/chunker.ts

const SPLITTERS: Record<AtomKind, Splitter> = {
  // ...
  'recipe': recipeSplitter,
};

function recipeSplitter(atom: AtomDeclaration): ChunkLevels {
  return {
    summary: `# ${atom.name}\n\n${atom.fields.find('description')?.value}`,
    core: ...,
    full: ...,
  };
}

5. Add a fixture test

// packages/parser/test/fixtures/atom-recipe.prime
recipe Spaghetti {
  id: "@kitchen/recipe-spaghetti"
  version: "1.0.0"
  description: "Classic spaghetti."
  domain: cooking

  ingredients: [
    { name: "spaghetti", weight-g: 200 },
    { name: "garlic", count: 3 },
  ]
  steps: [...]
  serves: 2
}

// packages/parser/test/parser.test.ts
test("parses recipe kind", () => {
  const ast = parse(readFixture("atom-recipe.prime"));
  expect(ast.atoms[0].kind).toBe("recipe");
});

6. Open the RFC

File a PR with all 5 changes and a brief rationale (problem, alternatives considered, expected impact). Tier-2 RFC means: 1 protocol-team review + 7-day objection window. See governance.md.

YAML-declared custom-kind (roadmap)

A planned v0.2 feature: declare a kind via YAML in domain.yaml without a parser patch. Trade-off: you get the structure, but no L3 semantic reasoning over the kind. See the roadmap.