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.
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.
# 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 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.
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.
Deterministic state
Snapshot a simulator, restore it later. Every retry starts clean.
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.
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
EACH MAC HOST
manzanasd
Go daemon · owns everything stateful
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.
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.
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.mdUp 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.
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 --mock02
Lease a simulator and act
Ask for a simulator. If it's busy, you queue. Then tap, type, and observe.
./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 observe03
Watch live, keep the evidence
Or declare the whole run in YAML. Watch live, follow the journal, or serve the fleet as MCP tools.
# 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 mcpOpen source.
Protocol-first. MIT.
The protocol is a published spec — anyone can build on it. Free, open, and yours to run.