Skip to content

Commit 842298c

Browse files
docs: add Mac bridge soft-link guide (cloud agent <-> Mac mini M4) (#122)
New docs/mac-bridge.md: a consolidated, reader-friendly guide to the git-bus 'soft link' between a Linux cloud agent and the local Mac mini M4 runner — the constraints (no inbound path, ephemeral git-native agents, allowlist-only command surface, on-device evidence gate), an end-to-end request/response flow diagram, the five components, the security model, a both-sides quickstart, the current preset allowlist, and the M1/M2/M3 roadmap boundary (WAN=control/tool, LAN=data). Cross-linked from the deeper design doc and the README Mac-bridge bullet. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
1 parent d31e409 commit 842298c

3 files changed

Lines changed: 195 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ since MLX runs only on Apple Silicon:
282282
VPN — only git push. Presets + param bounds are enforced by
283283
`inference_engine/bridge/manifest.py`; this is itself an instance of the
284284
multi-host capability plane ([ADR 0009](docs/adr/0009-mlx-distributed-spec-decode-and-capability-exchange.md)).
285+
Full guide: [`docs/mac-bridge.md`](docs/mac-bridge.md).
285286
- **Evidence gate** (`inference_engine/bench/k3_report_gate.py`): every Mac report is
286287
machine-validated — rejects fused runs that didn't execute (`blocks=0`), baseline
287288
bypasses claiming recall/speedup, self-comparison speedups, prefill-variance, and

docs/design/mac-bridge-cloud-agent-access.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Design — Mac bridge: cloud-agent access to the self-hosted `kakeya-mac-m4`
22

3+
> **New here?** Start with the reader-friendly guide
4+
> [`docs/mac-bridge.md`](../mac-bridge.md) (what the soft link is, the
5+
> request/response flow, security, quickstart). This document is the deeper
6+
> design record (transports M1/M2/M3 + fleet-integration evaluation).
7+
38
- **Status**: M1 implemented (git-bus transport); M2/M3 designed
49
- **Relates to**: ADR 0009 (multi-host plane), PR #105 (CapabilityService),
510
PR #109 evidence gate (`inference_engine/bench/k3_report_gate.py`),

docs/mac-bridge.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# The Mac bridge — a soft link between a cloud agent and a local Mac mini M4
2+
3+
This is the canonical, reader-friendly guide to how a **Linux cloud agent**
4+
(no Apple Silicon, no Metal) drives a **local Mac mini M4** to run everything
5+
MLX-dependent — the MLX verifier, the K3 spec-decode harness, the evidence-gate
6+
reruns — without any inbound network path to the Mac.
7+
8+
It is a "soft link" in the literal sense: there is **no socket, no SSH, no VPN,
9+
no tunnel** between the two machines. The link is built entirely out of things a
10+
cloud agent already has — a git checkout, git push permission, and a read-only
11+
`gh` — plus the Mac's existing outbound-only GitHub Actions runner. **Git is the
12+
wire.**
13+
14+
- **Deep-dive design** (transports M1/M2/M3, fleet-integration evaluation):
15+
[`docs/design/mac-bridge-cloud-agent-access.md`](design/mac-bridge-cloud-agent-access.md)
16+
- **Runner operator setup** (register runner, model paths, HF pre-warm):
17+
[`docs/ops/mac-m4-runner-setup.md`](ops/mac-m4-runner-setup.md)
18+
- **Implementation**: [`scripts/mac_bridge/`](../scripts/mac_bridge/),
19+
[`inference_engine/bridge/manifest.py`](../inference_engine/bridge/manifest.py),
20+
[`.github/workflows/mac-bridge.yaml`](../.github/workflows/mac-bridge.yaml)
21+
22+
---
23+
24+
## 1. Why a soft link (the constraints)
25+
26+
| # | Constraint | Consequence |
27+
| --- | --- | --- |
28+
| C1 | **No inbound path to the Mac.** It sits behind NAT, no public IP, no port-forward. | The transport must be initiated *from* the Mac, or relayed. The Mac's Actions runner already long-polls GitHub outbound-only — reuse that. |
29+
| C2 | **Cloud agents are ephemeral and git-native.** They reliably have a repo checkout, git push, read-only `gh`. They do **not** reliably have VPN keys, SSH keys, or workflow-dispatch rights. | The control channel must be plain git. Zero new secrets. |
30+
| C3 | **The Mac executes whatever lands on it.** A queue that forwards arbitrary shell to a desk machine is a remote-shell backdoor. | The command surface must be a typed **allowlist**, never free-form shell. |
31+
| C4 | **Evidence discipline.** Benchmark/eval results must pass the K3 evidence gate, not route around it. | The gate runs **on the Mac**, so a non-conforming report fails the bridge run itself. |
32+
33+
The git-bus bridge is the only transport that satisfies **C1 + C2 with zero new
34+
infrastructure**: git is the RPC bus, the Actions runner is the executor, and the
35+
request branch is the session.
36+
37+
## 2. Architecture at a glance
38+
39+
```
40+
Linux cloud agent (no Metal) GitHub Mac mini M4 (kakeya-mac-m4)
41+
─────────────────────────── ──────── ───────────────────────────
42+
kakeya_mac.py run self-hosted Actions runner
43+
│ --preset <name> --param k=v [self-hosted, macOS, ARM64,
44+
│ kakeya-mac-m4], outbound-only
45+
46+
request_run.py
47+
• branch AgentMemory/mac-bridge-<preset>-<nonce>-<suffix>
48+
• write .mac-bridge/request.json (the manifest)
49+
• git push ───────────────────────► push event
50+
│ on: push
51+
│ branches: mac-bridge/** ,
52+
│ AgentMemory/mac-bridge-*
53+
54+
mac-bridge.yaml ──long-poll──► runner picks up the job
55+
concurrency: mac-bridge │
56+
(one Mac, never cancel) ▼
57+
run_preset.py --manifest …
58+
• validate vs PRESET allowlist
59+
(typed, bounded params)
60+
• execute the preset's FIXED argv
61+
(no manifest string hits a shell)
62+
• K3 reports → evidence gate ON-device
63+
64+
push results ◄──────────────────────────────┘
65+
(commit .mac-bridge/logs/ +
66+
results/research/*.json back
67+
to the SAME branch; also
68+
upload as run artifacts)
69+
▲ │
70+
│ git fetch / gh run view (read-only) │
71+
fetch_results.py ◄───────────────────────────
72+
• poll until the result commit appears
73+
• read logs + result JSON from the branch
74+
```
75+
76+
Latency profile: **~10 s dispatch + queue + workload runtime**. This is the right
77+
shape for test / eval / bench cycles (minutes-scale); it is deliberately *not* an
78+
interactive debugger (that is the queued M2 tailnet-SSH transport — see the design
79+
doc). The fix for "too slow" is never to widen the command surface.
80+
81+
## 3. The five components
82+
83+
| Component | Where | Role |
84+
| --- | --- | --- |
85+
| **Client** (`kakeya_mac.py`, `request_run.py`, `fetch_results.py`) | cloud agent | stdlib-only front door: `doctor` / `run` / `status`. Branches, writes the manifest, pushes, polls, returns the worktree to the original branch. |
86+
| **Manifest + allowlist** (`inference_engine/bridge/manifest.py`) | shared library | The security contract: the set of allowed presets, their fixed argv templates, and the typed/bounded params. Unit-tested at 100 % on the Linux CI gate. |
87+
| **Request manifest** (`.mac-bridge/request.json`) | the request branch | The serialized RPC: preset name + validated params + a nonce. |
88+
| **Executor** (`mac-bridge.yaml``run_preset.py`) | Mac runner | Triggered by the push; materializes LFS checkpoints, validates the manifest against the allowlist, runs the preset's fixed argv, evidence-gates K3 reports, commits results back. |
89+
| **Runner** (`[self-hosted, macOS, ARM64, kakeya-mac-m4]`) | the Mac mini | The Apple-Silicon executor. Outbound-only; the same trust shape as any self-hosted Actions runner. |
90+
91+
## 4. Security model
92+
93+
- **Command surface = the preset allowlist.** Each preset is a *fixed* argv list;
94+
no user-controlled manifest string is ever interpolated into a shell. `pytest-path`
95+
is the only path-taking preset and it constrains the path to a repo-relative
96+
`tests/` prefix. Params are **typed and bounded** at manifest-validation time —
97+
before any process starts:
98+
- `n_samples ≤ 50`, `max_new_tokens ≤ 512`, `block_size ≤ 16`.
99+
Machine-local facts (verifier/model paths) come from the **runner's environment**
100+
(`KAKEYA_MAC_VERIFIER_PATH`, `KAKEYA_MAC_DRAFTER_ID`, `KAKEYA_MAC_FTHETA_DIR`),
101+
never from the manifest.
102+
- **Trigger surface = push permission on `mac-bridge/**` (or `AgentMemory/mac-bridge-*`).**
103+
This is the *same* population that can already run code on the runner via the
104+
`needs-mac-m4` PR label (`integration.yaml`). The bridge does **not** widen *who*
105+
can run code on the Mac — it widens *what can be conveniently requested* while
106+
**narrowing** it to an allowlist.
107+
- **Result integrity.** Results are commits on the request branch — reviewable,
108+
attributable, and evidence-gated before they merge anywhere.
109+
- **Resource protection.** `concurrency: mac-bridge` serializes the single Mac
110+
(never cancels a running job); each preset carries its own `timeout-minutes`,
111+
with a hard job cap (150 min) above it.
112+
113+
## 5. Quickstart
114+
115+
### Cloud-agent side — zero install, two commands
116+
117+
The client is stdlib-only; a fresh cloud agent needs no configuration beyond what
118+
it already has (repo checkout, git push, read-only `gh`).
119+
120+
```bash
121+
# 0. Sanity-check THIS environment (push rights, gh, bridge files):
122+
PYTHONPATH=.:sdks/python python3 scripts/mac_bridge/kakeya_mac.py doctor
123+
124+
# 1. Run a preset on the Mac and wait for the result:
125+
PYTHONPATH=.:sdks/python python3 scripts/mac_bridge/kakeya_mac.py run \
126+
--preset mlx-env-probe --wait 600
127+
128+
# 1b. A bench preset with bounded params:
129+
PYTHONPATH=.:sdks/python python3 scripts/mac_bridge/kakeya_mac.py run \
130+
--preset k3-beta-scorecard \
131+
--param n_samples=5 --param max_new_tokens=32 --param block_size=8 --wait 5400
132+
133+
# 2. Poll an earlier request later:
134+
PYTHONPATH=.:sdks/python python3 scripts/mac_bridge/kakeya_mac.py status \
135+
--branch <request-branch>
136+
```
137+
138+
`run` auto-detects the cloud-agent branch policy: on an `AgentMemory/<name>-<suffix>`
139+
checkout it creates the request branch as `AgentMemory/mac-bridge-<preset>-<nonce>-<suffix>`
140+
(the workflow accepts both namespaces), so the agent never leaves its allowed
141+
branch template. After pushing it returns the worktree to the original branch.
142+
143+
### Mac-mini side — one command (operator, one-time)
144+
145+
```bash
146+
# Existing kakeya-mac-m4 host (runner already registered):
147+
bash scripts/mac_bridge/setup_mac.sh
148+
149+
# Fresh Mac (also installs + registers the Actions runner):
150+
bash scripts/mac_bridge/setup_mac.sh \
151+
--runner-token <TOKEN> --repo-url https://github.com/<owner>/<repo>
152+
```
153+
154+
The script is idempotent and ends with a bridge self-test; a green exit means the
155+
next `mac-bridge/**` push executes. Full operator details (labels, model symlink
156+
locations, HF pre-warm, repo Actions variables) are in
157+
[`docs/ops/mac-m4-runner-setup.md`](ops/mac-m4-runner-setup.md).
158+
159+
## 6. Current preset allowlist
160+
161+
Authoritative source: `inference_engine/bridge/manifest.py` (the list below is a
162+
snapshot; the manifest and its unit tests are the contract).
163+
164+
| Preset | What runs on the Mac |
165+
| --- | --- |
166+
| `mlx-env-probe` | MLX/Metal environment + ring probe — "is Apple Silicon ML healthy, which versions" |
167+
| `mlx-backend-tests` | `pytest tests/backends/mlx/` — real-MLX truth for the fake-MLX Linux suites |
168+
| `integration-tests` | `pytest -m integration` — the v0.3 GA gate on demand |
169+
| `pytest-path` | `pytest <path>` with the path validated against a `tests/` prefix rule |
170+
| `k3-step1-incremental` | hardened Mac harness `--incremental` (Gap-A incremental decode evidence) |
171+
| `k3-step2-fused` / `k3-step2-fused-allmlx` | hardened Mac harness `--fused-specdecode` (fused spec-decode evidence) |
172+
| `k3-fused-allmlx-code` / `k3-fused-allmlx-code-trim` | all-MLX fused spec-decode on a code workload (CUDA-trim variant) |
173+
| `k3-fused-allmlx-natural` | all-MLX fused, natural stop (NIAH) |
174+
| `k3-fused-singlefused-probe` | single-fused-graph Metal-stability probe |
175+
| `k3-beta-scorecard` | NIAH ctx280 all-MLX fused + CUDA-trim — Kakeya-vs-MLX-only scorecard |
176+
| `k3-native-baseline` | labelled native-MLX AR oracle baseline |
177+
| `k3-kv-quant-eval` | 4-bit KV-quantization evaluation |
178+
| `k3-drafter-parity` / `k3-drafter-parity-fp32` | drafter port-fidelity / acceptance parity checks |
179+
| `k3-evidence-gate` | re-validate committed K3 reports on-device |
180+
181+
## 7. Where this is heading
182+
183+
The git-bus bridge is **M1** of a three-tier plan. M2 adds an optional tailnet-SSH
184+
transport for *interactive* MLX debugging (one Tailscale authkey secret), and M3
185+
folds the Mac into the ADR 0009 multi-host capability plane as a `remote-executor`
186+
TOOL capability. A key boundary, fixed by the latency analysis in the design doc:
187+
**WAN = control + tool plane; LAN = data plane** — token-level spec-decode drafts
188+
are latency-critical and must never cross the cloud↔desk boundary. See
189+
[`docs/design/mac-bridge-cloud-agent-access.md`](design/mac-bridge-cloud-agent-access.md) §4.

0 commit comments

Comments
 (0)