github Swift re-analysis due

Sunrise-Labs-Dot-AI/ghostie

github

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.

maintainer
Sunrise-Labs-Dot-AI
licence
MIT
first seen
2026-07-01
last seen
2026-09-17
releases · 30d
1
short id

Drift inferred · capture-to-capture

No drift recorded — single capability capture; advisories appear once its surface changes.

capabilities 14 tools
transport stdio · http counts 14 tools · 0 res · 0 prompts permission surface via README inference

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.

skills & danger signals github-tarball
code evidence vv0.13.0 · github-tarball
evidence-backed findings quoted directly from the published source artifact — not inferred

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