google sign-in no longer bounces back to the login screen
the dashboard now accepts google oauth even when your browser blocks the short-lived state cookie, and clears stale sessions before creating a fresh one on each google login.
every meaningful change, new features, fixes, and quiet improvements that i make.
the dashboard now accepts google oauth even when your browser blocks the short-lived state cookie, and clears stale sessions before creating a fresh one on each google login.
the local mcp scan tool now uses cached profiles immediately like the terminal cli, instead of waiting for account profile sync over the network.
setup docs and the dashboard wizard match how remote mcp actually works in the browser — including per-chat enable steps and a new perplexity connector path.
share one link with any ai app — it fetches step-by-step mcp setup for claude, cursor, chatgpt, codex, windsurf, and the rest, plus voice onboarding instructions.
a detailed ranking of ai writing models — prose quality, voice matching, seo, api pricing, and which models your chat subscription actually includes.
login, google sign-in, forgot password, and password reset now run on the edge worker instead of waiting for the python container to wake up. fixed repeat sign-in failures after a first successful login and cleared misleading “servers are waking up” errors when you were simply signed out.
fixed byok voice bible uploads that were rejected despite valid keywords, made welcome profile creation build the bible in the background, and tightened validation when saving or accepting drift updates.
new profiles are stored as a six-section operating manual you can paste into any chat — sentence mechanics, structure, vocabulary, tone, avoids, and three annotated examples. onboarding and welcome flows can build it from pasted writing without uploading samples first.
homepage buttons now say write in your voice for $1 and write in your brand voice on the team plan. removed the ltd savings row from pricing. fixed stray >> characters showing at the top of the blog page.
folder readmes now document edge auth, voice memory phases, deploy integrity preflight, lite container deploy, and uneed billing gates so the docs match what shipped in #342–#344.
a stale push to main had wiped july 11–13 blog posts, the site-wide get started for $1 ctas, voice memory wiring, and dashboard work from production. this release restores that mainline, keeps the uneed landing revamp, and blocks future deploys unless blog index, sitemap, cloudflare dist, and $1 checkout ctas all match source.
auto deploy was failing before upload because the workflow ran voice-memory tests without installing pytest. the dependency step is in place so blog and memory fixes actually ship.
production deploy now rebuilds the container, verifies every blog page and voice-memory editor bundle ships in cloudflare assets, smoke-checks live urls after upload, and refuses to cancel a deploy mid-flight when another push lands.
fixed /blog/voice-memory-composer 404s by verifying sitemap blog pages ship in cloudflare assets and checking the url after every deploy.
new post on what was broken in rewrite memory, what we shipped, and how ranked composition differs from dumping your full edit history into every prompt.
fixed editor compose silently failing on rewrites, duplicate memory blocks wasting tokens, team-shared profile stats missing teammate edits, and nightly consolidation not running from container cron.
rewrites and analyze calls can now pull a compact memory block from your edit history — ranked by which rules you accept or reject most. high-volume profiles can opt into similar-passage retrieval so prompts stay short.
when you accept a drift tuning note, it is included in the next rewrite and analyze prompts. cli and mcp learning data uses the same lesson format as the web editor.
the use hyv in cursor wiki page now leads with the cursor marketplace plugin and oauth mcp connect, with the cli install path as fallback.
manage billing now opens the right portal for your payment provider — dodo or kelviq — without waiting on the container. the billing tab also has a delete account section, and the dashboard is served with no-store caching so you get the current version.
email register, otp, login, and google oauth now run on the cloudflare worker with d1 and email — not the python container. the container only wakes for heavy work and sleeps after 2 minutes, so auth stays up without racking idle bill.
landing ctas now create an account first, then open kelviq payment. the dashboard mcp tab is remote-only (no local cli install path). billing checkout is served at the edge so payment links work even when the container is cold.
the blog pipeline now keeps at least one due keyword ready every day and maintains a five-post backlog, pulling future topics forward instead of waiting for every-other-day schedule gaps.
binary reframes and sermon cadence hit first in the editor score, rewrite prompts, and output gates — vocabulary slop is secondary.
the scanner now flags cross-sentence reframes like "this is not x. it is y", sermon anaphora, and polished founder metaphors — the patterns vocabulary checks miss.
removed the monthly and teams pills from the side plans, made the lifetime popular-choice badge green with a light sparkle, and tightened mobile stacking so lifetime shows first on small screens.
the pricing section now includes monthly, $79 lifetime, and team plans side by side, with lifetime marked as the popular choice and savings vs monthly billing called out below.
removed the muddy gradient wash from the hero, simplified the sticky nav background, and bumped the pricing contact line for readability.
rewrote terms, privacy, and billing pages with clearer international rights language. added a refunds page that states all sales are final. tightened the homepage problem line.
paid users can publish a voice profile to holdyourvoice.com/@handle, share the fingerprint and writing prompt publicly, and let others import it into their own account. your never-list stays private on the public page.
homepage kelviq checkout links now include the firstmonth discount so new subscribers see $1 for the first month instead of $9. wiki setup guides for claude, command code, cursor, and other apps are shortened to a three-step install → connect → test flow.
admin metrics now use discount-aware mrr from real payments ($1 first month individual, $29 multiple; agency/byok excluded). godview loads metrics first, then npm and analytics in the background. dashboard welcome wizard auto-starts free onboarding, docs tab fixed, and prompt analyze wired to /api/prompt/analyze. cli hyv mcp --setup now hydrates profiles into cursor, claude, codex, and more — verify with npx @holdyourvoice/hyv@latest mcp --test.
153 public pages now share the dark sticky nav, install pill, and canonical avatars. every page uses the landing hero as the default share image with secure og meta. sitemap, feeds, and llms discovery files regenerated for 164 public urls. install: npm i -g @holdyourvoice/hyv@latest && hyv welcome.
landing page and npm readme now lead with npx @holdyourvoice/hyv welcome and a free local scan section. new hyv content prints blog outlines, github actions snippets, and share templates. hyv plan --free shows the full free vs paid matrix. try: npx @holdyourvoice/hyv scan draft.md.
the npm cli now works fully offline for scan, fix, check, score, and diff — no subscription required. paid users get profile-aware never-list and learned-pattern detection, hybrid server analysis via hyv scan --server, and mcp tools hyv_analyze and hyv_clean for cursor and claude code. new commands: hyv welcome, hyv upgrade, hyv reinforce --last, hyv mcp --setup, hyv mcp --test. install: npm i -g @holdyourvoice/hyv@latest.
hold your voice is now a cli tool. install via npm i -g @holdyourvoice/hyv or npx @holdyourvoice/hyv. scans and rewrites run in your terminal against any file. your llm does the writing — hyv tells it how to sound like you. one voice profile, unlimited scans, $1 for the first month then $9/mo. the web dashboard is still there for profile management and billing. existing users: everything still works — the old editor is at /app, the new dashboard is at /dashboard.
platform llm calls now retry twice with exponential backoff before giving up. auth and billing errors (401/403/402) skip the fallback chain entirely instead of burning all providers. zen timeout raised to 30s, reasoning model timeout to 90s.
expired trials now move to the free plan automatically, and fix everything handles backend failures without leaving a confusing server error.
every published blog post now has a proper generated article image, and the blog page now features the brand voice maintenance guide.
new free tools cover word counting, grammar checks, paraphrasing, ai writing analysis, and text summarizing, with supported ai enhancement where it belongs.
uneed signups now keep the partner source through the app handoff, select the right plan, and keep the 30-day trial isolated to that page.
the editor formatting controls now sit in a compact collapsible menu beside the analysis panel, with cleaner spacing and the bottom editor fade restored.
uneed now has a dedicated hold your voice landing page with partner branding and scoped signup tracking.
mcp setup now includes /hyv-status, a one-call account view for profiles, documents, quota, byok billing, and team user rollups.
the homepage now explains how the rest api and mcp server let agents analyze drafts, resolve voice profiles, rewrite flagged lines, and keep publishing workflows on voice.
the homepage now shows how one draft moves through voice scoring, ai drift detection, sentence-level rewrites, and follow-up history.
every public page now has a matching .md version for agents, and the publishing checks fail if a new page ships without one.
team seats now draw from one shared monthly document bucket, so invited members cannot accidentally multiply the workspace limit.
generated pages now keep the header focused on the first month for a dollar, inline figures render as real images, and public voice profiles use cleaner @handle links.
god view now separates queue health from customer delivery health, so failed email automations point to the missing provider token instead of looking like a template bug.
paid upgrade emails now use the customer-safe cloudflare email service path with a worker fallback, so byok welcome emails do not get stuck on verified-recipient limits.
paid checkouts now promote trialing and expired users cleanly once payment is confirmed, so billing, app access, and god view stay in sync.
the site now has a dedicated founder page with photo, social links, and working about links across the public navigation and footer surfaces.
the voice profile page now groups setup answers, manual edits, learning memory, and samples into a denser workspace built for review and upkeep.
public pages now expose ai-readable markdown versions with strict headers and automated checks so new site pages keep the same discovery contract.
the editor button for saving the current draft as a writing sample now says “add as sample” so the action is easier to understand.
opening a blank or unscored document now clears the previous document’s score from the analysis panel instead of leaving an old number behind.
the quote screen is no longer exposed from the app route or sidebar, and non-byok accounts no longer wait on byok usage aggregation before the my key page opens.
shared document links now use a stable short url that survives title and brand changes, while private team-shared viewer and editor documents show up properly for recipients.
god view now shows all-time captured revenue in the top metrics instead of this month's document count, so paid upgrades are easier to see at a glance.
paid byok checkouts now have a second activation path if the payment webhook does not arrive, so a captured payment no longer leaves the account stuck as pending.
byok setup now lets you choose openai alongside anthropic, openrouter, and opencode, so new byok users can connect the provider account they already use.
paid byok checkouts now unlock immediately, existing data stays in place after purchase, and byok trials require a saved provider key before api or mcp access opens.
the homepage now opens with a clearer product definition, links to an about page and source notes, and exposes cleaner crawler context for ai search engines.
the editor now understands pasted markdown and typing shortcuts for headings, lists, quotes, links, code, and dividers, with cleaner rich-text copy output.
linkedin drafts now get a preview button in the editor, with a post-style modal, profile avatar support, light and dark preview modes, and cleaner footer controls.
the final onboarding step no longer traps you on a loading state. completed users are sent back into the app, and ai fixes now preserve list formatting in the editor.
the app now has a paid-only api/mcp page with copyable agent prompts, setup links, and key creation in one place, so local agents can configure mcp after payment is active.
the seo automation stack now repairs deterministic attribution, image, script, and discovery-file drift before writing audit reports, so recurring technical issues do not need manual cleanup.
we fixed malformed faq schema on a public article and added a lint guard so future pages fail checks before broken json-ld reaches search.
the editor now catches tidy founder-post rhythms like neat restatements and screenshot-ready punchlines, while cheaper background analysis looks for subtler issues after the instant scan.
profile setup still returns on the fast haiku path, then a stronger model can refine the saved voice profile in the background without blocking the page.
the fix everything fallback no longer reports recovered batch parser misses as product failures, and god view now keeps old fixed rows out of the live error lists.
sample-based voice analysis now uses a leaner haiku path with smaller prompts, so profile setup avoids the long reasoning-model wait that caused slow requests.
platform ai calls now route through opencode instead of direct claude api calls. voice analysis uses a stronger opencode model by default, with safer fallbacks and tighter provider error handling.
search and ai crawlers now get a richer public map of the site, including canonical pages, ai-readable summaries, and blog feed formats that stay updated with the generator.
guide and tool pages now point directly at live canonical pages instead of old redirect urls. the broken-link check also catches internal links that rely on server redirects, so search cleanup issues are harder to reintroduce.
the automate your seo page now focuses on buyer outcomes, launch support, pricing confidence, and a steadier mobile layout before asking visitors to book a call.
social previews now use smaller crawler-safe images with explicit dimensions, so shared links are more likely to show the right image in apps like whatsapp.
the public repository now has a fuller readme with setup, architecture, testing, api, and deployment notes, so the project is easier to understand from github.
new guide pages now keep their search title within the site limits, so published guides can pass checks before they go live.
autosend emails now use the actual hold your voice mark and a black-only visual treatment, so lifecycle and campaign emails feel closer to the product brand.
byok users can now manage their provider key from one sidebar page and see token usage, model calls, and source-backed provider cost in one place.
the voice memory and writing samples sections now finish loading reliably, so saved memory appears and sample uploads are available when voice v2 is on.
verification codes, resets, invites, digests, and lifecycle notes now share the same quiet hold your voice email frame so every inbox touchpoint feels consistent.
invited teammates show the right avatar immediately, pending invites update without a hard refresh, invites expire after 48 hours, and invitees land on the dashboard unless they choose to create a new brand.
the wiki index now opens with a simpler white header and no extra quick-answer card, stats block, or header buttons.
issue cards and tooltips now show why a line was flagged, including profile evidence, ai patterns, format fit, and learned accept/dismiss behavior. the voice profile page also shows readiness and voice memory so users know how much evidence the editor has.
the wiki now has dedicated api, mcp, profile routing, sharing, email, and support pages, plus a cleaner index that makes the product map easier to scan.
new signups now start on the newer voice profile system by default, and existing signed-up users are prepared for the same rollout in one batch.
batch rewrite responses are now parsed more defensively, so a model returning extra text or a numbered list does not crash the full fix pass.
lifetime byok customers now get a welcome email with the setup wiki link right after payment, while the existing upgrade email stays on the other paid plans.
scores now weigh brand voice match, ai-pattern cleanliness, remaining fixes, and writing strength instead of starting near the same range after every paste. the wiki and new blog post explain how the number moves.
the new wiki gives users and ai tools one clean place to understand the app, from voice profiles and teams to byok, api keys, mcp, sharing, billing, and troubleshooting.
there is now a dedicated blog post for the byok lifetime deal, with cleaner product visuals and a local email preview for the launch note.
the pricing section now highlights byok lifetime as the featured offer with updated plan details, cleaner trial messaging, and refreshed in-app upgrade labels. the homepage hero also calls out the limited-time byok deal more clearly.
pasted drafts now keep much more of their original structure, including headings, lists, quotes, links, and inline formatting. the editor’s own copy button now preserves that formatting too instead of flattening it to plain text. the slower ai deep check now only runs when you click run check yourself, and the editor tells you when it is running the main pass or a fallback model.
the server backend has been split from a single 4,500-line file into focused domain modules (auth, users, metrics, email, finance, seo, drift, errors). no user-facing behaviour changed — same routes, same auth guards, same rate limits. the reorganisation makes future changes faster and safer to ship.
reasoning models like qwen3.6-plus and deepseek can take 30–60 seconds on complex analysis prompts. the previous 25s timeout caused silent failures on those providers. anthropic (haiku/sonnet) stays at 25s.
the individual plan was listed at the wrong price in the admin revenue calculator, causing the mrr figure in the god dashboard to be understated. corrected to $19/mo to match the actual billing price.
multiple plan users can now bring their own openrouter or opencode key in addition to anthropic. select your provider in settings, paste your key, and all llm calls — including the initial voice profile build — run on your key at the appropriate model tier.
visiting holdyourvoice.com/blogs now redirects to holdyourvoice.com/blog instead of a 404.
social platforms were serving a stale cached version of the og image. added a cache-busting version parameter to force a fresh fetch across all pages.
switched from a single-threaded server to a multi-threaded one, and reduced per-llm-call timeout from 120s to 25s. a slow or hung ai request no longer blocks every other user on the site.
the "choose your path" step now shows time estimates for each option (~5 min vs ~30 sec), marks the paste-from-ai path as recommended with a distinct border and badge, and keeps both cards the same height.
the left navigation bar (dashboard, voice, analysis, etc.) no longer appears while a new user is going through the onboarding flow. it comes back once onboarding is complete.
added a new post cataloguing the ten most recognisable ai writing patterns — from throat-clear openings to symmetrical structure — with real examples of each and how to catch them in your own drafts.
several guide pages linked to blog posts and tools that did not exist, causing 404s. missing pages were created or redirected, dead-link redirects in server.py now cover both pretty-url and .html variants, and a new ci workflow blocks merges that introduce broken internal links.
all requests to www.holdyourvoice.com now 301 redirect to holdyourvoice.com to ensure a single canonical url. this fixes the "alternative page with proper canonical tag" warning in google search console and ensures proper seo credit consolidation.
sitemap.xml is now automatically generated and updated before every commit. the system scans all html files, excludes pages marked noindex and internal content (design templates, concepts, profiles, god admin, seo-automatic), and generates fresh urls with proper priorities and last-modified dates. new pages are included automatically.
get_user_plan and the document quota checker now fail open when the subscriptions table is missing, instead of crashing with an sqlite error. this fixes the security test suite on ci where a fresh database is created without running the full migration.
the rest api and mcp server are now gated behind an active paid plan. free and expired users cannot create api keys or call any /v1/* endpoint. the web app's document and analysis features remain free — only the external api surface is paid-only.
shortened a blog post title that was over 60 characters. added a noindex tag to the internal daily posts preview page so the seo linter stays clean.
when your $1 first month ends, you drop into the free plan — unlimited documents, full voice checks (including deep ai analysis), and collaboration still work. only ai rewrites (fix with ai) need a paid plan. the trial-expired screen is now a one-time popup you can dismiss, and a persistent "free · upgrade" badge sits in the sidebar.
trial countdowns in the admin dashboard were off by up to 5.5 hours because utc timestamps were parsed as local time. fixed by appending utc markers. also added an "expire now" option to the admin trial dropdown, and plugged a sweep gap where trialing users who completed onboarding but never got a trial_ends_at stamp stayed trialing forever.
swapped the secondary fallback in the llm chain from deepseek-v3 to qwen3.6-plus. ran 360 head-to-head tests across rewriting, generation, scoring, and drift detection — qwen won every category. when haiku is rate-limited, your draft still gets the strongest available fallback before the chain escalates to sonnet.
nine free tools now have an "enhance with ai" button that generates higher-quality output using the opencode go api with mimo-v2.5. improved heuristics across five more tools: readability checker now detects passive voice and jargon, email subject scorer has 80 power words and mobile preview, brand voice analyzer adds two new dimensions, brand name generator gets portmanteau strategy, and roi calculator includes payback period and ltv/cac ratio.
the underline in the favicon now wipes in from the left and exits to the right on a 2.8s loop. works in all major browsers that support svg animations.
mass-suppressed bot and scanner 404s (archive probes, git probes, old cms assets, api doc scanners, favicon variants). added redirects for /features, /about, /contact, /sitemap_index.xml, and /privacy + /terms subpaths on tool and compare pages. dead blog post urls now redirect to /blog. otp endpoints no longer trip the slow-request alarm — smtp latency is expected. added /llms.txt for ai crawlers.
browsers and third-party tools that request /favicon-32x32.png (and /favicon-16x16.png) now get a 301 redirect to the svg favicon instead of a 404 error.
added 301 redirects for two urls that were returning 404s: /blog/voice-guide-mistakes.html now redirects to the brand voice guide post, and /tools/platform-voice-checker.html redirects to the brand voice analyzer.
mcp_server.py was deleted in the previous cleanup commit despite being actively tested by the security suite. also restored increment_usage and increment_document which were lost from hyv/usage.py at the same time, breaking server startup.
new free tool at /tools/ai-drift-detector — paste any text to score it for ai-generated language patterns. detects transitional filler, robotic hedges, ai clichés, and connector overuse. fully client-side, no signup required.
cleaned up _archive, _design, _video, test files, and orphaned marketing assets from the codebase. also removed 9 dead functions from hyv modules (tasks.py, sentry.py, db.py, usage.py) that were never called.
if you had grammarly or quillbot installed, their underlines and tooltips were overlapping our own suggestion cards inside the editor. they now stay out of the writing area on /app, zen mode, and the voice audit tool. the rest of the page still works with your extensions as normal.
the analysis tab now opens with a bento snapshot of how you write — your archetype, peak writing time, most-used word, your catchphrase, your ai-accept rate, and a 10-draft score trend. unlocks once you've hit 10 documents or 2,500 words; until then, a live counter tracks your progress. download as a jpeg or share once it's yours.
these urls were returning 404. they now 301 redirect to /#pricing so anyone who types a pricing url lands in the right place.
add up to 50 of your own writing samples (paste or .md/.txt drop) and we'll build your voice profile from how you actually sound, not from flashcard guesses. every rewrite now sees that profile plus the previous and next sentences from your draft, gets scored against your real voice (0–100), and escalates to a smarter model if it doesn't pass. regenerate clicks now learn from what you reject — each next try is smarter than the last. opt-in per account for now; flipping on globally next.
broken pipe errors (client disconnected mid-response) are now silently ignored instead of being filed as bugs. scanner bot 404s (wp-admin, .php paths, etc.) are also suppressed. favicon.ico requests now redirect to favicon.svg instead of 404ing.
shipped scripts/seo_lint.py to scan every html file for the issues that kept slipping through (broken titles with anchor tags, title/description out of length range, missing og tags or canonical) — currently zero issues across all 72 pages. extended the server rewriter to auto-derive twitter:title/description/image from og:* tags and hreflang x-default from the canonical, so new pages stop having to remember those. fixed two more blog posts with anchor tags inside title, gave full og blocks to /privacy, /terms, and the duolingo / notion compare pages, marked internal preview pages noindex, and tightened titles + descriptions on every page the lint flagged. baked the same rules into blog_post.py / tool_build.py / comparison_page.py / programmatic_page.py / geo_guide.py so generated pages can't bring the bugs back.
fixed broken titles on two blog posts (anchor tags inside <title>), tightened titles and meta descriptions on /blog, /manifesto, and /blog/what-is-brand-voice, added missing twitter card tags + hreflang x-default to every public page, gave the /app surface a proper canonical, og tags and noindex, added jsonld schema to the manifesto, gave avatar images on the homepage real alt text, and auto-injected an apple-touch-icon link on every page via the server rewriter.
404s for /openapi.json, /swagger, and /api-docs are now silently ignored by the bug reporter, same as .env and wp-admin probes.
the otp verify handler was opening three separate sqlite connections in sequence. the third connection for rate-limit reset was racing the main write transaction and hitting the 5s busy_timeout. now inlines the rate reset into the same transaction, dropping it to two connections.
404s for paths commonly probed by vulnerability scanners (e.g. /.env, /backend/.env, /.env.old) no longer trigger bug-reporter issues. only genuine user-facing 404s are reported.
added a csp frame-ancestors directive so the site can be embedded by rankinpublic.xyz. previously the strict x-frame-options: deny header blocked all third-party embeds.
the dashboard grid now opens with a google-docs style "+ new document" tile in the first slot, alongside the existing button in the header. the tile hides while you're searching or filtering so results stay clean, and reappears when you clear them. also fixed the search box's magnifier icon, which was sitting a few pixels too low.
the dashboard search now understands meaning, not just keywords. type a phrase like "client onboarding emails" and it finds the right doc even if those exact words aren't in it. search queries of 3+ characters are debounced and sent to a vector similarity backend powered by google's text-embedding-004. existing documents are backfilled on first deploy.
if an email login triggered otp verification, the last used method was never written to storage so the badge wouldn't appear on the next visit. now correctly recorded after the otp step completes.
the server auto-injects a link to /css/transitions-lib.css on every html page but the file didn't exist. created the file with all motion utility classes (t-modal, t-dropdown, t-panel-slide, t-text-swap, t-icon-swap, t-digit-group, t-badge, t-page-slide, t-resize) and a prefers-reduced-motion guard.
badge background, text, and google border breathing animation are all black. email/password now shows the same black pill style as google — no more mismatched indicator.
badge background, text, and google border breathing animation are all black. email/password now shows the same black pill style as google — no more mismatched indicator.
the 'last used' pill is now regular weight instead of bold. when google was last used, the button gets a slow pulsing orange border. for email, the indicator is a small inline '· last used' label in the tab.
returning users see a small 'last used' chip next to the sign-in method they used previously, so they know which button to click without guessing.
previously the stat pill auto-reappeared 1.4 seconds after typing stopped, which read as a flicker. now it stays gone until you actually move the mouse.
swapped the fade overlays for a css mask-image so text actually dissolves into transparency at the edges. the page underneath shows through unmodified — no visible gradient band.
the fade at the bottom of zen mode previously had a faint boundary where the alpha dropped. the transition is now imperceptible.
the zen mode controls are now tucked in the bottom-right corner. the fade gradient is smoother, and focus mode is an inline button rather than a floating element.
the doc title shows above the writing area in zen and syncs both ways with the main editor. added soft gradient fades at the top and bottom so text floats in and out of view.
the auto-fix system now monitors server 500s, database failures, email errors, auth failures, and two more sources in addition to client-side exceptions.
404s were happening silently. they're now logged and fed to the auto-fix pipeline so broken links get caught automatically.
the self-healing pipeline previously only caught server-side errors. it now also receives client-side javascript exceptions from the app.
supermeme api was producing inconsistent results for blog illustrations. switched to google imagen for more reliable output.
errors from production get captured, triaged by severity, and routed to a repair workflow that proposes code fixes automatically — no manual intervention needed.
added a dedicated landing page explaining the seo automation service, its outputs, and how to get access.
zen mode is now live for all users — a distraction-free writing canvas with smooth entry/exit transitions and a minimal word count pill.
the validator was comparing new page structures against old published versions and incorrectly marking them as errors. fixed the comparison logic.
several automation scripts were crashing on api provider errors without retrying. added proper error handling and retry logic.
the 'fix with ai' button was trying to parse an html error page as json, causing a crash. it now handles non-200 responses gracefully.
the changelog link in the sidebar had an unexpected underline from a css specificity collision. now matches the styling of other sidebar links.
the severity labels (high/medium/low) inside analysis tooltips had been styled with near-invisible text after a css refactor. contrast is restored.
the tooltip that appears when hovering the zen mode pill was rendering below the button and getting clipped by the viewport. it now anchors above.
the voice score panel was showing stale data after edits without re-running analysis. it now updates correctly when the document changes.
admins can now downgrade a user to the free plan directly from the edit modal, without needing to touch the database.
users whose trials had expired were showing as 'none' in the admin dashboard, making it hard to distinguish from errors. they now correctly show as free.
the trial expiry email sequence now explains the free plan instead of just asking users to upgrade — clearer expectations on what they keep.
the free plan code changes merged to main but are not yet wired to any user-facing flow — groundwork for the upcoming tier release.
the onboarding banner was overflowing its container on some screen sizes and sitting off-center. layout is fixed.
the changelog footer had a large signup cta block that felt out of place. removed to keep the page focused on what shipped.
the public changelog now shows the complete history of every shipped change. a changelog shortcut was also added to the app sidebar.
the public changelog at holdyourvoice.com/changelog went live, showing the 13 most recent shipped changes.
three index pages were missing json-ld structured data, triggering 25 schema validation errors in google search console. all cleared.
major update to the admin dashboard: new metrics, improved routing, and several server-side improvements shipped together.
the seo-automatic landing page now reflects the self-healing workflow and includes kpi tracking sections.
a new automated system monitors seo health, detects regressions, and queues fixes without manual intervention.
the voice profiles listed in the footer were showing '@handle' prefixes that cluttered the display. now just the name.
the automated health commit step was failing when there were uncommitted changes. it now stashes first.
ga4 report calls were failing silently. added logging of the token identity and full error response to make failures debuggable.
text on comparison subpages wasn't consistently lowercase. fixed across all compare pages and seeded the image-failures tracking file.
a sweep across all public-facing pages to enforce lowercase in headings, titles, and meta tags per the brand voice rule.
automated content pages were sometimes getting wrong publish dates, mixed-case text, and broken image references. all three fixed at the generation step.
logged the day's fixes in the god view release history for audit purposes.
the 'fix all' batch action was crashing when any rewrite suggestion contained quotes, because the json wasn't being escaped. fixed.
debug logging added during otp troubleshooting was printing the raw verification code to railway logs. removed immediately.
the admin otp flow was checking the wrong session cookie after verification, causing valid logins to bounce. correct cookie name restored.
the admin otp flow was silently failing with no trace. added detailed server-side logging to the verify step to find the root cause.
the byok encryption function was refactored to return a (ciphertext, salt) tuple but the tests weren't updated. tests now match the new signature.
two security test cases were failing after daily caps were added and the byok module was renamed. tests updated to match.
completed a four-phase security audit covering authentication flows, rate limiting, data encryption at rest, and general hardening. multiple findings addressed.
added a /healthz endpoint that returns 200 for railway's health checks. without it, deployments could be marked unhealthy even when the server was running.
the faq auto-generator ran its scheduled pass and published new faq content for this date.
the rest api now supports multiple voice profiles per account. callers can reference a profile by brand name instead of uuid. token usage is now attributed per brand.
the /v1/documents update endpoint was returning a 'similarity' field that referenced a removed function, causing an occasional 500. removed.
the abuse detection was comparing against a wrong baseline, making legitimate users hit limits. also fixed a bug where typing (not submitting) was consuming quota slots.
document quota was being incremented twice on some save paths, causing users to hit limits prematurely. the sidebar and dashboard counters were also showing different numbers.
the email sequences tab was confusingly named 'sequences'. renamed to 'email' and hid the old redundant tab.
the trial cleanup job was incorrectly cancelling trials that were mid-onboarding. also fixed duplicate rows building up in the email send queue.
the editor now records every time you accept or dismiss an ai suggestion. when enough signal accumulates, the drift engine surfaces a proposal to update your voice profile.
when a user changed their email, the queue rewrite was matching by the old email string, which could incorrectly update rows belonging to other users. now keyed on user_id.
a few import statements were referencing drift handler functions that hadn't been merged yet, causing import errors on cold start. removed.
users can now export all their documents as markdown in a single zip download. also added a two-step email change flow with otp verification.
visual cleanup on comparison pages: removed divider lines and the writer.com navigation pill. the automation pipeline now inserts competitor links automatically.
the writer.com comparison page was missing the competitor's logo and outbound links. added both.
supermeme had a single api key path and no fallback. image_utils.py adds multi-key rotation and an endpoint fallback so image generation degrades gracefully.
blog posts, comparison pages, and tool pages now get ai-generated illustrations from supermeme.ai added automatically during the generation step.
added a public voice profiles index page. faq pages now get accurate publish dates. voice profile page dates are now read from the index file instead of the filesystem.
the comparison page auto-publisher ran its scheduled pass and published new comparison pages for this date.
three issues on the api/mcp page: missing nav arrow, timestamps showing utc instead of ist, and the solo price showing the old $29 rate. all fixed.
launched the /api-mcp documentation page explaining how to connect hold your voice to ai agents via the mcp protocol. server route added.
documents were running the voice check automatically on load before the user asked. also fixed a bug where the results panel showed 'no issues found' before the check had actually run.
fixed 14 findings from the security audit: input sanitization gaps, missing rate limits, weak session handling, and several smaller issues.
the ai suggestion tooltip was implemented with ad-hoc show/hide logic that kept breaking. rebuilt around an explicit 4-state machine (idle, loading, showing, closing).
four security vulnerabilities confirmed during the audit: an auth bypass, a csrf gap, an input sanitization issue, and a missing access control check.
new users could end up with plan='none' if the plan assignment step failed at signup. plan is now set atomically at auth time.
the privacy policy, terms of service, and other legal pages had mixed-case headings and body text. swept to lowercase.
the mobile signup gate now collects the user's name. added a /fup page explaining the fair usage policy.
added the /.well-known/oauth-authorization-server endpoint so oauth clients can discover authentication endpoints automatically.
the hero cta pill had some rough edges in its hover state. also removed a 1px ghost line appearing in the desktop nav on some browsers.
the api now enforces a content displacement quota to prevent abuse. the message shown when a user downgrades is now more specific about what changes.
navigation links on secondary screens (billing, access, profile) had inconsistent hover states. also fixed the launch pill on the homepage hero.
visual polish pass on the api & mcp tab and the public landing page — spacing, colour, and layout consistency.
cleaned up the api & mcp settings tab: repositioned the plan badge, reordered cards, added a trial gate, and tightened the interface.
removed the plan badge from the tab title and the plan limits card from the api & mcp section to reduce clutter.
cleaned up the api & mcp settings tab: repositioned the plan badge, reordered cards, added a trial gate, and tightened the interface.
removed the plan badge from the tab title and the plan limits card from the api & mcp section to reduce clutter.
the ai suggestion tooltip had accumulated 7 known bugs including wrong positioning, stale state after navigation, and double-click issues. all patched.
web-facing bots can now authenticate via jwks. also fixed markdown content negotiation so /blog/post and /blog/post.md both resolve correctly.
the markdown negotiation logic was doing a raw string check on the path, which broke on urls with query strings. switched to translate_path() which handles this correctly.
the api keys tab was a plain list of keys. it now shows a plan comparison table, an explanation of bring-your-own-key, and a breakdown of api usage by endpoint.
holdyourvoice.com now speaks the protocols ai agents expect: link headers for pagination (rfc 8288), content negotiation for markdown, and well-known discovery endpoints.
the blog, faq, and comparison idea generators weren't reading the full published backlog, so they occasionally suggested topics that were already live. now reads all published topics before generating.
moved faq pages to the /faq/ url structure. the cta button on faq pages is now black for consistency with the rest of the site.
the faq auto-generator status and queue was buried in the admin view. promoted to its own section in the seo tab.
the faq auto-generator ran its scheduled pass and published new faq content for this date.
a python f-string was being used to generate javascript, and an unescaped quote in the onclick handler was causing a syntax error at render time.
when the faq topic backlog drops below a threshold, the system now automatically generates new topic ideas and adds them to the queue.
a new weekly automation generates faq content on a schedule and publishes to /faq/<slug>. seeded with an initial backlog of question topics.
six confirmed vulnerabilities from the enterprise audit addressed: missing auth on one endpoint, two injection risks, an insecure direct object reference, a session fixation issue, and an information leak.
the seo god view now shows a rolling daily log of automation metrics — posts published, pages indexed, errors, and queue depth.
the analytics tab now has a single unified table combining page views, cta clicks, and signups from both posthog and ga4, with 7/30/90 day period filters.
the top ctas table in the analytics tab now shows how many signups each cta drove in the last 7 days, not just click counts.
ga4 api calls now degrade gracefully on any error. the activity and attribution tabs are hidden until data is reliable. added cta conversion data from posthog.
removed the google-auth third-party library. the ga4 integration now uses the same stdlib-only jwt approach as google search console, cutting a dependency.
a referenceerror was being thrown when doc save failed because a variable was referenced before assignment. also fixed a json parse error in the ga4 overview response.
the ga4 integration now automatically reuses the same service account credentials as google search console, so there's only one set of credentials to manage.
added a google analytics 4 tab to the admin dashboard. fixed a content security policy violation that was blocking some tracking scripts. added event tracking.
ga4 analytics is now automatically injected into every html page at serve time, like posthog. no manual tag needed on new pages.
expired accounts now get a read-only mode instead of full lockout. byok users can see their key status clearly. the quota model is documented in the api response.
the rest api now supports bring-your-own-key. the delete endpoint is disabled pending a safety review. all plans now have an rpm limit. api audit logs cleaned up.
addressed the critical and high-severity findings from the security audit before the enterprise feature launch.
launched the mcp server so ai agents can connect directly to hold your voice. renamed the sidebar section from 'api' to 'api/mcp'. security hardening applied.
every call to the rest api is now recorded in an audit log with user, endpoint, status, and timestamp. enables compliance reporting and anomaly detection.
api key management moved from a buried settings panel to its own dedicated screen in the sidebar, positioned below the access section.
api_auth.py was using the | union type syntax (python 3.10+) which broke on the railway python 3.9 runtime. switched to Optional[] annotations.
launched the rest api: /v1/analyze, /v1/rewrite, /v1/documents, and /v1/usage. api key auth, quota enforcement, and structured error responses included.
the pricing cards were combining document limits and review limits into a single line, which was confusing. split into two separate bullet points.
removed the monthly cap on reviews and rewrites for solo and team plans. documents remain limited per month — everything else is unlimited.
the schema audit section in the seo tab was hardcoded to show 1/1/1 instead of reading the real counts. fixed.
four automation scripts were calling mark_done() without writing the actual publish date, leaving all rows with null dates. fixed.
content was being marked as published with the scheduled date from the backlog rather than the actual date it went live. now stamps when mark_done() is called.
the blog index page was sorting and displaying the scheduled date instead of the actual publish date, making recent posts appear older than they are.
a batch close of low-risk bugs found across the automation pipeline — mostly edge cases in error handling and off-by-one issues in queue management.
the blog auto-publisher ran its scheduled pass and published new blog content for this date.
large html page generators were timing out on the standard api. switched to the streaming api, which keeps the connection alive for long-running generation calls.
html-generating calls were capped at a lower token limit that was cutting off large pages mid-generation. raised to 64k to match the model's full output capacity.
documented utm parameter rules in claude.md. fixed blog nav links using the wrong utm_medium. all automation scripts now bake utm params into generated ctas.
108 cta links across 47 files were missing utm tracking params. added utm_source, utm_medium, utm_campaign, and utm_content to all of them.
the /compare directory was serving a raw file listing. replaced with a designed index page with cards for each comparison.
the grammarly comparison page got a redesigned pricing table that highlights the differences more clearly.
the /tools directory was serving a raw file listing. replaced with a designed index page with cards for each tool.
the seo tab was crashing because 'today' was undefined in one code path. also fixed two cta links and updated grammarly pricing to reflect their current rates.
the activity log in the god view was showing programmatic seo pages without clickable urls. the url is now built and linked automatically.
three god view elements that were showing stale or redundant data — the today summary, status bar, and metric cards — removed to reduce noise.
content scripts were checking if today was past a scheduled date before publishing, which blocked legitimate immediate runs. removed all date gates.
the blog cron job was skipping posts whose scheduled date hadn't passed yet. now publishes whatever is next in the queue on every run.
addressed all outstanding schema validation errors across the site. also repaired two automation workflows that had stopped running.
the backlink outreach drafter was generating drafts that weren't being used. removed to simplify the automation pipeline.
the backlink outreach pill was firing but nothing happened. fixed the action. added a modal in the god view to create gmail drafts directly.
the blog listing page was showing posts in an inconsistent order. now sorted newest-first. the automation now inserts new posts at the top of the grid.
existing seo audit report files were missing the live url field. backfilled all reports with the correct published url.
seo audit reports now include a link to the live published page alongside each finding.
the seo tab in the admin dashboard was crashing with a nameerror because `os` was being used without being imported in one handler. fixed.
the audit scripts now automatically apply the fixes they identify instead of just reporting them. updated to node.js 24. page timestamps updated.
the title and meta description suggestion automation ran for this date and queued improvements.
the schema audit automation ran for this date and filed its findings.
the internal link audit automation ran for this date and identified missing link opportunities.
the backlink outreach drafter ran for this date and created draft outreach emails.
the on-page seo audit automation ran for this date and filed its findings.
the api usage tab was lumping app usage and automation usage together. split into two columns so the cost breakdown is clearer.
the seo-automatic landing page now explains the voice profiles integration. also added content about the auto-refill feature and updated pricing.
when any content queue runs dry, the system now automatically generates new topics and refills it. no manual intervention needed.
the automated voice profile generator ran for this date.
a new weekly automation generates voice profile content on a schedule and queues it for review.
fixed a reflected xss vulnerability. rate limits now persist across server restarts. otp codes are deleted after use. csp header added. html output sanitized.
the backfill query was doing a full table scan. switched to a join on profile_id. also removed a dead update to share_brand_slug that was a no-op.
shared documents were returning 404 when accessed via a url with a different brand slug than what was stored. now resolves by doc id regardless.
existing shared documents were missing the brand_slug field needed for clean public urls. backfilled from the associated voice profile.
shared document urls now always resolve correctly regardless of how the slug was formatted. also polished the 404 page.
hovering over a comment anchor on a public document now shows a tooltip with the comment preview, so readers can see what's being discussed without clicking.
the content gap script had a malformed shebang line and an unclosed docstring that prevented it from running. fixed.
tightened the cors allowlist to known origins. otp attempts are now rate limited. the seo-automatic dashboard requires auth. removed all hardcoded api keys.
the seo-automatic dashboard now shows on-page audit results and content gap analysis cards. also fixed an incorrect open page rank api url.
added three new data sources to the seo pipeline: on-page audit scores, content gap analysis against competitors, and open pagerank scores.
the seo-automatic page was defaulting to dark mode styles. switched to light mode and updated the pricing section with a refinement pass.
generated content now goes through a second pass using the user's voice profile and ai eliminator before publishing, improving quality and reducing ai-sounding patterns.
the logo was rendering white on the seo-automatic page due to a missing color override in the dark header section. fixed.
the seo-automatic landing page wasn't responsive. layout fixes for mobile and tablet breakpoints.
added an internal dashboard page at /seo-automatic that shows the live seo automation pipeline — queue status, recent publications, and metrics.
the geo guide automation now publishes every 3 days instead of weekly. expanded the topic queue to 20 guides.
the programmatic seo auto-publisher ran its scheduled pass for this date.
launched three new content automation pipelines: city/niche/brand-voice programmatic pages, answer-engine-optimized blog structure, and geo-targeted guides.
removed the sub-copy lines under cta buttons ('$1 first month · no card required · takes 5 minutes'). added a claude.md rule to prevent adding them back.
the query counting done posts was failing when rows didn't have a url column. updated the regex to match all done rows regardless.
the google search console feedback loop and monthly content calendar generation now use claude sonnet instead of haiku for better output quality.
the comparison page auto-publisher ran its scheduled pass for this date.
the compare/ directory was sometimes absent, causing `git add compare/` to fail in automation workflows. added a .gitkeep file to ensure the directory always exists.
the deploy script was failing when the compare/ directory didn't exist yet. added --ignore-unmatch so git add handles new directories gracefully.
the comparison workflow was failing when the compare/ directory didn't exist yet. now creates it if missing and backdates the first entry correctly.
removed the typefully social media distribution integration. social is not part of the current distribution strategy.
shipped a batch: competitor comparison pages, google search console feedback loop, internal linking automation, schema markup generation, typefully distribution, and minimal footer.
the seo god view now shows a daily health summary written by claude haiku — a plain-english digest of what's working and what needs attention.
the seo god view tab now includes a backlinks checklist and a daily health status panel.
the content calendar automation ran and generated the schedule for april.
the competitor monitoring scan ran for this date and filed its findings.
added the indexnow key verification file at /<key>.txt so the indexnow submission service can verify ownership.
the seo pipeline now includes backlink prospecting (finding relevant sites to reach out to) and submits the sitemap to indexnow on each publish.
added the indexnow key file needed to verify domain ownership before submitting the sitemap.
published a new blog post explaining the difference between brand voice and tone of voice — a common source of confusion.
added a new free tool: value proposition generator. enter your audience and what you do, get a sharp one-liner back.
the content calendar automation ran and generated the schedule for april.
the competitor monitoring scan ran for this date and filed its findings.
slowed blog publishing from daily to every other day to improve quality. refilled the keyword queue through may 19.
published a new blog post on recognising ai writing patterns and removing them from your own drafts.
launched a hub of 20 free writing tools at /tools. included a design overhaul and several seo fixes across the tools section.
comment anchors on shared documents now show in grey when not hovered. the text matching that places anchors is more robust against whitespace and formatting differences.
when a shared document had no html content yet, the page showed a blank body with no explanation. now shows a placeholder message.
added an email sequences tab to the admin dashboard. backfilled signup nudge emails for users who signed up without receiving them. plan labels are clearer.
the 'pending signup' state was too broad. split into two distinct states so it's clear whether a user abandoned before otp or after.
the full trial flow is now implemented: a gate that holds users in onboarding until setup is complete, and an automated nudge sequence that runs during the trial.
the tweet format tab is hidden for now (not ready). the sidebar border wasn't aligning with the editor nav bar — fixed.
the ai slop checker free tool was rebuilt from scratch with a cleaner interface and faster analysis. added a link to free tools in the footer.
the neetochat support widget was appearing on top of the editor and getting in the way. hidden on the editor screen.
replaced the featurebase feedback widget with neetochat, which supports both feedback and live support in one.
rewrote the 'why not ai' section with sharper, more direct copy. tightened spacing between sections for a cleaner vertical rhythm.
tooltip text colours were drifting from the approved design. updated to exactly match the reference.
tooltip body text was too low-contrast on the dark background. increased to meet readable contrast ratios.
tooltips now show a colour-coded severity strip (high/medium/low). swept 14 error rows from the fuckups tab. polished spacing throughout the editor.
analysis now runs automatically when a document loads. the legend moved to a less intrusive spot. issues header is sticky. tooltip rows have more breathing room. popup positioning fixed.
the detailed colour legend with labels was replaced by a compact reference strip — just the colours, no labels cluttering the panel.
applied fluid functionalism design principles to the editor layout. tightened the colour legend to take less vertical space.
the cta box at the end of each blog post was indistinct. redesigned with a dark base, accent colour strip, and a clearly styled button.
removed the 'your voice is yours' footer block that was appearing on every blog post — it was redundant with the cta and added noise.
the blog listing page got a full redesign. the entire card surface is now clickable, not just the title link.
a batch fix covering five areas: pricing display bugs, abuse guard edge cases, autosave failures, dodo/posthog integration issues, and landing page layout bugs.
the negation-cascade ai rule now highlights the full span of affected text rather than just the trigger word. autosave now fires on every input event, not just blur.
a site-wide polish pass: headings now use text-wrap:balance, body text uses text-wrap:pretty, font smoothing improved, numbers use tabular spacing, and transition overrides are more specific.
primary buttons had flat 1px borders that looked thin at larger sizes. replaced with a stacked box-shadow that gives them depth.
posthog analytics is now auto-injected into every html page by the server at serve time. no manual tag needed on new pages.
unhandled errors in the product now get captured and sent to a fuckups tab in the admin dashboard, making it easy to see what's breaking in real time.
the ai rewriter was silently failing when the api returned an error — no feedback to the user. now shows an error state. the tooltip action button was overflowing its container.
the landing page got a major redesign: a before/after hero mockup, an editorial-style how-it-works section, and a checklist for the 'why not just use ai' section.
the self-hosted traffic-source tracking script was removed. posthog covers everything it was doing.
the traffic-source analytics snippet had a wrong attribute value. the analytics dashboard is now embedded directly in the admin view for quicker access.
added a self-hosted traffic source tracking snippet to every page so we can see where users are coming from without relying solely on posthog.
six public brand voice profile pages are now live at /@handle. each shows a voice fingerprint, sample writing, and key voice attributes.
the blog and manifesto pages were missing the standard nav bar and footer. added both and enforced lowercase throughout.
svg logo references were being cached by cloudflare and not updating on deploy. added version query strings. also added the nav bar to all blog pages.
the css-text wordmarks on the app, admin dashboard, and voice audit pages were updated to match the new logo design.
the logo underline was 5px regardless of the logo size, making it look thin at larger sizes. now scales proportionally.
the logo wordmark svgs were rebuilt with google sans bold paths outlined directly, plus the signature underline. no more font dependency in svgs.
new users are now assigned a notionist avatar seed at signup. the backfill job that previously set seeds is now just a safety net for edge cases.
trained 10 new ai-ism detection rules from samples of linkedin posts, covering patterns like over-qualified claims, value-stacking lists, and engagement bait.
added a new ai-ism rule targeting the 'here's what x taught me about y:' phrasing pattern — a common ai writing tell when summarising an experience.
added three rules covering negation cascade ('not just x, but y') and adjective truth patterns ('the real reason', 'the honest truth') common in ai writing.
the app now has a url-per-section so the browser back button works. the sidebar persists across navigation. routing logic extracted into its own module.
the hero highlight animations are now static on initial load instead of animating on every pageview. the drift blob in the how-it-works section reacts to the voice score.
featurebase was being installed without user identification. now signs a jwt server-side for logged-in users so featurebase shows their account context.
installed the featurebase in-product messenger on both the marketing site and the app for feedback collection and feature requests.
the comments tab notification badge was orange. changed to black to match the overall colour scheme.
various polish improvements to the editor ui. also lowercased all text in the faq section on the homepage.
the nixpacks build was detecting both python and node and trying to build both, causing failures. forced python-only via nixpacks config.
the admin dashboard now shows the user's notionist avatar next to their name in every table row.
replaced photo upload avatars with generated dicebear notionist avatars. unique per user, always available, no upload needed.
the ai-ism v2 learning loop was hitting posthog rate limits on high-traffic days. added a dry-run mode and a memory cap to prevent unbounded growth.
final tuning pass using a representative corpus. all gates are green — no new false positives introduced, recall improved by 12%.
the ai-ism engine now has a learning loop that adjusts rule weights based on accept/reject signal. added a hit budget per analysis and a master toggle to disable all rules.
added bucket b (soft flags that only show if density is high) and bucket c (density-only detection). consolidated all banned patterns into a single registry.
54 new hard-tier patterns added to reach the first 100 rules milestone. covers overused business phrases, ai connector words, and formulaic sentence openers.
41 new hard-tier rules added covering the most common ai writing tells — antithesis constructions, hedging phrases, formulaic connectors, and cliché openers.
the aiismeliminator class is now exported for use in the api. proper noun detection added to the hard tier to catch things like 'in today's ai-powered world'.
rewrote the ai-ism engine to be driven by a rule registry. all 19 original rules re-evaluated — 3 promoted, 2 demoted, 14 kept.
added per-user allow lists for specific words and rules. tooltips now have an escape hatch to suppress a rule for a given highlight without dismissing the whole flag.
added a guardrails module that prevents ai-ism rules from flagging text inside code blocks, quotes, and proper nouns.
added a pre-pass module that builds context for each ai-ism rule — surrounding sentences, word density, paragraph structure — before the rule runs.
extracted all ai pattern definitions into a separate data-only registry. rules and patterns are now separate from the detection engine.
baseline telemetry added to measure current rule performance. the rejection schema extended to track which specific pattern within a rule triggered the flag.
the tooltip diff view was closing immediately if the user moved the mouse even slightly while a rewrite was in progress. now stays open until the rewrite completes.
the auth screen was showing the text wordmark. replaced with the favicon for a cleaner look. the password placeholder text is more welcoming.
both the tooltip and fix-with-ai button had event listener buildup bugs causing double-fires. rebuilt around event delegation with an in-flight guard to prevent concurrent calls.
the landing page got a redesign pass. a mobile audit fixed layout issues at small breakpoints. comment anchor highlighting fixed for anchors that span across dom nodes.
added a new #collaborate section to the landing page showcasing shared documents, inline comments, and team features.
test accounts were cluttering the admin user table. they're now hidden by a pattern filter that matches known test email patterns.
added stderr flushing so otp debug logs appear immediately in railway logs. added a secret-gated debug endpoint to inspect otp state without exposing it publicly.
added an emergency fallback for admin otp in case the primary email send fails. also improved otp email deliverability by fixing the from address and subject line.
a weekly digest email now goes out every monday morning showing each user their voice score trend, top accepted/dismissed suggestions, and one tip.
added an activation banner in the editor for new users who haven't run their first analysis yet. also added a free voice audit tool as a lead magnet.
reverted the admin login to otp-only, locked to a single admin email. the password-based login introduced in the previous change was too risky.
switched admin login to password-based auth. also fixed a race condition in the otp flow where two simultaneous requests could both succeed.
the drama detection rule was flagging any short sentence as dramatic. updated to be pattern-aware based on actual feedback — only flags known drama patterns.
a sweep of 13 fixes from an internal audit. also fixed the final tooltip and comment anchor edge cases.
three low-severity security findings applied: a missing security header, a verbose error message that leaked internal paths, and an overly permissive cors origin.
three bugs introduced by the previous batch of changes caught immediately in internal review and fixed.
document authors can now leave comments on their own documents. analysis tooltips are suppressed when the comments tab is active to avoid z-index conflicts.
comment anchors were disappearing when switching tabs. fixed so they persist. analysis highlights now appear on both the editor and comments tabs.
the 500kb photo upload limit was too tight for typical profile photos. raised to 1mb.
removed a redundant comment navigation button. fixed several comment anchor edge cases. added a count badge to the comments tab.
the email field on the auth screen gave no feedback for invalid email formats. now shows a red outline and error text inline.
the analysis panel and comments panel are now combined into a single tabbed right panel — less screen switching.
the share url was failing to generate because /api/auth/me wasn't returning brand_slug. added to the response.
the share url used to be generated when the popup opened, causing a delay. now generated eagerly in the background so it's ready instantly.
cloudflare was caching js and css and serving stale versions after deploys. the server now injects version tokens into asset urls to force cache busts.
added a comment sidebar to the editor so authors can read comments without switching screens. share url generation is now faster.
js and css assets now have version query strings so cloudflare serves the latest version on each deploy.
visitors reading a public shared document can now leave comments without an account. their name is optional.
public shared document pages were being indexed by search engines, which could expose private content. added noindex/nofollow meta tags.
users who bounced during onboarding without completing it sometimes had no trial record. handle_me now lazily creates one if missing.
the comment sidebar on shared docs couldn't be closed by clicking outside or pressing escape due to a z-index collision. fixed.
when the comment sidebar was closed, it was still reserving flex space, pushing the article off-center. sidebar is now removed from layout when closed.
the shared doc page had a footer cta in addition to the hero card cta. removed the footer one as redundant.
the share popup was sometimes opening in an already-open state. fixed. the voice score hero is now left-aligned with a grey base.
public shared documents now show a voice score hero at the top. added social share buttons for twitter/x, linkedin, and copy-link.
four critical bugs: emails being silently dropped on certain errors, schema migrations not running on cold start, auth response shape breaking a client, and a webhook endpoint bypassing env checks.
the users table in the admin dashboard was showing duplicate rows because a join was producing multiple rows per user. added distinct.
two post buttons in the admin dashboard were missing the csrf header, causing them to fail with 403. fixed.
rewrote 10 email templates with better copy. fixed triggers that weren't firing. added a mobile-specific lead panel and a convert-to-paid action in the admin.
three bugs in the mobile gate: the signup form was visible behind the gate, the submit button never updated to a success state, and the email queue wasn't being processed.
documents being collaboratively edited are now soft-locked — other editors see a notification rather than overwriting each other. public doc pages are live on the domain.
the cta at the end of every blog post was vague. rewritten to explicitly name the two core features: voice profile and ai eliminator.
polished the team management page ui. email sending now retries 3 times on failure and moves to a dead-letter queue on persistent failure.
wired up the full signup attribution system — every signup is now traceable to a specific button, page, or public document via posthog and the users table.
added the attribution and button tracking section to the dev guidelines so every future page and cta follows the same pattern.
added version tokens to all js and css asset urls so cloudflare is forced to serve fresh versions after each deploy.
the voice profile overlay was staying open when the user navigated to a different screen. now closes on route change.
the shared documents list was on the main dashboard. moved to the access page where it fits better alongside sharing and collaboration controls.
six bugs caught in an internal product audit: three ui issues, one data display error, one api edge case, and one broken link.
the cron endpoint was requiring a secret header even when no secret was configured, causing all cron jobs to return 401. the check is now skipped when no secret is set.
the access screen was never rendering because it was missing an initial display:none css rule, so the router couldn't transition it in.
anonymous commenters can now request access to a document. the owner gets an email and can approve or decline. approved commenters get a reply with a signup pitch.
applied fixes from the security audit: session handling, input validation, and access control. also improved the reliability of public link sharing.
a nameerror for `_re` was breaking the static file server, causing all css and js to 404. the regex variable was renamed but not updated everywhere.
app.html's inline css and js were split into separate files for maintainability. teams ui refinements. fixed a bug where comments weren't loading on first open.
added google-docs-style inline comments — highlight text, leave a note, see anchored threads. added an access section to manage who can view and comment.
the onboarding was looping because the profile save wasn't being awaited before checking the completion flag. added await and an explicit completion flag.
major feature release: shareable document links, real-time team collaboration, inline comments, and multi-brand management all shipped together.
the editor got a rich formatting toolbar (bold, italic, heading, list). the right panel is now collapsible. selection-based rewrite was overhauled to handle more selection shapes.
two bugs found in the selection rewrite feature: one where the selection was reset before the rewrite finished, and one where multi-paragraph selections failed.
two critical bugs in selection rewrite: the rewrite was replacing the wrong text range, and the undo history wasn't being preserved.
the selection rewrite tooltip was positioning itself off-screen on short selections. fixed. analysis results are now preloaded into cache so the panel shows instantly.
multi-line selection rewrites were only replacing the first line. fixed. the selection rewrite result is now integrated into the issue card workflow.
added a finance tab to the god view that pulls income and expense data from notion and shows a simple tracker.
api costs are now read from the database instead of being hardcoded. added user deletion in the admin dashboard. the god subdomain is no longer publicly accessible.
added a google search console tab to the admin dashboard showing impressions, clicks, and keyword rankings. the api tab now includes historical usage data.
added an api usage tab to the admin dashboard showing token consumption by model, user, and action. token usage is now tracked per api call.
the manifesto page had mixed-case headings. enforced lowercase throughout. renamed the main heading and updated the cta.
added a /manifesto page laying out the philosophy behind hold your voice — why ai writing needs a human voice anchor.
a pass of pagespeed improvements targeting a 90+ score: image optimization, render-blocking script fixes, and reduced layout shift.
admins can now extend a user's trial from the edit modal. the dropdown fields in the modal are now properly styled.
the admin dashboard wasn't usable on mobile. layout and tables are now responsive.
added an api endpoint for admins to update a user's plan and account status directly from the dashboard.
the email tab in the admin dashboard was a raw list. redesigned with better filters and a more readable layout.
renamed the admin dashboard to 'god of hold your voice' — clearer internal branding for the internal tool.
test accounts were showing up in the admin user table. filtered out based on email patterns.
users now see a feedback popup after creating their third document, asking what they think so far.
rewrote the landing page copy across the trust section, seo section, social reach section, and guidelines section for clarity and conversion.
the feature strip was too dense at mobile widths and breaking the layout. hidden on small screens.
features marked as 'coming soon' now appear as a grey pill badge instead of plain text, making the status clearer.
added memory and mcp as upcoming features to the team and agency pricing cards, marked as coming soon.
the agency pricing card now shows a tooltip explaining what bring-your-own-key means when you hover the byok feature line.
the format selector now defaults to linkedin on first load. the email format option is reordered to appear after the tweet format.
the post count in the sidebar was showing the wrong number. also fixed a hover state on the manage billing link that was triggering unexpectedly.
sensitive data at rest is now encrypted with aes-256. added rate limiting to auth endpoints. standard security headers added (hsts, x-frame-options, csp).
a full sweep of security fixes from a product audit: authentication gaps, missing input validation, insecure defaults, and several smaller findings.
three visual bugs caught in a ui audit: a misaligned element, a colour that didn't match the design system, and a layout break at a specific viewport width.
the hero heading was breaking onto three lines on mobile instead of two, compressing the hero too much. fixed with a max-width tweak.
a mobile layout audit pass fixing overflow issues and spacing. also a copywriting pass across the full landing page.
favicon paths were broken in some environments. footer cta copy updated. the 'from' name in outgoing emails changed to 'hold your voice'.
the url a user signed up from (referrer + page) is now recorded at signup so we can trace which pages and campaigns drive real accounts.
the admin email address was wrong in the config, causing otp emails to go to the wrong inbox.
launched the internal admin dashboard at god.holdyourvoice.com. shows users, documents, usage, and system health.
posthog analytics added to the site. designed a custom 404 page. added initial dev guidelines to the repo.
the favicon was an svg that referenced a google sans web font, which browsers don't load for favicons. replaced with a path-based svg that works everywhere.
the nav logo was too large at 28px. scaled down to 22px so it sits better alongside the nav links.
the final pre-launch bug fix pass. all known issues addressed. ready to go live.
nav links are now grouped closer to the cta button. the 'signal engine' link was removed — not needed in the main nav.
the signal engine section was a plain list. redesigned as a 3×2 card grid with dashboard-style indicators.
four bug fixes: the paragraph-level voice profile wasn't saving, the trial upgrade flow had a broken state, tick colors were inconsistent, and the header nav had a layout issue.
the ai was occasionally returning em dashes despite being told not to. added a stricter prompt instruction and a post-processing step that strips them regardless.
the 'fix everything' button was missing its icon. the 'remove em dashes' button color was changed to purple. button alignment fixed.
analysis results were lost on page refresh, forcing users to re-run. results are now cached in sessionstorage and restored on load.
added a one-click button to strip all em dashes from a document, replacing them with cleaner alternatives using haiku.
the selection rewrite tooltip was using absolute positioning that broke on scroll. changed to fixed. tooltip binding moved to editor init. label is clearer.
openrouter was being used as a fallback for non-anthropic models. removed entirely — the product runs on anthropic only: haiku for speed, sonnet for quality.
when the api returned an error, a raw error message was being shown in a toast that exposed internal details. errors now fail silently with a retry option.
the app was crashing immediately on load because urlparams was declared twice with const in the same scope. removed the duplicate.
the app could get stuck on a loading spinner if the boot request failed silently. added error handling and a 10-second timeout that shows an error state.
a pricing text label was incorrect. the how-it-works section icons now turn black on hover.
the individual plan description text was outdated. updated to reflect the current feature set.
simplified the hero call-to-action label to 'sign up now →', removing the 'it's free' qualifier which felt redundant.
added a 'choose your path' step to onboarding that lets users either import existing writing samples or paste a voice description to skip the sample collection step.
expired accounts now show a graceful degradation screen instead of a hard error. the multiple plan uses a purple accent. ctas are plan-aware.
the multiple plan card was stuck in 'coming soon' state. removed the badge, enabled the checkout button, and linked it to /app.
launched the email automation system: 4 sequences (onboarding, trial nudge, expiry, win-back), 10 templates, and a queue processor that sends on schedule.
replaced the generic og image with a screenshot of the product hero across all pages for better social sharing previews.
the megaphone icon was appearing in the nav and footer alongside the logo. removed — the favicon is the only logo mark used.
the highlighted words in the hero have a taller background rectangle and a thicker underline that sits flush to the bottom of the text.
title tags and meta descriptions across all public pages updated for better search indexing.
updated the logo and favicon to the new design. hero subtitle copy changed. highlight height in the hero animation adjusted.
the hero heading line-height was too tight at the large font size. increased to 1.4 for better readability.
the hero highlight animation now exactly matches the mockup: sweeps left-to-right, loops continuously, and highlights never overlap.
removed the word 'your' from the hero headline for tighter copy. fixed a visual glitch where green and red highlights overlapped. cleaned up button hover states.
all signup buttons were still pointing to the old app subdomain. updated to /app.
the hero underlines were too thin to read at some sizes. thicker strips. fixed line wrapping on mobile.
the hero text highlights now animate left-to-right in sequence, matching the way the product's analysis sweeps through a document.
added robots.txt and a sitemap.xml so google search console can crawl and index the site properly.
added colour highlights to the hero headline — red on 'ai writing' and green on 'exactly like you' to reinforce the contrast visually.
removed the green highlight from 'you' in the hero headline. the headline now wraps to two lines on desktop for better readability.
updated the hero headline to 'make your ai writing sound exactly like you.' — clearer value proposition and more direct.
footer text updated to match the preferred wording.
toasts were unstyled and blocking click events while visible. now properly styled, dismiss after 3 seconds, and have pointer-events:none.
the 'fix everything' button was running out of tokens on longer documents because the batch was capped too low. raised to 2000 tokens per batch.
published 9 seo-targeted blog posts. added a blog listing page. updated the footer. restored blog routes that had been broken.
bring-your-own-key now only supports anthropic api keys (claude). added a 4-step setup guide to make configuration clear.
new users must verify their email with a 6-digit otp code before accessing the app.
updated pricing to reflect that documents (not reviews) are the limit. fixed broken cta links. the multiple plan feature list is complete.
the multiple plan now includes multi-brand voice profiles, bring-your-own-key, team seats, and white-glove onboarding.
the backend now supports multiple voice profiles per account, with separate brand names, keywords, and voice descriptions for each.
the multiple plan is now available for purchase. removed the 'coming soon' label and activated the checkout flow.
google oauth was redirecting to app_url (the old subdomain) instead of base_url. google was rejecting the redirect as unauthorized.
final launch prep: expired account screen, delete account flow, favicon, error toasts, and multiple plan temporarily disabled until ready.
the format checklist was using a text 'x' for failing items. replaced with a styled red × icon.
the analysis cache was restoring in the wrong order on page load, causing highlights to appear out of sequence. also improved the restore logic to handle edge cases.
analysis results now persist when navigating between documents. replaced several icons with cleaner versions. added a sparkle animation to the ai analysis button.
a round of editor ux polish: added an undo icon to rewrites, improved the loading spinner, added press feedback to cards, and copy-to-clipboard confirmation.
the tooltip was getting stuck open and requiring a page refresh. fixed the lock mechanism. also fixed selection-based 'fix with ai' which was using the wrong text range.
the ai rewriter now includes few-shot examples in the prompt for better output quality. format context is passed to guide the style. the merge logic for suggestions is smarter.
analysis now runs in multiple passes using haiku. a fallback chain was added — if haiku fails, it tries gpt-oss-120b via openrouter.
switched the model provider to openrouter to enable benchmarking across multiple models without changing api clients.
the $1 first month is now fully self-managed in the server — no reliance on dodo's trial system. cleaner state management and easier to customize.
added a 'manage billing' button to the sidebar so users can reach the billing portal without going to settings.
documents are now capped at 15,000 words. above this limit, the analysis becomes slow and expensive. users are warned before they hit the limit.
the app moved from app.holdyourvoice.com to holdyourvoice.com/app, eliminating the subdomain and simplifying the routing.
set up routing for both holdyourvoice.com (marketing) and app.holdyourvoice.com (product) on the same server.
a production readiness pass: fixed all broken links, added og tags to every page, and secured session cookies with httponly and secure flags.
the backend is now production-ready: database migrations, session management, email sending, and api routing all solid.
vercel was serving index.html at / instead of routing to the app. switched from rewrites to routes to override the default.
added vercel.json with a route so / correctly serves app.html instead of the default index.html.
added the main app.html and a launcher script to start the development server.
mobile layout audit with several fixes. alignment pass across the full ui. eraser tool resized to match the design.
the eraser tool now has an animation when used. hover effects added throughout. micro-interactions on key buttons.
the favicon wasn't loading. nav links were turning green on hover instead of the accent colour. the team button hover state was wrong.
pricing buttons now have consistent hover colours. the favicon was switched to use the google sans typeface.
a general polish pass across the ui — animations smoothed out, several copy lines tightened.
converted all visible text across the page to lowercase, establishing the brand voice convention from the start.
the yellow highlight animations in the hero mockup now stagger in sequence rather than all appearing at once.
added animations to key hero elements. copy updated across the page. general ui polish pass.
first commit — the hold your voice landing page is live.