# TailMux - Implementation Plan

Date: 2026-05-05

## Status

TailMux has moved past the original proof-of-concept plan. This document is now the delivery map for the current product, not a historical checklist.

## Delivered

### Core CLI

- Cobra-based command tree.
- Config loading and validation.
- `tailmux init`.
- `tailmux doctor`.
- `tailmux status`.
- `tailmux version`.
- Shell completions.

### Routing And Isolation

- Profile-owned suffix routing.
- Suffix normalization and overlap rejection.
- Unknown `.ts.net` denial.
- Raw IP denial by default.
- No cross-profile fallback.
- HTTP CONNECT routing.
- Absolute-form HTTP proxy routing.
- SOCKS5 domain CONNECT routing.
- Tests for routing and denial behavior.

### Profile Backends

- Embedded `tsnet` backend.
- External `tailscaled` userspace backend.
- Composite runner that dispatches profile commands to the right backend.
- Profile login/logout/status commands.
- Embedded status and ping support.

### Browser And Developer Tooling

- PAC generation.
- PAC server at configured loopback endpoint.
- `tailmux env`.
- `tailmux connect <host> <port>` for SSH `ProxyCommand`.
- Safari/macOS PAC flow documented.

### Diagnostics

- `tailmux test <host>`.
- `tailmux diag path <host-or-url>`.
- Peer lookup from profile status JSON.
- Ping path classification for direct/DERP/relay signals.
- Optional `netcheck`.
- HTTP probe timing through the router.
- `tailmux diag fetch` repeated timing samples across router, embedded, and direct modes.
- SSE and dynamic response first-byte measurement with `--first-byte-only`.

### GUI And TUI

- `tailmux gui serve`.
- Local HTML dashboard and JSON API.
- Profile list/login/logout endpoints.
- Config YAML read/write endpoint.
- Path report endpoint.
- `tailmux tui` with profile summaries, path diagnostics, watch mode, and HTTP probe toggles.

### Performance Work

- Router now flushes dynamic, chunked, and unknown-length responses immediately.
- Tests cover SSE flushing and delayed chunked response flushing.
- Benchmarks exist for proxy keep-alive and fallback paths.
- Local measurements showed TailMux router was not the bottleneck after the streaming fix.

### Release Infrastructure

- Make targets for build/test/race/vet/lint/snapshot.
- GitHub CI workflow.
- GoReleaser config.
- Release/changelog workflow.

## Active Priorities

### P0 - Stabilize Current Runtime

Goal: keep the embedded `tsnet` path predictable for daily use.

Tasks:

- Re-run direct vs TailMux performance comparisons after every proxy or tsnet dependency change.
- Reduce noisy proxy logging without losing timing fields needed for diagnosis.
- Keep `examples/tailmux.example.yaml` and `tailmux init` aligned with `backend: "tsnet"`.
- Document exact recovery paths for embedded auth/state errors.
- Add tests for custom-domain suffix examples.

Acceptance criteria:

- `go test ./...` passes.
- Config example validates.
- Safari PAC path works for both configured tailnets.
- SSE first event is measured with `diag fetch --first-byte-only`.

### P1 - Lifecycle Management

Goal: make TailMux comfortable to run without manual terminal supervision.

Tasks:

- Design `tailmux launchd install`.
- Add launchd plist generation.
- Add `tailmux launchd uninstall`.
- Preserve profile state on uninstall.
- Add explicit status checks for running router/PAC/profile backends.
- Provide a safe stop command that does not touch the official Tailscale app.

Acceptance criteria:

- TailMux can start after login.
- Uninstall stops TailMux but preserves profile state.
- Existing official Tailscale client is not modified.

### P1 - GUI Productization

Goal: turn the local GUI from developer utility into a usable control surface.

Tasks:

- Show active profiles with backend, suffixes, auth state, and last error.
- Add config creation/editing with validation before save.
- Add PAC URL copy action.
- Add path reports with timing charts.
- Add recent reports history.
- Add profile login/logout actions with clear output.
- Avoid silent system network setting mutation.

Acceptance criteria:

- A new user can create a config from the GUI.
- Invalid suffix overlaps are blocked before save.
- Reports can be run and compared from the GUI.
- CLI remains the source of truth.

### P1 - TUI With Bubble Tea

Goal: replace the current simple renderer with a proper interactive terminal app.

Tasks:

- Introduce Bubble Tea/Bubbles if the dependency cost remains acceptable.
- Add profile table navigation.
- Add report panel.
- Add refresh controls.
- Add copyable commands and PAC URL display.
- Keep non-interactive one-shot rendering for scripts/tests.

Acceptance criteria:

- `tailmux tui` is usable as a long-running dashboard.
- Tests still cover rendering and state transitions.

### P2 - Custom Domain Routing Aliases

Goal: support profile-owned non-`ts.net` suffixes as a first-class documented feature.

Tasks:

- Add explicit tests for `.work.example.com` and `.home.example.com`.
- Improve validation messages around broad custom domains.
- Add `tailmux diag path` output for matched suffix.
- Add docs for public DNS, split DNS, and TLS caveats.

Acceptance criteria:

- Custom-domain browser traffic routes through the intended profile.
- Public domains not configured in TailMux remain `DIRECT` in PAC mode.
- No DNS provider writes or local DNS mutations are introduced.

### P2 - DNS Export

Goal: generate DNS artifacts without becoming a live DNS server.

Tasks:

- Design `tailmux dns export`.
- Read status data only from the selected profile.
- Generate CoreDNS/BIND/provider JSON snippets.
- Make all output deterministic and reviewable.

Acceptance criteria:

- Exporting work records cannot include personal devices.
- Exporting personal records cannot include work devices.
- No live DNS writes happen without explicit future command design.

### P3 - Network Extension Route Manager

Goal: evaluate transparent routing only after proxy/PAC routing is stable.

Tasks:

- Write a separate design doc.
- Identify required Apple entitlements and signing path.
- Prove hostname-to-flow attribution.
- Prove no fallback across profiles.
- Define explicit user consent for system changes.

Acceptance criteria:

- No implementation starts before the design proves isolation.

## Test Matrix

### Unit Tests

- config normalization
- config validation
- suffix matching
- overlap rejection
- PAC generation
- profile command construction
- embedded manager argument parsing
- path target parsing

### Integration-Style Tests

- CONNECT dispatch to the correct profile
- HTTP dispatch to the correct profile
- SOCKS5 domain dispatch
- raw IP denial
- unknown suffix denial
- profile-down fail-closed behavior
- SSE chunk flushing
- unknown-length dynamic response streaming
- persistent HTTP proxy keep-alive

### Manual Tailscale Tests

- login personal profile
- login work profile
- browse personal page through Safari PAC
- browse work page through Safari PAC
- run `tailmux diag path --netcheck` against both
- run `tailmux diag fetch` against a large dynamic page
- run `tailmux diag fetch --first-byte-only` against SSE
- compare direct official client vs TailMux when the official client is connected to the same tailnet
- stop TailMux and verify listeners are gone

## Performance Procedure

1. Start TailMux with the config under test.
2. Run `tailmux diag path <url> --netcheck`.
3. Record selected profile, backend, peer, ping path, and HTTP timing.
4. Run `tailmux diag fetch --modes router,embedded,direct --samples 5 <url>`.
5. For SSE, run `tailmux diag fetch --modes router,direct --samples 5 --first-byte-only <events-url>`.
6. If direct fails with DNS errors, connect the official Tailscale client to the same tailnet and re-run.
7. Compare first body byte and total time; do not rely on subjective browser feel alone.

## Definition Of Done For Current Runtime

TailMux is ready for daily internal use when:

- two profiles stay active concurrently through embedded `tsnet`
- Safari reaches both tailnets through PAC
- `tailmux status` shows both profiles
- `diag path` reports useful peer/path/timing data
- SSE first-event timing is close to direct official-client timing under the same network conditions
- unknown `.ts.net` hosts are denied
- raw IPs are denied by default
- tests cover routing and isolation decisions
- docs explain setup, auth, browser config, diagnostics, limits, and troubleshooting
