mountable.io

Small files between a Mac and Linux

Read a Linux sandbox agent's result on your Mac, send a reply, and observe renames and deletes through the same mountable.io filesystem.

Both machines mount the same filesystem. The Linux process writes a small result. The Mac reads it, renames it to acknowledge the result, then writes a reply. Linux reads that reply. Each side also observes a deletion by the other.

The runnable companion uses Python's standard library. It writes 58 bytes of synthetic text in total. It does not call a model or run a database.

1. Prepare the filesystem and machines

Use an existing paid mountable.io account and a dedicated test filesystem. Set a monthly spending cap and quotas before testing. The run below used an existing filesystem with a €1 monthly cap, a 1 GiB quota, a 10,000-entry quota and 100 changes per minute. Those are limits, not free allowances.

Install the current CLI on both machines:

curl -fsSL https://mountable.io/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
mountable version

The Mac needs Apple Silicon and macOS 26. Linux needs /dev/fuse and permission to mount, including a helper such as fusermount3 for an unprivileged process. See Mount on a Mac and Mount from a sandbox.

Download handoff.py to local disk on each machine. Keep the script outside the mount. Choose a fresh run ID together, such as demo-4182; use that same ID on both sides.

2. Mount both sides and wait for readiness

On your trusted backend or signed-in Mac, create a separate session for each machine. Keep each session ID so you can revoke it:

mountable login
FS_ID=your-filesystem-id
umask 077
mountable ticket create "$FS_ID" --max-duration 10m --json > mac-session.json
mountable ticket create "$FS_ID" --max-duration 10m --json > linux-session.json
MAC_SESSION_ID=$(python3 -c 'import json; print(json.load(open("mac-session.json"))["id"])')
LINUX_SESSION_ID=$(python3 -c 'import json; print(json.load(open("linux-session.json"))["id"])')

Each response contains an id and a one-time ticket. Pass only the Linux ticket through the sandbox's secret input as MOUNTABLE_TICKET. Keep the reusable API key and login on the trusted machine. Never print tickets, put them in arguments, or commit the response files.

On the Mac, in a dedicated terminal:

mkdir -p ~/agent-work
python3 -c 'import json; print(json.load(open("mac-session.json"))["ticket"])' |
  mountable mount --ticket-stdin --json ~/agent-work

On Linux, in a dedicated terminal:

mkdir -p /tmp/agent-work
printf '%s\n' "$MOUNTABLE_TICKET" |
  mountable mount --ticket-stdin --json /tmp/agent-work

Both commands stay running. Wait for the JSON mounted event on each machine before starting either companion. Stop if either command exits or readiness takes more than 30 seconds. An ordinary unmounted directory is local disk, so do not continue there.

Tickets must be exchanged within five minutes and are single use. Remove the response files after retaining the session IDs for cleanup.

3. Run the handoff

From another terminal on each machine, run the following within 20 seconds of one another. Run Python from the local directory containing handoff.py.

Linux
python3 handoff.py linux /tmp/agent-work --run-id demo-4182
Mac
python3 handoff.py mac ~/agent-work --run-id demo-4182

The companion creates only handoff-demo-4182/. The Linux side refuses to reuse an existing directory. Each file is closed after fsync, and each reader checks its full expected bytes.

StepLinuxMac
ResultWrites result.txtWaits for and reads the result
AcknowledgementWaits for reviewed.txt with the same bytes, then deletes itRenames result.txt to reviewed.txt, then waits for deletion
ReplyWaits for and reads reply.txt, then renames it to accepted.txtWrites reply.txt, then waits for the rename with the same bytes
FinishWaits for deletion of accepted.txtDeletes accepted.txt

Success ends with linux: handoff complete and mac: handoff complete. A missing confirmation raises TimeoutError and exits nonzero. Stop both processes if either fails; do not continue the workflow or assume a write was seen. Each polling step has a 20-second deadline. A blocked OS filesystem call can outlast that deadline, so an orchestrator should also impose an overall process deadline (100 seconds for this tiny run).

Each side writes only its own file. Coordinate writers by path; this is not a shared-database or simultaneous-editing protocol.

4. Clean up and revoke

After both processes succeed, remove only this run's directory from the Mac. macOS can leave ._* sidecar files in it, so inspect its contents first:

ls -la ~/agent-work/handoff-demo-4182
rm -r ~/agent-work/handoff-demo-4182
mountable unmount ~/agent-work

On Linux:

mountable unmount /tmp/agent-work

From the trusted backend, revoke both retained session IDs:

mountable sessions revoke "$MAC_SESSION_ID"
mountable sessions revoke "$LINUX_SESSION_ID"
mountable files list "$FS_ID" /
mountable fs usage "$FS_ID"

For a failed run, stop both companions, unmount and revoke the sessions, then inspect the dedicated run directory through the Files API. Remove its files, sidecars and empty directory without touching other paths. A new attempt needs fresh tickets and a fresh run ID.

Verified scope and cost

On 26 October 2026, released CLI 0.8.0 passed this companion on an Apple Silicon Mac running macOS 26.7.1 and Ubuntu 24.04 arm64 in a throwaway local Colima VM. Both mounts reached readiness. Both exact-byte reads, both renames and both deletes passed; mounts were detached, sessions revoked, the test tree removed and the VM deleted. This verifies that local Linux VM, rather than a new hosted sandbox provider.

The older CLI 0.6.0 measurement on 23 October used small files on an idle filesystem: all 30 write, rename and delete observations took under a second, with a maximum of 0.78 seconds. That is a measured result, not a coherence or latency guarantee. This companion did not measure current-release latency. The filesystem contract covers mount behavior.

The 0.8.0 run's usage counters increased by 9,704 written bytes and 58 read bytes, including filesystem overhead beyond the 31-byte result and 27-byte reply. Two 4,096-byte Mac sidecars were observed and removed. The final usage snapshot reported 792,207 retained bytes and 3 entries, versus 782,503 bytes and 3 entries before; directory listing confirmed the test tree was gone. Reserved usage remained €0.03 for this shared test filesystem. These snapshots do not isolate settled provider costs.

Storage is €0.17/GiB-month and downloads €0.017/GiB in EUR, plus file charges; see billing. At those rates, 9,704 bytes retained for a full month would be about €0.00000154 storage and 58 downloaded bytes about €0.00000000092, before file charges, tax and billing aggregation. The test did not retain its files for a month. The local VM and standard-library script added no hosted provider or model API spend, paid plan or credit.