# kyyn-core
Core vocabulary for [kyyn](https://github.com/drshade/kyyn): the registry
(kinds, fields, roles, affordances), the universal link grammar, the
serializable query AST and typed builder, the source-plugin contract, and the
validation protocol a KB's schema crate speaks.
A KB's `schema/` crate depends on this; the engine and the schema meet only
through these types.
## Schema authoring
Rust remains the canonical schema language. Derive `KyynKind` on stored
record structs and `KyynType` on nested structs or enums; the derives generate
the existing `Registry` vocabulary rather than a second schema format:
```rust
#[derive(serde::Serialize, serde::Deserialize, kyyn_core::KyynKind)]
#[kyyn(kind = "todo", storage = "facts/todos/{id}.ron")]
struct Todo {
id: String,
#[kyyn(role = "title")]
title: String,
#[kyyn(link(allowed = ["todo"]))]
blocked_by: Option<kyyn_core::link::Link>,
#[kyyn(markdown)]
notes: String,
}
```
`kyyn_schema!` assembles an explicit ordered kind list with the KB's roles,
queries, and optional custom-validation hook. Generic registry validation
always runs before custom findings are appended. Meaning Rust cannot infer —
Markdown rendering, roles, link policy and storage — must be explicit; an
ambiguous field is a compile error. Implement `KyynType` or `KyynKind`
manually for a representation outside the deliberately small derive surface.
Kind storage remains subject to Registry's existing ownership boundary: it
must be a relative path under `facts/` and may not contain `..`. `KyynKind`
reports that invariant at compile time; it does not introduce a macro-only
layout rule. For semantic annotations, do not shadow the standard `String`,
`Option`, `Vec`, or Kyyn `Link` names with unrelated types: early annotation
diagnostics identify those spellings before Rust resolves their definitions.
```rust,ignore
kyyn_core::kyyn_schema! {
kinds: [Charter, Todo, SelfContext],
roles: roles(),
queries: queries(),
custom_validate: validate::custom,
}
```
The optional custom hook has the same inputs as the protocol validator and
returns only its additional findings:
```rust,ignore
fn custom(
entries: &[(String, String)],
systems: &[&str],
) -> Vec<kyyn_core::violation::Violation> {
for record in kyyn_core::schema::custom_records::<Todo>(entries) {
// Typed cross-record/domain checks; generic Registry validation
// already owns routing and parse findings.
let todo = record.value;
}
Vec::new()
}
```
Schema `build.rs` files use the companion `kyyn-schema-build` crate to emit
the source hash consumed by `kyyn_schema!`; the hashing algorithm is shared
rather than copied into each KB.