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
Install and run the daemon
One line with npm (or brew). Run it on a Mac, or anywhere with a mock fleet.
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 --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. Apache-2.0.
The protocol is a published spec, anyone can build on it. Free, open, and yours to run.