Version 2.0 — Blackfall Labs
Ternsig is a virtual mainframe.
It does not simulate one. It does not approximate one. It is one — a centralized computational facility that accepts programs, manages persistent state, and provides uniform services to every application connected to it. Programs written in Runes are loaded, parsed, and evaluated against a kernel of typed modules. The mainframe owns the substrate. The mainframe owns the storage. The mainframe owns the execution lifecycle. Consumer applications request services from the mainframe. They do not reimplement them, any more than a payroll program reimplements the operating system.
The kernel is Rust. The programs are .rune files. The division of labor is absolute.
Every Ternsig installation presents the same logical structure to its consumers. The Runes engine and program loader sit at the top. Beneath them, five kernel modules expose verbs to running programs. Below the modules, the host state maintains the living condition of the system — chemical levels, boot phase, metabolic budget, tick count. At the foundation, the storage multiplexer provides centralized, audited persistence across four distinct backends and a write-ahead log.
The consumer application — whether it is a neuromorphic brain, an industrial controller, or something not yet imagined — sits outside the mainframe boundary. It adds its own namespaces, registers its own modules, supplies its own .rune programs, and reads and writes through the mainframe's persistence layer. It never touches the kernel. It never bypasses the multiplexer. It depends on ternsig alone.
┌─────────────────────────────────┐
│ TERNSIG MAINFRAME │
│ │
│ ┌───────────┐ ┌────────────┐ │
│ │ Runes │ │ Program │ │
│ │ Engine │ │ Loader │ │
│ └─────┬─────┘ └──────┬─────┘ │
│ │ │ │
│ ┌─────┴───────────────┴─────┐ │
│ │ Kernel Modules │ │
│ │ chem · lifecycle · math │ │
│ │ regulatory · bank │ │
│ └─────┬─────────────────────┘ │
│ │ │
│ ┌─────┴─────────────────────┐ │
│ │ Host State │ │
│ │ ChemicalState · Budget │ │
│ │ BootPhase · MainframeState│ │
│ └─────┬─────────────────────┘ │
│ │ │
│ ┌─────┴─────────────────────┐ │
│ │ Storage Multiplexer │ │
│ │ Cartridge · Engram · Spool│ │
│ │ Bank Cluster · WAL │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
▲
│
┌──────────────┴──────────────┐
│ Consumer Application │
│ (Astromind, or any other) │
│ │
│ Adds namespaces + modules │
│ Provides .rune programs │
│ Reads/writes via mainframe │
└──────────────────────────────┘
All Runes traits, the parser, the evaluator, and the full persistence layer are re-exported through the ternsig crate. Consumers require no direct dependency on runes-core, runes-parser, runes-eval, cartridge-rs, engram-rs, databank-rs, or dataspool-rs. One dependency. One interface. One mainframe.
Runes is a behavioral scripting language designed for systems that must express what they do in terms a human can read and a machine can enforce. Its syntax descends from Ruby. It bears no relation to JavaScript, Python, or any technology of the web. A Runes program declares its identity, imports the modules it requires, and calls verbs — named operations provided by the mainframe's kernel.
rune "neuromodulator_dynamics" do
version 1
namespace :kernel
end
use :chem
use :math
da = read(:dopamine)
if da > 180 do
inject(:dopamine, negate(shift(da, 3)))
endThe engine enforces namespace isolation with no exceptions and no overrides. A program declaring namespace :kernel may call verbs from modules registered under kernel, and no others. A program declaring namespace :nuclei may call verbs from modules registered under nuclei, and no others. This is not a convention. It is a gate. The engine will not evaluate a verb call that crosses a namespace boundary. The integrity of the system depends on this guarantee, and Ternsig provides it unconditionally.
Five modules ship with the mainframe. Each provides a set of verbs accessible to programs running in its registered namespace. Together, they give the running system access to its chemical substrate, its lifecycle state, its metabolic budget, its arithmetic faculties, and its distributed memory.
The chemical substrate is the system's internal weather. Four neuromodulators — dopamine, serotonin, norepinephrine, and GABA — are maintained as integer levels between 0 and 255. Programs read them, write them, and inject signed deltas into them. The substrate is shared. Every program in the namespace sees the same chemical state. What one program writes, the next program reads.
| Verb | Signature | Effect |
|---|---|---|
read |
(:chemical) -> Integer |
Read level (0-255) |
set |
(:chemical, value) -> Nil |
Write level |
inject |
(:chemical, delta) -> Nil |
Add or subtract from level |
ChemModule provides full read-write access. ChemROModule provides read-only access for namespaces that should observe the substrate but never alter it.
The lifecycle module exposes the system's vital signs. What phase of boot has been reached. What consciousness level is current. How many ticks have elapsed. Whether the system is at rest. And, when the time comes, the authority to request graceful shutdown. These are not suggestions. They are the ground truth of the system's operational state.
| Verb | Signature | Effect |
|---|---|---|
phase_read |
() -> Integer |
Current boot phase |
level_read |
() -> Integer |
Consciousness level |
tick_read |
() -> Integer |
Event counter |
rest_read |
() -> Integer |
Rest state (0 or 1) |
shutdown |
() -> Nil |
Request graceful shutdown |
Every operation costs something. The regulatory module makes this cost explicit. A finite metabolic budget is allocated per cycle. Programs check the remaining budget, charge costs against it, and halt themselves when it is depleted. There is no overdraft. When the budget reads zero, execution stops. This is the system's discipline — it cannot spend what it does not have.
| Verb | Signature | Effect |
|---|---|---|
budget_read |
() -> Integer |
Remaining budget |
budget_charge |
(cost) -> Nil |
Deduct cost from budget |
budget_gate |
() -> Nil |
Halt execution if budget depleted |
Six pure functions for integer arithmetic. They accept integers. They return integers. They access no host state. They produce no side effects. They are safe to register under any namespace in any configuration. Negation, arithmetic right shift, clamping, absolute value, minimum, maximum — the fundamental operations that programs need to reason about quantities without reaching for floating point.
| Verb | Signature | Effect |
|---|---|---|
negate |
(n) -> Integer |
Negation |
shift |
(n, bits) -> Integer |
Arithmetic right shift |
clamp |
(n, min, max) -> Integer |
Clamp to range |
abs |
(n) -> Integer |
Absolute value |
min |
(a, b) -> Integer |
Minimum of two values |
max |
(a, b) -> Integer |
Maximum of two values |
The bank module connects running programs to the mainframe's distributed representational memory — a system of named banks, each holding signal vectors that can be written, retrieved by identity, or queried by pattern similarity. This is not a key-value store. It is a content-addressable memory with thermal lifecycle management and sparse cosine similarity search over ternary signal vectors.
Signal vectors are transported as integer arrays, each element carrying the product of polarity and magnitude (range -255 to +255). The bank module converts these to and from the internal Signal representation automatically.
| Verb | Signature | Effect |
|---|---|---|
bank_read |
(name, id_high, id_low) -> Array |
Load entry by ID, returns signal vector |
bank_write |
(name, vector) -> Array |
Insert signal vector, returns [id_high, id_low] |
bank_query |
(name, query, top_k) -> Array |
Pattern completion by sparse cosine similarity |
Requires MainframeState attached to the host. Without mainframe services, bank verbs are unavailable — the system will report exactly why, and refuse to proceed.
No component in a Ternsig system reads or writes files directly. All persistent state flows through the storage multiplexer — a centralized facility that coordinates four backends and subjects every mutation to a write-ahead log. This is not optional. This is not a convenience layer. It is the only path to persistent storage that the system recognizes.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ CartridgeMux │ │ EngramMux │ │ SpoolMux │
│ (mutable) │ │ (immutable) │ │ (logs) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
└────────────────┬┘ │
┌────┴──────────────────┘
│
┌──────┴──────┐
│ WAL Spool │
└─────────────┘
The StorageHub is the central coordinator. It opens all backends at initialization, manages their lifecycle, and provides a single point of access for every persistence operation in the system. It is owned by MainframeState, which is attached to the host via TernsigHost.mainframe. When the mainframe is present, the full power of centralized persistence is available to every program and every module that needs it.
Ternsig interoperates with five Blackfall Labs file formats. Each format serves one purpose. Each purpose is served by one format. They are not interchangeable, and the system does not treat them as such.
| Format | Extension | Crate | Purpose | Mutability |
|---|---|---|---|---|
| Runes Program | .rune |
runes |
Behavioral programs executed by the engine | Read-only at runtime |
| Cartridge | .cart |
cartridge-rs |
Mutable runtime state — the system's writable workspace | Read-write |
| Engram | .eng |
engram-rs |
Immutable knowledge archives with cryptographic verification | Read-only |
| DataSpool | .spool |
dataspool-rs |
Indexed sequential storage for structured logs and audit trails | Append-only |
| Databank | (in-memory) | databank-rs |
Distributed representational memory with sparse cosine similarity | Read-write |
Runes Programs are the sole unit of behavior in the system. Every dynamic, every regulation, every gate and route — everything the system does — is expressed as a .rune file loaded and evaluated by the engine. The kernel provides the verbs. The programs provide the intent. Neither functions without the other.
Cartridges are the mutable filesystem. When the system boots, it loads from its cartridge. When it shuts down, it saves back to the same cartridge. Configuration, learned state, checkpoint data, and runtime artifacts all reside here. A cartridge is the system's workspace — everything it needs to resume where it left off.
Engrams are sealed knowledge. Constitution, identity priors, vocabulary, foundational structures — these ship as engrams. An engram is versioned, content-addressed, and cryptographically verified on load. Once built, it is never modified. It cannot be modified. The format guarantees it.
DataSpools are the record of what happened. Append-only binary logs with card-indexed random access, organized by region and namespace, rotated daily to keep file sizes bounded. The write-ahead log itself is a spool. When you need to know what the system did and when it did it, the spool has the answer.
Databanks hold the system's representational memory. Signal vectors stored with a thermal lifecycle — HOT entries are actively learning, WARM entries are settling, COOL entries are proven, COLD entries are frozen. Typed edges link entries for associative traversal. Queries return the top-k most similar entries by sparse cosine similarity over ternary signal vectors. This is pattern completion, not search — the system completes partial signals into full representations.
The fundamental data type across all Blackfall systems occupies three bytes and requires no floating-point unit.
Signal: s = p × m × k p ∈ {-1, 0, +1} m ∈ {0..255} k ∈ {1..255}
pub struct Signal {
pub polarity: i8, // -1, 0, or +1
pub magnitude: u8, // 0-255
pub multiplier: u8, // scaling factor (default 1)
}Three values. Three states of polarity. Excitatory, inhibitory, or silent. Every signal in the system — every synaptic transmission, every chemical reading, every bank entry element — is one of these. The arithmetic is integer add and subtract. The hardware requirement is a CPU. There is no GPU dependency. There is no floating-point dependency. The system computes on what every machine already has.
Ternsig ships a pure-integer adaptive learning algorithm. It does not descend from gradient descent. There is no loss function. There is no backpropagation. There is no optimizer. Learning proceeds by accumulation of evidence, gated by neuromodulatory state, constrained by thermal lifecycle.
- Peak-relative gating — Only activations exceeding one quarter of the peak magnitude participate in updates. Weak signals do not corrupt strong patterns.
- Sustained pressure — A single observation changes nothing. Pressure must accumulate in dedicated registers before the system commits to a structural change. Transient noise is filtered by design.
- Weaken before flip — When evidence demands a polarity reversal, magnitude depletes to zero first. The signal passes through silence before it changes sign. There are no discontinuous jumps.
- Dopamine gating — Learning requires neuromodulator support above threshold. Without dopamine, the system observes but does not adapt. Chemistry gates plasticity.
- Temperature lifecycle — HOT entries learn freely. WARM entries learn cautiously. COOL entries are proven and resist change. COLD entries are frozen. Knowledge crystallizes through use.
[dependencies]
ternsig = { git = "https://github.com/blackfall-labs/ternsig" }One line. The entire mainframe — engine, modules, persistence, learning — is available.
use ternsig::{Engine, Evaluator, ProgramLoader, TernsigHost};
use ternsig::{ChemModule, LifecycleModule, RegulatoryModule, MathModule};
let engine = Engine::builder()
.namespace("kernel")
.module(LifecycleModule::new())
.module(RegulatoryModule::new())
.module(ChemModule::new())
.module(MathModule::new())
.build()?;
let mut loader = ProgramLoader::new();
loader.load_dir("firmware/".as_ref())?;
let mut evaluator = Evaluator::new();
evaluator.set_host(TernsigHost::new());
for program in loader.programs() {
evaluator.eval_with_engine(&program.ast, &engine)?;
}The engine is built by declaring namespaces and registering modules under them. The loader discovers and parses .rune files from the filesystem. The evaluator executes parsed programs against the engine's module registry. Each component does one thing. Together, they are the mainframe.
use std::path::Path;
use ternsig::{MainframeState, TernsigHost};
let mainframe = MainframeState::open(
Path::new("data/cartridges/system.cart"),
Path::new("data/"),
)?;
let host = TernsigHost::with_mainframe(mainframe);With mainframe services attached, the full persistence layer comes online. Cartridges open for read-write access. Engrams load and verify. Spools begin accepting log entries. The write-ahead log audits every mutation. Bank verbs become operational. The system transitions from a program evaluator to a fully serviced mainframe.
The mainframe is designed to be extended. Consumers define their own modules using traits re-exported from ternsig, register them under their own namespaces, and the engine enforces isolation between them and the kernel automatically.
use ternsig::{Module, Verb, Value, EvalContext, VerbResult, ModuleVersion};
struct CascadeModule {
verbs: Vec<Box<dyn Verb>>,
}
impl Module for CascadeModule {
fn name(&self) -> &str { "cascade" }
fn version(&self) -> ModuleVersion { ModuleVersion::new(1, 0, 0) }
fn verbs(&self) -> &[Box<dyn Verb>] { &self.verbs }
}Register consumer modules alongside kernel modules. Each namespace is its own world:
let engine = Engine::builder()
.namespace("kernel")
.module(ternsig::ChemModule::new())
.module(ternsig::MathModule::new())
.module(ternsig::BankModule::new())
.namespace("nuclei")
.module(CascadeModule::new())
.module(ternsig::ChemROModule::new())
.module(ternsig::MathModule::new())
.build()?;The kernel sees its modules. The nuclei see theirs. Neither crosses the boundary. The mainframe guarantees it.
ternsig/
├── src/
│ ├── lib.rs # Crate root, Runes re-exports
│ ├── host.rs # TernsigHost, HasTernsigHost, MetabolicBudget, BootPhase
│ ├── mainframe.rs # MainframeState — persistence + bank cluster container
│ ├── loader.rs # .rune file discovery and parsing
│ ├── ternary.rs # Signal type (re-exports ternary-signal)
│ ├── learning.rs # Mastery learning algorithm
│ ├── logging.rs # Dataspool-backed per-namespace structured logging
│ ├── modules/
│ │ ├── mod.rs # Module index
│ │ ├── math.rs # :math — pure integer arithmetic
│ │ ├── chem.rs # :chem — neuromodulator state
│ │ ├── lifecycle.rs # :lifecycle — boot/phase/shutdown
│ │ ├── regulatory.rs # :regulatory — metabolic budget
│ │ └── bank.rs # :bank — distributed representational memory
│ ├── multiplex/
│ │ ├── mod.rs # StorageHub — central persistence coordinator
│ │ ├── error.rs # MultiplexError
│ │ ├── cartridge.rs # CartridgeMux — mutable state (.cart)
│ │ ├── engram.rs # EngramMux — immutable archives (.eng)
│ │ ├── spool.rs # SpoolMux — structured logging (.spool)
│ │ └── wal.rs # WalSpooler — write-ahead log audit trail
│ └── snn/ # Spiking neural network substrate
├── ternsig-core/ # Shared types (ChemicalState, Tier, SignalTemperature)
├── examples/ # Example .rune programs
├── tests/
│ └── integration.rs # Full pipeline integration tests
└── Cargo.toml
MIT OR Apache-2.0
Blackfall Labs — Neuromorphic systems. Not machine learning.