A fast, keyboard-summoned native macOS quick-chat panel built with SwiftUI and AppKit.
Summon a lightweight, distraction-free conversation window from anywhere with Option + Space, chat with OpenAI (via your existing local Codex CLI login) and open-weight models on OpenRouter from a single unified model picker, and dismiss right back to your work.
Zero external dependencies, zero external Swift packages, and no Electron/WebView or Node.js wrapper.
- Unified Model Picker (OpenAI + OpenRouter)
- OpenAI: Uses your local
codex loginsession (gpt-6-lunadefault when available) with hosted live web search—no OpenAI API key required. - OpenRouter: Optionally add an OpenRouter API key in Settings (
⌘,) to chat with fast, personable open-weight models alongside OpenAI, or run standalone with OpenRouter alone. - Curated Open-Weight Defaults: Ships with DeepSeek V4.1 Flash, Mistral Large 4, Qwen 3.8 Flash, Kimi K3, GLM 5.3 FlashX, Gemma 4 26B A4B, and DeepSeek V4 Pro—customizable directly in Settings (
slugorslug | Display Name). - Seamless Mid-Chat Switching: Switch between OpenAI and OpenRouter models inside the same conversation without losing context.
- Beam Follow-Ups: Preserves Beam's required reasoning metadata privately across turns and app restarts. Older replies without that metadata are supplied as quoted conversation context; reasoning is never shown in chat or forwarded to other models.
- Readable Errors: Failed requests expose a Details popover with the HTTP status, available provider diagnostics, selectable text, and Copy.
- OpenAI: Uses your local
- On-Demand Web Search
- Hosted live web search on OpenAI models and on-demand OpenRouter web search (
plugins: [{ id: "web" }]) triggered only when current information is needed, with inline Markdown source citations.
- Hosted live web search on OpenAI models and on-demand OpenRouter web search (
- Native macOS Experience
- Compact, draggable, resizable
NSPanelwith semantic light/dark appearance (clean white chat surface in light mode, native contrast in dark mode). - Joins all Spaces and works over fullscreen apps; stays open when it loses focus. Dismiss it with Escape or Command-W while keeping your draft, conversation, and warm backend ready.
- Native selectable prose, code blocks with one-click copy, and readable Unicode math normalization.
- Compact, draggable, resizable
| Shortcut | Action |
|---|---|
| ⌥ Space (configurable) | Summon or hide the SpeedChat panel from anywhere |
| ↵ (Enter) | Send message |
| ⇧↵ (Shift + Enter) | Insert newline in composer |
| ⌘N / ⌃N | Start a new chat (keeps selected model) |
| Esc | Stop active streaming response, or hide the panel when idle |
| ⌘W | Hide the panel without interrupting an active response or clearing draft |
| ⌘, | Open Settings |
| ⌘Q | Quit SpeedChat |
| Page Up / Page Down | Scroll transcript |
- macOS 14 (Sonoma) or newer (Apple Silicon /
arm64). - At least one model provider:
- OpenAI via Codex CLI: Install the Codex CLI and sign in once with
codex loginin Terminal, and/or - OpenRouter: An API key from openrouter.ai, configured in SpeedChat Settings (
⌘,) (works standalone with zero CLI dependencies).
- OpenAI via Codex CLI: Install the Codex CLI and sign in once with
When using OpenAI via Codex, the app automatically discovers codex (and node if your codex shim uses it) across /opt/homebrew/bin, /usr/local/bin, ~/.local/bin, common version-manager paths (~/.volta/bin, ~/.asdf/shims, ~/.local/share/mise/shims, ~/.fnm/current/bin, ~/Library/pnpm), and ~/.hermes/tools without sourcing shell startup files.
- Download
SpeedChat-macos-arm64.zipfrom the latest GitHub Release, unzip it, and dragSpeedChat.appinto/Applications. - Because the prebuilt app is ad-hoc signed rather than notarized with a paid Apple Developer ID, strip macOS's browser quarantine flag once in Terminal before first launch:
xattr -dr com.apple.quarantine /Applications/SpeedChat.app
open /Applications/SpeedChat.appClone the repository, run the Swift verification suite, build the signed .app bundle locally, and install to /Applications:
scripts/test.sh
scripts/build-app.sh
scripts/smoke-ui.sh
scripts/install-app.shscripts/build-app.shcompiles the release Swift executable, renders the.icnsapp icon natively with AppKit, bundles resources intodist/SpeedChat.app, and applies an ad-hoc code signature for local personal use.scripts/install-app.shvalidates the bundle signature and identifier (local.speedchat), stages the update, gracefully quits any running instance, retains a rollback copy (SpeedChat.previous.app), installs/Applications/SpeedChat.app, and launches it without altering your saved chats, preferences, or login items.scripts/package-release.shbuilds and packagesdist/SpeedChat-macos-arm64.zip(with SHA-256 checksum) for attaching to a GitHub Release.
To run directly from the checkout without installing to /Applications:
open dist/SpeedChat.app- Open SpeedChat (⌥Space) and press ⌘, (or click the menu-bar bubble icon → Settings…, or choose Configure OpenRouter in Settings… from the header model menu).
- Paste your OpenRouter API key (
sk-or-v1-...) using ⌘V or the Paste button. - Customize the open-source model list if desired:
- Add any OpenRouter model slug (
provider/model-nameorprovider/model-name | Custom Name). - Remove models you don't use with ×, or click Reset Defaults at any time.
- Add any OpenRouter model slug (
- Pick any model under the OpenAI or OpenRouter section of the header menu.
- Chat & Web Search Scope Only: Local file tools, shell execution, MCP servers, plugins, skills, browser automation, and code execution are explicitly disabled. Codex runs in an isolated empty temporary directory (
0700) with aread-onlysandbox andapprovalPolicy: "never". - Credential Isolation:
- Conversation state and OpenRouter configuration are stored in
~/Library/Application Support/SpeedChat/(state.jsonandopenrouter.json) with directory mode0700and file mode0600. - Subprocess environments are strictly allowlisted—ambient API keys,
NODE_OPTIONS, and OpenRouter credentials are never inherited by the Codex child process.
- Conversation state and OpenRouter configuration are stored in
- Safe Rendering & Links: Assistant replies render as native SwiftUI text/attributed strings (never HTML/WebView). All clicked links are validated at the native boundary (
LinkPolicy), permitting only well-formedhttp/httpsURLs without embedded credentials or control characters. Clipboard actions useNSPasteboarddirectly.
To remove local state after quitting:
rm -rf "$HOME/Library/Application Support/SpeedChat"# Run the full Swift Testing suite (ChatCore + NativeBridge)
scripts/test.sh
# Run the native UI fixture smoke test (generates docs/ui-smoke/report.json)
scripts/smoke-ui.shSee docs/verification.md for detailed test coverage and verification notes.
See THIRD_PARTY_NOTICES.md for third-party software notices.
Licensed under the MIT License. Copyright (c) 2026 Dana Pellerin.