BP BitPads Protocol

bitpads-tools · x86-64 NASM Assembly

CLI
Tools

Hand-assembled x86-64. No C runtime. Direct kernel syscalls. Provable protocol conformance at the instruction level.

The bitpads-tools CLI is a command-line encoder written in hand-assembled x86-64 NASM assembly. It produces .bp binary frame files that conform to the BitPads Protocol v2.0 specification — Pure Signal, Wave, Record, and BitLedger frames across all four protocol layers.

The design philosophy is aggressive minimalism. There is no C runtime, no standard library, no heap allocation, no external dependencies. The tool issues write, open, close, and exit syscalls directly through the kernel ABI. Every byte in the output buffer was put there by explicit instruction. This makes the binary's protocol conformance provable at the instruction level rather than inferred through a stack of library calls.

The 256-byte context block is stack-allocated at startup and freed on exit. No memory management is required. No garbage collector runs. The encoder populates fields in the context block from parsed CLI flags, routes to the appropriate frame builder, and the builder writes bytes sequentially into a stack-allocated output buffer. The resulting bytes go to a file, to stdout, or are discarded in dry-run mode. There is no post-processing step.

Why NASM: Writing the encoder at the instruction level means every byte written to the output buffer is a deliberate, auditable act. There is no intermediate representation that could silently misalign a field, pad a struct, or reorder bytes. The bit positions in the output match the specification because the code that writes them was written to match the specification, and there is no compiler between the specification and the output.

Current platform: The macOS CLI (assemblycli/) is functional and produces conformant frames for all four frame types. A Linux port (linux_assembly_cli/) has been assembled to ELF64 but has not yet been linked or run on a Linux machine.

Internal Design

Architecture

The 256-Byte Context Block

All state for a single frame assembly operation lives in a 256-byte context block allocated on the stack at entry. The block is a flat structure — no linked lists, no dynamic allocation, no pointers to the heap. CLI flag parsing writes field values into named offsets within the block. The dispatcher reads those offsets to decide which frame builder to call. Each component builder reads from the context block and writes bytes directly to the output buffer.

The context block contains: frame type selector, Meta byte 1 and 2 field values, Layer 1 sender identity words, domain and permission bits, Layer 2 batch header fields (currency, scaling, precision, rounding mode), Layer 3 value mantissa and shift, account pair, direction and status flags, optional time block fields (T1S and T2 formats), task code and action nibble, note byte count, signal slot presence byte, and output routing selector (file / stdout / dry-run).

Frame Assembly Pipeline

CLI Parse
cli_parse.asm — reads argv, populates context block fields
Dispatch
dispatch.asm — reads frame type selector, routes to builder
Frame Builder
build_signal / wave / record / ledger.asm
Meta Layers
meta1.asm + meta2.asm — construct Meta bytes 1 and 2
Layer Builders
layer1 / layer2 / layer3.asm — L1 identity, L2 batch, L3 record
Components
value / time_comp / task / note / setup.asm
CRC-15
crc15.asm — polynomial x^15 + x + 1 over session payload
Enhancement
c0gram / signals / cmd1100 / ctx1101 / tel1110.asm
I/O
fileio.asm + hexdump.asm — write syscall, dry-run hex
─────────────────────────────────────────────────────────────
FRAME ASSEMBLY PIPELINE — STACK-ONLY DATA FLOW
─────────────────────────────────────────────────────────────
argv[] → cli_parse.asm writes fields into ctx[0..255]
ctx[frame_type] → dispatch.asm selects builder routine
builder routine → meta1.asm writes byte 0 of output buf
→ meta2.asm writes byte 1 (Record/Ledger only)
→ layer1.asm writes 8 bytes — identity + CRC-15
→ layer2.asm writes 6 bytes — batch header
→ components value, time, task, note — if present
→ layer3.asm writes 5 bytes — 40-bit BitLedger record
outbuf[0..N] → fileio.asm write() syscall or hexdump to stdout
─────────────────────────────────────────────────────────────
No heap. No malloc. No post-processing. No intermediate file.
Context block: 256 bytes on the stack. Output buffer: stack.
─────────────────────────────────────────────────────────────

Directory Structure — assemblycli/

assemblycli/
  main.asm             entry point, stack frame, context block init, exit syscall
  cli_parse.asm        argv walker — maps flag strings to context block offsets
  dispatch.asm         frame type router — calls appropriate build_*.asm
  include/
    bitpads.inc         context block offsets, protocol constants, field masks
    macros.inc          NASM macros for common byte-write and bit-shift patterns
    syscall.inc         macOS syscall numbers (write=4, open=5, close=6, exit=1)
  src/builders/
    build_signal.asm    Pure Signal — 1-byte frame from Meta byte 1
    build_wave.asm      Wave — 2–4 byte frame, 16 category dispatch
    build_record.asm    Record — 13–29 bytes, optional component chain
    build_ledger.asm    BitLedger — full double-entry frame, 22+ bytes
  src/layers/
    meta1.asm           Meta byte 1 — mode, ACK, continuation, treatment, flags
    meta2.asm           Meta byte 2 — domain, permissions, record flags
    layer1.asm          8-byte session header — sender ID, CRC-15 embed
    layer2.asm          6-byte batch header — currency, scaling, precision
    layer3.asm          5-byte BitLedger record — 40-bit double-entry
  src/components/
    value.asm           value encoding — A × 2^S + r mantissa/shift packing
    time_comp.asm       T1S (3-byte) and T2 (4-byte) time block builders
    task.asm            2-byte task component — task code + action nibble
    note.asm            variable-length note block — byte count + data
    setup.asm           Session Config Extension — compound, BL block, nesting
  src/crypto/
    crc15.asm           CRC-15 — polynomial x^15+x+1, register-based bit iterator
  src/io/
    fileio.asm          open/write/close syscalls, stdout routing
    hexdump.asm         hex-formatted dry-run output to stdout
  src/enhancement/
    c0gram.asm          C0 Enhancement Grammar — base flag-byte builder
    signals.asm         signal slot presence byte — P1–P13 position flags
    cmd1100.asm         category 1100 — compact command wave builder
    ctx1101.asm         category 1101 — context declaration wave builder
    tel1110.asm         category 1110 — telegraph emulation wave builder

Output Specification

Frame Types

The CLI produces four frame types. Every frame begins with Meta byte 1. Mode, content type, and enhancement state are declared in that byte before the receiver processes anything else. A Pure Signal closes immediately; a BitLedger frame carries five independent protocol layers.

Pure Signal — 1 Byte

Meta byte 1 alone. The byte is the entire message. No session, no preamble, no continuation. Used for heartbeats, ACK requests, status pulses, and priority alerts. Bit 1 = 0 selects Wave mode; the frame closes after the single byte when the continuation bits declare none.

Pure Signal — 0x40 — Wave mode, ACK request, basic treatment
1 0 Wave
Mode
2 1 ACK
Req
3 0 Cont
None
4 0 Basic
Treat
5 0 Priority
6 0 Cipher
7 0 Ext
Flags
8 0 Profile
Mode / Control Content — Role A

Wave — 2–4 Bytes

Meta byte 1 plus a wave category byte (Wave byte) and, for categories 0100–0111, a Layer 1 value byte. Sixteen category codes spanning plain values, messages, status signals, commands, and stream opens. No identity overhead. No session Layer 1 required for basic categories. The CLI builds the wave category byte from the 4-bit category nibble and the wave content nibble.

Wave Frame — Meta byte 1 + Wave category byte
1 0 Wave
Mode
2 0 Control
3-4 00 Cont
Treat
5-8 0000 Role A
Flags
W1-4 CAT Category
Nibble
W5-8 CNT Content
Nibble
Mode / Control Wave Content

Record — 13–29 Bytes

Both Meta bytes plus Layer 1 (8 bytes of session identity with embedded CRC-15) plus optional components attached on demand: a value block, a time block (T1S at 3 bytes or T2 at 4 bytes), a task block (2 bytes), and a note block (variable). Each optional component is declared by a presence bit in Meta byte 2. The minimal fully-identified record is 13 bytes; the full form with all four optional components is 29 bytes.

Record Frame — Meta 1 + Meta 2 + Layer 1 (8 bytes) + optional components
M1.1 1 Record
Mode
M1.2-8 ... Meta 1
Flags
M2 ... Meta 2
Context
L1 8B Identity
+ CRC-15
VAL? V Value
(opt)
TIME? T Time
(opt)
TASK? T Task
(opt)
NOTE? N Note
(opt)
Mode / Control Identity / Session (L1) Content / Value Time Fields Task / Action

BitLedger — 22+ Bytes

The complete double-entry frame. Meta bytes 1 and 2, Layer 1 (identity + CRC-15), Layer 2 batch header (6 bytes declaring currency, scaling factor, precision defaults, separator convention, rounding balance direction), an optional Session Config Extension (1–5 bytes for compound mode, nesting level, and opposing convention), and the 5-byte Layer 3 BitLedger record. Conservation is enforced at encoding: the batch balance check runs before the first byte of Layer 3 is written.

BitLedger Frame — full double-entry, conservation-enforced, CRC-15 covered
M1 1B Meta 1
M2 1B Meta 2
L1 8B Identity
CRC-15
SCE? 1-5B Session
Config
L3.1-2 DF Dir
Flag
L3.3-27 N Value
25 bits
L3.32-38 C7 CRC-7
L3
L3.39-40 ST Status
Bits
Mode / Control Identity / L1 Account / L2 Batch Value (L3) Integrity / Config Direction / Status

Invocation

Commands & Flags

All flags set fields in the 256-byte context block before dispatch. Flags are grouped by protocol layer. Absent flags leave context block fields at their default values (zero, which produces minimal valid output for that field).

Frame Selection
FlagValuesEffect
--type signal · wave · record · ledger Selects frame builder. Default: signal
signal

Calls build_signal.asm. Only Meta byte 1 is written. Total output: 1 byte.

wave

Calls build_wave.asm. Meta byte 1 + wave category byte. Total: 2–4 bytes depending on category.

record

Calls build_record.asm. Meta bytes 1+2, Layer 1, optional value/time/task/note. Total: 13–29 bytes.

ledger

Calls build_ledger.asm. All layers including L2 batch header and L3 BitLedger record. Total: 22+ bytes.

--output <filename.bp> Write frame bytes to named file. Creates or overwrites.
--stdout flag Write frame bytes to stdout (fd 1). Binary output.
--dry-run flag Route to hexdump.asm — print hex annotation to stdout, write nothing.
Meta Byte 1 — Mode and Control Flags
FlagValuesBit Position
--ack flag Sets bit 2 of Meta byte 1. Requests acknowledgement from receiver.
--priority flag Sets bit 5 (Role A). Receiver enters elevated handling mode.
--cipher flag Sets bit 6 (Role A). Declares rolling codebook cipher active.
--ext-flags flag Sets bit 7 (Role A). Declares extension byte follows.
--category 0x00xF Sets Wave byte category nibble (bits 1–4 of wave byte). Used with --type wave.
--wave-content 0x00xF Sets Wave byte content nibble (bits 5–8). Meaning is category-dependent.
Layer 1 — Session Identity
FlagValuesEffect
--sender-id 0x000000010xFFFFFFFF 32-bit flat sender identity. Written to Layer 1 bytes 1–4.
--domain 0x00xF 4-bit domain selector in Layer 1. Declares financial, engineering, or custom semantic layer.
--permissions 0x00xF 4-bit permission field in Layer 1. Read/write/admin/stream capability mask.
Layer 2 — Batch Header (BitLedger frames)
FlagValuesEffect
--currency 0x000xFF 8-bit currency/unit code in Layer 2. Declares denomination for all records in the session.
--scale 015 4-bit scaling factor D (decimal shift). Sets the decimal position for the batch.
--precision 015 4-bit precision P. Minimum significant digits declared for the batch.
--round-balance up · down · even Rounding balance direction. Sets 2-bit rounding mode field in Layer 2.
Layer 3 — BitLedger Record Value and Accounting
FlagValuesEffect
--mantissa 016383 Value mantissa A in the encoding formula N = A × 2^S + r

The CLI packs mantissa A and shift S into the 25-bit value field of Layer 3. A is the significant integer. S is the power-of-two scale. The encoded value N = A × 2^S satisfies the conservation invariant when summed across all records in a batch.

Use --mantissa with --shift to set both. For tier-1 (S=0), --mantissa alone suffices.

--shift 010 Value shift S. Sets the power-of-two multiplier. S=0 encodes N = A exactly.
--account-pair 0x00xE 4-bit account pair / flow archetype in Layer 3 bits 28–31. 0xF is reserved for compound mode continuation.
--debit flag Sets direction flag in Layer 3 bit 1 to debit. Mutually exclusive with --credit.
--credit flag Sets direction flag in Layer 3 bit 1 to credit.
--final flag Sets completeness flag in Layer 3 bit 2. Marks record as final, not provisional.
Optional Components — Time, Task, Note
FlagValuesEffect
--time-t1s <unix-seconds> Adds T1S time block (3 bytes). Compressed Unix timestamp to ~2-second resolution.
--time-t2 <unix-seconds> Adds T2 time block (4 bytes). Full Unix timestamp with sub-second precision nibble.
--task 0x000xFF Adds 2-byte task component. 8-bit task code declares the class of work.
--task-action 0x00xF 4-bit action nibble within the task component. Verb on the task code.
--note <bytes> Appends note block. Length-prefixed variable bytes of annotation.
--signal-slots 0x000xFF Sets signal slot presence byte (P1–P8 active flags). Enhancement C0 bytes at declared positions.

Example Invocations

# Pure Signal — 1 byte, ACK request
./bitpads --type signal --ack --output heartbeat.bp

# Wave — category 0x0 (plain value), content 0x5
./bitpads --type wave --category 0x0 --wave-content 0x5 --stdout

# Wave — category 0xC (compact command)
./bitpads --type wave --category 0xC --wave-content 0x1 --output cmd.bp

# Minimal Record — identity + value only
./bitpads --type record \
  --sender-id 0x00010001 \
  --domain 0x1 \
  --mantissa 500 --shift 0 \
  --output record-min.bp

# Record with time and task components
./bitpads --type record \
  --sender-id 0x00010001 \
  --domain 0x1 \
  --mantissa 1250 --shift 2 \
  --time-t2 1746748800 \
  --task 0x07 --task-action 0x1 \
  --output record-full.bp

# BitLedger frame — full double-entry
./bitpads --type ledger \
  --sender-id 0x00010001 \
  --domain 0x0 \
  --currency 0x01 --scale 2 --precision 4 --round-balance even \
  --mantissa 9999 --shift 0 \
  --account-pair 0x1 --debit --final \
  --output ledger.bp

# Dry-run — show hex annotation, write nothing
./bitpads --type ledger \
  --sender-id 0x00010001 \
  --mantissa 100 --shift 0 \
  --account-pair 0x1 --credit \
  --dry-run

Implementation Status

What Works

Taken directly from the project readme. The macOS CLI (assemblycli/) is functional and produces conformant output for all of the following:

  • Frame assembly for Pure Signal, Wave, Record, and BitLedger types
  • Layer 1 with CRC-15 embed — polynomial x^15 + x + 1 computed over session payload
  • Layer 2 batch headers — currency, scaling, precision, separator convention, rounding balance
  • Meta Byte 1 construction — mode, ACK, continuation, treatment, Role A/B flags
  • Meta Byte 2 construction — domain, permissions, component presence bits, enhancement flags
  • Value encoding across four tiers — mantissa and shift packing into 25-bit field
  • T1S time fields — 3-byte compressed Unix timestamp to ~2-second resolution
  • T2 time fields — 4-byte full timestamp with sub-second precision nibble
  • Task and note blocks — 2-byte task component and length-prefixed note block
  • C0 Enhancement Grammar signal slot presence byte — P1–P8 position flags
  • Telegraph, compact command, and context declaration Wave categories (1110, 1100, 1101)
  • File output — open / write / close syscalls to named .bp file
  • Stdout output — write syscall to fd 1, binary frame bytes
  • Dry-run output mode — hex-annotated dump to stdout via hexdump.asm

Implementation Status

Known Gaps

Taken directly from the project readme. These are the current open items in the implementation:

  • Signal slot content bytes are declared in the presence byte but are not yet written to the output buffer — the byte is set but the slot's content follows only as a stub
  • The 28-byte vs 22-byte footprint discrepancy in the spec needs resolution — the path from the 22-byte irreducible minimum to the spec's cited 28-byte figure depends on which Session Config Extension sub-fields are treated as mandatory
  • No formal byte-level test vectors exist — conformance is verified by manual inspection of hex dumps, not automated comparison against known-good outputs
  • No decoder — the CLI is encode-only; there is no tool to parse a .bp file back into human-readable fields
  • --help output is absent — there is no usage message; the flag list is documented here and in the project readme only

Binary Output

Output Formats

File Output — .bp

The default output mode. The CLI opens a file at the path given by --output, writes the frame bytes sequentially, and closes the file. The file contains raw binary — no header, no container, no framing. One frame per file in the current implementation. The receiver opens the file and reads from byte 0; the first byte is always Meta byte 1.

Stdout

With --stdout the CLI issues a write(1, outbuf, n) syscall and exits. The binary frame bytes stream to stdout. This allows the CLI to be piped into another tool or redirected to a file: ./bitpads --type signal --ack --stdout > pulse.bp.

Dry-Run Mode

With --dry-run the output buffer is routed to hexdump.asm instead of fileio.asm. Each byte is formatted as a two-digit hex value with a field annotation showing which protocol field it belongs to. Nothing is written to disk.

Hex Dump — Pure Signal (1 byte)

── DRY RUN · Pure Signal · --ack ────────────────────────────
Byte 00 0x40 0100 0000 Meta byte 1 — Wave mode, ACK request, basic treatment
── END FRAME · 1 byte ───────────────────────────────────────

Hex Dump — Minimal BitLedger Frame (22 bytes)

── DRY RUN · BitLedger · sender=0x00010001 · A=100 S=0 ──────
Byte 00 0x81 1000 0001 Meta byte 1 — Record mode, complete, basic, no ext
Byte 01 0x10 0001 0000 Meta byte 2 — domain 0x1, L2 present, L3 present
Byte 02 0x00 0000 0000 Layer 1 — Sender ID byte 1 (network)
Byte 03 0x01 0000 0001 Layer 1 — Sender ID byte 2 (system)
Byte 04 0x00 0000 0000 Layer 1 — Sender ID byte 3 (node high)
Byte 05 0x01 0000 0001 Layer 1 — Sender ID byte 4 (node low)
Byte 06 0x10 0001 0000 Layer 1 — domain nibble + permissions nibble
Byte 07 0x00 0000 0000 Layer 1 — CRC-15 high byte (7 bits + MSB of CRC low)
Byte 08 0xC4 1100 0100 Layer 1 — CRC-15 low byte + reserved 1-bit
Byte 09 0x01 0000 0001 Layer 2 — currency code (0x01 = USD)
Byte 0A 0x24 0010 0100 Layer 2 — scale D=2, precision P=4
Byte 0B 0x00 0000 0000 Layer 2 — separator convention, flags
Byte 0C 0x00 0000 0000 Layer 2 — rounding balance + reserved
Byte 0D 0x00 0000 0000 Layer 2 — batch sequence high
Byte 0E 0x01 0000 0001 Layer 2 — batch sequence low
Byte 0F 0x02 0000 0010 Layer 3 byte 1 — direction=debit (bit1=1), compl=final (bit2=1), value MSB
Byte 10 0x00 0000 0000 Layer 3 byte 2 — value field (N=100, packed A=100 S=0)
Byte 11 0x64 0110 0100 Layer 3 byte 3 — value field low (0x64 = 100 decimal)
Byte 12 0x10 0001 0000 Layer 3 byte 4 — account pair 0x1 (debit/credit), CRC-7 high
Byte 13 0xE2 1110 0010 Layer 3 byte 5 — CRC-7 low + status bits (direction mirror)
── END FRAME · 20 bytes L1+L2+L3 + 2 Meta ──────────────────
Conservation check: single-record batch, balance deferred to batch close.

Encoding Formula

Value Encoding

Every value in the protocol encodes as a scaled integer. No floating point anywhere.

The encoding formula is N = A × 2S + r, where A is the integer mantissa, S is the power-of-two shift, and r is the rounding remainder. The 25-bit field in Layer 3 packs A and S; r is declared separately by the rounding balance flag. Every integer from 0 to 33,554,431 (225 − 1) is exactly reachable with S = 0. For larger values, S increases the effective range at the cost of resolution.

N = A × 2S + r
A = integer mantissa · S = power-of-two shift · r = rounding remainder (0 or 1, declared by flag)

Encoding Tiers

Tier 1
S = 0

Exact integers. A directly encodes the value. Maximum A = 33,554,431. Use for values up to ~33.5M in the session's base denomination.

--mantissa 100 --shift 0
→ N = 100
Tier 2
S = 1–3

Small multiplier. Doubles, quadruples, or octuples A. Useful for even values where resolution in the low bit is not needed.

--mantissa 500 --shift 2
→ N = 2000
Tier 3
S = 4–7

Medium multiplier. Effective range extends to ~500M–4B. Resolution coarsens proportionally. Rounding flag becomes significant.

--mantissa 8191 --shift 5
→ N = 262,112
Tier 4
S = 8–10

Large multiplier. Maximum S = 10 gives A × 1024. At A = 32,767 and S = 10, N ≈ 33.5B. Protocol maximum for a single record.

--mantissa 32767 --shift 10
→ N = 33,553,408
Value Encoding Calculator — N = A × 2^S + r
Formula 100 × 2^0 + 0

Encoded value N 100
Hex 0x00000064
Binary (25-bit field) 0 0000 0000 0000 0110 0100

CLI flags --mantissa 100 --shift 0
Range check Within 25-bit field

Integrity Mechanism

CRC-15 Implementation

The CRC-15 is computed by src/crypto/crc15.asm over the session payload in Layer 1. The polynomial is x15 + x + 1 — a degree-15 polynomial with Hamming distance 4 for frame lengths up to 32,767 bits. This polynomial detects all burst errors of 15 bits or fewer, all single-bit errors, all double-bit errors, and all errors of odd bit count.

Algorithm

The implementation is register-based with no lookup table. A 16-bit CRC register (initialised to all-ones) is loaded before the session payload bytes are processed. For each byte in the session payload, each bit is processed from MSB to LSB. On each bit: the input bit is XORed with the current MSB of the register; if the result is 1, the register is shifted left one position and XORed with the polynomial mask 0x8003 (representing x15 + x + 1 in bit-reflection form); otherwise the register is shifted left only. After all payload bits are processed, the register holds the 15-bit CRC. The CRC is embedded in Layer 1 bytes 7–8 (15 bits, 1 reserved).

── CRC-15 WORKED EXAMPLE ─────────────────────────────────────
Polynomial x^15 + x + 1 = 0x8003
Init register 0x7FFF (all 15 bits set)
──
Session payload:
Byte 0 0x00 sender ID network byte
Byte 1 0x01 sender ID system byte
Byte 2 0x00 sender ID node high
Byte 3 0x01 sender ID node low
Byte 4 0x10 domain + permissions nibbles
──
Processing byte 0x01 (bit 7→0):
bit=0: MSB XOR 0 = 0 → shift left only CRC = 0x7FFE
bit=0: MSB XOR 0 = 0 → shift left only CRC = 0x7FFC
... ...
bit=1: MSB XOR 1 = 1 → shift + XOR 0x8003 CRC flips two bits
──
Final CRC-15 example: 0x18C4
Layer 1 byte 7 0 001 1000 bits [14:8] of CRC + reserved bit (1)
Layer 1 byte 8 1100 0100 bits [7:0] of CRC = 0xC4
────────────────────────────────────────────────────────────
Receiver recomputes CRC over same payload bytes.
CRC mismatch → session rejected before L2 or L3 is processed.
────────────────────────────────────────────────────────────

Why no lookup table: A table-driven CRC requires a 256-entry × 2-byte table in data memory — feasible in a standard runtime but non-trivial in a no-heap, stack-only assembly environment where memory layout is explicit. The register-based bit iterator uses two registers and a branch per bit. For sessions where the payload is 5 bytes (40 bits), the loop runs exactly 40 iterations — a fixed, auditable cost.

Development Status

Roadmap

The following items represent the current development boundary. Protocol specifications are versioned and stable. The implementation gaps below are implementation work, not specification changes.

01
Signal Slot Content Bytes

The signal slot presence byte is written correctly — declaring which of P1–P13 are active in this frame. The content bytes that should follow at those positions are not yet written. The gap is implementation, not specification: the slot positions and content formats are fully defined.

02
22 vs 28 Byte Footprint

The spec's footprint table cites 28 bytes for a full BitLedger frame. The named components sum to 22 bytes. The path to 28 runs through which Session Config Extension sub-fields (compound mode marker, nesting level declaration, opposing convention extension) are treated as mandatory for a given session configuration. This needs a normative decision in the spec before the CLI can enforce it.

03
Linux Port

The Linux ELF64 build (linux_assembly_cli/) has been assembled but not linked or executed on a Linux machine. The primary difference is the syscall convention: Linux uses syscall with rax/rdi/rsi/rdx registers; macOS uses the Mach trap interface. The protocol logic is identical — only the I/O layer changes.

04
--help Output

The CLI currently has no usage message. Running ./bitpads without arguments produces no output. The flag documentation exists in this page and in the project readme. A --help flag is straightforward to add — it is a data section of ASCII bytes and a single write(1, help_str, len) syscall.

05
Byte-Level Test Vectors

No formal test vectors exist. Conformance is verified by manual inspection of --dry-run hex output. A test vector file — known-good hex outputs for each frame type with known inputs — would enable automated regression testing and provide a reference for decoder implementors.

06
Decoder

The CLI is encode-only. There is no tool to parse a .bp file back into human-readable fields. A decoder would complete the round-trip and enable automated conformance testing: encode a frame, decode it, compare field values to the input flags. The decoder is the natural next major component after the encoder is feature-complete.