Skip to content

boxed-dev/candidly

Repository files navigation

 ██████╗ █████╗ ███╗   ██╗██████╗ ██╗██████╗ ██╗     ██╗   ██╗
██╔════╝██╔══██╗████╗  ██║██╔══██╗██║██╔══██╗██║     ╚██╗ ██╔╝
██║     ███████║██╔██╗ ██║██║  ██║██║██║  ██║██║      ╚████╔╝
██║     ██╔══██║██║╚██╗██║██║  ██║██║██║  ██║██║       ╚██╔╝
╚██████╗██║  ██║██║ ╚████║██████╔╝██║██████╔╝███████╗   ██║
 ╚═════╝╚═╝  ╚═╝╚═╝  ╚═══╝╚═════╝ ╚═╝╚═════╝ ╚══════╝   ╚═╝

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.

license manifest-v3 typescript solid stars

why

  • 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.

install

chrome web store

Pending review: https://chrome.google.com/webstore/detail/candidly/<id>

from source

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

usage

  1. Click the Candidly icon, paste any API key. The popup auto-detects the provider from the prefix (sk-ant-, sk-, xai-, AIza).
  2. Open Gmail and start composing.
  3. Click the Candidly button in the compose toolbar.
  4. Pick a tone: Subtle, Human, or CEO.
  5. 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

tones

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.

providers

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.

privacy

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)

development

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 suite

480+ automated assertions across 9 test suites, including a real Chromium end-to-end run via Playwright.

testing

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)

project structure

.
├── 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

stack

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

license

MIT. See LICENSE.

contributing

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.

About

Gmail Chrome extension that humanizes AI email drafts. BYOK with Claude, GPT, Grok, and Gemini. MV3, privacy-first, no servers.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors