Octagon GitHub

Built for iPhone fleets

Your iPhone farm, on autopilot. One Mac drives every phone over iOS Voice Control -
no cloud, no unofficial APIs - with a nine-tool MCP server
so Claude can queue sessions and read events.

MCP Tools
Claude Desktop + Code

tools

stdio server
fully local

See the tools

Zero Cloud
Everything Local

file

SQLite database
on your Mac

How it works

Voice Control
Real Device Actions

APIs

No unofficial APIs
no jailbreak

Get started

How it works

Real taps, not APIs

A hub on your Mac keeps one brain per phone. The Mac speaks a cue out loud - "Alpha Swipe Next" - and the phone's Voice Control custom command hears it and taps. Pacing is variable, not metronomic. One cue at a time, serialized by a global audio lock. The dashboard, the hub, the database: all local.

MCP tools over stdio

SQLite file holds it all

unofficial APIs, ever

cloud. Your Mac, your data

Octagon architecture On your Mac, a dashboard and a hub with one brain per phone write to a local SQLite file. The hub speaks cues to iPhones over Voice Control. An MCP client reaches the same farm over a local stdio server. Your Mac Dashboard localhost:3010, chat for the fleet queue Hub - infra/farm/hub.js one brain per phone, self-healing restarts, global audio lock: one cue at a time Brain Alpha speaks its cue Brain Bravo speaks its cue Brain Charlie speaks its cue SQLite - infra/db/farm.db every event and health record, one file spoken cue iPhone - Alpha Voice Control custom command "Alpha Swipe Next" iPhone - Bravo Voice Control custom command "Bravo Swipe Next" iPhone - Charlie Voice Control custom command "Charlie Swipe Next" say, one at a time Claude Desktop / MCP client mcp/server.js, local stdio same nine tools Octagon architecture On your Mac, a dashboard and a hub with one brain per phone write to a local SQLite file. The hub speaks cues to iPhones over Voice Control. An MCP client reaches the same farm over a local stdio server. Your Mac Dashboard localhost:3010 Hub - infra/farm/hub.js one brain per phone, self-healing restarts, global audio lock: one cue at a time Brain Alpha Brain Bravo Brain Charlie SQLite - infra/db/farm.db every event and health record say "Alpha Swipe Next" one at a time, global audio lock iPhone - Alpha Voice Control custom command: "Alpha Swipe Next" iPhone - Bravo Voice Control custom command: "Bravo Swipe Next" iPhone - Charlie Voice Control custom command: "Charlie Swipe Next" Claude Desktop / any MCP client mcp/server.js, local stdio, same nine tools
The hub keeps one brain per phone. Each brain speaks its phone's cue; the phone's Voice Control command does the rest. Everything is written to one SQLite file on your Mac.

Agents

One chat. Every phone.

Your farm is staffed. One conversation coordinates the whole layer: a supervisor, a monitor, and one agent per phone. Type "run 20" and a 20-minute session queues, executes, and reports back in the same thread.

Nova

Supervisor

Dispatches work and answers for the fleet. Ask @Nova status and get the queue, the health, the last word from every phone.

Sentry

Monitor

Watches health and counts the queue. When a phone goes quiet, Sentry says so in the chat.

Phone agents

One per phone

Queue pacing sessions, run them over Voice Control, take handoffs from other agents, and report every step back in the conversation.

Dashboard screenshot - synthetic demo data A single phone conversation in the Octagon dashboard: a queued 20-minute session, its start and finish reports, and a hub heartbeat, all on synthetic demo data
The conversation: "run 20" queues a session, the phone agent executes it and reports back. Synthetic demo data.

Demo

See it before you wire a single phone

The screenshot below was taken with synthetic demo data seeded by the repository. No real devices, accounts or activity are shown.

Dashboard screenshot - synthetic demo data Octagon fleet dashboard with four devices, their status, session stats and activity queue, running on synthetic demo data
The fleet dashboard: phones, sessions and health in one place. Synthetic demo data.

Quick start

Clone to dashboard

You need a Mac and Node 20 or newer. Clone, configure, install the two workspaces:

git clone https://github.com/YannisKiefer/octagon.git
cd octagon
cp .env.example .env
npm install --prefix infra/farm
npm install --prefix apps/dashboard

Optional: seed synthetic demo data, then start the dashboard:

node scripts/seed-demo.js
npm run dev --prefix apps/dashboard

Open http://localhost:3010. In development the dashboard opens without a login. A production build (npm run build && npm start) enforces authentication from .env: set DASHBOARD_ADMIN_USER and DASHBOARD_ADMIN_PASSWORD, and give NEXTAUTH_SECRET a real value:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Your data lives in one file, infra/db/farm.db, next to the checkout. Delete it and everything is gone. To connect real iPhones, follow the setup guide: enable Voice Control on each phone, create its custom command, plug in over USB.

Download

Octagon for Mac

Native app for Apple Silicon. Download the DMG, drag Octagon to Applications, and go. The dashboard, the hub, and the MCP server are all inside - no terminal required.

Download Octagon-1.1.0-arm64.dmg All releases

Unsigned build (no paid Apple certificate): the first launch needs one extra step. Open the DMG, drag Octagon to Applications, double-click it once, then allow it under System Settings - Privacy and Security - Open Anyway. After that it opens normally. Requires macOS on Apple Silicon. Prefer building it yourself? The source is the release archive.

MCP

Nine tools, one local server

tools over stdio

Octagon ships a local MCP server over stdio. There is no network listener and no auth by design; access is limited to the local SQLite file and the hub. Point Claude Desktop, Claude Code or any MCP client at it, and Claude can run the fleet:

The tools

list_phones
List phones registered in the local farm, with health.
get_phone
One phone with its health record.
run_session
Queue a pacing session for a phone (slot, minutes). It executes while the hub is running.
get_events
Recent events for a phone, newest first.
get_phone_screen
Capture the screen via idevicescreenshot, or get an explicit "unavailable" answer. Never a placeholder image.
list_agents
List the active agents of the multi-agent layer: supervisor, monitor, phone.
create_agent
Create an agent with a role: phone, monitor, supervisor or custom.
assign_agent
Move an active agent to another registered device.
handoff_task
Hand a task to a phone agent. The task moves to that agent's device and the handoff lands in the group chat.

The config

{
  "mcpServers": {
    "octagon": {
      "command": "node",
      "args": ["/absolute/path/to/octagon/mcp/server.js"]
    }
  }
}

In Claude Desktop this goes in claude_desktop_config.json. In Claude Code you can run: claude mcp add octagon -- node /absolute/path/to/octagon/mcp/server.js

Requirements and limits

What you need, and what to expect

You need

  • A Mac. Octagon uses the built-in say command for cues.
  • Node 20 or newer.
  • iPhones you own, with Voice Control enabled and set to English.
  • Optional: libimobiledevice for screen capture and reading UDIDs.

Know before you start

  • Screen capture needs libimobiledevice and a configured UDID. Without them, the MCP tool answers "unavailable" instead of guessing.
  • One phone is cued at a time. A global audio lock serializes the spoken cues.
  • Voice Control cues are English. Your iPhone Voice Control language should be set accordingly.
  • Sessions execute while the hub is up. It is a local process, not a service.
  • Posting content is on the roadmap, not implemented. No auto likes, comments, follows or DMs. No proxy support.

Privacy

One file. Your machine.

SQLite file, nothing else

All state lives in a single local SQLite file: infra/db/farm.db. Devices, health, tasks, events. Nothing leaves the machine: no telemetry, no accounts, no cloud storage. The MCP server is local stdio only. Delete the file, and everything is gone.