summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorinfo@mode42.com <info@mode42.com>2026-08-07 18:25:13 +0000
committerinfo@mode42.com <info@mode42.com>2026-08-07 18:25:13 +0000
commit04d965d67a7264a1c7c211494aebda1953df7603 (patch)
tree0ebd700a6e219f84a26a656f4bee8778bc75da7b /docs
Initial push
Diffstat (limited to 'docs')
-rw-r--r--docs/ARCHITECTURE.md40
-rw-r--r--docs/AX25-NATIVE-CODEC.md33
-rw-r--r--docs/BAYCOM-FREEZES.md40
-rw-r--r--docs/BAYCOM.md52
-rw-r--r--docs/CRDOP.md44
-rw-r--r--docs/DEV/README.md9
-rw-r--r--docs/DEV/TMODEM-C1224.md40
-rw-r--r--docs/DEV/TNC-MODEM-DEV.md191
-rw-r--r--docs/DEVELOPMENT.md38
-rw-r--r--docs/FREEBSD-AX25.md34
-rw-r--r--docs/HARDWARE-ACCEPTANCE.md38
-rw-r--r--docs/HYBBX.md44
-rw-r--r--docs/LINUX-HOST-SETUP.md48
-rw-r--r--docs/MASTER-GUIDE.md264
-rw-r--r--docs/MAX25-CLIENT.md36
-rw-r--r--docs/MAX25-OPERATOR-RUNBOOK.md105
-rw-r--r--docs/MAX25-TERMINAL.md95
-rw-r--r--docs/MERGE-REPORT.md36
-rw-r--r--docs/MODULAR-TCPIP-SERVER.md33
-rw-r--r--docs/NETDEV.md27
-rw-r--r--docs/PACKET-RADIO.md46
-rw-r--r--docs/PATHS.md46
-rw-r--r--docs/PLATFORMS.md34
-rw-r--r--docs/PLUGINS-DEVICE-MODEL.md36
-rw-r--r--docs/README.md40
-rw-r--r--docs/TX-RX-TEST.md137
-rw-r--r--docs/V1.0.0-SCOPE.md42
-rw-r--r--docs/V2.0.0-SCOPE.md35
-rw-r--r--docs/WEBSOCKET.md129
29 files changed, 1792 insertions, 0 deletions
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
new file mode 100644
index 0000000..a1dc291
--- /dev/null
+++ b/docs/ARCHITECTURE.md
@@ -0,0 +1,40 @@
+# Architecture · MAX25-Stack 1.8.0
+
+Main AX.25 Stack — standalone packet-radio with HyBBX-compatible plugin boundaries.
+
+## Layer model matrix
+
+| Layer | Examples |
+|-------|----------|
+| Terminal | `max25-terminal`, `max25-client` |
+| Daemon | `max25d` — M25/1, plugin lifecycle |
+| Operating mode | `standalone`, `service`, `hybbx-host` |
+| Hardware | `tncs`, `modems`, `soft-modems` |
+| Device | `tnc2c`, `max25e0`, `soft-crdop` |
+| Protocol | KISS, kernel hdlcdrv, CRDOP M25 host |
+
+## DEV-Level matrix
+
+| DEV-Level | Focus |
+|-----------|-------|
+| DEV-Level 1 (current) | Modular TCP/IP, Linux+FreeBSD compat, `max25d0` |
+| DEV-Level 2 | Main+Secondary supervision, `max25-tun` |
+| DEV-Level 3 | WebSocket gateway |
+| DEV-Level 4 | CRDOP expansion |
+| Later | AI/assistant — deferred |
+
+## Platform split matrix
+
+| Component | Linux | FreeBSD |
+|-----------|-------|---------|
+| `max25d` + RF (TNC/BayCom) | yes | scaffold |
+| `max25-terminal` | yes | yes (remote) |
+| CRDOP | ALSA | OSS |
+| Kernel BayCom `bcsf0` | yes | no |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Platforms | [PLATFORMS.md](PLATFORMS.md) |
+| v2 scope | [V2.0.0-SCOPE.md](V2.0.0-SCOPE.md) |
diff --git a/docs/AX25-NATIVE-CODEC.md b/docs/AX25-NATIVE-CODEC.md
new file mode 100644
index 0000000..a865e9c
--- /dev/null
+++ b/docs/AX25-NATIVE-CODEC.md
@@ -0,0 +1,33 @@
+# AX.25 native codec · MAX25-Stack 1.8.0
+
+In-tree userspace AX.25 encode/decode — no kernel AX.25 required for max25d.
+
+## Component matrix
+
+| Module | Role |
+|--------|------|
+| `ax25_codec.py` | Address encode/decode, FCS |
+| `kiss_bridge.py` | KISS frame wrap/unwrap |
+| `banlist.py` | Source address ban list |
+
+## Build matrix
+
+| Option | Default | Effect |
+|--------|---------|--------|
+| `MAX25_BUNDLE_AX25` | OFF | Vendored ax25-apps tarballs reference-only |
+| In-tree codec | always | Used by max25d and terminal |
+
+## FCS matrix
+
+| Direction | Rule |
+|-----------|------|
+| To TNC (KISS DATA) | FCS stripped |
+| From TNC (RX) | FCS validated in codec |
+| UI frames | Built in terminal or HyBBX attach path |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Packet radio | [PACKET-RADIO.md](PACKET-RADIO.md) |
+| Hardware acceptance | [HARDWARE-ACCEPTANCE.md](HARDWARE-ACCEPTANCE.md) |
diff --git a/docs/BAYCOM-FREEZES.md b/docs/BAYCOM-FREEZES.md
new file mode 100644
index 0000000..5b63e81
--- /dev/null
+++ b/docs/BAYCOM-FREEZES.md
@@ -0,0 +1,40 @@
+# BayCom/based — host freeze warning (RX / TX)
+
+**MAX25-Stack** · **BayCom/based** SER12 class (PC-COM / TCM3105)
+
+**Status:** BayCom/based is **available · usable** (default build ON). This page documents **freeze risk** on some hosts — especially legacy kernel paths and EMI near interactive desktops. Current product uses userspace **max25-bcpr**.
+
+> **Warning:** On some hosts (especially interactive desktops), **RX and TX** with BayCom/based PC-COM-class hardware can **hard-freeze** or soft-hang the machine — historically observed with kernel `baycom_ser_fdx`. Treat SQ-open / strong RF / USB HID hubs as risk.
+
+## Freeze classes
+
+| Class | Typical trigger | Radio needed? |
+|-------|-----------------|---------------|
+| **TX / calibrate (legacy kernel)** | `baycom_test calibrate N`, HDLC calibrate ioctl | **No** — observed with radio **off** |
+| **RX / RF EMI** | Peer packet TX / strong RF near the PC; USB HID dropout (`EMI?` in `dmesg`) | Over-air RF; can freeze **even if** no modem driver is loaded |
+| Soft hang | High UART IRQ bitbang load; brief input/USB stall | Often radio off |
+
+Kernel `baycom_ser_fdx` / `baycom-pr` was **removed** from this tree (2026-07-18). Do **not** reintroduce calibrate against `bcsf*` on interactive desktops.
+
+## Forbidden / high risk on interactive desktops
+
+| Do not | Why |
+|--------|-----|
+| Load `baycom_ser_fdx` / run calibrate helpers | Instant hard freeze observed on interactive hosts |
+| Hot-plug radio/mic cables while any path owns the UART | Freeze risk |
+| Leave stack up unattended next to live RF | EMI class |
+
+## Safer practice (experimental opt-in only)
+
+| Do | Notes |
+|----|--------|
+| Prefer a **dedicated / minimal** host when RF is strong | Reduces EMI freeze class on interactive desktops |
+| Unplug AF / power radio off when not testing | Reduces EMI class |
+| Move keyboard/mouse to motherboard USB ports | Avoid front/shared hubs near RF |
+
+## Related
+
+| Topic | Path |
+|-------|------|
+| BayCom/based status | [BAYCOM.md](BAYCOM.md) |
+| Unified TX/RX release test | [TX-RX-TEST.md](TX-RX-TEST.md) · `scripts/tx-rx-test.sh` |
diff --git a/docs/BAYCOM.md b/docs/BAYCOM.md
new file mode 100644
index 0000000..ed6e334
--- /dev/null
+++ b/docs/BAYCOM.md
@@ -0,0 +1,52 @@
+# BayCom/based · MAX25-Stack
+
+Public mark: **BayCom/based**. Product path: **max25-bcpr** (daemon **max25-bcprd**, ctl **max25-bcpr-ctl**). Host device: **`max25e0`** (forks `max25e0:bcN` only).
+
+## Status: available and usable
+
+| Fact | Value |
+|------|--------|
+| Product status | **Available** — shipped operator path with HyBBX co-host |
+| Default build | `MAX25_BUILD_MAX25_BCPR=ON` |
+| Device id | **`max25e0`** only |
+| KISS release | **`/tmp/max25-bcpr/kiss-bc0`** — HyBBX opens after max25d prep |
+| Attach modes | `hybbx-host` · `hybbx-main` · `hybbx-cohost` — max25d releases KISS to HyBBX |
+| Host addresses | IPv4 `127.0.0.25/8`, IPv6 `::25/128` (defaults; overridable in `max25d.ini`) |
+| Kernel path | `baycom_ser_fdx` / `baycom-pr` **removed** — userspace **max25-bcpr** only |
+
+## Start (with HyBBX co-host)
+
+```bash
+# max25d with mode=hybbx-cohost and [features] max25_bcpr=yes
+./scripts/run-max25d.sh
+ls -la /tmp/max25-bcpr/kiss-bc0 # KISS PTY after max25-bcpr ready
+# then HyBBX with [networks] baycom=yes, device=/tmp/max25-bcpr/kiss-bc0
+```
+
+Example INI: `share/max25-bcpr/max25-bcpr.ini.example` · `share/hybbx/hybbx-standalone.ini.example` (HyBBX repo).
+
+## Operator rules
+
+| Rule | Detail |
+|------|--------|
+| RX before TX | Prove RX (Soft-DCD / decode) before live TX |
+| Serial ownership | One process per UART — max25d prep then HyBBX attach |
+| HyBBX user | Must be in group `dialout` for KISS PTY |
+
+Development freeze notes: [BAYCOM-FREEZES.md](BAYCOM-FREEZES.md) — not part of normal operator path.
+
+## Build
+
+```bash
+cmake -B build -DMAX25_BUILD_MAX25_BCPR=ON # default ON in release preset
+cmake --build build --target max25-bcprd max25-bcpr-ctl
+```
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Device model | [PLUGINS-DEVICE-MODEL.md](PLUGINS-DEVICE-MODEL.md) |
+| TX/RX test | [TX-RX-TEST.md](TX-RX-TEST.md) |
+| HyBBX attach | HyBBX [docs/BAYCOM.md](../../hyBBX/docs/BAYCOM.md) |
+| TNC / modem bring-up | [DEV/TNC-MODEM-DEV.md](DEV/TNC-MODEM-DEV.md) |
diff --git a/docs/CRDOP.md b/docs/CRDOP.md
new file mode 100644
index 0000000..927f2f2
--- /dev/null
+++ b/docs/CRDOP.md
@@ -0,0 +1,44 @@
+# CRDOP / MAX25-SoftModem · MAX25-Stack 1.8.0
+
+In-house sound-card modem — acoustically AX.25-compatible AFSK.
+
+## Status matrix
+
+| Item | Value |
+|------|-------|
+| Device id | `soft-crdop` |
+| Build | `MAX25_BUILD_CRDOP=ON` default |
+| Phase | development and test |
+| Speed | 1200 bd primary, max 19200 bd |
+| Duplex | half and full |
+| Audio | ALSA direct — no PulseAudio |
+
+## Port matrix
+
+| Port | Role |
+|------|------|
+| 8515 | control (M25 host protocol) |
+| 8516 | data |
+| 7325 | max25d M25/1 (operator IPC) |
+
+## Platform matrix
+
+| Host | CRDOP role |
+|------|------------|
+| Linux | RF backend in max25d |
+| FreeBSD | primary softmodem path (OSS) |
+
+## Start matrix
+
+| Step | Command |
+|------|---------|
+| Build | `./scripts/build.sh` |
+| Start | `max25-ctl start --hardware soft-modems --device soft-crdop` |
+| HyBBX | merge `share/hybbx/crdop-host.ini.example` |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Audio architecture | `stacks/crdop/docs/AUDIO-ARCHITECTURE.md` |
+| HyBBX | [HYBBX.md](HYBBX.md) |
diff --git a/docs/DEV/README.md b/docs/DEV/README.md
new file mode 100644
index 0000000..3aa5770
--- /dev/null
+++ b/docs/DEV/README.md
@@ -0,0 +1,9 @@
+# Development docs · MAX25-Stack
+
+Pure **development** material lives under `docs/DEV/`.
+
+Operator-facing / release manuals stay in `docs/` (and README). Full doc rewrite later — until then, put new bring-up / recovery / internal how-to notes here.
+
+| Doc | Role |
+|-----|------|
+| [TNC-MODEM-DEV.md](TNC-MODEM-DEV.md) | TNC + BayCom/based KISS bring-up, software-first recovery |
diff --git a/docs/DEV/TMODEM-C1224.md b/docs/DEV/TMODEM-C1224.md
new file mode 100644
index 0000000..6b40968
--- /dev/null
+++ b/docs/DEV/TMODEM-C1224.md
@@ -0,0 +1,40 @@
+# T-Modem-c1224 — max25d device (`tmodem`)
+
+**AS-IS** · prototype · English only.
+
+## Role
+
+[T-Modem-c1224](https://github.com/ngteq/T-Modem-c1224) Pico firmware presents **USB CDC KISS** (half-TNC: HDLC on Pico, AFSK on TCM3105-class chip). max25d talks **raw KISS** on `/dev/ttyACM*` — same family as `kiss-raw-serial` / `baycom-kiss` serial path, but **not** BayCom/based and **not** SER12.
+
+## Enable
+
+```ini
+[features]
+tmodem = yes
+
+[devices]
+default = tmodem
+tmodem = /dev/ttyACM0
+
+[serial.tmodem]
+baud = 115200
+line = 8n1
+dtr_rts = no
+```
+
+Example file: `share/max25/max25d.tmodem.ini.example`.
+
+## Terminal
+
+```bash
+max25-terminal -d tmodem
+# or SET DEVICE tmodem after connect
+```
+
+## RX before TX
+
+Any on-air smoke: prove RX (noise / Soft-DCD / decode) before live TX. See `scripts/tx-rx-test.sh` and vault §0.20.
+
+## HyBBX
+
+Attach-only via a running max25d with `tmodem` enabled. No T-Modem L1 inside HyBBX.
diff --git a/docs/DEV/TNC-MODEM-DEV.md b/docs/DEV/TNC-MODEM-DEV.md
new file mode 100644
index 0000000..e547d0f
--- /dev/null
+++ b/docs/DEV/TNC-MODEM-DEV.md
@@ -0,0 +1,191 @@
+# TNC / Modem bring-up · MAX25-Stack
+
+English bring-up for **TNCs** (HDLC + KISS on host serial) and **BayCom/based** modems (bits↔AFSK + PTT; host owns HDLC). Applies to MAX25-Stack and to any stack that attaches the same hardware classes.
+
+---
+
+## 1. Roles — TNC vs modem
+
+| Class | What it is | Host owns | Typical face |
+|-------|------------|-----------|--------------|
+| **TNC** (TNC2C, PK-TNC2, TNC2multi, …) | Firmware does HDLC; host talks **command mode** then **KISS** on UART | Serial lifecycle, recovery, KISS entry | `tnc2c`, `pktnc2`, … |
+| **BayCom/based** modem | Board is **modem-only** (TCM3105-class AFSK + PTT) | HDLC, SER12 bit clock, KISS PTY, PTT | **`max25e0`** (bcpr) |
+| Soft-modem (CRDOP) | Soundcard AFSK | Audio + soft HDLC | `soft-crdop` |
+
+```text
+TNC path: Radio AF ↔ TNC (HDLC+modem) ↔ UART KISS ↔ host stack
+Modem path: Radio AF ↔ BayCom/based chip ↔ SER12 UART ↔ host HDLC (bcpr) ↔ KISS
+```
+
+Do **not** treat a BayCom/based board as a TNC. Do **not** open the same `/dev/tty*` from two processes.
+
+---
+
+## 2. KISS bring-up (any stack)
+
+### 2.1 Serial ownership
+
+| Rule | Why |
+|------|-----|
+| **One opener** per UART | Dual openers → garbled RX, failed recovery, flaky KISS |
+| Hold **DTR+RTS high** while the port is owned | Landolt TNC2C terminal detect needs DTR high at power-on; drop on close → echo-only |
+| Match **baud / line** to hardware | Wrong baud → garbage or echo only |
+
+| Device class (typical) | Baud | Line | Notes |
+|------------------------|------|------|-------|
+| Landolt TNC2C | **19200** | 8N1 | Not 4800/9600/7E1 |
+| PK-TNC2 / many TF boards | **9600** | 8N1 | Profile-dependent |
+| BayCom/based SER12 | UART clocked by host SER12 | — | Product path: **max25-bcpr**, not kernel `baycom_ser_fdx` |
+
+### 2.2 Command sequence (TheFirmware / TNC-2 class)
+
+| Step | Action |
+|------|--------|
+| 1 | Free the port (`pkill` stray terminals; one stack owns the fd) |
+| 2 | Open UART with DTR+RTS high; settle ~2 s |
+| 3 | Reach **terminal / host command mode** (banner / `cmd:`) — see recovery below |
+| 4 | Set callsign / radio params as required by firmware |
+| 5 | Enter KISS: TheFirmware **ESC `@K`** (`0x1B 40 4B`); legacy TAPR `kiss on` only as fallback |
+| 6 | Keep the **same process** owning the port for KISS DATA |
+
+KISS exit (if needed): `kiss off`, or frame `0xC0 0xFF 0xC0`, or firmware `RESTART`.
+
+### 2.3 Boot-wait (cold start)
+
+After mains loss or cold power without DTR, some boards (notably Landolt TNC2C) need **boot-wait with DTR high during power-on**:
+
+```bash
+cd stacks/tncs
+./tnc2c-boot-wait.sh /dev/ttyS4 # keep script open; power OFF 10s → ON
+# then start the stack immediately so DTR stays high
+```
+
+Quiet AF / closed squelch (CD off) during boot improves banner reliability.
+
+---
+
+## 3. Power-cycle history — and the correct path
+
+| Era | Practice | Status |
+|-----|----------|--------|
+| Former | Power-cycle + boot-wait for almost every KISS/host recovery | Still valid as **rescue** |
+| Root cause (hardware) | Landolt: DTR must be high **at** power-on; late open → echo/transparent | Not fully soft-fixable |
+| Root cause (host) | Recovery answers lost if an RX thread races the drain; no escalation to boot-wait | Fixed / mitigated in product recovery path |
+| Correct default | **Software recovery ladder first**; power-cycle only if echo-only after ladder | Prefer `tnc_serial_recovery` / `tnc2c-host-reset` |
+
+### Software-first ladder (summary)
+
+1. DTR+RTS high, passive listen
+2. KISS return `0xC0 0xFF 0xC0`
+3. JHOST 0 flush (`^Q^X` + nulls + `JHOST 0`)
+4. ESC `V` / ESC `QRES` (software cold boot; DTR stays high)
+5. Legacy `kiss off` + `INFO` (last resort)
+6. KISS entry ESC `@K`
+
+Success markers: `TheFirmware`, `NORD`, `Version 2.7`, `Checksum`, `cmd:`.
+
+| If… | Then… |
+|-----|--------|
+| Ladder fails → echo only | `./tnc2c-boot-wait.sh` + power OFF→ON with DTR held |
+| Standalone reset OK, stack FAIL | Check dual openers / RX race / start order |
+| After boot-wait | Start stack **immediately** (avoid DTR drop gap) |
+
+Detail: `stacks/tncs/docs/TNC-RECOVERY.md`.
+
+---
+
+## 4. Common failure modes
+
+| Symptom | Likely cause | Fix |
+|---------|--------------|-----|
+| Garbage / no banner | Wrong baud or 7E1 | Match profile (e.g. TNC2C **19200 8N1**) |
+| Echo only (`INFO`→`INFO`) | No terminal mode; DTR missed at power-on | Recovery ladder → else boot-wait + power-cycle |
+| Binary noise, no commands | Stuck in KISS | KISS return frame or `kiss off` |
+| Intermittent recovery | Second process on same tty | One owner; kill minicom/`fuser` |
+| Silent TX after good session (modem) | **Stale KISS PTY** (max25-bcprd recycled outside max25d) | Restart **max25d only** (`auto_start` owns max25-bcprd) |
+| TX blocked with Soft-DCD busy | `fulldup=no` + Soft-DCD holds channel | Bench: `fulldup=yes`; production CSMA prove-out later |
+| Closed squelch ≠ TX fail | No RX noise does not prove PTT failure | Separate MCR/keying from mic wiring |
+
+---
+
+## 5. MAX25-Stack
+
+### 5.1 Paths
+
+| Path | Role |
+|------|------|
+| **TNC** | `stacks/tncs/` · devices `tnc2c` / `pktnc2` / … · KISS-serial backend |
+| **BayCom/based** | `stacks/max25-bcpr/` · `[features] max25_bcpr=yes` · device **`max25e0`** |
+| **CRDOP** | `stacks/crdop/` · soft-modem (out of scope here beyond role table) |
+
+### 5.2 Device face `max25e0`
+
+| Surface | Name |
+|---------|------|
+| Product device id | **`max25e0`** |
+| INI mapping | `max25e0 = max25-bcpr:bc0` (right side = **backend:port tag**, not product id) |
+| Multi-dev | Always forks **`max25e0:bcN`** |
+| Forbidden ids | `bcpr`, `bcpr-bc0`, `bcpr-bc1`, any `bcpr-*` as product face |
+| `max25e*` family | **MAX25-Stack only** |
+
+### 5.3 Start
+
+```bash
+# Feature (site or ./local — never commit live secrets)
+# [features]
+# max25_bcpr = yes
+#
+# [devices]
+# max25e0 = max25-bcpr:bc0
+
+./scripts/run-max25d.sh # escalates root only when ttyS/USB/SER12 needs it
+./scripts/run-max25-terminal.sh -U /run/max25/modem.sock
+```
+
+| Rule | Value |
+|------|-------|
+| Preferred ownership | **max25d** starts/stops max25-bcprd (`auto_start`) |
+| Do not | Recycle `max25-bcprd` under a live max25d (stale PTY) |
+| Root | **Only when necessary** (SER12 / ioperm / `/dev/port` / ttyS bind) — TCP/unix-only may stay unprivileged |
+| Drop | After privileged init, drop to `[daemon] user=` / `group=` when set |
+
+Site INI examples: `/etc/max25/max25d.ini`, `/etc/max25/max25-bcpr.ini`. Tree secrets: `./local/`.
+
+### 5.4 RX before TX (live RF)
+
+Prove **RX** before live **`--tx`** / on-air SEND:
+
+| Class | RX proof |
+|-------|----------|
+| BayCom/based | Soft-DCD / noise activity or decoded KISS RX |
+| TNC | CONNECT + STATUS (RX ready) before SEND |
+| Offline L0 | Encode/decode without PTT — allowed |
+
+`--force-tx` is debug-only. See [TX-RX-TEST.md](docs/TX-RX-TEST.md).
+
+### 5.5 Minimal matrices (no duplication)
+
+| Goal | Doc |
+|------|-----|
+| Day-to-day ops | [MAX25-OPERATOR-RUNBOOK.md](docs/MAX25-OPERATOR-RUNBOOK.md) |
+| BayCom/based / bcpr | [BAYCOM.md](docs/BAYCOM.md) · [BAYCOM-FREEZES.md](docs/BAYCOM-FREEZES.md) |
+| Linear operator guide | [MASTER-GUIDE.md](docs/MASTER-GUIDE.md) |
+| TNC software recovery | [stacks/tncs/docs/TNC-RECOVERY.md](stacks/tncs/docs/TNC-RECOVERY.md) |
+| Device model | [PLUGINS-DEVICE-MODEL.md](docs/PLUGINS-DEVICE-MODEL.md) |
+| Doc index | [docs/README.md](docs/README.md) |
+
+---
+
+## 6. Quick decision tree
+
+```text
+Need KISS on a UART TNC?
+├─ Port free + correct baud?
+│ └─ no → fix ownership / baud
+├─ Terminal / cmd: present?
+│ ├─ no → software recovery ladder
+│ │ └─ still echo only → boot-wait + power-cycle (DTR high)
+│ └─ yes → ESC @K (or profile kiss entry) → keep one owner
+└─ BayCom/based?
+ └─ [features] max25_bcpr=yes · max25e0 · run-max25d.sh · RX proof → then TX
+```
diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md
new file mode 100644
index 0000000..4a602ea
--- /dev/null
+++ b/docs/DEVELOPMENT.md
@@ -0,0 +1,38 @@
+# Development · MAX25-Stack 1.8.0
+
+Contributor build, test, and repository layout.
+
+## Workflow matrix
+
+| Step | Command |
+|------|---------|
+| Build | `./scripts/build.sh` |
+| Test | `./scripts/test.sh` |
+| Release check | `./scripts/release-check.sh` |
+| Plugin discovery | `./scripts/discover-plugins.sh --json` |
+
+## CMake matrix
+
+| Option | Default |
+|--------|---------|
+| `MAX25_BUILD_CRDOP` | ON |
+| `MAX25_BUNDLE_AX25` | OFF |
+
+## Layout matrix
+
+| Path | Content |
+|------|---------|
+| `stacks/daemon/` | max25d |
+| `stacks/terminal/` | max25-terminal |
+| `stacks/tncs/` | TNC tools |
+| `stacks/max25-bcpr/` | BayCom/based userspace SER12 (bcpr) |
+| `stacks/crdop/` | SoftModem |
+| `plugins/` | manifest + betriebsform |
+| `share/` | INI examples |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Paths | [PATHS.md](PATHS.md) |
+| Architecture | [ARCHITECTURE.md](ARCHITECTURE.md) |
diff --git a/docs/FREEBSD-AX25.md b/docs/FREEBSD-AX25.md
new file mode 100644
index 0000000..eb762e7
--- /dev/null
+++ b/docs/FREEBSD-AX25.md
@@ -0,0 +1,34 @@
+# FreeBSD AX.25 port · MAX25-Stack 1.8.0
+
+FreeBSD platform plan — no native kernel AX.25; userspace KISS/M25/1 only.
+
+## Platform matrix
+
+| Component | FreeBSD |
+|-----------|---------|
+| `max25d` + TNC/BayCom RF | scaffold (Linux-first v1) |
+| `max25-terminal` | yes — remote to Linux `:7325` |
+| CRDOP / OSS | yes — primary softmodem path |
+| Kernel BayCom | no |
+
+## Split deployment matrix
+
+| Role | Typical host |
+|------|--------------|
+| FreeBSD Main | TCP/IP hub + CRDOP |
+| Linux Secondary | TNC / BayCom RF backend |
+
+## Scaffold matrix (v1.8.0)
+
+| Item | Path |
+|------|------|
+| Platform detection | `max25_platform.py` |
+| OSS sound-proxy | CRDOP stack |
+| INI example | `share/max25/max25d.freebsd.ini.example` |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Platforms | [PLATFORMS.md](PLATFORMS.md) |
+| CRDOP | [CRDOP.md](CRDOP.md) |
diff --git a/docs/HARDWARE-ACCEPTANCE.md b/docs/HARDWARE-ACCEPTANCE.md
new file mode 100644
index 0000000..3d329b8
--- /dev/null
+++ b/docs/HARDWARE-ACCEPTANCE.md
@@ -0,0 +1,38 @@
+# Hardware acceptance · MAX25-Stack 1.8.0
+
+Manual RF acceptance criteria for release tagging.
+
+## Smoke test matrix
+
+| Device | Pass criterion |
+|--------|----------------|
+| `tnc2c` | UART boot-wait + KISS + decode at remote |
+| `max25e0` | bcpr SER12 + PTT + on-air |
+| `soft-crdop` | ALSA loopback or acoustic bench (optional for tag) |
+
+## Offline test matrix
+
+| Test | Scope |
+|------|-------|
+| `release-check.sh` | repo consistency |
+| `scripts/tx-rx-test.sh` (L0) | TX/RX host paths — TNC + BayCom/based (bcpr) |
+| `test_crdop_backend.py` | CRDOP backend |
+| `test_bell202_line_code.py` | modem line code |
+| `max25_test` target | offline smoke (includes `max25_tx_rx_test`) |
+
+Live TX/RX (`--live` / `--tx`): see [TX-RX-TEST.md](TX-RX-TEST.md) — not CI.
+
+## Blocker matrix
+
+| Gate | v1.8.0 status |
+|------|---------------|
+| CI offline gates | pass target |
+| Manual TNC RF | operator pending |
+| Manual BayCom RF | operator pending |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Release readiness | [../RELEASE-READINESS.md](../RELEASE-READINESS.md) |
+| v1 scope | [V1.0.0-SCOPE.md](V1.0.0-SCOPE.md) |
diff --git a/docs/HYBBX.md b/docs/HYBBX.md
new file mode 100644
index 0000000..4772d5f
--- /dev/null
+++ b/docs/HYBBX.md
@@ -0,0 +1,44 @@
+# HyBBX integration · MAX25-Stack 1.8.0
+
+MAX25 is the standalone RF/link layer — HyBBX consumes via transport plugins after MAX25 prep.
+
+## Plugin mapping matrix
+
+| MAX25 hardware | HyBBX plugin | INI `[networks]` |
+|----------------|--------------|------------------|
+| `hardware/tncs` | `packet_radio` | `ax25=yes` |
+| `hardware/modems` | `baycom` | `baycom=yes` |
+| `hardware/soft-modems` | `crdop` | `crdop=yes` |
+
+## Order rule matrix
+
+| Rule | Detail |
+|------|--------|
+| Start order | MAX25 before HyBBX |
+| Serial ownership | One process per port |
+| v2.4.0 HyBBX | `[max25] check=yes`, `kiss_entry=none` |
+| BayCom in packet_radio | rejected — use MAX25 + baycom plugin |
+
+## TNC workflow matrix
+
+| Step | Action |
+|------|--------|
+| 1 | `max25-ctl start --hardware tncs --device tnc2c` |
+| 2 | Merge `share/hybbx/tnc2c-host.ini.example` |
+| 3 | HyBBX `[max25] check=yes`, `kiss_entry=none` |
+| 4 | Start HyBBX Secondary → HBX to Main |
+
+## INI fragment matrix
+
+| Device | Example INI |
+|--------|-------------|
+| TNC2C | `share/hybbx/tnc2c-host.ini.example` |
+| BayCom/based | via MAX25 **bcpr** (kernel SER12 host INI removed) |
+| CRDOP | `share/hybbx/crdop-host.ini.example` |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Packet radio facts | [PACKET-RADIO.md](PACKET-RADIO.md) |
+| BayCom | [BAYCOM.md](BAYCOM.md) |
diff --git a/docs/LINUX-HOST-SETUP.md b/docs/LINUX-HOST-SETUP.md
new file mode 100644
index 0000000..5f3ada9
--- /dev/null
+++ b/docs/LINUX-HOST-SETUP.md
@@ -0,0 +1,48 @@
+# Linux host setup · MAX25-Stack 1.8.0
+
+Example settings for running `max25d` on a Linux host with USB TNC or sound-card modem.
+
+## Component matrix
+
+| Component | On Linux | Notes |
+|-----------|----------|-------|
+| `max25d` | yes | Python 3 |
+| `max25-terminal` | yes | Unix socket or `127.0.0.1:7325` |
+| TNC2C / USB TNC | yes | `/dev/ttyUSB*` |
+| BayCom/based (SER12) | yes | `max25-bcpr` default ON; KISS `/tmp/max25-bcpr/kiss-bc0` |
+| CRDOP | yes | ALSA sound device |
+| HyBBX attach | yes | after MAX25 prep |
+
+## Dependency matrix (Debian/Ubuntu)
+
+| Package group | Packages |
+|---------------|----------|
+| Build | `build-essential`, `cmake`, `pkg-config`, `git` |
+| Runtime | `python3`, `libncurses-dev` |
+| CRDOP | `libasound2-dev` |
+| BayCom/based | built with default stack | Real 8250 UART; prove RX before TX |
+
+## Install matrix
+
+| Step | Command |
+|------|---------|
+| Build | `./scripts/build.sh` |
+| INI deploy | copy `share/max25/max25d.ini.host.example` → site config |
+| Run daemon | `max25d -c /etc/max25/max25d.ini` |
+| Terminal | `max25-terminal -U /run/max25/modem.sock --ax25-ui` |
+| Serial access | `usermod -aG dialout $USER` |
+
+## Config matrix
+
+| Item | Value |
+|------|-------|
+| Live INI | site path or `./local/max25d.ini` |
+| M25/1 port | `7325` |
+| Secrets | `./local/` only |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Operator runbook | [MAX25-OPERATOR-RUNBOOK.md](MAX25-OPERATOR-RUNBOOK.md) |
+| HyBBX | [HYBBX.md](HYBBX.md) |
diff --git a/docs/MASTER-GUIDE.md b/docs/MASTER-GUIDE.md
new file mode 100644
index 0000000..17a395d
--- /dev/null
+++ b/docs/MASTER-GUIDE.md
@@ -0,0 +1,264 @@
+<!-- AUTO-SYNC 2026-08-01 — vault: projects/max25-stack/2026-07-13-master-documentation.md -->
+<!-- Re-sync: /home/akb/Code/0-RESEARCHES/tools/vault-sync-slave-docs.sh -->
+
+# MAX25-Stack — Master operator guide
+
+**Shipped guide** — canonical edits in research vault `projects/max25-stack/2026-07-13-master-documentation.md`; run sync script after change.
+
+## Summary
+
+Single linear guide: MAX25 layer model, `max25d`, devices (TNC, BayCom, CRDOP), M25/1 protocol, TNC recovery, FreeBSD split, HyBBX boundary. Shipped docs in `docs/` and `stacks/tncs/docs/` remain **frozen reference**.
+
+---
+
+## 1. What MAX25 is
+
+**Main AX.25 Stack (MAX25)** — standalone packet-radio stack with HyBBX-compatible plugin boundaries. Owns RF prep (boot-wait, KISS entry, BayCom kernel lifecycle, CRDOP audio). HyBBX consumes prepared devices via transport plugins.
+
+```
+max25-terminal / max25-client (F10 menu, M25/1)
+ │
+max25d — Main + Secondaries (:7325 M25/1)
+ │
+HyBBX (external) — packet_radio | baycom | crdop
+ │
+Hardware — tnc2c | baycom-ser12 | soft-crdop
+```
+
+Frozen: `docs/ARCHITECTURE.md`, `docs/README.md`.
+
+---
+
+## 2. Host layout — Main + Secondaries
+
+| Role | Count | Function |
+|------|-------|----------|
+| **Main** | 1× | Stack hub, HyBBX attach point, M25/1 `:7325` |
+| **Secondary** | 0–5+ | Additional `max25d` instances — one RF backend each |
+
+**Linux rules (when netdev ships):**
+
+| Item | Name |
+|------|------|
+| TUN interface | **`max25d0`** only |
+| BayCom kernel netdev | **`bcsf0`** unchanged |
+
+**Example split:** FreeBSD Main (CRDOP/TCP/IP hub) + Linux Secondary (TNC/BayCom). Not mandatory — single Linux host is the primary v1 layout.
+
+Vault matrix: [2026-07-13-max25-freebsd-tnc-baycom-full-feature-matrix.md](2026-07-13-max25-freebsd-tnc-baycom-full-feature-matrix.md).
+
+---
+
+## 3. Install and site configuration
+
+```bash
+git clone <repo> MAX25-Stack && cd MAX25-Stack
+./scripts/build.sh
+sudo cmake --install build --prefix /usr/local # or user prefix
+```
+
+| File | Purpose |
+|------|---------|
+| `~/.config/max25/max25d.ini` | Devices, TCP, auth, serial watch |
+| `share/max25/max25d.ini.example` | Template |
+| `share/hybbx/*-host.ini.example` | HyBBX attach fragments |
+
+```ini
+[devices]
+tnc2c = serial:/dev/ttyUSB0
+; soft-crdop = crdop:default
+```
+
+Frozen runbook: `docs/MAX25-OPERATOR-RUNBOOK.md`, `docs/LINUX-HOST-SETUP.md`.
+
+---
+
+## 4. Start stack — by device type
+
+### TNC (tnc2c, pktnc2)
+
+```bash
+max25-ctl start --hardware tncs --device tnc2c
+# or: stacks/tncs/tnc2c-boot-wait.sh
+```
+
+Boot-wait: DTR+RTS high during power-on (Landolt TNC2C). Software recovery ladder before power cycle.
+
+### BayCom/based (max25-bcpr userspace SER12)
+
+**Available and usable** — default build ON (`MAX25_BUILD_MAX25_BCPR=ON`). Device **`max25e0`**. KISS release **`/tmp/max25-bcpr/kiss-bc0`**.
+
+```bash
+max25-ctl start --mode hybbx-cohost # or hybbx-host / standalone
+# max25-bcpr-ctl when running daemon directly
+```
+
+HyBBX attach: `[networks] baycom=yes` · `[transport.baycom1] device=/tmp/max25-bcpr/kiss-bc0`.
+
+SSoT: [2026-08-01-baycom-pccom-operational-status.md](../integration/2026-08-01-baycom-pccom-operational-status.md) · [cohost runbook](../integration/2026-07-31-standalone-cohost-runbook.md).
+
+Legacy kernel path (`baycom-pr` / `baycom_ser_fdx`) — removed from product; freeze notes in shipped `docs/BAYCOM-FREEZES.md` only.
+
+### CRDOP (soft modem)
+
+```bash
+max25-ctl start --hardware soft-modems --device soft-crdop
+# TCP 8515 (control) / 8516 (data)
+```
+
+Vault dev master: [2026-07-13-crdop-development-master.md](2026-07-13-crdop-development-master.md).
+
+Verify: `max25-ctl status` · `ss -ltn | grep 7325`.
+
+---
+
+## 5. M25/1 and operator terminal
+
+| Item | Value |
+|------|-------|
+| Protocol | M25/1 text commands on TCP `:7325` |
+| Client | `max25-terminal` — `SET DEVICE`, `CONNECT`, `SEND` |
+| Codec | In-tree `ax25_codec.py` — no kernel AX.25 required |
+
+Frozen: `docs/MAX25-TERMINAL.md`, `include/max25/protocol.md`.
+
+---
+
+## 6. TNC recovery (software-first)
+
+Power cycle is **rescue fallback** only when DTR was low at cold boot or hardware hang.
+
+| Situation | First action |
+|-----------|--------------|
+| Echo-only (`INFO` → `INFO`) | `tnc2c-host-reset.sh` or max25d serial watch |
+| After prep `error-host` | Auto boot-wait escalate (if enabled) |
+| Cold boot, no `cmd:` | `tnc2c-boot-wait.sh` with DTR before power-on |
+
+**Software ladder** (TheFirmware TF 2.7): KISS return → JHOST 0 → ESC V → ESC QRES → ESC `@K` → MYCALL.
+
+| Layer | Responsibility |
+|-------|----------------|
+| `max25d` / boot-wait | DTR, recovery, `kiss on`, serial watch |
+| HyBBX `packet_radio` | Attach only — `kiss_entry=none` |
+
+Vault SSoT: [2026-07-13-thefirmware-native-recovery-sequence.md](2026-07-13-thefirmware-native-recovery-sequence.md) · [hardware/tnc2c/2026-07-13-kiss-host-without-power-cycle.md](../../hardware/tnc2c/2026-07-13-kiss-host-without-power-cycle.md).
+
+max25d INI defaults: `serial_watch=yes`, `stack_recover_only=yes`, `serial_bootwait_escalate=yes`.
+
+Known failure mode (power-cycle still required): [2026-07-13-max25d-tnc-recovery-power-cycle-root-cause.md](2026-07-13-max25d-tnc-recovery-power-cycle-root-cause.md).
+
+Frozen: `MAX25-Stack/stacks/tncs/docs/TNC-RECOVERY.md`.
+
+---
+
+## 7. BayCom/based ↔ max25d
+
+```
+Radio ← UART ← max25-bcprd (userspace SER12+HDLC) ← KISS PTY /tmp/max25-bcpr/kiss-bc0 ← HyBBX baycom / max25d
+```
+
+| Fact | Value |
+|------|--------|
+| Ship status | **Available · usable** — default build ON |
+| Device id | **`max25e0`** (forks `max25e0:bcN`) |
+| HyBBX cohost | `mode=hybbx-cohost` · verified standalone Main co-host 2026-07-31 / 2026-08-01 |
+| RX before TX | Prove decode before live TX — [RX rule](../../operations/2026-07-19-rx-before-tx-rule.md) |
+
+| Use BayCom/based when | Use TNC when |
+|-----------------------|--------------|
+| PC-COM / SER12 on real 8250 UART | TNC2C, PK-TNC2, USB serial KISS |
+| max25-bcpr userspace path | Boot-wait + firmware KISS |
+
+Alias compatibility: [2026-07-13-baycom-max25d-alias-compatibility.md](2026-07-13-baycom-max25d-alias-compatibility.md).
+
+Shipped: `docs/BAYCOM.md` · vault SSoT: [2026-08-01-baycom-pccom-operational-status.md](../integration/2026-08-01-baycom-pccom-operational-status.md).
+
+---
+
+## 8. CRDOP
+
+MAX25-SoftModem (`soft-crdop`) — acoustic AX.25 over soundcard. FreeBSD uses OSS; Linux uses ALSA.
+
+| Host | CRDOP role |
+|------|------------|
+| Linux | RF backend in `max25d` |
+| FreeBSD | Primary softmodem path (no kernel BayCom/TNC in stack defaults) |
+
+**Upstream (operator · 2026-07-25):** modulation development on **T-Modem-384b** HW → **soft import** into this MAX25 soft path (**no** HW modem IC on MAX25). HyBBX boundary unchanged. SSoT: [384b identity § flow](../../operations/2026-07-25-t-modem-384b-identity.md#development-flow-operator--2026-07-25) · [CRDOP master](2026-07-13-crdop-development-master.md).
+
+Frozen: `docs/CRDOP.md`, `stacks/crdop/docs/`.
+
+---
+
+## 9. FreeBSD and platform split
+
+| Component | Linux | FreeBSD |
+|-----------|-------|---------|
+| `max25d` + RF (TNC/BayCom) | ✅ | ❌ (daemon Linux-first in v1) |
+| `max25-terminal` | ✅ | ✅ (remote to Linux `:7325`) |
+| CRDOP standalone / OSS | ALSA | OSS (DEV-Level 1 port) |
+| Kernel BayCom `bcsf0` | ✅ | ❌ |
+
+No native FreeBSD kernel AX.25 — userspace KISS/M25/1 only. Vault: [2026-07-13-max25-freebsd-tnc-baycom-full-feature-matrix.md](2026-07-13-max25-freebsd-tnc-baycom-full-feature-matrix.md).
+
+Frozen: `docs/FREEBSD-AX25.md`, `docs/PLATFORMS.md`.
+
+---
+
+## 10. HyBBX boundary
+
+**MAX25 before HyBBX.** One serial owner per port.
+
+| MAX25 owns | HyBBX owns |
+|------------|------------|
+| Boot-wait, MYCALL, `kiss on`, max25-bcpr prep, CRDOPC | `[max25] check`, KISS attach, AX.25 UI, HBX, broadcast |
+
+```bash
+max25-ctl start --hardware tncs --device tnc2c # 1
+ss -ltn | grep 7325 # 2
+hybbxd -c hybbx.ini # 3 — kiss_entry=none
+```
+
+Vault: [../integration/2026-07-12-max25-hybbx-boundary-final.md](../integration/2026-07-12-max25-hybbx-boundary-final.md).
+
+Frozen: `docs/HYBBX.md`, `docs/PACKET-RADIO.md`.
+
+---
+
+## 11. Virtual netdev (planned)
+
+TUN **`max25d0`** — IPv4 `127.0.0.25/8`, IPv6 `::25/128`. DEV-Level 1 scaffold; `[netdev] enabled=no` default.
+
+Vault analysis: [2026-07-13-max25-tcpip-virtual-netdev-hbx-analysis.md](2026-07-13-max25-tcpip-virtual-netdev-hbx-analysis.md).
+
+Frozen: `docs/NETDEV.md`.
+
+---
+
+## 12. Troubleshooting
+
+| Symptom | Check |
+|---------|-------|
+| Serial busy | One owner — stop minicom; max25d **or** HyBBX |
+| TNC silent / echo-only | Recovery ladder; DTR at boot |
+| max25d unreachable | HyBBX skips local TNC when `[max25] check=yes` |
+| BayCom KISS open failed (io) | KISS path `/tmp/max25-bcpr/kiss-bc0`; max25d `mode=hybbx-cohost`; HyBBX in `dialout` — [root-cause](../integration/2026-07-31-baycom-kiss-open-io-root-cause.md) |
+| CRDOP TCP fail | Ports 8515/8516; `crdopc` running |
+
+Release audit: [2026-07-12-max25-v1.0.0-release-audit.md](2026-07-12-max25-v1.0.0-release-audit.md).
+
+---
+
+## Related
+
+| Topic | Path |
+|-------|------|
+| FreeBSD + feature matrix SSoT | [2026-07-13-max25-freebsd-tnc-baycom-full-feature-matrix.md](2026-07-13-max25-freebsd-tnc-baycom-full-feature-matrix.md) |
+| TF native recovery SSoT | [2026-07-13-thefirmware-native-recovery-sequence.md](2026-07-13-thefirmware-native-recovery-sequence.md) |
+| max25d power-cycle root cause | [2026-07-13-max25d-tnc-recovery-power-cycle-root-cause.md](2026-07-13-max25d-tnc-recovery-power-cycle-root-cause.md) |
+| CRDOP development | [2026-07-13-crdop-development-master.md](2026-07-13-crdop-development-master.md) |
+| HyBBX integration guide | [../hybbx/2026-07-13-master-documentation.md](../hybbx/2026-07-13-master-documentation.md) |
+| Dual-TNC operator flow | [DUAL-TNC-OPERATOR-GUIDE.md](DUAL-TNC-OPERATOR-GUIDE.md) |
+| TNC2multi integration | [2026-07-14-tnc2multi-max25-integration.md](2026-07-14-tnc2multi-max25-integration.md) |
+| Linux kernel AX.25 ecosystem gap | [reference/2026-07-13-linux-kernel-ax25-ecosystem-gap.md](../../reference/2026-07-13-linux-kernel-ax25-ecosystem-gap.md) |
+| Frozen product docs | `docs/`, `stacks/tncs/docs/` |
diff --git a/docs/MAX25-CLIENT.md b/docs/MAX25-CLIENT.md
new file mode 100644
index 0000000..65ba453
--- /dev/null
+++ b/docs/MAX25-CLIENT.md
@@ -0,0 +1,36 @@
+# max25-client / M25/1 · MAX25-Stack 1.8.0
+
+M25/1 text protocol reference for client developers.
+
+## Protocol matrix
+
+| Item | Value |
+|------|-------|
+| Transport | TCP `:7325` or Unix socket |
+| Framing | line-oriented text commands |
+| Spec | `include/max25/protocol.md` |
+| Codec | in-tree — no kernel AX.25 required |
+
+## Session matrix
+
+| Phase | Commands |
+|-------|----------|
+| Select device | `SET DEVICE`, `LIST DEVICES` |
+| Connect | `CONNECT`, `DISCONNECT` |
+| Transfer | `SEND`, status queries |
+| Ban list | `BAN`, `UNBAN`, `BANS` |
+
+## Client profile matrix
+
+| Item | Path |
+|------|------|
+| Profiles | `share/clients/` |
+| Index | `share/clients/index.yaml` |
+| Official client | `max25-terminal` only |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Terminal operator | [MAX25-TERMINAL.md](MAX25-TERMINAL.md) |
+| Architecture | [ARCHITECTURE.md](ARCHITECTURE.md) |
diff --git a/docs/MAX25-OPERATOR-RUNBOOK.md b/docs/MAX25-OPERATOR-RUNBOOK.md
new file mode 100644
index 0000000..dd53b24
--- /dev/null
+++ b/docs/MAX25-OPERATOR-RUNBOOK.md
@@ -0,0 +1,105 @@
+# Operator runbook · MAX25-Stack
+
+Day-to-day operator procedures for max25d and RF backends.
+
+Public mark for SER12/PC-COM class: **BayCom/based**. Product path: **max25-bcpr** (available · default build ON). Never **Konverter** / **converter**.
+
+## Canonical paths
+
+| Component | Path / command |
+|-----------|----------------|
+| Daemon | **`./scripts/run-max25d.sh`** · `stacks/daemon/max25d` · `/usr/local/bin/max25d` |
+| Terminal | **`./scripts/run-max25-terminal.sh`** · `/usr/local/bin/max25-terminal` · `build*/bin/…` |
+| max25-bcpr-ctl | `stacks/max25-bcpr/tools/max25-bcpr-ctl` or `/usr/local/sbin/max25-bcpr-ctl` |
+| TX/RX test | `scripts/tx-rx-test.sh` |
+| Site INI | `/etc/max25/max25d.ini` · `/etc/max25/max25-bcpr.ini` |
+| Tree INI | `local/max25d.ini` (gitignored) |
+| KISS PTY | `/tmp/max25-bcpr/kiss-bc0` (from bcpr.ini `kiss_link`) |
+| Unix sock | `/run/max25/modem.sock` |
+
+**Never** `stacks/daemon/max25-terminal` (does not exist).
+**Never** trust a leftover ELF at `stacks/terminal/max25-terminal` — use the launcher or PATH (`--help` must list `-d, --device`).
+
+## Daily workflow (BayCom/based · bcpr)
+
+```bash
+cd /home/akb/Code/10-PROJECTS/MAX25-Stack # or your clone
+
+# 1) daemon (owns max25-bcprd when auto_start=yes) — needs socket dir
+sudo mkdir -p /run/max25
+sudo ./scripts/run-max25d.sh # uses local/max25d.ini or /etc/max25/max25d.ini
+# wait for: raw KISS open /tmp/max25-bcpr/kiss-bc0
+
+# 2) terminal (checks socket; picks binary with -d)
+./scripts/run-max25-terminal.sh -U /run/max25/modem.sock
+# CONNECT (F10→6) → SEND …
+```
+
+`connect failed` ⇒ max25d not running (no `/run/max25/modem.sock`). Start step 1 first.
+
+Manual bcpr (only when debugging without max25d):
+
+```bash
+sudo ./stacks/max25-bcpr/tools/max25-bcpr-ctl -c /etc/max25/max25-bcpr.ini preflight
+sudo ./stacks/max25-bcpr/tools/max25-bcpr-ctl -c /etc/max25/max25-bcpr.ini start
+sudo ./stacks/max25-bcpr/tools/max25-bcpr-ctl -c /etc/max25/max25-bcpr.ini status
+```
+
+## Device start matrix
+
+| Device | Command |
+|--------|---------|
+| TNC2C | `max25-ctl start --hardware tncs --device tnc2c` |
+| BayCom/based | max25d `[features] max25_bcpr=yes` · device `max25e0` — see [BAYCOM.md](BAYCOM.md) |
+| CRDOP | `max25-ctl start --hardware soft-modems --device soft-crdop` |
+
+## TX prove-out
+
+| Path | Command |
+|------|---------|
+| Unified | `sudo ./scripts/tx-rx-test.sh --device modem --live --tx --tx-seconds 3 -c /etc/max25/max25-bcpr.ini` |
+| max25-bcpr smoke | `sudo ./stacks/max25-bcpr/tools/max25-bcpr-ctl -c /etc/max25/max25-bcpr.ini smoke --live --tx --tx-seconds 3` |
+| Terminal | `./scripts/run-max25-terminal.sh -U /run/max25/modem.sock` → CONNECT → SEND |
+
+Details: [TX-RX-TEST.md](TX-RX-TEST.md).
+
+### TX path matrix (Zentralnerv)
+
+| Trigger | Host MCR (~3s) | Notes |
+|---------|----------------|-------|
+| Long KISS → `/tmp/max25-bcpr/kiss-bc0` (info ≈376B, slave held open) | Yes | Proven RF when LED/wattmeter watched |
+| `max25-bcpr-rxtx-smoke` / `tx-rx-test` L4 `--tx --tx-seconds 3` | Yes | Requires MCR `0xe`/`0xf` for PASS |
+| max25d unix/terminal `SEND` | Yes (shorter if payload ≤256B ≈2.2s) | Keep PTY open (max25d); do not recycle max25-bcprd outside max25d |
+| open/write/**close** KISS without hold | No / intermittent | POLLHUP race — fixed in max25-bcprd (POLLIN before HUP) |
+| Stale max25d FD after external max25-bcprd restart | No | Restart **max25d** only |
+
+Operator RF evidence (optional, not CI): radio **TX/PTT LED** + **external** wattmeter needle.
+
+**2026-07-19:** Operator confirmed RF on AX25WRK1 (TX LED / external wattmeter) during live prove-out.
+
+## Recovery matrix
+
+| Situation | First action |
+|-----------|--------------|
+| Echo-only TNC | `tnc2c-host-reset.sh` or serial watch |
+| After crash | boot-wait escalate if enabled |
+| Cold boot no `cmd:` | `tnc2c-boot-wait.sh` with DTR before power-on |
+| Power cycle | rescue fallback only |
+| Stale max25-bcpr KISS | restart **max25d** only (do not recycle max25-bcprd outside max25d) |
+
+## Status matrix
+
+| Check | Command |
+|-------|---------|
+| Daemon | `max25-ctl status` / `ss -ltn \| grep 7325` |
+| max25-bcpr | `sudo max25-bcpr-ctl -c /etc/max25/max25-bcpr.ini status` |
+| Logs | max25d stdout / site log path |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Linux setup | [LINUX-HOST-SETUP.md](LINUX-HOST-SETUP.md) |
+| Terminal | [MAX25-TERMINAL.md](MAX25-TERMINAL.md) |
+| BayCom/based | [BAYCOM.md](BAYCOM.md) |
+| TNC recovery | `stacks/tncs/docs/TNC-RECOVERY.md` |
diff --git a/docs/MAX25-TERMINAL.md b/docs/MAX25-TERMINAL.md
new file mode 100644
index 0000000..86d2a22
--- /dev/null
+++ b/docs/MAX25-TERMINAL.md
@@ -0,0 +1,95 @@
+# max25-terminal · MAX25-Stack
+
+Sole official operator client — text lines + F10 menu over M25/1.
+
+## Canonical binary
+
+| Path | Role |
+|------|------|
+| `/usr/local/bin/max25-terminal` | Install / PATH — **prefer** |
+| `build*/bin/max25-terminal` | CMake output |
+| `stacks/terminal/max25-terminal` | Tree copy after build (optional) |
+
+**Never** `stacks/daemon/max25-terminal` — that path does not exist (daemon is `stacks/daemon/max25d`).
+
+```bash
+max25-terminal --help
+# lists: -H -p -U -d/--device -v --probe …
+```
+
+`-d` / `--device` is **optional**: with max25d `[devices] default = max25e0`, the session already starts on that id. Use `-d` only to override, or type `SET DEVICE <id>` / F10 → **7**.
+
+## Canonical connect (BayCom/based · bcpr)
+
+```bash
+# max25d already up (auto_start owns max25-bcprd)
+max25-terminal -U /run/max25/modem.sock
+# header DEVICE: max25e0 when default=max25e0
+# F10 → 6 (CONNECT) then SEND … or F10 → 4
+```
+
+## Connection matrix
+
+| Mode | Target |
+|------|--------|
+| Unix socket | `/run/max25/modem.sock` |
+| TCP | `127.0.0.1:7325` or remote host |
+| Flags | `--ax25-ui` (default on) · `--no-ax25-ui` for plain SEND |
+
+```bash
+max25-terminal -U /run/max25/modem.sock
+max25-terminal -T -H 127.0.0.1 -p 7325
+# optional override after connect:
+max25-terminal -U /run/max25/modem.sock -d max25e0
+```
+
+## Device selection
+
+| Method | When |
+|--------|------|
+| max25d `[devices] default = …` | Session starts on that id — **no** `-d` needed |
+| `-d` / `--device ID` | CLI `SET DEVICE` right after connect |
+| Type `SET DEVICE <id>` | In the terminal prompt |
+| F10 → **7** | Menu: Change DEVICE (TX target) |
+
+`CONNECT` (F10 → **6**, or type `CONNECT`) attaches the **currently selected** device.
+
+## Command matrix
+
+| Command | Action |
+|---------|--------|
+| `SET DEVICE <id>` | Select RF backend |
+| `GET DEVICES` | List enabled devices |
+| `CONNECT` | Attach selected device |
+| `SEND …` | Transmit payload |
+| F10 menu | Device ops, status, bans |
+
+## F10 menu
+
+| Key | Action |
+|-----|--------|
+| 1 | CALLERID |
+| 2 | CALLID |
+| 3 | Status |
+| 4 | Send line |
+| 5 | RX only (Monitor) |
+| 6 | Connection on/off (`CONNECT` / `DISCONNECT`) |
+| 7 | Change DEVICE |
+| 8 | List devices (`GET DEVICES`) |
+| 0 | Quit |
+
+## Identity matrix
+
+| Terminal field | AX.25 field |
+|----------------|-------------|
+| CALLERID | source address |
+| CALLID | destination address |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| M25/1 protocol | [MAX25-CLIENT.md](MAX25-CLIENT.md) |
+| Operator runbook | [MAX25-OPERATOR-RUNBOOK.md](MAX25-OPERATOR-RUNBOOK.md) |
+| BayCom/based (bcpr) | [BAYCOM.md](BAYCOM.md) |
+| TX/RX release test | [TX-RX-TEST.md](TX-RX-TEST.md) |
diff --git a/docs/MERGE-REPORT.md b/docs/MERGE-REPORT.md
new file mode 100644
index 0000000..32ca145
--- /dev/null
+++ b/docs/MERGE-REPORT.md
@@ -0,0 +1,36 @@
+# Merge report · MAX25-Stack 1.8.0
+
+Archive of stack merge history — BayCom, CRDOP, TNC tools into unified MAX25-Stack.
+
+## Merge source matrix
+
+| Source stack | Target path | Status |
+|--------------|-------------|--------|
+| BayCom PR-Stack | `stacks/baycom-pr/` | merged |
+| CRDOP dev track | `stacks/crdop/` | merged |
+| TNC tools | `stacks/tncs/` | merged |
+| Terminal | `stacks/terminal/` | merged |
+| Daemon | `stacks/daemon/` | merged |
+
+## Version matrix
+
+| Component | Version note |
+|-----------|--------------|
+| MAX25-Stack | 1.8.0 (product) |
+| BayCom PR-Stack upstream | 1.0.0 |
+| CRDOP dev track | CUR999 until standalone milestone |
+
+## Policy matrix
+
+| Rule | Detail |
+|------|--------|
+| Single repo | all stacks under MAX25-Stack |
+| HyBBX | external consumer — `share/hybbx/` fragments |
+| Docs | English, matrix index in `docs/README.md` |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Architecture | [ARCHITECTURE.md](ARCHITECTURE.md) |
+| Paths | [PATHS.md](PATHS.md) |
diff --git a/docs/MODULAR-TCPIP-SERVER.md b/docs/MODULAR-TCPIP-SERVER.md
new file mode 100644
index 0000000..5e38266
--- /dev/null
+++ b/docs/MODULAR-TCPIP-SERVER.md
@@ -0,0 +1,33 @@
+# Modular TCP/IP server · MAX25-Stack 1.8.0
+
+Main + Secondary TCP/IP topology service — DEV-Level 1.
+
+## Topology matrix
+
+| Role | Function |
+|------|----------|
+| Main | TCP/IP hub, coordinates secondaries |
+| Secondary | RF backend + registers with Main |
+| Cross-host | LAN `host:port` peers |
+
+## Component matrix
+
+| Item | Path |
+|------|------|
+| Service | `modular_tcp_server.py` |
+| INI Main | `share/max25/max25d.main.ini.example` |
+| INI Secondary | `share/max25/max25d.secondary-linux.ini.example` |
+
+## Platform matrix
+
+| Host | Role |
+|------|------|
+| FreeBSD | TCP/IP hub + CRDOP (documented split) |
+| Linux | TNC / BayCom Secondary |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Architecture | [ARCHITECTURE.md](ARCHITECTURE.md) |
+| FreeBSD | [FREEBSD-AX25.md](FREEBSD-AX25.md) |
diff --git a/docs/NETDEV.md b/docs/NETDEV.md
new file mode 100644
index 0000000..b4ded39
--- /dev/null
+++ b/docs/NETDEV.md
@@ -0,0 +1,27 @@
+# Virtual netdev max25d0 · MAX25-Stack 1.8.0
+
+TUN interface plan for modular TCP/IP — DEV-Level 1/2.
+
+## Interface matrix
+
+| Item | Value |
+|------|-------|
+| TUN name | `max25d0` (Linux) |
+| Purpose | IPv4/IPv6 over AX.25 path |
+| Status | planned / scaffold |
+| Sidecar | `max25-tun` (DEV-Level 2) |
+
+## Relation matrix
+
+| Component | Role |
+|-----------|------|
+| max25d | KISS/device backends |
+| max25d0 | IP encapsulation endpoint |
+| modular TCP/IP server | Main/Secondary split |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Modular TCP/IP | [MODULAR-TCPIP-SERVER.md](MODULAR-TCPIP-SERVER.md) |
+| v2 scope | [V2.0.0-SCOPE.md](V2.0.0-SCOPE.md) |
diff --git a/docs/PACKET-RADIO.md b/docs/PACKET-RADIO.md
new file mode 100644
index 0000000..5876ff3
--- /dev/null
+++ b/docs/PACKET-RADIO.md
@@ -0,0 +1,46 @@
+# Packet Radio & AX.25 · MAX25-Stack 1.8.0
+
+Technical reference for on-air and host-side AX.25/KISS behaviour in MAX25.
+
+## Layer matrix
+
+| Layer | MAX25 owns |
+|-------|------------|
+| Operator UI | `max25-terminal` |
+| Session / IPC | `max25d` M25/1 |
+| Device prep | boot-wait, modprobe, KISS PTY |
+| AX.25 codec | `ax25_codec.py` / `kiss_bridge.py` |
+| KISS framing | FEND/FESC, port nibble |
+| HyBBX attach | external — after stack up |
+
+## Address matrix
+
+| Rule | Value |
+|------|-------|
+| Call body | 1–6 chars A–Z/0–9 |
+| SSID | `-0` … `-15` |
+| Path order | DEST → DIGI* → SOURCE |
+
+## KISS matrix
+
+| Item | Rule |
+|------|------|
+| FCS on DATA to TNC | stripped — TNC adds on air |
+| KISS return recovery | `0xC0 0xFF 0xC0` before prep |
+| MYCALL | MAX25 prep — not HyBBX |
+
+## CRDOP note matrix
+
+| Item | Value |
+|------|-------|
+| Device id | `soft-crdop` |
+| Speed | 1200 bd primary, up to 19200 bd |
+| Duplex | half and full |
+| TCP ports | 8515 control / 8516 data |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Device workflow | [PLUGINS-DEVICE-MODEL.md](PLUGINS-DEVICE-MODEL.md) |
+| HyBBX | [HYBBX.md](HYBBX.md) |
diff --git a/docs/PATHS.md b/docs/PATHS.md
new file mode 100644
index 0000000..c0ba5d3
--- /dev/null
+++ b/docs/PATHS.md
@@ -0,0 +1,46 @@
+# Repository paths · MAX25-Stack
+
+Canonical directory map for contributors and operators.
+
+## Top-level matrix
+
+| Path | Role |
+|------|------|
+| `stacks/daemon/` | max25d supervisor (`max25d` / `max25d.py`) — **not** the terminal |
+| `stacks/terminal/` | operator client (`max25-terminal`) |
+| `stacks/tncs/` | TNC boot-wait, recovery |
+| `stacks/max25-bcpr/` | BayCom/based SER12 (max25-bcpr) · `max25-bcprd` / `max25-bcpr-ctl` |
+| `stacks/crdop/` | MAX25-SoftModem |
+| `plugins/` | hardware/device registry |
+| `share/max25/` | max25d INI examples |
+| `share/hybbx/` | HyBBX attach fragments |
+| `docs/` | shipped documentation |
+| `scripts/` | build, test, install · `tx-rx-test.sh` |
+
+## Operator binaries (do not invent paths)
+
+| Binary | Canonical |
+|--------|-----------|
+| max25d | `stacks/daemon/max25d` · install `/usr/local/bin/max25d` |
+| max25-terminal | **`scripts/run-max25-terminal.sh`** · `/usr/local/bin/max25-terminal` · `build*/bin/max25-terminal` |
+| max25-bcpr-ctl | `stacks/max25-bcpr/tools/max25-bcpr-ctl` · install `/usr/local/sbin/max25-bcpr-ctl` |
+| max25-bcprd | `build*/bin/max25-bcprd` · install `/usr/local/bin/max25-bcprd` |
+| max25d (start) | **`scripts/run-max25d.sh`** · `stacks/daemon/max25d` |
+
+Wrong: `stacks/daemon/max25-terminal` (does not exist).
+Wrong: relying on leftover ELF `stacks/terminal/max25-terminal` (gitignored; often stale, missing `-d`).
+
+## Config matrix
+
+| Live config | Path |
+|-------------|------|
+| Operator secrets | `./local/` (gitignored) |
+| System INI example | `share/max25/max25d.ini.example` |
+| HyBBX fragments | `share/hybbx/*-host.ini.example` |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Development | [DEVELOPMENT.md](DEVELOPMENT.md) |
+| Doc index | [README.md](README.md) |
diff --git a/docs/PLATFORMS.md b/docs/PLATFORMS.md
new file mode 100644
index 0000000..12f3c3a
--- /dev/null
+++ b/docs/PLATFORMS.md
@@ -0,0 +1,34 @@
+# Platforms · MAX25-Stack 1.8.0
+
+Supported and planned platforms for max25d and max25-terminal.
+
+## Component matrix
+
+| Component | Linux | FreeBSD | Other |
+|-----------|-------|---------|-------|
+| `max25d` (full RF) | yes | scaffold | planned |
+| `max25-terminal` | yes | yes | AmigaOS, macOS, Windows |
+| CRDOP | ALSA | OSS | — |
+| BayCom kernel | yes | no | — |
+
+## Priority matrix
+
+| Priority | Platform |
+|----------|----------|
+| 1 | Linux/KLinux (full) |
+| 2 | FreeBSD server + CRDOP |
+| 3 | OpenBSD → NetBSD → macOS → Windows |
+
+## Interface name matrix
+
+| Item | Linux name |
+|------|------------|
+| TUN (when shipped) | `max25d0` |
+| BayCom netdev | `bcsf0` |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| FreeBSD plan | [FREEBSD-AX25.md](FREEBSD-AX25.md) |
+| v2 scope | [V2.0.0-SCOPE.md](V2.0.0-SCOPE.md) |
diff --git a/docs/PLUGINS-DEVICE-MODEL.md b/docs/PLUGINS-DEVICE-MODEL.md
new file mode 100644
index 0000000..266cbf7
--- /dev/null
+++ b/docs/PLUGINS-DEVICE-MODEL.md
@@ -0,0 +1,36 @@
+# Plugins & device model · MAX25-Stack 1.8.0
+
+Unified five-step device workflow for all RF backends.
+
+## Workflow matrix
+
+| Step | Action |
+|------|--------|
+| 1 | Select operating mode (`standalone`, `hybbx-host`, `service`) |
+| 2 | Select hardware class (`tncs`, `modems`, `soft-modems`) |
+| 3 | Select device id from registry |
+| 4 | Run prep (`max25-ctl start …`) |
+| 5 | Verify M25/1 + optional HyBBX attach |
+
+## Registry matrix
+
+| Layer | Source |
+|-------|--------|
+| Manifest | `plugins/manifest.yaml` |
+| Discovery | `./scripts/discover-plugins.sh` |
+| HyBBX mode | `plugins/betriebsform/hybbx-host/` |
+
+## Device class matrix
+
+| Hardware | Devices | Protocol |
+|----------|---------|----------|
+| `tncs` | `tnc2c`, (deferred `pktnc2`) | KISS serial |
+| `modems` | `max25e0` / `baycom-kiss` | bcpr SER12 / USB KISS |
+| `soft-modems` | `soft-crdop` | M25 host TCP + ALSA |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Full device list | [DEVICES-LIST-FULL.md](DEVICES-LIST-FULL.md) |
+| Architecture | [ARCHITECTURE.md](ARCHITECTURE.md) |
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..6f5b79f
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,40 @@
+# Documentation index · MAX25-Stack 1.8.0
+
+Compact doc map for MAX25 — start at MASTER-GUIDE for linear operator flow.
+
+## By role matrix
+
+| Role | Document |
+|------|----------|
+| Master operator guide | [MASTER-GUIDE.md](MASTER-GUIDE.md) |
+| TNC / modem bring-up | [DEV/TNC-MODEM-DEV.md](DEV/TNC-MODEM-DEV.md) |
+| Host setup | [LINUX-HOST-SETUP.md](LINUX-HOST-SETUP.md) |
+| Device workflow | [PLUGINS-DEVICE-MODEL.md](PLUGINS-DEVICE-MODEL.md) |
+| Terminal operator | [MAX25-TERMINAL.md](MAX25-TERMINAL.md) |
+| Client / M25/1 | [MAX25-CLIENT.md](MAX25-CLIENT.md) |
+| HyBBX integrator | [HYBBX.md](HYBBX.md) |
+| BayCom / PC-COM | [BAYCOM.md](BAYCOM.md) |
+| BayCom freeze warning (RX/TX) | [BAYCOM-FREEZES.md](BAYCOM-FREEZES.md) |
+| TX/RX release test (TNC + BayCom/based) | [TX-RX-TEST.md](TX-RX-TEST.md) |
+| Operator runbook | [MAX25-OPERATOR-RUNBOOK.md](MAX25-OPERATOR-RUNBOOK.md) |
+| Contributor | [DEVELOPMENT.md](DEVELOPMENT.md) |
+
+## Technical reference matrix
+
+| Topic | Document |
+|-------|----------|
+| Architecture | [ARCHITECTURE.md](ARCHITECTURE.md) |
+| Packet radio / AX.25 | [PACKET-RADIO.md](PACKET-RADIO.md) |
+| CRDOP / SoftModem | [CRDOP.md](CRDOP.md) |
+| Platforms | [PLATFORMS.md](PLATFORMS.md) |
+| FreeBSD port | [FREEBSD-AX25.md](FREEBSD-AX25.md) |
+| Modular TCP/IP | [MODULAR-TCPIP-SERVER.md](MODULAR-TCPIP-SERVER.md) |
+| v1 scope | [V1.0.0-SCOPE.md](V1.0.0-SCOPE.md) |
+| v2 goals | [V2.0.0-SCOPE.md](V2.0.0-SCOPE.md) |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Root README | [../README.md](../README.md) |
+| Release gates | [../RELEASE-READINESS.md](../RELEASE-READINESS.md) |
diff --git a/docs/TX-RX-TEST.md b/docs/TX-RX-TEST.md
new file mode 100644
index 0000000..404323e
--- /dev/null
+++ b/docs/TX-RX-TEST.md
@@ -0,0 +1,137 @@
+# TX / RX release test · MAX25-Stack
+
+**RX before TX (§0.20):** live `--tx` requires Soft-DCD/noise (`dcd-bc*` / `rx-activity-bc*`) or TNC RX CONNECT in the same run. Override only `--force-tx` (against policy).
+**Root (§0.21):** start via `scripts/run-max25d.sh` (auto sudo/su).
+
+
+Unified operator and CI test for **TX** and **RX** on both device classes:
+
+| Class | Public mark | Internal / code |
+|-------|-------------|-----------------|
+| Modem (SER12 / PC-COM) | **BayCom/based** | **bcpr** |
+| Classic TNC | TNC / KISS serial | `tnc2c`, `pktnc2`, … |
+
+Entry: `scripts/tx-rx-test.sh`. Offline **L0** ships in release gates (`ctest`, `max25_test`, `release-check.sh`). Live / TX levels are **manual** (operator-gated).
+
+## Levels
+
+| Level | Name | Default | Scope |
+|-------|------|---------|-------|
+| **L0** | Offline | **always** | Host CONNECT/SEND loopback · KISS encode/decode · TNC recovery units · bcpr HDLC/dry-run smoke |
+| **L1** | Soft preflight | `--level 1` | bcpr preflight soft · TNC profile present |
+| **L2/L3** | Live RX | `--live` | Modem: timed `max25-bcprd` attach + listen (nofreeze). TNC: unix `CONNECT` + STATUS |
+| **L4** | Capped TX | `--live --tx` | Modem: ~3s KISS UI (default `--tx-seconds 3`, ≈376B info) + MCR proof. TNC: one `SEND` on live socket |
+
+Defaults: **NO TX**. Live seconds capped (default 15, max 60). No calibrate. No kernel `baycom_ser_fdx`.
+
+L4 modem notes:
+
+| Item | Contract |
+|------|----------|
+| Payload | Default ~3s PTT (proven AX25WRK1 inject: info **376B** → ~3005 ms MCR) — not a 23-byte stub |
+| `--tx-seconds N` | Target key window (1–12); longer than ~3s uses multiple bursts (`BCPR_MAXFLEN` cap) |
+| Host proof | Script requires UART **MCR** key (`0x0e`/`0x0f`); `PASS:` without MCR = fail |
+| Live stack | Reuses running `max25-bcprd` + `kiss_link` when present (no second attach / no blanket `pkill`) |
+| KISS peer | Smoke keeps the KISS slave open during TX (standalone attach); closing after write → POLLHUP → no MCR |
+| RF evidence | Wattmeter needle + radio TX/PTT LED during the key window — not automated |
+
+## Operator RF evidence (optional · not automated)
+
+On a live host with radio + in-line wattmeter (e.g. AX25WRK1), during `--live --tx` (~3s default):
+
+| Check | Pass |
+|-------|------|
+| External power meter | Needle deflection during TX burst |
+| Radio TX / PTT LED | Lit for the TX window (~3s) |
+| Script line | `MCR_keyed=…ms` and `PASS: L4 TX MCR keyed` |
+
+Host write-only `PASS:` without MCR is insufficient. SQ closed / no speaker audio does **not** disprove TX. Not in CI.
+
+## Offline (CI / release)
+
+```bash
+cd /path/to/MAX25-Stack
+
+# Operator entry (L0)
+./scripts/tx-rx-test.sh
+
+# Or via CMake
+cmake -B build -DCMAKE_BUILD_TYPE=Release -DMAX25_BUNDLE_AX25=OFF -DMAX25_BUILD_MAX25_BCPR=ON
+cmake --build build -j"$(nproc)"
+cmake --build build --target max25_tx_rx_test
+# also: ctest -R max25_tx_rx_offline --output-on-failure
+# umbrella: cmake --build build --target max25_test
+# release: bash scripts/release-check.sh
+```
+
+Pass criterion: all `PASS:` / `OK:` lines; exit 0.
+
+## Live — BayCom/based (bcpr / PC-COM)
+
+Requires root + live INI (`dry_run=no`, real IRQ/serial). Prefer dedicated host. See [BAYCOM.md](BAYCOM.md) · [BAYCOM-FREEZES.md](BAYCOM-FREEZES.md).
+
+```bash
+# Soft L1 + short live RX (radio may be OFF)
+sudo ./scripts/tx-rx-test.sh --device modem --live --seconds 15 \
+ -c /etc/max25/max25-bcpr.ini
+
+# Capped TX (~3s PTT — watch wattmeter / TX LED; MCR required for PASS)
+sudo ./scripts/tx-rx-test.sh --device modem --live --tx --tx-seconds 3 \
+ -c /etc/max25/max25-bcpr.ini
+
+# Longer attach window (optional)
+sudo ./scripts/tx-rx-test.sh --device modem --live --tx --seconds 20 --tx-seconds 3 \
+ -c /etc/max25/max25-bcpr.ini
+```
+
+Equivalent max25-bcpr-only path: `stacks/max25-bcpr/tools/max25-bcpr-ctl smoke [--live] [--tx] [--tx-seconds N]`.
+
+Prefer a running max25d/max25-bcprd stack (script reuses `kiss_link`). Fresh timed `max25-bcprd` only when none is running.
+
+max25d path (after stack up): `max25-terminal -U /run/max25/modem.sock` (with `default = max25e0`, no `-d` required) → `CONNECT` → `SEND …` — host TX keys UART MCR on SER12. Prefer PATH/`build*/bin` (stale `stacks/terminal/max25-terminal` may lack `-d`). For ~3s visible PTT use KISS inject ≥~376B info (unix `SEND` is capped by max25d `MAX_PAYLOAD=256` ≈2.2s).
+
+## Live — classic TNC
+
+Start **max25d** with a TNC device (`tnc2c` / `pktnc2`) so `/run/max25/modem.sock` (or `/tmp/max25/modem.sock`) exists.
+
+```bash
+# RX readiness (CONNECT + STATUS) — no SEND
+./scripts/tx-rx-test.sh --device tnc --live
+
+# One capped SEND (keys radio if PTT wired)
+./scripts/tx-rx-test.sh --device tnc --live --tx
+```
+
+Override socket: `MAX25_SOCK=/run/max25/modem.sock`.
+
+## Both classes
+
+```bash
+./scripts/tx-rx-test.sh --device all # L0 offline
+sudo ./scripts/tx-rx-test.sh --device all --live -c /etc/max25/max25-bcpr.ini
+```
+
+TNC live still needs a running max25d socket; modem live needs bcpr INI.
+
+## What is in release / CI
+
+| Gate | Runs |
+|------|------|
+| `scripts/tx-rx-test.sh` (L0) | Offline TX/RX for TNC + bcpr |
+| CTest `max25_tx_rx_offline` | Same |
+| Target `max25_tx_rx_test` | Same |
+| `max25_test` | Depends on `max25_tx_rx_test` |
+| `scripts/release-check.sh` | Invokes L0 tx-rx-test |
+| GitHub CI | `max25_test` + `release-check.sh` |
+
+**Not** in CI: `--live` / `--tx` (hardware / RF).
+
+## Related
+
+| Doc | Role |
+|-----|------|
+| [BAYCOM.md](BAYCOM.md) | BayCom/based bring-up |
+| [BAYCOM-FREEZES.md](BAYCOM-FREEZES.md) | Freeze warning |
+| [HARDWARE-ACCEPTANCE.md](HARDWARE-ACCEPTANCE.md) | Manual RF matrix |
+| [`stacks/max25-bcpr/README.md`](../stacks/max25-bcpr/README.md) | bcpr smoke L0–L4 |
+| [`stacks/tncs/docs/TNC-RECOVERY.md`](../stacks/tncs/docs/TNC-RECOVERY.md) | TNC recovery |
diff --git a/docs/V1.0.0-SCOPE.md b/docs/V1.0.0-SCOPE.md
new file mode 100644
index 0000000..33629dc
--- /dev/null
+++ b/docs/V1.0.0-SCOPE.md
@@ -0,0 +1,42 @@
+# v1.0.0 scope · MAX25-Stack 1.8.0
+
+Baseline release scope — still authoritative for v1 device set.
+
+## Active device matrix
+
+| Device | Status | HyBBX |
+|--------|--------|-------|
+| `tnc2c` | active | `packet_radio` |
+| `max25e0` | active | `bcpr` (kernel baycom-ser12 removed) |
+| `soft-crdop` | active | `crdop` |
+
+## Goal matrix
+
+| # | Goal |
+|---|------|
+| 1 | Operator brings up one radio path without HyBBX |
+| 2 | Clear HyBBX attach contract |
+| 3 | Offline CI gates pass on Linux |
+
+## CRDOP matrix (v1)
+
+| Topic | Value |
+|-------|-------|
+| Build | ON by default |
+| Speed | 1200 bd+, max 19200 bd |
+| Phase | development and test |
+| Audio | ALSA direct |
+
+## Deferred matrix
+
+| Item | Target |
+|------|--------|
+| `pktnc2`, `baycom-par96`, `baycom-kiss` | v1.1+ |
+| Rootless daily BayCom | v2.0.0 |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| v2 goals | [V2.0.0-SCOPE.md](V2.0.0-SCOPE.md) |
+| Release readiness | [../RELEASE-READINESS.md](../RELEASE-READINESS.md) |
diff --git a/docs/V2.0.0-SCOPE.md b/docs/V2.0.0-SCOPE.md
new file mode 100644
index 0000000..3e6873c
--- /dev/null
+++ b/docs/V2.0.0-SCOPE.md
@@ -0,0 +1,35 @@
+# v2.0.0 scope · MAX25-Stack 1.8.0
+
+Planning document — mandatory v2 goals for home Linux operation.
+
+## DEV-Level matrix
+
+| Level | Focus | Status |
+|-------|-------|--------|
+| DEV-Level 1 | Modular TCP/IP, Linux+FreeBSD, `max25d0`, rootless foundation | active |
+| DEV-Level 2 | Main+Secondary supervision, `max25-tun` | planned |
+| DEV-Level 3 | WebSocket gateway | planned |
+| DEV-Level 4 | CRDOP expansion | deferred |
+| Later | AI/assistant — deferred | deferred |
+
+## Mandatory goal matrix
+
+| Goal | Detail |
+|------|--------|
+| Rootless daily operation | no sudo for routine max25d (v2 target) |
+| One-command setup | guided install for home Linux |
+| Cross-platform base | Linux + FreeBSD before mid-tier features |
+
+## CRDOP policy matrix
+
+| Phase | CRDOP scope |
+|-------|-------------|
+| v1 / DEV-Level 1 | minimal/native — build + backend + bench |
+| DEV-Level 4 | OSS polish, G3RUH, deeper integration |
+
+## Related
+
+| Goal | Doc |
+|------|-----|
+| Modular TCP/IP | [MODULAR-TCPIP-SERVER.md](MODULAR-TCPIP-SERVER.md) |
+| Platforms | [PLATFORMS.md](PLATFORMS.md) |
diff --git a/docs/WEBSOCKET.md b/docs/WEBSOCKET.md
new file mode 100644
index 0000000..1077637
--- /dev/null
+++ b/docs/WEBSOCKET.md
@@ -0,0 +1,129 @@
+# WebSocket browser terminal · MAX25-Stack
+
+Remote operator terminal over WebSocket — same M25/1 session model as `max25-terminal`, via loopback proxy.
+
+## Architecture
+
+```
+Browser (PHP + JS)
+ → httpd reverse-proxy WS /max25-websocket/ws (TLS/wss at edge)
+ → max25-ws-proxy 127.0.0.1:7326/max25
+ → max25d M25/1 TCP 127.0.0.1:7325
+```
+
+WebSocket is **not** inside max25d (unlike hyBBX in-process WebSocket). The proxy forwards bytes without protocol translation.
+
+| Component | Path |
+|-----------|------|
+| Browser UI | `stacks/web/share/reverse-proxy/docroot/max25-websocket/` |
+| Session defaults | `/etc/max25/web-terminal.ini` (see `web-terminal.ini.example`) |
+| WebSocket proxy | `max25-ws-proxy` — config `web-proxy.ini` |
+| Primary CLI client | `max25-terminal` (unchanged) |
+
+## Ports
+
+| Port | Service |
+|------|---------|
+| **7325** | max25d M25/1 TCP |
+| **7326** | WebSocket proxy (loopback; expose via httpd only) |
+
+## Session defaults (`web-terminal.ini`)
+
+Copy `share/web-terminal.ini.example` to `/etc/max25/web-terminal.ini` or set `MAX25_WEB_TERMINAL_INI`.
+
+Values mirror max25d `[modem]` and `[devices] default`. Applied **per WebSocket session** on connect:
+
+| Key | Source | Meaning |
+|-----|--------|---------|
+| `device` | `[session]` or max25d `[devices] default` | One device per session (`SET DEVICE`) |
+| `callerid` | `[session]` or max25d `[modem]` | `SET CALLERID` if different from daemon |
+| `callid` | `[session]` or max25d `[modem]` | `SET CALLID` if different |
+| `ax25_ui` | `[session]` or max25d `[modem]` | `SET AX25_UI on\|off` |
+| `connect_on_start` | `[session]` | `CONNECT` after setup (default yes) |
+
+Optional `max25d_ini` under `[max25-web-terminal]` merges missing keys from live max25d config.
+
+## Browser UI
+
+### Header
+
+Live fields: **DEVICE**, **CALLERID**, **CALLID**, **ax25-ui**, **connected**.
+
+**Device dropdown** lists only ids returned by `GET DEVICES` from max25d. Unknown ids are rejected.
+
+### Menu (F10 equivalent)
+
+Non-intrusive **Menu ▾** dropdown plus slash commands:
+
+| Command | Action |
+|---------|--------|
+| `/callerid [id]` | `SET CALLERID` |
+| `/callid [id]` | `SET CALLID` |
+| `/status` | `GET STATUS` |
+| `/send <text>` | `SEND` |
+| `/monitor [on\|off\|toggle]` | `MONITOR` |
+| `/connect` / `/disconnect` | `CONNECT` / `DISCONNECT` |
+| `/devices` | `GET DEVICES` (device overview) |
+| `/device <id>` | `SET DEVICE` (max25d id only) |
+| `/ax25_ui on\|off` | `SET AX25_UI` |
+| `/help` | Command list |
+
+Plain text (no `/`) is sent as **`SEND`** — same as `max25-terminal` Enter.
+
+### Multiple sessions
+
+Each browser tab / WebSocket connection is an independent M25/1 client. Same `web-terminal.ini` defaults apply; per-session changes via `/` commands or dropdown.
+
+## Deploy
+
+```bash
+cmake --install $BUILD --prefix $PREFIX
+```
+
+Installs:
+
+- `$PREFIX/bin/max25-ws-proxy`
+- `$PREFIX/share/max25/web-proxy.ini.example`
+- `$PREFIX/share/max25/web-terminal.ini.example`
+- `$PREFIX/share/max25/reverse-proxy/` (httpd snippets + `docroot/`)
+
+### systemd (proxy)
+
+Example: `share/max25/max25-ws-proxy.service.example` — run proxy on loopback; point httpd `WS` to `127.0.0.1:7326/max25`.
+
+### httpd
+
+See `share/max25/reverse-proxy/{nginx,apache2,lighttpd}.conf.example` — proxy `WS /max25-websocket/ws` to the loopback WebSocket service.
+
+## Local dev
+
+```bash
+./stacks/web/scripts/dev-server.sh
+```
+
+Open `http://127.0.0.1:8080/` — requires max25d on TCP 7325 and proxy on 7326.
+
+## max25-terminal device overview
+
+CLI client F10 menu:
+
+| # | Action |
+|---|--------|
+| 8 | List DEVICES (`GET DEVICES` → RX pane) |
+| 7 | Change DEVICE (lists devices first, then prompt) |
+
+Device list at session start after `CONNECT`.
+
+## Security
+
+- Proxy binds **loopback** by default — expose only through httpd + TLS.
+- Optional `tcp_password` in `web-proxy.ini` `[upstream]` when max25d `[network] tcp_password` is set.
+- No browser-side auth beyond site/httpd policy.
+
+## Related
+
+| Doc | Topic |
+|-----|-------|
+| [MAX25-TERMINAL.md](MAX25-TERMINAL.md) | CLI operator client |
+| [MAX25-CLIENT.md](MAX25-CLIENT.md) | M25/1 protocol |
+| [stacks/web/README.md](../stacks/web/README.md) | Stack build / smoke |
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com