██████╗ █████╗ ███╗ ██╗██████╗ ██╗██████╗ ██╗ ██╗ ██╗
██╔════╝██╔══██╗████╗ ██║██╔══██╗██║██╔══██╗██║ ╚██╗ ██╔╝
██║ ███████║██╔██╗ ██║██║ ██║██║██║ ██║██║ ╚████╔╝
██║ ██╔══██║██║╚██╗██║██║ ██║██║██║ ██║██║ ╚██╔╝
╚██████╗██║ ██║██║ ╚████║██████╔╝██║██████╔╝███████╗ ██║
╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ╚═╝╚═════╝ ╚══════╝ ╚═╝
rewrite AI email drafts to read like a human, from inside gmail.
Candidly is a privacy-first Gmail Chrome extension that humanizes AI text right in the compose window. It is a bring-your-own-key (BYOK) AI email rewriter that talks directly to Claude, GPT, Grok, or Gemini from the browser. No Candidly server, no proxy, no telemetry. Three tones, one click, your key.
- AI drafts have an obvious tell. Candidly strips em-dashes, hedge phrases, and the "delve / paradigm / synergy" vocabulary at the prompt layer.
- Pasting drafts into another tab is friction. Candidly mounts a button in the Gmail compose toolbar and replaces the body in place.
- You already pay for an API key. Candidly uses yours directly. No subscription, no markup, no shared pool.
- Your draft is private. The request goes from your browser to your chosen provider and back. Nothing else sees it.
- Three voices cover most needs: Subtle, Human, CEO.
Pending review: https://chrome.google.com/webstore/detail/candidly/<id>
git clone https://github.com/boxed-dev/candidly.git
cd candidly
pnpm i
pnpm build
# then in Chrome:
# 1. open chrome://extensions
# 2. enable Developer mode
# 3. click "Load unpacked"
# 4. select .output/chrome-mv3- Click the Candidly icon, paste any API key. The popup auto-detects the provider from the prefix (
sk-ant-,sk-,xai-,AIza). - Open Gmail and start composing.
- Click the Candidly button in the compose toolbar.
- Pick a tone: Subtle, Human, or CEO.
- Click Replace. The draft is rewritten in place.
BEFORE
Hi Sarah, I hope this email finds you well. I wanted to reach out
regarding the Q3 roadmap. Could we perhaps schedule a brief sync
to delve into the priorities?
AFTER (subtle)
Hi Sarah, hope you're doing well. Wanted to reach out about the Q3
roadmap. Could we schedule a short sync to go through the priorities?
AFTER (human)
hey sarah, quick one on the Q3 roadmap. got 15 min this week to walk
through priorities? honestly easier than email tag.
AFTER (ceo)
sarah, q3 roadmap. need 15 min this week. priorities.
Sent from my iPhone
| tone | target length | behavior |
|---|---|---|
| Subtle | input length ±10% | Smooths AI rhythm and hedge phrases. Structure intact. Reads like a polish, not a rewrite. |
| Human | 70-90% of input | Conversational. Contractions, varied lengths, occasional soft hedges (honestly, tbh). |
| CEO | 30-50% of input | Blunt. Fragments. Lowercase sentence starts. One plausible typo. Appends Sent from my iPhone. |
| provider | key prefix | default model | host |
|---|---|---|---|
| Anthropic | sk-ant- |
claude-sonnet-4-6 |
api.anthropic.com |
| OpenAI | sk-, sk-proj- |
gpt-5.2 |
api.openai.com |
| xAI | xai- |
grok-4.3 |
api.x.ai |
| Google Gemini | AIza |
gemini-2.5-flash |
generativelanguage.googleapis.com |
BYOK means the key lives in chrome.storage.local on this device, and rewrite requests go from the browser straight to the provider you picked. No Candidly server is in the path.
The API key is stored in chrome.storage.local. Drafts are sent only to the provider whose key is configured. SHA-256 hashes of drafts are used for the local rewrite cache and the free-tier counter, so the plaintext never leaves the cache key derivation. Cache TTL is 24 hours, bounded to a 5 MB budget. No analytics, no telemetry, no remote code execution. The host permissions are pinned to the four provider domains plus mail.google.com.
[gmail draft] -> [content script] -> [service worker] -> [provider api]
|
v
[chrome.storage.local]
(key, cache, quota)
pnpm i
pnpm dev # wxt dev with HMR
pnpm build # production MV3 build -> .output/chrome-mv3
pnpm zip # zipped artifact for store upload
pnpm compile # tsc --noEmit
pnpm test:all # full suite480+ automated assertions across 9 test suites, including a real Chromium end-to-end run via Playwright.
| suite | what it covers | assertions |
|---|---|---|
test:smoke |
Build artifacts, manifest, prompt rules, provider key detection. | 74 |
test:dom |
Gmail compose DOM probing and toolbar injection against linkedom fixtures. | 54 |
test:logic |
Diff engine, cache TTL/budget, free-quota math, hash determinism. | 103 |
test:components |
Solid components: panel rendering, tone selector, diff preview. | 22 |
test:background |
Service worker port handling, fan-out across tones, cache hits, errors. | 36 |
test:popup |
Popup flow: provider auto-detect, key validation, save/clear. | 37 |
test:bundle |
Built .output/chrome-mv3 artifact integrity and MV3 manifest shape. |
138 |
test:e2e |
Real Chromium loads the unpacked build via Playwright; mounts on Gmail. | 16 |
test:errors |
Provider error classification across 4xx/5xx and network failure. | 4 (live) |
.
├── entrypoints/
│ ├── background.ts # MV3 service worker, port-based fan-out
│ ├── content.tsx # Gmail compose mount + Solid panel
│ └── popup/
│ ├── App.tsx
│ ├── main.tsx
│ └── index.html
├── components/
│ ├── CandidlyPanel.tsx
│ ├── DiffPreview.tsx
│ └── IntensitySlider.tsx
├── lib/
│ ├── providers/ # anthropic, openai, xai, gemini, types
│ ├── prompts.ts # SHARED_RULES + per-tone instructions
│ ├── storage.ts # creds, cache, quota, SHA-256 hashing
│ ├── diff.ts
│ └── messages.ts
├── styles/panel.css
├── public/icon/ # 16/32/48/96/128
├── test/
│ └── fixtures/gmail.mjs
└── wxt.config.ts
| dep | version | role |
|---|---|---|
wxt |
0.20.25 | MV3 extension framework, build, HMR |
solid-js |
1.9.11 | Reactive UI for popup and content panel |
tailwindcss |
4.2.4 | Styling (via @tailwindcss/vite) |
typescript |
5.9.3 | Type-checked with tsc --noEmit |
diff |
9.0.0 | Word-level diff for the rewrite preview |
linkedom |
0.18.12 | Headless DOM for Gmail fixture tests |
tsx |
4.22.0 | Run .ts test files directly |
MIT. See LICENSE.
PRs welcome. Issues welcome. No formal process. Keep changes small and focused. All tests must pass (pnpm test:all) and the codebase must type-check (pnpm compile) before review. If a change touches prompts, providers, or storage, add a test next to it.