Public: anyone can read this; the crew can change it.

Billing is a seam with two providers, none and stripe; with none, every forge is free within its plan #11134

shipped production is serving it opened this has it
opened this

Why. The forge must be ready for a payment processor without relying on one. An operator who gives forges away configures nothing and loses nothing.

What. A new src/billing/ with one interface and the none provider. No SDK, no new dependency.

type Entitlement = { forge: string; plan: string; status: 'active' | 'grace' | 'none'; periodEnd?: number; source: string };
interface Billing {
  name: string; // 'none' | 'stripe'
  checkout(i: { order: string; plan: string; email?: string; returnUrl: string }): Promise<{ url: string } | null>;
  portal(forge: string, returnUrl: string): Promise<{ url: string } | null>;
  webhook(req: Request): Promise<Entitlement[]>; // verifies, dedupes by event id, throws on a bad signature
  reconcile(forge: string): Promise<Entitlement>; // pull; the safety net
}
  • A store of entitlements: forge → plan, status, period end, payer (email or account), provider, the provider's customer and subscription ids. One row per forge; every change is kept in the audit trail.
  • none: checkout and portal answer null; reconcile answers the stored row. An admin grants or changes a forge's plan by hand (PUT /api/v1/forges/{name}/plan, the forges page, and an MCP tool with dryRun). Existing forges get an active row on the plan matching their size, source granted.
  • The provider in use is a setting, shown on an admin Billing settings page; default none.

Acceptance.

  • With no provider set, every flow that exists today behaves the same (a test proves the visitor spawn path is unchanged).
  • An admin grant changes a forge's plan and the change shows in the audit trail.
  • Unit tests cover the store and the none provider. docs/PROFIT.md gains a short Billing section naming the seam.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs