Grammarly for AI Prompts

Promptly is a Chromium (Manifest V3) extension that reviews your prompt as you type on 23 AI sites — ChatGPT, Claude, Gemini, Perplexity, Copilot and more. Ten local checks score it in real time, a floating badge shows where it stands, and one click offers a diffed rewrite you can accept or dismiss. It never edits your prompt on its own — and prompt text never leaves the machine unless you explicitly ask for a cloud rewrite.

Chrome Extension Manifest V3 TypeScript React 19 Shadow DOM Local-first 23 AI Sites BYOK Zustand Vite + CRXJS

Promptly

A case study by Haroon K M Scroll to read ↓
Built with
TypeScript React 19 Vite 8 CRXJS Zustand Tailwind v4 compromise diff-match-patch Chrome MV3 APIs Vitest happy-dom Playwright Supabase ESLint + Prettier
The thesis

Better prompts get better answers — but nobody wants to paste their prompt into a second tool to find out. Promptly puts the feedback loop where you already type: a live score as you write, the reasons behind it, and a one-click, diffed rewrite you accept or dismiss. Analysis runs locally in the page — no server, no telemetry — so your prompt never leaves the machine unless you ask.

See it live

From a two-word prompt to a structured brief — in one click

Type “make website” and the badge scores it 40 — Weak. Open the breakdown to see why: too short, vague verb, no constraints. Hit Improve and a rewrite appears as a word-level diff — role, constraints, output format and success criteria scaffolded in, with bracketed placeholders for what only you know. Accept, and it lands back in the editor, rescored.

View on GitHub →
01
The pipeline

How it works

From a keystroke in someone else's web app to an accepted rewrite — everything happens inside the page, in real time.

01

Detect

Hand-tuned adapters pin the exact prompt editor on ChatGPT, Claude, Gemini, Perplexity and Copilot — #prompt-textarea, ProseMirror contenteditables and friends. On the other allowlisted sites, a heuristic scores every visible input by size, position, send-button proximity and placeholder wording — and engages only when confident. A MutationObserver keeps up when SPAs re-render the composer.

02

Watch

Keystrokes are debounced at 200ms; pasted prompts analyze immediately. A requestAnimationFrame loop re-anchors the badge as the composer moves, and a 600ms poll catches sites that rewrite or clear the editor programmatically — with no input event at all.

03

Analyze

Ten pure-TypeScript checks run in-page — clarity, context, ambiguity, objective, constraints, output format, success criteria, role, tool readiness and structure. Zero runtime dependencies, synchronous, task-type aware: a coding prompt is judged on different constraints than a research one.

04

Score

Findings deduct from seven components — info −5, warn −15, high −30 — and a weighted mean makes the overall score: clarity and objective weigh 20 each, context and constraints 15, the rest 10. Under four meaningful words? Hard-capped at 40.

05

Badge

A pill toolbar floats above the composer's corner: the P mark, improve, library and a band-coloured score chip — ≥80 green “Strong”, 50–79 amber “Okay”, <50 red “Weak”. Click it for the full breakdown with per-component bars.

06

Improve

A deterministic local rewriter answers instantly — eight topic profiles scaffold role, constraints, output format and success criteria, with bracketed placeholders for what it can't know. If a provider is enabled, an AI rewrite follows: your Anthropic or OpenAI key, or a fully local Ollama model. Changes render as a word-level ins/del diff.

07

Accept

Accept writes the rewrite back framework-aware — the native value setter plus an input event for React textareas, insertText for ProseMirror and Lexical — and falls back to the clipboard if the editor refuses. An improveEpoch counter guarantees a late-arriving AI response can never resurrect a diff you already dismissed.

02
Capabilities

What it does

Everything between typing a prompt and sending a better one — without leaving the site you're on.

Live score badge

A floating pill scores the prompt as you type and tracks the composer as the page moves — with zero layout shift on the host site.

Prompt breakdown

Seven component bars — clarity, context, constraints, format, objective, ambiguity, AI readiness — plus a plain-language suggestion for every finding.

One-click improve

Instant local rewrite, upgraded by AI when a provider is on. Review the word-level diff, then accept, copy or dismiss — it never edits without you.

Refine with an instruction

Tell it what you want — “make it shorter”, “add acceptance tests” — and the rewrite is steered by your note on top of the analysis.

Prompt library

Save prompts you like and apply them anywhere the extension runs. Device-local by default; sign in and the library syncs through Supabase row-level security.

Bring your own AI

Provider chain: Anthropic key → OpenAI key → local Ollama → the built-in rewriter. Remote calls need both an explicit opt-in toggle and a key.

23 AI sites

From ChatGPT, Claude and Gemini to Poe, DeepSeek, Mistral, NotebookLM, bolt.new, v0, Replit, Cursor and Devin — plus a heuristic fallback for editors it hasn't met.

Keyboard-first

Ctrl+Shift+P toggles the card. The panel is draggable, clamps to the viewport, and follows the site's light or dark theme live.

Paste-aware timing

Typing is debounced 200ms to stay out of your way; a pasted prompt is scored instantly — the moment you're most likely to want a verdict.

Private by default

No analytics, no server, no telemetry. The only network call is the opt-in cloud rewrite — on your key, on your click.

03
The analyzer

Ten checks, zero dependencies

The analyzer is pure synchronous TypeScript — no models, no network, no libraries. Each check is a pure function over the prompt text, and each finding carries its own fix. A task-type classifier (coding, research, analysis, writing, general) decides which expectations apply.

clarity

Flags prompts under four meaningful words, and vague verbs — make, fix, improve — that carry no measurable request.

context

Catches “summarize this” and “fix it” — deictic references with no antecedent the model could possibly resolve.

ambiguity

Vague quantifiers — some, a few, stuff — and unresolved either/or choices that leave the model guessing.

objective

No actionable verb and not a question? The model has no task. This is a high-severity finding — −30 to its component.

constraints

Task-aware: a coding prompt should name a language or framework; writing wants length, tone or audience; research wants timeframe and sources.

output format

You're asking for an artifact but haven't said what shape — bullets, table, JSON, code block, word count.

success criteria

Substantial tasks with no measurable bar for “done” get a nudge toward acceptance criteria.

role

Suggests a persona matched to the detected task type — “act as a senior engineer” — when none is set.

tool readiness

“Latest” and “news” suggest enabling web search; a mentioned attachment prompts a check that it's actually attached.

multi-step

Sequential connectives — then, after that, finally — without numbered steps earn a structure suggestion.

04
Under the hood

How it's built

Running inside two dozen other teams' web apps — without breaking them, lagging them, or leaking from them — is the actual engineering problem.

23
AI sites supported
10
Local checks per keystroke
93
Automated tests
  • The overlay lives in a <promptly-root> Shadow DOM with inlined styles — site CSS can't bleed in, Promptly's can't leak out, and the host page's layout never shifts.
  • API keys never reach page context: the content script strips them from settings before anything enters the in-page store, and network calls happen only in the background service worker — on an explicit click.
  • Minimal MV3 surface: storage and activeTab permissions only, with optional host permissions for the two AI APIs and localhost. Sites it shouldn't touch are excluded structurally — they're simply not in the manifest's matches.
  • The analyzer is dependency-free by design so the per-keystroke path stays fast; the ~300KB compromise NLP library is dynamically imported only on the first Improve click, never while you type.
  • Every content-script callback is wrapped in a guard — a Promptly failure logs and disappears; it never breaks the page you're working in.
  • An improveEpoch counter is bumped on every accept, dismiss and re-improve, so a slow AI response that lands after you've moved on is silently dropped instead of overwriting your editor.
  • Editor write-back is framework-aware: React-controlled textareas get the native value setter plus a synthetic input event; ProseMirror and Lexical get select-all + insertText; success is judged by whitespace-normalized comparison, with a clipboard fallback.
  • Cloud rewrites default to claude-sonnet-5 at temperature 0.2 with a 15-second timeout — instructed to rewrite the prompt, never answer it, and preserve the user's intent, facts and language.
  • The prompt library is device-local until you sign in; with an account it syncs through Supabase behind row-level security, and the SDK itself is lazy-loaded only when a backend is configured.
  • 82 Vitest unit tests cover the checks, scorer, heuristics and providers; 11 Playwright e2e tests load the real extension into Chromium against fixture chat pages — including a test that it stays dormant on non-matched origins.
By the numbers
0
Prompts sent anywhere by default
1
Click from weak prompt to rewrite
200ms
From keystroke to fresh score