AI proposes, you approve. A macOS menu bar app that gives Claude read-only iMessage + WhatsApp access with a staged-draft, human-approval send flow.
Drift inferred · capture-to-capture
No drift recorded — single capability capture; advisories appear once its surface changes.
tools
-
clear_message_thread_priority
Clear a cross-transport priority.
-
discard_message_draft
Delete one staged draft by generalized draft_ref.
-
get_message_current_time
UTC + system-local timestamps, for building since filters.
-
get_message_draft
Read one staged draft by generalized draft_ref.
-
get_message_thread
Messages for a generalized thread_ref, paginated via before.
-
ghostie_health_check
Diagnose the facade plus iMessage and WhatsApp daemon dependencies.
-
list_message_drafts
List staged drafts across one or all transports.
-
list_message_thread_priorities
List cross-transport priorities.
-
list_message_threads
Recent threads across one or all transports. Requires since or contact_filter.
-
query
shorter than 2 chars → rejected.
-
search_message_history
Search across one or all transports. Requires query plus since or contact_filter.
-
set_message_thread_priority
Set a cross-transport priority on a thread_ref.
-
since
older than 2 years → rejected (no deep-history dumps).
-
stage_message_draft
Stage an iMessage or WhatsApp draft for human approval. Does NOT send.
analyzed commit efeb7b9 · analyzer v33 · 3d ago
skills & prompt files 11
- agent-rules Sunrise-Labs-Dot-AI-ghostie-efeb7b9/AGENTS.md
- agent-rules Sunrise-Labs-Dot-AI-ghostie-efeb7b9/CLAUDE.md
- agent-rules Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/AGENTS.md
- agent-rules Sunrise-Labs-Dot-AI-ghostie-efeb7b9/menubar/AGENTS.md
- agent-rules Sunrise-Labs-Dot-AI-ghostie-efeb7b9/scripts/AGENTS.md
- agent-rules Sunrise-Labs-Dot-AI-ghostie-efeb7b9/skills/AGENTS.md
- skill Sunrise-Labs-Dot-AI-ghostie-efeb7b9/skills/birthday-reminder/SKILL.md
- skill Sunrise-Labs-Dot-AI-ghostie-efeb7b9/skills/birthday-text-voice/SKILL.md
- skill Sunrise-Labs-Dot-AI-ghostie-efeb7b9/skills/texting-analytics/SKILL.md
- skill Sunrise-Labs-Dot-AI-ghostie-efeb7b9/skills/texting-voice-skill-creator/SKILL.md
- agent-rules Sunrise-Labs-Dot-AI-ghostie-efeb7b9/tests/AGENTS.md
danger signals1
- suspicious endpoint us.i.posthog.com (telemetry) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/site/analytics.js :21
var POSTHOG_HOST = "https://us.i.posthog.com";
code files: 468
filesystem 97
- fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/callhistory.test.ts :3
import { mkdtempSync, rmSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/gaps.test.ts :3
import { mkdtempSync, rmSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/index.test.ts :2
import { mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/index.ts :24
import { readFileSync, writeFileSync, existsSync, lstatSync, renameSync, unlinkSync, mkdirSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/keeptabs.test.ts :3
import { mkdtempSync, rmSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/seed.test.ts :3
import { mkdtempSync, rmSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/signals.test.ts :3
import { mkdtempSync, rmSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/signalsCache.test.ts :2
import { mkdtempSync, rmSync, writeFileSync, symlinkSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/signalsCache.ts :36
} from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/store.test.ts :2
import { mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/store.ts :18
} from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/ghostie/src/index.test.ts :2
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
show 28 more
- fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/ghostie/src/witness.test.ts :2
import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/ghostie/src/witness.ts :31
} from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/attachments.test.ts :14
} from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/chatdb/contacts.ts :13
import { readdirSync, existsSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/chatdb/open.ts :3
import { existsSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/chatdb/queries.test.ts :3
import { mkdtempSync, mkdirSync, writeFileSync, chmodSync, rmSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/chatdb/queries.ts :5
import { statSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/control-gate.test.ts :10
import { mkdtempSync, rmSync, writeFileSync, existsSync, readFileSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/control-gate.ts :47
import { existsSync, readFileSync, writeFileSync, statSync, mkdirSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/daemon/index.ts :11
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/daemon/peer-auth.ts :56
import { statSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/daemon/rpc.test.ts :8
import { mkdtempSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/daemon/server.ts :21
import { existsSync, unlinkSync, chmodSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/device-id.test.ts :8
import { mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync, mkdirSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/imessage/audit.test.ts :2
import { mkdtempSync, rmSync, existsSync, readFileSync, chmodSync, statSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/imessage/audit.ts :30
import { mkdirSync, existsSync, appendFileSync, readFileSync, lstatSync, chmodSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/imessage/failure-log.test.ts :2
import { mkdtempSync, rmSync, readFileSync, existsSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/imessage/failure-log.ts :22
import { mkdirSync, existsSync, appendFileSync, lstatSync, chmodSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/automations.test.ts :2
import { mkdtempSync, rmSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/automations.ts :1
import { existsSync, lstatSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/contacts-cache.test.ts :2
import { mkdtempSync, writeFileSync, rmSync, mkdirSync, symlinkSync, chmodSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/contacts-cache.ts :1
import { existsSync, readFileSync, statSync, lstatSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/drafts.test.ts :2
import { mkdtempSync, writeFileSync, rmSync, readdirSync, statSync, copyFileSync, symlinkSync, readFileSync, existsSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/drafts.ts :1
import { mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync, statSync, lstatSync, existsSync, renameSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/migrate.ts :57
} from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/priorities.test.ts :2
import { mkdtempSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync, writeFileSync, mkdirSync } from "node:fs"; - fs Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/priorities.ts :25
import { existsSync, lstatSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs"; - fs (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/storage/relay-executor.test.ts :9
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
57 more not shown — this panel samples each group; the count above is the real total.
shell / exec 10
- shell (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/birthday-generator/src/index.test.ts :29
const p = Bun.spawnSync(["bun", "run", ENTRY, "--db", join(dir, "nope.db"), "--no-calls", "--no-cache", ...args], { cwd: dir }); - shell (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/ghostie/src/index.test.ts :119
const proc = Bun.spawn(["bun", "run", "src/index.ts"], { - shell (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/ghostie/src/remote-host.test.ts :4
const child = Bun.spawn(["bun", "run", "src/remote-host.ts"], { cwd: new URL("..", import.meta.url).pathname.replace(/\/src\/$/, "/"), stdin: "pipe", stdout: "pipe", stderr: "pipe" }); - shell Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/daemon/codesign.ts :15
const p = Bun.spawnSync({ - shell Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/imessage/send.ts :24
import { spawn } from "node:child_process"; - shell (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/scripts/pair.ts :180
Bun.spawn({ cmd: ["open", PNG_PATH], stdout: "ignore", stderr: "ignore" }); - shell Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/daemon/codesign.ts :25
const p = Bun.spawnSync({ - shell Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/storage/keychain.ts :69
const proc = Bun.spawnSync({ - shell (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/tests/experience/mcp-agent-choice-contract.mjs :2
import { spawnSync } from "node:child_process"; - shell (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/tests/remote-tunnel/probe.test.ts :5
import { execFileSync } from 'node:child_process';
network 13
- net (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/ghostie/src/index.test.ts :3
import { createServer, type Server } from "node:net"; - net Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/daemon/peer-auth.ts :55
import type { Socket } from "node:net"; - net Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/imessage-drafts/src/daemon/server.ts :20
import { createServer, type Server, type Socket } from "node:net"; - net Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/remote-relay/src/page.ts :21
const response=await fetch(path,{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+token},body:JSON.stringify(body)}); - net (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/remote-relay/src/server.test.ts :14
const request = (path: string, body?: unknown, auth = token, headers: Record<string, string> = {}) => fetch(`http://127.0.0.1:${relay.server.port}${path}`, { method: body === undefined ? "GET" : "POST - net Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/remote-relay/src/server.ts :39
async fetch(request, server) { - net Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/shared/src/daemon-client.ts :1
import { Socket } from "node:net"; - net (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/scripts/pair.ts :20
import { connect, type Socket } from "node:net"; - net Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/daemon/peer-auth.ts :60
import type { Socket } from "node:net"; - net Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/daemon/server.ts :19
import { createServer, type Server, type Socket } from "node:net"; - net (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/site/scripts/check-download-flow.js :5
const https = require("https"); - net (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/tests/remote-tunnel/probe.test.ts :21
const verifiedFetch: typeof fetch = ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, { ...init, tls: { ca } })) as typeof fetch;
show 1 more
- net (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/tests/remote-tunnel/probe.ts :17
async fetch(request) {
secrets 15
- secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/daemon/send-direct.test.ts :9
process.env.WHATSAPP_MCP_TEST_KEY = randomBytes(32).toString("base64"); - secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/storage/crypto.test.ts :6
const originalTestKey = process.env.WHATSAPP_MCP_TEST_KEY; - secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/storage/keychain-probe.test.ts :17
const savedTestKey = process.env.WHATSAPP_MCP_TEST_KEY; - secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/storage/keychain.test.ts :9
const savedTestKey = process.env.WHATSAPP_MCP_TEST_KEY; - secrets Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/storage/keychain.ts :162
const testKey = process.env.WHATSAPP_MCP_TEST_KEY; - secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/storage/messages-undecryptable.test.ts :19
const savedTestKey = process.env.WHATSAPP_MCP_TEST_KEY; - secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/storage/messages.test.ts :14
process.env.WHATSAPP_MCP_TEST_KEY = randomBytes(32).toString("base64"); - secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/mcps/whatsapp-drafts/src/storage/session-recovery.test.ts :19
const savedTestKey = process.env.WHATSAPP_MCP_TEST_KEY; - secrets Sunrise-Labs-Dot-AI-ghostie-efeb7b9/site/api/ai-proxy.js :20
const defaultClerk = process.env.CLERK_SECRET_KEY - secrets Sunrise-Labs-Dot-AI-ghostie-efeb7b9/site/api/create-tip-session.js :19
const stripeClient = process.env.STRIPE_SECRET_KEY - secrets Sunrise-Labs-Dot-AI-ghostie-efeb7b9/site/api/premium.js :22
const stripeClient = process.env.STRIPE_SECRET_KEY - secrets Sunrise-Labs-Dot-AI-ghostie-efeb7b9/site/api/referral.js :26
const defaultClerk = process.env.CLERK_SECRET_KEY
show 3 more
- secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/site/scripts/check-tip-jar.js :8
process.env.STRIPE_SECRET_KEY = "sk_test_unit"; - secrets Sunrise-Labs-Dot-AI-ghostie-efeb7b9/site/texting-wrapped/api/create-tip-session.js :41
const secretKey = process.env.STRIPE_SECRET_KEY; - secrets (weak) Sunrise-Labs-Dot-AI-ghostie-efeb7b9/tests/remote-tunnel/probe.ts :53
const key = process.env.PROBE_TLS_KEY;
declared dependencies 4
- @clerk/backend@^1.21.0
- @vercel/edge@^1.3.1
- stripe@^18.0.0
- github.com/sparkle-project/Sparkle@2.9.2