Skip to content

danb235/rewritedb

Repository files navigation

RewriteDB

CI Latest release Platform License

Rewrite selected text — or dictate by voiceanywhere on your Mac with a keyboard shortcut. Select text → press ⇧⌘R → Claude rewrites it and pastes it back in place. Or hit your dictation hotkey → speak → the transcription (optionally cleaned up by Claude) is pasted at your cursor. Rewriting uses the Anthropic (Claude) API by default, or an optional on-device model (no API key, fully offline); speech-to-text always runs 100% on-device with Whisper.

RewriteDB is an open-source reimagining of the (now abandoned) RewriteCmd app. It fixes the bug that broke the original: when using the Claude API, model IDs are no longer baked into the binary — the model list is fetched live from Anthropic, so it stays current automatically (retired models drop off and new ones appear with no app update). It also goes further than the original with an optional on-device model and voice dictation.

┌─────────────────┐   ⇧⌘R    ┌────────────────┐   rewrite    ┌────────────────────┐
│  Any macOS app  │ ───────▶ │    RewriteDB    │ ───────────▶ │  Claude API        │
│ (selected text) │ ◀─────── │ (menu-bar app)  │ ◀─────────── │  ·or· local model  │
└─────────────────┘  paste   └────────────────┘   result      └────────────────────┘

Contents

Features

  • Global hotkey rewrite — works in any app (Mail, Slack, Notion, IDEs, browsers…).
  • Local rewrite option (offline, no API key) — don't want to pay for the API? In Settings → Rewrite, set the primary provider to Local (on-device) and download a small model (Qwen3-4B-Instruct, Q4_K_M, ~2.5 GB) that runs entirely on your Mac via llama.cpp. Keep both configured and toggle anytime; the model loads on first use and unloads when idle to free memory.
  • Automatic fallback — make Claude your primary and enable Fall back to the other provider; if Claude is unavailable (offline, rate-limited, or a server error) RewriteDB transparently rewrites with the local model instead, so a rewrite never just fails when you're offline.
  • On-device voice dictation — press a hotkey, speak, and the transcription pastes at your cursor. Powered by local Whisper (large-v3-turbo) via whisper.cpp — audio never leaves your Mac. Three actions: Dictate (raw transcript), Dictate + Clean (transcript → Claude cleanup → paste), and the classic rewrite of selected text.
  • History — recover any past rewrite or dictation. Entries are badged by kind (Rewrite / Dictation / Dictation + Clean); copy the before, the after, or a transcript back to the clipboard. Local, newest 100.
  • Bring your own Anthropic API key — stored in the macOS Keychain; only ever sent to api.anthropic.com.
  • Live, self-updating model list — fetched from GET /v1/models; pick any current model, no app update needed.
  • Unlimited custom instructions — each with its own name, system prompt, and global shortcut. Seeded with Auto Clean (⇧⌘R), Formal, Friendly, and Translate to English. No paywall.
  • First-run onboarding wizard — a guided window takes a new user from install to working in about a minute: choose Claude / on-device / both, then grant access, add a key, and download models with every step verified live (Continue unlocks only once the check actually passes). Re-runnable from the menu ("Run Setup Again…").
  • Animated menu-bar icon — a custom Equalizer waveform that reads at a glance: idle · listening (bars bounce) · working (shimmer) · setup-needed (pulse) · error. A template image, so it adapts to light/dark menu bars and inverts on highlight.
  • Guided setup — the menu lists exactly what's missing — for rewriting and dictation — with one-click fixes; a consistent status badge shows readiness across every screen.
  • In-app updatesCheck for Updates… downloads and installs new signed releases (showing the release notes first); permissions carry across updates.
  • Launch at login toggle.
  • Native Swift + SwiftUI menu-bar app. No Dock icon. No telemetry.

Requirements

To run the app (the recommended prebuilt install):

  • An Apple Silicon Mac on macOS 13.3 (Ventura) or later — developed and used on macOS 15. (No Intel build.)
  • An Anthropic API key for cloud rewriting and Dictate + Clean — optional if you only use the on-device rewrite modelhttps://console.anthropic.com/settings/keys.
  • For local (offline) rewriting: a one-time ~2.5 GB on-device model download (in-app). No API key needed.
  • For dictation: a microphone and a one-time ~1.6 GB Whisper model download (in-app).

No developer tools are needed to run RewriteDB. Building from source additionally needs Xcode Command Line Tools (full Xcode not required) — see Build from source.


Install (recommended)

This is how to get RewriteDB — most people should start here. Download the prebuilt, signed app; no toolchain, no building. Apple Silicon (arm64), macOS 13.3+.

  1. Download the latest RewriteDB-vX.Y.Z.zip from the Releases page and unzip it.
  2. Move RewriteDB.app to /Applications.
  3. RewriteDB is signed with a self-signed certificate but not notarized by Apple (it's free and open-source, with no paid Apple Developer account), so macOS quarantines it after download. Clear that once — in Terminal:
    xattr -dr com.apple.quarantine /Applications/RewriteDB.app
    or double-click it, dismiss the "can't be opened" dialog, then go to System Settings → Privacy & Security, scroll to Security, and click Open Anyway (admin password). (macOS Sequoia removed the old Control-click → Open shortcut.)
  4. Launch it — the onboarding wizard walks you through setup (see First run).

Updates are automatic. RewriteDB checks for new releases and offers a one-click Check for Updates… (menu bar) that shows the release notes before installing — one click fetches and installs it for you, and because releases share a stable signing identity, your permissions carry over. (Optional: verify the download's SHA-256 against the release notes.)

Prefer to build it yourself? See Build from source — that path is for contributors and doesn't auto-update.


First run

The easiest path: the onboarding wizard opens automatically on first launch and walks you through everything below — choosing a rewrite provider, granting Accessibility, adding a key and/or downloading models, and (optionally) setting up dictation — verifying each step as you go. You can reopen it anytime from the menu bar → Run Setup Again….

Prefer to do it manually? Equivalent steps:

  1. Grant Accessibility access. Click the menu-bar icon → Grant Accessibility access…, enable RewriteDB, then quit and relaunch. (Required to copy your selection and paste the result back.)
  2. Add your API key and pick a model. Menu bar → Settings… → Rewrite, paste your key, Save (this also fetches the model list), then pick a model. (Skip this if you'll only use the local rewrite model — see below.)

The menu-bar icon settles into its idle Equalizer state once Accessibility + a usable provider are set.

Optional — rewrite offline with no API key (Settings → Rewrite): set the primary provider to Local (on-device) and Download model (~2.5 GB, one time). Rewrites then run entirely on your Mac — no key, no network. Both providers can be set up at once; switch the primary anytime, or enable Fall back to the other provider to use the local model automatically whenever Claude is unavailable.

Optional — set up dictation (Settings → Dictation): (1) Download the Whisper model (~1.6 GB, on-device), (2) Grant Microphone access, (3) set a hotkey for Dictate and/or Dictate + Clean. Each step shows a ✓ when done, and the menu-bar icon only flags unfinished dictation setup once you've started (a rewrite-only user is never nagged).


Usage

Rewrite selected text:

  1. Select text in any app.
  2. Press ⇧⌘R (Auto Clean), or pick an instruction from the menu-bar icon.
  3. The selection is replaced in place with the rewrite — from Claude or the local model, whichever you've set as primary (the icon spins while it works).

Dictate by voice:

  1. Press your Dictate or Dictate + Clean hotkey (Settings → Dictation). The menu-bar icon pulses while listening.
  2. Speak, then press the hotkey again to stop. The icon spins while it transcribes on-device (and, for Dictate + Clean, runs the transcript through your rewrite provider — Claude or the local model).
  3. The text is pasted at your cursor.

Add, edit, reorder, and assign shortcuts to instructions under Settings → Instructions — unlimited, free. Recover any past rewrite or dictation from History (menu → History…).


How it works

Concern Implementation
App shell SwiftUI MenuBarExtra (macOS 13+), LSUIElement (no Dock icon)
Global hotkey KeyboardShortcuts (pinned to 1.15.0 — see note)
Capture / replace Synthesize ⌘C to copy, run the rewrite (Claude API or on-device model), write result to the clipboard, synthesize ⌘V (then restore your clipboard)
API Raw HTTPS via URLSessionPOST /v1/messages, GET /v1/models, anthropic-version: 2023-06-01
Local rewriting Optional on-device Qwen3-4B-Instruct (Q4_K_M) via the prebuilt llama.cpp XCFramework — same CLT-friendly binary-target approach as Whisper (embedded Metal, no metal toolchain, GPU-accelerated); loads on first use, unloads when idle
API key storage macOS Keychain (Security framework)
Settings persistence UserDefaults (instructions, rewrite provider + fallback, selected model, cached model list, dictation prefs)
Launch at login SMAppService.mainApp
Live permission status Polls AXIsProcessTrusted() only while access is missing, then stops
Speech-to-text Local Whisper (large-v3-turbo) via the prebuilt whisper.cpp XCFramework — a SwiftPM binary target with a precompiled Metal library, so it builds under CLT (no metal toolchain) yet is GPU-accelerated at runtime
Audio capture AVAudioEngine → 16 kHz mono via AVAudioConverter; kept in memory only, never written to disk
On-device models Downloaded once to Application Support (Whisper ~1.6 GB; local rewrite model ~2.5 GB); fully offline afterward. Both load lazily and unload after ~4 min idle
History Before/after (or transcript) of each action as JSON in Application Support (newest 100)

KeyboardShortcuts is pinned to 1.15.0 because newer versions use the SwiftUI #Preview macro, whose macro plugin ships only with full Xcode — so swift build under the Command Line Tools can't expand it. 1.15.0 is the newest release without #Preview and has the full API used here.


Project structure

Sources/
  RewriteDBKit/        # Pure, dependency-free logic (unit-tested)
    Instruction.swift          # instruction model + seeded defaults
    AnthropicModel.swift       # model decoding + default-model selection
    AnthropicClient.swift      # Messages/Models API client + pure parsing helpers
    HistoryEntry.swift         # history model (kind + before/after) with legacy-safe decode
    RewriteProvider.swift      # rewrite backend selector (Anthropic API | local on-device) + fallback order
    RewritePrompt.swift        # wraps to-rewrite text as inert data (so a dictated request is cleaned, not answered)
    WordDiff.swift             # pure word-level LCS diff for the History before/after view
  RewriteDB/           # The menu-bar app (UI, permissions, hotkeys, dictation, local LLM)
    RewriteDBApp.swift, AppState.swift
    Services/          # Keychain, RewriteService, LaunchAtLogin, Accessibility, ShortcutsRegistry, HistoryStore,
                       #   MicrophonePermissions, ModelStatus, WhisperEngine, WhisperModelStore, DictationService,
                       #   LocalLLMEngine, LocalLLMModelStore   (llama.cpp rewrite provider)
    Views/             # MenuBarContent, HistoryView, WaveformIcon (animated menu-bar glyph),
                       #   StatusBadge, OnboardingWizard, + Settings tabs (Rewrite / Instructions / Dictation / General)
  RewriteDBTests/      # Dependency-free test runner (`swift run RewriteDBTests`)
Scripts/
  setup-signing.sh     # one-time: create local signing identity (dev builds)
  setup-ci-signing.sh  # one-time: provision the CI release-signing secrets
  build-app.sh         # build + bundle (embeds whisper.framework + llama.framework) + sign RewriteDB.app
  run.sh               # build if needed, then launch
Resources/Info.plist   # LSUIElement, bundle id, version, microphone usage string

Build from source (contributors)

Most people don't need thisinstall the prebuilt app instead (it also auto-updates). This section is for hacking on RewriteDB. Source builds use a different signing identity than releases and do not receive in-app updates.

Needs Xcode Command Line Tools (xcode-select --install) — full Xcode is not required. One-liner — clone, set up signing, build, and launch:

git clone https://github.com/danb235/rewritedb.git && cd rewritedb && ./Scripts/setup-signing.sh && ./Scripts/build-app.sh && ./Scripts/run.sh

Or step by step:

git clone https://github.com/danb235/rewritedb.git && cd rewritedb
./Scripts/setup-signing.sh  # ONE TIME: local self-signed cert so permissions persist (see below)
./Scripts/build-app.sh      # compiles + assembles RewriteDB.app (downloads deps on first run)
./Scripts/run.sh            # launches it (builds first if needed)

An Equalizer-waveform icon appears in your menu bar (no Dock icon); first launch opens the onboarding wizard (see First run). You can also open Package.swift in Xcode if you have the full IDE installed.

Why the self-signed certificate?

./Scripts/setup-signing.sh creates a local, self-signed code-signing certificate in your login keychain (it never leaves your Mac; this is not notarization and needs no Apple Developer account).

It matters because macOS ties both the Accessibility grant and Keychain access to the app's exact code signature. An ad-hoc signature (the default codesign --sign -) changes on every rebuild, so each rebuild would silently revoke your permissions — the classic "the toggle is on but it still doesn't work" symptom. A stable certificate fixes this permanently: the app's identity stays constant across rebuilds, so you grant access once. (Your local dev identity is separate from the CI identity that signs releases — so switching between a source build and an installed release re-grants once.)


Testing

The pure logic (models, default selection, API response parsing, error extraction, the rewrite-input framing) is covered by a small dependency-free test runner — XCTest and swift-testing aren't fully usable without full Xcode, so the tests run anywhere swift does:

swift run RewriteDBTests

It exits non-zero on any failure, and runs on every push via GitHub Actions (CI).


Troubleshooting

  • Hotkey does nothing. Make sure RewriteDB has Accessibility access (menu bar → Grant…), then quit and relaunch — macOS only applies a new grant on relaunch. The menu-bar icon shows ⚠️ until it's ready.
  • Permissions look enabled but the app says they're missing (often right after an update or a rebuild). macOS ties the grant to the app's code signature, so a signature change (e.g. a source build → an installed release, or a rebuild without a stable cert) can leave a stale "on" toggle that no longer applies. Toggle RewriteDB off then on in System Settings → Privacy & Security → Accessibility (and Microphone), or reset and re-grant:
    tccutil reset Accessibility com.opensource.rewritedb
    tccutil reset Microphone com.opensource.rewritedb
    then quit and relaunch. Releases all share one identity, so update-to-update this won't recur. If it instead recurs on every source rebuild, you're building without a stable cert — run ./Scripts/setup-signing.sh once (see Build from source), rebuild, then reset and grant one final time.
  • "No text selected." Ensure text is actually selected and the app supports ⌘C/⌘V.
  • Local rewrite says the model isn't installed. Settings → Rewrite → set primary to Local (on-device)Download model (~2.5 GB, one time). While it downloads, the menu-bar ⚠️
    • "To rewrite text" checklist shows the step; switch the primary back to Anthropic API anytime.
  • Dictation is greyed out / "Download speech model". Open Settings → Dictation and download the Whisper model (~1.6 GB, one time). Dictation also needs Microphone access (Settings → Dictation → Grant…) — the menu-bar ⚠️ + "To dictate" checklist point you to whatever's missing.
  • "RewriteDB can't be opened" (downloaded app). It's self-signed but not notarized. Clear the quarantine flag — xattr -dr com.apple.quarantine /Applications/RewriteDB.appor open it once, then System Settings → Privacy & Security → Open Anyway. (Sequoia removed the Control-click → Open trick.)

Uninstall

  1. Quit RewriteDB (menu bar → Quit RewriteDB). If Launch at login is on, turn it off first (Settings → General) so no login item is left behind.
  2. Delete the app:
    rm -rf /Applications/RewriteDB.app     # …or wherever you keep it

That's all you need to stop using it. To also remove everything it stored — the on-device models (several GB), history, settings, cached data, and your saved API key:

rm -rf ~/Library/"Application Support"/RewriteDB          # models (~4 GB) + history
rm -f  ~/Library/Preferences/com.opensource.rewritedb.plist   # settings, instructions, shortcuts
rm -rf ~/Library/Caches/com.opensource.rewritedb
rm -rf ~/Library/HTTPStorages/com.opensource.rewritedb
defaults delete com.opensource.rewritedb 2>/dev/null || true  # UserDefaults (in case it's cached)
security delete-generic-password -s com.opensource.rewritedb 2>/dev/null || true  # your Anthropic API key

Then revoke the macOS permission grants (removes the leftover RewriteDB rows from System Settings):

tccutil reset Accessibility com.opensource.rewritedb
tccutil reset Microphone com.opensource.rewritedb

That's the complete footprint — RewriteDB keeps no other state and sends no telemetry. (If you also ran it from source with swift run, dev builds additionally use a RewriteDB UserDefaults domain: defaults delete RewriteDB.)


Releasing (maintainers)

Easiest: run the /release Claude Code skill (optionally /release <x.y.z|patch|minor|major>). It curates the notes from every change since the last tag, updates the CHANGELOG, shows a preview to approve, then pushes the tag and watches the workflow. Users can then update in-app.

Or do it by hand:

  1. Move the relevant ## [Unreleased] items in CHANGELOG.md into a new ## [X.Y.Z] - YYYY-MM-DD section and commit.
  2. Tag and push: git tag vX.Y.Z && git push origin vX.Y.Z.
  3. .github/workflows/release.yml runs the tests, builds + version-stamps RewriteDB.app, zips it, and publishes a GitHub Release whose notes are that CHANGELOG section (+ install steps + SHA-256).

One-time: stable release signing (recommended). So the in-app updater's grants persist across updates (macOS ties Accessibility/Microphone to the signing identity), releases are signed with a stable self-signed identity stored as repo secrets RDB_SIGNING_P12 (base64) and RDB_SIGNING_PASSWORD. Provision (or later rotate) them with one command:

./Scripts/setup-ci-signing.sh   # generates the CI "RewriteDB Self-Signed" identity + sets both secrets

Without these secrets the release still builds (ad-hoc signed) — but each update resets macOS permissions, so users must re-grant. (Scripts/setup-signing.sh is the separate local identity for your own build-app.sh dev builds; end users only ever see the CI identity above.)


Contributing

Contributions are welcome — see CONTRIBUTING.md for how to build (Command Line Tools only), run the tests, and open a PR, and ARCHITECTURE.md for a tour of the code. By participating you agree to the Code of Conduct.


Security

Your API key stays in the macOS Keychain and is only sent to Anthropic; dictation and local rewriting run entirely on-device; there's no telemetry. To report a vulnerability, see SECURITY.md.


Credit

Inspired by the original RewriteCmd (rewritecmd.com). This is an independent, open-source rebuild and is not affiliated with it.

License

MIT — see LICENSE.

About

Rewrite selected text anywhere on your Mac with a global hotkey, using the Anthropic (Claude) API. Open-source menu-bar app.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors