Repository navigation
Scoping: drive mimolette builds from a Claude Code session on asiago (tool locality, not remote terminal) #71
Description
Problem
mimolette.local is the designated macOS development server: an Apple Silicon
Mac Mini with materially better specs than the daily-driver MacBook Air
(asiago). The need for that hardware is real and demonstrated — builds,
simulators, and toolchain work are meaningfully faster there.
But mimolette is effectively headless. Not literally — it has a display — but
using it directly requires switching keyboard/mouse, waking it for Synergy, or
launching Remote Desktop. Each is enough friction that in practice the machine
is not driven by hand, and ideally never would be.
App development on a headless server is hard. The obvious fix — mosh + tmux with
Claude Code running on mimolette — solves session persistence but creates a
worse problem: it relocates the human's environment to the wrong machine. If
mimolette-CC decides to open a browser, it opens mimolette's browser. The
operator's accounts, browser sessions, clipboard, local files, and MCP
integrations (1Password, Chrome, etc.) all live on asiago, and a remote-terminal
architecture strands them.
Desired shape
Operator drives Claude Code on asiago. Local environment stays local:
browser, accounts, clipboard, personal files, local MCP servers. Work requiring
the Mini's hardware executes on mimolette, which installs and uses whatever
tools it needs but never requires a direct hand on its keyboard.
Framed precisely: this is a tool-locality problem, not a session-persistence
problem. The goal is not a remote terminal. It is a controller on asiago whose
reach extends to mimolette.
Goals
- Operator interacts with a Claude Code session running on asiago.
- Browser, credentials, clipboard, and local MCP servers remain on asiago.
- Hardware-heavy execution (builds, simulators, Xcode, EAS, Android SDK) happens
on mimolette. - Long-running remote work survives the operator closing the laptop lid.
- mimolette requires no attached input devices under normal operation.
Non-goals
- Replacing mosh/tmux access to mimolette for genuine interactive admin work.
That path stays available; it is simply not the primary development workflow. - Running the operator's browser or credential store on mimolette.
- Tunneling / Tailscale / off-LAN access. Explicitly deferred. Everything
below assumes both machines are on the same network. Remote access is a
well-understood addition that does not alter the architectural choice. - Any change to the existing
OP_SERVICE_ACCOUNT_TOKENssh-forwarding design
(see CLAUDE.md) unless Open Question 2 forces it.
Explicitly rejected: two conversational Claudes
An early framing was "Claude Code on asiago talks to Claude Code on mimolette."
Rejecting that as the primary architecture:
- Both agents would hold substantially the same context, one of them badly.
- Every hop between them is a natural-language bottleneck where context is
summarized and lost. - Failures surface as one model's paraphrase of an error rather than the error.
Two agents earn their cost when they hold different context — e.g. a
controller holding operator intent, dispatching a slow build to a worker whose
only job is to babysit it. That narrow case is Option C below.
Established environment
Verified, not assumed. Details in the Hardware appendix.
asiago already SMB-mounts mimolette's workspace. All 22 working repos are
reachable at /Volumes/Workspaces on asiago. This means native Read / Edit /
Grep / Write operate on the real files from asiago — no ssh cat, no dual
checkout, no sync boundary, single source of truth.
Path translation is pure string substitution, requiring no lookup table or
configuration:
| Side | Path |
|---|---|
| asiago (SMB client) | /Volumes/Workspaces/<repo> |
| mimolette (canonical) | /Volumes/extra-vieille/Workspaces/<repo> |
| mimolette (symlink) | ~/Developer/<repo> |
Convention: prefer the canonical path over the ~/Developer symlink in
scripted ssh commands. Some toolchains resolve symlinks and report canonical
paths in output; pinning avoids logs that disagree with the invoked directory.
Consequence for the architecture choice: remote file access is already
solved by existing infrastructure. What remains to be solved is remote
execution.
Candidate architectures
Option A — Local CC + ssh executor (zero infrastructure) — leading
Claude Code runs on asiago. Files are edited natively over the existing SMB
mount. Remote execution goes over ssh mimolette '...'. Long builds launch into
a detached tmux on the Mini and are polled for status.
- Pros: nothing to build; preserves the existing ssh credential flow exactly;
browser and MCP servers stay local by construction; file access already works. - Cons: no structured tool schemas (the agent must recall invocation
conventions); no permission granularity — ssh-via-bash is all-or-nothing. - Why it leads: the SMB mount removes the strongest argument for Option B.
Option B — MCP server on mimolette
mimolette runs an MCP server exposing build/test/exec capabilities. asiago-CC
connects over an ssh tunnel.
- Pros: structured tools with real schemas; per-tool permissioning; errors
surface verbatim. - Cons: real implementation and maintenance cost. Primary risk: an agent
driving a remote box tends to want an arbitrary shell more than a few curated
verbs. If the server collapses intoexec(cmd), this is ssh with more moving
parts and strictly more failure modes. - Gating test: can 3–5 specific, recurring operations be named that cover
most remote traffic? Since SMB already handles file access, the remaining scope
is essentially build execution — the probable answer is one or two
operations, which argues against building this. Experiment 1 tests that.
Option C — Remote Control / SendMessage peer
A persistent CC session on mimolette registers as an addressable peer; asiago-CC
dispatches via SendMessage.
- Status: entirely untested. See Open Question 1.
- Pros: native mechanism, nothing to build. Good fit for fire-and-forget
dispatch ("run the build, notify when done"). - Cons: does not solve persistence — sessions register while alive and go
offline when they end, so keeping a peer available still means keeping a
session alive (tmux). Reply direction unverified.
Option D — Agent SDK server on mimolette
A long-lived process wrapping the Claude Agent SDK, exposing a session over
HTTP/websocket, with asiago as a thin client.
- Assessment: buildable and genuinely designed for this, but requires
reimplementing session management, auth, streaming, tool permission prompts,
and interrupt handling. Not warranted unless A, B, and C all fail against a
specific articulable need.
Open design questions
1. Does a mimolette CC session appear as an addressable peer from asiago?
Untested. A prior ListAgents run from asiago showed ~70 peers, but every
Remote Control entry is a phone-attached session — an established,
frequently used workflow. mimolette has never been used as a Remote Control
peer, so no inference about machine-to-machine peering can be drawn from that
history.
Test: start CC on mimolette inside tmux over ssh, then from asiago:
- Does the session appear as
idlerather thanoffline? - Does
SendMessageto it produce any effect? - Does a reply return to the dispatching session, or land only in the peer's
own transcript?
Question 3 is decisive for Option C. Bidirectional replies make it a real
controller/worker split with zero infrastructure. Dispatch-only reduces it to a
job runner — still useful, much narrower.
2. Credential flow for any non-ssh listener
Per CLAUDE.md, the target deliberately does not store OP_SERVICE_ACCOUNT_TOKEN
in its Keychain; the token arrives via the dev machine's ssh wrapper (SendEnv)
and target AcceptEnv. The existing note records "no current use case" for
non-ssh sessions having it.
A boot-started MCP server (Option B) or persistent peer (Option C) is exactly
that use case. Either would require revisiting the decision — Keychain on
target, or accepting the listener cannot reach 1Password. Option A sidesteps
this entirely by preserving ssh-session semantics, a further point in its
favor.
3. What actually needs to run remotely?
Unquantified. Builds and simulators clearly. Less clear: test runs, linting,
dependency installs, git operations. The answer determines whether remote
traffic is a few coarse heavy operations (viable for B) or continuous
fine-grained chatter (favors A). Experiment 1 answers this.
4. Does SMB editing interfere with concurrent builds?
Editing over SMB while a build runs on the far side is a cache-coherence
question, not only a latency one. Xcode's build system and any file-watchers on
mimolette read files an SMB client on asiago is concurrently writing. Usually
fine, but can produce stale reads or partially-visible writes surfacing as
inexplicable build failures.
Not expected to block. Recorded so it is treated as a prime suspect rather than
diagnosed from scratch. Watch during Experiment 1.
Experiments
Experiment 1 — friction log (one real work session, nothing built).
Work a genuine task in asiago-CC: edit via /Volumes/Workspaces, dispatch builds
over ssh. Record every point of awkwardness. That list is the candidate tool
schema for Option B — and if it reads as "it just wanted a shell," Option B is
disconfirmed and Option A stands. Also answers Open Questions 3 and 4.
Experiment 2 — benchmark the premise.
Time an identical real build on asiago (internal NVMe) vs. mimolette (USB 3.2
Gen 2 bridged NVMe). Tests whether the Mini's CPU advantage survives its storage
handicap. Expected outcome is "yes"; this establishes the baseline.
Experiment 3 — peer addressability (~10 min, nothing built).
Resolves Open Question 1 and settles Option C outright. Cheap, but lower priority
than 1 and 2 — Option A's viability rises considerably if SMB-edit plus ssh-build
proves comfortable.
Success criteria
An architecture is adopted when, over a real development session:
- The operator never switches input to mimolette.
- Browser and credential operations resolve on asiago without special handling.
- A long build survives closing the laptop lid and its result is retrievable.
- Remote invocation friction is low enough not to prompt a fallback to
mosh+tmux.
Status
Scoping only. No implementation committed. Current leaning is Option A —
SMB for files, ssh for execution, nothing built — pending Experiment 1.
Graduates to a docs/plans/ document once the experiments resolve the open
questions.
Appendix: hardware findings
Verified via diskutil, ioreg, system_profiler, and vendor specifications.
None of this affects the architecture choice — the storage path is identical
under all four options. It bears on the premise that mimolette is materially
better for build work.
Storage
- Volume:
extra-vieille, 2TB APFS, 12G used byWorkspaces - Media: NVMe SSD (user-supplied) in the integrated slot of a
UGREEN Mac mini M4 Dock - Transport: USB-to-NVMe bridge → USB 3.2 Gen 2 (10 Gb/s), ~1 GB/s
practical sequential - Host connection: "Dual USB-C Host Cable" — two USB-C plugs in one molded
housing, both USB - Thunderbolt: all three Mini ports report
No device connected— 120
Gb/s of aggregate bandwidth unused - Contents:
Workspaces(22 repos),Caches,Simulators,Android— the
complete build working set
Note: the dock's "NVMe SSD support" describes the media, not the transport.
The drive is genuinely NVMe but reaches the Mac through a USB bridge, not PCIe —
diskutil reports Protocol: USB. Easy to misread as implying a PCIe path.
Assessment
10 Gb/s is the top of the USB 3.x range. Sequential throughput is comfortably
adequate for compilation — a Swift build does not approach 1 GB/s sequential
read. The residual concern is per-operation latency through the USB bridge,
which accumulates via operation count rather than presenting as a bandwidth
ceiling. This is Xcode's access pattern, most acutely on incremental builds.
Relevant comparison:
| Path | Transport | Practical ceiling |
|---|---|---|
| Current | NVMe → USB bridge → USB 3.2 Gen 2 | ~1 GB/s |
| Thunderbolt/USB4 enclosure | NVMe → PCIe | ~3 GB/s |
| Mini internal | NVMe → PCIe | ~3–5 GB/s |
A Thunderbolt 4 / USB4 NVMe enclosure on any unused port would remove the bridge
entirely. Deprioritized — at 10 Gb/s the current path is unlikely to be the
binding constraint. Revisit only if Experiment 2 shows builds are I/O-bound.
Tooling note
system_profiler SPUSBDataType exits rc=0 with zero bytes and empty stderr
in a non-interactive ssh session — a clean success producing nothing. Any future
target-side automation shelling out to system_profiler may silently receive an
empty string rather than an error. ioreg and diskutil work correctly over
ssh and are the reliable substitutes.
Activity
twistedmelonman commentedon Oct 1, 2026
2026-10-01 decision: Mimolette is also the end-state CI build machine. Interim step: the full suites run once, in CI, as required checks (claude-config#664, dotfiles#387).
Not started. Next: a self-hosted runner, with fork-PR approval on public repos, and
caffeinate -iaround jobs.