Source

Cortex

A native desktop client for working with models directly, in Tauri and React, built so the price of every reply is in front of you: live per-model prices, the cost of each answer, a monthly budget, and an estimate before you send. Streaming with stop, a global quick prompt, search, presets, and export to an Obsidian vault.

  • Rust
  • Tauri
  • React
  • TypeScript
Repository
mattrguerra/cortex
Branch
main
Files
140 files · 34 folders
Languages
Rust 48% · TypeScript 40% · CSS 7% · JavaScript 2%
Visibility
Private on GitHub, published here in full

Cortex

A native desktop client for language models that shows what every reply costs. Tauri v2 (a Rust shell) and React, on DeepInfra's hosted models or any model server you run yourself.

Cortex in light mode: a sidebar of chats with the cost of each, and a conversation about a backup script with the tokens and cost under the reply

Quick start

Needs Rust (stable) and Node 22. On Linux, also the WebKitGTK development libraries that .github/workflows/ci.yml installs.

npm ci
npx vite build           # first: the Rust build embeds the built interface
cargo test --workspace   # core logic, the provider against the stand-in, whole turns
npm test                 # Vitest: formatting, markdown safety, the store, the app renders
npm run typecheck        # tsc
npm run test:ui          # Playwright: the interface in Chromium, on sample data
npm run tauri dev        # the app, with hot reload

The end-to-end run drives the real app over WebDriver on Linux. It needs webkit2gtk-driver, xvfb, dbus-x11 and cargo install tauri-driver, and a debug build with the e2e feature first:

npx tauri build --debug --no-bundle --features e2e
scripts/e2e-linux.sh

CI also checks formatting and lints:

cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
npm run format:check     # Prettier over src/ and e2e/

Why it exists

Hosted chat apps charge a flat monthly fee whether you ask one question or a thousand. Paying per token through an inference provider is usually far cheaper, but only if you can see what you are spending. Cortex puts the price of every reply in front of you: tokens in and out and the dollar cost under each answer, a running total per conversation, the month so far against a budget, and an estimate of what a prompt will cost before you send it.

How it is built

The logic lives in crates/cortex-core, a plain Rust library: the provider client and its streaming parser, pricing and cost, SQLite storage with full-text search, attachments and export. src-tauri holds the commands, the windows, the tray and the shortcut. The React interface talks to it through one typed interface, whose TypeScript types are generated from the Rust structs. More in docs/architecture.md.

crates/cortex-core/   providers, streaming, pricing, cost, storage, export
crates/standin/       the test stand-in for DeepInfra and local servers
src-tauri/            the desktop shell: commands, windows, tray, shortcut
src/                  the React interface (main window and quick prompt)
e2e/                  Playwright (interface) and WebDriver (real app) tests
docs/                 architecture, cost accounting, the Mac checklist

What it does

  • Streaming chat with any chat model on DeepInfra, or on a local server (Ollama, LM Studio, llama.cpp: anything OpenAI-compatible). Stop a reply at any point; what arrived is kept.
  • A cost meter everywhere. Live per-model prices from DeepInfra, stored with each reply so history never changes. Estimates are labeled "est.". Local models cost nothing. See how cost is counted.
  • A model picker with prices: search, filter by vision, reasoning, favorites or local, and see input and output price per million tokens and the context size before you choose.
  • A quick prompt. Cmd+Shift+Space anywhere opens a small frosted prompt over whatever you are doing. Ask, read, press Esc. Cmd+Enter moves the conversation into the main window.
  • Presets: saved system prompts (with an optional model and temperature), applied to a chat in one click.
  • Search across every chat (full-text, as you type).
  • Export to an Obsidian vault: a conversation as Markdown with frontmatter (models, tokens, cost), images copied beside it.
  • Images and files: paste or drop an image for a vision model (it is downscaled first, since vision models bill by size), or a text file to read as context.
  • macOS window materials: frosted panels over native vibrancy, light and dark, with a choice of material and panel tint, and a solid mode for when transparency gets in the way.
  • Menu bar: this month's spend, a new chat or the quick prompt, from anywhere.

Screenshots

Cortex in dark mode, reading a chart of two pricing plans with a vision model

The model picker: every chat model with its input and output price per million tokens and its context size

Usage: spend this month by model and by day

The quick prompt with an answer and its cost

Screenshots are the interface on its built-in sample data (every chat in them is invented), shown over the backdrop the page paints when there is no native vibrancy. On a Mac the panels sit on the frosted desktop instead.

Privacy

  • Chats, attachments and settings live in one SQLite file on your computer.
  • API keys live in the macOS Keychain, never in the database or a file. The interface can set or remove a key but never read one back. A key is checked with the provider before it is stored, so a mistyped one is caught at once.
  • The only network traffic is to the provider you chose, from the Rust side. The webview itself cannot reach the network (its content security policy allows none).
  • No telemetry, no accounts, no update pings. With a local model, nothing leaves the machine at all.

Install

Build from source: after the Quick start, npm run tauri build makes a release build (the .app and a .dmg on macOS). The build is ad-hoc signed, not notarized, so macOS asks once: open System Settings, Privacy & Security, and choose "Open Anyway". Then:

  1. Settings, DeepInfra: paste your API key (from deepinfra.com, Dashboard, API Keys).
  2. Optionally add a local server under Local servers (Ollama is http://localhost:11434/v1).
  3. Set a monthly budget if you want the warnings.

npm run dev serves the interface alone in a browser, on sample data.

Tests

The Rust tests run every provider path against crates/standin, a small OpenAI-compatible server whose behavior is picked by model id: streaming with usage, no usage, cached tokens, reasoning, images, errors before and during a stream, and a slow reply for testing Stop (which checks that the server sees the connection close). The Playwright run covers two window sizes in both themes, the main flows, and an axe check for contrast and labels. The end-to-end run starts the actual Tauri binary under a virtual display, points it at the stand-in, and sends a message, stops one, searches, and exports a note.

What needs a real key and a Mac (live prices, DeepInfra's usage reporting, vibrancy, the Keychain, the global shortcut) is a five-minute checklist in docs/verify-on-mac.md.

Keyboard

Keys Does
Cmd+Shift+Space Quick prompt, from anywhere (changeable)
Cmd+N New chat
Cmd+K Search chats
Cmd+, Settings
Enter / Shift+Enter Send / new line
Esc Stop the reply; close a panel
Cmd+Enter (quick prompt) Continue in the main window

Limitations

  • No tool calling or agents: Cortex is for talking to a model, on purpose.
  • macOS is the target. Linux builds and is tested (without vibrancy); Windows is not built.
  • The quick prompt may not appear over full-screen apps on macOS.
  • Token estimates for local servers are approximate, and marked as such.
  • Prices come from DeepInfra's public model list, which is an extension to the OpenAI format rather than a documented contract; the dated offline copy is the fallback.

License

MIT.