* fix(cli): synthesize happy-args instead of TODO examples Derive runnable pp:happy-args and Example strings from spec example/enum/default/format at generate time. Omit example-value placeholders from emitted Example lines rather than shipping copy-paste 400s. Leave opaque IDs and other underivable required inputs unset so live dogfood does not invent values. Closes #4258 Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> * test(cli): update goldens for synthesized happy-args Refresh generate-golden-api and generate-public-param-names fixtures so required params with spec defaults emit runnable Example strings and pp:happy-args, and underivable placeholders are omitted from Cobra Example lines. Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> * fix(cli): omit invented Cobra examples; reject unencodable happy-args Apply the same required-input derivability gate to synthesized Cobra Example strings as to pp:happy-args, and refuse values with literal backslashes that splitHappyArgs cannot round-trip. Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> * fix(cli): skip underivable optional positionals in happy-args Optional positionals no longer fail closed during synthesis. Required positionals still block; underivable optionals are omitted from pp:happy-args and synthesized Cobra examples. Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> * fix(cli): fail closed on non-trailing optional positionals Happy-args overlays positionals by index after dropping labels, so omitting a mid-list optional rebinds later values. Skip only a trailing underivable-optional suffix; otherwise leave synthesis unset. Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com>
70 KiB
OpenAPI Extensions
This document is the canonical reference for Printing Press-specific OpenAPI
x-* extensions. OpenAPI allows extension fields anywhere, but the Printing
Press only reads the extensions listed here.
Source of truth: internal/openapi/parser.go. This document should be updated
in the same change as any new Extensions["x-*"] lookup in that file.
Summary
| Extension | Location | Parsed field | Required |
|---|---|---|---|
x-api-name |
info |
APISpec.Name |
No |
x-display-name |
info |
APISpec.DisplayName |
No |
x-website |
info |
APISpec.WebsiteURL |
No |
x-proxy-routes |
info |
APISpec.ProxyRoutes |
No |
x-origin |
info |
Google Discovery resource fallback | No |
x-providerName |
info |
Google Discovery resource fallback | No |
x-roles |
root or info |
APISpec.Roles |
No |
x-tier-routing |
root or info |
APISpec.TierRouting |
No |
x-rate-class |
root or info |
APISpec.RateClass |
No |
x-pp-default-rate-limit |
root or info |
APISpec.DefaultRateLimit |
No |
x-mcp |
root or info |
APISpec.MCP |
No |
x-cache |
root or info |
APISpec.Cache |
No |
x-learn |
root or info |
APISpec.Learn |
No |
x-pp-query |
root | APISpec.QuerySync |
No |
x-pp-response-envelope |
root or info |
APISpec.ResponseEnvelopeKey |
No |
x-auth-type |
components.securitySchemes.<name> |
APISpec.Auth.Type |
No |
x-auth-format |
components.securitySchemes.<name> |
APISpec.Auth.Format |
No |
x-prefix |
components.securitySchemes.<name> |
APISpec.Auth.Format |
No |
x-auth-env-vars |
components.securitySchemes.<name> |
APISpec.Auth.EnvVars |
No |
x-auth-vars |
components.securitySchemes.<name> |
APISpec.Auth.EnvVarSpecs |
No |
x-speakeasy-example |
components.securitySchemes.<name> |
APISpec.Auth.EnvVars |
No |
x-auth-optional |
components.securitySchemes.<name> |
APISpec.Auth.Optional |
No |
x-auth-key-url |
components.securitySchemes.<name> |
APISpec.Auth.KeyURL |
No |
x-auth-title |
components.securitySchemes.<name> |
APISpec.Auth.Title |
No |
x-auth-description |
components.securitySchemes.<name> |
APISpec.Auth.Description |
No |
x-auth-subtype |
components.securitySchemes.<name> |
APISpec.Auth.Subtype |
No |
x-auth-cookie-domain |
components.securitySchemes.<name> |
APISpec.Auth.CookieDomain |
No |
x-auth-cookies |
components.securitySchemes.<name> |
APISpec.Auth.Cookies |
No |
x-auth-companion |
components.securitySchemes.<name> or info |
APISpec.Auth.LoginURL, LoginCompleteSelector, JWTCarrierCookie |
No |
x-oauth-device-flow |
components.securitySchemes.<name> |
APISpec.Auth.OAuth2Grant, DeviceAuthorizationURL, TokenURL, Scopes, DefaultClientID |
No |
x-oauth-refresh-token-mechanism |
components.securitySchemes.<name> |
APISpec.Auth.RefreshTokenMechanism |
No |
x-resource-id |
path item | Endpoint.IDField |
No |
x-critical |
path item | Endpoint.Critical |
No |
x-tier |
path item or operation | Endpoint.Tier |
No |
x-data-source-strategy |
path item or operation | Endpoint.DataSourceStrategy |
No |
x-live-dogfood-requires-tier |
path item or operation | Endpoint.LiveDogfoodRequiresTier |
No |
x-requires-role |
operation | Endpoint.RequiresRole |
No |
x-happy-args |
operation | Endpoint.HappyArgs |
No |
x-happy-stdin |
operation | Endpoint.HappyStdin |
No |
x-pp-example |
operation | Endpoint.Example (verbatim Cobra example override) |
No |
x-pp-resource |
operation | resource name override | No |
x-pp-pagination |
operation | Endpoint.Pagination |
No |
x-pp-mutation |
operation | Endpoint.Mutation |
No |
x-pp-safe-probe |
operation | skill guidance only; not parsed in parser.go | No |
x-pp-sync-walker |
operation | Endpoint.Walker |
No |
x-sync-params |
operation | Endpoint.SyncParams |
No |
x-pp-dispatch-param |
parameter | Param.DispatchParam |
No |
x-pp-tenant-scope-column |
path item | Endpoint.TenantScopeColumn |
No |
x-pp-membership-field |
path item | Endpoint.MembershipField |
No |
info Extensions
x-api-name
Overrides the API slug only when info.title does not fold to a usable slug.
The parser first applies its normal name cleaning to info.title; x-api-name
is only consulted when that result is empty or api.
Parsed field: APISpec.Name
Rules:
- Optional.
- Must be a string.
- Cleaned with the same slug normalization as
info.title. - Ignored when the cleaned value is empty or
api. - Ignored when
info.titlealready produced a usable slug.
Example:
info:
title: API
version: "1.0"
x-api-name: example-service
x-display-name
Preserves the human-readable brand name when slug-derived title casing would deform it.
Parsed field: APISpec.DisplayName
Rules:
- Optional.
- Must be a string.
- Leading and trailing whitespace is trimmed.
- Empty or non-string values leave
DisplayNameempty, so downstream code falls back to spec metadata or slug-derived naming. - The parser does not enforce a length cap for
x-display-name. The separateregistry.jsondisplay-name fallback used bymcp-syncrejects registry values longer than 40 characters, but that limit does not apply here.
Example:
info:
title: Cal Com
version: "1.0"
x-display-name: Cal.com
x-website
Provides a product or vendor website URL when standard OpenAPI metadata does not carry one.
Parsed field: APISpec.WebsiteURL
Rules:
- Optional.
- Must be a string.
- Used only when
info.contact.urlis absent. externalDocs.urlis used afterx-websiteif no website URL has been found.- The parser does not validate the URL shape.
Example:
info:
title: Example Service
version: "1.0"
x-website: https://www.example.com
x-proxy-routes
Declares route-to-service mapping for the proxy-envelope client pattern.
Parsed field: APISpec.ProxyRoutes
Rules:
- Optional.
- Must be a map.
- Map keys are path prefixes.
- Map values must be strings; non-string values are skipped.
- A missing or malformed map leaves
ProxyRoutesempty.
Example:
info:
title: Example Service
version: "1.0"
x-proxy-routes:
/v1/search: search
/v1/publish: publishing
x-origin / x-providerName
Recognized on Google Discovery specs converted by apis.guru. These extensions do
not populate an APISpec field; they gate the parser's operationId-based
resource fallback for paths such as /v2/{name} and /{resource}:getIamPolicy.
Rules:
- Optional.
x-providerName: googleapis.comenables Google Discovery resource fallback.x-originenables the fallback when any entry hasformat: googleor a Discovery URL undergoogleapis.com/$discovery.- Ignored for non-Google specs.
x-tier-routing
Declares opt-in free/paid credential routing for APIs where some endpoints work without credentials and other endpoints require a separate paid key or token.
Parsed field: APISpec.TierRouting
Rules:
- Optional.
- May be declared at the OpenAPI root or under
info. - Requires a
tiersmap when present. default_tieris optional; endpoints withoutx-tieruse global auth when it is absent.- V1 tier auth supports only
none,api_key, andbearer_token. - Credential-bearing tier
base_urlvalues must be HTTPS and cannot point at loopback, private, link-local, or unrelated hosts unlessallow_cross_host_auth: truedocuments explicit review. - Incompatible with
client_pattern: proxy-envelopeand with resource- or endpoint-levelbase_urloverrides when any tier declares its ownbase_url. - Tier credential env vars are read from the environment at request time; they are not serialized into generated config files.
Example:
x-tier-routing:
default_tier: free
tiers:
free:
auth:
type: none
paid:
base_url: https://paid.api.example.com
auth:
type: api_key
in: query
header: api_key
env_vars: [EXAMPLE_PAID_KEY]
x-roles
Declares the authenticated persona labels that operation-level RBAC gates may reference.
Parsed field: APISpec.Roles
Rules:
- Optional.
- May be declared at the OpenAPI root or under
info. - Must be a string list.
- Each role must match
^[A-Za-z][A-Za-z0-9_-]*$. - Every operation-level
x-requires-rolevalue must name one declared role.
Example:
x-roles: [parent, student, teacher, admin]
x-rate-class
Declares the API's rate-limit operating point so generated sync defaults can avoid wasteful parallelism on low-total-budget APIs.
Parsed field: APISpec.RateClass
Rules:
- Optional.
- May be declared at the OpenAPI root or under
info. Root takes precedence when both are present. - Must be a string.
- Accepted values are
per-second,daily,monthly, andunlimited. dailyandmonthlygeneratesync --concurrencywith a default of 1.per-second,unlimited, and absent keep the default of 4.- This only changes generated sync worker defaults. It does not add runtime rate limiting, retries, or backoff.
Example:
info:
title: Low Quota API
version: "1.0"
x-rate-class: monthly
x-pp-default-rate-limit
Sets the built-in default for the generated CLI's --rate-limit flag from an
OpenAPI spec, mirroring the internal YAML default_rate_limit field.
Parsed field: APISpec.DefaultRateLimit
Rules:
- Optional.
- May be declared at the OpenAPI root or under
info. Root takes precedence when both are present. - The value is either the string
"auto"(case-insensitive) or a non-negative number (a JSON number or a numeric string). Any other shape is rejected with a validation error. "auto"selects the header-driven adaptive limiter so the CLI paces itself to the server'sX-Ratelimit-*headers with no hardcoded ceiling. A numeric value (e.g.2) pins a fixed requests-per-second ceiling.- When absent, the generated
--rate-limitdefault isclient.RateLimitAuto(the same as"auto"), for both sniffed and documented specs. This only sets the default; the generated--rate-limitflag still overrides it at runtime.
Example:
info:
title: Throttled API
version: "1.0"
x-pp-default-rate-limit: auto
x-mcp
Declares MCP server shape for the generated CLI. Mirrors the internal YAML
spec's top-level mcp: block so OpenAPI specs can opt into the same
pre-generation MCP enrichment recipe (notably the code-orchestration pattern
for large surfaces: transport: [stdio, http] + orchestration: code +
endpoint_tools: hidden).
Parsed field: APISpec.MCP (spec.MCPConfig)
Rules:
- Optional. Specs without
x-mcpget the endpoint-mirror surface while they remain at or below the orchestration threshold. Small APIs (typed-endpoint count at or belowspec.DefaultRemoteTransportEndpointThreshold, currently 30) also get the http transport compiled in alongside stdio so the same binary can reach cloud-hosted agents. Large APIs abovespec.DefaultOrchestrationThreshold(currently 50) default to the Cloudflare MCP pattern (transport: [stdio, http],orchestration: code, andendpoint_tools: hidden) whenorchestrationis unset. Setorchestration: endpoint-mirrorto opt out. Settingtransportexplicitly (includingtransport: [stdio]) bypasses the transport default and is honored as-is. - May be declared at the OpenAPI root or under
info. Root takes precedence when both are present. - For backwards compatibility, root-level
mcp:is also accepted when canonicalx-mcpis absent. The parser emits a warning asking authors to rename it tox-mcp.x-mcpandmcpare never merged; any canonicalx-mcpdeclaration, including underinfo, wins as a complete config. - Shape mirrors the internal YAML
mcp:block field-for-field:transport,addr,intents,endpoint_tools,orchestration,orchestration_threshold. - Validated by
validateMCPat spec load (same allowlist as internal YAML): unknown transports and malformed addresses are rejected.
Example:
x-mcp:
transport: [stdio, http]
orchestration: code
endpoint_tools: hidden
x-cache
Declares cache-freshness and auto-refresh behavior for generated CLIs. Mirrors
the internal YAML spec's top-level cache: block so OpenAPI specs with a
store-backed sync surface can opt into the same freshness machinery.
Parsed field: APISpec.Cache (spec.CacheConfig)
Rules:
- Optional. Specs without
x-cachekeep today's behavior: no freshness helper or auto-refresh hook is emitted unless cache is configured elsewhere. - May be declared at the OpenAPI root or under
info. Root takes precedence when both are present. - Shape mirrors the internal YAML
cache:block field-for-field:enabled,stale_after,refresh_timeout,env_opt_out,resources,commands. - Validated by the same cache/share validation as internal YAML specs. Duration
fields must be Go duration strings,
commandsrequireenabled: true, and command resource names must refer to parsed resources.
Example:
x-cache:
enabled: true
stale_after: 6h
refresh_timeout: 30s
env_opt_out: EXAMPLE_NO_AUTO_REFRESH
resources:
quotes: 5m
commands:
- name: dashboard
resources: [quotes]
x-learn
Declares the self-learning loop configuration for generated CLIs. Mirrors the
internal YAML spec's top-level learn: block so OpenAPI-sourced prints can
author ticker patterns, stopwords, synonym folds, and entity-lookup seeds the
same way internal specs do.
Parsed field: APISpec.Learn (spec.LearnConfig)
Rules:
- Optional. Specs without
x-learnexpress no learn preference and take the generator's learn-loop default.enabled: falseis likewise treated as unset under that default (a plain bool cannot express "explicitly off"); the authoritative opt-out isdisabled: true. - May be declared at the OpenAPI root or under
info. Root takes precedence when both are present. - Shape mirrors the internal YAML
learn:block field-for-field:enabled,disabled,ticker_patterns,stopwords,synonyms,entity_lookup_seeds. disabled: trueis the generation-time opt-out. Combining it with an explicitenabled: trueis rejected at parse time as contradictory.- Validated by the same learn validation as internal YAML specs: ticker
patterns must compile as Go regexps and must not classify every remaining
content token in seeded playbook
query_family_examplesas a ticker (that empties QueryFamily and makes recall unreachable), seed kinds must be lowercase identifiers, canonicals must be non-empty and unique within a kind, and synonym pairs must be non-empty lowercase single-hop folds (no chains, no self-references).
Example:
x-learn:
enabled: true
ticker_patterns:
- "[A-Z]{2,6}-[0-9]+"
stopwords: [the, of]
synonyms:
last night: yesterday
entity_lookup_seeds:
country:
- canonical: USA
aliases: [united states, america]
x-pp-example
Overrides the generated command's --help Example with a verbatim, authored
invocation. The synthesized example only includes required params, so an
endpoint whose params are all optional — the common "pass one of channelId /
handle / url" shape — otherwise advertises a bare command the API rejects
with a 4xx. That broken example also fails the live-dogfood happy-path and
json-fidelity probes, which run the Example verbatim.
Parsed field: Endpoint.Example (the same field the internal YAML spec sets via
example:).
Rules:
- Optional. Endpoints without
x-pp-examplekeep today's synthesized example byte-for-byte. - Operation-level only. The value is the full invocation including the binary
name (
<api-slug>-pp-cli <command> <args>); the parser normalizes it to the canonical two-space indent on each line, so authors may omit the leading spaces. - Use it instead of marking a param
requiredto force it into the example — marking it required would also make the generated CLI flag mandatory, which a one-of endpoint must not be. - Whitespace-only values are ignored (treated as absent); non-string values warn and are ignored.
Example:
paths:
/v1/youtube/channel:
get:
operationId: getYoutubeChannel
x-pp-example: "scrape-creators-pp-cli youtube list-channel --handle mkbhd"
parameters:
- { name: channelId, in: query, required: false, schema: { type: string } }
- { name: handle, in: query, required: false, schema: { type: string } }
- { name: url, in: query, required: false, schema: { type: string } }
x-pp-response-envelope
Declares the exact top-level key used by an API's single-key JSON response
wrapper, such as result in {"result": {"items": [...]}}. The generated
client removes that wrapper before the response reaches commands, pagination,
or sync. This is opt-in because a top-level key can also be part of a
legitimate payload.
Parsed field: APISpec.ResponseEnvelopeKey
Rules:
- Optional. Specs without this extension keep the response body unchanged.
- Declared at the OpenAPI root or under
info. - Must be a string; surrounding whitespace is trimmed.
- Unwrapping applies only to successful JSON responses whose body is an object with exactly one property matching the configured key. Other bodies pass through unchanged.
Example:
x-pp-response-envelope: result
x-pp-query
Declares the SQL-query-endpoint sync shape (QuickBooks Online, Salesforce SOQL):
an API where every list resource is read through one shared endpoint with an
injected SELECT-style query, results wrapped in an entity-named envelope, and
paging carried inside the query text. Mirrors the internal YAML spec's top-level
query_sync: block. When present, the sync generator emits the query injection,
the response-envelope unwrap, and the in-query offset-paging loop by
construction — gated so a normal REST list API's generated output is
byte-identical to today.
Parsed field: APISpec.QuerySync (spec.QuerySyncConfig)
Rules:
- Optional. Specs without
x-pp-querykeep today's REST sync behavior exactly. - Declared at the OpenAPI root (the internal YAML form lives in the top-level
query_sync:block). All query dialect text lives in the hint, never the generator — the template substitutes the{entity},{start}, and{limit}placeholders at runtime. - A resource participates only when its list endpoint's path equals
pathAND it declares aresponse_path(e.g.QueryResponse.<Entity>); the per-resource entity name is taken from that endpoint's response item (e.g.Invoice). Raw passthrough resources on the same path with noresponse_pathare skipped. - Fields:
path(required, the shared query endpoint, e.g./query);query_param(the param carrying the SELECT, defaultquery);query_template(required, the SELECT + paging clause with{entity}/{start}/{limit}placeholders);version_param+version_value(an optional extra param sent on every query call);envelope_key(the result-envelope object key joined to the runtime extractor list, e.g.QueryResponse);page_size(in-query page size and offset stride, default1000).
Example:
x-pp-query:
path: /query
query_param: query
query_template: "select * from {entity} startposition {start} maxresults {limit}"
version_param: minorversion
version_value: "75"
envelope_key: QueryResponse
page_size: 1000
x-tenant-env-var
Declares the env-var name that resolves the implicit {tenant} path
placeholder for multi-tenant SaaS APIs whose every path is
/tenant/{tenant}/<resource>. Without this annotation, the generator
classifies tenant-templated paths as parent-context-dependent and emits an
empty defaultSyncResources / syncResourcePath map; sync silently no-ops
and every downstream offline command ships broken.
Parsed fields: APISpec.EndpointTemplateVars (tenant added),
APISpec.EndpointTemplateEnvOverrides["tenant"] (env-var name), and
APISpec.GlobalPathTemplateVars when {tenant} is present on at least
80% of endpoints and can safely map to a root persistent flag.
Rules:
- Optional. Specs without
x-tenant-env-varkeep single-tenant behavior; no{tenant}-aware emission, no spurious env reads. - Accepted at the document root or under
info(path-positional templates are spec-wide either way); the root value wins when both are set. Press operators commonly place this at the document root, so the parser must accept it there — an info-only reader silently drops the extension, and the affected print loses tenant-awaresync,config.go, andurl.goemission with no error, only asyncwarning at runtime that reads like a resource-specific problem. - Value must be a non-empty string after
TrimSpace. Whitespace-only values are treated as absent. - The placeholder name is
tenant. Specs that use a different placeholder ({workspace},{org}) should setEndpointTemplateVars+EndpointTemplateEnvOverridesdirectly in internal YAML until this extension generalizes.
Effect on generated output (when set):
- The profiler treats
/.../{tenant}/...paths as standalone-listable, so the resource becomes a flatSyncableResourcerather than aDependentSyncResource. - The emitted
config.goreads the override env-var name (e.g.ST_TENANT_ID) intoConfig.TemplateVars["tenant"]atLoad()time. - The emitted
url.gobuildURLsubstitutes{tenant}fromConfig.TemplateVarsat request time and names the override env var in the actionable error when the value is missing. - When
{tenant}appears on at least 80% of endpoints and its public flag name does not collide with existing root flags, the emitted root command exposes--tenantas an optional override for the sameConfig.TemplateVars["tenant"]value. Matching per-command{tenant}positionals are removed; sparse path params remain per-command inputs. - Typed MCP endpoint tools for tenant-scoped paths expose optional
tenantinput that overrides the env/config value for that one call. - The emitted
sync.gofilters{tenant}out of the unresolved-key warning so per-tenant paths don't get skipped as "requires parent context".
Example:
info:
title: ServiceTitan CRM
version: 1.0.0
x-tenant-env-var: ST_TENANT_ID
x-pp-tenant-scope-column
Declares, on a collection's list path-item, the column or field name that identifies the tenant (e.g. workspace) scope for each row returned by that collection. It is self-declaring: the annotated collection's own rows carry this column. Use it on list path-items whose synced rows are partitioned by a workspace or organization identifier.
Parsed field: Endpoint.TenantScopeColumn
The value flows into the resource profile and is consumed in two places:
- Tenant-scoped dependent fan-out (parent tables): a parent collection
carrying a tenant column is surfaced via
APIProfile.TenantScopedParents()into the generatedparentTenantScopeColumnsmap, so dependent fan-out targets only rows belonging to the active tenant. - Flat tenant-scoped reconcile: a flat resource becomes reconcilable
(
ReconcileMode = "flat") when it carries a tenant column, has a stable primary key, and is not routed through a discriminator dispatcher. - Single-tenant whole-table reconcile: when a print has zero
TenantScopeColumnannotations, eligible flat resources (stable PK, no discriminator) are classifiedReconcileMode = "flat_global"and the table is the partition. Unscoped resources in a mixed print stay"none".
Rules:
- Optional. Absence means no tenant scoping is recorded for the collection.
- Placed on the list path-item object (same level as
get:,post:, etc.), not on an individual operation. - Must be a string naming the response field that holds the tenant scope
(e.g.
workspace,workspace_slug,org_id); non-string values are ignored with a warning. - The field names the foreign-key column whose values identify tenant boundaries in the synced rows.
Example:
paths:
/projects/:
x-pp-tenant-scope-column: workspace
get:
operationId: list_projects
summary: List or retrieve projects
x-pp-membership-field
Declares, on a parent collection's list path-item, the boolean field in that
collection's own row payload that indicates whether the authenticated user is a
member of the resource (e.g. is_member). Dependent fan-out over the parent
table skips rows whose field is false — their sub-resources would 403 — so a
sync reports one clear "not a member" summary instead of a 403 per
(sub-resource, parent).
Parsed field: Endpoint.MembershipField
Rules:
- Optional. Absence means no membership filtering is recorded.
- Placed on the list path-item object (same level as
get:,post:, etc.), not on an individual operation. - Must be a string naming a boolean field in the row payload; non-string values are ignored with a warning.
- The field name must be a simple identifier (
^[a-zA-Z_][a-zA-Z0-9_]*$). It is interpolated into the generated store's non-member query, so dotted or nested-path field names are rejected at runtime and the membership skip becomes a no-op rather than filtering rows. - Consumed by the profiler when building dependent-sync resource metadata.
Example:
paths:
/workspaces/:
x-pp-membership-field: is_member
get:
operationId: list_workspaces
summary: List workspaces
x-path-template-env-vars
Generic, map-shaped successor to x-tenant-env-var. Each entry binds a
path placeholder to an object with two optional fields. The env field
registers a runtime env-var override for the placeholder, flowing into
the same EndpointTemplateVars / EndpointTemplateEnvOverrides bucket
that x-tenant-env-var populates — suitable for BaseURL placeholders
such as Atlassian's {workspace} or GitHub's {org}. The default
field bakes a literal into operation paths at generation time and drops
the matching path parameter, suitable for canonical always-valid values
such as Gmail's userId='me' for the authenticated user. When both are
set on the same entry, default wins and env is ignored — the
placeholder is fully resolved before runtime substitution sees it.
Parsed fields: APISpec.EndpointTemplateVars,
APISpec.EndpointTemplateEnvOverrides,
APISpec.EndpointPathParamDefaults, and
APISpec.GlobalPathTemplateVars for env-backed placeholders that meet
the same 80% common-path promotion rule.
Rules:
- Optional. Specs without this extension keep prior behavior; the new field stays empty and no generated output changes.
- Accepted at the document root or under
info(path-positional templates are spec-wide either way); the root value wins when both are set. Same root-or-info lookup asx-tenant-env-var. - Coexists with
x-tenant-env-var; both feed the same template-vars bucket. Thetenantplaceholder may be set by either extension. envanddefaultvalues must be non-empty afterTrimSpace. Whitespace-only values are treated as absent on the entry.- Entries with neither
envnordefaultset are skipped silently. - Env-backed placeholders that appear in at least 80% of endpoint paths
are promoted to optional root persistent flags (for example
{workspace}->--workspace) when the derived flag and Go field names do not collide with existing root command flags. Matching per-command path positionals are removed, while same-named non-path positionals and sparse path params remain command inputs. - Typed MCP endpoint tools for promoted env-backed path placeholders expose optional per-call inputs that override env/config values before URL substitution.
Effect on generated output (when set):
env-set entries behave exactly likex-tenant-env-varfor the declared placeholder: the emittedconfig.go,url.go, andsync.goresolve the placeholder against the named env var at runtime, and the profiler treats/.../{placeholder}/...paths as standalone-listable.default-set entries are baked in at parse time: every operation path underResourceshas{placeholder}replaced with the literal, and the matching path parameter is dropped from each endpoint'sParams. The printed CLI exposes neither a placeholder nor a flag for the resolved parameter.
Examples:
Runtime env-var override for a BaseURL placeholder, parallel to
x-tenant-env-var:
info:
title: Atlassian API
version: 1.0.0
x-path-template-env-vars:
workspace:
env: ATLASSIAN_WORKSPACE
Build-time literal substitution that bakes a canonical value into every operation path and drops the matching path parameter:
info:
title: Gmail Users API
version: 1.0.0
x-path-template-env-vars:
userId:
default: me
Security Scheme Extensions
Security scheme extensions are read from
components.securitySchemes.<scheme-name>. They can declare composed cookie
auth or override install/config metadata when the API spec's service identity
differs from the product identity exposed by the printed CLI.
When components.securitySchemes is absent, the parser may infer simple
bearer auth from clear API-wide prose such as Authorization: Bearer,
personal access token, fine-grained PAT, app installation token, or
OAuth app token. An explicitly empty block disables that prose fallback:
components:
securitySchemes: {}
x-auth-type
Marks an API key scheme as composed auth.
Parsed field: APISpec.Auth.Type
Rules:
- Optional.
- Must be the exact string
composedto take effect. - Only read for OpenAPI
apiKeysecurity schemes. - Any other value leaves the normal API key mapping in place.
x-auth-format
Template used to assemble the composed auth header or cookie value.
Parsed field: APISpec.Auth.Format
Rules:
- Optional.
- Only read when
x-auth-type: composed. - Must be a string.
x-prefix
Declares a literal token prefix for header API key schemes.
Parsed field: APISpec.Auth.Format
Rules:
- Optional.
- Only read for OpenAPI
apiKeysecurity schemes within: header. - Must be a string.
- Leading and trailing whitespace is trimmed.
- When present, the parser stores
"<prefix> {token}"inAuth.Format. - Ignored for query API keys and non-API-key auth schemes.
Example:
components:
securitySchemes:
apiKey:
type: apiKey
in: header
name: Authorization
x-prefix: Klaviyo-API-Key
x-auth-basic-username / x-auth-basic-password
Declares the literal username or password half for HTTP Basic auth schemes where only the other half should be supplied by the user.
Parsed field: APISpec.Auth.Format
Rules:
- Optional.
- Only read for OpenAPI
httpsecurity schemes withscheme: basic. - Must be a string.
- Leading and trailing whitespace is trimmed.
- When only
x-auth-basic-usernameis present, the parser stores"Basic <username>:{token}"inAuth.Format. - When only
x-auth-basic-passwordis present, the parser stores"Basic {token}:<password>"inAuth.Format. - If both are present or both are absent, the normal Basic auth format remains
"Basic {username}:{password}".
Example:
components:
securitySchemes:
basicAuth:
type: http
scheme: basic
x-auth-basic-username: API_KEY
x-auth-env-vars
Overrides the generated credential environment variable names.
Parsed field: APISpec.Auth.EnvVars
Rules:
- Optional.
- Must be a list of strings. A single string is also accepted for convenience.
- Leading and trailing whitespace is trimmed from each item.
- Empty and non-string list items are ignored.
- When at least one non-empty item is present, the list replaces the parser's generated env var names.
- On apiKey/header schemes that appear beside the selected auth scheme in the
same AND security requirement, the first non-empty item supplies the
generated per-call env var for that sibling header. Use
x-auth-varsfor richer metadata or when more than one credential variable belongs to the same scheme. - If a sibling apiKey/header scheme omits
x-auth-env-varsandx-auth-vars, the parser derives a required per-call env var from the API slug and header name, for exampleDISPATCH_ST_APP_KEYforST-App-Key.
x-auth-vars
Overrides the generated credential environment variable metadata.
Parsed field: APISpec.Auth.EnvVarSpecs
Rules:
- Optional.
- Must be a list of objects.
- Each object must include
name,kind,required, andsensitive. namemust be a non-empty string.kindmust be one ofper_call,auth_flow_input, orharvested.requiredandsensitivemust be booleans.descriptionis optional and must be a string when present.- Group IDs and legacy aliases are not parsed. Express OR relationships in
descriptiontext and by marking each alternativerequired: false. - Use either
x-auth-env-varsfor legacy name-only overrides orx-auth-varsfor rich metadata. If both are present,x-auth-varswins. - Malformed values are ignored with a warning, and the parser falls back to the generated auth env-var defaults.
Example:
components:
securitySchemes:
apiKey:
type: apiKey
in: header
name: Authorization
x-auth-vars:
- name: TODOIST_API_KEY
kind: per_call
required: true
sensitive: true
description: Todoist API key.
x-speakeasy-example
Uses a Speakeasy security-scheme example as the credential environment variable name when it is shaped like a shell env var.
Parsed field: APISpec.Auth.EnvVars
Rules:
- Optional.
- Must be a string shaped like an uppercase environment variable name, for
example
DUB_API_KEY. - Ignored when
x-auth-env-varsis present. - Ignored when the selected auth config has multiple env vars.
- Ignored when the value looks like a token value instead of an env var name.
x-auth-optional
Marks the credential as optional for install/config surfaces.
Parsed field: APISpec.Auth.Optional
Rules:
- Optional.
- Must be a boolean.
truemakes MCPBuser_config.requiredfalse even for auth types that normally require credentials.
x-auth-key-url
Declares the page where users can get a credential.
Parsed field: APISpec.Auth.KeyURL
Rules:
- Optional.
- Must be a string.
- Leading and trailing whitespace is trimmed.
- The parser does not validate the URL shape.
When the extension is absent and the spec has any auth, the parser falls back through the following sources in order:
- The selected security scheme's
description(extracted via regex). info.description, but only when the surrounding text mentions credential-related cues (token,api key,credential,register,sign up, etc.) so an unrelated URL doesn't get picked.
Within either description, generic protocol references such as MDN, RFC/IETF,
HTTPWG, and Wikipedia links are ignored. A clear credential-management surface
(console, dashboard, api-keys/apikeys, or settings/integrations) wins
over an earlier neutral URL; otherwise the first accepted non-generic URL is
kept as the fallback.
externalDocs.url and info.contact.url are intentionally not fallbacks
for KeyURL. Those almost always point at the API's docs landing page or the
company homepage, neither of which is where users actually create a token.
When KeyURL ends up empty, the printed CLI uses WebsiteURL (already
populated from externalDocs.url, info.contact.url, and x-website) under
a separate See API docs: <URL> line — honest framing for those URLs.
The result drives the printed CLI's Get a key at: <URL> output in auth
prompts and doctor.
x-auth-instructions
Free-form one-line guidance shown alongside x-auth-key-url, e.g. "Settings →
Personal access tokens → Generate new". The printed CLI surfaces this under
the URL in auth prompts, doctor, and the auth setup command.
Parsed field: APISpec.Auth.Instructions
Rules:
- Optional.
- Must be a string.
- Leading and trailing whitespace is trimmed.
- Use this when
x-auth-key-urllands on a docs page rather than the keys UI; the URL says where to start, the instruction says what to do once there.
x-auth-title
Overrides the title shown for the credential field in install/config surfaces.
Parsed field: APISpec.Auth.Title
Rules:
- Optional.
- Must be a string.
- Leading and trailing whitespace is trimmed.
- Used when the selected auth scheme has a single env var. Multiple env vars keep env-var-name titles to avoid duplicate field labels.
x-auth-description
Overrides the full description shown for the credential field in install/config surfaces.
Parsed field: APISpec.Auth.Description
Rules:
- Optional.
- Must be a string.
- Leading and trailing whitespace is trimmed.
- Used as the complete description when the selected auth scheme has a single
env var. When omitted, the generator builds a description from env var name,
display name, optionality, and
x-auth-key-url.
Example:
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: x-apikey
x-auth-env-vars:
- FLIGHTAWARE_API_KEY
x-auth-optional: true
x-auth-key-url: https://flightaware.com/commercial/aeroapi/
x-auth-title: FlightAware AeroAPI Key
x-auth-description: Optional FlightAware AeroAPI credential for enriched flight data.
x-auth-subtype
Refines Auth.Type for runtime flows that need a different credential-capture
path than the base type implies. Recognized values include
google_service_account, which selects the generated Google service-account
JWT bearer exchange scaffold, and auth0_spa_in_memory, a bearer-token spec
whose access token is held by the Auth0 SPA SDK with cacheLocation: memory.
Cookie/localStorage extractors have no path to the latter token (it lives in JS
heap only), so the generator emits a --auth0-spa flag on auth login --chrome
that drives a Chrome DevTools Protocol outbound-Authorization interceptor.
Parsed field: APISpec.Auth.Subtype
Rules:
- Optional.
- Must be a string.
- Recognized values:
google_service_account,auth0_spa_in_memory. Other values are silently dropped by the parser; the in-spec value never round-trips unless it matches a known subtype. google_service_accountis valid only with a bearer-token auth type. It emitsauth service-account, accepts a service-account JSON key throughGOOGLE_APPLICATION_CREDENTIALS, and supports a pre-minted bearer override throughGOOGLE_OAUTH_ACCESS_TOKEN.- Spec-level validation rejects
auth.subtype: auth0_spa_in_memorypaired with any non-emptyauth.typeother thanbearer_token. Auth0 SPA tokens are always Authorization-bearer values; combining the subtype withapi_keyorcookiewould silently emit a CDP path against a credential that isn't a JWT. - Sniff-time detection (
internal/browsersniff/auth0_spa.go) sets the subtype automatically when an/oauth/tokenresponse carriesaccess_tokenin the JSON body without a JWT-shaped Set-Cookie on the same response. Authors rarely need to set it by hand.
Example:
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
x-auth-subtype: auth0_spa_in_memory
x-auth-cookie-domain
Domain used when extracting named cookies for composed auth.
Parsed field: APISpec.Auth.CookieDomain
Rules:
- Optional.
- Only read when
x-auth-type: composed. - Must be a string.
x-auth-cookies
Cookie names required to fill the composed auth format.
Parsed field: APISpec.Auth.Cookies
Rules:
- Optional.
- Only read when
x-auth-type: composed. - Must be a list.
- List items must be strings; non-string items are skipped.
Example:
components:
securitySchemes:
browserSession:
type: apiKey
in: header
name: Authorization
x-auth-type: composed
x-auth-format: "Session {session_id}:{csrf_token}"
x-auth-cookie-domain: app.example.com
x-auth-cookies:
- session_id
- csrf_token
x-auth-companion
Declares the deterministic hints the generated CLI needs to hand off to
press-auth login non-interactively. With these set, auth login --chrome --auto-login shells out to press-auth login <domain> --login-url ... --jwt-carrier-cookie ... and the user never has to remember those values.
Parsed fields:
login_url->APISpec.Auth.LoginURLlogin_complete_selector->APISpec.Auth.LoginCompleteSelectorjwt_carrier_cookie->APISpec.Auth.JWTCarrierCookie
Placement:
- Allowed on
components.securitySchemes.<name>and oninfo. Scheme-level fields win over info-level when both are set. Info-level is intended for specs that declare composed auth without a single named security scheme.
Rules:
- All three sub-fields are optional. When absent, the generated CLI prints
a hint instructing the user to invoke
press-auth loginmanually. login_urlmust parse as a URL and usehttps://(orhttp://localhost/http://127.0.0.1). Plainhttp://against other hosts would leak the captured cookies to a network sniffer; the parser rejects it.login_complete_selectoris opaque — pass through verbatim as a CSS selector. The parser does not validate it beyond non-emptiness.jwt_carrier_cookieshould match one of the names listed incookies. A mismatch surfaces as a stderr warning at parse time (typo surfacing) rather than a hard error.- Only these three public hints are embedded into the generated CLI's source. Cookie values, JWT tokens, and other user-secret material never appear in generated constants — press-auth captures and stores those itself.
Internal YAML equivalent (under the auth: block):
auth:
type: composed
cookie_domain: example.com
cookies:
- session_id
- guestsession
login_url: https://www.example.com/account/login
login_complete_selector: "a[href*=signout]"
jwt_carrier_cookie: guestsession
OpenAPI security-scheme placement:
components:
securitySchemes:
browserSession:
type: apiKey
in: cookie
name: guestsession
x-auth-companion:
login_url: https://www.example.com/account/login
login_complete_selector: "a[href*=signout]"
jwt_carrier_cookie: guestsession
OpenAPI info-level placement (for specs without a named scheme):
info:
title: Example
x-auth-companion:
login_url: https://www.example.com/account/login
login_complete_selector: "a[href*=signout]"
jwt_carrier_cookie: guestsession
x-oauth-device-flow
Declares OAuth 2.0 device authorization grant metadata for CLI-first OAuth
flows. OpenAPI 3.0 does not have a native deviceCode flow, so the Printing
Press reads this extension from an OAuth2 security scheme and emits a generated
auth login --device-code command plus refresh-token handling.
Parsed fields: APISpec.Auth.OAuth2Grant=device_code,
APISpec.Auth.DeviceAuthorizationURL, APISpec.Auth.TokenURL,
APISpec.Auth.Scopes, APISpec.Auth.DefaultClientID.
Rules:
- Optional. When present, the parser treats the security scheme as a bearer OAuth flow backed by stored access tokens.
- Must be an object.
deviceAuthorizationUrl(ordevice_authorization_url) andtokenUrl(ortoken_url) are required byAPISpec.Validate()whenoauth2_grant: device_code.scopesmay be a string or list of strings. Lists are sorted for stable generation.defaultClientId(ordefault_client_id) is optional. When absent, the generated CLI prompts for--client-idor the inferred<API>_CLIENT_IDenvironment variable.
Example:
components:
securitySchemes:
OAuth2:
type: oauth2
x-oauth-device-flow:
deviceAuthorizationUrl: https://login.example.com/common/oauth2/v2.0/devicecode
tokenUrl: https://login.example.com/common/oauth2/v2.0/token
defaultClientId: public-client-id
scopes:
- Calendars.Read
- Mail.Read
x-oauth-refresh-token-mechanism
Declares how the authorization endpoint should be asked to issue a refresh
token. Providers diverge: Google reads access_type=offline as a query
parameter, while WHOOP, X/Twitter, and others read a magic scope value
(offline, offline.access, offline_access) instead. The generator emits
neither by default because a Google-shaped silent default silently breaks
other providers (broken refresh path is invisible until access-token TTL
expires).
Parsed field: APISpec.Auth.RefreshTokenMechanism
Rules:
- Optional. Only consumed by the authorization_code grant template; ignored for other grants and non-OAuth2 auth.
- Must be a string. Leading and trailing whitespace on the whole value is trimmed.
- Two exact-match prefixes are accepted:
scope:<value>appends<value>to the scope list. No query param is added.query:<key>=<value>sets the query parameter exactly once. No scope change.
- Malformed values (empty key, empty value, missing
=forquery, unknown prefix, uppercase prefix) are ignored and produce no emission. - For
query:<key>=<value>, the reserved authorization-URL parameter namesclient_id,redirect_uri,response_type,state, andscopeare rejected. Permitting them would let a spec author silently overwrite the generator's CSRF state token or core OAuth params. - Note: the single-mechanism shape cannot express Google's two-param recipe
(
access_type=offline+prompt=consent). The first param is sufficient for refresh-token issuance on initial consent; the second forces re-consent on subsequent logins to keep the refresh-token contract alive. Specs that need both should declare one via this extension and add the other through a future multi-mechanism syntax (out of scope here).
Example:
components:
securitySchemes:
OAuth2:
type: oauth2
x-oauth-refresh-token-mechanism: scope:offline
flows:
authorizationCode:
authorizationUrl: https://api.example.com/oauth/authorize
tokenUrl: https://api.example.com/oauth/token
scopes:
read: Read access
x-url-name and x-param-url-names
Overrides the URL query key for a parameter without changing the public CLI/MCP input name. Use this for APIs whose documented flag name or shared OpenAPI component name differs from the exact wire query key a specific endpoint accepts.
Parsed field: Param.URLName
Rules:
x-url-nameis allowed on an OpenAPI Parameter Object and applies wherever that parameter object is used.x-param-url-namesis allowed on a Path Item Object or Operation Object. It is an object mapping parameter names to URL query keys. Operation entries override path-item entries.- The parameter's
nameremains the public input identity used for generated Go identifiers, CLI flags, MCP public names, and manifest public names. - The override only changes generated URL query emission, MCP
WireName, and manifestwire_name. - Empty names, empty URL keys, and non-string override values are ignored with warnings.
Example:
paths:
/opportunities/search:
get:
x-param-url-names:
locationId: location_id
parameters:
- $ref: "#/components/parameters/LocationId"
/opportunities/pipelines:
get:
parameters:
- $ref: "#/components/parameters/LocationId"
components:
parameters:
LocationId:
name: locationId
in: query
schema:
type: string
In this example both endpoints keep the same public locationId input, but
only /opportunities/search sends ?location_id= on the wire.
x-pp-dispatch-param
Marks a query parameter as a fixed dispatch discriminator whose default value
selects the upstream route rather than tuning the request. Generated runnable
examples keep that default instead of substituting a synthetic dogfood value.
Parsed field: Param.DispatchParam
Use this for shared-path APIs where a query parameter such as type or
action selects the report or operation. Do not use it for ordinary filters,
limits, page sizes, or other tunable inputs.
Example:
paths:
/:
get:
operationId: getDomainRank
parameters:
- name: report
in: query
x-pp-dispatch-param: true
schema:
type: string
default: domain_rank
Path Item Extensions
Path item extensions are read from a path object, beside its HTTP operations. They apply to every operation under that path because sync identity and critical resource status are resource-scoped, and operation-level data-source strategy can override the path default.
x-resource-id
Declares the response field that should be used as the primary key when sync stores resources locally.
Parsed field: Endpoint.IDField
Rules:
- Optional.
- Must be a string. A dotted path (
entityInfo.entityId) is stored verbatim and walked at runtime byLookupFieldValue; it is not limited to a single top-level key. A+-separated list (date+model_permaslug) is a composite identity: generatedExtractResourceIDjoins the part values with+at storage time. Date-shaped parts are allowed inside a composite; a solo date field is not, becauseCanonicalResourceIDrejects ISO-date values. - Leading and trailing whitespace is trimmed.
- Non-string values emit a warning and are ignored.
- A non-empty
x-resource-idwins over every automatic response-schema fallback. - An empty or missing value falls through to the parser's automatic
resolveIDFieldFromResponseSchemachain: bareid; then a resource-derived singular key ending in_id,_uuid,_guid, or_uid(matched through snake-case normalization, so camelCase and PascalCase spellings such aswidgetIdare preserved when emitted); then vendor identifier keysgid,sid,uid,uuid, andguid; then a sole remaining<stem>_uid/ camelCasestemUidfield whose stem is the resource's own collection noun (soalertUidmatchesaccount-alerts-open, while a foreignaccountUidon/sitesfalls through; two own-stem spellings stay ambiguous); then URL-shaped identifier keysuri,self,selfLink,href, andurl; thenname; then the first solo-usable required scalar. A date-shaped required field (OpenAPIformat: date/date-time, a date-like name such asdate/created_at, or an ISO-date example) is never selected as a solo IDField: if later required identity fields exist (string or numeric, excluding mutable/metric names such asstatusortotal_tokens), they are joined with+as a composite identity; otherwise IDField stays empty so runtime fallbacks apply. GeneratedExtractResourceIDjoins part values with+after escaping\and+inside each part so distinct tuples cannot collide. Date-shaped parts are allowed inside a composite; a solo date field is not, becauseCanonicalResourceIDrejects ISO-date values. URL-shaped keys qualify only when the field schema is a plausible ID and either the field is required or its name, title, description, or format carries an identifier hint; an optional genericurltherefore falls through toname. - URL-shaped keys intentionally trail id-shaped keys, so APIs that expose both
idandselfkeep the compact primary key. - Qualified URL-shaped keys intentionally win over display
namewhen no id-shaped key is available. A resource URL or URI is usually record-unique, while display names can collide; keying onnamewould collapse two records with the same display label into one local row. - Applies to every operation on the path item.
Example:
paths:
/widgets:
x-resource-id: widget_uid
get:
operationId: listWidgets
responses:
"200":
description: OK
Nested identifiers use the same extension with a dotted path. Generated
LookupFieldValue walks each segment with snake/camel/Pascal spellings and
a trailing-underscore variant, so entityInfo.entityId reaches a payload
shaped like {"entityInfo":{"entityId":"..."}} without a hand-written
override:
paths:
/entities:
x-resource-id: entityInfo.entityId
get:
operationId: listEntities
responses:
"200":
description: OK
Composite identities use the same extension with +-separated field names.
Generated extraction joins the part values with + so a date-shaped column
can participate in the row key without becoming a solo ID:
paths:
/datasets/rankings-daily:
x-resource-id: date+model_permaslug
get:
operationId: listRankingsDaily
responses:
"200":
description: OK
Generated dependent sync uses the resolved resource ID field when substituting
parent IDs into child path parameters. When the resolved ID field is URL-shaped
(uri, self, selfLink, href, or url), generated
replaceURLIDPathParam reduces a full URL value to its trailing path segment
before normal path escaping. This is intentional: dependent fetches whose
upstream path expects {id} must not send a full URL as that path segment. Do
not restore scheme, host, query, or earlier path components in generated path
params.
store.BareResourceID is a separate storage-key helper for stripping the
NUL-delimited parent suffix from composite dependent-resource storage IDs. It is
not part of response-schema identity selection and should not be changed to
alter URL-shaped record identity behavior.
x-critical
Marks a syncable resource as essential. Generated sync commands fail the run
when a critical resource fails, while non-critical resource failures can be
reported as warnings unless --strict is used.
Parsed field: Endpoint.Critical
Rules:
- Optional.
- Defaults to
false. - Accepts native booleans.
- Also accepts the strings
"true"and"1"as true, case-insensitive after trimming. - The strings
"false","0", and""are false. - Other string values emit a warning and are false.
- Non-boolean, non-string values emit a warning and are false.
- Applies to every operation on the path item.
Example:
paths:
/accounts:
x-critical: true
get:
operationId: listAccounts
responses:
"200":
description: OK
x-pp-syncable
Opts a list endpoint into generated default sync even when the profiler would normally exclude it because required path or query parameters are not automatically satisfiable.
Parsed field: Endpoint.Syncable
Rules:
- Optional.
- Defaults to
false. - Accepts native booleans.
- May be set on a path item or a single operation.
- Use only when required inputs are supplied by defaults, endpoint template variables, or another generated runtime mechanism.
Example:
paths:
/tenant/{tenant_id}/items:
get:
operationId: listTenantItems
x-pp-syncable: true
parameters:
- name: tenant_id
in: path
required: true
schema:
type: string
responses:
"200":
description: OK
x-pp-mutation
Overrides the generator's read/write classification when the HTTP method is
not enough. true marks a GET action as state-changing (start, stop, restart,
deploy). false marks a POST (or other non-GET) endpoint as a read so the
generated command prints the response body instead of the mutation
acknowledgment envelope. Unset RPC-over-GET operations without a read token
fail closed (not mcp:read-only).
Parsed field: Endpoint.Mutation
Rules:
- Optional.
- Unset means classify from the HTTP verb, operation name, path shape, and body shape. RPC-over-GET without a read signal is a write.
- Must be a native boolean.
- Applies only at the operation level.
- When set, the generator uses this value before HTTP-verb and operation-name
fallbacks. Do not infer reads from filter-shaped parameter names alone;
use this flag or a read-shaped operation name (
search,list,query). - Internal YAML uses the same boolean as
mutation:.
Example:
paths:
/applications/{id}/restart:
get:
operationId: restartApplication
x-pp-mutation: true
responses:
"204":
description: Restarted
/sets/items:
post:
operationId: projectItems
x-pp-mutation: false
responses:
"200":
description: Matched rows
x-tier
Selects a tier declared by x-tier-routing for a path item or one operation.
Parsed field: Endpoint.Tier
Rules:
- Optional.
- Must be a string.
- Operation-level
x-tieroverrides path-item-levelx-tier. - The value must name a tier in
x-tier-routing.tiers. security: []/security: [{}]must not be combined with an auth-bearing tier. Use anonetier for anonymous endpoints.
Example:
paths:
/public/search:
x-tier: free
get:
responses:
"200": {description: ok}
/premium/search:
get:
x-tier: paid
responses:
"200": {description: ok}
x-data-source-strategy
Declares how a generated read command should honor the global
--data-source auto|local|live flag.
Parsed field: Endpoint.DataSourceStrategy
Rules:
- Optional.
- May be declared on a path item or operation.
- Operation-level values override path-item-level values.
- Must be one of
auto,local, orlive. autokeeps the normal live-with-local-fallback behavior for store-backed reads.localmakes the command use local synced data forautoandlocal, and reject--data-source livewith a clear no-live-equivalent error.livemakes the command use the remote API forautoandlive, and reject--data-source localwith a clear no-local-data-source error.
Example:
paths:
/reports/snapshot:
get:
x-data-source-strategy: local
responses:
"200": {description: ok}
x-live-dogfood-requires-tier
Declares the runner credential tier required before cli-printing-press dogfood --live should probe an endpoint.
Parsed field: Endpoint.LiveDogfoodRequiresTier
Rules:
- Optional.
- May be declared on a path item or operation.
- Operation-level values override path-item-level values.
- Must be a string; non-string values are ignored with a warning.
- This is dogfood-only. It does not select an upstream auth route and should
not be confused with
x-tier. - When absent, the parser may infer
streamingfor obviousGETstreaming endpoints such as paths ending in/streamor responses withtext/event-stream.
The generator emits the value as the Cobra annotation pp:requires-tier.
Live dogfood skips annotated commands unless --auth-tier or PP_AUTH_TIER
matches the value.
Example:
paths:
/2/tweets/firehose/stream:
get:
x-live-dogfood-requires-tier: enterprise
responses:
"200":
description: Streaming response
content:
text/event-stream:
schema:
type: string
x-requires-role
Requires the authenticated account to have one of the declared x-roles before
the generated command calls the API.
Parsed field: Endpoint.RequiresRole
Rules:
- Optional.
- Must be on an operation, not the root,
info, or path item. - Must be a string naming a role declared by
x-roles. - The generator emits the guard framework and endpoint call site. How a printed CLI discovers the authenticated account's role remains API-specific.
Example:
x-roles: [parent, student, teacher, admin]
paths:
/users:
get:
operationId: listUsers
x-requires-role: admin
responses:
"200": {description: ok}
x-pp-resource
Overrides the resource bucket for one OpenAPI operation. Use it when the path
parser would derive a reserved Printing Press template name such as search,
or when the upstream path shape does not expose the intended resource name.
Parsed field: resource map key in APISpec.Resources
Rules:
- Optional.
- Must be a string.
- The value is sanitized to the same resource-name form the parser uses for path-derived names.
- Non-string values emit a warning and are ignored.
- Applies only to the operation where it appears.
Example:
paths:
/search:
post:
operationId: searchNotes
x-pp-resource: notes_search
responses:
"200": {description: ok}
x-pp-pagination
Overrides pagination detection for one GET operation.
Parsed field: Endpoint.Pagination
Rules:
- Optional.
- Must be on an operation, not the root,
info, or path item. - Must be a string.
- Accepted value:
none. nonetells generated sync not to send inferred cursor, page, offset, or page-size query parameters for this endpoint, even when the operation exposes page-looking filters such aspage,page_size, orlimit.- Use for list endpoints that return the whole collection in one response and reject pagination keys as invalid filters.
- Unsupported values emit a warning and fall back to normal pagination detection.
Example:
paths:
/ip_addresses:
get:
operationId: listIPAddresses
x-pp-pagination: none
parameters:
- name: page_size
in: query
schema: {type: integer}
responses:
"200": {description: ok}
x-pp-safe-probe
Marks a mutation endpoint as explicitly safe for the Phase 1.9 reachability gate to call once as an optional second probe after the low-risk GET/body capture. This extension is consumed by Printing Press skill guidance rather than the Go OpenAPI parser; it documents author intent for agents reviewing a resolved spec.
Parsed field: none; consumed by skill guidance only
Rules:
- Optional.
- Must be on an operation, not the root,
info, or path item. - Accepts native boolean
trueonly. - Use only for idempotent or otherwise harmless operations for the real account being used.
- Absence or any value other than native boolean
truemeans mutation probing is not allowed; agents must stop after the GET/body reachability capture.
Example:
paths:
/webhooks/test:
post:
x-pp-safe-probe: true
responses:
"200": {description: ok}
x-happy-args
Declares live-dogfood happy-path fixture arguments for one operation. Use it
when generate-time synthesis cannot satisfy the endpoint contract: the generator
already emits pp:happy-args from parameter example, enum, default, and
format when every required input is derivable. Keep the extension for opaque
IDs, coordinates with no schema hint, or conditional query flags that generic
values cannot satisfy.
Parsed field: Endpoint.HappyArgs
Rules:
- Optional.
- Must be on an operation, not the root,
info, or path item. - Must be a string in the runtime annotation format consumed by
pp:happy-args. - Tokens are separated by unescaped semicolons. Escape a literal semicolon as
\;(write\\;inside a YAML double-quoted string).<label>=valueorlabel=valueoverlays synthesized positional args,--flag=valuereplaces the matching example flag or adds a new flag/value pair, and bare--flagtokens are treated as boolean--flag=true. - Negative numeric flag values are emitted in
--flag=-12.3form so Cobra does not parse the value as a shorthand flag cluster. - Empty or whitespace-only values behave the same as absence.
Example:
paths:
/referents:
get:
operationId: listReferents
x-happy-args: "--song-id=378195"
responses:
"200": {description: ok}
x-happy-stdin
Declares a JSON request-body fixture for a live-dogfood command that reads its
input from stdin. The generator emits the fixture as the pp:happy-stdin
annotation, and the matrix pipes it to both the happy-path and JSON-fidelity
probes.
Parsed field: Endpoint.HappyStdin
Rules:
- Optional.
- Must be on an operation, not the root,
info, or path item. - Must be a string containing valid JSON.
- Commands that require stdin but do not declare this fixture are skipped with
reason
no-stdin-fixture; the runner never synthesizes a request body.
Example:
paths:
/widgets/inspect:
post:
x-happy-stdin: '{"name":"synthetic"}'
responses:
"200": {description: ok}
x-pp-sync-walker
Declares a hierarchical-walk dependency for a child endpoint. Synthesizes (or augments) a dependent-resource entry so the generator's existing parent-child sync machinery handles the fan-out — fetch the parent, extract the named field from each parent record, substitute it into the child path, fetch each child.
Use this when the auto-detected parent-child link in the profiler would miss your endpoint or pick the wrong parent. Common cases:
- The child path's placeholder name does not match a parent resource (e.g.
/games/{game_key}/leagues—game_keydoes not stem to "games" via the default_id/_keystripping). - The parent placeholder lives in a matrix or query parameter rather than the
path, so the path has no
{placeholder}for auto-detection to read. - The child path uses a parent field that is not the parent's primary key
(e.g. Yahoo Fantasy's
game_key, Reddit'ssubredditname).
Parsed field: Endpoint.Walker (a *spec.WalkerConfig)
Rules:
- Optional.
- Operation-level only. (No path-item-level form today.)
parent(string, required): the resource name to iterate. The parent must itself be a syncable resource (i.e., have a flat-list endpoint). Walkers pointing at non-syncable parents emit awarning:to stderr at generate time and are dropped.key_field(string, optional): the field to extract from each parent record for substitution into the child path. Defaults to the parent's primary key. Set this when the child path needs a non-PK field.key_param(string, optional): the child request slot that receives the extracted value. When that name is a{placeholder}in the child path, generated sync substitutes it into the URL. When it is not — a query parameter such asGET /messages?roomId=— generated sync writes the parent-row value into the requestparamsmap. Defaults to the first (and only){placeholder}in the child path when there is exactly one. Required explicitly when the child path has 0 or 2+ placeholders — the single-placeholder default would otherwise pick the wrong slot (or no slot at all). The generator warns and drops the walker when it's ambiguous andkey_paramis missing.- Walker-emitted dependents flow through the same
syncDependentResourcemachinery as auto-detected ones, so concurrency/retry/cursor/Upsert behavior is identical.
Internal YAML emits this as walker: on the endpoint with the same
sub-field names (parent, key_field, key_param). Both surfaces parse
to the same WalkerConfig struct.
Example:
paths:
/games:
get:
summary: List games (parent for the walker below)
responses:
"200": {description: ok}
/games/{game_key}/leagues:
get:
summary: List leagues for a game
x-pp-sync-walker:
parent: games
key_field: game_key
key_param: game_key
parameters:
- name: game_key
in: path
required: true
schema: {type: string}
responses:
"200": {description: ok}
/standings:
get:
summary: List standings for a game (query-param parent key)
x-pp-sync-walker:
parent: games
key_field: game_key
key_param: gameId
parameters:
- name: gameId
in: query
required: true
schema: {type: string}
responses:
"200": {description: ok}
x-sync-params
Query parameters applied only during generated sync. List/get endpoint
commands keep the API's documented defaults; sync uses these values so a
naive sync does not treat a default-filtered slice (status=open,
state=open) as the complete resource.
Parsed field: Endpoint.SyncParams
Rules:
- Optional. Absent the field, generated sync still auto-widens a
status/statequery param whose specdefault:isopenwhen the param's enum includesall(preferred) orany. That is the GitHub issues / Alpaca orders / Shopify orders idiom. Other defaults (tenant scope, sort,include_*) are not widened. - Operation-level only.
- Must be an object mapping parameter names to string values. Non-string values are stringified. Empty names or values are skipped. Malformed values warn and are ignored rather than failing the parse.
- Overlay order: spec
default:(with history-hiding widen) first, thenx-sync-params, then user--param/--resource-paramat runtime. Sync-owned paging/since/sort keys are skipped, same as spec defaults. - An explicit
x-sync-paramsentry for a key suppresses auto-widen for that key, includingstatus: openwhen the intended sync scope really is the open slice. - When a resource still has an unwidened
status/state=opendefault (noall/anyin the enum and no overlay) and sync stores 0 rows, generated sync emitssync_warningwith reasondefault_filter_hides_historyinstead of silent success-with-zero.
Internal YAML emits this as sync_params: on the endpoint with the same
map shape.
Example:
paths:
/v2/orders:
get:
summary: List orders
x-sync-params:
status: all
parameters:
- name: status
in: query
schema:
type: string
default: open
enum: [open, closed, all]
responses:
"200": {description: ok}
x-streaming
Declares that a spec has WebSocket-primary ingest with REST metadata refresh.
Internal YAML uses the same shape as streaming: at the top level.
Parsed field: APISpec.Streaming (spec.StreamingConfig)
Rules:
- Optional. When omitted, REST-only generation is unchanged.
transportmust currently bewebsocket.urlmust be an absolutews://orwss://URL.framingmay besingle_object_per_frameornewline_delimited_json. Empty defaults tosingle_object_per_frame.metadata.endpointis optional, but required when any metadata sub-field is declared.metadata.refresh_cadenceis a Go duration. Empty defaults to30s.metadata.statusesdefaults to[live, pending].metadata.primary_keydefaults toid.
When present, the generator emits live ws sync, live rest sync,
internal/wsclient, and local SQLite tables for stream frames, stream
metadata, and <api>_rebase_log lifecycle events.
Example:
x-streaming:
transport: websocket
url: "wss://api.example.com/v1/ws"
subscribe_shape: '{"type":"subscribe","channels":["events"]}'
framing: newline_delimited_json
metadata:
endpoint: "/v1/events"
refresh_cadence: 30s
statuses: [live, pending]
primary_key: event_id