Skip to content

Getting Started — KN-86 Cartridge SDK

30 minutes from cold install to your first running .kn86 cartridge.

The KN-86 SDK gives you a single CLI — kn86 — that scaffolds, builds, and runs cartridges for the Kinoshita KN-86 Deckline. This guide takes you from zero to a “Hello, Operator” cart that paints the screen and emits a CIPHER fragment to the auxiliary OLED.

  • Rust toolchainrustc 1.75 or newer (the SDK is distributed via cargo install). Install via rustup.
  • The desktop emulatorkn86emu, the SDL3 host at hosts/emulator/ in the kn-86 monorepo. The SDK shells out to it for kn86 run. Build it from the monorepo root with:
    Terminal window
    cmake -S hosts/emulator -B hosts/emulator/build && cmake --build hosts/emulator/build
    This produces hosts/emulator/build/bin/kn86emu. (Note: hosts/emulator/ is currently a stub pending source population — see the repo README.)
  • macOS or Linux. Tested on macOS arm64 (Apple Silicon) and Linux x86_64. Windows is not supported in v0.1; use WSL2.
  • SDL2 for the emulator (brew install sdl2 on macOS, or your distro’s libsdl2-dev on Linux).
Terminal window
cargo install --path sdk/tools/kn86-sdk # from a kn-86 monorepo checkout

That installs the kn86 binary into ~/.cargo/bin. Confirm:

Terminal window
kn86 --version
# kn86 0.1.0 (NoshAPI v1.0)

The version line tells you two things: the SDK version and the NoshAPI version that SDK pins. Cart manifests must match the major NoshAPI version, or kn86 build rejects the build with an actionable error.

If kn86: command not found, ensure ~/.cargo/bin is on your $PATH (rustup adds this for you on most shells; check echo $PATH).

Terminal window
kn86 new hello-operator
cd hello-operator

You’ll get this layout:

hello-operator/
├── cart.toml # Manifest — identity, API version, build paths.
├── src/
│ └── main.lsp # Entry-point Lisp source.
├── README.md # Cart-author quickstart.
└── .gitignore

Open cart.toml — every field is annotated. The cart-id is deterministically derived from your project name (FNV-1a) so the same name always gets the same ID; rotate it manually if you publish a cart and need a fresh identity.

The [api].nosh-api-version = "1.0" line is your contract with the runtime: kn86 build checks the major matches the SDK’s pinned NoshAPI version (currently 1) and refuses to build on a mismatch.

The scaffold gives you a runnable cart. Open src/main.lsp:

(register-cell-type "operator-greeting" ROOT-TYPE
(fn (cell event)
(if (is event 'enter)
(do
(text-clear)
(text-puts 2 2 "KN-86 DECKLINE :: HELLO, OPERATOR")
(text-puts 2 4 "Cartridge: hello-operator")
...
(sfx-confirm))
(if (is event 'info)
(do
(cipher-emit "trace.acknowledged" "operator")
(sfx-keyclick))
...))))
(spawn-cell ROOT-TYPE)

What’s happening:

  • register-cell-type declares a cell type and the lambda that handles its events. Every cart is a tree of cells; the runtime dispatches keypresses by walking from the focused cell up the tree.
  • text-puts writes a string at (col, row) on the main grid (128×75 cells at the 1× ceiling per ADR-0036; CLAUDE.md Canonical Hardware Specification is authoritative). Rows 1–73 are yours; Row 0 (status) and Row 74 (action bar) are firmware-owned — never draw there.
  • cipher-emit sends a CIPHER fragment to the auxiliary 256×64 OLED. CIPHER is OLED-exclusive (the Null cart is the lone exception).
  • sfx-confirm / sfx-keyclick are pre-mixed YM2149 cues. The raw psg-write register interface is also available; see the FFI reference.
  • spawn-cell at the bottom is the cart entry — the runtime invokes top-level forms once when the cart loads, so this brings the root cell into existence.
Terminal window
kn86 build
# Built /home/you/hello-operator/build/hello-operator.kn86 (1947 bytes) [NoshAPI v1.0, VM v1.0]

Under the hood, kn86 build:

  1. Reads cart.toml, validates it, and verifies the NoshAPI major matches the SDK’s pinned version.
  2. Reads src/main.lsp.
  3. Wraps the source in an ADR-0006 v2.0 .kn86 container with an 80-byte header, a static-data END tag, and a CRC-32 checksum.
  4. Writes it to build/hello-operator.kn86.

The code section embeds the .lsp source verbatim (ADR-0006 Option 1, the v0.1 launch path and current behavior) — Fe tree-walks the source on load; there is no bytecode. Ahead-of-time Fe bytecode compilation is a deferred future (see ADR-0004 2026-06-14 amendment); the file format already reserves the offsets for it.

Terminal window
kn86 run

kn86 run locates the emulator binary in this priority order:

  1. --emu /absolute/path/to/kn86emu
  2. $KN86_EMU environment variable
  3. kn86emu on $PATH

If you built the emulator from source and didn’t install it system-wide:

Terminal window
export KN86_EMU=/path/to/kn-86/hosts/emulator/build/bin/kn86emu
kn86 run

You should see the KN-86 phosphor-on-black screen (AMBER by default per ADR-0036; the SYS tab lets you swap to WHITE or GREEN) with your “HELLO, OPERATOR” greeting. Press INFO to fire cipher-emit (watch the auxiliary OLED — trace.acknowledged operator). Press BACK to exit.

  • FFI reference — every NoshAPI primitive with signature, semantics, error modes, and an example. Auto-generated from docs/adr/ADR-0005-ffi-surface.md (single source of truth). Regenerate locally with kn86 docs ffi.
  • Reference cartridges — the launch-title carts in carts/carts/ (blackledger.lsp, icebreaker.lsp, depthcharge.lsp, neongrid.lsp) are full-feature examples spanning multi-cell hierarchies, mission phases, and CIPHER vocabularies.
  • Lisp paradigmdocs/software/cartridges/authoring/lisp-paradigm.md describes how each of the 14 module keys (CAR, CDR, CONS, EQ, EVAL, QUOTE, INFO, BACK, NIL, ATOM, plus 4 module- specific) maps to gameplay actions.
  • Screen design rulesdocs/software/cartridges/authoring/screen-design-rules.md lays out the Row 0 / Rows 1–23 / Row 24 contract.
SymptomFix
kn86: command not foundEnsure ~/.cargo/bin is on $PATH.
cart.toml not foundRun kn86 build from the project root (where cart.toml lives).
cart.toml nosh-api-version is X.Y, but this SDK targets v1.0Either bump cart.toml [api].nosh-api-version to a compatible value, or install a matching SDK version.
could not find emulator binary kn86emuBuild kn86emu (see Prerequisites) and either put it on $PATH or set KN86_EMU.
invalid cart nameNames must be lowercase kebab-case, 2..=31 chars: [a-z][a-z0-9-]*, no trailing dash.
  • macOS arm64 (Apple Silicon) — confirmed working. SDL2 via Homebrew (brew install sdl2).
  • Linux x86_64 — confirmed working. Distro packages typically ship libsdl2-dev (Debian/Ubuntu) or SDL2-devel (Fedora).
  • Windows — not supported in v0.1. WSL2 with an X server (or WSLg on Windows 11) works as a Linux fallback.

SDK v0.1.x targets NoshAPI v1.x. The promise:

  • Patch bumps of the SDK never change the FFI surface.
  • Minor bumps of the SDK can ship NoshAPI minor additions (new primitives, never removals or signature changes).
  • Major bumps of the SDK move to a new NoshAPI major and may break older carts. The CLI surface (kn86 new / kn86 build / kn86 run) is independently semver’d.

See docs/software/api-reference/nosh-api/versioning.md for the full rules.