NEW v0.5.10 — Claude Opus 4.8 is now the default
// guide · security model

How we handle your keys and your code.

Plain English. No weasel words. If we can't honor a guarantee, we don't make it.

// api keys

Keys live in a permission-locked file.

Every provider API key you enter in the setup app is written to ~/Library/Application Support/Joint Chiefs/credentials.json with file mode 0600 — readable and writable only by your macOS user account. With FileVault on, it's encrypted at rest like everything else on the disk. The key never leaves this Mac except as the Authorization header of a request to the provider you configured.

Only one binary reads or writes that file: jointchiefs-keygetter, a minimal Swift executable. The CLI and the MCP server never touch the file directly. When they need a key, they spawn jointchiefs-keygetter as a child process, read the key from its stdout, use it for one request, and drop it. The file's access path lives in exactly one place you can audit.

Earlier versions used the macOS Keychain. We moved off it because Joint Chiefs has to work headless — over SSH, from a cron job, with no one logged in. The Keychain's access approval is a GUI prompt, and a headless session can't answer one. A 0600 file has no prompt and no session dependency. It's the same way an SSH key or an AWS credentials file is stored — and it's honest about the trade: a 0600 file protects your keys from other accounts on the Mac, not from something already running as you. Upgrading from an older version? The setup app moves your existing Keychain keys into the file automatically on first launch.

// the mcp server

Stdio only. No ports. No network listeners.

The MCP server (jointchiefs-mcp) talks to exactly one thing: the parent process that spawned it. Communication is JSON-RPC over stdin/stdout. It never binds a TCP port, never listens on a Unix socket, never accepts HTTP, never sends telemetry.

This isn't a configuration choice — it's an architectural invariant. The code has no HTTP, SSE, or WebSocket server at all. Every security assumption in this product depends on the MCP client owning our stdio by definition. If you don't trust the client that spawned us, nothing else matters.

// where your code goes

Your code goes to the providers you configured. Nowhere else.

When you run a review, the only outbound network traffic is to the LLM providers whose API keys you've enabled: OpenAI, Google Gemini, xAI Grok, Anthropic, and optionally a local model — either via Ollama or any OpenAI-compatible server (LM Studio, Jan, llama.cpp-server, Msty, LocalAI), which usually runs on your own machine. No analytics, no error reporting, no update-check pings to our servers — because we don't have any.

Provider responses land in a local transcript file on your Mac. We don't cache them anywhere else. You can delete transcripts whenever you want; they have no external representation.

// distribution

How the binaries reach you.

SigningAll four binaries (jointchiefs, jointchiefs-mcp, jointchiefs-keygetter, jointchiefs-setup) are signed with an Apple Developer ID.
NotarizationThe DMG and all four binaries are notarized by Apple — Gatekeeper validates every one before launch.
UpdatesThe macOS app updates via Sparkle, which verifies an EdDSA signature on every update payload before installing.
CLI / MCP updatesThe CLI and MCP server binaries are versioned alongside the app and replaced atomically on update.
Source auditEntire repo is MIT-licensed at github.com/djfunboy/joint-chiefs. Reproducible local builds via swift build -c release.
// threat model

What we protect against — and what we don't.

We protect against

  • API keys leaking into shell history, logs, or the MCP wire protocol — they're confined to one 0600 file and read only via the keygetter.
  • Keys being invalidated by routine updates — they live in a plain file, not bound to any binary's code signature.
  • Rogue processes reading the MCP server's input — the stdio-only invariant means the parent process is the only speaker.
  • Network-based supply-chain attacks on the update path — Sparkle EdDSA verification catches tampered payloads.
  • Silent error-reporting or analytics — there are none, so there's nothing to tamper with.

We don't protect against

  • A malicious MCP client. The client owns our stdio by construction — we trust it at spawn time.
  • A compromised provider. If OpenAI's API is breached, your review code is in that breach. Choose your providers accordingly.
  • Local malware that already has your user account. A 0600 file is readable by anything running as you — and so is the keygetter. Without FileVault, so is the disk to someone with physical access. That's a macOS-level concern, not an app-level one.
  • Shoulder surfing, screen recording, or unrelated exfiltration vectors outside this app's boundary.

Found something worth flagging?

Open an issue on GitHub with the security label, or email security@jointchiefs.ai for anything sensitive. Coordinated disclosure welcome.