PermDock
Getting started

Installation

Install the permdock package, pick a Standard Schema validator, and learn which subpath exports exist.

PermDock is in Phase 0. Nothing is published to npm yet; the commands below describe the intended install experience so that the docs, README and skills agree before the first release. See the roadmap for what ships in which phase.

Packages

PackagePurposeRequired
permdockCore plus every adapter as a subpath export (permdock/react, permdock/next, permdock/hono, ...)Yes
@permdock/clipermdock collect, catalog, usage, openapi, rls, doctor, skillsOptional, dev only
@permdock/testingPolicy matrix tests, snapshot fixtures, RLS parity runner, instant() helpersOptional, dev only
pnpm add permdock
pnpm add -D @permdock/cli @permdock/testing

npm and yarn work the same way; the repository itself uses pnpm workspaces.

Requirements

  • TypeScript 5.9, 6 or 7. The type tests in tests/types run against all three, and the public API avoids template-literal unions so TypeScript 7 stays fast. Permissions are typed object references, not string unions.
  • ESM only. There is no CommonJS build. Your tsconfig.json needs a moduleResolution that understands package exports (bundler, node16 or nodenext) so subpath imports such as permdock/react resolve.
  • A current Node.js LTS release for servers and the CLI. Browser and React Native bundles are produced from the same ESM entry points.
  • Zero runtime dependencies in core. @standard-schema/spec is the only regular dependency and it is types only.

Runtimes

Core uses only the WinterTC Minimum Common API (fetch, Request, Response, URL, crypto.subtle, TextEncoder, structuredClone) and no Node built-ins, no AsyncLocalStorage, no module-level state. That is by construction (invariants 7 and 12 in AGENTS.md) and a conformance test in tests/bundle asserts it from Phase 1: every client entry and permdock/server must load in a bare WinterTC-shaped global. The table lists what each runtime adds or lacks; nothing in it changes how a decision is made.

RuntimeCore, permdock/server, agent adaptersNotes
Node.js LTSYesThe CLI and permdock/node need Node; permdock/jwt uses jose's Node build
BunYesElysia's home runtime; bun test runs the policy matrix unchanged
Deno, Deno DeployYesImport from npm specifiers or JSR once published; no Node built-ins to polyfill
Cloudflare WorkersYesmemoryApprovalStore is per isolate: use Durable Objects or KV behind ApprovalStore and SnapshotSource (approvals); D1 has no RLS, where compilers still apply (RLS)
Vercel Functions (Fluid), EdgeYespermdock/next targets the Node runtime for React.cache and 'use cache: private'; the Fetch kernel runs on Edge too
Netlify Functions and EdgeYesSame as Vercel Edge
AWS LambdaYesThrough permdock/node or a Fetch adapter such as Hono's; approvals need an external ApprovalStore
Browsers, React Native (Hermes)Client entries onlypermdock/react, permdock/react-native, permdock/webmcp; no policy code ships (invariant 8)

The one runtime-specific caveat is state: any store or sink that defaults to memory (memoryApprovalStore, memorySink) is per process or per isolate and resets on cold start. permdock doctor warns when the memory store is the configured ApprovalStore in a serverless target. Recipes for Durable Objects, KV, Redis and Postgres stores live on the approvals and audit and observability pages; none is a package.

A Standard Schema validator

Resources are defined from any validator that implements Standard Schema. Bring the one you already use:

pnpm add zod      # or
pnpm add valibot  # or
pnpm add arktype

PermDock never imports a validator itself. resource(Post, ...) reads Post['~standard'] to infer the instance type and to validate untrusted input at trust boundaries (see validation). Boundary validation is synchronous, so a schema whose validate returns a Promise produces a typed PermDockValidationError instead of a silent deny.

Subpath exports

All adapters live in the one permdock package. Import only what a bundle needs; nothing from a server entry is reachable from a client entry.

Import pathContentsPhase
permdockdefinePermissions, resource, mergePermissions, listPermissions, findPermission, definePolicy, role, allow, deny, subject, createPermDock, errors1
permdock/reactPermDockProvider, usePermDock, usePermission, <Protected>1
permdock/nextcreatePermDock returning getPermDock, getPermission, PermDockProvider, permdockHandler1
permdock/next/plugincreatePermDockPlugin (build-time collect hook only)2
@permdock/cli/unplugincreatePermDockUnplugin (the same collect hook for Vite, Rollup, webpack, Rspack and esbuild; TanStack Start, React Router, SvelteKit, Nuxt, Astro, Solid)2
permdock/serverFetch-first kernel shared by the HTTP adapters1
permdock/honocreatePermDock returning permdock middleware and protect1
permdock/express, permdock/fastify, permdock/elysia, permdock/nest, permdock/nodeSame shape as permdock/hono2
permdock/jwtsubjectFromJwt, createJwtSubjectResolver: JWKS verification and claim mapping to a subject (jose optional peer)1
permdock/terminalcreatePermDock returning permdock, protect, filterCommands, format for your own CLI2
permdock/trpc, permdock/orpcRPC middleware with OpenAPI hooks2
permdock/mcpcreatePermDock returning protectServer2
permdock/ai-sdkcreatePermDock returning toolApproval, capabilityMiddleware, needsApproval1
permdock/claude-agentcreatePermDock returning canUseTool, permissionRequestHook1
permdock/evecreatePermDock returning approval, approvalFor, permdock for Eve defineTool1
permdock/openaicreatePermDock returning needsApproval, guardTools, resolveInterruptions, permdock for the OpenAI Agents SDK1
permdock/approvalsApprovalStore interface, memoryApprovalStore, approvalsHandler; the store option of every agent and HTTP adapter1
permdock/cloudcloud({ url, key }) returning approvals, sink, snapshots for PermDock Cloud; optional, server-only, never on the decision path2
permdock/webmcpregisterTools2
permdock/a2acreatePermDock returning agentCard, extendedAgentCard2
permdock/authzencreatePermDock returning the AuthZEN handler1 (endpoint), 2 (full)
permdock/ssfcreatePermDock returning the CAEP receiver3
permdock/openapiOpenAPI 3.2 emission (document or Overlay) and import2
permdock/otelSpan per check and a decision counter2
permdock/react-nativeReact adapter plus persisted storage2
permdock/vue, permdock/svelte, permdock/solidUI adapters2
permdock/drizzle, permdock/prisma, permdock/kyselytoWhere condition compilers3
permdock/supabase, permdock/better-auth, permdock/clerk, permdock/convex, permdock/pdpSubject providers3 and 4

The full matrix with example apps and related standards is on the adapters index.

Optional peers

Core has no runtime dependencies. A few entries verify material or talk to a vendor SDK and declare an optional peer instead of bundling it:

EntryOptional peerWhy
permdock/jwtjoseJWS verification and JWKS fetching; see JWT
permdock/otel@opentelemetry/apiSpan and metric emission
permdock/mcp@modelcontextprotocol/server 2.x (types only)protectServer duck-types the McpServer at runtime; the peer supplies AuthInfo and registerTool option types. SDK 1.x is not supported (MCP adapter, Hosting)
permdock/supabase, permdock/clerk, permdock/better-auth, permdock/convexThe provider SDKSession and claim verification stays with the provider; see authentication
permdock/terminalAn OS keychain bindingToken storage; falls back to a mode-0600 file

TypeScript configuration

A minimal tsconfig.json that works with the subpath exports and keeps inference fast:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "exactOptionalPropertyTypes": true,
    "skipLibCheck": true
  }
}

strict matters: subject narrowing through assert and the actions / collection arity checks rely on strict null checks. The library itself is built with isolatedDeclarations and erasableSyntaxOnly, so its declaration files contain no inferred-only types and load quickly.

Where files go

FileContentsImported by
src/permissions.tsdefinePermissions() or mergePermissions(); no rulesEverything, including client bundles
src/policy.tsdefinePolicy() with rolesServer only
src/permdock/server.tscreatePermDock from a server adapterServer code
src/permissions.generated.tsOutput of permdock rls import or openapi importsrc/permissions.ts
permissions.catalog.jsonOutput of permdock collect; committedCI (--check), docs, OpenAPI

The quick start fills in the first three.

Verify the install

pnpm permdock doctor

doctor checks the TypeScript version, module resolution, that exactly one copy of permdock is installed, that no server entry is imported from a client file, that memoryApprovalStore() is not the store in a serverless deployment that surfaces approvals, that PERMDOCK_CLOUD_* variables (when present) are server-only and reach the API, and that the catalog produced by permdock collect is fresh. It is the first thing the shipped wire-permdock skill runs.

Next steps

  • Quick start: define, grant, check, guard.
  • Larger apps: per-feature definitions, mergePermissions, permdock collect.
  • Naming: why every adapter exports createPermDock.

On this page