Cyber Stack Adoption Plan
Context
The cyber protocol defines a nine-crate stack. Trident is the language compiler. This plan integrates the canonical cyber crates, adds nox as a new VM target and cyber as a new OS target, and introduces a direct AST→Noun compilation path that bypasses TIR for tree targets.
Nock stays. Nox is an additional tree machine.
The Stack
nebu (field) → hemera (hash) → nox (VM) → zheng (proofs) → bbg (state)
├→ tru
└→ plumb
hemera → mudra (crypto)
hemera → radio (transport)
Maturity
| Crate | Version | Status | Ready? |
|---|---|---|---|
| nebu | 0.1.0 | ~3.3k LOC, field + NTT + extensions + GPU | YES |
| hemera | 0.2.0 | complete, test vectors, unaudited | YES |
| nox | 0.1.0 | spec complete, source skeleton | SPEC ONLY |
| zheng | 0.1.0 | spec complete, placeholder impl | SPEC ONLY |
| bbg | — | spec complete, placeholder impl | SPEC ONLY |
First Principles: Why Trident + nox Are a Natural Pair
Trident and nox share deep structural properties. The synergy is not accidental — both are designed around the same field, the same constraints, and the same computational model.
Shared foundations
| Property | Trident | nox |
|---|---|---|
| Arithmetic | Goldilocks field-native | Goldilocks field-native |
| Execution | Bounded, no recursion | Bounded by focus budget |
| Types | Field, Bool, U32, Digest | field (F_p), word (Z/2^32), hash (4×F_p) |
| Data | Structs = flat field elements | Nouns = binary trees of field elements |
| Control | if/else, for, match | branch (pattern 4) |
| Hash | hemera (content addressing) | hemera (pattern 15) |
| Determinism | Required for proofs | Confluence theorem |
| Proofs | STARK target | Execution trace IS STARK witness |
Why TIR is the wrong path for nox
Current pipeline:
Source (tree) → AST (tree) → TypeCheck → TIR (flat stack) → TreeLowering → Noun (tree)
This is tree → flat → tree. Information destruction followed by reconstruction. Specific losses:
-
Parallelism destroyed.
let a = x + y; let b = w * z— these are independent in the AST. TIR sequentializes them into Push/Dup/Add /Push/Dup/Mul. In nox,cons(add(x,y), mul(w,z))is parallel by confluence. Direct lowering preserves independence. -
Stack artifacts injected. TIR adds Dup/Swap/Pop for stack management. nox has no stack — the subject tree has O(1) axis addressing. Stack ops become useless cons cells in the noun.
-
Types erased. TIR is untyped — all 54 ops operate on anonymous stack slots. nox needs type tags (field=0x00, word=0x01, hash=0x02) for domain separation in hemera hashing. The typed AST has this; TIR throws it away.
-
Spill/reload noise. TIR's StackManager exists because stack machines have finite depth (16 on Triton). nox subject trees can be arbitrarily deep. No spill needed, but TIR generates spill ops that TreeLowering must undo.
-
Memoization shape lost. nox's cybergraph caches results by
H(formula, object). Source-shaped nouns produce sub-trees that match across similar programs → more cache hits. Stack-shaped nouns produce unique trees per stack layout → fewer hits.
The direct path
Source → AST → TypeCheck → NounBuilder → Noun
The typed AST carries everything NounBuilder needs:
- Tree structure (from source)
- Types and widths (from TypeChecker's ModuleExports)
- Variable bindings and scopes (from AST Let nodes)
- Control flow (from AST If/For/Match)
- Monomorphized function instances (from TypeChecker)
What NounBuilder replaces:
- TIRBuilder (AST → TIR) — skip entirely
- TreeLowering (TIR → Noun) — skip entirely
- StackManager — replaced by SubjectManager (tree axes, not stack depth)
Structural correspondence
| Trident source | nox pattern | Direct mapping |
|---|---|---|
let x = expr |
cons (3) | Extend subject: [3 [expr] [rest]] |
x (variable) |
axis (0) | Navigate subject: [0 axis_of_x] |
a + b |
add (5) | [5 [0 axis_a] [0 axis_b]] |
a - b |
sub (6) | [6 [0 axis_a] [0 axis_b]] |
a * b |
mul (7) | [7 [0 axis_a] [0 axis_b]] |
1 / a |
inv (8) | [8 [0 axis_a]] |
a == b |
eq (9) | [9 [0 axis_a] [0 axis_b]] |
a < b |
lt (10) | [10 [0 axis_a] [0 axis_b]] |
a ^ b |
xor (11) | [11 [0 axis_a] [0 axis_b]] |
a & b |
and (12) | [12 [0 axis_a] [0 axis_b]] |
hash(x) |
hash (15) | [15 [0 axis_x]] |
if c { a } else { b } |
branch (4) | [4 [c_noun] [a_noun] [b_noun]] |
f(x) |
compose (2) | [2 [x_subject] [f_formula]] |
42 |
quote (1) | [1 42] |
secret_read() |
hint (16) | [16 [constraint] [formula]] |
(a, b) |
cons (3) | [3 [a_noun] [b_noun]] |
s.field |
axis (0) | [0 axis_of_field] |
Every source construct maps to exactly one nox pattern. No intermediate representation needed.
Gains from direct lowering
| Metric | Through TIR | Direct AST→Noun | Why |
|---|---|---|---|
| Compilation passes | 2 (AST→TIR→Noun) | 1 (AST→Noun) | Skip TIR entirely |
| Noun size | larger | ~20-30% smaller | No Dup/Swap/spill artifacts |
| Parallelism | lost | preserved | cons/compose sub-exprs stay independent |
| Type info | erased | preserved | Domain separation in hemera hashing |
| Memoization | poor cache shape | source-aligned shape | Similar programs share sub-trees |
| Focus prediction | approximate | exact | Pattern costs known at compile time |
| Compiler complexity | 2 modules | 1 module | NounBuilder replaces TIRBuilder + TreeLowering |
| Spill/reload | yes (finite stack) | none | Subject tree has no depth limit |
nox-specific optimizations (tree-native)
These optimizations are impossible through TIR because TIR destroys the tree structure they operate on.
-
Subject sharing. Multiple functions can share subject sub-trees. If
f(a,b)andg(a,c)both needa, the subject tree placesaat a shared axis. Through TIR, each function gets its own stack layout. -
Memoization-aware layout. Place frequently-hashed sub-expressions at known axes so
H(formula, object)cache keys collide across similar programs. The compiler can optimize for cache hits. -
Cons tree compaction. Flatten right-nested cons chains when possible.
[3 [3 a b] c]→[3 a [3 b c]]when semantically equivalent. Shallower trees = cheaper axis lookups. -
Dead axis elimination. If a variable is bound but never accessed by axis, don't cons it into the subject. TIR has dead code elimination but it operates on stack ops, not tree shape.
-
Focus budgeting. Since every pattern has a known cost (add=1, inv=64, hash=200), the compiler can compute exact focus cost of any noun tree at compile time. Report this as
trident cost. -
Parallel marking. Mark cons/compose nodes whose sub-expressions are independent (no shared axis reads). A parallel nox executor can use these marks. TIR destroys this information.
Phase 1: nebu + hemera (NOW — 2.5 sessions)
Both crates are implemented. Mechanical replacement.
1a. Dependencies
# Cargo.toml — add:
nebu = { path = "../nebu/rs" }
hemera = { package = "cyber-hemera", path = "../hemera/rs" }
# Remove: blake3 = "1"
1b. Bridge Goldilocks to nebu
src/field/goldilocks.rs becomes thin wrapper: delegate ops to
nebu::Goldilocks, implement trident's PrimeField trait.
BabyBear and Mersenne31 keep their own implementations.
1c. Replace hashing with hemera
Delete src/field/poseidon2.rs (295 LOC) and
src/package/poseidon2.rs (340 LOC).
ContentHash: [u8; 32] → [u8; 64]. hash_version: 1 → 2.
All call sites (~10 files): poseidon2::hash_bytes() → hemera::hash().
1d. Tests
- All hash test vectors change (new expected values)
- Snapshot tests:
cargo insta review - Benchmark references: rewrite using hemera
- Integration:
trident hashoutputs 128 hex chars - Trisha rebuild + verify (Tip5 on-chain unchanged)
1e. Documentation
6 files: language.md, vm.md, content-addressing.md, src/README.md, CLAUDE.md, README.md.
Estimate
| Task | Pomodoros |
|---|---|
| Cargo.toml + goldilocks bridge | 2 |
| Delete poseidon2 + replace call sites | 2 |
| ContentHash 32→64 ripple (store, manifests, CLI, artifacts) | 3 |
| Fix all tests + update expected values | 3 |
| Update benchmarks/references | 2 |
| Docs (6 files) | 1 |
| Trisha rebuild + verify | 1 |
| Final verification (check, test, bench, grep) | 1 |
| Total | 15 pomodoros = 2.5 sessions |
Phase 2: vm/nox/ target + direct AST→Noun path (NOW — 5 sessions)
This is the central architectural change. Add nox as a new VM target with a direct compilation path that bypasses TIR.
2a. Create vm/nox/ target profile
vm/nox/
target.toml
README.md
[target]
name = "nox"
display_name = "NOX"
architecture = "tree"
output_extension = ".nox"
[field]
prime = "2^64 - 2^32 + 1"
bits = 64
[hash]
function = "Hemera"
digest_width = 8
rate = 8
[cost]
tables = ["focus"]
[status]
level = 0
lowering = "NounLowering"
lowering_path = "noun"
cost_model = true
tests = false
notes = "Direct AST→Noun. Spec-aligned, awaiting nox crate."
2b. Register in target system
src/config/target/mod.rs— add nox to VM registryreference/vm.md— add NOX rowreference/targets.md— add nox entryvm/README.md— add to table
2c. Create NounBuilder (the core work)
New module: src/ir/noun/ — direct AST→Noun lowering for tree targets.
src/ir/noun/
mod.rs # NounBuilder, public API
subject.rs # SubjectManager (variable → axis mapping)
lower.rs # AST node → nox pattern conversion
focus.rs # Focus cost calculation
serialize.rs # Noun → .nox binary format
tests.rs # Unit + property tests
SubjectManager replaces StackManager:
NounBuilder walks typed AST:
Key lowering rules:
build_expr(Literal(v)) → Noun::cell(1, Noun::atom(v)) // quote
build_expr(Var(name)) → Noun::cell(0, axis_of(name)) // axis
build_expr(BinOp(Add,a,b)) → Noun::cell(5, [build(a), build(b)]) // add
build_expr(BinOp(Mul,a,b)) → Noun::cell(7, [build(a), build(b)]) // mul
build_expr(Call(f, args)) → Noun::cell(2, [args_subject, f_formula]) // compose
build_stmt(Let(x, init)) → Noun::cell(3, [build(init), ...]) // cons (extend subject)
build_stmt(If(c, t, e)) → Noun::cell(4, [build(c), build(t), build(e)]) // branch
2d. Nox-specific optimizations
| Optimization | What | Estimated gain |
|---|---|---|
| Dead axis elimination | Don't cons unused variables | 5-15% smaller nouns |
| Subject sharing | Shared sub-trees for common args | 10-20% smaller for multi-fn |
| Cons compaction | Flatten right-nested cons | ~5% smaller nouns |
| Parallel marking | Tag independent sub-exprs | Future: parallel executor |
| Focus precomputation | Exact focus cost at compile time | 100% accurate cost prediction |
2e. Serialization (.nox format)
Binary format for nox nouns. Atoms are 8-byte field elements (not arbitrary-width naturals like Nock .jam). Three sizes: 8 (atom), 32 (hash), 64 (cell = two hemera hashes).
2f. Cost model (focus)
src/cost/nox.rs — focus cost tables
Pattern costs (canonical):
structural (0-4): 1
field arith (5-7, 9): 1
inv (8): 64
lt (10): 1 (exec), ~64 (constraints)
bitwise (11-14): 1 (exec), ~32 (constraints)
hash (15): 200
hint (16): 1 + sub-costs
Focus cost is calculable at compile time from the noun tree.
trident cost --target nox program.tri → exact focus budget.
2g. Pipeline integration
// src/api/mod.rs — add nox path
The existing TIR path stays for stack/register/GPU targets. The noun path is an alternative for tree targets (nox, and potentially Nock in the future if we want better Nock output).
2h. Tests
| Test category | Count | What |
|---|---|---|
| Target loading | 2 | target.toml parses, registers |
| SubjectManager | 8 | bind, lookup, scope push/pop, axis math |
| NounBuilder per-expr | 12 | literal, var, binop (+,-,*,/,==,<), call, field access |
| NounBuilder per-stmt | 8 | let, if/else, for, match, return, assign |
| NounBuilder functions | 4 | single fn, multi fn, generic fn, recursive-like |
| Focus calculation | 6 | each pattern cost, compound expressions |
| Serialization roundtrip | 4 | atom, hash, cell, nested |
| End-to-end | 4 | trident build --target nox on test programs |
| Snapshot | 6 | golden noun output for reference programs |
| Total | ~54 |
2i. Documentation
| File | Change |
|---|---|
vm/nox/README.md |
Full target profile |
vm/README.md |
Add NOX to registry |
reference/vm.md |
Add NOX row with all parameters |
reference/targets.md |
Add nox integration level |
reference/ir.md |
Add noun lowering section (AST→Noun path) |
src/README.md |
Add src/ir/noun/ module description |
CLAUDE.md |
Add noun path to pipeline contract |
Estimate
| Task | Pomodoros |
|---|---|
| vm/nox/ target profile + registration | 2 |
| SubjectManager (variable → axis) | 3 |
| NounBuilder core (expr + stmt lowering) | 6 |
| Function handling (call, multi-fn, generics) | 3 |
| Nox optimizations (dead axis, subject sharing) | 3 |
| Focus cost model | 2 |
| Serialization (.nox format) | 2 |
| Tests (~54 tests) | 5 |
| Pipeline integration (api/mod.rs) | 1 |
| Documentation (7 files) | 2 |
End-to-end: trident build --target nox |
1 |
| Total | 30 pomodoros = 5 sessions |
Phase 3: os/cyber/ target (NOW — 1 session)
New OS target alongside Nockchain, Neptune, etc.
3a. Create OS profile
os/cyber/
target.toml
README.md
types.tri # Particle, Neuron, Cyberlink, Token, Focus
cyberlink.tri # cyberlink creation/validation
[os]
name = "cyber"
display_name = "Cyber"
vm = "nox"
[runtime]
binding_prefix = "os.cyber"
account_model = "cybergraph"
storage_model = "bbg"
transaction_model = "proof-based"
[status]
level = 0
ext_modules = 0
tests = false
notes = "Types from bbg spec. Awaiting runtime."
3b. Types from bbg spec
// os/cyber/types.tri
module os.cyber.types
pub struct Particle {
hash: Digest,
energy: Field,
focus: Field,
}
pub struct Neuron {
focus: Field,
karma: Field,
stake: Field,
}
pub struct Cyberlink {
from: Digest,
to: Digest,
neuron: Digest,
weight: Field,
}
3c. Registration + tests + docs
src/config/target/os.rs— add cyberreference/os.md— add entryos/README.md— add to table- Target loading test, type compilation test, resolved target test
Estimate
| Task | Pomodoros |
|---|---|
| target.toml + README | 1 |
| Type definitions (.tri files) | 2 |
| Register in OS system + tests | 2 |
| Docs (3 files) | 1 |
| Total | 6 pomodoros = 1 session |
Phase 4: Align runtime with zheng API (NOW — 1 session)
4a. Update traits
Provergainsfocus: u64parameterProveResultcarries structuredProofVerifiertakesStatement(program hash + I/O + focus bound)- New:
Foldertrait for recursive composition ProgramBundle.program_digest→ 64 bytes (hemera)- New:
focus_bound: u64field
4b. Tests + docs
- Mock implementations for trait compilation tests
- ProgramBundle serialization roundtrip
- Update runtime/ docs
Estimate
| Task | Pomodoros |
|---|---|
| Update trait signatures | 2 |
| Update ProgramBundle | 1 |
| Mock tests | 2 |
| Docs | 1 |
| Total | 6 pomodoros = 1 session |
Phase 5: Full pipeline (BLOCKED on nox + zheng)
When nox can execute and zheng can prove:
.tri → trident build --target nox → .nox noun
→ nox execute → trace → zheng prove → proof
New warrior binary for cyber target.
Estimate: 4-5 sessions when deps are ready
Total Estimate
| Phase | Status | Pomodoros | Sessions |
|---|---|---|---|
| 1. nebu + hemera | NOW | 15 | 2.5 |
| 2. vm/nox/ + AST→Noun | NOW | 30 | 5 |
| 3. os/cyber/ | NOW | 6 | 1 |
| 4. Runtime/zheng | NOW | 6 | 1 |
| 5. Full pipeline | BLOCKED | 24-30 | 4-5 |
| Total | 81-87 | 13.5-14.5 |
Phases 1-4 (9.5 sessions) can run without waiting for nox/zheng. Phase 5 blocked until cyber stack crates have working code.
Risk
- nebu v0.1.0 API churn — thin wrapper insulates.
- ContentHash 64-byte ripple — biggest Phase 1 change.
- NounBuilder complexity — the SubjectManager (variable→axis) is the hard part. Stack machines have linear layout; tree machines have exponential branching. Axis calculation must be correct.
- nox spec vs implementation — spec says "frozen" but implementation may reveal issues. NounBuilder should be modular.
- Multi-target — TIR stays for 20+ stack/register/GPU targets. Noun path is tree-target only. Two paths = more code, but each is simpler than a forced universal path.
- bbg types draft — os/cyber/ types will iterate.
- Triton VM unaffected — hemera replaces only off-chain content addressing. trisha stays. Tip5 stays on-chain.