# Antheos Protocol **Version 1.0 — Level 1 Specification** © Are Bjørby February 2026 --- # 1. Introduction Antheos (Ant) is an anonymous, lightweight, decentralized communication protocol with a wrap-and-tunnel philosophy and a bus abstraction that utilizes existing hardware and software. It is designed to operate on any transport — from a UART serial line to a TCP socket, from a LoRa radio to a human carrying a USB drive. This document defines the Level 1 specification: the complete, self-contained procedural protocol covering transport (bus operations), service discovery, and session management. Level 1 is the universal baseline. Every verb does exactly one thing. It runs on all devices from MCU to server cluster. Antheos is designed to support capability tiers beyond Level 1. Higher levels are defined in separate specifications and are fully optional. A Level 1 implementation is complete and conformant without knowledge of any higher level. ## 1.1 Design Context: Object-Oriented Hardware — the O³ Vision *(This section is non-normative. It records the design intent behind the protocol; a conformant implementation depends only on the normative sections that follow.)* Antheos exists to let independent devices exchange services without a central operating system. The motivating observation is that a computer is already a collection of devices sharing a chassis — processor, memory, storage, network, sensors — and that as each device acquires its own compute, the operating system's historical role narrows. A traditional operating system answers a scarcity question: one expensive processor multiplexed across many tasks by a privileged arbiter. When every device is itself a processor, the machine is better understood as a small network of peers, and what those peers need is not a kernel but a shared *communication law*. Antheos is that law. This is why Design Principle 1 (Section 2) admits only devices and buses — no controller, no central authority. The same protocol spans scales because the model is uniform at every scale: a logical device inside one chassis, a physical device on a shared bus, and a remote service across a network are addressed, discovered, and (optionally) authenticated identically. This cross-scale uniformity — one object model holding from an on-die component out to a remote service — is what this design names **O³ (Object-Oriented Omni-scale)**: *object-oriented* in the messaging sense (peers communicate; no shared mutable state) and *omni-scale* because the single law holds at every distance. Only the transport changes with distance — shared memory within a machine, a socket across a network, a radio between devices — while the law above it does not. The identity model (Section 5) anticipates this: a device's DID and IID are *hardwired* — carried by the device, not assigned by the network — which is the shape fully object-oriented hardware takes natively. On conventional hardware, where the processor and memory are still physically shared, this model is realized by a thin layer beneath Antheos that presents the shared resources as logical devices speaking the protocol. Such a layer need not interpose on every operation: a peer negotiates access to a resource once over Antheos (the control path), then uses the granted resource directly at hardware speed (the data path). The protocol is the control plane; raw access is the data plane. This separation is the same one found in capability-export kernels and in production paravirtualized device interfaces. Reduced to essentials, the authority such a layer must hold is small: the power to **grant** access to a shared resource, and the power to **reclaim** it from a peer that does not yield. Everything else — isolation enforcement, stable identity, the bus itself — is either delegated to the participating devices or carried by the fabric they share. Grant and reclaim are physical-layer concerns; they do not reintroduce a central authority over *meaning*, which is what Principle 1 forbids. As hardware becomes natively object-oriented, even these responsibilities migrate from software into the interconnect — and the operating system, in the form Antheos assumes away, is gone. --- # 2. Design Principles - **Simplicity**: Only devices and buses exist. No routers, no controllers, no central authority. - **Decentralization**: All instances are peers. Identity is established through registries; communication is peer-to-peer. - **Universality**: CP437 encoding ensures every message is displayable on any terminal, printer, or display manufactured since 1981. - **Scalability**: The same protocol frames flow from server clusters to 8-bit microcontrollers. Constrained devices handle what they can and drop what they cannot. - **Wrap and Tunnel**: Antheos wraps its messages and tunnels through any transport that can carry bytes. The bus abstraction is agnostic to the physical or virtual medium. - **Query, Don't Advertise**: Instances discover capabilities by querying, not by advertising. No upfront capability handshakes. No schema exchanges. --- # 3. Terms and Definitions | **Term** | **Definition** | | :--------- | :----------------------------------------------------------------- | | Text | CP437 characters excluding reserved control characters | | Blob | Binary data (arbitrary bytes) | | Instance | Device, software, or HID endpoint communicating on a network | | Network | Instances connected to one or more buses | | Bus | Device, software, system, or person facilitating instance communication | | Message | A head of words followed by an optional binary tail | | Head | The CP437 portion of a message, containing words | | Word | A typed, delimited unit within the head | | Tail | Optional binary data following the head | | Flag | A qualifier within a word (radix or unit) | | Body | The content portion of a word | | Session | A separate group of related messages between instances | | Service | A session offered by an instance to accomplish a specific task | | Origin | Source, creator, or owner of instances | | Id | A text or number used to identify objects | | Registry | An entity maintaining a list of identifiers | --- # 4. Protocol Encoding Antheos uses CP437 (Code Page 437), the character encoding developed by IBM for the original PC in 1981. CP437 is a single-byte encoding defining 256 characters. The first 128 (0x00–0x7F) align with ASCII. The upper 128 (0x80–0xFF) include accented letters, Greek symbols, and box-drawing characters. Antheos leverages CP437's universal hardware and software support. Every message is human-readable on any device that can display CP437 — which includes virtually all computing hardware ever manufactured. The protocol reserves 7 bytes from the CP437 control character range (0x00–0x1F) as structural delimiters. ## 4.1 Reserved Control Characters All reserved bytes were selected to avoid collisions with ASCII flow control (XON 0x11, XOFF 0x13), terminal escapes (ESC 0x1B), whitespace (TAB 0x09, LF 0x0A, CR 0x0D), and null terminators (0x00). This ensures Antheos frames pass transparently through serial links with software flow control, terminal emulators, and C string handling. | **Hex** | **Abbr** | **CP437 Glyph** | **Role** | | :------ | :------- | :-------------- | :----------------------- | | 0x02 | SOM | ☻ | Start of Message | | 0x03 | EOM | ♥ | End of Message | | 0x04 | SOR | ♦ | Start of Radix qualifier | | 0x07 | SOU | • | Start of Unit qualifier | | 0x10 | EOW | ► | End of Word | | 0x12 | SOW | ↕ | Start of Word | | 0x1A | SOB | → | Start of Body | These 7 bytes are forbidden in word bodies and text content. Their presence in the byte stream always indicates protocol structure, enabling stream parsing without buffering entire messages. --- # 5. Identifier Types Antheos uses a layered identity model. Each identifier type has a defined scope, format, and lifetime. The layers build from organizational identity (OID) down to per-message sequencing (MID). | **Id** | **Name** | **Scope** | **Format** | **Lifetime** | | :----- | :-------- | :--------- | :--------- | :---------------------------------------- | | OID | Origin | Registry | ASCII | Registry-defined | | DID | Device | Origin | ASCII | Origin-defined (hardwired type identifier)| | IID | Instance | Origin | ASCII | Origin-defined (hardwired serial) | | BID | Bus | Bus | Base-32 | Ephemeral (established at bus connection) | | SID | Session | Instance | Base-32 | Session duration (fresh per session) | | MID | Message | Session | Decimal | Message duration (sequential counter) | ## 5.1 OID (Origin Identifier) The OID identifies the origin — the organization, individual, or entity that created and owns instances. OIDs are maintained by registries. An OID is a plaintext ASCII string. Carried in an ID word without radix flag. ## 5.2 DID (Device Identifier) The DID identifies the device type within an origin's namespace. It is a hardwired, human-readable ASCII string (e.g., "Thermostat", "SensorV2"). Defined by the origin, not the network. Carried in an ID word without radix flag. ## 5.3 IID (Instance Identifier) The IID identifies a specific instance of a device type. It is a hardwired unique serial (e.g., "SN00482"). Together, OID:DID:IID uniquely identifies any physical or virtual instance in the world. Carried in an ID word without radix flag. ## 5.4 BID (Bus Identifier) The BID is a base-32 address negotiated at bus connection through the Establish/Conflict protocol (see Section 9.1). BIDs are ephemeral and local to a single bus. They are kept as short as possible, growing only on collision. A device connected to multiple buses holds a separate BID on each. Carried in an ID word with radix flag U (duotrigesimal). ## 5.5 SID (Session Identifier) The SID identifies a session between instances. It is a base-32 hash of OID:DID:IID:\. Every new session receives a fresh SID — SIDs are never reused. A monotonic counter ensures each SID is unique; the counter resets on device reboot. Carried in an ID word with radix flag U (duotrigesimal). ## 5.6 MID (Message Identifier) The MID is a decimal counter that increments sequentially within a session, starting at 1. MID=0 is the wrap signal (see Section 11.1.2). Carried in an ID word with radix flag D (decimal). ## 5.7 Identifier Encoding Summary All identifiers are carried in ID words (@). The ID word optionally includes a radix flag to specify the encoding of numeric identifiers. Unit flags are never used with ID words. | **Identifier** | **Radix** | **Wire Example** | | :------------- | :----------- | :---------------- | | OID | (none) | ↕@→example► | | DID | (none) | ↕@→Thermostat► | | IID | (none) | ↕@→SN00482► | | BID | U (base-32) | ↕@♦U→4T9X2► | | SID | U (base-32) | ↕@♦U→A7K2M► | | MID | D (decimal) | ↕@♦D→1► | **BID/SID Disambiguation:** Both BID and SID use base-32 encoding with radix flag U. The verb scope determines which identifier type is expected: - **Bus-scope verbs** (E, C, B, P, R, D, V, S, W, X): base-32 IDs are BIDs - **Service-scope verbs** (Q, O, A): base-32 IDs are BIDs (addressing the offering instance) - **Session-scope verbs** (K, T, N, L, U, F): the first base-32 ID is SID; a second base-32 ID, if present, is a BID A receiver determines identifier type by the verb in the SYMBOL word, not by inspecting the identifier value itself. --- # 6. Word Encoding A word is the fundamental data unit within an Antheos message head. Each word is delimited by SOW (0x12) and EOW (0x10), with typed content between them. ## 6.1 Word Structure The general word structure is: ``` [SOW] [WT] ([SOR][RF]) ([SOU][UF]) [SOB] Body [EOW] ``` **WT** (Word Type) is always the first byte after SOW. **SOR/RF** (Radix Flag) and **SOU/UF** (Unit Flag) are conditionally present depending on the word type. **SOB** marks the start of the body content. **EOW** terminates the word. Flag requirements vary by word type: | **Category** | **Radix (SOR/RF)** | **Unit (SOU/UF)** | **Word Types** | | :----------------------------- | :----------------- | :---------------- | :----------------------------------------------- | | Radix + Unit required | Required | Required | INTEGER (#), REAL ($), SCIENTIFIC (%), BLOB (\*) | | Radix optional, Unit forbidden | Optional | Forbidden | ID (@) | | Both forbidden | Forbidden | Forbidden | SYMBOL (!), PATH (/), TEXT ("), LOGICAL (?), TIMESTAMP (&), DURATION (+), MESSAGE (~) | ## 6.2 Word Types | **CP437** | **Hex** | **Type** | **Description** | **Flags** | | :-------- | :------ | :---------- | :-------------------------------------------------- | :-------------- | | ! | 0x21 | SYMBOL | Protocol verbs and markers | None | | @ | 0x40 | ID | Identifiers (OID, DID, IID, BID, SID, MID) | Radix optional | | / | 0x2F | PATH | Routing sequences | None | | " | 0x22 | TEXT | Plain text content | None | | # | 0x23 | INTEGER | Integer values | Radix + Unit | | $ | 0x24 | REAL | Floating-point values | Radix + Unit | | % | 0x25 | SCIENTIFIC | Exponential notation | Radix + Unit | | ? | 0x3F | LOGICAL | Boolean expression per §6.2.1 — flag-char atoms + `!`/`&`/`|`/parens | None | | & | 0x26 | TIMESTAMP | ISO 8601 instant per §6.2.2 — canonical microsecond UTC | None | | + | 0x2B | DURATION | ISO 8601 duration per §6.2.3 — canonical microsecond | None | | \* | 0x2A | BLOB | Tail size declaration (unit = size field width) | Radix + Unit | | ~ | 0x7E | MESSAGE | Embedded message reference | None | ## 6.2.1 LOGICAL Body Grammar A LOGICAL word (`?`, 0x3F) carries a boolean expression over a closed set of single-character atoms. The V1 grammar is intentionally compact — atoms are drawn from the existing radix-flag and unit-flag character sets so a Scaleback expression like `!H&!Q` parses with no extra symbol table. ### V1 Grammar (EBNF) ```ebnf LOGICAL-body := disjunction disjunction := conjunction ( "|" conjunction )* conjunction := negation ( "&" negation )* negation := "!" negation | primary primary := atom | "(" disjunction ")" atom := "I" | "O" | "D" | "H" | "U" (* radix-flag chars, §6.3 *) | "B" | "W" | "Q" | "M" | "G" | "T" (* unit-flag chars, §6.4; D is shared with radix above *) ``` The grammar encodes operator precedence by nesting depth: `!` (NOT) binds tighter than `&` (AND), which binds tighter than `|` (OR). Both binary operators are left-associative — `A&B&C` parses as `(A&B)&C`. Parens override precedence. ### V1 Atom Set Eleven distinct CP437 characters: `I`, `O`, `D`, `H`, `U`, `B`, `W`, `Q`, `M`, `G`, `T`. The `D` character is shared between the radix-flag set (decimal) and the unit-flag set (doubleword) — a LOGICAL atom `D` refers to whichever flag semantic the consumer expects in context. Atom semantics are consumer-defined, not grammar-defined; the grammar only constrains the alphabet. Characters NOT in the V1 atom set: any CP437 character outside the 11-char alphabet above. Notably `F` is not an atom in V1 (there is no F-flag in §6.3 or §6.4). Consumers needing additional atom characters or multi-character identifiers must wait for V2. ### V1 Examples | **Body** | **Reading** (Scaleback semantic) | | :--------- | :------------------------------------------------------------ | | `!H&!Q` | NOT hex AND NOT quadword (current Scaleback example, §6.5) | | `!Q&!T` | NOT quadword AND NOT terabyte (current Scaleback example) | | `!H|!U` | NOT hex OR NOT base-32 (V1 admits OR via grammar) | | `!(H&Q)` | NOT (hex AND quadword) — De Morgan equivalent of `!H|!Q` | | `T` | the T atom alone (Scaleback: "I can't handle terabyte" only meaningful in negation; standalone T is a no-op tautology in pure-Scaleback reading) | The atom semantics shown reflect Scaleback's flag-exclusion use. Other consumers (e.g. a downstream logical value-class consumer) may impose different atom semantics over the same grammar (e.g., singleton-body shape with consumer-defined literal-true/false interpretation). ### V1 Rejected Inputs | **Input** | **Error** | | :-------------- | :------------------------------------------------------- | | Empty body | reject with teaching error | | `F`, `Z`, etc. | reject — character not in V1 atom set | | `Hello` | reject — multi-character atoms not in V1 | | `H^Q` | reject — `^` (XOR) not in V1 operator set | | `(H` | reject — unmatched paren | | `H&` | reject — operator without right operand | | `H Q` | reject — whitespace not in V1 grammar | ### V2 Extension Hooks Reserved for future versions, deliberately constrained at V1: - **Multi-character atom identifiers** — for consumers needing richer atom namespaces; would require a delimiter convention to disambiguate `HQ` from `H` `Q`. - **Additional operators** — XOR (`^`), IMPLIES (`>`), IFF (`=`), etc. Reserved characters chosen here would not be V1-grammar-valid (currently rejected) so V2 adoption is forward-compatible. - **Whitespace tolerance** — V1 is strict (no spaces); V2 may admit whitespace between tokens for human readability. - **Reserved literal atoms** — V1 does not reserve any atoms for literal true/false semantics; the operator-defined atom approach leaves the literal-vs-flag distinction to consumers. V2 may introduce a reserved literal convention if a consumer surfaces requiring grammar-layer literal semantics. - **Quoted-string atoms** — for embedding human-readable identifiers, deferred to V2 with a quoting convention to avoid ambiguity with the operator characters. ## 6.2.2 TIMESTAMP Canonical Form A TIMESTAMP word (`&`, 0x26) carries an ISO 8601 instant. Parsers accept a documented set of input forms and canonicalize on parse; emitters produce exactly one canonical form per stored instant. The discipline is *parse loose, store canonical, emit canonical* — two conformant implementations produce byte-identical TIMESTAMP words for the same instant. ### Canonical Emit Form ``` YYYY-MM-DDTHH:MM:SS.uuuuuuZ ``` - 27 bytes exactly. - 4-digit year (0000–9999), zero-padded. - UTC only — the zone field is the literal `Z`. - Microsecond precision (6 fractional digits after the seconds decimal), zero-padded. Example: `2026-02-08T12:00:00.000000Z` ### Accepted Input Forms | **Input shape** | **Action** | | :------------------------------------------- | :----------------------------------------------- | | `YYYY-MM-DDTHH:MM:SS` | pad fractional seconds to `.000000` | | `YYYY-MM-DDTHH:MM:SS.fff` | pad fractional seconds to 6 digits | | `YYYY-MM-DDTHH:MM:SS.ffffff` | accept as-is (already canonical precision) | | `YYYY-MM-DDTHH:MM:SS.fffffffff` | truncate sub-μs digits (NOT round) | | Trailing `Z` (UTC) | accept as-is | | Trailing `±HH:MM` (offset) | convert to UTC, emit `Z` | Sub-microsecond truncation is mandatory and NOT rounding — rounding admits multiple valid implementations; truncation has one. ### Rejected Input Forms | **Input shape** | **Error** | | :------------------------------------------- | :----------------------------------------------- | | Named time zone (`America/New_York`, `UTC`) | reject with teaching error | | Extended year (`±YYYYYY-MM-DD…`) | reject with teaching error | | Leap second (`23:59:60`) | reject with teaching error | | Empty body | reject with teaching error | ### V2 Extension Hooks Reserved for future versions, deliberately constrained at V1: - **Named time zones** — for "the meeting is at 3pm in America/New_York" use cases where the named zone preserves information across DST transitions that a fixed offset loses. - **Extended year range** — for historical / geological / archaeological consumers requiring pre-year-0 or post-year-9999 dates (ISO 8601 `±YYYYYY-MM-DD…`). - **Leap-second handling** — for precise-time consumers requiring the `23:59:60` representation. - **Alternative time scales** — TAI, TT, TDB for consumers requiring time scales other than UTC. - **Uncertainty notation** — EDTF-style annotations on uncertain instants. ## 6.2.3 DURATION Canonical Form A DURATION word (`+`, 0x2B) carries an ISO 8601 duration — a typed time *interval*, complementary to TIMESTAMP's *instant*. Same parse-loose-canonicalize-emit-strict discipline as TIMESTAMP: two conformant implementations produce byte-identical DURATION words for the same duration. ### Body Shape ISO 8601 duration form: ``` [-]P[nY][nM][nD][T[nH][nM][nS]] ``` Where `P` is the literal letter (PERIOD), `T` is the literal letter (TIME-separator, required if any time component is present), and `n` is an unsigned integer (calendar components) or unsigned decimal (seconds component only). A leading `-` denotes negative direction. Alternative weeks form: ``` [-]PnW ``` Mutually exclusive with calendar-component bodies — a single body MAY NOT mix `nW` with `nY` / `nM` / `nD` components. Implementations reject mixed forms (`P2W3D`) with a teaching error. Examples: - `P3Y6M4DT12H30M5S` — 3 years 6 months 4 days 12 hours 30 minutes 5 seconds - `PT1H30M` — 1 hour 30 minutes (no calendar components; `T` separator still required) - `P2W` — 2 weeks (alternative form) - `-P3D` — negative 3 days ("3 days ago") - `PT0.123456S` — 0.123456 seconds (microsecond sub-second precision) ### Canonical Emit Form The canonical body is the minimal-component form: components with zero magnitude are omitted, calendar components precede `T`, time components follow `T`, and seconds carry up to 6 fractional digits (omitted entirely if integer seconds; zero-padded to 6 digits only if any fractional precision is present). Special cases: - Any zero-duration input form canonicalizes to `PT0S`. - A weeks-form input emits as `PnW` and is NOT converted to days — the canonical form preserves the input's component shape. - A negative duration preserves its leading `-`. ### Accepted Input Forms | **Input shape** | **Action** | | :------------------------------------------- | :--------------------------------------------------------- | | `P0D`, `P0Y`, `PT0S` | canonicalize to `PT0S` | | Zero components mixed with non-zero (`P3Y0M4D`) | drop zero components → `P3Y4D` | | Integer seconds (`PT5S`) | emit without decimal point | | Fractional seconds < μs (`PT0.123S`) | pad to canonical precision → `PT0.123000S` | | Fractional seconds > μs (`PT0.123456789S`) | truncate sub-μs digits → `PT0.123456S` | | Leading `-` (`-P3D`) | preserve negative direction | | Weeks form (`P2W`) | preserve weeks form; do NOT convert to days | ### Rejected Input Forms | **Input shape** | **Error** | | :------------------------------------------- | :--------------------------------------------------------- | | Empty body (`P` alone, `-P`) | reject with teaching error | | Mixed weeks + calendar (`P2W3D`) | reject with teaching error per mutual-exclusivity rule | | Components without `P` prefix (`3Y6M`) | reject — `P` prefix mandatory | | Time components without `T` (`P12H30M`) | reject — `T` separator mandatory before HMS components | ### Semantics — Out of Scope Arithmetic and comparison semantics over DURATION (`TIMESTAMP + DURATION = TIMESTAMP`, `DURATION + DURATION = DURATION`, ordering, calendar-relative vs fixed-second interpretation of the `Y`/`M`/`D`/`W` components) are out of scope for Antheos. Antheos defines only the byte sequence and its parse/emit canonical form. The consuming reasoner is responsible for defining how DURATION values combine — a consuming reasoner defines its own arithmetic semantics over the DURATION word type in its own specification. ### V2 Extension Hooks Reserved for future versions, deliberately constrained at V1 (wire-format extensions only — semantics remain consumer-defined per the section above): - **Sub-microsecond precision** — nanosecond / picosecond fractional digits. - **Explicit positive sign** (`+P3D`) — currently the unsigned form means positive direction; a future spec may admit explicit `+` in the byte sequence. - **Repeat notation** — ISO 8601 `R[n]//` repeating-interval form (currently outside DURATION word scope; would compose with TIMESTAMP separately at the wire-format level). ## 6.3 Radix Flags Specifies the base encoding of a numeric body. Follows the SOR (0x04) delimiter. | **Flag** | **Name** | **Base** | | :------- | :-------------- | :------- | | I | Binary | Base 2 | | O | Octal | Base 8 | | D | Decimal | Base 10 | | H | Hexadecimal | Base 16 | | U | Duotrigesimal | Base 32 | ## 6.4 Unit Flags Specifies the data width of a numeric value. Follows the SOU (0x07) delimiter. Required for INTEGER, REAL, SCIENTIFIC, and BLOB word types. Forbidden for all other types including ID. | **Flag** | **Name** | **Size** | | :------- | :--------- | :--------- | | B | Byte | 8 bits | | W | Word | 16 bits | | D | Doubleword | 32 bits | | Q | Quadword | 64 bits | | M | Megabyte | 2²⁰ bytes | | G | Gigabyte | 2³⁰ bytes | | T | Terabyte | 2⁴⁰ bytes | ## 6.5 Word Encoding Examples Each example shows the pseudo form (using abbreviations) and the wire form (using CP437 glyphs). In wire form: ↕=SOW, ♦=SOR, •=SOU, →=SOB, ►=EOW. **SYMBOL word** (verb "Establish"): ``` Pseudo: [SOW] ! [SOB] E [EOW] Wire: ↕!→E► ``` *No flags. Body is a single character.* **ID word** (ASCII, no radix — OID): ``` Pseudo: [SOW] @ [SOB] example [EOW] Wire: ↕@→example► ``` *Plain ASCII identifier. No radix or unit flags.* **ID word** (base-32 radix — BID): ``` Pseudo: [SOW] @ [SOR]U [SOB] 4T9X2 [EOW] Wire: ↕@♦U→4T9X2► ``` *Radix flag U (duotrigesimal). No unit flag.* **ID word** (decimal radix — MID): ``` Pseudo: [SOW] @ [SOR]D [SOB] 1 [EOW] Wire: ↕@♦D→1► ``` *Radix flag D (decimal). No unit flag.* **TEXT word**: ``` Pseudo: [SOW] " [SOB] temperature [EOW] Wire: ↕"→temperature► ``` *No flags. Body is plain text.* **PATH word** (dot-separated BID sequence): ``` Pseudo: [SOW] / [SOB] AA.BB.CC.DD [EOW] Wire: ↕/→AA.BB.CC.DD► ``` *No flags. Body is a dot-separated sequence of BIDs forming a route.* **INTEGER word** (decimal, byte-width, value 32): ``` Pseudo: [SOW] # [SOR]D [SOU]B [SOB] 32 [EOW] Wire: ↕#♦D•B→32► ``` *Radix D (decimal), Unit B (byte). Both required.* **INTEGER word** (hex, doubleword, value FF00): ``` Pseudo: [SOW] # [SOR]H [SOU]D [SOB] FF00 [EOW] Wire: ↕#♦H•D→FF00► ``` *Radix H (hex), Unit D (doubleword).* **LOGICAL word** (exclusion expression): ``` Pseudo: [SOW] ? [SOB] !H&!Q [EOW] Wire: ↕?→!H&!Q► ``` *No flags. Body is a boolean expression per §6.2.1 — NOT hex AND NOT quadword.* **BLOB word** (hex, doubleword, declaring 6656 byte tail block): ``` Pseudo: [SOW] * [SOR]H [SOU]D [SOB] 1A00 [EOW] Wire: ↕*♦H•D→1A00► ``` *Radix H, Unit D. Declares a tail block of 0x1A00 (6656) bytes.* **TIMESTAMP word** (canonical microsecond UTC): ``` Pseudo: [SOW] & [SOB] 2026-02-08T12:00:00.000000Z [EOW] Wire: ↕&→2026-02-08T12:00:00.000000Z► ``` *No flags. Body is ISO 8601 canonical form per §6.2.2 — 27 bytes, UTC only, microsecond precision.* **DURATION word** (calendar + time components): ``` Pseudo: [SOW] + [SOB] P3Y6M4DT12H30M5S [EOW] Wire: ↕+→P3Y6M4DT12H30M5S► ``` *No flags. Body is ISO 8601 duration per §6.2.3. Negative direction with leading `-` (e.g. `-P3D`) and the weeks form (`P2W`) are also valid bodies.* --- # 7. Message Frame Structure ## 7.1 Frame Layout ``` [SOM] Word₁ Word₂ ... Wordₙ [EOM] Tail₁ Tail₂ ... ``` A message begins with SOM (0x02) and the head ends with EOM (0x03). The head contains one or more words, each delimited by SOW/EOW. The optional tail follows EOM and consists of binary data blocks. ## 7.2 Head The head is the structured, CP437-encoded portion of the message. It contains words that specify the operation, addressing, parameters, and any tail size declarations. Words are parsed sequentially as they arrive — a receiver does not need to buffer the entire head before processing. ## 7.3 Tail The tail is optional binary data following EOM. It is partitioned into blocks whose sizes are declared by BLOB (\*) words in the head, indexed by their position. The first BLOB word declares the size of the first tail block, the second BLOB word the second block, and so on. A receiver that has parsed the head knows the exact byte count of the tail before the first tail byte arrives. **BLOB Word Semantics:** The BLOB body is a number representing the byte count of the corresponding tail block. The radix flag specifies the number's encoding (decimal, hex, etc.) and the unit flag specifies the numeric range (B = 8-bit, W = 16-bit, D = 32-bit, Q = 64-bit). For example, `*♦D•B→10` declares a 10-byte block; `*♦H•D→1A00` declares a 6656-byte block. **Example**: A message with two BLOB words in the head: ``` [SOM] ...words... [SOW]*[SOR]H[SOU]D[SOB]0100[EOW] [SOW]*[SOR]H[SOU]D[SOB]0200[EOW] [EOM] <256 bytes> <512 bytes> ``` Both BLOB words use unit D (doubleword / 32-bit size field) and radix H (hexadecimal). The first declares 0x0100 = 256 bytes. The second declares 0x0200 = 512 bytes. Total tail length is 768 bytes. BLOB words are positional and non-repeating within a single message head. Each BLOB word declares exactly one tail block, indexed by its ordinal position in the head. A message head containing more BLOB words than tail blocks, or a tail shorter than the sum of all declared BLOB sizes, is malformed. A receiver that detects either condition MUST discard the message and respond with `!X MALFORMED_FRAME`. A receiver that has already begun consuming tail bytes when a size mismatch is detected MUST scan forward to the next SOM byte and report `!X MALFORMED_FRAME`. ## 7.4 Stream Parsing Antheos is designed for stream parsing. A receiver processes one byte at a time: 1. Wait for SOM (0x02). All bytes before SOM are discarded. 2. Parse words as SOW/EOW pairs arrive. Each word is self-describing: word type, optional radix flag, optional unit flag, and body content. 3. On EOM (0x03), the head is complete. Sum the sizes declared by any BLOB words to determine the total tail length. 4. Read tail bytes until the declared total is reached. The next SOM starts a new message. If at any point the receiver cannot continue (buffer full, unsupported type, malformed word), it either sends a Scaleback response or silently drops the frame and scans forward for the next SOM byte. Because SOM is a reserved byte (Section 4.1) that cannot appear inside a head word, a SOM encountered before the current frame's EOM is unambiguously the start of a new message. A stream parser abandons the incomplete frame and resynchronizes **at** this SOM — consistent with step 1, only the bytes *before* the SOM are discarded; the SOM itself begins the new frame — rather than consuming it and waiting for a later SOM (which would also discard the frame the in-head SOM begins). This does not apply within the tail: tail bytes are length-delimited binary (Section 7.3), so a 0x02 byte there is data, not a delimiter, and is consumed as part of the declared block. ## 7.5 Messages Without Tail A message with no BLOB words in the head has no tail. The byte immediately following EOM is either the SOM of the next message or non-message bus traffic. This is the common case for control messages (Establish, Conflict, Ping, etc.). ## 7.6 Word Order Words within a message head MUST appear in the following order: 1. **SYMBOL word** — exactly one, always the first word. 2. **ID words** — zero or more, in order: BID (if present), SID (if present), MID (if present). 3. **Payload words** — zero or more, in application-defined order. --- # 8. Level 1 Symbols Level 1 defines three scopes of operation: bus, service, and session. Symbols are single ASCII characters following the SYMBOL word type (!). Every symbol is unique across all scopes. No disambiguation is required. ## 8.1 Bus Scope Bus scope operations manage transport-level concerns: addressing, message relay, keepalive, capability negotiation, and error reporting. | **Symbol** | **Verb** | **Description** | | :--------- | :---------- | :----------------------------------------- | | E | Establish | Claim a BID on this bus | | C | Conflict | Report a BID collision | | B | Broadcast | Send to all instances on this bus | | P | Ping | Keepalive / presence check | | R | Relay | Forward a message to another bus | | D | Discover | Find which bus a BID resides on | | V | Verify | Resolve BID to full OID:DID:IID identity | | S | Scaleback | Declare receiver capability limits (reactive) | | W | Acknowledge | Confirm receipt of a bus-scope message | | X | Exception | Report a structured error | ## 8.2 Service Scope Service scope operations handle runtime capability discovery. An instance that wants a capability queries for it. Instances that can provide it offer. The querying instance accepts. No upfront advertisement, no schema exchange. | **Symbol** | **Verb** | **Description** | | :--------- | :------- | :-------------------------------------------------- | | Q | Query | Request a service or capability | | O | Offer | Offer to provide the requested service | | A | Accept | Accept an offer, establishing the service agreement | ## 8.3 Session Scope Session scope operations manage active communication sessions between instances. Sessions are optional — not every interaction requires one. | **Symbol** | **Verb** | **Description** | | :--------- | :------- | :--------------------------------------------- | | K | Call | Send a request within a session | | T | Status | Request or report session state | | N | Notify | Push an event notification within a session | | L | Locate | Find which bus a session (SID) resides on | | U | Resume | Reconnect to an interrupted session | | F | Finish | Close a session | --- # 9. Bus Operations ## 9.1 BID Establishment When an instance connects to a bus, it must obtain a unique BID through the Establish/Conflict protocol. ### 9.1.1 Establishment Procedure 1. Generate a random BID candidate of the initial length (base-32 encoded). 2. Transmit an Establish message with the candidate BID. 3. Wait for the timeout period. 4. If a Conflict is received for this BID, increment the BID length and return to step 1. 5. If the BID length exceeds the maximum, transmit an Exception with reason "BID_OVERFLOW" and abort the connection attempt. 6. If no Conflict is received within the timeout, the BID is claimed. The instance begins listening on the bus. ### 9.1.2 Conflict Detection While listening on a bus, an instance that receives an Establish message for a BID it already holds must respond with a Conflict message containing that BID. ### 9.1.3 State Machine | **State** | **Entry Condition** | **Action** | **Transitions** | | :---------- | :------------------------- | :--------------------- | :----------------------------------------------------------------------------------------------------------- | | IDLE | Initial / after disconnect | None | PROPOSING (on connect) | | PROPOSING | Generated candidate BID | Send !E, start timeout | ESTABLISHED (timeout expires, no conflict) / PROPOSING (conflict received, length < max) / FAILED (length >= max) | | ESTABLISHED | No conflict within timeout | Listen on bus | IDLE (on disconnect) | | FAILED | Max BID length exceeded | Send !X "BID_OVERFLOW" | IDLE | ### 9.1.4 Wire Examples **Establish BID:** ``` Pseudo: [SOM] [SOW]!E[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→E►↕@♦U→4T9X2►♥ ``` *Instance proposes BID "4T9X2" on the bus.* **Conflict detected:** ``` Pseudo: [SOM] [SOW]!C[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→C►↕@♦U→4T9X2►♥ ``` *Existing instance reports BID "4T9X2" is already in use.* **Establishment failed:** ``` Pseudo: [SOM] [SOW]!X[EOW] [SOW]"[SOB]BID_OVERFLOW[EOW] [EOM] Wire: ☻↕!→X►↕"→BID_OVERFLOW►♥ ``` *Instance could not establish a BID within the maximum length.* ## 9.2 Reactive Scaleback Scaleback is the mechanism by which a constrained receiver communicates its limits to a sender. There is no upfront capability handshake. A receiver that cannot process a message has two options: send a Scaleback response stating its limits, or silently drop the message. ### 9.2.1 Drop (Silent) A receiver that cannot process a message and cannot (or chooses not to) send a Scaleback simply discards the remaining frame bytes and scans forward for the next SOM byte. This is the universal fallback that requires zero transmit capability. The sender receives no indication that the message was dropped. ### 9.2.2 Scaleback Message A Scaleback message communicates receiver limits using two mechanisms: - **Negative flags** (LOGICAL word): An exclusion list of radix types and/or unit types the receiver cannot handle, expressed as a logical negation. The body grammar is defined in §6.2.1 — Scaleback uses the flag-char atom semantic. - **Positive sizes** (INTEGER words): Maximum head size in bytes, followed by maximum tail size in bytes. A tail size of 0 means the receiver cannot handle binary tails. A fully capable device never sends Scaleback. Only constraints are communicated. Either component (flags or sizes) may be omitted if that dimension is unconstrained. ### 9.2.3 Scaleback Wire Examples **Full Scaleback (type exclusions + size limits):** ``` Pseudo: [SOM] [SOW]!S[EOW] [SOW]?[SOB]!H&!Q[EOW] [SOW]#[SOR]D[SOU]W[SOB]32[EOW] [SOW]#[SOR]D[SOU]W[SOB]0[EOW] [EOM] Wire: ☻↕!→S►↕?→!H&!Q►↕#♦D•W→32►↕#♦D•W→0►♥ ``` *Cannot handle hex or quadword. Max head 32 bytes. No tail.* **Size-only Scaleback (no type exclusions):** ``` Pseudo: [SOM] [SOW]!S[EOW] [SOW]#[SOR]D[SOU]W[SOB]64[EOW] [SOW]#[SOR]D[SOU]W[SOB]0[EOW] [EOM] Wire: ☻↕!→S►↕#♦D•W→64►↕#♦D•W→0►♥ ``` *No type exclusions. Max head 64 bytes. No tail.* **Flags-only Scaleback (no size limits):** ``` Pseudo: [SOM] [SOW]!S[EOW] [SOW]?[SOB]!Q&!T[EOW] [EOM] Wire: ☻↕!→S►↕?→!Q&!T►♥ ``` *Cannot handle quadword or terabyte. No size constraints.* On receiving a Scaleback, the sender may resend the message within the stated limits, attempt a different encoding, or accept that this receiver cannot handle the message. The sender has no obligation to retry. ### 9.2.4 Scaleback Semantics - A Scaleback applies to the sender-receiver pair for the duration of the current bus connection. - A receiver may send a new Scaleback at any time to update its limits (e.g., after freeing buffer space). - A Scaleback with no LOGICAL word and no INTEGER words is a no-op and should be ignored. - Scaleback is unreliable by design. There is no guaranteed delivery. A sender that receives a Scaleback may respond with an Acknowledge (`!W`) containing the Scaleback sender's BID, confirming the limits were received. The Acknowledge carries only the BID; correlation is implicit — an Acknowledge from BID X to BID Y confirms receipt of the most recent Scaleback from Y to X. A receiver that does not receive an Acknowledge MAY retransmit the Scaleback. A sender that does not respect stated limits after acknowledging them will have its messages silently dropped. ## 9.3 Path Addressing Antheos uses a path-and-index mechanism for multi-hop routing. A PATH word contains a dot-separated sequence of BIDs representing the complete route. An INTEGER index word identifies the current position within that path. The index is zero-based: position 0 is the origin, position N is the Nth hop. When paths are used for addressing, the message ends with the index followed by the path. This ordering is intentional: a stream-parsing instance reads the index first, then scans the path counting dots to find its target position. Single-pass, no backtracking, no buffering the entire path. ``` ... [payload words] [#index] [/path] [EOM] ``` ### 9.3.1 Broadcast Path (Expanding) A broadcast carries a single path that expands as the message traverses instances. Each forwarding instance appends its own BID to the path. No index is needed during broadcast — the message goes to all instances. When any receiver wants to reply, the path contains the complete return route. The receiver sets the index to its own position (the last entry) and sends a Relay using the same path. **Trace: Broadcast from A (BID=AA) through B, C to D:** At A (origin): ``` Pseudo: [SOM] [SOW]!B[EOW] [SOW]"[SOB]Hello[EOW] [SOW]/[SOB]AA[EOW] [EOM] Wire: ☻↕!→B►↕"→Hello►↕/→AA►♥ ``` *Origin broadcasts. Path contains only the origin BID.* At B (appends BB): ``` Pseudo: [SOM] [SOW]!B[EOW] [SOW]"[SOB]Hello[EOW] [SOW]/[SOB]AA.BB[EOW] [EOM] Wire: ☻↕!→B►↕"→Hello►↕/→AA.BB►♥ ``` *B forwards broadcast, appending its BID to the path.* At C (appends CC): ``` Pseudo: [SOM] [SOW]!B[EOW] [SOW]"[SOB]Hello[EOW] [SOW]/[SOB]AA.BB.CC[EOW] [EOM] Wire: ☻↕!→B►↕"→Hello►↕/→AA.BB.CC►♥ ``` *C forwards broadcast, appending its BID.* At D (appends DD): ``` Pseudo: [SOM] [SOW]!B[EOW] [SOW]"[SOB]Hello[EOW] [SOW]/[SOB]AA.BB.CC.DD[EOW] [EOM] Wire: ☻↕!→B►↕"→Hello►↕/→AA.BB.CC.DD►♥ ``` *D receives broadcast. Path is now complete and fixed.* ### 9.3.2 Relay Path (Index Decrement) A relay carries the complete fixed path (established during broadcast or known in advance) and a zero-based index indicating the current sender's position. Each forwarding instance decrements the index and forwards to the BID at position index–1 in the path. The path never changes during relay. Only the index is modified. This means a forwarding instance performs no string manipulation — it reads the index, subtracts one, counts dots in the path to find the next-hop BID, and forwards. **Relay procedure at each hop:** 1. Read the index from the INTEGER word. 2. Compute next_hop = index − 1. 3. If next_hop < 0: error, discard message. 4. Find path[next_hop] by counting dots (zero-based) in the PATH body. 5. If path[next_hop] matches my BID: I am the destination. Deliver the message. 6. Otherwise: write next_hop as the new index, forward to path[next_hop]. **Trace: D (index=3) replies to A via the established path AA.BB.CC.DD:** D sends (index=3, D's position): ``` Pseudo: [SOM] [SOW]!R[EOW] [SOW]"[SOB]Reply[EOW] [SOW]#[SOR]D[SOU]B[SOB]3[EOW] [SOW]/[SOB]AA.BB.CC.DD[EOW] [EOM] Wire: ☻↕!→R►↕"→Reply►↕#♦D•B→3►↕/→AA.BB.CC.DD►♥ ``` *D sends relay. Index=3, next hop is path[2]=CC.* At C (decrements to 2): ``` Pseudo: [SOM] [SOW]!R[EOW] [SOW]"[SOB]Reply[EOW] [SOW]#[SOR]D[SOU]B[SOB]2[EOW] [SOW]/[SOB]AA.BB.CC.DD[EOW] [EOM] Wire: ☻↕!→R►↕"→Reply►↕#♦D•B→2►↕/→AA.BB.CC.DD►♥ ``` *C forwards. Index=2, next hop is path[1]=BB.* At B (decrements to 1): ``` Pseudo: [SOM] [SOW]!R[EOW] [SOW]"[SOB]Reply[EOW] [SOW]#[SOR]D[SOU]B[SOB]1[EOW] [SOW]/[SOB]AA.BB.CC.DD[EOW] [EOM] Wire: ☻↕!→R►↕"→Reply►↕#♦D•B→1►↕/→AA.BB.CC.DD►♥ ``` *B forwards. Index=1, next hop is path[0]=AA.* At A (index=1, path[0]=AA = me): message delivered. *A receives the message. Index-1=0, path[0]=AA matches own BID. Delivered.* ### 9.3.3 Path Recovery **Failure Detection:** A forwarding instance that cannot deliver to the next-hop BID (instance disconnected, bus lost, timeout) MUST NOT forward the message. It becomes the recovery origin for that message. **Recovery:** The recovery origin issues a Discover (`!D`) for the unreachable BID, broadcasting it on all buses it is connected to. If a Discover response is received within timeout, the recovery origin updates its local routing table and retransmits the original message toward the newly discovered BID. The path word is not modified — path integrity is the originator's concern. **Wire example** (C cannot reach BB): ``` Pseudo: [SOM] [SOW]!D[EOW] [SOW]@[SOR]U[SOB]BB[EOW] [EOM] Wire: ☻↕!→D►↕@♦U→BB►♥ ``` *C broadcasts Discover for BID BB.* **Discover Fails:** If no Discover response is received within timeout, the recovery origin sends `!X RELAY_FAILED` back toward the originator via the reverse relay procedure — index set to the recovery origin's own position, decrementing toward position 0. The Exception carries the unreachable BID as a TEXT word. **Return Path Also Broken:** If the recovery origin cannot relay the Exception back, it MUST silently discard the message. The originator will detect failure through its own timeout. ## 9.4 Broadcast A broadcast message is sent to all instances on the current bus. Broadcast is always a local bus operation. Multi-bus forwarding is handled by Relay (Section 9.3.2), using the path built during broadcast (Section 9.3.1). ``` Pseudo: [SOM] [SOW]!B[EOW] [SOW]"[SOB]Hello all[EOW] [EOM] Wire: ☻↕!→B►↕"→Hello all►♥ ``` *Broadcast to all instances on this bus.* ## 9.5 Ping Ping is a keepalive and presence check. It may target a specific BID or be broadcast. The response is a Ping containing the responder's BID. **Ping a specific instance:** ``` Pseudo: [SOM] [SOW]!P[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→P►↕@♦U→4T9X2►♥ ``` *Ping instance at BID "4T9X2".* **Response:** ``` Pseudo: [SOM] [SOW]!P[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→P►↕@♦U→4T9X2►♥ ``` *Pong: instance 4T9X2 confirms presence.* **Broadcast ping:** ``` Pseudo: [SOM] [SOW]!P[EOW] [EOM] Wire: ☻↕!→P►♥ ``` *Broadcast ping. All instances respond with their BID.* **Broadcast responses:** ``` Wire: ☻↕!→P►↕@♦U→4T9X2►♥ Wire: ☻↕!→P►↕@♦U→7M3K9►♥ ``` *Multiple instances respond, each with own BID.* ## 9.6 Discover Discover (`!D`) finds which bus a BID resides on. This is used for path recovery when a relay cannot reach the next hop. **Request:** ``` Pseudo: [SOM] [SOW]!D[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→D►↕@♦U→4T9X2►♥ ``` *Discover: where is BID 4T9X2?* **Response (BID found on this bus):** ``` Pseudo: [SOM] [SOW]!D[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [SOW]@[SOR]U[SOB]7M3K9[EOW] [EOM] Wire: ☻↕!→D►↕@♦U→4T9X2►↕@♦U→7M3K9►♥ ``` *Discovered: BID 4T9X2 is reachable via BID 7M3K9 on this bus.* An instance that receives a Discover for a BID it holds responds with its own BID. An instance connected to multiple buses that knows the target BID is reachable on another bus MAY respond with the gateway BID for that route. If no response is received, the BID is considered unreachable. ## 9.7 Verify Verify resolves a BID to its full OID:DID:IID identity. The response contains the three identity components as separate ID words. **Request:** ``` Pseudo: [SOM] [SOW]!V[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→V►↕@♦U→4T9X2►♥ ``` *Request identity of instance at BID "4T9X2".* **Response:** ``` Pseudo: [SOM] [SOW]!V[EOW] [SOW]@[SOB]example[EOW] [SOW]@[SOB]Thermostat[EOW] [SOW]@[SOB]SN00482[EOW] [EOM] Wire: ☻↕!→V►↕@→example►↕@→Thermostat►↕@→SN00482►♥ ``` *Response: OID=example, DID=Thermostat, IID=SN00482.* ## 9.8 Acknowledge Acknowledge (`!W`) confirms receipt of a bus-scope message. It is used primarily to confirm Scaleback was received, but may be used to confirm any bus-scope message where the sender requires assurance. ``` Pseudo: [SOM] [SOW]!W[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→W►↕@♦U→4T9X2►♥ ``` *Acknowledge: confirming receipt of a message from BID "4T9X2".* Acknowledge is not mandatory for any message. It is available when confirmation is needed. ## 9.9 Exception Exceptions are structured error reports. The SYMBOL !X is followed by a TEXT word containing the error reason. ``` Pseudo: [SOM] [SOW]!X[EOW] [SOW]"[SOB]BID_OVERFLOW[EOW] [EOM] Wire: ☻↕!→X►↕"→BID_OVERFLOW►♥ ``` *Exception: BID establishment exceeded maximum length.* --- # 10. Service Operations Service discovery follows a strict Query/Offer/Accept pattern. An instance that needs a capability queries for it. Instances that can provide it respond with offers. The querying instance selects and accepts an offer. Sessions are not obligatory. A service interaction may consist of a single Query/Offer/Accept exchange followed by direct message exchange, or it may establish a long-lived session. The service scope defines the discovery mechanism; the session scope (Section 11) defines optional persistent communication. ## 10.1 Query An instance broadcasts or directs a query describing the service it needs. The query contains a TEXT word describing the desired capability. The capability TEXT MUST be non-empty: an empty query describes no service, and a match-all interpretation would constitute the capability enumeration the demand-driven model prohibits (Sections 10.2, 15). A builder MUST reject an empty capability; a receiver MAY ignore a Query with an empty capability. ``` Pseudo: [SOM] [SOW]!Q[EOW] [SOW]"[SOB]temperature[EOW] [EOM] Wire: ☻↕!→Q►↕"→temperature►♥ ``` *Query: I need a temperature service.* ## 10.2 Offer Instances that can provide the requested service respond with an offer. The offer includes the responding instance's BID and a description of what it provides. The offer implicitly defines the interface — there is no separate interface definition language. An Offer MUST only be sent in response to a Query. Unsolicited Offers (broadcasting capabilities at startup or at any time without a preceding Query) are prohibited. This prevents capability enumeration by passive observers and enforces the demand-driven discovery model described in Section 8.2. ``` Pseudo: [SOM] [SOW]!O[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [SOW]"[SOB]temperature_celsius[EOW] [EOM] Wire: ☻↕!→O►↕@♦U→4T9X2►↕"→temperature_celsius►♥ ``` *Offer: instance at BID "4T9X2" can provide temperature in Celsius.* ## 10.3 Accept The querying instance accepts an offer by addressing the offering instance's BID. This establishes the service agreement and may optionally initiate a session. ``` Pseudo: [SOM] [SOW]!A[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→A►↕@♦U→4T9X2►♥ ``` *Accept: I accept the offer from BID "4T9X2".* ### 10.3.1 Accept with Sender BID An Accept frame MUST include a second `@U` word carrying the sender's BID. This allows the offering instance to identify who accepted its offer without waiting for a session to be established. ``` Pseudo: [SOM] [SOW]!A[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [SOW]@[SOR]U[SOB]7M3K9[EOW] [EOM] Wire: ☻↕!→A►↕@♦U→4T9X2►↕@♦U→7M3K9►♥ ``` *Accept: instance "7M3K9" accepts the offer from BID "4T9X2".* The first `@U` word is the target BID (the offering instance). The second `@U` word is the sender BID (the accepting instance). ## 10.4 Offer Collection A Query may elicit multiple Offers from different instances. The querying instance decides how to handle them: - **First-offer-wins**: Accept the first Offer received, ignore subsequent Offers. Minimizes latency. - **Collect-then-choose**: Wait for a timeout period, collect all Offers, then Accept the preferred one. Enables comparison. Offers not followed by an Accept are implicitly declined. No explicit rejection message is required. An offering instance MUST NOT assume its Offer will be accepted and MUST NOT allocate resources until Accept is received. --- # 11. Session Operations Sessions provide persistent, stateful communication between instances. They are optional — bus-scope operations and one-shot service interactions do not require sessions. When an interaction needs message sequencing, state tracking, or long-lived communication, a session is established. ## 11.1 Session Lifecycle ### 11.1.1 Creation A session is typically initiated after a service Accept, but may be opened directly between instances that already know each other. The initiating instance generates a fresh SID from a hash of OID:DID:IID:\ and sends the first session-scope message. ### 11.1.2 Active Communication Within a session, messages are sequenced by MID, a decimal counter starting at 1 and incrementing by 1 with each message. Call (`!K`) sends requests, Status (`!T`) queries state, and Notify (`!N`) pushes unsolicited events. **MID Wrap:** When MID reaches the maximum value, the instance transmits a wrap message with MID=0 — containing only the session verb, SID, and MID=0, with no payload. The receiver resets its sequence expectation to MID=1. Normal sequencing resumes immediately after the wrap message. ### 11.1.3 Interruption and Recovery If a session is interrupted (bus disconnect, device reset), the Locate verb finds where the remote instance now resides, and Resume reconnects to the session. ### 11.1.4 Termination Finish closes a session. The SID is discarded — it is never reused. ### 11.1.5 State Machine | **State** | **Entry Condition** | **Transitions** | | :--------- | :--------------------------- | :---------------------------------------------------- | | IDLE | No session | ACTIVE (on Accept or direct open) | | ACTIVE | Session created, SID assigned| SUSPENDED (on disconnect) / IDLE (on Finish) | | SUSPENDED | Bus lost or timeout | ACTIVE (on Resume) / IDLE (on Finish or timeout expiry)| **Session Timeout:** The duration before a SUSPENDED session transitions to IDLE is implementation-defined. An instance whose session has timed out MUST respond with `!X SESSION_EXPIRED` if a Resume (`!U`) arrives for that SID afterward. An instance MAY signal an impending timeout via `!T` (Status) before transitioning. ## 11.2 SID Generation SIDs are variable-length base-32 hashes derived from the instance's identity and a monotonic counter. Every session receives a fresh SID — SIDs are never reused. SID length starts short and grows on collision, keeping typical messages compact while scaling to high session counts. **SID Length:** An implementation defines initial length, increment on collision, and maximum length. SID generation starts at the initial length and grows on collision until a unique SID is found or maximum length is reached. **Generation Procedure:** 1. Compute hash of OID:DID:IID:\. Store hash bytes in little-endian order (least significant byte first) so that truncation preserves the most-varying bits — the counter varies the trailing input bytes, which drive the hash's low-order bits the most, so truncating from the low end is near-uniform. (Truncating from the high end can collide badly at very short lengths; an implementation's initial length SHOULD stay clear of that regime — e.g. an initial length of 6 base-32 characters gives a 32⁶ ≈ 1.07×10⁹ space.) 2. Encode as base-32, truncated to current SID length (starting at initial length). 3. Check if truncated SID matches any currently active session. 4. If collision: increase length by increment, re-truncate, and repeat from step 3. 5. If length exceeds maximum: increment sid_counter, reset length to initial, and repeat from step 1. 6. If no collision: SID is assigned, increment sid_counter. **Rotation:** SIDs are generated fresh for every session. When a session finishes, its SID is discarded. The monotonic counter ensures forward progress — no SID is ever reissued. The counter resets on device reboot. If a Resume (`!U`) arrives for a SID that is currently active but belongs to a different session than the sender expects, the receiving instance MUST respond with `!X RESUME_DENIED`. ### 11.2.1 Non-conformant Escape Hatch The §11.2 generation procedure is the conformance bar — implementations claiming spec conformance MUST run the collision-check-and-grow algorithm against the active-session set. An implementation MAY additionally expose a non-conformant SID-generation path (e.g. an "unchecked" acquire that skips the active-set check) for memory-constrained environments where maintaining the active-set is infeasible — the constrained-device rationale from §11.2 step 1 anticipates this case. Such a path is a structurally-named escape hatch — not a default. Implementations exposing one MUST: - Name it explicitly to signal non-conformance at every call site (e.g. `acquire_unchecked()` rather than `acquire()`). - Document at the call site and in API documentation that calling it FORFEITS the spec §11.2 uniqueness guarantee: two concurrent sessions can receive identical SIDs at the minimum length under the base-32 truncation birthday bound. - Not present the unchecked path as the default-named API of the SID generator. A conformant peer encountering a counterparty that produced a duplicate SID MAY treat the second-arriving session as a protocol error and respond with the same exception path used for any other §11.2 violation. The conformance bar binds the implementation that *generates* the SID; the receiving peer is entitled to assume §11.2 was followed. ## 11.3 Call Call sends a request within an active session and expects a response. The response is itself a Call with the next sequential MID. Receipt of the response confirms delivery of the request. If no response arrives within timeout, the sender MAY retransmit or treat the session as interrupted. **Request:** ``` Pseudo: [SOM] [SOW]!K[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [SOW]@[SOR]D[SOB]1[EOW] [SOW]"[SOB]get_reading[EOW] [EOM] Wire: ☻↕!→K►↕@♦U→A7K2M►↕@♦D→1►↕"→get_reading►♥ ``` *Session Call: SID=A7K2M, MID=1, request="get_reading".* **Response:** ``` Pseudo: [SOM] [SOW]!K[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [SOW]@[SOR]D[SOB]2[EOW] [SOW]"[SOB]23.5[EOW] [EOM] Wire: ☻↕!→K►↕@♦U→A7K2M►↕@♦D→2►↕"→23.5►♥ ``` *Session Call response: SID=A7K2M, MID=2, response="23.5".* ## 11.4 Status Status requests or reports the current state of a session. A Status request expects a Status response; the response confirms both delivery and current session state. **Request:** ``` Pseudo: [SOM] [SOW]!T[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [SOW]@[SOR]D[SOB]2[EOW] [EOM] Wire: ☻↕!→T►↕@♦U→A7K2M►↕@♦D→2►♥ ``` *Session Status request: SID=A7K2M, MID=2.* **Response:** ``` Pseudo: [SOM] [SOW]!T[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [SOW]@[SOR]D[SOB]3[EOW] [SOW]"[SOB]ACTIVE[EOW] [EOM] Wire: ☻↕!→T►↕@♦U→A7K2M►↕@♦D→3►↕"→ACTIVE►♥ ``` *Session Status response: SID=A7K2M, MID=3, state="ACTIVE".* ## 11.5 Notify Notify pushes an unsolicited event within a session. Unlike Call, it does not expect a response and delivery is not confirmed. Notify is fire-and-forget; use Call if acknowledgment is required. ``` Pseudo: [SOM] [SOW]!N[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [SOW]@[SOR]D[SOB]3[EOW] [SOW]"[SOB]threshold_exceeded[EOW] [EOM] Wire: ☻↕!→N►↕@♦U→A7K2M►↕@♦D→3►↕"→threshold_exceeded►♥ ``` *Session Notify: SID=A7K2M, MID=3, event="threshold_exceeded".* ## 11.6 Locate Locate finds which bus a session (SID) resides on. This is used after a bus change or reconnect. **Request:** ``` Pseudo: [SOM] [SOW]!L[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [EOM] Wire: ☻↕!→L►↕@♦U→A7K2M►♥ ``` *Locate: where is session A7K2M?* **Response (session found):** ``` Pseudo: [SOM] [SOW]!L[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [SOW]@[SOR]U[SOB]4T9X2[EOW] [EOM] Wire: ☻↕!→L►↕@♦U→A7K2M►↕@♦U→4T9X2►♥ ``` *Located: session A7K2M is at BID 4T9X2.* ## 11.7 Resume Resume reconnects to an interrupted session. The remote instance responds with Status confirming the session state, or with an Exception if the session is no longer available. **Request:** ``` Pseudo: [SOM] [SOW]!U[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [EOM] Wire: ☻↕!→U►↕@♦U→A7K2M►♥ ``` *Resume session A7K2M.* **Response (success):** ``` Pseudo: [SOM] [SOW]!T[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [SOW]@[SOR]D[SOB]47[EOW] [SOW]"[SOB]ACTIVE[EOW] [EOM] Wire: ☻↕!→T►↕@♦U→A7K2M►↕@♦D→47►↕"→ACTIVE►♥ ``` *Session resumed: SID=A7K2M, last MID=47, state=ACTIVE. Normal communication resumes at MID 48.* **Response (failure):** ``` Pseudo: [SOM] [SOW]!X[EOW] [SOW]"[SOB]SESSION_EXPIRED[EOW] [EOM] Wire: ☻↕!→X►↕"→SESSION_EXPIRED►♥ ``` *Session A7K2M has timed out and been reclaimed.* ## 11.8 Finish Finish closes a session. The sender immediately transitions the session to IDLE and discards the SID. Finish is fire-and-forget — no response is expected. If the remote instance does not receive the Finish, its session timeout will eventually reclaim the session. ``` Pseudo: [SOM] [SOW]!F[EOW] [SOW]@[SOR]U[SOB]A7K2M[EOW] [EOM] Wire: ☻↕!→F►↕@♦U→A7K2M►♥ ``` *Finish session A7K2M. SID discarded.* --- # 12. Bus Transmission Rules - Buses carry CP437 byte streams transparently. A bus does not interpret, modify, or filter message content. - Devices respect PATH words for routing. A device that receives a message with a PATH not addressed to it forwards the message if connected to the next hop, or discards it. - No session or message interpretation occurs at the bus level. The bus is a passive transport medium. - Bytes between messages (outside SOM/EOM framing) are ignored. This allows Antheos to coexist with other traffic on shared buses. --- # 13. Standard Exception Codes The following exception reason strings are defined for Level 1. Implementations may define additional reason strings for application-specific errors. Exception reasons are carried in a TEXT word following the !X symbol. | **Reason** | **Scope** | **Meaning** | | :------------------ | :-------- | :----------------------------------------------- | | BID_OVERFLOW | Bus | BID establishment exceeded maximum length | | BID_TIMEOUT | Bus | BID establishment timed out without resolution | | RELAY_FAILED | Bus | Message could not be forwarded to the next hop | | PATH_BROKEN | Bus | A hop in the route path is unreachable | | INDEX_INVALID | Bus | Path index is out of range for the given path | | UNKNOWN_BID | Bus | Addressed BID not found on this bus | | MALFORMED_FRAME | Bus | Message frame is structurally invalid | | UNSUPPORTED_TYPE | Bus | Word type not supported by this instance | | SERVICE_UNKNOWN | Service | No instance offers the requested service | | OFFER_EXPIRED | Service | The offer is no longer valid | | SESSION_NOT_FOUND | Session | SID does not match any known session | | SESSION_EXPIRED | Session | Session has timed out and been reclaimed | | RESUME_DENIED | Session | Session cannot be resumed | | MID_OUT_OF_ORDER | Session | Message ID does not follow expected sequence | --- # 14. Capability Level 1 is the complete, self-contained baseline. Every symbol has a single, fixed meaning. Every message does exactly one thing. This is the universal foundation. Capability tiers beyond Level 1 are discovered at runtime through the Query/Offer/Accept mechanism (Section 10) and defined in separate specifications. Level 1 makes no assumptions about what those capabilities are or how they behave. --- # 15. Conformance Requirements This section defines the requirements for a conformant Antheos Level 1 implementation. The keyword MUST is used per RFC 2119. ## 15.1 Minimum Conformant Implementation An instance MUST: - Parse SOM and EOM to identify message boundaries. - Parse SOW and EOW to identify word boundaries. - Recognize the SYMBOL word type (!). - Implement the Establish/Conflict protocol (bus scope: E, C). - Silently drop messages it cannot process (scan forward to next SOM). ## 15.2 Optional Features An instance MAY implement any combination of: - Bus scope: B, P, R, D, V, S, W, X - Service scope: Q, O, A - Session scope: K, T, N, L, U, F - Path addressing and relay - Any word types beyond SYMBOL --- # 16. Security Considerations Antheos Level 1 provides no encryption, authentication, or integrity protection. The protocol is designed as a transparent transport layer; security is a concern for higher layers built on top of Level 1. - **No encryption**: All message content is transmitted in cleartext CP437. Any entity with access to the bus can read all traffic. - **No authentication**: BIDs are self-asserted through Establish/Conflict. Any instance can claim any available BID. The Verify verb provides identity disclosure but not identity proof. - **No integrity**: Messages can be modified in transit on shared buses. There is no checksum or signature mechanism at Level 1. - **BID spoofing**: An adversary can claim a BID that was previously held by another instance after that instance disconnects. - **Capability enumeration**: A passive observer on a shared bus can catalogue available services by monitoring Query/Offer traffic. Unsolicited Offer broadcasts would make this trivial without any traffic generation; the prohibition in Section 10.2 limits enumeration to active observation of demand-driven exchanges. Applications requiring security implement encryption and authentication as a higher-level service, negotiated through Query/Offer/Accept. The Antheos frame structure (typed words, delimited boundaries) provides clear attachment points for security wrappers around message content. SIDs are generated fresh per session and never reused, preventing cross-session correlation through SID observation. SID generation mixes entropy from `/dev/urandom` into the FNV-1a hash alongside the identity and counter, making SIDs unpredictable to external observers. Without entropy, SID generation falls back to deterministic mode (identity + counter only). Knowledge of a SID allows interaction with the session. Session ownership is declared via an `O:\n` body-header prefix in the first K-verb of a session. This allows the receiving peer to map SID→BID for session attribution. The `O:` header follows the same convention as the `T:\n` trace header and is extracted after it. --- # 17. Licensing MIT License Copyright (c) 2025-2026 Are Bjørby Permission is hereby granted, free of charge, to any person obtaining a copy of this specification and associated documentation files (the "Specification"), to deal in the Specification without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. THE SPECIFICATION IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SPECIFICATION OR THE USE OR OTHER DEALINGS IN THE SPECIFICATION. --- # Appendix A: Level 2 — Authentication (Z-verb) *This appendix defines an optional Level 2 extension. A Level 1 implementation is complete and conformant without it.* ## A.1 Overview The Z-verb (Authenticate) provides Ed25519 challenge-response authentication between peers. It extends the existing Q/O/A+V handshake with a cryptographic proof step: V discloses identity ("I am X"), Z proves it ("Prove you are X"). ## A.2 Wire Format **Challenge (server → client):** ``` SOM [!Z] [@U target_bid] ["nonce_hex] EOM ``` - `target_bid`: Base-32 BID of the peer being challenged - `nonce_hex`: 32-byte random nonce, hex-encoded (64 chars) **Response (client → server):** ``` SOM [!Z] [@U target_bid] [@ key_id] ["sig_hex] EOM ``` - `target_bid`: Base-32 BID of the challenger (server) - `key_id`: Plain ID word — hex identifier of the signing key - `sig_hex`: Ed25519 signature over the nonce (64 bytes, 128 hex chars) ## A.3 Auth Flow ``` After Q → O → A → V exchange: SERVER CLIENT | | |──[Z: client_bid, nonce_hex]──────────>| challenge | | (client signs nonce) |<─────[Z: server_bid, key_id, sig_hex]─| proof | (server verifies) | | | | Auth OK: session proceeds | | Auth FAIL: !X AUTH_FAILED | ``` ## A.4 Requirements - Server sends Z-challenge AFTER receiving V-response (identity must be known to look up the peer's trusted public key). - Client responds only to Z-challenges addressed to its own BID. - Nonce MUST be fresh per challenge (no reuse). Server generates via CSPRNG. - If verification fails, server SHOULD send `!X AUTH_FAILED`. - Auth is opt-in: peers that don't require auth skip the Z exchange entirely. This preserves backward compatibility with Level 1 peers. ## A.5 Security Notes - Ed25519 signatures are deterministic (no weak-RNG attack surface). - Nonce freshness prevents replay attacks. - Z-verb does not provide encryption — message content remains cleartext. - The trusted key store (OID → public key mapping) is out of scope for the protocol. It may be a local config file, a key registry service, or any other mechanism. --- *— End of Antheos Protocol 1.0 Level 1 Specification —*