Content
# 🍝 Macaroni
### Your Mac, at your command.
**Macaroni** is a bridge between your Mac's apps and any AI agent: a growing
**suite of macOS app tools** that an agent can use to act on your behalf. One bowl,
many noodles. Everything runs **locally** on your Mac.
One core, three surfaces. The front door is a local
[MCP](https://modelcontextprotocol.io) server — point Claude, ChatGPT, or VS Code at
it and your agent gains hands on your Mac. There's also a `roni` CLI and an
**iMessage control loop**, and that last surface unlocks the marquee setup: a small,
always-on Mac you text like a contact, with an AI on the other end acting on your Mac
from your phone.
Today it serves the first noodle: **Messages (iMessage)**. Reminders, Notes, and
Calendar are next.
> macOS only. Everything runs **locally** on your Mac, with no server to host and nothing
> exposed to the network.
> 🧑💻 **Resuming work (humans & agents)?** Open this repo, read [AGENTS.md](AGENTS.md),
> then run `gh issue list --label roadmap` to grab a task. Full plan in [ROADMAP.md](ROADMAP.md).
---
## Why "Macaroni"? 🍝
Because the name is the product.
- **Mac** is in the name twice over: it's your *Mac*, and in Gaelic *Mac‑* means
**"son of."**
- **‑aroni → Roni.** In Hebrew, **Roni** (רוֹנִי) means **"my joy / my song,"** and
as a verb it's the imperative **"rejoice!"**, fittingly *a command.* So
**Mac‑a‑Roni** reads as **"son of joy,"** a tool that takes your orders and
brings a little delight.
- The dish itself traces back through Italian *maccheroni* to the Greek **makaria**,
rooted in **makar‑, "blessed / happy."** Macaroni has meant *the happy dish* for
a very long time.
And the noodle is a shockingly good metaphor for what we're building:
| 🍝 The noodle | 🛠️ The product |
|---|---|
| Many small pieces, one warm bowl | A **suite** of Mac tools working together |
| The elbow's **bend** is a connector | The **bridge** between you and your Mac (over iMessage) |
| Comfort food | An **approachable**, friendly agent, not a control panel |
| "Use your noodle" | The **agent's brain** doing the thinking for you |
So: the platform is the **bowl**, each app is a **noodle**, the iMessage link is the
**bridge**, and **Roni**, a little elbow‑macaroni at the helm, is the one taking
your orders.
---
## Deployment models
The **iMessage control loop** is the one surface you deploy rather than just call, so
it has two shapes. Both are ways to run the same bridge — the MCP server and CLI need
no deployment.
| Model | How you talk to it | Replies | Setup |
|---|---|---|---|
| **Dedicated agent Mac** (`--direct`) | text the agent's **contact** (its own Apple ID, e.g. `stormclaw`) | genuinely incoming (left) | a Mac + Apple ID for the agent |
| **Single Mac** (`--mention`) | text **yourself** `@roni …` | self-messages | none |
The dedicated model is the marquee setup: a small always-on Mac that bridges your
hardware + apps to an AI, reachable from your phone. The single-Mac/`@roni` model is a
zero-setup way to try it. Full guide: [docs/deployment.md](docs/deployment.md).
---
## Why it's local-only
Macaroni needs **Full Disk Access** to read `~/Library/Messages/chat.db` and
**Automation permission** for the Messages app to send. Because of that it must run
on your machine anyway, so the MCP server uses **stdio transport**: your AI client
(Claude Desktop, ChatGPT, VS Code) launches the server as a subprocess when it
starts and talks to it over stdin/stdout. No hosting, no open ports, nothing leaves
your Mac.
| | Local stdio MCP (used here) | Remote HTTP MCP |
|---|---|---|
| Hosting | None; client spawns it | You run a server somewhere |
| Network exposure | None | Exposed over HTTP |
| Where your data goes | Stays on your Mac | Sent to/through a server |
## Install
```bash
git clone https://github.com/jochien/macaroni
cd macaroni
scripts/setup.sh # Python >=3.10; builds .venv, installs dev+mcp
```
Prefer to install into your own environment? macaroni needs **Python >= 3.10**:
```bash
python3 -m pip install -e ".[mcp]" # add ,dev for tests (use a 3.10+ python)
```
### Grant macOS permissions (one time)
- **Full Disk Access** → add your terminal app (or the AI client that launches the
server). System Settings → Privacy & Security → Full Disk Access. Restart the app.
- **Automation → Messages** → granted on first send; allow when prompted.
### One-command checkup
```bash
roni setup # checks permissions + path, prints client config
roni setup --write # also writes the config into detected clients (backs up)
```
## Use it from the CLI
The suite namespaces each app under `roni <app> <action>`, so it grows cleanly:
```bash
roni messages recent 10
roni messages thread "+14255550123" 20
roni messages search "dinner"
roni messages send "you@icloud.com" "hello from the CLI"
# coming soon: roni reminders add "milk" · roni notes new "idea"
```
## Use it as an MCP server
Run directly to test:
```bash
roni-mcp # stdio server; Ctrl-C to stop
```
### Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"macaroni": { "command": "roni-mcp" }
}
}
```
### VS Code (GitHub Copilot)
Add to `.vscode/mcp.json` (or your user `mcp.json`):
```json
{
"servers": {
"macaroni": { "type": "stdio", "command": "roni-mcp" }
}
}
```
### ChatGPT
Use the desktop app's MCP/connector support (where available) and point it at the
`roni-mcp` stdio command, same as above.
**Full step-by-step setup for Claude, OpenAI/ChatGPT, and VS Code + Copilot,
including the absolute-path gotcha, is in [docs/install.md](docs/install.md).**
### Tools exposed
`messages_recent`, `messages_thread`, `messages_search`, `messages_context`,
`messages_send`, `messages_send_chat`.
## The bridge: an iMessage control loop
Drive an agent remotely over iMessage. Two modes, matching the deployment models above:
- **`--direct`** (dedicated agent Mac): text the agent's own contact. Every incoming
message from the owner is treated as a command; `--self` is the **owner's** handle.
- **`--mention`** (single Mac): text **yourself** with a mention token. Only messages
you write that contain the token are commands; everything else you text yourself
stays private.
```bash
# Single Mac, text yourself @roni:
roni listen --once --reset --json \
--self "you@icloud.com" --mention "@roni"
# Dedicated agent Mac, text the agent's contact (--self is the owner):
roni listen --once --reset --json \
--self "owner@icloud.com" --direct
```
Emits one JSON event and exits (re-run to continue; state is persisted so an agent
can drive the loop one turn at a time):
```json
{"event": "command", "text": "what's on my calendar", "source": "self", "group": false}
```
- `@roni` works in **group chats** too; only *your* mention line is read, never other
people's messages or surrounding context.
- Each event carries `source`, `chat_id`, and `group` so an agent knows where it came
from and can reply privately (default) or, on explicit request, to the whole group.
See [docs/control-loop.md](docs/control-loop.md) for the full agent loop pattern.
## Privacy & safety model
- Reads are **read-only**; the Messages database is never modified.
- The control loop reads **only messages you send** (plus people you explicitly
whitelist). See [docs/permissions.md](docs/permissions.md) for tiered access.
- Group context is read **only on explicit request** (`messages_context`).
- Posting to a group (`messages_send_chat`) messages other people, so agents must
**confirm the exact text with you first**.
## Roadmap: more noodles
The platform is the **bowl**; each app is a **noodle**. Next up: **Reminders**, then
**Notes**, **Calendar**, and **Contacts** (name → handle). The full plan lives in
[ROADMAP.md](ROADMAP.md), and the **dispatcher + sub-agents** design for autonomous
mode is in [docs/architecture.md](docs/architecture.md).
## Run it always-on (launchd)
```bash
roni daemon install --self you@icloud.com --mention "@roni" # single-Mac listener
# or, dedicated agent Mac: roni daemon install --self owner@icloud.com --direct
roni daemon status
roni daemon uninstall
```
## Project
- [CHANGELOG.md](CHANGELOG.md): versioned release notes (SemVer).
- [CONTRIBUTING.md](CONTRIBUTING.md): branch → PR → release workflow.
## Feedback
This is early and experimental, and feedback is very welcome. Open an
[issue](https://github.com/jochien/macaroni/issues) with bugs, ideas, or how you'd
like to use it. PRs welcome too (see [CONTRIBUTING.md](CONTRIBUTING.md)).
```
roni reminders add "milk" # 🔜 next noodle
roni notes new "idea" # 🔜
roni calendar today # 🔜
```
## License
MIT. See [LICENSE](LICENSE).