# openkind-core
> The canonical Jev wire contract, data structures, and validation rules for `openkind`.
`openkind-core` is the foundational crate of the `openkind` workspace. It defines the Jev wire types (`SystemRequest`, `SystemResponse`, `Question`, `Answer`, `State`) and the validation invariants of the [TypeSafe Jev API contract](https://docs.typesafe.ai/api), spoken over HTTP and gRPC.
It depends on no other workspace crate. The engine, API, server, CLI, client, runtime, backends, bench, and schema-generation crates all depend on it.
## Quickstart
```rust
use std::collections::HashMap;
use openkind_core::{
validate_request, NoulQuestion, Question, State, SystemRequest, WireHashState,
};
let mut questions = HashMap::with_hasher(WireHashState::default());
questions.insert(
"is_urgent".into(),
Question::Noul(NoulQuestion {
instructions: serde_json::json!("Does this message convey urgency?"),
criteria: None,
}),
);
let request = SystemRequest {
state: State::Text("Server down in production!".into()),
model: "mock".into(),
questions,
};
assert!(validate_request(&request).is_ok());
```
Question maps use `WireHashState`, a foldhash-based hasher, so construct them with `HashMap::with_hasher(WireHashState::default())` rather than `HashMap::new()`.
## Wire types
- `SystemRequest`: the `/v1/systemone` request body, with `state`, `model`, and a map of question ID to `Question`. `API_VERSION` (`"jev-compatible-0.1"`) pins the wire version.
- `SystemResponse`: one `Answer` per question ID plus required token `Usage`.
- `Question`: a tagged enum of `NoulQuestion`, `ChoiceQuestion`, and `ScoreQuestion`. `instructions` accepts a string, object, or array, and Choice criteria values may be `null`.
- `Answer`: a tagged enum of `NoulAnswer`, `ChoiceAnswer`, and `ScoreAnswer`. `NoulAnswer` carries only `noul` and has no `confidence` field, per the spec.
- `State`: polymorphic input accepting plain text, a JSON object, or a JSON array.
- `ModelInfo` / `ModelsResponse`: wire structures for `GET /v1/models`.
Every wire float (`probabilities`, `score`, `noul`, `confidence`) is `f64`, so JSON round-trips exactly; an `f32` would turn `0.92` into `0.9200000166893005`.
## Validation
- `validate_request(&req)` rejects empty question maps, empty instructions, Choice questions without options, Score rubrics with fewer than two non-empty levels, and Noul criteria with empty `true`/`false` descriptions. It also caps requests at 10,000 questions and questions at 10,000 criteria options.
- `validate_response_for_request(&resp, &req)` and its retained `ResponseContract` check each answer against its request: answer type, selected Choice option, probability keys, sum-to-one distributions within tolerance, `confidence` and `noul` bounds in `[0.0, 1.0]`, and Score legend, index, and score consistency. `validate_response(&resp, &criteria)` remains for callers that only hold a criteria map.
## JSON schemas
The request, question, answer, and state types derive `schemars::JsonSchema`. The committed schemas under [`schemas/`](schemas/) are generated by the separate `openkind-gen-schemas` crate with `cargo run -p openkind-gen-schemas -- --write` and are never hand-edited.
## Testing
```bash
cargo test -p openkind-core
```
Module unit tests sit in `src/`, and [`tests/conformance.rs`](tests/conformance.rs) pins the wire format to examples and rules from the Jev spec.
## License
See the [MIT license](../../LICENSE). Cargo metadata declares `MIT OR Apache-2.0`.