§ Changelog · release notes

What we shipped.

A running record of the platform work that matters to agent builders and cohort users — newest first.

Each release block lists what changed and why. Releases that ship a new SDK version get their own permalink at /changelog/<slug> with version chips linking to the npm or PyPI page; in-page anchors stay reachable as #r-<date>. Every PR with user- or builder-visible impact lands a Fixed / Added / Changed / Security / Infrastructure entry here — enforced by CI.

Updated


  1. Analytics stops following you past the marketing site

    • Changed

      Third-party pageview analytics is gone from the marketing site entirely. No script is loaded on any page, so the "no tracking pixels" commitment on /security now holds without qualification rather than depending on how a tracker is configured. Conversion measurement moves to counters the API already maintains server-side, which are unaffected by ad blockers and never see a visitor's browsing.

    • Security

      Pageview analytics no longer records anything once you sign in. The marketing site loads Umami cookielessly, but Umami's default auto-tracking patches history.pushState for the whole document, and the script outlived the marketing layout — so a client-side navigation into /onboarding or /dashboard kept reporting authenticated page paths, including ones carrying agent and mailbox ids. Auto-tracking is now off and pageviews are reported explicitly, only for routes that resolve through the marketing layout. This closes a gap against the "no tracking pixels" commitment on /security; the dashboard was never meant to be in scope.

    • Fixed

      The analytics service survives being rescheduled. Its startup ran a database preflight that exited immediately rather than retrying, so whenever the app and its database moved to a new node together, the app lost the race and crash-looped instead of waiting — briefly taking analytics.agentdraft.io offline. Startup now waits for the database to accept connections.

    • Infrastructure

      The analytics database is no longer a candidate for routine cluster scale-down, and a PodDisruptionBudget makes a voluntary eviction of its single replica stall visibly instead of silently dropping analytics.

    • Fixed

      Signups that start from a comparison or alternatives page are attributed again. Those pages tag their "free audit" call to action with a src marker, but the audit tool dropped it on the way to sign-in and substituted a fixed marker of its own — so fifteen of the nineteen tagged entry points reported nothing, and the server-side funnel could not tell which page had earned a signup. The tag now travels through to sign-in and survives the magic-link round trip.

    • Security

      The signup funnel's per-source breakdown can no longer be flooded with junk. A marketing call to action tags its link with a src marker that the sign-in endpoint stores as part of a counter's key — but the endpoint is public and accepted any string, so a caller could mint unlimited counter rows and bury the real attribution under noise. Unrecognised markers are now grouped under other, holding a day's breakdown to a fixed size.

  2. Blog ingest accepts updates and deletes, not just creates

    • Added

      PUT /v1/blog/posts/{id} and DELETE /v1/blog/posts/{id} now exist. The ingest API was create-only, so a publisher correcting an already-published post got a 404 — which its own error handling read as "this content was rejected" rather than "there is no route here", flipping a live, correct post to a failed state it could never repair.

    • Fixed

      Both write paths re-materialize the affected static blog page before returning, so a corrected post is visible to readers and crawlers immediately instead of waiting for the next frontend deploy. A delete removes its page rather than leaving it served.

    • Fixed

      Materialized blog pages keep the site masthead, nav, and footer. emitBlogShell() blanked the entire #app subtree when cutting the publish-time shell, and MarketingLayout — which owns <nav> and <footer> — lives inside it, so every page the ingest API wrote went live with only the article: 10 links instead of 52. It stayed invisible while pages were create-only, because the next frontend deploy re-rendered over them; adding PUT made materializer output long-lived and the gap permanent. The shell now cuts at the layout's <main>, so the chrome survives.

    • Fixed

      A materialized post or index page no longer emits a second <main> landmark inside the layout's own — the same one-landmark rule /docs already follows, so "skip to main content" stays unambiguous.

    • Security

      Pinned nanoid to 3.3.17 through an override. The advisory (GHSA-2v37-7h3g-55p8, custom generators can loop indefinitely on a zero size) landed against the version Vite pulls in transitively via PostCSS, which turned the CI dependency audit red on commits that were green when they were cut.

    • Fixed

      Entitlement reads and dunning updates now use centralized DynamoDB key builders, and a failed invoice cannot create a deadline-only row for an org without an entitlements record. A first-invoice decline for such an org is acknowledged rather than erroring, so Stripe no longer retries the event for days.

  3. One redirect path for a stored paid-tier signup

    • Changed

      The pricing page's comparison table, tier bullets, and FAQ prose no longer advertise Calendars / seat, Multi-agent priority, or Audit retention — none had an enforcement call site in app/ — and the table now lists only entitlements the backend actually checks alongside the free tier's 3 agents.

    • Changed

      The pricing page's comparison table also drops the SSO / SCIM and White-label endpoints rows and their matching Enterprise-tier bullets: like the three rows removed above, sso and white_label are declared on the Entitlements dataclass but read nowhere else in app/, so they had no enforcement call site backing the claim either.

    • Changed

      Onboarding now starts Stripe Checkout for a stored paid-tier intent through a single shared helper instead of duplicating the flow per page. A failed checkout call now lands on Billing with a checkout_error message rather than leaving the tab on a blank redirect.

    • Changed

      The Stripe webhook now handles invoice.payment_failed: a failed charge starts a 7-day grace period instead of silently keeping paid entitlements until Stripe eventually cancels, and a subsequent successful payment clears it.

    • Infrastructure

      Added a read-only scripts/stripe_account_audit.sh and inventoried the live webhook endpoint and account branding/business profile ahead of the billing-repair work, so the minimal Stripe-side change set (currently: none) is documented before anything mutates.

    • Changed

      Confirmed the live Stripe webhook endpoint's enabled_events with a real API write, re-asserting checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, and invoice.payment_failed together so dunning-relevant event coverage is documented and verified rather than assumed.

    • Fixed

      Dry-ran the exact webhook enabled_events, Files API logo/icon upload, and business_profile/settings.branding mutation calls against a non-production Stripe account before touching live, catching that standalone-account branding self-updates are API-rejected and must go through the Dashboard instead.

    • Infrastructure

      Live Checkout branding's settings.branding.icon/.logo still point at a stray google-oauth-logo.png file instead of an AgentDraft mark, and business_profile.name/product_description are wrong/unset — not yet fixed for customers — after uploading a correct apple-touch-icon.png as new, unattached business_icon/business_logo files and confirming Stripe blanket-rejects (403) self-service account writes on this standalone account, so attaching them needs a human via Dashboard using the values recorded in docs/stripe-account-audit.md.

    • Fixed

      The Billing page now shows an explicit Developer plan card ($0 / forever) and a 7 days — developer audit-retention footer instead of silently falling through to the Enterprise arm's $5k–$20k / year copy for free-tier accounts.

    • Changed

      Free-tier accounts on the Billing page now get working Upgrade to Individual and Upgrade to Team buttons that start Stripe Checkout directly, replacing the disabled On enterprise button every Developer-tier user used to see as their only upgrade affordance.

    • Changed

      The Billing page now reads the checkout_error message left by the onboarding fallback redirect and shows it in a visible banner above the upgrade buttons instead of silently dropping it, clearing the parameter from the URL afterward so a refresh doesn't re-raise it.

    • Changed

      Locked in regression coverage for Enterprise checkout being unreachable by construction: billingApi.checkout's tier parameter accepts only individual and team (an enterprise call fails vue-tsc --noEmit), and the /pricing page's Enterprise CTA is now tested to open the mailto:sales@agentdraft.io contact-sales flow and issue no request to the checkout endpoint.

    • Fixed

      Removed the marketing masthead's r/indiehackers giveaway banner (a year of Team free), which was undercutting the price this billing work exists to charge. The bulletin strip's status/edition/build-date meta still renders.

    • Changed

      Finishing the onboarding template step with a stored paid-tier intent now drops the visitor straight into Stripe Checkout for that tier instead of routing them to Billing to click upgrade again; with no stored intent, onboarding still finishes on the Rules page.

    • Changed

      An already-onboarded user who verifies with a stored paid-tier intent now lands straight in Stripe Checkout for that tier instead of Billing; users still mid-onboarding, or with no stored intent, keep their existing destination.

    • Changed

      The dashboard usage endpoint now returns a nullable dunning_grace_until field with the org's stamped card-failure grace deadline, so the Billing page will be able to warn a user before their paid tier lapses.

    • Changed

      The Billing page now shows a Payment failed — update your card within N days warning while dunning_grace_until is set and still in the future, so a lapsed card's grace window is visible before the downgrade happens instead of after.

    • Fixed

      Free Developer-tier accounts can now open Stripe Checkout to upgrade, and the Billing page no longer reports Enterprise pricing when a free-tier account loads it.

    • Changed

      The /pricing comparison table no longer lists Calendars / seat, Multi-agent priority, or Audit retention — none had a backing entitlement check — and the free Developer tier is now stated as 3 agents instead of 1.

  4. Free tier now representable in the billing client

    • Fixed

      The frontend Tier type now includes developer, matching the tier every new org actually resolves to on the backend — billing UI can represent the free tier instead of only paid ones.

    • Changed

      The Developer tier's pricing-page copy now states 3 agents instead of 1, so a free workspace can actually try multi-agent priority resolution rather than being capped before it can use it.

  5. Free tier can now run multiple agents

    • Fixed

      The free Developer tier's agent cap is now 3, not 1 — a free workspace can actually run more than one agent, which is what multi-agent priority means.

  6. Retired marketing URLs now resolve cleanly

    • Fixed

      Old calendar, agent-mailbox, and framework-guide URLs now permanently redirect to their current canonical pages instead of serving the noindex 404 shell.

    • Added

      A public /contact page now routes product, billing, enterprise, security, press, and partnership questions to the right channel.

    • Fixed

      Documentation and glossary links with a #section now scroll to the requested section instead of always returning to the top of the page.

  7. Approvals — a human sign-off gate for any agent action

    • Added

      Workspaces can have more than one person in them. A new Team page invites teammates by email; they accept, land in your workspace, and share its plan, billing and calendars. Team includes five seats, Enterprise unlimited — the seats number on the pricing page previously bound nothing, because there was no way to add a second person at all.

    • Changed

      Seats are capped per tier. A pending invite holds its seat until it's accepted, revoked, or expires after 72 hours, and inviting past the cap returns 402 quota_exceeded. An address that already has its own AgentDraft workspace can't join another one.

    • Security

      Billing (checkout, portal, plan changes) and the webhook signing secret are now owner-only. Everything else in a workspace stays shared, which is what a seat is for — but a credential that signs every delivery, and the payment method, are not.

    • Changed

      The per-tier mailbox count is now enforced, not just advertised. An agent receives mail only while it holds one of your plan's inboxes — Developer and Individual include one, Team five, Enterprise unlimited — so Individual's three agents share a single mailbox rather than quietly getting three. Agents past the allowance are created normally and still book, hold and audit; they have no address until a slot frees up.

    • Added

      POST and DELETE /v1/dashboard/agents/{id}/mailbox move an inbox between agents, so a finite pool of mailboxes is usable across a larger pool of agents. Enabling one past the cap returns 402 quota_exceeded, and GET /v1/dashboard/billing/usage now reports mailbox consumption.

    • Changed

      mailbox_address is now nullable on the agent APIs and GET /v1/mailbox/me reports inbound_enabled, so an SDK can tell that an agent has no inbox instead of caching an address that silently drops mail. Agents created before this change keep their inbox.

    • Fixed

      Corrected calendar-provider claims across the site. Several pages said AgentDraft connects to Microsoft 365, Apple iCloud, Fastmail and generic CalDAV; those are waitlist-only, exactly as the dashboard's connect screen has always shown. Google Calendar, Folio and read-only ICS are what ship today, and the rest are now described as roadmap.

    • Fixed

      The Team tier no longer advertises "private beta · no card required". Starting Team opens a live Stripe subscription checkout at $25/month, and always has.

    • Fixed

      The pricing FAQ said Enterprise "adds" SSO, SCIM, white-label endpoints, a dedicated email IP and a custom-domain mailbox. None of those are built; the comparison table on the same page already called them pilot-scoped, and the FAQ now agrees with it.

    • Fixed

      The public collision benchmark now publishes a real measured run instead of a hand-authored reference fixture. Its correctness metric also no longer counts priority bumping as a double-booking — a legitimate bump chain produces several 201s in one round, which scored a healthy engine at 22% accuracy. Latency figures are now labelled with the stack they were measured on.

    • Fixed

      The blog publish guard matched blocked phrases as bare substrings, so SSO fired inside subprocessor and a truthful DPA post was rejected with a 422. Phrases now match on word boundaries.

    • Added

      Agents can pause for a human on any consequential action with POST /v1/approvals — a deploy, a payment, an outbound email — attaching an evidence payload and polling GET /v1/approvals/{id} for the decision. Requires the new approvals:request scope, which is off by default on new keys.

    • Added

      New Approvals queue in the dashboard: action-type badge, the agent's evidence pretty-printed and collapsible, an expiry countdown, and an optional note that reaches both the agent and the audit log on approve or deny.

    • Added

      Four subscribable webhook events — approval.requested, approval.approved, approval.denied, approval.expired. Payloads carry the decision, never the evidence blob.

    • Added

      client.approvals.request(), .get(), and .wait() in both the Python and TypeScript SDKs; wait() returns on any terminal status and follows the request's own expiry so it can't hang forever.

    • Added

      Email notification when an agent is waiting on you, throttled to one message per five minutes with the pending count, and switchable off under Settings → Notifications.

    • Added

      Approvals now explains itself. The queue carries a collapsible "How approvals work" panel — how to grant approvals:request, what an agent sends, what your note does, and why an expiry counts as a no — and the docs gain a full § 06 Approvals section with runnable Python, TypeScript and cURL examples, a status table, and the field limits.

    • Fixed

      Approval requests carrying a long unbroken value — a URL, an object key, a token — no longer stretch the approvals queue sideways; long summaries and evidence now wrap in place, on phones included.

    • Fixed

      The approval note field now shows a focus ring when tabbed to, and the Settings notification link is underlined rather than distinguished by colour alone.

    • Changed

      Approvals is now the fourth leg of the product description — inbox + calendar + approvals + audit — across the site metadata, the A2A agent card, the ChatGPT app manifest, and the public capability contract at /.well-known/product-capabilities.json, which gains a human_approvals entry plus guardrails marking Slack/email approve-from-chat and approval policy engines as not-yet-shipped.

    • Changed

      A malformed blog-publish payload now returns 400 invalid_payload instead of 422. On the publish routes 422 is reserved for capability-claim rejections, so publishing clients can tell a broken request from a blocked claim.

    • Fixed

      The capability-claim guard now recognises is/are as asserting a claim, and matches a phrase through the ways HTML mangles it — a line break, a &nbsp;, an inline <em>. Copy like "AgentDraft is open source" is caught rather than published, while comparison copy that names a competitor's feature and denies it of AgentDraft still publishes.

  8. Cookieless marketing analytics goes live

    • Infrastructure

      Deployed the self-hosted Umami instance behind analytics.agentdraft.io — cookieless, no cross-site identifiers, marketing pages only; the dashboard stays untracked.

  9. Answer-engine polish and a shorter path to an API key

    • Added

      Glossary entries for agentic email, mailbox quota, and human-in-the-loop gate, cross-linked into the email guides.

    • Added

      Blog posts rendered by the publish pipeline now declare speakable JSON-LD and can include structured comparison tables.

    • Changed

      The glossary, comparison pages, and email-flow monitoring guide now state free-tier pricing up front with direct sign-up CTAs.

    • Fixed

      Replaced dead citation links in three blog posts with verified primary sources.

    • Fixed

      Corrected a blog post that rendered unconverted markdown emphasis as literal asterisks.

    • Fixed

      The Nylas comparison page no longer mixes two different Nylas pricing tiers when arguing AgentDraft is cheaper.

  10. The blog claim guard checks claims, not keywords

    • Fixed

      The capability-claim guard no longer rejects a post just for containing a word like self-hosted, SOC 2, or SAML. It now checks whether the sentence *asserts* the capability of AgentDraft: truthful disclaimers ("AgentDraft is not self-hosted", "SSO is on the roadmap, not available today", "we do not hold SOC 2") publish, while over-claims are still blocked. Previously the exact wording the guard itself recommended could be rejected.

    • Changed

      The guard's paraphrase lexicon was widened so over-claims that dodge the original keywords are still caught (e.g. "run AgentDraft on your own servers", "Okta/Azure AD single sign-on", "Outlook sync"), and the public /.well-known/product-capabilities.json contract reflects the expanded terms.

    • Added

      The guard now rejects the false claim that AgentDraft ships load-testing or throughput stress-testing tools for your architecture (it publishes only a conflict-engine correctness benchmark). Phrases like "benchmarking tools to stress-test your architecture" and "simulate high-volume traffic" are blocked, while posts about the real public benchmark still publish.

    • Fixed

      The blog publish guard now allows glossary-style SEO mentions like SAML, SOC 2, or Outlook when the sentence does not claim AgentDraft supports, holds, or ships that capability.

    • Changed

      The public docs now spell out the AgentDraft mailbox inbound size limit: messages over 40 MB are rejected at SMTP with 552 5.2.3, so monitors should send summaries plus artifact links instead of retrying oversized MIME bodies.

  11. No more dead citation links on the blog

    • Fixed

      The blog publishing integration now strips ephemeral Vertex grounding-api-redirect citation links at ingest. These AI-generated source links expire within days and were surfacing as broken outbound links on published posts; they're now removed automatically, so re-publishing a post self-heals any dead citation.

    • Fixed

      The blog capability-claim guard now only flags a blocked term (open source, SOC 2, ISO 27001, etc.) when the same sentence names AgentDraft. Educational posts discussing third-party open-source frameworks or telling readers to vet a vendor's certifications are no longer wrongly rejected, while genuine false claims about AgentDraft are still blocked.

  12. Every published blog post is back in the sitemap

    • Fixed

      The sitemap now lists all published blog posts. The build-time query stopped at DynamoDB's 1 MB page limit and silently dropped the oldest posts; it now paginates to exhaustion so search engines can discover every article.

    • Added

      The email-flow monitoring page now links to Nightlamp, the first-party deployment that runs its email-dependent checks on AgentDraft mailboxes.

    • Changed

      The blog publishing integration now rejects posts that assert capabilities AgentDraft doesn't ship (open source, self-hosting, SSO, Microsoft 365 sync, compliance certifications) with a structured 422, and the public /.well-known/product-capabilities.json contract lists those blocked claims so external SEO tooling stops generating them.

  13. Answer-engine remediation pass

    • Fixed

      Blog, legal, and alternatives pages now expose clearer short-answer blocks, question-led sections, and FAQ schema for answer engines.

  14. DNSCove authoritative DNS cutover

    • Infrastructure

      Production DNS and cert-manager DNS-01 automation now target DNSCove while AWS Certificate Manager continues to issue CloudFront certificates.

Older releases

  1. Blog ingest API returns the real post URL
  2. Free calendar collision audit, right from the comparison pages
  3. Try the API with no signup
  4. Instant API key, plus a code fallback for magic links
  5. A faster path from CTA to API key
  6. Alternatives guides, glossary expansion, and benchmark census
  7. Trust pages, SEO metadata, and production API tuning
  8. Billing correctness and an open-source collision benchmark
  9. A guided setup checklist and a clearer, more accessible dashboard
  10. Send feedback from the dashboard, plus blog & security SEO fixes
  11. Checkout now collects tax and accepts promo codes
  12. Calendar list no longer breaks after disconnecting a feed
  13. Webmail calendar connector is now Folio
  14. Calendar connect surfaces real errors; local dev boots again
  15. Billing webhook resolves the correct plan
  16. Private app routes are easier for crawlers to retire
  17. Google user data disclosures
  18. Launch-readiness proof is easier to audit
  19. Dashboard sessions last through the workday
  20. Publish and webhook setup feedback is clearer
  21. Mailbox webhooks can target one agent
  22. Email-flow monitoring with AgentDraft mailboxes
  23. Block out your vacations
  24. Counter-proposals documented, plus API reference fixes
  25. Webhooks are now documented
  26. Booking notes and the video link now land on the calendar event
  27. The timezone picker is now searchable
  28. Set your timezone — the one that actually gates bookings
  29. SDKs speak title, invitee, and timezone
  30. Scheduling rules are actually enforced
  31. Working hours read in your own timezone
  32. Pricing answers its own questions
  33. Bookings know who they're for
  34. One canonical URL per marketing page
  35. Connected calendars resync themselves
  36. The glossary doubles in size
  37. Integration pages for n8n and the OpenAI Agents SDK
  38. A sharper share card and a more legible masthead
  39. The free Developer tier reaches the homepage
  40. A free Developer tier, a mobile nav, and a clearer homepage
  41. Blog posts published via the ingestion API render cleanly
  42. Recurring ICS events with a non-UTC UNTIL now expand fully
  43. Permanently delete revoked agents
  44. Lowercase-safe agent mailbox routing
  45. Mid-run human consent for high-impact agent actions
  46. Marketing claim audit and pricing copy alignment
  47. Conferencing links, Calendar Audit, ChatGPT App, coordination-layer pillar
  48. Dashboard Webhooks page
  49. P1 differentiation moat — multi-agent negotiation + OSS engine reference
  50. P0 distribution oxygen — A2A protocol, two more /vs pages, Vercel AI + Mastra adapters, Claude skill
  51. Footer composition + Field notes in masthead nav
  52. Launch wave 1 — collision benchmark, vs/temporal-cortex, newsletter capture
  53. SEO landing pages + outbound mail fix
  54. Launch-week polish
  55. Passkeys
  56. A real changelog
  57. Launch readiness — SDKs, packages, and discovery
  58. Calendar connectors, agent key lifecycle, mailbox API
  59. Agent mailboxes, onboarding, dashboard hardening
  60. Production architecture and deploy pipeline
  61. Initial AgentDraft platform

Frequently asked

What gets a changelog entry?

Anything users or agent builders can observe — new endpoints, breaking changes, dashboard UX, fixed bugs, security patches, infrastructure work that touches the public plane. Internal-only refactors and tests opt out with the skip-changelog label. CI fails any other PR that doesn't touch this changelog file.

How do per-release permalinks work?

Releases that ship a new SDK version get a dedicated /changelog/<slug> permalink with a short summary, version chips, and SoftwareApplication JSON-LD. In-page anchors stay reachable at #r-<date> for releases without a permalink — if multiple un-slugged releases share a date, the second and later get a numeric suffix.