0002: One umbrella package with subpath exports
Why runtime adapters ship inside the single permdock package while the CLI and testing helpers are separate scoped packages.
Status
Accepted, September 2026.
Context
PermDock ships a core plus more than thirty adapters (React, React Native, Next.js, Vue, Svelte, Solid, a Fetch server kernel, Hono, Express, Fastify, Elysia, Nest, Node, tRPC, oRPC, MCP, AI SDK, Claude Agent SDK, WebMCP, A2A, AuthZEN, SSF, OpenAPI, OTel, Drizzle, Prisma, Kysely, Supabase, Better Auth, Clerk, Convex, PDP). Two packaging models were compared:
- Scoped packages per adapter (
@permdock/core,@permdock/react,@permdock/next, ...), the CASL and Kilpi model. Independent peer dependencies and version ranges per adapter, but consumers (and agents) must discover which package they need, and version skew between core and adapters is a recurring support burden. - One umbrella package with subpath exports (
permdock,permdock/react,permdock/next, ...), the permix model. One install, one version, and tree-shaking throughexportskeeps unused adapters out of bundles.
The tooling is different in kind. The catalog collector needs a JavaScript parser (oxc-parser); RLS import needs a Postgres parser (pgsql-parser, libpg_query compiled to WASM). Both are heavy, native-or-WASM dependencies that must never be pulled into an application bundle or an edge function.
Decision
- Runtime code ships as one npm package,
permdock, with subpath exports. Core ispermdock; every adapter ispermdock/<framework>. Framework SDKs are optional peer dependencies. @permdock/cliis a separate package that ownscollect,catalog,usage,openapi,rls,doctorandskills, and depends onoxc-parserandpgsql-parser. The Next.js build hookcreatePermDockPluginlives with the CLI code and is exposed aspermdock/next/plugin.@permdock/testingis a separate package for policy matrix tests, snapshot fixtures, the RLS parity runner andinstant()helpers, so Vitest and Playwright dependencies stay out ofpermdock.- Agent Skills (
wire-permdock,audit-permissions) ship insidepermdockunderskills/.
Consequences
- An agent needs exactly one install line (
pnpm add permdock) to wire any adapter; the skill can state import paths without a package lookup. - Core and adapters are always version-aligned; there is no "adapter X requires core Y" matrix.
- Bundle budgets are enforced per entry point in
tests/bundle, because a single package makes accidental cross-imports easy. Client entries are checked for server-only imports bypermdock doctor. - Peer dependency declarations grow with every adapter; all are optional, and
publintandarethetypeswrongrun in CI to keep theexportsmap correct. - The import path names the framework, which is why identifiers never do (see 0005).
Alternatives considered
@permdock/*per adapter. Cleaner peer dependencies and independent release cadence, rejected for install friction, version skew and worse agent ergonomics. Kilpi's separate@kilpi/clientand@kilpi/react-serverpackages are the cautionary example.- Everything in one package, CLI included. Rejected: the parsers would land in every
node_modules, and bundlers would need to be told to ignore them. - CLI as a dev dependency of the umbrella. Rejected for the same reason;
npx @permdock/cliandpnpm add -D @permdock/cliare explicit. - Testing helpers inside
permdock/testing. Rejected because they depend on Vitest and Playwright types, which must not appear in the runtime package.