| name | join-network |
| description | Join a personal Mac (MacBook or Mac mini) to a live stoa training run as a rollout worker. Covers both run paths: the GSM8K quickstart (Qwen2.5-1.5B, no retriever, one command) and the PaperSearchQA fleet (LFM2.5-8B-A1B, per-tier knobs plus a BM25 retriever). Use when someone wants their Apple-silicon Mac to contribute rollouts to an existing run. |
Join a Mac to a stoa run
Goal: get this Mac generating rollouts for a live run without breaking the person's daily-driver machine.
Workers are disposable, so joining, leaving, or crashing never disturbs the trainer.
First, ask which run
Ask the user which run this Mac is joining, then follow only that block:
- GSM8K quickstart: Qwen2.5-1.5B on GSM8K. No retriever, no memory tiers, one command. This is the
simple path.
- PaperSearchQA fleet: LFM2.5-8B-A1B on PaperSearchQA. Per-tier decode knobs plus a BM25 retriever.
Either way, get these from the run operator out of band (secrets can't live in the repo):
- R2 credentials:
R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET.
DRL_RUN, the run id.
- The group size
n (DRL_N_SAMPLES, the trainer's --n-samples-per-prompt). This MUST match, or
every group this Mac produces is dropped by the trainer. The GSM8K quickstart uses the default 8.
DRL_PULSE_PLANE (bf16 for the quickstart, int8g64 for the fleet). The worker fails closed if it
disagrees with the trainer's published plane.
Path A: GSM8K quickstart
Simple: no retriever, no tiers. In your checkout of this repo on the Mac:
uv sync --extra worker --extra data
uv run python trainer/prep_gsm8k.py ~/dRL_data
DRL_RUN=<id> DRL_PULSE_PLANE=bf16 bash worker/run_dRL_worker_gsm8k.sh
Use the operator's DRL_RUN. The worker wipes any stale local weight cache for a new run id, pulls the v1
anchor, quantizes to int8 at load, generates GSM8K groups, grades each completion with gsm8k_rm (the last
<answer>...</answer> span against the gold integer), and streams records to R2. It polls R2 for new weight
versions between batches. The default group size is DRL_N_SAMPLES=8; set it only if the operator's n
differs.
Add more Macs by running the same command on each, but give every extra Mac a unique, stable
DRL_WORKER_ID so two Macs don't overwrite each other's rollouts (the script defaults it to
mac-$(hostname -s), so set it explicitly whenever hostnames could collide):
DRL_RUN=<id> DRL_PULSE_PLANE=bf16 DRL_WORKER_ID=mac-2 bash worker/run_dRL_worker_gsm8k.sh
To sanity-check the worker half with no trainer at all, run the standalone smoke first. It loads the real
model on this Mac, generates, grades, writes to a throwaway R2 prefix, reads the records back, and cleans up:
uv run python worker/run_local_e2e.py 2 4 128
Path B: PaperSearchQA fleet
This Mac needs the fleet worker stack (ops/setup_mac_worker.sh installs it) and, unless it's a light-tier
box, a local BM25 retriever. Light-tier Macs use the operator's shared retriever URL instead.
-
Check the machine. Run bash ops/detect_mac_tier.sh. It reports the memory tier and the right
per-box knobs. Below ~15 GB, this Mac can't be a worker, so stop and say so.
| tier | unified memory | DRL_GROUPS_PER_BATCH | DRL_PAGED_NUM_BLOCKS | retriever |
|---|
| full | 44 GB and up | 8 | 45056 | local |
| mid | 24 to 43 GB | 4 | 22528 | local |
| light | 18 to 23 GB | 2 | 11264 | shared (remote) |
| light | 15 to 17 GB | 1 | 5632 | shared (remote) |
detect_mac_tier.sh picks G by capacity within the light tier: a single group on the tightest ~16 GB
boxes, two where there's headroom. These G values are tuned for the benchmarked LFM2.5-8B-A1B; a
different model changes memory-per-stream, so re-tune G for it. DRL_N_SAMPLES (the group size) does
NOT vary by tier. It's the run's n from the operator, the same on every Mac and equal to the trainer's
--n-samples-per-prompt. In the paged KV modes (all shipped templates use paged_prefix) the pool is a
derived contract: DRL_PAGED_NUM_BLOCKS = DRL_GROUPS_PER_BATCH x DRL_N_SAMPLES x 704, and
join_and_run.sh refuses to start if they're inconsistent (the check is skipped under
DRL_KV_MODE=contiguous).
-
Set it up (one time). Install uv if needed (curl -LsSf https://astral.sh/uv/install.sh | sh), then
bash ops/setup_mac_worker.sh. It builds the venv, installs the int8 LFM2.5-8B-A1B model, patches the
mlx_lm lfm2_moe router (sigmoid, to match the trainer), and runs the int8 parity self-cert (stack only,
no search index). On full and mid tiers the join step pulls the search index tarball from the run's R2
(the operator builds and uploads it once; it's large, so confirm with the person first if disk or a
metered connection is a concern). On the light tier, skip the local index and use the operator's shared
retriever instead.
-
Write the config. Put the four R2 values in ~/.r2env (chmod 600), and copy ops/run.env from the
tier example (ops/run.env.fleet.example for full, ops/run.env.fleet-24gb.example for mid,
ops/run.env.fleet-16gb.example for light) with DRL_RUN, DRL_N_SAMPLES=<n from the operator>, and the
detected DRL_GROUPS_PER_BATCH / DRL_PAGED_NUM_BLOCKS. Light tier: also set PSQA_RETRIEVER_LOCAL=0
and PSQA_RETRIEVER_URL to the shared retriever (the -16gb template already sets both). The templates
pin DRL_PULSE_PLANE=int8g64 to match the fleet trainer.
-
Join. bash ops/join_and_run.sh. On full and mid tiers it starts the local retriever first (pulling
the index on the first run); it then pulls the current weights from R2 (cold join about two minutes) and
streams rollouts. Add --name "<label>" to name this Mac on the dashboards. join_and_run.sh is
re-joinable and idempotent, so a crash-restart is the same command.
Personal-machine etiquette
- On a laptop the person actively uses, run it in the foreground and stop anytime with Ctrl-C. The run
doesn't care. On a dedicated always-on box (a Mac mini), install the launchd supervisor
(
ops/install_supervisor.sh) so it auto-restarts and survives reboots.
- It uses the GPU and holds several GB of RAM while running. The mid and light tiers exist so it stays
within a machine you're also using. If it feels heavy, drop a tier (fewer groups per batch).
Confirm it's contributing
The worker log shows completed sweeps and uploads; the operator's dashboard shows this Mac's rollouts
arriving. If groups are being dropped, DRL_N_SAMPLES doesn't match the run's n. Fix it and rejoin.