mirror of
https://github.com/hanzoai/kai.git
synced 2026-10-17 11:18:06 +00:00
examples/claude-code holds a Stop hook, a PreToolUse hook and the kai skill. .claude-plugin/marketplace.json makes this repo the marketplace "kai" (not "hanzo", a name another Hanzo marketplace already holds), so /plugin install kai@kai installs it. Kai does not yet read agent work reliably: its zero-shot answers to "done", "verified" and "risky" are near chance. So rules in code decide first, Kai can only tighten (send a turn back, or ask before an action; never allow), both hooks fail open on any error or timeout, and the default mode, shadow, logs Kai's answers and changes nothing. The log holds probabilities and verdicts only, 0600 in a 0700 directory. A state sent to Kai is redacted and at most 3,000 characters of JSON; only https, or http on loopback, is called, and no redirect is followed. Against the first draft: plugin options are read as CLAUDE_PLUGIN_OPTION_<KEY> uppercased, as Claude Code exports them (the draft read lowercase names and never saw the plugin's key or mode). The floor is checked before the read-only shortcut, which let "env rm -rf" and awk's system() through, and now catches "git checkout -- .", "rm -Rf" and split rm flags. A background-task notice no longer starts a new turn. Stop answers with decision "block" as JSON. Only the last 8 MiB of a transcript is read: a 745 MB one made the hook throw. test/kai.test.mjs runs both hooks offline against a stand-in for Kai on 127.0.0.1, 25 tests; test.sh runs it with the rest. In a live Claude Code 2.1.296 session against the stand-in, the Stop block came back as "Stop hook feedback", the PreToolUse ask denied an allowed command under -p, and shadow showed a notice and let it run.
6.0 KiB
6.0 KiB
LLM.md — Kai cookbook
Overview
The public cookbook for Kai, Hanzo AI's decision model: runnable examples in
curl, Python, TypeScript, Go and Rust, and 18 recipes that each check Kai's answer
on their own input. Kai answers typed questions with probabilities over the
declared answers and writes no text (usage.output_tokens is 0).
Facts below were measured against production on 2026-10-09 (routing.checkpoint
kai-1.2, weights SHA-256 0834a74f…, calibration cal_e23c27a1f768bff7, CPU).
Models
kaiandhanzo/kai: the same model. Other spellings (hanzoai/kai-1,kai-1,kai-1-agent,kai-1-multilingual,jev) answer 400unknown model.typesafe/jev-1.13(also~typesafe/jev-latest): TypeSafe's model on the same endpoint and wire format.KAI_MODELswitches every example and recipe to it.- Price (
/v1/models): kai $0.021 per million input tokens, Jev $0.042, output free.
Wire API
POST https://api.hanzo.ai/v1/decisions,Authorization: Bearer <HANZO_API_KEY>.- Request:
{"model", "state", "questions": {"<name>": {"type", "instructions", "criteria"}}}.stateis a string, object or array. An unknown top-level field answers 400, an unknown question field 422. choice:criteriais an object (option → description) or a list of options. Answer:choice,probabilities,answer_confidence,confidence.score:criteriais the ordered list of levels, lowest first (levels→ 422). Answer:score(expected level index),legend,probabilitieskeyed "0".."n-1",answer_confidence,confidence.noul: Answer:noul= P(true). There is noactionfield.booleanis also accepted and answersprobability; the cookbook does not use it.answer_confidenceis the top probability;confidence= (p − 1/n) / (1 − 1/n).- Response:
id,model,provider,answers,usage,routing(backend,checkpoint,sha256,calibration,device,trained,extrapolated,reason),state_hash,latency_ms.
Limits
- Up to 100 questions per request; 101 → 422.
- Trained at 1,024 tokens of state per question (
routing.trained). Longer state is accepted withrouting.extrapolated: trueand is unreliable: at 3,982 tokens one fact read 0.985 at the start, 0.663 in the middle, 0.507 at the end. - One three-option question: 29–349 ms server time over 70 calls, 0.3–0.6 s round trip. 100 questions in one request: 13.9 s.
SDKs (8.5.704 on PyPI and npm; pinned in requirements.txt and package.json)
- Python:
from hanzoai.cloud import ApiClient, Configuration,from hanzoai.cloud.api import AiApi,from hanzoai.cloud.models.ai_decisions_request import AiDecisionsRequest;AiApi(ApiClient(Configuration(access_token=key))).post_decisions(AiDecisionsRequest.from_dict(body)). Builds every shape (choice with object or list criteria, score, noul). There is nofrom hanzoai import Hanzo. - TypeScript:
new AiApi(new Configuration({ accessToken })).postDecisions({ aiDecisionsRequest: body })returns an axios response (.data). No default export and noHanzoclass. The axios error object holds the request's Authorization header, so every TS file rethrows only status and body. - Go:
github.com/hanzoai/go-sdk/v8v8.5.623 hasAiAPI.PostDecisions, but its decoder refuses a choice with object criteria (oneOf matches twice) and its typed form wraps state and instructions inAiDecisionSidesFalse.examples/gouses net/http. - Rust:
hanzo-client8.5.156 (newest on crates.io) has no/v1/decisions.examples/rustuses reqwest with rustls.
Layout
examples/{curl,python,typescript,go,rust}: one call each; they pass when they answer.recipes/NN_name/:request.json(the call),expect.json(checked answers: a list of acceptable options for choice, of level indices for score, a boolean for noul; a question absent from it has no obvious answer and is printed only),run.py,run.ts(identical across recipes),README.md(its request and checked answers copy the two JSON files).examples/claude-code/: a Claude Code plugin (.claude-plugin/plugin.json,hooks/hooks.json,hooks/kai.mjs,skills/kai/SKILL.md)..claude-plugin/marketplace.jsonat the root makes the repo the marketplacekai(/plugin install kai@kai), nothanzo, so it cannot collide with another Hanzo marketplace a user holds (Claude Code keeps one marketplace per name). One dependency-free Node file runs aStophook (send back an unverified "done") and aPreToolUsehook (ask before an action that cannot be undone). Rules in code decide first; Kai only tightens; the hooks fail open and never allow; the default modeshadowlogs and changes nothing;onacts. Options reach the hook asCLAUDE_PLUGIN_OPTION_HANZO_API_KEYandCLAUDE_PLUGIN_OPTION_MODE(keys uppercased); a hand install setsHANZO_API_KEYandKAI_HOOK_MODE. Log:~/.hanzo/kai-hook/decisions.jsonl(0700/0600), numbers and verdicts only. A state sent to Kai is at most 3,000 characters of JSON, redacted; only the transcript's last 8 MiB is read.test/kai.test.mjsruns it offline against a loopback stand-in (node --test);claude plugin validate examples/claude-codeandclaude plugin validate .pass. kai-1.2 reads "done", "verified" and "risky" near chance, soonis not recommended until a trained version ships (README, Claude Code plugin).test.sh: runs everything live, prints<language>: N passed, M failed, exits 1 on any failure. The plugin's tests run offline in it, with an environment built by the test, never the key.hanzo.yml+.github/workflows/cicd.yml: hanzoai/ci runstest.shon our runners on push, pull request and daily, with the key read from KMS/ci/kaiHANZO_API_KEY(prod).SUBMIT.md: the systemonemodels.org "List an example" form contents.
Results (2026-10-09)
- Examples: curl 4/4, Python 4/4, TypeScript 4/4, Go 1/1, Rust 1/1 run.
- Recipes on kai: 6 of 18 pass in Python and in TypeScript (01, 06, 09, 11, 16, 17). Kai answers deterministically: the same request gives the same probabilities.