Files
alktype/docs/architecture/overview.md
glm-5.2 1a8a44ed0e Draft builder API (ADR-009) and generalized validation validate_bytes (ADR-010) for v0.1.0
- ADR-009: fluent Rust builder producing serde_json::Value, covers
  AlkType kinds + standard JSON Schema; resolves OQ-003 (alkcall is the
  unblocking consumer)
- ADR-010: AlkTypeEngine::validate_bytes(&[u8]) as the single-call
  binary-buffer validation entry point; materialize Value from bytes,
  then validate; two methods on one struct, not a trait
- builder.md: full builder API spec (Schema, Definitions, Discriminator)
  with four usage examples (channels chunk header, call input schema,
  SFTP Packet union, OperationSpec error schemas)
- validation.md: new validate_bytes subsection + entry-point comparison
  table; AlkTypeEngine impl block updated; design decisions table updated
- overview.md: builder.md added to component pointers; 'Not a schema
  builder' scope boundary retired; ADR-009/010 added to decisions table;
  OQ-003 marked resolved; Consumers table adds alkcall as first consumer
- open-questions.md + questions/003: OQ-003 moved from deferred(scope)
  to resolved (ADR-009)
- README.md: builder doc + ADR-009/010 added; OQ-003 marked resolved;
  two new Key Design Principles (9, 10) for v0.1.0 additions

Doc-only change; 346 tests pass, clippy clean.
2026-08-11 05:41:49 +00:00

13 KiB

status, last_updated
status last_updated
draft 2026-08-11

alktype — Overview

The binary struct engine: a small Rust crate that takes a JSON Schema with AlkType:* custom keywords and produces an offset map, read/write functions, and validation — all driven by the schema. The schema is the format definition; the engine is generic.

This document covers the crate's purpose, the "schema is the format" principle, its dependency edges, consumers, and scope boundaries. Component details are in the sibling documents.

What

alktype is a library crate that consumes JSON Schemas annotated with AlkType:* custom keywords (the same kinds defined in TypeBox's typedef.ts, plus AlkType:Bytes, AlkType:Int64, and AlkType:Uint64 as alktype additions) and produces three capabilities:

  1. An offset map — walks the schema, computes byte offsets for each field based on type sizes, field order, and alignment.
  2. Read/write functions — given a &[u8] buffer and a field path, read the field's bytes at its offset (zero-copy for fixed-size types). Given a &mut [u8] buffer, write a value at its offset.
  3. Validation — via jsonschema custom keywords, validates that a buffer's bytes match the schema's type constraints.

The heavy lifting is done by the jsonschema crate (validation) and serde_json (schema parsing). The novel code is the offset computation — a recursive walk of the schema JSON that computes byte positions for each field. The custom keyword implementations are small (a few lines each, generated from shared macros — see validation.md).

The crate replaces two prior attempts that built their own jsonschema engines — typebox-rs (~8,400 lines) and the @alkdev/alktype prototype (~5,600 lines) — with jsonschema + an offset map + small custom keyword implementations. See ADR-001.

Why

The crate's purpose is to be a binary struct engine for components that read or write binary data at computed offsets. Instead of per-protocol serde structs (russh-sftp's 29 packet types), per-handler wire format code (TTY's 5-byte format parser), or per-format offset computation (metatensor's tensor access), all of these become instances of the same engine with different schemas.

The guiding insight:

The schema is the format. A JSON Schema with AlkType:Float32, AlkType:Struct, AlkType:Union etc. is both the validation spec and the layout spec. No separate format definition, no separate parser, no separate validator. One schema, three uses: validate, compute offsets, access data.

This is the convergence of three threads identified in the call-channels-unification research: the typedef.ts schema kinds from TypeBox, the russh-sftp protocol packets, and the metatensor format. The common pattern: a JSON Schema describes the shape of binary data, and the binary data is the struct's bytes at computed offsets.

The crate was bumped up in the timeline when the call-channels-unification research surfaced that channels, TTY, and the binary call protocol are all variations on the same wire-format family — [discriminant][length][payload]. The alktype engine makes the "channels is call with a binary data plane" unification concrete: the binary data plane's wire format is the call protocol's own schema system, just binary-encoded. The channel_open marker says "use binary framing"; the alktype engine says "here's how to read/write the binary payload."

The "Schema Is the Format" Principle

A JSON Schema with AlkType:* custom keywords serves three roles simultaneously:

Role Mechanism When
Validation spec jsonschema custom keywords Load time (build validator), access time (validate buffer)
Layout spec Offset computation from type sizes + field order Load time (build offset map)
Data access Read/write at computed offsets Access time (read field, write field)

No separate format definition, no separate parser, no separate validator. The schema is the single source of truth for the binary format. Adding a new field to a protocol is adding a property to the schema JSON — the engine computes the new offsets automatically.

This is the same principle as #[repr(C)] struct field access, but at runtime from a portable JSON Schema instead of at compile-time from language-specific annotations. The schema is the ABI contract.

Dependencies

alktype
├── jsonschema (v0.46.5, Draft 2020-12) — validation engine, custom keyword support
├── serde_json (with preserve_order)     — schema parsing; field order is load-bearing
└── (no tokio, no platform deps)         — WASM-clean by construction

alktype is dependency-light: jsonschema + serde_json only. No tokio, no platform deps. Compiles to wasm32-unknown-unknown for browser use. The jsonschema crate is already in the workspace at @alkdev/alknet: jsonschema/ — alktype is its first consumer.

serde_json requires the preserve_order feature because field order is load-bearing for binary layouts. The order of properties in the schema JSON determines the order of fields in the binary struct.

Consumers

Consumer Schema describes Engine provides
alkcall (v0.1.0 first consumer) channels' ChunkHeader { channel_id: u32 BE, length: u32 BE } + call's OperationSpec.input_schema / output_schema / error_schemas validate_bytes for the 8-byte chunk header; validate_json for call's JSON payloads; builder API for both
russh-sftp 29 packet structs + Packet union (byte discriminator) Read/write SFTP frames from bytes
metatensor Model layout (ConvNet struct, tensor refs) Offset map for mmap'd tensor access
binary call frames call.requested / call.responded / etc. structs Read/write binary call frames
TTY negotiation NegotiateRequest / NegotiateResponse structs Read/write TTY control frames
channels wire ChunkHeader { channel_id, length } 8-byte chunk header (now in scope for alkcall; was "trivial" pre-v0.1.0)

alkcall — the merged alknet-call (call protocol) + alknet-channels (channel multiplexing) extraction from @alkdev/alknet — is the consumer that bumped the builder API (OQ-003) and generalized validation (ADR-010) into v0.1.0. It uses alktype for two distinct schema roles (binary layout + JSON payloads) from one library. See builder.md and validation.md §"validate_bytes".

The russh-sftp case is the most instructive and the highest-value POC target. The Packet enum's TryFrom<&mut Bytes> impl is a hand-written dispatch on a type byte followed by serde deserialization. Under alktype, the dispatch is TUnion with a byte-offset discriminator — the schema says "byte 0 is the discriminator, bytes 1..N are the variant struct." The engine reads the discriminator, looks up the variant schema, computes offsets, reads fields. Same result, no per-packet-type code.

Scope Boundaries (What This Is Not)

These boundaries are decided in ADR-001.

  • Not metatensor. alktype is the binary struct engine. Metatensor is a format (8-byte header + JSON header + binary data) that uses the alktype engine for its offset computation and tensor access.
  • Not a Value system. TypeBox's Value.Diff, Value.Migrate, Value.Convert — schema evolution — is out of scope for v1. The engine should not do anything that explicitly blocks adding a Value system later.
  • Not a code generator. typebox-rs's codegen/ module is a separate concern. The alktype engine consumes schemas; it does not generate them.
  • Schema builder is in scope as of v0.1.0. A fluent Rust API for constructing schemas at runtime, producing serde_json::Value, is shipped in v0.1.0 (ADR-009, resolves OQ-003). The builder covers AlkType kinds and standard JSON Schema; see builder.md. Schemas may still be authored in TypeBox, generated by ujsx components, or hand-written — the builder is an additional construction path, not a replacement.
  • Not a serialization framework. The alktype engine is not a general-purpose serde replacement. It operates on raw byte buffers at computed offsets — no intermediate Value tree, no reflection, no dynamic dispatch per field. For JSON data, use serde. For binary data with a known schema, use alktype.

Architecture (component pointers)

  • schema-layer.md — the 19 AlkType:* kinds, jsonschema custom keyword integration, TypeBox interop, schema annotations (endianness, alignment, encoding, TUnion discriminators).
  • layout-engine.md — offset computation, the two layout modes (packed sequential vs aligned static), alignment, endianness, variable-length field handling.
  • data-access.md — read/write functions, TUnion dispatch, field paths, zero-copy access for fixed-size types, length-prefix reading for variable-length types.
  • validation.md — custom keyword validators for all 19 AlkType:* kinds, AlkTypeError, load-time vs access-time validation, AlkTypeEngine as the compiled form of a schema. validate_json for JSON values; validate_bytes for binary buffers (ADR-010).
  • builder.md — fluent Rust API for constructing alktype JSON Schemas at runtime, producing serde_json::Value. Covers AlkType kinds and standard JSON Schema (ADR-009).

Design Decisions

Decision ADR Summary
Purpose, scope, and the jsonschema engine ADR-001 What the crate is/isn't; why jsonschema not a custom engine; "schema is the format" principle; scope boundaries
Two layout modes ADR-002 Packed sequential (LayoutBuilder/SequentialReader) for protocols; aligned static (OffsetMap) for mmap formats
Schema annotations ADR-003 Endianness (schema-level, default LE), alignment (struct + field-level), encoding (length-prefixed vs offset-indirect), TUnion discriminators (byte-offset vs field-name)
Error handling and validation ADR-004 AlkTypeError enum; load-time build, access-time check; field-path-carrying errors; jsonschema ValidationError wrapping
Int64/Uint64 kinds ADR-005 64-bit integers as first-class kinds (SFTP offsets, metatensor data_offsets)
Non-final inline variable fields ADR-006 Rejected in aligned mode (would clobber subsequent fields)
Packed-mode read factory ADR-007 engine.sequential_reader() returns an owned fresh reader
TUnion in aligned mode ADR-008 Rejected for v1 (broken semantics; no current consumer needs it)
Builder API ADR-009 Fluent Rust API producing serde_json::Value; covers AlkType kinds + standard JSON Schema; resolves OQ-003
Generalized validation — validate_bytes ADR-010 Single-call binary-buffer validation on AlkTypeEngine; materialize Value from bytes, then validate

Open Questions

See open-questions.md for full details.

  • OQ-001 (deferred(scope)): Arrays of variable-length-element structs.
  • OQ-002 (deferred(scope)): no_std + alloc support.
  • OQ-003 (resolved by ADR-009): Builder API for schema construction. Shipped in v0.1.0; see builder.md.

References

  • @alkdev/alknet: docs/research/alknet-typedef/findings.md — POC results (26 tests passing, two layout modes, TUnion dispatch, endianness)
  • @alkdev/alknet: docs/research/call-channels-unification/findings.md §"alknet-typedef: JSON Schema as the binary struct engine" — the origin of this research thread
  • @alkdev/alknet: typebox/example/typedef/typedef.ts — the TypeBox schema kinds (619 lines)
  • @alkdev/alknet: jsonschema/ — the jsonschema crate (v0.46.5, Draft 2020-12)
  • @alkdev/alknet: alknet-typedef-poc/ — the POC code (disposable)
  • @alkdev/alknet: typebox-rs/ — prior attempt, replaced by alktype
  • @alkdev/alknet: alktype-prototype/ — prior attempt (the @alkdev/alktype prototype; not to be confused with this crate, which reuses the name but is backed by the jsonschema crate)

Note

: The research findings, POC code, and prior-attempt paths above refer to the parent @alkdev/alknet workspace where this crate originated. They are preserved here as historical context for the architectural decisions; the artifacts themselves are not part of this standalone repo.