OpenAPI ecosystem, September 2026
How PermDock's Overlay and standard security output fit the TypeScript OpenAPI toolchain (next-openapi-gen, hono-openapi, TypeSpec, Hey API, Orval, Kubb, Redocly, Bump.sh, Scalar, Mintlify, Fern, Speakeasy, Schemathesis, Arazzo runners, OpenAPI-to-MCP bridges), which tools are producers, appliers or consumers, and what PermDock adopts, adapts and avoids.
Source: a review run in September 2026 of the tools a TypeScript team already has in its OpenAPI pipeline, asking what PermDock must emit so each of them works without knowing PermDock exists, and where a recipe is enough versus where an adapter would be needed. Sources were the tools' documentation and repositories linked below. The review produced ADR 0023 and the recipes on the OpenAPI adapter, Next.js adapter, MCP adapter, CLI: openapi and Overlay pages.
The pipeline
Every TypeScript OpenAPI setup, whatever the framework, reduces to the same four stages. PermDock occupies one of them.
- Producer. Something turns route handlers into an OpenAPI description: a framework plugin (
hono-openapi,@hono/zod-openapi,@orpc/openapi,trpc-to-openapi,@elysia/openapi,@fastify/swagger,@nestjs/swagger) or a scanner that reads route files (next-openapi-gen). Producers own paths, parameters, schemas andoperationIds. - PermDock.
permdock openapi emit --format overlayreads the catalog and the description and writes an Overlay that addssecuritySchemes, per-operationsecurityandx-permdock-*. Where PermDock has an in-process hook (Hono, oRPC, tRPC, Elysia, Fastify, Nest) the same fields are attached during generation and the Overlay is optional. - Applier. An Overlay 1.x applier merges the Overlay into the description. PermDock does not ship one (0019); the project's existing tool does it.
- Consumers. Docs UIs, SDK generators, OpenAPI-to-MCP bridges, Arazzo runners, gateways and
permdock openapi importread the applied description. They see standardsecurity; the ones that opt in also readx-permdock-*.
The join key across all four stages is operationId. Producers generate it, the Overlay targets it, Arazzo steps reference it, and --check fails when it is missing.
Producers
| Tool | Frameworks | Security input | PermDock path | Notes |
|---|---|---|---|---|
| next-openapi-gen | Next.js, TanStack Start, React Router, Remix, SvelteKit, Nuxt, Astro, Hono, Express | JSDoc @auth, authPresets; overlay.apply | Overlay | Scans route files; targets 3.0 to 3.2; scaffolds Scalar; compiles Arazzo. The Next.js recipe |
| hono-openapi | Hono | describeRoute({ security }) | In-process describe() | Already a hook on the Hono adapter |
| @hono/zod-openapi | Hono | createRoute({ security }) | In-process security() | Same |
| @orpc/openapi | oRPC | oo.spec() | In-process spec() | oRPC adapter |
| trpc-to-openapi | tRPC | meta.openapi.protect: true | In-process describe(), Overlay for per-scope | Boolean protect only; the Overlay adds the scopes (tRPC adapter) |
| @elysia/openapi | Elysia | detail.security | In-process | Scalar is the default UI (Elysia adapter) |
| @fastify/swagger, @nestjs/swagger | Fastify, Nest | Schema security, decorators | In-process | Fastify, Nest |
| Hand-written YAML or JSON | Any | Author writes security | Overlay | Design-first teams; the Overlay keeps PermDock's contribution separate |
| TypeSpec 1.0 | Design-first, any framework | @useAuth decorators compiled by @typespec/openapi3 | Overlay on the emitted document | 1.0 GA; emits OpenAPI 3.0, 3.1 and 3.2; an MCP server emitter is being explored upstream. The Overlay is applied to the emitter output, never to the .tsp source, so TypeSpec stays the single authoring surface |
| tsoa, ts-rest, Effect HttpApi, feTS | Express, Koa, Hapi (tsoa); any (ts-rest, Effect); any Fetch runtime (feTS) | Decorators or contract-level security | Overlay | Code-first producers with no per-route hook PermDock can attach to; the same two-command recipe as next-openapi-gen |
next-openapi-gen matters most because it is the only producer for Next.js route handlers, which is where permdock/next lives. Its overlay.apply option means the Overlay is applied inside the same generate run, so the recipe is two commands and no glue code.
Appliers
| Tool | Where it runs | Overlay versions | Notes |
|---|---|---|---|
next-openapi-gen overlay.apply | Inside openapi-gen generate | 1.0, 1.1, 1.2 | Applies before writing the spec, so Scalar and Arazzo see the applied result; the first applier PermDock's --overlay 1.2 output is tested against |
Redocly CLI join --overlay | Lint, bundle, generate-client pipelines | 1.x | Experimental flag; redocly lint also validates Overlay documents. Common in design-first teams |
| Scalar CLI | Docs and registry pipelines | none yet | Overlay support is on Scalar's roadmap; apply with one of the above before scalar registry publish |
Bump.sh CLI bump overlay | Docs deploy pipelines; the Bump.sh GitHub Action takes an overlay: input | 1.x | Applies at deploy time so the hosted docs show the applied description while the repository keeps the producer's file untouched |
Speakeasy CLI speakeasy overlay apply | SDK generation workflows | 1.x | Speakeasy's own extensions arrive through overlays too, so a project can chain PermDock's Overlay and Speakeasy's in one workflow |
| Zuplo CLI | Gateway import | 1.x | Applies before the description is imported as gateway routes |
| openapi-format, oas-patch, overlays-js | Generic CLIs and libraries | 1.x | Vendor-neutral appliers for pipelines without one of the above; overlays-js is the reference JavaScript implementation |
PermDock emits Overlay 1.1.0 by default and, behind --overlay 1.2, the pinned Overlay 1.2 draft, whose one addition is reusable actions (components.actions plus $ref references); the earlier targetFormat idea is not in the v1.2-dev text. The 1.2 form collapses the repeated per-operation update bodies into one reusable action per permission set. It stays opt-in until 1.2.0 ships and the appliers below accept it (Overlay, ADR 0025).
Consumers
| Tool | Role | Reads | What PermDock must do | Recipe or adapter |
|---|---|---|---|---|
Hey API (@hey-api/openapi-ts) | Typed SDKs, TanStack Query hooks, validators | security, securitySchemes | Emit standard fields | Recipe: point it at the applied description. A plugin reading x-permdock-* is Phase 4 at earliest |
| Orval | Clients, TanStack Query, MSW mocks, MCP servers | security | Emit standard fields; x-permdock-permissions for the MCP output | Recipe; see bridges below |
Redocly generate-client | Clients | security | Emit standard fields | Recipe |
openapi-typescript with openapi-fetch | Types-only generation plus a typed fetch wrapper; the most used TypeScript generator | Schemas; security is not projected into types | Nothing; credentials are attached by the application | Nothing to do. openapi-fetch is in maintenance mode, which is one reason Hey API is the recommended SDK path |
| Kubb | Plugin-based generator: types, clients, TanStack Query, MSW, Zod, Redoc docs, MCP servers | security; x-permdock-permissions for the MCP plugin | Emit standard fields | Recipe; the MCP output follows the bridge recipe below |
OpenAPI Generator (typescript-fetch, typescript-axios), Kiota | Multi-language generators | security, securitySchemes | Emit standard fields | Nothing to do; teams generating non-TypeScript clients from the same description get the same scopes |
| Fern, Speakeasy | Commercial SDK, docs and MCP-server generators | security; own x-fern-* and x-speakeasy-* extensions | Emit standard fields; never write their namespaces | Recipe; see bridges below for the MCP output. Stainless, the third of this group, was acquired by Anthropic on 18 May 2026 and its hosted generator is being wound down; the x-stainless-* never-write rule stays because published descriptions still carry the fields |
| Scalar API Reference | Docs UI, Try-it client | security, OAuth scopes, x-badges, several vendor code-sample extensions | Standard fields; optional x-badges approval hint | Recipe; an operation-level plugin for x-permdock-* needs upstream plugin API support first |
| Swagger UI, Redoc, Stoplight Elements, RapiDoc, fumadocs-openapi | Docs UIs | security | Standard fields | Nothing to do |
| API gateways (Kong, Envoy, Tyk, Zuplo) | Enforcement from the description or from AuthZEN | security; AuthZEN | Standard fields; permdock/authzen | Already covered on AuthZEN |
| Spectral, Redocly lint, vacuum | Linters | Whole document | Ship a ruleset file | Phase 2 artefact, not a package |
permdock openapi import | PermDock's own consumer | security, x-permdock-* | Round-trips its own output | CLI: openapi |
Arazzo runners, permdock.simulate | Workflow pre-flight | operationId, x-permdock-permissions | Run on the applied description | Arazzo |
Docs hosts
Hosted documentation products are consumers too, and every one of them is a commercial product a team may already pay for. All read standard security and securitySchemes; several add their own extensions, which PermDock never writes (registries).
| Host | Own extensions | Applies Overlays | Also generates | Notes |
|---|---|---|---|---|
| Mintlify | x-mint (page metadata, href), x-mcp (per-operation MCP exposure) | No; apply before upload | An MCP server from the docs and the description, honouring securitySchemes | The most direct overlap with the bridge recipe below: an operation's x-mcp opt-in should match whether it carries x-permdock-permissions |
| Bump.sh | x-topics (narrative sections) | Yes, bump overlay and the GitHub Action | Changelog and diff | The applier and the host are one tool; a natural fit for --check in the same workflow |
| Fern docs | x-fern-* | No | SDKs and an MCP server from the same description | Docs, SDK and MCP from one applied description |
| Zudoku | none required | No | none | Zuplo's open-source docs UI; reads security and lets a team self-host |
| Redocly Realm | x-* rendering hints of its own | Yes, through Redocly CLI | Mock server | The Redocly CLI applier feeds it |
| Docusaurus OpenAPI, GitBook, Postman | Postman collections import security | No | Postman: collections and an MCP server | Import the applied description |
OpenAPI-to-MCP bridges
Orval, Kubb, Scalar, Speakeasy, Fern, Mintlify, Postman's MCP Generator, Zuplo, Kong's openapi2mcp, AWS Bedrock AgentCore Gateway and several smaller tools generate an MCP server from an OpenAPI description, one tool per operation. Agents then call the API through that server. Without PermDock in the loop the generated tools have no permission binding and permdock/mcp's list_tools filtering and approval-required elicitation never run. The recipe on the MCP adapter: read the operation's x-permdock-permissions from the applied description and bind it as the generated tool's permission. Standard security is not enough here because the bridge needs the permission key, not the scope; this is the one consumer for which the extension carries information the standard field cannot.
Several bridges carry their own per-operation extension for tool exposure, and each is a consumer-side concern that PermDock never writes: Mintlify x-mcp, Zuplo x-zuplo-route.mcp, Kong x-kong-mcp-tool-name and the ai-mcp-proxy plugin, Speakeasy x-speakeasy-mcp. Two deserve a note:
- Speakeasy scopes.
x-speakeasy-mcp.scopestags each tool with scope strings and the generated server takes--scopeflags at start time, so it is a coarse, deploy-time filter, not a per-caller check. The recipe is a consumer-side overlay that derivesx-speakeasy-mcp.scopesfrom the operation'spermission.scopevalues (post:deletebecomes a Speakeasy scope of the same name), so the two models agree, whilepermdock/mcpremains the per-callerlist_toolsandcall_toolcheck inside the generated server. - AgentCore Gateway. The gateway turns OpenAPI targets into MCP tools and applies Cedar policies whose
context.toolNameis theoperationId(commercial landscape). Because the tools are MCP,protectServerstill applies when the server runs in your process; when Amazon hosts the target, the Cedar policy is the enforcement point and PermDock's contribution is the applied description'ssecurityand the operation ids it can check against.
Testing and diff
Three tool classes read security in ways that turn PermDock's output into a runtime check:
- Schemathesis has an
ignored_authcheck: for every operation declaringsecurity, it sends the request without credentials and fails if the server answers anything other than401or403. Run against the applied description, it is a parity test that every operation PermDock says is protected actually rejects an anonymous call, which catches a route that lost itsprotectafter the description was published. - oasdiff treats a removed or weakened
securityrequirement as a breaking change; a CI step comparing the previous and current applied descriptions is a second line behindpermdock openapi --check. - Prism and Microcks mock servers answer
401for operations withsecuritywhen credentials are absent, so client-side tests exercise the denied path against the same description.
Scalar specifics
Scalar owns the registered scalar namespace; PermDock never writes into it (registries). Scalar renders x-badges (unregistered, rendering-only) on operations, which is enough to show "Approval required" next to a publishPost operation without Scalar understanding PermDock. Scalar's plugin API has historically bound custom x-* components to Info, Tag and Schema objects rather than operations (plugins); an operation-level PermDock plugin waits for that to change upstream.
Hey API specifics
Hey API clients attach credentials from the description's security schemes (clients), so a PermDock-annotated description produces SDKs whose calls carry the right scopes with no PermDock code. Its custom plugin API iterates operations (plugin.forEach('operation', ...), custom plugins), which is where a later plugin would read x-permdock-permissions and emit a typed permissions map beside each SDK function. Recorded as Phase 4, only if the recipe proves insufficient.
Two sources of truth
The one failure mode of composing is two tools writing security on the same operation. next-openapi-gen's @auth JSDoc tag and authPresets, hono-openapi's security option and hand-written security in a YAML file all compete with the Overlay. The rule: on operations PermDock covers, PermDock owns security and the producer owns everything else. permdock openapi emit --check reports operations whose source already carries security that the Overlay would replace, so the conflict is caught in CI rather than in a published description.
Adjacent formats
- AsyncAPI. Arazzo 1.1 accepts AsyncAPI sources, and an Overlay's JSONPath targets are not bound to OpenAPI. PermDock has no AsyncAPI emitter; if one is ever needed it is the same Overlay engine pointed at an AsyncAPI document, not a new adapter. Tracked.
- Problem Details. The
403body PermDock documents on protected operations (Problem Details) is what generated SDKs surface as the typed error, and what MSW fixtures in@permdock/testingreturn (testing). - Arazzo. next-openapi-gen's
arazzoblock compiles workflow files against the generatedoperationIds after the spec write;simulate({ arazzo, openapi })must read the applied description sox-permdock-permissionsis present (Arazzo).
Adopt / adapt / avoid
Adopt:
- The Overlay as the hand-off between PermDock and every producer it has no in-process hook for;
operationIdas the join key. - Standard
securityandsecuritySchemesas the contract with SDK generators, docs UIs and gateways, so Hey API, Orval, Redocly and Scalar work with no PermDock code. - next-openapi-gen
overlay.applyas the Next.js applier and Scalar as the default docs UI it scaffolds. - The existing appliers (next-openapi-gen, Redocly CLI, Bump.sh, Speakeasy,
overlays-js) instead of shipping one. - An existing OpenAPI parser for
permdock openapirather than a hand-rolled AST. - Schemathesis
ignored_authand oasdiff as the runtime and diff checks behind--check, documented on the CLI page. - TypeSpec and other design-first producers through the same Overlay, applied to emitter output.
Adapt:
x-badgesas an opt-in approval hint for docs UIs that render it; no semantics, off by default.- A Spectral / Redocly / vacuum ruleset expressing PermDock's document invariants, shipped as a file.
x-permdock-permissionsas the binding OpenAPI-to-MCP bridges read, documented as a recipe on the MCP adapter page.- A consumer-side overlay deriving Speakeasy
x-speakeasy-mcp.scopesand Mintlifyx-mcpopt-ins from PermDock's fields, so a team's docs host and SDK vendor agree with the policy without PermDock writing their namespaces. - Later first-party plugins (Hey API operation plugin, Scalar operation plugin) only if recipes fail, and only after upstream plugin APIs support the operation level.
- Overlay 1.2 as an opt-in output (
--overlay 1.2) pinned tov1.2-dev, default after release and applier support.
Avoid:
- Wrapping a producer, generator or docs UI in a PermDock package.
- Two sources of
securityon one operation. - Writing into
x-scalar-*,x-stainless-*,x-readme,x-mint,x-mcp,x-speakeasy-*,x-fern-*,x-topics, gateway import namespaces (x-amazon-apigateway-*,x-google-*,x-kong-*,x-zuplo-*) or anyx-oai-*name that is not registered. - A docs-host or generator package (
permdock/mintlify,permdock/bump,permdock/fern): each is reached through the applied description. - Making the Overlay the CLI default before the document form is unnecessary.
- Moving Arazzo
simulateearlier than Phase 4 because a producer happens to compile Arazzo.
Decisions informed
- ADR 0023: compose with the OpenAPI toolchain
- ADR 0019: extensions and Overlay (the Overlay-applier deferral is confirmed)
- ADR 0014: OpenAPI 3.2
- Pages shaped: OpenAPI adapter, Next.js adapter, MCP adapter, CLI: openapi, OpenAPI Overlay, Arazzo, OpenAPI 3.2, landscape, ecosystem index
SaaS tenancy and roles, September 2026
How authorization engines, auth providers and entitlement platforms model tenants, teams, scoped roles, tenant-defined custom roles and the SaaS features around them; which standards apply (RFC 9068 claims, SCIM groups, AuthZEN, INCITS 359); and what PermDock adopts, adapts and leaves upstream.
Agent frameworks beyond the five adapters
Which TypeScript agent frameworks and agent-UI protocols expose a hook PermDock could occupy (LangGraph.js, Mastra, Inngest AgentKit, Cloudflare Agents, Google ADK, OpenAI Apps SDK, AG-UI, Cursor and Claude Code hooks), which are already covered by an existing adapter, and why none becomes an adapter before Phase 4.