File size: 15,852 Bytes
b74fac2 bc6edea b74fac2 bc6edea b74fac2 bc6edea b74fac2 bc5169b b74fac2 bc6edea b74fac2 bc6edea b74fac2 bc6edea b74fac2 bc6edea b74fac2 bc6edea b74fac2 bc6edea b74fac2 bc6edea b74fac2 bc6edea b74fac2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | # Armiger & Armiger Ultra Ecosystem Integration Guide
This guide provides step-by-step instructions, turnkey Docker Compose stacks, and reference HTTP adapters for integrating **Armiger** (`8.3 MB INT8 CPU`) and **Armiger Ultra** (`32.3 MB FP32 GPU/CPU` + 6 official plugins) with:
1. **[Part A β Integrating with `DH-Waypoint`](#part-a--integrating-armiger-with-dh-waypoint)** (`https://github.com/spencernorton/DH-Waypoint`):
- Native `dh-waypoint.processor.v1` processor contract (`GET /v1/manifest`, `GET /v1/status`, `POST /v1/process`, and batch `POST /v1/classify`)
- Pre-ingest `dh-waypoint.processors.admission.v1` cohort admission gate (`POST /v1/admit`)
- Closed-loop 4-tier `dh-waypoint.processors.feedback.v1` outcome telemetry (`POST /v1/feedback`)
2. **[Part B β Integrating with `Bitmagnet`](#part-b--integrating-armiger-with-bitmagnet)**:
- Pre-ingest / post-crawl batch classifier & malware/honeypot pruner (`examples/bitmagnet/bitmagnet_armiger_bridge.py`)
- GraphQL `torrentDelete` / content enrichment bridge & Torznab proxy enrichment
3. **[Part C β Integrating with Torznab Index Consumers (`Prowlarr`, `Sonarr`, `Radarr`, `Lidarr`, `Readarr`) & `qBittorrent`](#part-c--integrating-armiger-with-torznab-index-consumers--qbittorrent)**:
- Pre-grab Torznab filtering proxy (`examples/arr-stack/armiger_torznab_proxy.py`) blocking disguised `.exe`/`.scr`/`.lnk` malware, fake-seeder honeypot traps, dead swarms, and unrequested foreign-language audio tracks before grab
- Post-import webhook & `ffprobe` physical ground-truth receiver (`examples/arr-stack/armiger_arr_webhook_receiver.py`) wired into `SeriesWebhookAdapter`, `MovieWebhookAdapter`, `AudioWebhookAdapter`, `PublicationWebhookAdapter`, `QBittorrentAdapter`, and `PhysicalGroundTruthVerifier` for local conformal calibration and opt-in anonymous `BEP-44`/`BEP-46` RSI knowledge sharing
---
## Architecture Overview
```mermaid
flowchart LR
subgraph Indexers["DHT Indexers & Crawlers"]
DHW["DH-Waypoint Core<br/>(processorapi/v1)"]
BM["Bitmagnet<br/>(GraphQL + Torznab)"]
PR["Prowlarr<br/>(Indexer Manager)"]
end
subgraph ArmigerSuite["Armiger / Armiger Ultra"]
PROC["Armiger Waypoint Processor<br/>(/v1/manifest, /v1/process, /v1/classify, /v1/admit, /v1/feedback)"]
BMBR["Bitmagnet Armiger Bridge<br/>(/v1/bitmagnet/classify)"]
TPROXY["Armiger Torznab Proxy<br/>(Port 8097 Admission Gate)"]
WHOOK["Armiger Webhook & ffprobe Receiver<br/>(Port 8098 Ground Truth + BEP-44 RSI)"]
end
subgraph ArrStack["*Arr Media Managers & Download Client"]
SON["Sonarr / Radarr / Lidarr / Readarr"]
QBT["qBittorrent / Transmission"]
end
DHW <-->|"HTTP processorapi/v1"| PROC
BM <-->|"Batch Classify + GraphQL Prune"| BMBR
DHW -->|"Torznab Feed"| TPROXY
BM -->|"Torznab Feed"| TPROXY
PR -->|"Torznab Feed"| TPROXY
TPROXY -->|"Sanitized & Enriched XML"| SON
SON -->|"Grab Approved Release"| QBT
SON -->|"On Import Webhook"| WHOOK
QBT -->|"On Completion + ffprobe"| WHOOK
WHOOK -.->|"Local Calibration & Opt-In BEP-44 RSI"| PROC
```
---
## Part A β Integrating Armiger with `DH-Waypoint`
[`DH-Waypoint`](https://github.com/spencernorton/DH-Waypoint) includes a built-in external processor subsystem (`processorapi/v1`) that connects directly to [`examples/dh-waypoint/armiger_waypoint_processor.py`](../examples/dh-waypoint/armiger_waypoint_processor.py).
### 1. Turnkey Docker Compose Stack
Launch `DH-Waypoint`, `PostgreSQL`, and `Armiger Ultra` together using [`examples/dh-waypoint/docker-compose.yml`](../examples/dh-waypoint/docker-compose.yml):
```bash
export POSTGRES_PASSWORD="<postgres-password>"
docker compose -f examples/dh-waypoint/docker-compose.yml up -d
```
### 2. Drop-In Plugin Manifest (`07-armiger-ultra.plugin.yml`)
Mount [`examples/dh-waypoint/07-armiger-ultra.plugin.yml`](../examples/dh-waypoint/07-armiger-ultra.plugin.yml) into `DH_WAYPOINT_PROCESSORS_PLUGIN_DIR` (`/etc/dh-waypoint/plugins.d/07-armiger-ultra.plugin.yml`):
```yaml
processor:
name: armiger-ultra
endpoint: http://armiger-ultra:8095/v1/classify
timeout: 5s
max_batch: 64
required: false
forward_files: true
max_files: 64
forward_trackers: true
forward_swarm: true
admission:
enabled: true
endpoint: http://armiger-ultra:8095/v1/admit
timeout: 3s
max_batch: 64
max_files: 64
fail_open: true
learning:
enabled: true
feedback_endpoint: http://armiger-ultra:8095/v1/feedback
feedback_timeout: 5s
feedback_batch_size: 64
flush_interval: 15s
queue_size: 2048
```
### 3. Equivalent `DH_WAYPOINT_*` Environment Variables
If you configure `DH-Waypoint` via environment variables instead of `plugins.d`:
| Variable | Recommended Value | Purpose |
| :--- | :--- | :--- |
| `DH_WAYPOINT_PROCESSORS_HTTP_CHAIN` | `armiger-ultra=http://armiger-ultra:8095/v1/classify` | Ordered HTTP classification chain (`dh-waypoint.processor.v1`). |
| `DH_WAYPOINT_PROCESSORS_HTTP_FORWARD_FILES` | `true` | Forwards physical file paths and byte sizes to Armiger's File-Tree Encoder. |
| `DH_WAYPOINT_PROCESSORS_HTTP_FORWARD_TRACKERS` | `true` | Forwards tracker domain hints to `SwarmPriors`. |
| `DH_WAYPOINT_PROCESSORS_HTTP_FORWARD_SWARM` | `true` | Forwards seeder/leecher counts to `SwarmSurvivalNet`. |
| `DH_WAYPOINT_PROCESSORS_ADMISSION_ENABLED` | `true` | Enables pre-ingest cohort admission (`dh-waypoint.processors.admission.v1`). |
| `DH_WAYPOINT_PROCESSORS_ADMISSION_ENDPOINT` | `http://armiger-ultra:8095/v1/admit` | Pre-ingest admission endpoint. |
| `DH_WAYPOINT_LEARNING_ENABLED` | `true` | Enables the 4-tier `dh-waypoint.processors.feedback.v1` outcome loop. |
| `DH_WAYPOINT_LEARNING_FEEDBACK_ENDPOINT` | `http://armiger-ultra:8095/v1/feedback` | Delivers `t1_discovery` through `t4_playback` feedback batches to Armiger. |
---
## Part B β Integrating Armiger with `Bitmagnet`
Upstream `Bitmagnet` uses deterministic keyword/extension rules (`35.17%` 11-class accuracy on `N=10,262` audited torrents). Deploying [`examples/bitmagnet/bitmagnet_armiger_bridge.py`](../examples/bitmagnet/bitmagnet_armiger_bridge.py) upgrades a `Bitmagnet` deployment to **`95.49%` 11-class accuracy** (`97.60%` 6-dimension composite accuracy) and **`100%` fake-seeder malware trap recall**.
### 1. Turnkey `Bitmagnet` + `Armiger` Docker Compose Stack
Start the stack in [`examples/bitmagnet/docker-compose.yml`](../examples/bitmagnet/docker-compose.yml):
```bash
export POSTGRES_PASSWORD="<postgres-password>"
docker compose -f examples/bitmagnet/docker-compose.yml up -d
```
This launches two companion services alongside `bitmagnet`:
- **`armiger-bitmagnet-bridge` (`port 8096`)**: Evaluates batches of newly crawled Bitmagnet torrents (`POST /v1/bitmagnet/classify`), maps Armiger's 11-class predictions (`movie`, `tv_show`, `music`, `ebook`, `audiobook`, `comic`, `software`, `game`, `xxx`) and tags (`armiger:<category>`, `armiger:lang:<lang>`, `armiger:viability:<tier>`) onto Bitmagnet items, and automatically executes Bitmagnet's GraphQL `torrent.delete` mutation against disguised malware payloads (`.mkv.exe`, `.scr`, `.lnk`, `.vbs`) and fake-seeder honeypots.
- **`armiger-torznab-proxy` (`port 8097`)**: Wraps `http://bitmagnet:3333/torznab` with real-time neural admission filtering before `Prowlarr`, `Sonarr`, or `Radarr` sees search results.
### 2. Calling the Bitmagnet Classifier Bridge Directly
```bash
curl -sS -X POST http://localhost:8096/v1/bitmagnet/classify \
-H "Content-Type: application/json" \
-d '{
"torrents": [
{
"infoHash": "1111222233334444555566667777888899990000",
"name": "Sintel.2010.2160p.UHD.Master.HEVC.FLAC.5.1-OPEN",
"size": 74500000000,
"seeders": 320,
"leechers": 18,
"files": [{"path": "Sintel.2010.2160p.mkv", "size": 74500000000}]
},
{
"infoHash": "aaaa22223333444455556666777788889999bbbb",
"name": "Big.Buck.Bunny.2008.1080p.WEBM.mkv.exe",
"size": 15400000,
"seeders": 4500,
"leechers": 12,
"files": [{"path": "Big.Buck.Bunny.2008.1080p.WEBM.mkv.exe", "size": 15400000}]
}
]
}'
```
The bridge classifies the first item as `contentType: "movie"` (`viabilityTier: "alive_viable"`) and flags the second item (`Big.Buck.Bunny.2008.1080p.WEBM.mkv.exe`) for immediate deletion via `graphqlDeleteMutation`.
---
## Part C β Integrating Armiger with Torznab Index Consumers & `qBittorrent`
Armiger integrates with standard Torznab XML/RSS index consumers (`Prowlarr`, `Sonarr`, `Radarr`, `Lidarr`, `Readarr`) and BitTorrent clients (`qBittorrent`, `Transmission`) at **two stages**:
1. **Stage 1 β Pre-Grab Torznab Filtering Proxy (`port 8097`):** Blocks malware masquerades, fake-seeder honeypots, dead swarms, and unrequested foreign-language audio releases *before* any `*Arr` app grabs them.
2. **Stage 2 β Post-Import Webhook & `ffprobe` Ground-Truth Receiver (`port 8098`):** Verifies completed downloads and `ffprobe` media streams to calibrate local Mondrian thresholds and optionally contribute differential-privacy blinded telemetry to the `BEP-44`/`BEP-46` RSI network.
### 1. Stage 1: Wiring the Torznab Filtering Proxy (`Prowlarr` / `Sonarr` / `Radarr` / `Lidarr` / `Readarr`)
Start [`examples/arr-stack/docker-compose.yml`](../examples/arr-stack/docker-compose.yml):
```bash
export UPSTREAM_TORZNAB_URL="http://dh-waypoint:3333/torznab"
docker compose -f examples/arr-stack/docker-compose.yml up -d
```
#### Configuring in `Prowlarr`, `Sonarr`, `Radarr`, `Lidarr`, or `Readarr`:
1. Open **Settings -> Indexers -> + -> Torznab (Custom)**.
2. Set **URL** to `http://armiger-torznab-proxy:8097` (instead of pointing directly at `http://bitmagnet:3333/torznab` or `http://dh-waypoint:3333/torznab`).
3. Every Torznab search query (`?t=search`, `?t=tvsearch`, `?t=movie`, `?t=music`, `?t=book`) is transparently forwarded upstream, batch-scored by `ArmigerUltraPipeline`, stripped of unsafe/honeypot/dead/wrong-language items, and annotated with custom `<torznab:attr>` tags:
- `armiger_category` (`movie`, `tv_show`, `music`, `audiobook`, `ebook`, `comic`, `software`, `game`, `xxx`)
- `armiger_lang` (`english`, `non_english`, `multi_or_unknown`)
- `armiger_viability` (`alive_strong`, `alive_viable`, `marginal`, `dead`)
- `armiger_survival_prob` (`0.0000`β`1.0000`)
#### Torznab Proxy Environment Controls
| Variable | Default | Description |
| :--- | :---: | :--- |
| `UPSTREAM_TORZNAB_URL` | `http://dh-waypoint:3333/torznab` | Upstream Torznab base URL (`DH-Waypoint`, `Bitmagnet`, or `Prowlarr`). |
| `ARMIGER_VARIANT` | `int8` | `int8` (`8.3 MB` CPU fast-path, `2.44 ms` p50) or `fp32` (`32.3 MB` GPU/CPU). |
| `ARMIGER_REJECT_DEAD_SWARMS` | `true` | Drops Torznab items whose `SwarmSurvivalNet` viability tier is `dead`. |
| `ARMIGER_REQUIRE_ENGLISH_AUDIO` | `false` | When `true`, blocks releases classified as `non_english` audio by `AudioLanguageGuard`. |
| `ARMIGER_ALLOW_ENGLISH_SUBS` | `true` | When `ARMIGER_REQUIRE_ENGLISH_AUDIO=true`, permits foreign-audio anime/films that carry verified English subtitles (`has_eng_subs`). |
### 2. Stage 2: Wiring Post-Import Webhooks (`Sonarr`, `Radarr`, `Lidarr`, `Readarr`, `qBittorrent`)
`armiger-arr-webhook-receiver` (`port 8098`) exposes dedicated endpoints backed by the adapters in [`armiger_dht_rsi.py`](../armiger_dht_rsi.py):
| Application | Where to Configure in UI | Webhook URL | Underlying Armiger Adapter |
| :--- | :--- | :--- | :--- |
| **Sonarr** | `Settings -> Connect -> + -> Webhook` (`On Import`, `On Upgrade`) | `http://armiger-arr-webhook-receiver:8098/webhooks/sonarr` | `SeriesWebhookAdapter` |
| **Radarr** | `Settings -> Connect -> + -> Webhook` (`On Import`, `On Upgrade`) | `http://armiger-arr-webhook-receiver:8098/webhooks/radarr` | `MovieWebhookAdapter` |
| **Lidarr** | `Settings -> Connect -> + -> Webhook` (`On Release Import`, `On Upgrade`) | `http://armiger-arr-webhook-receiver:8098/webhooks/lidarr` | `AudioWebhookAdapter` |
| **Readarr** | `Settings -> Connect -> + -> Webhook` (`On Release Import`, `On Upgrade`) | `http://armiger-arr-webhook-receiver:8098/webhooks/readarr` | `PublicationWebhookAdapter` |
| **qBittorrent** | `Options -> Downloads -> Run external program` | `POST http://armiger-arr-webhook-receiver:8098/webhooks/qbittorrent` | `QBittorrentAdapter` |
#### `qBittorrent` Completion Command
In `qBittorrent` (`Tools -> Options -> Downloads -> Run external program on torrent completion`), configure:
```bash
curl -sS -X POST http://armiger-arr-webhook-receiver:8098/webhooks/qbittorrent -H "Content-Type: application/json" -d "{\"name\":\"%N\",\"hash\":\"%I\",\"content_path\":\"%F\",\"size\":%Z,\"progress\":1.0,\"state\":\"uploading\"}"
```
#### Programmatic Python Usage (`SeriesWebhookAdapter`, `MovieWebhookAdapter`, `QBittorrentAdapter`, `PhysicalGroundTruthVerifier`)
You can also invoke the webhook adapters and `ffprobe` verifier directly in Python via `ArmigerUltraPipeline.ingest_rsi_feedback`:
```python
from armiger_ultra_pipeline import ArmigerUltraPipeline
pipeline = ArmigerUltraPipeline.from_directory(".", variant="int8")
# 1. Ingest a native Sonarr "Download" (Import) webhook + ffprobe output
ok, reason, record = pipeline.ingest_rsi_feedback(
{
"eventType": "Download",
"series": {"title": "Cosmos Laundromat", "tvdbId": 310123},
"episodes": [{"seasonNumber": 1, "episodeNumber": 1}],
"release": {
"releaseTitle": "Cosmos.Laundromat.S01E01.1080p.WEB-DL.DDP5.1.H.264-OPEN",
"size": 1_450_000_000,
},
"episodeFile": {
"relativePath": "Season 01/Cosmos.Laundromat.S01E01.mkv",
"size": 1_450_000_000,
"mediaInfo": {
"videoCodec": "h264",
"audioFormat": "eac3",
"audioChannels": 5.1,
"audioLanguages": "eng",
"subtitles": "eng",
},
},
},
adapter="series_webhook",
)
assert ok and reason == "accepted_and_queued_with_poisson_jitter"
print(record.blinded_stem.blinded_hash, record.category, record.lang)
# 2. Ingest a native Radarr "Download" (Import) webhook
ok, reason, record = pipeline.ingest_rsi_feedback(
{
"eventType": "Download",
"movie": {"title": "Sintel", "year": 2010, "tmdbId": 45745},
"release": {
"releaseTitle": "Sintel.2010.2160p.UHD.Master.HEVC.FLAC.5.1-OPEN",
"size": 24_800_000_000,
},
"movieFile": {
"relativePath": "Sintel (2010)/Sintel.2010.2160p.mkv",
"size": 24_800_000_000,
},
},
adapter="movie_webhook",
)
assert ok and record.category == "movie"
```
### 3. `BEP-44` / `BEP-46` Privacy & RSI Participation Modes
All adapters enforce `PhysicalGroundTruthVerifier` (never trusting unverified model predictions) and `TelemetryAnonymizer` (stripping tracker passkeys, local paths, and IP addresses; blinding title stems via post-quantum `HMAC-SHA256` + `SHAKE-256`; applying Laplace differential privacy $\epsilon = 1.0$; and scheduling outbound packets with Poisson timing jitter):
| `ARMIGER_DHT_RSI_MODE` | Behavior |
| :--- | :--- |
| `off` | Disables all `BEP-44`/`BEP-46` DHT traffic; calibration and ground-truth verification stay strictly local. |
| `pull_only` *(Default)* | Verifies and applies `M`-of-`N` hybrid post-quantum (`Ed25519` + `WOTS+-SHAKE256`) signed calibration manifests from the DHT after passing the 500-item golden canary gate; never transmits telemetry. |
| `anonymous_contribute` | Opts in to transmitting differential-privacy blinded, hybrid post-quantum (`X25519` + `ML-KEM-768` + `ChaCha20-Poly1305`) encrypted ground-truth observations. |
|