Skip to content

Hosted page: plans, pricing, and the founding ladder - #996

Merged
nedtwigg merged 20 commits into
mainfrom
pricing-page-fable
Oct 8, 2026
Merged

nedtwigg merged 20 commits into
mainfrom
pricing-page-fable

Conversation

@nedtwigg

@nedtwigg nedtwigg commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Turns /hosted from a "coming soon" preview into the page that sells Dormouse Hosted, on a new design-stage spec, docs/specs/pricing.md.

The page

  • Plan cards first: Free / Hosted / Founding, directly under the title (#pricing). Hosted has a Monthly / Yearly toggle ($10 / $100); Founding is $50/yr, struck against $100, rising $10 per closed cohort of 100.
  • One owner for every price: website/src/lib/hosted-pricing.ts. The page, the Product / Offer JSON-LD (still PreOrder), and the tests all read it.
  • Founding's live half: website/src/lib/hosted-cohorts.ts fetches seats left and the opted-in founders row from /api/hosted/cohorts after hydration. The endpoint isn't deployed yet, so the card renders without it. Avatars must be same-origin paths, otherwise the client draws an initial.
  • Buy buttons open an unbuilt-checkout notice. Nothing is charged and no seat is taken. Hosted billing: checkout, subscription entitlement, founding cohorts #1001 adds CHECKOUT_OPEN to switch them to real checkout.
  • Then come what a member gets, "Self-hosting stays free", and a short FAQ: refunds, the founding lock, the founders row, what happens if Hosted shuts down, and team pricing by email.

Around the site

  • Pre-launch strip: Home and every reference page carry a yellow "Pre-launch — word of mouth only, please." bar, sized inside SiteHeader's fixed height so no offset moves. The playgrounds leave it off. Remove it, and the prelaunch props, at launch.
  • /pricing 301-redirects to /hosted/, pinned by checkPricingRedirect in scripts/public-docs-lint.mjs.
  • "Coming soon" copy is gone from Home, the Pocket playground, the root README, vscode-ext/README.md, the hosting notice, and the Settings voice link.
  • docs/specs/website-docs.md -> /hosted now defers content to pricing.md.

Not in this PR

The spec's decisions are recorded here: the account's subscription is the entitlement, with no licence and no trial. The rest of pricing.md -> Future (Scope: hosted-sales) is built by the stack on top of this PR: #999 sign-in and member voice, #1000 VS Code voice, #998 the toggle upsell, #1001 billing and cohorts, #1002 metrics, #1003 walkthrough fixes. #997 updates Privacy and Terms.

Test plan

  • lint:specs, lint:md, lint:public-docs
  • website 346/346, typecheck
  • Banner checked in a browser on Home and /hosted, desktop and phone width
  • Root pnpm test in CI
  • Look over the page in a browser, light and dark, at phone width

🤖 Generated with Claude Code

nedtwigg and others added 16 commits September 9, 2026 15:11
Design-stage spec under a hosted-launch scope: the tiers and founding
ladder, what the Individual plan grants, the licence the clients verify,
the managed-voice boundary, and the /hosted page contract. Indexed in
AGENTS.md with a word budget.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qu9YLVgpJyz63KKtzJMedL
/hosted stops being a launch teaser and becomes the page that sells the one
paid service: the tier table, what the Individual plan grants today and later,
self-hosting stays free, and a five-question FAQ. /pricing 301-redirects to it
rather than becoming a second page with its own, staler numbers.

Checkout is stage 2, so a buy button opens a notice that says so — it names the
tier, says nothing was charged and no seat taken, and carries the devlog form
that used to be a page section of its own. The page repeats above the table
that checkout is not open, and the JSON-LD offers are PreOrder, so nothing here
claims you can buy today.

hosted-pricing.ts is the one owner of every price on the site; the page, the
structured data, and the tests read it rather than restating a number. Seat
counts come from a server endpoint that is not deployed yet, and every failure
renders the table without counts — which is the same path an outage takes.

Promotes "The Hosted page" above the fold in the pricing spec, splitting the
published ladder from the commerce rules that still need checkout, and pins the
redirect with checkPricingRedirect.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfXoRS8HDVR4DbZ9yBZx9m
A table asked a buyer to read across three columns to compare three plans. The
cards read the way a pricing page is read: cheapest commitment on the left,
largest on the right, side by side from `md` up and stacked in that same order
on a phone. The recommended tier is the middle one, marked by the accent border
and the badge rather than a surface of its own — that would be a tint no docs
token is derived against.

Card-internal alignment is deliberate. Empty reserves keep the three names,
blurbs and seat lines on shared baselines, but only while the cards are a row;
stacked, a reserve is just a gap. `mt-auto` lines the buttons up however tall
the cards run, and the button says "Buy" alone because "Buy Founding permanent"
wrapped to two lines and broke that line — the tier name stays on the aria-label
a screen reader reads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfXoRS8HDVR4DbZ9yBZx9m
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both grants — the managed Relay and ElevenLabs voices — are described as
included today across the Hosted page, the hosting notice, Home, Pocket,
the READMEs, and the Settings voice line. Founding annual now closes only
when the ladder reaches list. Checkout still opens the TODO notice, and the
notice keeps the pending independent review security-remote.md requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Repoint pricing.md from the retired saas-multitenant scope to hosted.md,
which now owns the Hosted Relay's accounts, enrollment, and entitlement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Free states what never costs anything; Hosted toggles monthly (default)
and yearly at list; Founding is the annual ladder alone, with the seats
left and a row of founders who opted in at checkout, avatars only from
this origin. The founding-permanent tier is dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e whole fleet

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…unding perk line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Free leads with nothing held back and zero network requests; Hosted lists
the buzz-and-answer loop and a voice per pane; Founding sells the lock.
The note under the cards no longer names the next ladder step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed Pocket and self-host

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s Free and Hosted, two Founding

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nroll with a Relay, ElevenLabs speech synthesis

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tar; team plans by email

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Relay boundary box and the 'What it costs' heading repeated what the
Free card now says and pushed the prices below the fold. The hosted
qualifier (metadata, the pending independent review, the trust model)
moves into the managed Relay section; #pricing stays an anchor for the
JSON-LD offers. /self-host keeps the box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/specs/website-docs.md
#	scripts/spec-word-budgets.json
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 773926b
Status: ✅  Deploy successful!
Preview URL: https://5c4c206a.mouseterm.pages.dev
Branch Preview URL: https://pricing-page-fable.mouseterm.pages.dev

View logs

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The page now presents unbuilt behavior as available today. docs/specs/hosted.md -> "Managed voice" says managed voice is "An admin-only test slice", and isAdmin is also the Hosted Relay's entitlement (NOT_ENTITLED_ERROR for anyone else). No checkout or licence exists yet to grant either. Despite that, the diff says:

  • Hosted.tsx labels both sections "Included with any plan".
  • The voice section promises voices "chosen per pane from a curated set", an in-app disclosure "before the first request", clips "cached on your machine", and a "daily fair-use cap". pricing.md lists all four under Future (Managed voice), and none exists in lib/src/lib/managed-voice-engine.ts.
  • vscode-ext/README.md now says "The released extension connects through Dormouse Hosted". A non-admin user who installs it can't enroll a Burrow.
  • Home and the Pocket playground drop "in development" for Pocket. docs/specs/website-docs.md requires that "Pocket is described only as shipped or explicitly in development". For anyone without the admin account, Pocket over Hosted is neither.

The root is pricing.md's "Must describe both grants as live, never upcoming." That rule sits above the fold but states a commitment the code doesn't keep, so it conflicts with the spec lifecycle in AGENTS.md. The JSON-LD stays PreOrder and the buy buttons are honest, but the surrounding prose isn't. One fix is to keep the prices and cards and describe what the plan will grant until checkout ships. That would leave the voice-section specifics under Future.

fetchCohort requests an endpoint that nothing serves, on every visit. /api/hosted/cohorts is a path on the static Pages site. website/ has no Functions, and Hosted's Workers sit on subdomains, so the request fails on every page load and its result is always discarded. Avatars are expected as same-origin paths, which assumes dormouse.sh will proxy them, but no host for that is decided yet. Until Future item 1 picks the host, hosted-cohorts.ts, the sameOriginPath guard, and FoundersRow defend against responses that can't happen. They might also pin the wrong origin. Dropping them, and keeping the seats line out of the card until the endpoint exists, would shrink this PR without changing what a reader sees.

…o trial

Ned, 2026-10-03: a desktop signs in by device code and the server checks
the subscription on every voice and Relay request. The 30-day refund is the
trial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switch from a licence to the account's subscription missed three places that still describe the old model. The two in this diff take the suggestions below. The third is outside the diff: docs/specs/hosted.md -> Future item 3 still reads "a real entitlement or licence replacing ADMIN_EMAIL". pricing.md now rules out a licence ("No licence, no offline verification"), so that item should name the subscription instead.

Comment thread docs/specs/pricing.md Outdated
Comment thread website/src/pages/Hosted.tsx Outdated
nedtwigg and others added 3 commits October 7, 2026 16:54
# Conflicts:
#	docs/specs/website-docs.md
#	scripts/spec-word-budgets.json
#	website/src/lib/docs-rail.test.tsx
"Pre-launch — word of mouth only, please." sits inside SiteHeader's fixed
height, so every offset keyed to it stays right. The playgrounds leave it
off. Delete it, and the `prelaunch` props, at launch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A desktop signs in by device code, so nothing is activated. One voice per
Pane is still Future, so the page and the plan table promise a member
default from a curated set. hosted.md's Future item names the subscription,
not a licence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nedtwigg

nedtwigg commented Oct 7, 2026

Copy link
Copy Markdown
Member Author

Replying to the first draft review: this PR is the first of a stack that builds everything it describes, and the stack is rolling out now, so the page presents the plan as live on purpose.

Until those deploy, the site carries a "Pre-launch — word of mouth only, please." strip, and the buy buttons still open the "Checkout is not wired up yet" notice (CHECKOUT_OPEN is false, JSON-LD PreOrder).

I did take one valid point: one voice per Pane is still Future in the whole stack, so the page and the plan table no longer promise it. The hosted.md Future item from the second review now names the subscription instead of a licence.

@dormouse-bot

Copy link
Copy Markdown
Collaborator

That resolves both reviews for me. The stack (#999–#1001) covers what the page presents as live, and the pre-launch strip plus CHECKOUT_OPEN/PreOrder cover the gap until it deploys. With #1001 serving /api/hosted/cohorts through a Workers route, the cohort fetch now has a real target. I checked the follow-ups at 773926b: hosted.md Future item 3 names the subscription, and the page no longer makes the per-Pane voice claim.

@nedtwigg
nedtwigg marked this pull request as ready for review October 8, 2026 00:17
@nedtwigg
nedtwigg merged commit 7dcc3b7 into main Oct 8, 2026
14 checks passed
@nedtwigg
nedtwigg deleted the pricing-page-fable branch October 8, 2026 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants