# The Patchbay matrix

The routing table from § 1 has a UI: the **Patchbay** rail panel renders the routing table as a JACK-style **Sources × Sinks matrix**. One row per Source, one column per Sink, and a cell at every intersection where a connection is possible.

## Opening it

```yaml
actions:
  - action_id: patchbay.toggle
    input: { open: true }
    label: "▶ Open the Patchbay"
```

Click the **Patchbay** icon in the left rail (the cable icon) — or the button above. The panel opens at the right edge of the rail.

The footer shows the current connection count (e.g. `7 connections`), so you can tell at a glance whether your project is sparsely wired or full of routing.

## Reading the matrix

The matrix splits cleanly into two zones:

- **Audio block** (top-left) — audio Sources × audio Sinks.
- **MIDI block** (bottom-right) — MIDI Sources × MIDI Sinks.
- The off-diagonal quadrants (audio Source × MIDI Sink and vice versa) are **greyed out** — kind-mismatched cells can't connect, by construction.

A cell has three possible states:

| State | Meaning | Click does |
|---|---|---|
| **Greyed out** | Kind-mismatched (audio × MIDI). | No-op. |
| **Empty hollow** | Compatible kinds, NOT currently connected. | Creates the connection. |
| **Filled (cyan for audio, purple for MIDI)** | Currently connected. | Disconnects. |

Row + column headers use the entity's **label** (e.g. *"Builder: bass-acid-303.builder"*, *"Track: Bass"*) so you don't need to read raw module ids. The kind icon (audio waveform vs music note) sits next to each header for a quick scan.

## V1 takes the first port

Most Sources expose a single `out` port; most Sinks a single `in`. The matrix V1 takes the **first declared port** of each entity as the canonical one, so each Source / Sink gets exactly one row / column:

- Builders / Faust DSPs use `out`.
- Master + Recorder use `in` on the Sink side, `out` on the Source side.
- Send slots (when present) use `send-in`.
- An installed instrument exposes one MIDI port (`in`) AND a modulation port per param — the matrix V1 doesn't render the per-param modulation column (use `routing.connect` from the MCP side, or the Modulators panel UI).

**Multi-port matrices** (one column per port for entities that expose several) are a future polish; today the matrix is one row / one column per entity.

## Making + breaking a connection

Three real-world tasks, one click each:

### Sending a Builder to the mixer

The normal way is the Master panel's **"+ ADD AUDIO"** picker — it creates a MixerTrack and wires the Builder into it in one step. In the matrix you can do the same by hand: open the Builder, wait for its source to appear, then click the cell at `(Builder row, <track>:in column)` in the audio block (a track must exist first). The cell fills cyan; the Builder now feeds that track, which sums into master.

> A Builder does **not** auto-wire to master on its own anymore — opening/running it only registers the Source. You attach it to a MixerTrack explicitly (via "+ ADD AUDIO" or the matrix). Once attached the route persists across re-opens.

### Routing the Keyboard to your own Builder

Your Builder uses a `midi_note` node (so it accepts MIDI in). Find the Builder in the MIDI block as a Sink — it appears once the `midi_note` node binds. Click the cell at `(keyboard-default row, your-Builder column)`. The cell fills purple. Pressing a key on the Keyboard now drives your Builder, alongside any other sink `keyboard-default` is wired to.

### Disconnecting a hung wire

A filled cell stays connected even when its underlying entity is gone (e.g. if you closed the project before disconnecting). Re-open the project, click the still-filled cell, the wire's gone. Routing-engine reconciliation handles this without ceremony.

## What the matrix DOESN'T show

A few routing-table features live outside the V1 matrix:

- **Per-cable gain** — the matrix is a Boolean on/off editor. Adjust audio connection gain via the **Mixer** panel (one fader per Source-to-master connection) or via `routing.set { connection_id, gain }` from MCP.
- **Modulation cables** — the per-param modulation Sinks aren't columns in V1. Use the **Modulators** panel (LFO bind UI) or `routing.connect { kind: "modulation", amount: ... }`.
- **Cable suspend (enabled flag)** — no UI hook in V1. `routing.set { connection_id, enabled: false }` to mute a wire without removing it; useful for A/B comparisons.

If you find yourself wanting any of these as a click, file an issue on the project — the V2 matrix is on the roadmap once the V1 UX has soaked.

## The audible-consumer hint, revisited

When the matrix has zero audio paths reaching `master` (or every reaching MixerTrack is muted), the **Mixer** panel surfaces a **Smart Mute Hint** badge. It's the matrix's quiet way of telling you "you're playing but no path will be heard". Common cause: you haven't added the source to a MixerTrack yet ("+ ADD AUDIO"), or every track is muted.

## Activity gets every edit

Every click in the matrix routes through `api.actions.run('routing.connect' | 'routing.disconnect')`, so the **Activity** rail panel (right side) shows each connect / disconnect as a discrete log entry. Useful for:

- **Auditing what just happened** — if a colleague (or the AI) was wiring and you want to see the trail.
- **Spotting a misclick** — if you accidentally disconnected something, Activity shows the previous connect + the rogue disconnect, ready to recreate.

Next section: the differences between audio, MIDI, and modulation cables — gain, amount, the enabled flag, and which one to reach for.
