Skip to content

Latest commit

 

History

History
85 lines (74 loc) · 4.78 KB

ABOUT.md

File metadata and controls

85 lines (74 loc) · 4.78 KB

Simlock

Simlock is a control plane for iOS simulators and Android emulators, built for environments where multiple coding agents run in parallel — on one machine, or across a fleet of them behind a single address.

The problem

Agents that need a simulator grab whatever simctl / avdmanager shows them. Two agents that pick the same device start fighting over it — booting, erasing, and installing over each other — without ever knowing the other exists.

The solution

Simlock is a CLI-first control plane (backed by a local daemon) that is the same for both platforms and gives agents one primitive: lease a device. An optional local stdio MCP integration exposes the focused lease/release workflow to compatible agent clients; the CLI remains the full operator interface. An optional, token-authenticated HTTP API lets remote agents lease devices from a self-hosted simlock host over the network (see HTTP-API.md). A host process that wants to allocate devices without spawning a simlock command at all — agent-device, for example — can instead depend on simlock/client/simlock/admin, the typed programmatic client the CLI and MCP frontends are themselves built on (see CLIENT.md). With HTTP on, the daemon also serves a web console for operators, signed in with an operator token (see CONSOLE.md).

  • simlock lease returns a ready device — booted and health-checked — that no other agent will touch for the duration of the lease.
  • If no matching device is free, simlock provisions one, up to a configurable capacity limit derived from the machine's CPU and RAM.
  • If the limit is reached, the CLI blocks and waits in a fair queue until a device frees up (with --timeout and --no-wait escape hatches).
  • A phone or tablet an admin enrolled is leased the same way, with simlock lease --physical: one agent at a time, and on release every app that is not on the device's enrollment list is uninstalled, so the next agent starts from the apps it was enrolled with. Simlock never creates, erases or destroys such a device.
  • Devices that sit unused are cleaned up in tiers: shut down after a short idle period (reclaim RAM), deleted after a longer one (reclaim disk).

More than one machine: fleets

One machine's worth of devices runs out eventually, and a team with several Macs should not have to hand each agent a specific one. So a simlock daemon runs in one of two modes. A worker is what every daemon is today — it owns the devices on its machine — and joining a fleet costs it two config keys pointing at a gateway; it keeps serving its own local agents exactly as before. A gateway owns no devices at all: workers dial out to it over a single WebSocket uplink (so a machine behind NAT needs no inbound port), and it fronts them with one fleet-wide queue, dispatching each request to the worker best placed to serve it — a warm device if one is free, otherwise the healthy, unqueued machine with the most free capacity. Agents and the web console point at one URL and stop caring which machine a device lives on: a gateway speaks the same contract a worker does, so lease, renew, release, status, and even simlock simctl / simlock adb (proxied to the owning worker) are the same commands they always were. The gateway never touches a device itself — the capacity accounting, the registry, and every safety invariant stay on the worker.

Key properties

  • Advisory coordination. Simlock does not sandbox anything. It works because agents are instructed to never call simctl / avdmanager directly and to only use devices handed to them by a lease.
  • TTL leases, one kind everywhere. Every lease carries a TTL and lives until it expires, is renewed, or is released — on the socket, over HTTP, and over MCP alike. simlock lease stays running in the background, renewing on a timer and releasing when it exits, so killing it normally frees the device at once; --detach skips the staying alive and leaves the renewing to you. A holder that dies without releasing costs its device only until the TTL runs out.
  • One lease per agent by default — raise lease.maxPerRequester to allow more; fleet-wide when a gateway issued it.
  • Managed-device registry. Simlock only ever shuts down, erases, or deletes devices it created itself. Everything else on the machine is read-only to it.
  • Agent-first output. CLI lease results are one JSON line on stdout; progress (e.g. provisioning ETAs) streams as JSON lines on stderr. The optional MCP server reserves stdout for MCP JSON-RPC.

See CLI.md for the command surface, CLIENT.md for the programmatic client, HTTP-API.md for the network API, and CONSOLE.md for the web console.