feat(engine)!: replace plan entitlements with host admission hooks

Merged
WI
3d ago
+694-1236

The engine has no plans, usage quotas or billing. Admission and metering are host concerns, exposed through AdmissionHooks; self-host passes none and every workspace is admitted.

Admission hooks

EngineDeps.admission (also createNodeRuntime({ admission }) and startServer({ admission })):

interface AdmissionHooks {
  admit?(ctx: { workspace; action: 'request' | 'message' }): Promise<AdmissionDenial | null | undefined>;
  committed?(ctx): Promise<void>;                       // 2xx, never an idempotent replay
  rateLimitPerMinute?(workspace): Promise<number>;      // per-workspace ceiling override
}
interface AdmissionDenial { status; code; message; details?; retryAt? }
  • request is checked in rateLimit after the per-minute bucket, so throttled requests never reach the host. message is checked on channel posts, DMs, group DMs and thread replies.
  • A denial renders as { ok: false, error: { code, message, ...details } } with its status. Retry-After/X-RateLimit-Reset are set only when retryAt is given.
  • A denied message send that has an Idempotency-Key still replays its stored receipt. Only a fresh send is refused, and that refusal leaves no idempotency lock behind.
  • committed runs through runInBackground (waitUntil on Workers).
  • A hook that throws admits the request. A failing rateLimitPerMinute falls back to EngineConfig.rateLimitPerMinute (default 30,000).

Plans out of the engine

  • EntitlementsProvider, StaticEntitlementsProvider, PLAN_LIMITS, the plan-limit and message-allowance middleware, usageTracker, and the usage:* KV counter helpers no longer exist.
  • Migration 0077_drop_workspace_plan.sql drops workspaces.plan. Workspace.plan is no longer in the API, OpenAPI, @relaycast/types, or the Rust and Swift SDK models.
  • WorkspaceDeliveryPolicyConfig.resolve receives { id }.
  • Self-hosted workspaces are never quota-limited, so #432 (self-host workspaces hitting free quotas through the schema default) cannot occur.

Release and downstream

Major bump for engine/types/Swift (a public field, an error code and exports are removed); the Rust SDK change goes into its pending 10.0.0. relaycast-cloud must move its tier table (PLAN_LIMITS, the workspace-plan: override, trial allowance, api-call metering, upgrade guidance) behind AdmissionHooks. It must also copy workspaces.plan into its own storage before applying engine migration 0077; its fleet/routes.ts writes that column directly today.

Supersedes #484. Fixes #432.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Agent Relay sessions

  • claude session 661e56aa · opened via gh pr create · last active 2026-10-27