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

Install and run the daemon

One line with npm (or brew). Run it on a Mac, or anywhere with a mock fleet.

install & run
npx manzanasd-client@latest doctor   # binary + setup diagnosis in one shot

# or homebrew:
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. Apache-2.0.

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