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:
- None of the 28 captures the structure your domain needs.
- The structure is general enough to serve more than one corpus.
- 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.