Files

1 line
9.4 KiB
JSON

{"repo": "boxed-dev/candidly", "files": {"README.md": {"264d9dc88ac7d46f6cf417dbb456b4600114aa12": {"t": 1785674534.1149025, "n": 8554, "h": "37d2d50b6aae7772", "c": "```\n ██████╗ █████╗ ███╗ ██╗██████╗ ██╗██████╗ ██╗ ██╗ ██╗\n██╔════╝██╔══██╗████╗ ██║██╔══██╗██║██╔══██╗██║ ╚██╗ ██╔╝\n██║ ███████║██╔██╗ ██║██║ ██║██║██║ ██║██║ ╚████╔╝\n██║ ██╔══██║██║╚██╗██║██║ ██║██║██║ ██║██║ ╚██╔╝\n╚██████╗██║ ██║██║ ╚████║██████╔╝██║██████╔╝███████╗ ██║\n ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ╚═╝╚═════╝ ╚══════╝ ╚═╝\n```\n\n> rewrite AI email drafts to read like a human, from inside gmail.\n\nCandidly 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.\n\n![license](https://img.shields.io/github/license/boxed-dev/candidly?style=flat-square) ![manifest-v3](https://img.shields.io/badge/manifest-v3-blue?style=flat-square) ![typescript](https://img.shields.io/badge/made%20with-typescript-3178c6?style=flat-square) ![solid](https://img.shields.io/badge/made%20with-solid-2c4f7c?style=flat-square) ![stars](https://img.shields.io/github/stars/boxed-dev/candidly?style=flat-square)\n\n## why\n\n- AI drafts have an obvious tell. Candidly strips em-dashes, hedge phrases, and the \"delve / paradigm / synergy\" vocabulary at the prompt layer.\n- Pasting drafts into another tab is friction. Candidly mounts a button in the Gmail compose toolbar and replaces the body in place.\n- You already pay for an API key. Candidly uses yours directly. No subscription, no markup, no shared pool.\n- Your draft is private. The request goes from your browser to your chosen provider and back. Nothing else sees it.\n- Three voices cover most needs: Subtle, Human, CEO.\n\n## install\n\n### chrome web store\n\nPending review: `https://chrome.google.com/webstore/detail/candidly/<id>`\n\n### from source\n\n```sh\ngit clone https://github.com/boxed-dev/candidly.git\ncd candidly\npnpm i\npnpm build\n# then in Chrome:\n# 1. open chrome://extensions\n# 2. enable Developer mode\n# 3. click \"Load unpacked\"\n# 4. select .output/chrome-mv3\n```\n\n## usage\n\n1. Click the Candidly icon, paste any API key. The popup auto-detects the provider from the prefix (`sk-ant-`, `sk-`, `xai-`, `AIza`).\n2. Open Gmail and start composing.\n3. Click the Candidly button in the compose toolbar.\n4. Pick a tone: Subtle, Human, or CEO.\n5. Click Replace. The draft is rewritten in place.\n\n```text\nBEFORE\nHi Sarah, I hope this email finds you well. I wanted to reach out\nregarding the Q3 roadmap. Could we perhaps schedule a brief sync\nto delve into the priorities?\n\nAFTER (subtle)\nHi Sarah, hope you're doing well. Wanted to reach out about the Q3\nroadmap. Could we schedule a short sync to go through the priorities?\n\nAFTER (human)\nhey sarah, quick one on the Q3 roadmap. got 15 min this week to walk\nthrough priorities? honestly easier than email tag.\n\nAFTER (ceo)\nsarah, q3 roadmap. need 15 min this week. priorities.\n\nSent from my iPhone\n```\n\n## tones\n\n| tone | target length | behavior |\n|--------|-------------------|-------------------------------------------------------------------------------------------|\n| Subtle | input length ±10% | Smooths AI rhythm and hedge phrases. Structure intact. Reads like a polish, not a rewrite.|\n| Human | 70-90% of input | Conversational. Contractions, varied lengths, occasional soft hedges (`honestly`, `tbh`). |\n| CEO | 30-50% of input | Blunt. Fragments. Lowercase sentence starts. One plausible typo. Appends `Sent from my iPhone`. |\n\n## providers\n\n| provider | key prefix | default model | host |\n|----------------|---------------------|---------------------|--------------------------------------------|\n| Anthropic | `sk-ant-` | `claude-sonnet-4-6` | `api.anthropic.com` |\n| OpenAI | `sk-`, `sk-proj-` | `gpt-5.2` | `api.openai.com` |\n| xAI | `xai-` | `grok-4.3` | `api.x.ai` |\n| Google Gemini | `AIza` | `gemini-2.5-flash` | `generativelanguage.googleapis.com` |\n\nBYOK 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.\n\n## privacy\n\nThe 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`.\n\n```text\n[gmail draft] -> [content script] -> [service worker] -> [provider api]\n |\n v\n [chrome.storage.local]\n (key, cache, quota)\n```\n\n## development\n\n```sh\npnpm i\npnpm dev # wxt dev with HMR\npnpm build # production MV3 build -> .output/chrome-mv3\npnpm zip # zipped artifact for store upload\npnpm compile # tsc --noEmit\npnpm test:all # full suite\n```\n\n480+ automated assertions across 9 test suites, including a real Chromium end-to-end run via Playwright.\n\n## testing\n\n| suite | what it covers | assertions |\n|-------------------|-------------------------------------------------------------------------|------------|\n| `test:smoke` | Build artifacts, manifest, prompt rules, provider key detection. | 74 |\n| `test:dom` | Gmail compose DOM probing and toolbar injection against linkedom fixtures. | 54 |\n| `test:logic` | Diff engine, cache TTL/budget, free-quota math, hash determinism. | 103 |\n| `test:components` | Solid components: panel rendering, tone selector, diff preview. | 22 |\n| `test:background` | Service worker port handling, fan-out across tones, cache hits, errors. | 36 |\n| `test:popup` | Popup flow: provider auto-detect, key validation, save/clear. | 37 |\n| `test:bundle` | Built `.output/chrome-mv3` artifact integrity and MV3 manifest shape. | 138 |\n| `test:e2e` | Real Chromium loads the unpacked build via Playwright; mounts on Gmail. | 16 |\n| `test:errors` | Provider error classification across 4xx/5xx and network failure. | 4 (live) |\n\n## project structure\n\n```text\n.\n├── entrypoints/\n│ ├── background.ts # MV3 service worker, port-based fan-out\n│ ├── content.tsx # Gmail compose mount + Solid panel\n│ └── popup/\n│ ├── App.tsx\n│ ├── main.tsx\n│ └── index.html\n├── components/\n│ ├── CandidlyPanel.tsx\n│ ├── DiffPreview.tsx\n│ └── IntensitySlider.tsx\n├── lib/\n│ ├── providers/ # anthropic, openai, xai, gemini, types\n│ ├── prompts.ts # SHARED_RULES + per-tone instructions\n│ ├── storage.ts # creds, cache, quota, SHA-256 hashing\n│ ├── diff.ts\n│ └── messages.ts\n├── styles/panel.css\n├── public/icon/ # 16/32/48/96/128\n├── test/\n│ └── fixtures/gmail.mjs\n└── wxt.config.ts\n```\n\n## stack\n\n| dep | version | role |\n|------------------|----------|-----------------------------------------------|\n| `wxt` | 0.20.25 | MV3 extension framework, build, HMR |\n| `solid-js` | 1.9.11 | Reactive UI for popup and content panel |\n| `tailwindcss` | 4.2.4 | Styling (via `@tailwindcss/vite`) |\n| `typescript` | 5.9.3 | Type-checked with `tsc --noEmit` |\n| `diff` | 9.0.0 | Word-level diff for the rewrite preview |\n| `linkedom` | 0.18.12 | Headless DOM for Gmail fixture tests |\n| `tsx` | 4.22.0 | Run `.ts` test files directly |\n\n## license\n\nMIT. See [LICENSE](./LICENSE).\n\n## contributing\n\nPRs 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.\n"}}}}