August 11, 2026 · BariBariGood
v0.5.0: one call from clean simulator to evidence
Until now, driving a simulator through manzanas meant hand-sequencing the loop yourself: acquire a lease, boot the target, apply fixtures, install the app, launch it, dispatch a dozen actions, capture artifacts, and — on every failure path — remember to release the lease. Every agent I watched do this wrote the same boilerplate, and every one of them occasionally forgot the release and orphaned a simulator.
v0.5.0 makes the whole loop one call. A run is a declarative spec; the daemon owns the choreography:
acquire lease → boot → fixtures → install app → launch → steps →
artifact capture → release lease (applying its reset)The YAML run-spec
You describe what to lease, what to install, and what to do — the native step DSL is just the existing action surface, one action per step, dispatched and journaled exactly like POST /v0/actions:
# login-smoke.yaml
name: login-smoke
target:
labels: [ios26]
app:
path: /Users/ci/builds/MyApp.app # .app bundle on the daemon host
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: auditThen:
$ 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 2 type_into_element: ok
step 3 tap_element: ok
step 4 wait_for_element: ok
step 5 audit: ok-o evidence.md writes the journal's markdown export — the same document as GET /v0/journal/{run}/export.md — with every step, tree hash, screenshot, and audit finding. Paste it into a PR comment and the run argues for itself.
Steps are actions, not a new language
I deliberately did not invent a test framework. Each step is one action kind from the protocol, with the payload passed through verbatim:
steps:
- name: optional human label
action: tap_element # any action kind: tap, swipe, type,
with: {id: username} # tap_element, wait_for_element,
timeout_seconds: 15 # scroll_to_element, observe,
continue_on_error: false # screenshot, audit, batch, ...Steps stop at the first failure (later steps report skipped); continue_on_error lets cleanup steps run anyway. Whatever fails — a step, a boot, an install, the run budget expiring — the lease is always released with its reset. The evidence trail of a red run is as complete as a green one.
Three frontends, one schema
The same spec drives POST /v0/runs (the wire API, sync by default, async with polling for long runs), manzanas run spec.yaml (the CLI), and the MCP run tool — so an agent that speaks MCP gets the one-call loop for free. 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, then proxied to the owning daemon.
Also in v0.5.0
Broker-transparent clients. The CLI and MCP server now follow a broker lease's host_addr annotation automatically — point them at the broker and every lease-scoped call routes to the owning daemon. Fleet dashboard. The broker serves an aggregated /dash across every daemon, next to each daemon's own. Version surfacing + optional auth. Binaries report the build version stamped at link time, and --auth-token puts a shared bearer token in front of the whole API. Mock actions backend. --mock now carries a full deterministic action backend, so the entire loop — including runs — works on a Linux box with no Mac at all. That one gets its own post.
v0.5.0 is on GitHub and the Homebrew tap. Full run-spec reference in docs/runs.md.