io.github.honeycrisp-suite/context
Local-first personal context over MCP: mail/calendar metadata, briefings, person lookups. No cloud.
Open source Open in the app JSON README (API)
About
Local-first personal context over MCP: mail/calendar metadata, briefings, person lookups. No cloud.
Details
- Kind
- MCP servers
- Topic
- Productivity
- Publisher
- honeycrisp-suite
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 0.1.2
- Last push
- 2026-08-27T03:39:14Z
- Repository state
- ativo
- Language
- TypeScript
- License
- MIT
- Added
- 2026-08-29 04:00:08
- Updated
- 2026-08-29 04:00:08
- Origin id
io.github.honeycrisp-suite/context
README
# Cortland π
**Give an AI real access to your Mac β Mail, Calendar, Reminders, Notes, files β
without giving it the keys.** Every consequential action previews first, waits
for your approval through a channel the model can't touch, gets logged, and can
be undone. Bring your own model: Claude, or a local one that never leaves the
machine.
```
You: Add a reminder to call the vet tomorrow at 2pm
Cortland: Received β working on itβ¦
Cortland: Added "Call vet" for tomorrow, Aug 3 at 2:00 PM.
```
That conversation happened over iMessage, answered by a 4 GB model running on
an 8 GB MacBook Air. Nothing left the Mac.
The texting interface needs a **second Apple ID**, signed into Messages on the
Mac only β a mouthpiece, not a worker. It owns no mail, no calendar, no data.
You text it from your phone like any contact; the Mac still does the work as
*you*. Your system iCloud stays yours. Claude Code, Cursor, Codex, and other
MCP clients skip this step: they talk to the same tools over stdio.
---
## What it looks like in use
**Ask about your week** β reads are free, no approval needed:
```
You: Anything from the school this week?
Cortland: Three emails from Lincoln Elementary. Two are the weekly
newsletter; one from Ms. Alvarez on Tuesday asks for a
permission slip by Friday.
```
**Ask it to change something** β writes stop and ask, every time:
<p align="center">
<img src="docs/images/imessage-approval.svg" alt="An iMessage thread: the user asks to delete a reminder; Cortland acknowledges, then replies with an approval request naming the reminder, its list, and its due date, asking the user to reply "yes a3f9c1"; the user replies with the code; Cortland confirms the deletion with the same details." width="430">
</p>
The code in that prompt is generated by the framework and never enters the
model's context β so even a fully prompt-injected model can't forge your
approval. Ignore the message and the action expires, refused.
**Ask what it can do** β answered from the tools actually installed, so it
can't overclaim:
```
You: what can you do?
Cortland: Here's what I can do with your Mac:
β’ Calendar: list, look up, create, delete
β’ Mail: search, read, follow threads, draft, send (asks first), flag, file
β’ Notes: search, read, create, add to
β’ Reminders: list, search, create, tick off, delete
Anything that deletes or changes things asks you first β I text
you a code and wait for "yes <code>". Reads just happen.
```
**In Claude Code or Claude Desktop**, the same tools are just there:
> **You:** send a reply to Ms. Alvarez saying the slip is coming Thursday
> **Claude:** *[searches mail, reads the thread]* I can send this from your
> Personal account to alex@example.com. Approve in the usual channel.
`mail_send` is write-gated. Live mode plus per-action human approval. A stolen
token can only *ask*.
---
## Requirements
macOS only. Nothing here runs on Windows or Linux β the tools talk to Apple
apps via Automation.
| | Minimum | Comfortable |
|---|---|---|
| **OS** | macOS 13 Ventura | macOS 15+ |
| **Mac** | Any Mac that runs Ventura (Intel can drive Cursor/Claude) | Apple Silicon (M1 or newer) |
| **Node** | 20 LTS (`node -v`) | 22 |
| **Toolchain** | Xcode Command Line Tools (`xcode-select -p`) | same β `better-sqlite3` compiles native code |
| **Client** | One MCP app: Cursor, Claude Code, Claude Desktop, Codex, or LM Studio | plus Ollama if you want to **text** it |
| **RAM** | 8 GB (cloud/Cursor model, or Gemma 4 E2B) | 16 GB+ for larger local models |
| **Disk** | ~500 MB for this repoβs build | **+6 GB** if you pull `gemma4:e2b-it-qat` |
| **Apple apps** | The apps you want touched, signed in as you | Mail + Reminders is the usual first pair |
**iMessage bridge only:** macOS 13+ (modern `chat.db`), Full Disk Access for
the process that runs Node, Automation β Messages, and a **second Apple ID**
signed into Messages.app β not into System Settings. See
[SETUP.md Β§5.1](SETUP.md#51-create-the-assistants-apple-id).
**Osaurus as a client:** Apple Silicon, macOS 15.5+.
Not required: an npm `@cortland` install (0.2.0 is GitHub-only for now), a
developer account, iCloud for Path A, or any API key.
---
## Quick start
**Fastest path to βit searched my mailβ** β Cursor (or Claude Code) as the
brain, no second Apple ID, no Ollama:
```bash
xcode-select --install # if `xcode-select -p` fails
git clone https://github.com/cortland-suite/cortland.git
cd cortland
npm install && npm run build # first install compiles sqlite β a minute
```
Then Cursor Settings β MCP, add servers pointing `node` at
`packages/mail/dist/server.js` (and reminders/notes/calendar if you want
them). Absolute paths. JSON is in
**[docs/08_local_models.md](docs/08_local_models.md#cursor)**.
Ask: *search my mail for anything from school this week.* macOS will prompt
**Automation** (Cursor β Mail). Allow it.
Writes stay previews until you set `"live": true` in
`~/Library/Application Support/cortland/config.json`. Even then, send/delete
asks you per action.
**Texting it from your phone** is a longer path (second Apple ID + Ollama).
[SETUP.md](SETUP.md) is the ordered list; [docs/08](docs/08_local_models.md)
is the illustrated one.
---
## Why it exists
Most MCP servers for personal data are thin wrappers around AppleScript:
`delete_email`, `send_message`, executed the instant a model calls them. That's
a hard thing to trust with an inbox, and the alternatives don't help β cloud
assistants (Poke, Arlo, Lindy) can't touch Apple-native data at all, because
Apple gives them no API, and self-hosted agents like OpenClaw run ungoverned
(a CVSS 8.8 in January 2026, with permission gates still on the roadmap).
Cortland inverts the default. A tool call *previews* what it would do unless
you've opted into live mode, and even then every consequential action waits for
you. The framework enforcing that is a small library with a test suite proving
each guarantee can't be bypassed β and every tool in the suite is built on it.
---
## The guarantees
| | |
|---|---|
| **Dry-run by default** | Gated tools preview instead of executing. Every config error resolves *toward* dry-run. |
| **The human gate is out-of-band** | Approval arrives via a native dialog, a file you move, your client's own UI, or a text you reply to β never through model text. |
| **Everything is audited** | Success, failure, dry-run, denial, refusal: one local SQLite row each. "What did my tools actually do?" always has an answer. |
| **Undo is enforced at registration** | A tool claiming native undo must produce a recipe *before* the write, or the framework refuses it. |
| **Content is data, not instructions** | Everything read from mail, notes, or messages returns inside a nonce-delimited fence. |
| **Safety by absence** | No ungated send. No attendee invitations. No reading conversations other than your own. |
| **Local-first** | No accounts, no credentials, no cloud. Your model, your machine, your disk. |
---
## Install
`@cortland` 0.2.0 is not on npm yet. From the repo:
```bash
git clone https://github.com/cortland-suite/cortland.git
cd cortland
npm install
npm run build
npx cortland setup
```
The wizard asks before every step and records what it did. Full walkthrough β
including the iMessage bridge, permissions, and model choice β in
**[SETUP.md](SETUP.md)**. Connecting Cursor, Codex, LM Studio, Osaurus, or
Ollama: **[docs/08_local_models.md](docs/08_local_models.md)**.
---
## Packages
| Package | What it does |
|---|---|
| [`@cortland/governed`](packages/governed) | The framework: dry-run defaults, approval gates, audit, provenance, undo, injection fencing. Build your own governed tools on it. |
| [`@cortland/mail`](packages/mail) | Apple Mail: read, search (two tiers), threads, drafts, send (write-gated). |
| [`@cortland/reminders`](packages/reminders) | Reminders: lists, search, create, complete, delete β with native undo. |
| [`@cortland/notes`](packages/notes) | Notes: folders, search, read, create, append. |
| [`@cortland/calendar`](packages/calendar) | Calendar: window queries, create, delete. Cannot send invitations, by design. |
| [`@cortland/context`](packages/context) | Local context layer: mail/calendar *metadata* (pointers, never bodies), briefings, person lookups, a corrections flywheel. |
| [`@cortland/imessage`](packages/imessage) | Text your own AI. Second Apple ID in Messages (mouthpiece only); owner-only by construction, approvals by reply. |
| [`@cortland/folders`](packages/folders) | Folder-as-API: drop a file in iCloud from any device, a declared local pipeline runs. |
| [`@cortland/remote`](packages/remote) | Reach the suite from your other devices over your own private network. |
| [`@cortland/setup`](packages/setup) | The onboarding wizard. |
---
## Bring your own model
Cortland is the tools. You pick the brain.
<p align="center">
<img src="docs/images/two-paths.svg" alt="Path A: an MCP client hosts the model and Cortland is a plugin. Path B: you text an iMessage bridge; Ollama is the brain; the Mac still acts as you." width="860">
</p>
**Path A.** Cursor, Claude Code, Claude Desktop, Codex, LM Studio, or Osaurus
hosts the model. Cortland is an MCP plugin. No second Apple ID.
**Path B.** You text it. A second Apple ID signs into Messages on the Mac
(mouthpiece only). Ollama runs Gemma 4 on disk. Approvals are `yes <code>`
in the same thread.
Field-tested on an 8 GB M2: `gemma4:e2b-it-qat` (4.3 GB) makes clean tool
calls and refuses honestly. The governed contract matters *more* with a
small model, not less.
**Walkthroughs, including LM Studio and Osaurus from a clean install:**
**[docs/08_local_models.md](docs/08_local_models.md)**. Clean-Mac order,
permissions, and the iMessage second-ID steps: **[SETUP.md](SETUP.md)**.
---
## Privacy model
- **Pointers, not copies.** The context layer stores metadata referencing
messages by ID; bodies are never stored. Delete a message in Mail and the
pointer dangles and gets pruned.
- **Model use is opt-in and declared.** Works fully deterministically with no
model. Configure one and its network egress is declared in config and
recorded in the audit log on every run.
- **Nothing phones home.** The only optional outbound call is a push ping you
configure yourself, and its body is a fixed string carrying no information.
---
## Docs
- **[SETUP.md](SETUP.md)** β clean Mac to working assistant, with the gotchas.
- **[docs/08_local_models.md](docs/08_local_models.md)** β connect Cursor, Codex,
LM Studio, Osaurus, or Ollama; illustrated, from zero.
- **[SECURITY.md](SECURITY.md)** β reporting, and what's in scope.
- **`docs/`** β one design doc per component: the framework contract (01),
Mail (02), folder-as-API (03), the context layer (04), remote access (05),
the iMessage bridge (06), the threat model / review guide (07), and local
models (08).
- **`NOTES.md`** β the engineering log: decisions with dates, open questions,
and every field finding, including the ones that were embarrassing.
## License
MIT. See [LICENSE](LICENSE).