# Packages (shared engines)

**Packages are not pillars.** They are reusable engines multiple pillars call.
Pillars own product policy and UI; packages own mechanics.

```
Pillars (product)          Packages (engines)              App shell
Watch · Library ·          BitTorrentDrive · mcp ·         TVAnarchy.app
Download · Net · Devices   governor · ContentKey · …       RootView + Settings
```

| Kind | Question it answers |
|------|---------------------|
| **Pillar** | What job is the user doing? |
| **Package** | What shared machinery do several jobs use? |
| **Cross** | Shell chrome, release tooling, install identity config |

---

## Catalog

### Shipped

| Package | Path | Consumers | Job |
|---------|------|-----------|-----|
| **mcp** | `mcp/` | Watch, Library, Download, Devices, iOS bridge | Subprocess CLI — vlc, transmission, ssh, bridge HTTP |
| **governor** | `governor/` | Download, Watch (watchlog), Devices (registry), Net (future tick) | 24/7 daemon — custody, keeper, fleet serve |
| **recommender** | `recommender/` | Library | TMDB/IMDb/TVmaze/AniList enrich + **MLX M2** title/episode refiner |
| **search** | `search/` | Download | Vendored torrent index search (TPB/Nyaa/1337x) |
| **ContentKey** | `TVAnarchyCore/ContentID.swift` | Library, Net, Devices, Download | Stable identity for titles — not paths |
| **PlayerTargets** | `TVAnarchyCore/*Target.swift` | Watch, Devices | VLC / mpv / QuickTime / Roku control plane |
| **Bridge** | `mcp/src/bridge/`, `AppLocalAPI.swift` | Watch, Download, iOS | Thin-client HTTP (`:8787`, localhost API) |
| **Mesh** | `TVAnarchyCore/Mesh/`, WG ops | Devices, Download, Net transport | Install pairing, overlay reachability |
| **SSHTransport** | `TVAnarchyCore/` | Watch, Library, Devices | Remote command templates to always-on hosts |

### Specified (not extracted yet)

| Package | Path (planned) | Consumers | Job |
|---------|----------------|-----------|-----|
| **BitTorrentDrive** | [bittorrentdrive.md](./bittorrentdrive.md) | **Net** (external face), **Devices** (internal face), Download (actuation) | Pin/move bytes — editions + storage tiers |
| **NetMerge** | `TVAnarchyCore/Net/` or `governor/src/net/merge.ts` | Net, Library, Watch | Per-part observation merge policies |
| **PlacementIndex** | with BitTorrentDrive internal | Devices, Library, Watch | Logical path → tier locations |
| **TitleLibrary** | `titles/by-key.jsonl` | Library | `contentKey` → episode title; MLX writes once |

### External dependencies (not TVAnarchy-owned)

| Package | Source | Consumer |
|---------|--------|----------|
| **VLCKit** | SPM | iOS Watch playback |
| **LilithDesignTokens** | `@packages` | iOS chrome |
| **transmission** | daemon on the always-on host | Download via mcp |

---

## Package vs pillar (quick reference)

| If it… | It is… |
|--------|--------|
| Has a Settings section and a user-facing job name | **Pillar** |
| Is called by 2+ pillars without owning UI | **Package** |
| Is theme, logs, build scripts, `fleet.json` | **Cross** (config/infra) |
| Lives only in one pillar and never shared | **Pillar module** (stay in pillar folder) |

---

## Faces pattern (like BitTorrentDrive)

Some packages expose **faces** — same engine, different policy:

| Package | Face | Pillar consumer |
|---------|------|-----------------|
| BitTorrentDrive | external | Net editions |
| BitTorrentDrive | internal | Devices storage pools |
| BitTorrentDrive | acquisition | Download transmission add (public swarms) |
| mcp bridge | stream/remote | Watch (iOS) |
| mcp bridge | torrents | Download (iOS) |
| governor | `fleet/*` | Download custody |
| governor | `watch` + keeper | Watch history + prefetch |
| governor | `net/*` (planned) | Net publish/subscribe tick |
| ContentKey | catalog | Library |
| ContentKey | observation | Net |
| ContentKey | placement | Devices |

---

## What is NOT a package

| Thing | Why |
|-------|-----|
| `TVAnarchy` macOS views | **App shell** — hosts pillar UI |
| `SettingsStore` sections | **Cross + pillar prefs** — not an engine |
| `Theme/` Winamp | **Cross chrome** — presentation |
| `SearchController` UI | **Download pillar** — wraps `search/` package |
| `LibraryController` | **Library pillar** — orchestrates scanner + store |
| `Net` edition schemas | **Pillar spec** — data product, not transport |

---

## Dependency diagram

```mermaid
flowchart TB
    subgraph pillars [Pillars]
        W[Watch]
        L[Library]
        D[Download]
        N[Net]
        Dev[Devices]
    end

    subgraph pkg [Packages]
        BTD[BitTorrentDrive]
        MCP[mcp]
        Gov[governor]
        CK[ContentKey]
        PT[PlayerTargets]
        Br[Bridge]
        Mesh[Mesh]
        Rec[recommender]
        Srch[search]
        // New DRY TS packages (see code packages/ at root)
        Types[@tv-anarchy/types]
        Config[@tv-anarchy/config]
        Media[@tv-anarchy/media]
        Net[@tv-anarchy/net]
    end

    W --> PT
    W --> MCP
    W --> Br
    W --> CK
    L --> CK
    L --> Rec
    L --> MCP
    L --> Media
    D --> Srch
    D --> MCP
    D --> Gov
    D --> BTD
    N --> BTD
    N --> Gov
    N --> Net
    Dev --> BTD
    Dev --> Mesh
    Dev --> MCP
    Gov --> BTD
    Gov --> Types
    Gov --> Config
    Gov --> Media
    Gov --> Net
    Br --> MCP
    // host-daemon will depend on many of the above
```

---

## Adding a new package

1. For design docs: `v2/packages/<name>.md` + update manifest.json + correlation.
2. For code (DRY TS packages at root/packages/): create package/ with types + src, add workspace dep in governor/mcp package.json (or future host-daemon), document in v2/packages/README.md.
3. Tag consumers in `correlation/components.md`.
4. Do **not** add a sidebar tab.

See [bittorrentdrive.md](./bittorrentdrive.md) as the template.

## DRY Code Packages (new for v2)

To avoid duplication across governor, mcp, and the control-plane host daemon (and future net services), we extracted:

- `packages/types` — canonical data models (full DeviceConfig + conns matching Swift, FleetHost, Episode/Scan*, TitleRecord, NetObservation, Holding, WatchEvent+Client, ParsedEpisode, etc.). SSOT.
- `packages/config` — load/save devices.json + profiles + AppConfig (tolerant, atomic, defaults from types).
- `packages/media` — scanner (scanLibrary/scanMovies/findShow), watchlog (record/read/progress/summarize/parse, all from prior dups), quality scoring, resolve, org helpers. Complete, no stubs.
- `packages/net` — mergeObservations (weighted group), buildEdition, subscribeAndMerge (basic complete + policy).

Fully implemented (production on first pass). Consume via `workspace:*`.

Update `governor/package.json` and `mcp/package.json` to depend on them as they stabilize. This directly supports pillar separation while DRY, and makes host-daemon (the control-plane host daemon on the always-on host) development easier (reuses TS toolchain).

See packages/*/src/index.ts (now complete implementations, deduped watch+scan+config logic, models in types). Ported from governor/mcp dups + tolerant patterns; ready for host-daemon consumption.

**Faces + DRY role in pillars** (see plan.md Appendix C): Packages provide the shared engines that let pillars stay separated (different jobs, state, UI, trust) while avoiding duplication. BTD is the canonical example (one swarm/pin/manifest/verification code; three faces with pillar-specific policy, ACL, size, and namespace). TitleLibrary merge pattern is explicitly reusable as template for Net parts without forcing a shared superclass. Security packages (e.g. PathGuard reusable cross) follow same: doc + manifest + correlation update; faces for policy (e.g. strict vs tolerant per surface/pillar); TitleLibrary/BTD template for guards too.