Skip to content

Axion: Schema-First Data Contracts

Axion: Schema-First Data Contracts

Version: 1.0.0 Status: Production Last Updated: 2026-01-10


Overview

Axion is a type-safe schema language and code generation system for defining deterministic data structures across multiple languages. It is used across all Orix products (Airlock, Lattice, Flux, Echo, Nexus, Lumen).


The Problem

Schema Drift and Data Chaos

Hand-written data models create multiple sources of truth:

TYPICAL PROJECT TODAY:
┌────────────────────────────────────────────────────────┐
│ Backend: C# classes (hand-written) │
│ Frontend: TypeScript interfaces (hand-written) │
│ Database: SQL schema (hand-written) │
│ API Docs: OpenAPI spec (hand-written) │
│ Validation: Separate validator code (hand-written) │
│ │
│ Result: 5 sources of truth, constant drift │
└────────────────────────────────────────────────────────┘

Consequences:

  • Type mismatches between client and server
  • Serialization bugs from manual coding
  • No single source of truth for data structures
  • Cross-language incompatibilities
  • Breaking changes not caught until runtime

How Axion Solves It

Single Source of Truth

AXION APPROACH:
┌────────────────────────────────────────────────────────┐
│ │
│ schema/user.axion │
│ (SINGLE SOURCE) │
│ │ │
│ ┌───────────┼───────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ C# code TypeScript SQL DDL │
│ interfaces (optional) │
│ │
│ Result: 1 source of truth, zero drift │
└────────────────────────────────────────────────────────┘

Technical Approach

  1. Define once in .axion schema files
  2. Generate code for C#, TypeScript, Python, Rust
  3. Guaranteed type safety across all languages
  4. Binary serialization with schema versioning
  5. Annotations for validation, encryption, indexing

What Axion Provides

1. Schema Language (.axion files)

Human-readable schema definition with:

  • Type declarations (entity, component, enum, config)
  • Field annotations (@key, @indexed, @encrypted, @range)
  • Built-in validation constraints
  • Documentation as first-class citizen

2. Code Generation (Fusion)

Multi-target code generation from single schema:

  • C#: Structs with serialization, equality, Lattice ORM
  • TypeScript: Interfaces with validation, Zod schemas
  • Python: Dataclasses with validation (planned)
  • Rust: Structs with serde (planned)

3. Binary Serialization Format

Deterministic binary encoding with:

  • 90%+ compression vs JSON
  • Schema hash validation
  • Field-level encryption support
  • Varint encoding for compact integers
  • Ordered iteration for determinism

4. Runtime Validation

Schema-driven validation at runtime:

  • Type checking
  • Range constraints (@range(min, max))
  • String patterns (@pattern(regex))
  • Custom validation rules

Schema Language Example

/// =============================================================================
/// Airlock Secrets Schema
/// =============================================================================
///
/// Core data models for the Airlock secrets manager.
/// Defines Secret entity with field-level encryption support.
namespace airlock.secrets
// =============================================================================
// Secret Types
// =============================================================================
/// Classification of secret types
enum SecretType {
GenericSecret = 0,
Password = 1,
ApiKey = 2,
Token = 3,
SshKey = 4,
DatabaseCred = 5,
Certificate = 6,
SecureNote = 7
}
// =============================================================================
// Secret Entity
// =============================================================================
/// A secret stored in the vault.
/// Supports field-level encryption, indexing, and versioning.
entity Secret {
/// Unique identifier
@key
id: uuid,
/// Display name (encrypted, indexed for blind search)
@encrypted(group: "metadata")
@indexed
name: string,
/// Type classification
secretType: SecretType = GenericSecret,
/// The actual secret value (encrypted at rest)
@encrypted(group: "sensitive")
value: string,
/// Tags for organization (encrypted, indexed)
@encrypted(group: "metadata")
@indexed
tags: list<string>,
/// Optional notes (encrypted)
@encrypted(group: "metadata")
notes: string?,
/// Creation timestamp
created_at: timestamp,
/// Last modification timestamp
updated_at: timestamp,
/// Optional expiration timestamp
expires_at: timestamp?
}

Key Features Demonstrated

FeatureExamplePurpose
Triple-slash comments/// A secret stored...Documentation
Type safetyid: uuidExplicit types
Annotations@key, @encryptedMetadata
Default values= GenericSecretSensible defaults
Optional fieldsnotes: string?Nullability
Collectionslist<string>Complex types
EnumsSecretTypeConstrained values

Generated Code Example

Input Schema (Flux Simulation)

namespace flux.simulation
/// Represents a discrete unit of simulation time
entity Tick {
/// Tick number (monotonically increasing)
@key
value: int64,
/// Hash of world state at this tick
state_hash: bytes?,
/// Number of entities active at this tick
entity_count: int32 = 0,
/// Whether this tick has been verified deterministic
verified: bool = false
}

Generated C# Code

// <auto-generated>
// Generated by Forge from flux.simulation
// Do not edit directly.
// </auto-generated>
#nullable enable
using System;
using System.Runtime.InteropServices;
namespace Flux.Generated;
/// <summary>
/// Represents a discrete unit of simulation time
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Tick : IEquatable<Tick>
{
/// <summary>
/// Tick number (monotonically increasing)
/// </summary>
public long Value;
/// <summary>
/// Hash of world state at this tick
/// </summary>
public byte[]? StateHash;
/// <summary>
/// Number of entities active at this tick
/// </summary>
public int EntityCount;
/// <summary>
/// Whether this tick has been verified deterministic
/// </summary>
public bool Verified;
// IEquatable<Tick> implementation
public bool Equals(Tick other) { /* ... */ }
public override bool Equals(object? obj) { /* ... */ }
public override int GetHashCode() { /* ... */ }
// Serialization methods
public void Pack(ref MessagePackWriter writer) { /* ... */ }
public static Tick Unpack(ref MessagePackReader reader) { /* ... */ }
}

What Gets Generated

  • Struct definition with correct layout
  • XML documentation from schema comments
  • IEquatable implementation for value semantics
  • Serialization methods (Pack/Unpack)
  • Default values applied in constructors
  • Validation (if constraints specified)

Axion vs Alternatives

vs Protobuf

FeatureProtobufAxion
Human-readable schemaYesYes
Human-readable dataNo (binary only)Yes (.axiomdata format)
Comments in dataN/AYes
AnnotationsLimitedExtensive (@encrypted, @indexed, etc.)
Native encryptionNoYes (field-level)
Validation rulesLimitedExtensive (@range, @pattern)
Cross-languageYesYes
DeterminismMostlyGuaranteed
Wire format efficiencyExcellentExcellent

Key difference: Protobuf is schema → binary. Axion is schema → human-readable data → binary.

vs JSON Schema

FeatureJSON SchemaAxion
Schema languageJSON (verbose)Axion (concise)
CommentsNoYes
Code generationThird-party toolsBuilt-in (Fusion)
Binary formatNoYes (90%+ compression)
DeterminismNo (key order)Yes (bit-perfect)
EncryptionNoNative
Type safetyValidation onlyCompile-time types

Key difference: JSON Schema validates existing JSON. Axion generates typed code and validates.

vs TypeScript Interfaces

FeatureTypeScriptAxion
Cross-languageNo (TS only)Yes (C#, TS, Rust, etc.)
Runtime validationRequires Zod/io-tsBuilt-in
Binary serializationManualAutomatic
DeterminismNoYes
EncryptionManualDeclarative (@encrypted)
Server-side typesDuplicate in C#Single source

Key difference: TypeScript interfaces are frontend-only. Axion generates for all languages.

vs GraphQL Schema

FeatureGraphQLAxion
PurposeAPI queriesData contracts
Binary formatNoYes
DeterminismNoYes
EncryptionNoNative
Storage formatSeparate concernIntegrated
Time-travel queriesNoVia Chronicle

Key difference: GraphQL defines API shape. Axion defines data contracts + storage + encryption.


Real-World Schema: Lattice Storage

namespace lattice.storage
/// Available storage engine backends
enum StorageEngine {
Lmdb = 0, // Lightning Memory-Mapped Database (default)
Sqlite = 1, // SQLite for compatibility
RocksDb = 2, // RocksDB for high-throughput
Memory = 3 // In-memory for testing
}
/// Transaction isolation levels
enum IsolationLevel {
ReadUncommitted = 0,
ReadCommitted = 1,
RepeatableRead = 2,
Serializable = 3,
Snapshot = 4 // MVCC
}
/// Represents a database transaction
entity Transaction {
/// Unique transaction identifier
@key
id: uuid,
/// Transaction state
state: TransactionState,
/// Isolation level for this transaction
isolation: IsolationLevel = Snapshot,
/// Tick at which transaction started
start_tick: int64,
/// Tick at which transaction committed (if applicable)
commit_tick: int64?,
/// Read set version for MVCC
read_version: int64,
/// Number of operations in this transaction
operation_count: int32 = 0,
/// Whether this is a read-only transaction
read_only: bool = false
}
/// Runtime storage configuration
config StorageConfig {
/// Storage engine to use
engine: StorageEngine = Lmdb,
/// Maximum database size in bytes (0 = unlimited)
max_size_bytes: int64 = 0,
/// Page size in bytes (4096-65536)
page_size: int32 = 4096,
/// Enable memory-mapped I/O
mmap: bool = true,
/// Sync mode for durability
sync_mode: SyncMode = Normal,
/// Enable write-ahead logging
wal_enabled: bool = true
}

Demonstrates

  • Enums for constrained choices
  • Entities for mutable data
  • Config for runtime settings
  • Default values for sensible behavior
  • Optional fields (commit_tick: int64?)
  • Documentation as schema comments

Performance: Binary Format

Size Comparison

Example: User record with 8 fields (id, email, name, age, role, settings, created, updated)

┌──────────────────────┬──────────┬─────────────┐
│ Format │ Size │ vs JSON │
├──────────────────────┼──────────┼─────────────┤
│ JSON (formatted) │ 412 B │ Baseline │
│ JSON (minified) │ 268 B │ -35% │
│ MessagePack │ 180 B │ -56% │
│ Protobuf │ 95 B │ -77% │
│ Axion Binary (.axb) │ 45 B │ -89% │
└──────────────────────┴──────────┴─────────────┘

Why So Compact?

  1. No field names (schema defines order)
  2. Varint encoding (28 = 1 byte, not “28” = 2 bytes)
  3. Enum as ordinal (1 byte, not “Admin” = 5 bytes)
  4. Bool as bit (not “true” = 4 bytes)
  5. Timestamp as tick (8 bytes, not ISO string = 24 bytes)
  6. Schema hash validates structure

Parse Speed

From actual benchmarks:

┌──────────────────────┬──────────────┬───────────┐
│ Operation │ Speed │ vs JSON │
├──────────────────────┼──────────────┼───────────┤
│ Decode (cold) │ 5-20x faster │ 5-20x │
│ Decode (hot, cached) │ ~7μs / 1M │ 100x+ │
│ Encode │ 2-10x faster │ 2-10x │
└──────────────────────┴──────────────┴───────────┘

Annotations Reference

Field Annotations

AnnotationPurposeExample
@keyPrimary keyid: uuid @key
@indexedCreate indexusername: string @indexed
@encrypted(group)Field-level encryptionssn: string @encrypted(group: "pii")
@range(min, max)Numeric constraintage: int32 @range(0, 150)
@pattern(regex)String validationemail: string @pattern("^.*@.*$")
@deprecatedMark for removalold_field: int32 @deprecated
@default(value)Default valuerole: Role @default(User)

Type Annotations

AnnotationPurposeExample
@version(M, m, p)Schema version@version(1, 0, 0)
namespacePackage namespacenamespace flux.simulation

Implementation Notes

  • Multiple annotations allowed per field
  • Annotations generate code (validation, encryption, indexing)
  • Custom annotations via plugin system
  • Domain-specific annotations (gaming, finance, IoT packs)

Advantages

1. Single Source of Truth

Before Axion:

user.cs (C#) ≠ user.ts (TypeScript) ≠ users.sql (Database)
↓ ↓ ↓
Runtime errors Type mismatches Schema drift

With Axion:

user.axion (SINGLE SOURCE)
├→ user.cs (generated)
├→ user.ts (generated)
└→ users.sql (generated, optional)
Result: Guaranteed consistency

2. Type Safety Across Languages

  • Schema defines types once
  • Generated code is strongly typed in target language
  • Compile-time errors instead of runtime bugs
  • Refactoring is safe (rename in schema, regenerate)

3. Automatic Serialization

  • No hand-written serialization code
  • Zero-allocation in hot paths (C#)
  • Deterministic byte output (same input = same bytes)
  • Versioning support built-in

4. Schema Evolution

  • Add optional fields (backward compatible)
  • Deprecate fields (@deprecated)
  • Version tracking (@version)
  • Migration tools (planned)

5. First-Class Documentation

  • Comments in schema become XML docs (C#), JSDoc (TS)
  • Single place to document data structures
  • Always in sync with code

Disadvantages

1. Additional Build Step

  • Requires code generation before compilation
  • Need to regenerate when schema changes
  • Tool dependency (orix CLI)

Mitigation: IDE integration, watch mode, CI/CD automation

2. Learning New Syntax

  • Developers must learn .axion syntax
  • Not as ubiquitous as JSON or Protobuf

Mitigation: Similar to TypeScript/Rust, excellent error messages, LSP support

3. Generated Code Not Always Idiomatic

  • Generated C# may not match hand-written style
  • Limited customization without modifying generator

Mitigation: Plugin system for domain-specific code generation

4. Orix-Specific (Currently)

  • Not industry-standard (yet)
  • Limited third-party tooling
  • Smaller ecosystem than Protobuf

Mitigation: Open-source, extensible, interoperates with JSON/Protobuf


Workflow: Schema-First Development

Step 1: Define Schema

schemas/game/player.axion
namespace game.player
entity Player {
@key
id: uuid,
username: string,
@range(min: 0, max: 100)
health: int32,
position: vec3,
inventory: list<Item>
}

Step 2: Generate Code

Terminal window
# From Orix CLI
orix axion export csharp schemas/game/player.axion -o src/Game/Generated
# Or via build tool integration

Step 3: Use Generated Types

using Game.Generated;
public class PlayerService
{
public Player CreatePlayer(string username, Vector3 position)
{
return new Player
{
Id = EntityAllocator.Allocate(), // NOT Guid.NewGuid()
Username = username,
Health = 100, // Range validation in schema
Position = position,
Inventory = new UnsafeList<Item>()
};
}
}

Step 4: Serialization

// Serialize to binary
var writer = new MessagePackWriter();
player.Pack(ref writer);
byte[] binary = writer.FlushAndGetArray();
// Deserialize from binary
var reader = new MessagePackReader(binary);
var loaded = Player.Unpack(ref reader);
// Guaranteed: loaded.Equals(player) == true

CLI Commands

Terminal window
# Validate schema syntax
orix check schemas
# Generate C# code
orix axion export csharp schemas/user.axion -o src/Generated
# Generate TypeScript code
orix axion export typescript schemas/user.axion -o src/generated
# Generate all schemas in directory
orix axion export csharp schemas/**/*.axion -o src/Generated
# Get schema hash (for version tracking)
orix axion hash schemas/user.axion
# Output: sha256:a1b2c3d4e5f6...

Integration: Lattice ORM

Axion schemas can generate Lattice ORM Active Record methods:

// Enable Lattice code generation
var options = new EmitterOptions
{
GenerateLattice = true // Enables Find, Save, Delete, Where methods
};
// Generated code includes:
public partial struct User : ILatticeEntity
{
// Active Record methods
public static User? Find(Guid id);
public static List<User> Where(Expression<Func<User, bool>> predicate);
public void Save();
public void Delete();
// Query builder
public static UserQuery Query();
}
// Usage
var user = User.Find(userId);
if (user != null)
{
user.Name = "Updated Name";
user.Save(); // Automatically persisted
}
var admins = User.Where(u => u.Role == Role.Admin);

Future: VSCode Extension

Planned features:

  • Syntax highlighting for .axion files
  • IntelliSense (field completion, type suggestions)
  • Real-time validation
  • Go to definition
  • Hover documentation
  • Code actions (generate sample data, fix errors)
  • Integrated code generation

Status: Language Server Protocol (LSP) implementation in progress


Comparison Summary

CriterionJSON SchemaProtobufGraphQLAxion
Schema languageJSON (verbose).protoSDL.axion
Human-readable dataYes (JSON)NoN/AYes (.axiomdata)
Code generationThird-partyBuilt-inThird-partyBuilt-in (Fusion)
Binary formatNoYesNoYes (90%+)
DeterminismNoMostlyNoGuaranteed
EncryptionNoNoNoNative
Cross-languageValidation onlyYesYesYes
Type safetyRuntime onlyCompile-timeRuntimeCompile-time
AnnotationsLimitedLimitedDirectivesExtensive
EcosystemLargeMassiveLargeGrowing

Conclusion

Axion is schema-first data contracts for the Orix platform.

It solves the “schema drift” problem by providing:

  • Single source of truth (.axion files)
  • Multi-language code generation (C#, TypeScript, Rust, Python)
  • Deterministic binary serialization (90%+ compression)
  • Native encryption support (field-level)
  • Built-in validation constraints

When to use Axion:

  • Need type safety across multiple languages
  • Require deterministic serialization
  • Want declarative encryption
  • Building with Lattice/Flux/Nexus
  • Need schema evolution support

When not to use Axion:

  • Simple JSON APIs (use JSON directly)
  • One-off scripts (overhead not worth it)
  • Ecosystem maturity critical (use Protobuf)
  • No code generation in build pipeline

Current status: Production-ready. 13 schemas across Orix products. Performance validated in benchmarks.


Example Schemas in Orix

ProductSchemaPurpose
Airlocksecrets.axionVault secrets with encryption
Latticestorage.axionTransaction and snapshot types
Latticechronicle.axionTime-travel query types
Fluxsimulation.axionTick and entity lifecycle
Nexusnetwork.axionNetwork messages and sync
Echoreplay.axionRecording and playback
Lumenobservability.axionLogging and metrics

Documentation version: 1.0 Last updated: 2026-01-06 Platform: Orix Component: Axion Schema & Code Generation