Current source version: 0.18.1. This repository includes the extension source and developer tests. The sections below document its architecture and verification history; live-site coverage remains under evaluation.
Extract the release ZIP, open chrome://extensions, enable Developer mode, choose Load unpacked, and select the folder containing manifest.json. Reload existing site tabs after updating. No build/transpilation is required. Use Mock provider for a local, no-key trial. This is an evaluation build: authenticated live-site and packaged-extension acceptance remain outstanding.
The existing Manifest V3 structure and window.WriteFlow namespace remain intact:
content/detector.js: delegated editor focus detection and sensitive-field exclusion.content/adapters.js: text editing, native input value setter, contenteditable insertion and Gmail line formatting.content/context-dom.js: composed-tree traversal, visibility and strict composer association.content/platform-adapters.js: 19 independent selector definitions behind one adapter contract. Each exposes detection, editor discovery, context/conversation extraction, audience hints, metadata and capabilities. Generic writing exposes no automatic context capability.content/context-extractors.js: compatibility facade for the existing UI.services/context-model.js: DOM-free normalization and serialization; a shared 6,000-character context budget and at most six prior messages. The target is preserved before allocating the remaining budget to recent messages. Serialization also caps labels and text together.services/promptBuilder.js: existing writing/social/email prompts consume normalized objects or manually pasted strings. DOM selectors never enter this layer.content/ui.js: existing Shadow DOM UI, generation/cancellation, reply/rewrite, result actions and per-field undo. Context-analysis caches remain in memory, now capped at 20 entries each. Active UI is checked every 250 ms for navigation/editor removal; this checks one field, not the whole page.services/ai.js: existing direct BYOK providers and one configured fallback, unchanged.services/storage.js, services/license.js, options, popup and service worker: retained local settings, Gumroad licensing and existing UI. Dynamically registered scripts get the new dependency order on upgrade.{
platform: 'linkedin', type: 'post_reply',
author: { name: '', role: '' },
content: { primaryText: '', parentText: '', quotedText: '' },
conversation: [{ author: '', direction: 'unknown', text: '' }],
metadata: { title: '', timestamp: '', url: '' }
}
Unknown metadata stays empty. Relationships are not inferred. URL metadata drops query strings and fragments and is not included in the prompt serialization. Context is read only when requested; gaining focus makes no AI request. Existing Pro analysis may call the provider after the user opens a reply panel.
Association must be an enclosing post/comment/thread, an explicit quote in the active email reply, or a single visible source in the same dialog. Missing/ambiguous markup returns null. There is no nearest-post, first-post, longest-text, or whole-document email fallback. This intentionally reduces automatic coverage when association cannot be established. Social reply panels retain manual paste; email falls back to writing.
F = synthetic browser fixture passed, not live-site certification. All platforms below have generic writing through the shared editor layer. No authenticated service was verified. Layout variants outside the selector contract may require manual context. New Priority 2/3 definitions are provisional and need real DOM snapshots before production claims.
| Platform | Writing | Context | Conversation | Smart Compose |
|---|---|---|---|---|
| Shared editor F | F; nested reply | No | No | |
| X/Twitter | Shared editor F | F; associated tweet/dialog | No | No |
| Shared editor F | F; explicit body/comment hooks | No | No | |
| Shared editor F | F; composed-tree reply | No | No | |
| YouTube | Shared editor F | F; associated video/comment | No | No |
| Gmail | Shared editor F | F; thread/explicit quote | F; scoped recent messages | No |
| Outlook | Shared editor F | F; thread/explicit quote | F; scoped recent messages | No |
| Slack | Shared editor F | F; scoped messages | F | No |
| Shared editor F | F; active chat | F | No | |
| Shared editor F | F; provisional caption hooks | No | No | |
| Threads | Shared editor F | F; provisional post hooks | No | No |
| TikTok | Shared editor F | F; provisional video hooks | No | No |
| Discord | Shared editor F | F; provisional chat container | F | No |
| Bluesky | Shared editor F | F; provisional feed hooks | No | No |
| Quora | Shared editor F | F; provisional answer hooks | No | No |
| Medium | Shared editor F | F; enclosing article only | No | No |
| Substack | Shared editor F | F; enclosing post only | No | No |
| Tumblr | Shared editor F | F; provisional post hooks | No | No |
| Shared editor F | F; provisional pin hooks | No | No | |
| Other permitted sites | Shared editor F | Manual only | No | No |
Manifest coverage remains unchanged. Custom domains and domains absent from the original manifest require the existing per-site permission flow. Closed Shadow DOM and cross-origin frames are not supported. Editor discovery is lazy; findEditors is not a background full-page scan.
OpenAI, Anthropic, Gemini, Groq, OpenRouter and Mock remain available. Real API calls go directly from the isolated content script to the chosen provider; fallback uses the user's configured second provider/key. No WriteFlow backend, account, analytics server, remote prompt store or extra extension permissions were added. Keys and writing samples stay in chrome.storage.local; keys are not added to host-page DOM. Selected writing/context and optional samples go to the chosen AI provider when generating. Pro verification separately contacts Gumroad, as before.
Generated by re-reading the actual gating in the code, not by memory — see CHANGELOG.md's Milestone 16 entries for exactly what changed and why.
Free:
FREE_SOCIAL_STYLE_IDS in services/storage.js)Pro:
Dynamic adjustment chips (Milestone 7) and the Natural Writing baseline (Milestone 8) are NOT tier-gated — available to whichever tier the underlying generation itself already belongs to. This was a deliberate scope decision at the time, not an oversight.
The local tier flag (tier in chrome.storage.local, set after Gumroad license verification) is not tamper-proof entitlement enforcement — this is an inherent trade-off of the BYOK, no-backend architecture (see the Known limitations section elsewhere in this README/CHANGELOG for the fuller discussion). Saved prompts (12), writing samples (3), and feedback metadata (100) retain their existing local caps.
A known gap, stated plainly: most of this README predates Milestones 2 through 16 (it's still titled "Milestone 1" above) and describes the codebase as it stood then — the architecture/context-model/verification-matrix sections above have NOT been kept current. CHANGELOG.md is the accurate, up-to-date record of everything built since. A full README rewrite covering the current architecture is worth doing before an actual store release, but wasn't attempted here to avoid claiming accuracy for a document this large without the same verification rigor applied to the rest of this milestone.
npm run build runs syntax, package asset, version and static/dynamic script-order checks. Runtime production code has no npm dependencies.
npm install then npx playwright install chromium and npm test run browser tests. Set CHROME_PATH to a Chrome executable to test that installation. The test runner uses only synthetic local pages, mocked storage and mocked provider/license responses; it does not send paid AI requests or access real accounts.
For an interactive run without Playwright process launch: run node tests/create-browser-harness.cjs, then python tests/serve.py, and open http://127.0.0.1:8765/tests/browser.html. Results are saved in tests/browser-results.json. The preview controls apply the exact light/dark palette rules for inspection without changing browser/OS settings.
See MILESTONE-1-REPORT.md for measured results, known defects and outstanding acceptance work. Passing fixtures does not establish compatibility with every React editor, authenticated platform, real provider model, or Chrome extension integration.
3 commits
JavaScript
85.3%
HTML
14.4%
Current source version: 0.18.1. This repository includes the extension source and developer tests. The sections below document its architecture and verification history; live-site coverage remains under evaluation.
Extract the release ZIP, open chrome://extensions, enable Developer mode, choose Load unpacked, and select the folder containing manifest.json. Reload existing site tabs after updating. No build/transpilation is required. Use Mock provider for a local, no-key trial. This is an evaluation build: authenticated live-site and packaged-extension acceptance remain outstanding.
The existing Manifest V3 structure and window.WriteFlow namespace remain intact:
content/detector.js: delegated editor focus detection and sensitive-field exclusion.content/adapters.js: text editing, native input value setter, contenteditable insertion and Gmail line formatting.content/context-dom.js: composed-tree traversal, visibility and strict composer association.content/platform-adapters.js: 19 independent selector definitions behind one adapter contract. Each exposes detection, editor discovery, context/conversation extraction, audience hints, metadata and capabilities. Generic writing exposes no automatic context capability.content/context-extractors.js: compatibility facade for the existing UI.services/context-model.js: DOM-free normalization and serialization; a shared 6,000-character context budget and at most six prior messages. The target is preserved before allocating the remaining budget to recent messages. Serialization also caps labels and text together.services/promptBuilder.js: existing writing/social/email prompts consume normalized objects or manually pasted strings. DOM selectors never enter this layer.content/ui.js: existing Shadow DOM UI, generation/cancellation, reply/rewrite, result actions and per-field undo. Context-analysis caches remain in memory, now capped at 20 entries each. Active UI is checked every 250 ms for navigation/editor removal; this checks one field, not the whole page.services/ai.js: existing direct BYOK providers and one configured fallback, unchanged.services/storage.js, services/license.js, options, popup and service worker: retained local settings, Gumroad licensing and existing UI. Dynamically registered scripts get the new dependency order on upgrade.{
platform: 'linkedin', type: 'post_reply',
author: { name: '', role: '' },
content: { primaryText: '', parentText: '', quotedText: '' },
conversation: [{ author: '', direction: 'unknown', text: '' }],
metadata: { title: '', timestamp: '', url: '' }
}
Unknown metadata stays empty. Relationships are not inferred. URL metadata drops query strings and fragments and is not included in the prompt serialization. Context is read only when requested; gaining focus makes no AI request. Existing Pro analysis may call the provider after the user opens a reply panel.
Association must be an enclosing post/comment/thread, an explicit quote in the active email reply, or a single visible source in the same dialog. Missing/ambiguous markup returns null. There is no nearest-post, first-post, longest-text, or whole-document email fallback. This intentionally reduces automatic coverage when association cannot be established. Social reply panels retain manual paste; email falls back to writing.
F = synthetic browser fixture passed, not live-site certification. All platforms below have generic writing through the shared editor layer. No authenticated service was verified. Layout variants outside the selector contract may require manual context. New Priority 2/3 definitions are provisional and need real DOM snapshots before production claims.
| Platform | Writing | Context | Conversation | Smart Compose |
|---|---|---|---|---|
| Shared editor F | F; nested reply | No | No | |
| X/Twitter | Shared editor F | F; associated tweet/dialog | No | No |
| Shared editor F | F; explicit body/comment hooks | No | No | |
| Shared editor F | F; composed-tree reply | No | No | |
| YouTube | Shared editor F | F; associated video/comment | No | No |
| Gmail | Shared editor F | F; thread/explicit quote | F; scoped recent messages | No |
| Outlook | Shared editor F | F; thread/explicit quote | F; scoped recent messages | No |
| Slack | Shared editor F | F; scoped messages | F | No |
| Shared editor F | F; active chat | F | No | |
| Shared editor F | F; provisional caption hooks | No | No | |
| Threads | Shared editor F | F; provisional post hooks | No | No |
| TikTok | Shared editor F | F; provisional video hooks | No | No |
| Discord | Shared editor F | F; provisional chat container | F | No |
| Bluesky | Shared editor F | F; provisional feed hooks | No | No |
| Quora | Shared editor F | F; provisional answer hooks | No | No |
| Medium | Shared editor F | F; enclosing article only | No | No |
| Substack | Shared editor F | F; enclosing post only | No | No |
| Tumblr | Shared editor F | F; provisional post hooks | No | No |
| Shared editor F | F; provisional pin hooks | No | No | |
| Other permitted sites | Shared editor F | Manual only | No | No |
Manifest coverage remains unchanged. Custom domains and domains absent from the original manifest require the existing per-site permission flow. Closed Shadow DOM and cross-origin frames are not supported. Editor discovery is lazy; findEditors is not a background full-page scan.
OpenAI, Anthropic, Gemini, Groq, OpenRouter and Mock remain available. Real API calls go directly from the isolated content script to the chosen provider; fallback uses the user's configured second provider/key. No WriteFlow backend, account, analytics server, remote prompt store or extra extension permissions were added. Keys and writing samples stay in chrome.storage.local; keys are not added to host-page DOM. Selected writing/context and optional samples go to the chosen AI provider when generating. Pro verification separately contacts Gumroad, as before.
Generated by re-reading the actual gating in the code, not by memory — see CHANGELOG.md's Milestone 16 entries for exactly what changed and why.
Free:
FREE_SOCIAL_STYLE_IDS in services/storage.js)Pro:
Dynamic adjustment chips (Milestone 7) and the Natural Writing baseline (Milestone 8) are NOT tier-gated — available to whichever tier the underlying generation itself already belongs to. This was a deliberate scope decision at the time, not an oversight.
The local tier flag (tier in chrome.storage.local, set after Gumroad license verification) is not tamper-proof entitlement enforcement — this is an inherent trade-off of the BYOK, no-backend architecture (see the Known limitations section elsewhere in this README/CHANGELOG for the fuller discussion). Saved prompts (12), writing samples (3), and feedback metadata (100) retain their existing local caps.
A known gap, stated plainly: most of this README predates Milestones 2 through 16 (it's still titled "Milestone 1" above) and describes the codebase as it stood then — the architecture/context-model/verification-matrix sections above have NOT been kept current. CHANGELOG.md is the accurate, up-to-date record of everything built since. A full README rewrite covering the current architecture is worth doing before an actual store release, but wasn't attempted here to avoid claiming accuracy for a document this large without the same verification rigor applied to the rest of this milestone.
npm run build runs syntax, package asset, version and static/dynamic script-order checks. Runtime production code has no npm dependencies.
npm install then npx playwright install chromium and npm test run browser tests. Set CHROME_PATH to a Chrome executable to test that installation. The test runner uses only synthetic local pages, mocked storage and mocked provider/license responses; it does not send paid AI requests or access real accounts.
For an interactive run without Playwright process launch: run node tests/create-browser-harness.cjs, then python tests/serve.py, and open http://127.0.0.1:8765/tests/browser.html. Results are saved in tests/browser-results.json. The preview controls apply the exact light/dark palette rules for inspection without changing browser/OS settings.
See MILESTONE-1-REPORT.md for measured results, known defects and outstanding acceptance work. Passing fixtures does not establish compatibility with every React editor, authenticated platform, real provider model, or Chrome extension integration.
3 commits
JavaScript
85.3%
HTML
14.4%