manzanas

Tends your orchardof Macs and simulators.

One daemon per Mac. Your AI agents share its simulators without stepping on each other — and one call runs the whole loop, from clean simulator to evidence.

manzanas — launch film

N agents. One Mac.
Chaos, until now.

Run two agents on the same Mac and they boot each other's simulators and type into the wrong window. manzanasd is the referee: one agent per simulator, everyone else queues.

N agents

share one Mac's simulators.

0 collisions

the daemon decides who owns what, and everyone else waits in line.

1 protocol

the CLI, MCP tools, and browser viewer all speak the same API.

NEW IN v0.5.0

One call, from clean simulator
to evidence.

A run executes the whole agent loop from a single request: acquire lease → boot → fixtures → install → launch → steps → artifacts → release. Declare it once in YAML; the daemon owns the choreography — and the lease is always released, whatever fails.

run-spec · yaml
# login-smoke.yaml
name: login-smoke
target:
  labels: [ios26]
app:
  path: /Users/ci/builds/MyApp.app
  bundle_id: com.example.myapp
steps:
  - action: tap_element
    with: {id: username}
  - action: type_into_element
    with: {id: username, text: agent}
  - action: type_into_element
    with: {id: password, text: hunter2}
  - action: tap_element
    with: {label: "Sign In"}
  - action: wait_for_element
    with: {label: "Welcome, agent!", timeout_ms: 5000}
  - name: quality gate
    action: audit
manzanas run
$ manzanas run login-smoke.yaml -o evidence.md
run run_1a2b3c4d5e6f7a8b: passed
  journal run: lse_0123456789abcdef
  step 0 tap_element: ok
  step 1 type_into_element: ok
  ...
  step 5 audit: ok · 0 findings

# evidence.md is the journal's PR-ready
# markdown export — paste it into a PR.

POST /v0/runs

The wire API. Sync by default; async with polling for long runs.

manzanas run spec.yaml

The CLI. -o writes the journal's markdown export for your PR.

MCP run tool

Agents pass the same YAML spec; run_status polls async runs.

Three frontends, one schema. All three also work pointed at a broker: the run is placed on a fleet host with the same warm-first ranking as lease scheduling.

Everything stateful
lives in the daemon.

Leases

Ask for a simulator; get it — or a place in line. When a lease expires, the next agent takes over.

claude-1 · iPhone 17 Proactive · 214s
codex-2 · any ios26queued · #1
gemini-3 · iPad Proactive · 87s

Live streaming

Watch any simulator live in your browser while an agent drives it. MJPEG live view in the browser; per-lease H.264 recordings land in the journal.

LIVE · mjpeg · 3 viewers

Deterministic state

Snapshot a simulator, restore it later. Every retry starts clean.

snap_a1 · clean install
snap_b7 · logged-in
restore → snap_b7

Evidence journal

Every action is recorded with proof — what changed, screenshots included.

#41 action.tap 187,412 · tree 4c91→a2ff

#42 action.type "hello" · tree a2ff→09be

#43 screenshot · artifacts/43.png

#44 action.audit · 3 findings · annotated.png

MCP-native

One command — manzanas mcp — turns the fleet into MCP tools for any agent.

→ tools/call lease_acquire

{"labels":["ios26"],"ttl_seconds":300}

← lse_9f2 · iPhone 17 Pro

Fleet dashboard

Every daemon serves its own dashboard at /dash; the broker serves one aggregating the whole fleet — targets, leases, live multiview, and the journal browser. Embedded in the binary, nothing to install.

emac · 4 targets3 booted · 1 parked
work · 3 targets2 booted · 1 leased
studio · 5 targetswarm pool · 4 parked

One endpoint, N Macs

Point the CLI or MCP server at a broker and every lease-scoped call follows the lease to its owning daemon automatically. No extra configuration; media never flows through the broker.

→ lease acquire (broker :7440)

← lse_9f2 · host_addr emac:7433

→ tap 187 412 (emac :7433, direct)

Sims and devices. One API.

Simulators and physical iPhones (devicectl + WebDriverAgent) — same API. Every binary reports its build version, and an optional shared bearer token (--auth-token) gates the whole surface.

Thin clients.
One stateful daemon per Mac.

Agents and humans talk to the daemon over one simple JSON API — HTTP for requests, WebSocket for streams.

LINUX · CI · ANYWHERE

manzanas

thin client · Go · single binary

CLI — lease / tap / type / observe
MCP server — manzanas mcp (stdio)
stream viewer — browser

EACH MAC HOST

manzanasd

Go daemon · owns everything stateful

registry — sims via simctl · boot / shutdown / health
lease — TTL · labels · FIFO queues
actions — HID + a11y observe (AXe) · screenshots
stream — MJPEG · N viewers per target
state — snapshot / restore · fixtures
journal — actions + tree hashes + artifacts

SIMULATORS

iOS simulators

leased · queued · idle — sims + devices

Watch your agents work.
Live, in any browser.

Open a stream on any leased simulator and watch it live — while the agent keeps working.

mac-01.local:7433/v0/streams/str_4kd/mjpeg
LIVE · mjpeg · 30 fps

lease

lse_9f2

target

iPhone 17 Pro

viewers

3

actions.dispatch tap 187,412

actions.dispatch type "hello manzanas"

observe · tree hash a2ff…09be

Try it in 60 seconds.
No Mac required.

--mock runs the daemon anywhere — Linux, CI, your laptop — with a full mock action backend. The same lease → observe → tap → audit code an agent hits on a real Mac, against a deterministic synthetic app screen.

60-second quickstart · linux / ci / anywhere
git clone https://github.com/BariBariGood/manzanas
cd manzanas && make build

# no Mac, no Xcode — a deterministic mock fleet:
./bin/manzanasd --addr :7433 --mock

# the full loop against a synthetic app screen:
cat > smoke.yaml <<'EOF'
name: smoke
target: {labels: [ios26]}
steps:
  - action: type_into_element
    with: {id: username, text: agent}
  - action: type_into_element
    with: {id: password, text: pw}
  - action: tap_element
    with: {label: "Sign In"}
  - action: wait_for_element
    with: {label: "Welcome, agent!", timeout_ms: 5000}
  - action: audit
EOF
./bin/manzanas run smoke.yaml -o evidence.md

Up and running
in three steps.

01

Build and run the daemon

Install from the tap (or make build) and run it on a Mac — or anywhere with a mock fleet.

install & run
brew tap baribarigood/tap \
  https://github.com/BariBariGood/homebrew-tap
brew trust baribarigood/tap
brew install manzanasd
brew services start manzanasd   # port 7433

# anywhere (Linux/dev/CI), with a mock fleet:
./bin/manzanasd --addr :7433 --mock

02

Lease a simulator and act

Ask for a simulator. If it's busy, you queue. Then tap, type, and observe.

manzanas cli
./bin/manzanas lease acquire \
  --labels ios26 --agent claude-1

export MANZANAS_LEASE=lse_9f2
./bin/manzanas tap 187 412
./bin/manzanas type "hello manzanas"
./bin/manzanas observe

03

Watch live, keep the evidence

Or declare the whole run in YAML. Watch live, follow the journal, or serve the fleet as MCP tools.

run · journal · mcp
# or skip steps 2–3: one call, whole run
./bin/manzanas run spec.yaml -o evidence.md

./bin/manzanas stream url --lease $MANZANAS_LEASE
./bin/manzanas journal tail $MANZANAS_LEASE

# serve MCP tools over stdio:
./bin/manzanas mcp

Open source.
Protocol-first. MIT.

The protocol is a published spec — anyone can build on it. Free, open, and yours to run.