Documentation
¶
Index ¶
- Constants
- Variables
- func AllAuthEnvVarSpecsInferred(envVarSpecs []AuthEnvVar) bool
- type APISpec
- func (s *APISpec) CountMCPTools() (total, public int)
- func (s *APISpec) EffectiveDisplayName() string
- func (s *APISpec) EffectiveEndpointAuth(resource Resource, endpoint Endpoint) (authType string, noAuth bool)
- func (s *APISpec) EffectiveHTTPTransport() string
- func (s *APISpec) EffectiveSubEndpointAuth(parent Resource, subResource Resource, endpoint Endpoint) (authType string, noAuth bool)
- func (s *APISpec) EffectiveTier(resource Resource, endpoint Endpoint) string
- func (s *APISpec) EffectiveTierConfig(resource Resource, endpoint Endpoint) (string, TierConfig, bool)
- func (s *APISpec) HasCostThrottling() bool
- func (s *APISpec) HasHTMLExtractMode(mode string) bool
- func (s *APISpec) HasHTMLExtraction() bool
- func (s *APISpec) HasResourceBaseURLOverride() bool
- func (s *APISpec) HasTierRouting() bool
- func (s *APISpec) IsSynthetic() bool
- func (s *APISpec) NormalizeAuthEnvVarSpecs()
- func (s *APISpec) UsesBrowserHTTP3Transport() bool
- func (s *APISpec) UsesBrowserHTTPTransport() bool
- func (s *APISpec) UsesBrowserManagedUserAgent() bool
- func (s *APISpec) Validate() error
- type AuthConfig
- type AuthEnvVar
- type AuthEnvVarKind
- type BearerRefreshConfig
- type CacheCommand
- type CacheConfig
- type ConfigSpec
- type Endpoint
- type ExtraCommand
- type HTMLExtract
- type Intent
- type IntentParam
- type IntentStep
- type MCPConfig
- type Pagination
- type Param
- type RequiredHeader
- type Resource
- type ResponseDef
- type ResponseDiscriminator
- type ShareConfig
- type ThrottleShape
- type ThrottlingConfig
- type TierConfig
- type TierRoutingConfig
- type TypeDef
- type TypeField
Constants ¶
const ( KindREST = "rest" // default; strict path-validity against the spec KindSynthetic = "synthetic" // multi-source / combo CLI; dogfood + scorecard relax path-validity )
Valid values for APISpec.Kind. A bare string with no const was the established convention for sibling fields (SpecSource, ClientPattern), but Kind is compared in production code at multiple sites, so the constant prevents typos from silently falling through to the default-rest path.
const ( HTTPTransportStandard = "standard" // default for official API clients HTTPTransportBrowserChrome = "browser-chrome" // Chrome-impersonated transport for browser-facing web surfaces HTTPTransportBrowserChromeH3 = "browser-chrome-h3" // Chrome-impersonated transport forced through HTTP/3 for stricter bot screens )
const ( ResponseFormatJSON = "json" ResponseFormatHTML = "html" )
const ( TierAuthTypeNone = "none" TierAuthTypeAPIKey = "api_key" TierAuthTypeBearerToken = "bearer_token" TierAuthPlacementHeader = "header" TierAuthPlacementQuery = "query" )
const ( HTMLExtractModePage = "page" HTMLExtractModeLinks = "links" HTMLExtractModeEmbeddedJSON = "embedded-json" )
const DefaultEmbeddedJSONScriptSelector = "script#__NEXT_DATA__"
DefaultEmbeddedJSONScriptSelector is the script-tag selector used when `html_extract.mode: embedded-json` is set without an explicit `script_selector`. Targets Next.js's pages-router `<script id="__NEXT_DATA__">` block — the most common shape and the one the food52 retro surfaced. Other SSR frameworks declare different selectors:
- Nuxt: script#__NUXT__
- Remix: script:contains("window.__remixContext") (use selector with type or id when available)
- Astro: site-specific; declare per spec
const DefaultOrchestrationThreshold = 50
DefaultOrchestrationThreshold is the endpoint-count above which the generator recommends (but does not require) code-orchestration. At 50+ endpoints, even intent-grouped tools tend to overflow an agent's usable context; code-orchestration covers the full surface in a pair of tools.
const OAuth2GrantAuthorizationCode = "authorization_code"
OAuth2GrantAuthorizationCode is the 3-legged user-OAuth flow (browser redirect, callback server, code exchange at TokenURL).
const OAuth2GrantClientCredentials = "client_credentials"
OAuth2GrantClientCredentials is the 2-legged server-to-server flow used by M2M APIs (Auth0 Management, Microsoft Graph daemon apps): POST to TokenURL with form-encoded client_id/client_secret, no user redirect.
Variables ¶
var ReservedCLIResourceNames = map[string]struct{}{
"agent_context": {},
"api_discovery": {},
"auth": {},
"auto_refresh": {},
"cache": {},
"channel_workflow": {},
"client": {},
"data_source": {},
"deliver": {},
"doctor": {},
"export": {},
"feedback": {},
"helpers": {},
"html_extract": {},
"import": {},
"profile": {},
"refresh_bearer": {},
"root": {},
"search": {},
"share_commands": {},
"sync": {},
"tail": {},
"types": {},
"which": {},
"workflow": {},
}
ReservedCLIResourceNames is the set of resource names that would collide with reserved single-file templates emitted into the printed CLI's internal/cli/ directory. Two collisions occur if a spec uses one of these as a resource name: the resource template's <name>.go overwrites the reserved file (losing helpers like FeedbackEndpointConfigured() from feedback.go), AND the resource's `new<Name>Cmd` cobra-builder shadows the reserved template's same-named function, breaking the build with a redeclaration error.
Renaming the file alone is not enough; the function-name collision still breaks the build. Reject at parse time and ask the author to rename the resource (e.g., `feedback` → `customer_feedback`, `auth` → `accounts`).
The contract is intentionally stable: removing an entry is allowed only when the corresponding reserved template is also removed from the generator.
var ReservedCobraUseNames = map[string]struct{}{
"about": {},
"agent-context": {},
"analytics": {},
"api": {},
"auth": {},
"completion": {},
"doctor": {},
"export": {},
"feedback": {},
"health": {},
"help": {},
"import": {},
"jobs": {},
"load": {},
"orphans": {},
"profile": {},
"refresh-bearer": {},
"search": {},
"share": {},
"similar": {},
"sql": {},
"stale": {},
"sync": {},
"tail": {},
"version": {},
"which": {},
"workflow": {},
}
ReservedCobraUseNames is the set of cobra command names registered at the top level of every printed CLI's root cobra tree. A spec resource whose name maps to one of these would shadow the framework command at runtime. Distinct from ReservedCLIResourceNames above: that set protects template-file overwrites (snake_case); this set protects cobra-Use shadowing (kebab-case). Hand-maintained; drift invariants enforced by tests in reserved_drift_test.go.
Functions ¶
func AllAuthEnvVarSpecsInferred ¶ added in v3.10.0
func AllAuthEnvVarSpecsInferred(envVarSpecs []AuthEnvVar) bool
Types ¶
type APISpec ¶
type APISpec struct {
Name string `yaml:"name" json:"name"`
// DisplayName is the human-readable brand name used in user-facing
// surfaces that aren't a kebab-case slug — Claude Desktop's connector
// list, MCPB manifest display_name, the MCP server's protocol-level
// name in `server.NewMCPServer(...)`. Authors can set it explicitly
// (e.g. "Company GOAT", "Cal.com", "PokéAPI") to preserve unusual
// capitalization or punctuation; when empty the generator title-cases
// Name as a fallback. The generate command also fills this from a
// matching catalog entry's display_name when available.
DisplayName string `yaml:"display_name,omitempty" json:"display_name,omitempty"`
// Description describes the API itself ("REST API for ordering pizza").
// It flows into generated docs and SKILL.md but is intentionally NOT used
// as the printed CLI's --help text; that's CLIDescription's job.
Description string `yaml:"description" json:"description"`
// CLIDescription, when set, becomes the printed CLI's root cobra command
// `Short:` text. Spec authors should phrase it as what the CLI does
// ("Order Seattle pizza from the terminal"), not what the API is. When
// blank the generator falls back to the research narrative's headline,
// then to a generic "Manage <api> resources via the <api> API". Adding
// this field eliminates a recurring manual rewrite step that the main
// skill used to instruct Claude to perform after every generation.
CLIDescription string `yaml:"cli_description,omitempty" json:"cli_description,omitempty"`
Version string `yaml:"version" json:"version"`
BaseURL string `yaml:"base_url" json:"base_url"`
BasePath string `yaml:"base_path,omitempty" json:"base_path,omitempty"`
// GraphQLEndpointPath is the path appended to BaseURL for GraphQL POSTs.
// REST specs leave it empty; GraphQL specs default it to "/graphql" but
// can override (e.g., Shopify's "/admin/api/{version}/graphql.json").
// The split exists because some GraphQL APIs put the endpoint behind a
// per-tenant subdomain or version segment, and the old single-BaseURL
// model couldn't represent that without hardcoding "/graphql" in the
// generated client.
GraphQLEndpointPath string `yaml:"graphql_endpoint_path,omitempty" json:"graphql_endpoint_path,omitempty"`
// EndpointTemplateVars lists placeholder names embedded in BaseURL or
// GraphQLEndpointPath as {var} (e.g., ["shop", "version"]). The
// generator emits per-variable env-var lookups in the printed CLI's
// config so users can resolve them at runtime. PR-1 carries this field
// as plumbing only; PR-2 wires the runtime substitution.
EndpointTemplateVars []string `yaml:"endpoint_template_vars,omitempty" json:"endpoint_template_vars,omitempty"`
Owner string `yaml:"owner,omitempty" json:"owner,omitempty"` // GitHub owner for import paths and Homebrew tap
Kind string `yaml:"kind,omitempty" json:"kind,omitempty"` // "rest" (default) or "synthetic" — synthetic CLIs aggregate multiple sources beyond the spec; dogfood's path-validity check is relaxed accordingly
SpecSource string `yaml:"spec_source,omitempty" json:"spec_source,omitempty"` // official, community, sniffed, docs — affects generated client defaults
ClientPattern string `yaml:"client_pattern,omitempty" json:"client_pattern,omitempty"` // rest (default), proxy-envelope — affects generated HTTP client
HTTPTransport string `yaml:"http_transport,omitempty" json:"http_transport,omitempty"` // standard (default for official APIs), browser-chrome, or browser-chrome-h3
ProxyRoutes map[string]string `yaml:"proxy_routes,omitempty" json:"proxy_routes,omitempty"` // path prefix → service name for proxy-envelope routing
BearerRefresh BearerRefreshConfig `yaml:"bearer_refresh,omitempty" json:"bearer_refresh,omitzero"` // live-source metadata for rotating public client bearer tokens
WebsiteURL string `yaml:"website_url,omitempty" json:"website_url,omitempty"` // product/company website (not the API base URL)
Category string `yaml:"category,omitempty" json:"category,omitempty"` // catalog category (e.g., productivity, developer-tools) — used for library install path
Auth AuthConfig `yaml:"auth" json:"auth"`
TierRouting TierRoutingConfig `yaml:"tier_routing,omitempty" json:"tier_routing,omitzero"`
RequiredHeaders []RequiredHeader `yaml:"required_headers,omitempty" json:"required_headers,omitempty"`
Config ConfigSpec `yaml:"config" json:"config"`
Resources map[string]Resource `yaml:"resources" json:"resources"`
Types map[string]TypeDef `yaml:"types" json:"types"`
ExtraCommands []ExtraCommand `yaml:"extra_commands,omitempty" json:"extra_commands,omitempty"` // hand-written cobra commands declared so SKILL.md can document them; spec-only metadata, no code generated
Cache CacheConfig `yaml:"cache,omitempty" json:"cache"` // cache freshness + auto-refresh config; when enabled, generated read commands auto-refresh stale local data before serving
MCP MCPConfig `yaml:"mcp,omitempty" json:"mcp"` // MCP server generation config; when unset, the emitted MCP binary is stdio-only (today's default). Opting into http adds a --transport/--addr flag surface so the same binary can serve cloud-hosted agents.
Throttling ThrottlingConfig `yaml:"throttling,omitempty" json:"throttling"` // cost-based throttling config; when Enabled with a recognized Shape, the generator emits a ThrottleState (generic harness) plus a per-Shape parser that reads the API's cost bucket. Only the "shopify" Shape ships in v1.
}
func ParseBytes ¶
func (*APISpec) CountMCPTools ¶
CountMCPTools counts total endpoints and public (NoAuth) endpoints across all resources and sub-resources.
func (*APISpec) EffectiveDisplayName ¶
EffectiveDisplayName returns the human-readable brand name for this CLI. Explicit DisplayName wins (preserves "Company GOAT", "Cal.com", "PokéAPI" shape); otherwise we title-case Name. Used by the MCP server's protocol name, the MCPB manifest, and any surface that wants a friendly identity instead of the kebab-case slug.
func (*APISpec) EffectiveEndpointAuth ¶ added in v3.9.0
func (*APISpec) EffectiveHTTPTransport ¶
func (*APISpec) EffectiveSubEndpointAuth ¶ added in v3.9.0
func (*APISpec) EffectiveTier ¶ added in v3.9.0
func (*APISpec) EffectiveTierConfig ¶ added in v3.9.0
func (*APISpec) HasCostThrottling ¶ added in v3.1.0
HasCostThrottling reports whether the spec opts into cost-based throttling primitives. Used by the generator to gate emission of throttle.go and the related conditional blocks in client.go / graphql_client.go / root.go. Specs without this flag regenerate byte-identical to the pre-PR-3 output.
func (*APISpec) HasHTMLExtractMode ¶
HasHTMLExtractMode reports whether any endpoint in the spec declares html_extract with the given effective mode. Used by the html_extract template to gate per-mode helpers: a CLI that uses only HTMLExtractModeEmbeddedJSON does not need the page-mode DOM walkers or links-mode anchor parsing, and vice versa.
`mode` should be one of the HTMLExtractMode* constants. Modes that don't appear in any endpoint return false; modes are matched by their effective value (so an unset Mode counts as page).
func (*APISpec) HasHTMLExtraction ¶
func (*APISpec) HasResourceBaseURLOverride ¶
HasResourceBaseURLOverride reports whether any resource (top-level or nested sub-resource) declares a BaseURL override. Used by the client template to gate the absolute-URL detection branch — specs that don't opt in regenerate byte-identically.
func (*APISpec) HasTierRouting ¶ added in v3.9.0
func (*APISpec) IsSynthetic ¶
IsSynthetic reports whether this spec declares a multi-source / combo CLI where hand-built commands intentionally go beyond the spec. Dogfood skips strict path-validity and scorecard marks path_validity as unscored.
func (*APISpec) NormalizeAuthEnvVarSpecs ¶ added in v3.10.0
func (s *APISpec) NormalizeAuthEnvVarSpecs()
func (*APISpec) UsesBrowserHTTP3Transport ¶
func (*APISpec) UsesBrowserHTTPTransport ¶
func (*APISpec) UsesBrowserManagedUserAgent ¶
type AuthConfig ¶
type AuthConfig struct {
Type string `yaml:"type" json:"type"` // api_key, oauth2, bearer_token, cookie, composed, session_handshake, none
Header string `yaml:"header" json:"header"`
Format string `yaml:"format" json:"format"`
EnvVars []string `yaml:"env_vars" json:"env_vars"`
EnvVarSpecs []AuthEnvVar `yaml:"env_var_specs,omitempty" json:"env_var_specs,omitempty"`
Optional bool `yaml:"optional,omitempty" json:"optional,omitempty"` // true when the key enhances a subset of features (e.g., USDA nutrition backfill) rather than gating core functionality; doctor treats unconfigured optional auth as INFO not FAIL and README frames the section as "Optional"
Scheme string `yaml:"scheme,omitempty" json:"scheme,omitempty"` // OpenAPI security scheme name
In string `yaml:"in,omitempty" json:"in,omitempty"` // header, query, cookie
KeyURL string `yaml:"key_url,omitempty" json:"key_url,omitempty"` // URL where users can register for an API key
Title string `yaml:"title,omitempty" json:"title,omitempty"` // user-facing credential field title for install/config surfaces
Description string `yaml:"description,omitempty" json:"description,omitempty"`
AuthorizationURL string `yaml:"authorization_url,omitempty" json:"authorization_url,omitempty"`
TokenURL string `yaml:"token_url,omitempty" json:"token_url,omitempty"`
Scopes []string `yaml:"scopes,omitempty" json:"scopes,omitempty"`
CookieDomain string `yaml:"cookie_domain,omitempty" json:"cookie_domain,omitempty"` // domain to read browser cookies from (e.g. ".notion.so")
Cookies []string `yaml:"cookies,omitempty" json:"cookies,omitempty"` // named cookies to extract for composed auth (e.g. ["customerId", "authToken"])
Inferred bool `yaml:"inferred,omitempty" json:"inferred,omitempty"` // true when auth was inferred from spec description, not declared in securitySchemes
// VerifyPath is an optional path appended to base_url that the doctor
// command probes to validate credentials. Set this to a known-good
// authenticated GET endpoint that returns 2xx for any valid token (e.g.
// "/me?fields=id" for Meta, "/v1/account" for Stripe, "/user" for GitHub,
// "/users/@me" for Discord). When empty, doctor falls back to probing
// the bare base URL and classifies 401/403 as "inconclusive" rather than
// "invalid", because many versioned API roots return 401 regardless of
// token validity (the path isn't a routed endpoint, but the gateway
// still demands credentials in a meaningful context).
VerifyPath string `yaml:"verify_path,omitempty" json:"verify_path,omitempty"`
// Browser-session verification fields. Used when a website-facing CLI
// depends on browser-derived cookies or clearance state for its required
// happy path. The generator emits validation and proof handling, and the
// shipcheck pipeline treats a missing proof as a blocker.
RequiresBrowserSession bool `yaml:"requires_browser_session,omitempty" json:"requires_browser_session,omitempty"`
BrowserSessionReason string `yaml:"browser_session_reason,omitempty" json:"browser_session_reason,omitempty"`
BrowserSessionValidationPath string `yaml:"browser_session_validation_path,omitempty" json:"browser_session_validation_path,omitempty"`
BrowserSessionValidationMethod string `yaml:"browser_session_validation_method,omitempty" json:"browser_session_validation_method,omitempty"`
// Session-handshake fields. Used only when Type == "session_handshake".
// The pattern: GET BootstrapURL to seed cookies → GET TokenURL to receive
// an anti-CSRF token (the "crumb" on Yahoo Finance, similarly named on
// Walmart, some streaming APIs, Facebook's internal graph) → pass that
// token on every subsequent data request as TokenParamName in TokenParamIn.
// The generator emits a cookie jar, disk-persisted session file, and auto-
// invalidation on InvalidateOnStatus responses.
BootstrapURL string `yaml:"bootstrap_url,omitempty" json:"bootstrap_url,omitempty"` // optional GET to seed cookies before token fetch (e.g. "https://fc.yahoo.com/")
SessionTokenURL string `yaml:"session_token_url,omitempty" json:"session_token_url,omitempty"` // endpoint that returns the token (e.g. "https://query2.finance.yahoo.com/v1/test/getcrumb"); distinct from TokenURL (OAuth) to avoid conflation
TokenFormat string `yaml:"token_format,omitempty" json:"token_format,omitempty"` // "text" (raw body) or "json" (extract via TokenJSONPath); default "text"
TokenJSONPath string `yaml:"token_json_path,omitempty" json:"token_json_path,omitempty"` // when TokenFormat is "json", dot-path to the token field (e.g. "data.crumb")
TokenParamName string `yaml:"token_param_name,omitempty" json:"token_param_name,omitempty"` // parameter name to attach to requests (e.g. "crumb")
TokenParamIn string `yaml:"token_param_in,omitempty" json:"token_param_in,omitempty"` // "query" or "header"; default "query"
InvalidateOnStatus []int `yaml:"invalidate_on_status,omitempty" json:"invalidate_on_status,omitempty"` // HTTP status codes that should invalidate the cached token and re-bootstrap (e.g. [401, 403])
SessionTTLHours int `yaml:"session_ttl_hours,omitempty" json:"session_ttl_hours,omitempty"` // how long to trust a cached session (default 24)
// OAuth2Grant selects the OAuth2 sub-flow when Type=="oauth2". Defaults
// to authorization_code; ignored for non-oauth2 types. Read via
// EffectiveOAuth2Grant() so the default lives in one place.
OAuth2Grant string `yaml:"oauth2_grant,omitempty" json:"oauth2_grant,omitempty"`
}
func (*AuthConfig) CanonicalEnvVar ¶ added in v3.10.0
func (c *AuthConfig) CanonicalEnvVar() *AuthEnvVar
CanonicalEnvVar returns the deterministic canonical entry for human-prose surfaces.
func (AuthConfig) EffectiveOAuth2Grant ¶ added in v3.8.0
func (c AuthConfig) EffectiveOAuth2Grant() string
EffectiveOAuth2Grant returns the configured OAuth2 grant type, defaulting to OAuth2GrantAuthorizationCode when unset.
func (*AuthConfig) IsAuthEnvVarORCase ¶ added in v3.10.0
func (c *AuthConfig) IsAuthEnvVarORCase() bool
IsAuthEnvVarORCase reports whether all EnvVarSpecs are non-required per_call vars. In this shape, no single var is the canonical credential; the runtime tries each in turn and returns the first non-empty value. Returns false when EnvVarSpecs has fewer than 2 entries, any entry is Required, or any entry is not Kind=per_call.
func (*AuthConfig) NormalizeEnvVarSpecs ¶ added in v3.10.0
func (c *AuthConfig) NormalizeEnvVarSpecs(context string)
type AuthEnvVar ¶ added in v3.10.0
type AuthEnvVar struct {
Name string `yaml:"name" json:"name"`
Kind AuthEnvVarKind `yaml:"kind,omitempty" json:"kind,omitempty"`
Required bool `yaml:"required" json:"required"`
Sensitive bool `yaml:"sensitive" json:"sensitive"` // orthogonal to Kind; drives redaction policy
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Inferred bool `yaml:"inferred,omitempty" json:"inferred,omitempty"`
}
func (AuthEnvVar) EffectiveKind ¶ added in v3.10.0
func (v AuthEnvVar) EffectiveKind() AuthEnvVarKind
EffectiveKind treats legacy empty kinds as per-call credentials.
func (AuthEnvVar) IsRequestCredential ¶ added in v3.10.0
func (v AuthEnvVar) IsRequestCredential() bool
IsRequestCredential reports whether this env var can satisfy request auth.
func (AuthEnvVar) MarkdownDescription ¶ added in v3.10.0
func (v AuthEnvVar) MarkdownDescription() string
type AuthEnvVarKind ¶ added in v3.10.0
type AuthEnvVarKind string
const ( AuthEnvVarKindPerCall AuthEnvVarKind = "per_call" AuthEnvVarKindAuthFlowInput AuthEnvVarKind = "auth_flow_input" AuthEnvVarKindHarvested AuthEnvVarKind = "harvested" )
func (AuthEnvVarKind) SensitivePlaceholder ¶ added in v3.10.0
func (k AuthEnvVarKind) SensitivePlaceholder() string
type BearerRefreshConfig ¶ added in v3.9.0
type BearerRefreshConfig struct {
BundleURL string `yaml:"bundle_url,omitempty" json:"bundle_url,omitempty"`
Pattern string `yaml:"pattern,omitempty" json:"pattern,omitempty"`
}
func (BearerRefreshConfig) Enabled ¶ added in v3.9.0
func (c BearerRefreshConfig) Enabled() bool
type CacheCommand ¶
type CacheCommand struct {
Name string `yaml:"name" json:"name"` // lowercase cobra command path, without the binary name (e.g., "today" or "insights stale")
Resources []string `yaml:"resources" json:"resources"` // resource names to refresh before serving the command
}
CacheCommand declares that a hand-authored command path reads one or more syncable resources and should participate in the generated freshness hook.
type CacheConfig ¶
type CacheConfig struct {
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"` // master switch; when false, freshness helpers and pre-run refresh hook are not emitted
StaleAfter string `yaml:"stale_after,omitempty" json:"stale_after,omitempty"` // default duration after which any resource's last_synced_at is considered stale (e.g., "6h"). Blank means runtime default (6h).
RefreshTimeout string `yaml:"refresh_timeout,omitempty" json:"refresh_timeout,omitempty"` // max wall-clock the pre-run refresh may block the command (e.g., "30s"). On timeout the command serves stale data with a stderr warning. Blank means runtime default (30s).
EnvOptOut string `yaml:"env_opt_out,omitempty" json:"env_opt_out,omitempty"` // env var name that disables auto-refresh when set to "1" (e.g., LINEAR_NO_AUTO_REFRESH). Blank lets the template derive {{upper name}}_NO_AUTO_REFRESH.
Resources map[string]string `yaml:"resources,omitempty" json:"resources,omitempty"` // per-resource override of stale_after (e.g., quotes: "5m", channels: "24h"). Resources not listed inherit StaleAfter.
Commands []CacheCommand `yaml:"commands,omitempty" json:"commands,omitempty"` // optional custom command-path coverage for hand-authored store-backed reads. Generated resource commands are covered automatically.
}
CacheConfig gates the auto-refresh machinery emitted into a printed CLI. Opt-in — CLIs whose local store is per-user state (carts, drafts) should leave Enabled at its zero value so reads never silently replace the user's state with a snapshot from a different session.
StaleAfter and RefreshTimeout are strings parsed to time.Duration at CLI runtime; keeping them as strings lets spec authors write "6h" or "30s" and preserves the yaml-level representation for round-trip tooling.
type ConfigSpec ¶
type Endpoint ¶
type Endpoint struct {
Method string `yaml:"method" json:"method"`
Path string `yaml:"path" json:"path"`
Description string `yaml:"description" json:"description"`
Params []Param `yaml:"params" json:"params"`
Body []Param `yaml:"body" json:"body"`
Response ResponseDef `yaml:"response" json:"response"`
ResponseFormat string `yaml:"response_format,omitempty" json:"response_format,omitempty"` // json (default) or html
HTMLExtract *HTMLExtract `yaml:"html_extract,omitempty" json:"html_extract,omitempty"` // extraction options when response_format is html
Pagination *Pagination `yaml:"pagination" json:"pagination"`
ResponsePath string `yaml:"response_path,omitempty" json:"response_path,omitempty"` // path to extract data array from response (e.g., "data", "results.items")
Meta map[string]string `yaml:"meta,omitempty" json:"meta,omitempty"` // per-endpoint metadata (e.g., source_tier, source_count from crowd-sniff)
HeaderOverrides []RequiredHeader `yaml:"header_overrides,omitempty" json:"header_overrides,omitempty"` // per-endpoint header overrides (e.g., different api-version)
NoAuth bool `yaml:"no_auth,omitempty" json:"no_auth,omitempty"` // true when the endpoint does not require authentication
Tier string `yaml:"tier,omitempty" json:"tier,omitempty"`
// IDField is the resolved primary-key field name for items returned by this
// endpoint, populated either by a path-item-level `x-resource-id` extension
// or, for OpenAPI specs, by walking the response schema (id → name → first
// required scalar). Empty when no key could be resolved; templates fall back
// to runtime list scanning. Internal YAML specs may set this directly.
IDField string `yaml:"id_field,omitempty" json:"id_field,omitempty"`
// Critical flags this endpoint's resource as essential to a sync run. When
// true, a per-resource failure is treated as a hard failure even under the
// new (non-strict) exit-code policy. Populated from the path-item-level
// `x-critical` extension on OpenAPI specs; defaults to false.
Critical bool `yaml:"critical,omitempty" json:"critical,omitempty"`
Alias string `yaml:"-" json:"-"` // computed, not from YAML
}
func (Endpoint) EffectiveResponseFormat ¶
func (Endpoint) UsesHTMLResponse ¶
type ExtraCommand ¶
type ExtraCommand struct {
Name string `yaml:"name" json:"name"` // command path, e.g. "boxscore" or "tv airing-today"
Description string `yaml:"description" json:"description"` // one-line description rendered after a dash
Args string `yaml:"args,omitempty" json:"args,omitempty"` // optional positional arg signature, e.g. "<event_id>" or "<team1> <team2>"
}
ExtraCommand declares a hand-written cobra command so the SKILL.md Command Reference can list it alongside spec-driven resources. The generator does not emit code for these — authors hand-write the command in internal/cli/. Without this declaration the SKILL.md template only sees .Resources and silently omits hand-written commands, which is the drift class that motivated this field.
type HTMLExtract ¶
type HTMLExtract struct {
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"` // page (default), links, or embedded-json
LinkPrefixes []string `yaml:"link_prefixes,omitempty" json:"link_prefixes,omitempty"` // URL path prefixes to keep when extracting links (mode: links)
Limit int `yaml:"limit,omitempty" json:"limit,omitempty"` // max links to return; defaults at runtime (mode: links)
// ScriptSelector identifies the <script> tag containing serialized
// page state when mode is embedded-json. Defaults to
// DefaultEmbeddedJSONScriptSelector ("script#__NEXT_DATA__") when
// empty — the most common Next.js pages-router shape. Other SSR
// frameworks declare per-site selectors (Nuxt: "script#__NUXT__",
// etc.). Selector grammar is the simple "tag" / "tag#id" form
// supported by the runtime extractor; expand later if needed.
ScriptSelector string `yaml:"script_selector,omitempty" json:"script_selector,omitempty"`
// JSONPath is a dot-notation walk into the parsed JSON inside the
// matched script tag (mode: embedded-json). For Next.js the typical
// value is "props.pageProps.<route-data>"; for Nuxt "data.<route>".
// Empty path returns the entire parsed JSON. Missing intermediate
// keys yield a typed-empty result rather than an error.
JSONPath string `yaml:"json_path,omitempty" json:"json_path,omitempty"`
}
func (*HTMLExtract) EffectiveMode ¶
func (h *HTMLExtract) EffectiveMode() string
func (*HTMLExtract) EffectiveScriptSelector ¶
func (h *HTMLExtract) EffectiveScriptSelector() string
EffectiveScriptSelector returns the configured script selector, or the default Next.js pages-router selector when unset. Only meaningful when EffectiveMode() == HTMLExtractModeEmbeddedJSON.
type Intent ¶
type Intent struct {
Name string `yaml:"name" json:"name"` // MCP tool name; snake_case, unique within the spec
Description string `yaml:"description" json:"description"` // agent-facing description; should name the *intent*, not the endpoints
Params []IntentParam `yaml:"params,omitempty" json:"params,omitempty"` // input parameters the intent tool exposes to MCP callers
Steps []IntentStep `yaml:"steps" json:"steps"` // ordered list of endpoint calls; at least one required
Returns string `yaml:"returns,omitempty" json:"returns,omitempty"` // capture name whose value is returned to the caller; defaults to the last step's capture when blank
}
Intent declares an MCP tool that composes multiple endpoint calls into a single agent-facing operation. The generator emits one handler per intent that resolves bindings, calls each endpoint in order against the CLI's existing HTTP client, and returns the captured value named by Returns.
Binding syntax — each value in a step's Bind map is a string expression:
- `${input.<name>}` resolves to the MCP request's input parameter
- `${<capture>.<field>}` resolves to a field of a previous step's captured JSON response
- anything else is used as a string literal
Type coercion: all bound values are rendered as strings at runtime; JSON bodies for POST/PUT/PATCH are built from the resolved map. The intent surface intentionally does not support array indexing, conditional branching, or looping in v1 — those escapes belong in U3's code-orchestration pattern, not here.
type IntentParam ¶
type IntentParam struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type"` // one of: string, integer, boolean
Required bool `yaml:"required,omitempty" json:"required,omitempty"`
Description string `yaml:"description" json:"description"`
}
IntentParam mirrors a narrow slice of the endpoint Param type. Kept small by design: intents are compositions, so parameter shapes should be simple string/int/bool inputs that bind into step calls, not full nested bodies.
type IntentStep ¶
type IntentStep struct {
Endpoint string `yaml:"endpoint" json:"endpoint"` // dotted path into the spec's resources, e.g., "messages.get_thread"
Bind map[string]string `yaml:"bind,omitempty" json:"bind,omitempty"` // map of endpoint param name -> binding expression
Capture string `yaml:"capture,omitempty" json:"capture,omitempty"` // name to bind this step's response under for subsequent steps / returns; must be unique within the intent
}
IntentStep declares one endpoint call inside an intent. Endpoint references are `resource.endpoint` or `resource.sub_resource.endpoint`; the validator confirms the path resolves against APISpec.Resources at spec load.
type MCPConfig ¶
type MCPConfig struct {
Transport []string `yaml:"transport,omitempty" json:"transport,omitempty"` // allowed transports the generated binary compiles support for; empty == [stdio]. Runtime transport is chosen via the --transport flag and PP_MCP_TRANSPORT env.
Addr string `yaml:"addr,omitempty" json:"addr,omitempty"` // default bind address for the http transport (e.g., ":7777"). Blank means runtime default (":7777"). Ignored unless http is in Transport.
Intents []Intent `yaml:"intents,omitempty" json:"intents,omitempty"` // higher-level MCP tools that compose multiple endpoint calls. The agent sees one intent tool; the generator emits a handler that fans out to the declared endpoints sequentially. Anti-pattern to fight: one-tool-per-endpoint mirrors that force agents to stitch primitives.
EndpointTools string `yaml:"endpoint_tools,omitempty" json:"endpoint_tools,omitempty"` // "visible" (default) keeps the per-endpoint MCP tools; "hidden" suppresses them so only intents + generator-emitted tools appear. Use "hidden" when intents fully cover the surface and raw endpoints would be noise.
Orchestration string `yaml:"orchestration,omitempty" json:"orchestration,omitempty"` // "endpoint-mirror" (default), "intent", or "code". Code-orchestration emits a thin <api>_search + <api>_execute pair covering the full surface in ~1K tokens; used for very large APIs where even intent-grouped tools would overflow context. Mutually exclusive with endpoint-mirror at emission time.
OrchestrationThreshold int `yaml:"orchestration_threshold,omitempty" json:"orchestration_threshold,omitempty"` // endpoint count above which the generator warns that code-orchestration would be a better default. Zero means use the built-in default (50).
}
MCPConfig declares how the generated MCP server binary is shaped. When empty the generator emits today's behavior: a stdio-only server via server.ServeStdio. Opting http into Transport adds a --transport flag (stdio|http) and, for http, an --addr flag so the same binary can also serve an HTTP streamable transport.
Rationale: stdio-only servers can only reach clients that share a filesystem and can spawn a subprocess. Cloud-hosted agents (hosted Claude Code sessions, Managed Agents, web clients) cannot, so they need a remote transport option. Declaring transports in the spec rather than inferring at generate time keeps the decision visible and reviewable in the published CLI's source spec.
Allowed Transport values: "stdio", "http". An empty list is treated as ["stdio"] for backward compatibility. Unknown values are rejected at spec load; this prevents silent drift when new transports are introduced.
func (MCPConfig) EffectiveOrchestrationThreshold ¶
EffectiveOrchestrationThreshold returns the resolved threshold, applying the built-in default when the spec leaves it unset.
func (MCPConfig) EffectiveTransports ¶
EffectiveTransports returns the transports the generated binary should support, defaulting to stdio when none are declared. Using this helper from templates and the generator avoids sprinkling the default in two places.
func (MCPConfig) HasTransport ¶
HasTransport reports whether t is among the effective transports for this MCPConfig. Case-insensitive on the comparison since spec authors may write "HTTP" and the generator normalizes to lowercase at validation time.
func (MCPConfig) IsCodeOrchestration ¶
IsCodeOrchestration reports whether this MCP config opts into the code-orchestration thin surface. Templates branch on this to emit only <api>_search + <api>_execute instead of the endpoint-mirror.
type Pagination ¶
type Pagination struct {
Type string `yaml:"type" json:"type"` // cursor, offset, page_token
LimitParam string `yaml:"limit_param" json:"limit_param"` // query param name for page size (limit, maxResults, pageSize)
CursorParam string `yaml:"cursor_param" json:"cursor_param"` // query param name for cursor (after, pageToken, offset)
NextCursorPath string `yaml:"next_cursor_path" json:"next_cursor_path"` // response field with next cursor (nextPageToken, cursor)
HasMoreField string `yaml:"has_more_field" json:"has_more_field"` // response field indicating more pages (has_more)
}
type Param ¶
type Param struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type"`
Required bool `yaml:"required" json:"required"`
Positional bool `yaml:"positional" json:"positional"`
PathParam bool `yaml:"path_param,omitempty" json:"path_param,omitempty"` // true for path params rendered as flags (e.g., pagination)
Default any `yaml:"default" json:"default"`
Description string `yaml:"description" json:"description"`
Fields []Param `yaml:"fields" json:"fields"` // for nested objects
Enum []string `yaml:"enum,omitempty" json:"enum,omitempty"` // enum constraints for the parameter
Format string `yaml:"format,omitempty" json:"format,omitempty"` // OpenAPI format hints (date-time, email, uri, etc.)
// IdentName, when set, overrides Name for Go identifier and CLI flag
// derivation (camel/flagName). Name remains the wire-side parameter name
// used in URLs, JSON keys, and path substitution. Populated by the
// generator's flag-collision dedup pass when two params on the same
// endpoint would otherwise produce identical Go identifiers or CLI flag
// names — for example Twilio's StartTime/StartTime>/StartTime< all
// collapsing to "StartTime" through camelization. Most params leave this
// empty and template helpers fall back to Name.
IdentName string `yaml:"-" json:"-"`
}
type RequiredHeader ¶
type RequiredHeader struct {
Name string `yaml:"name" json:"name"`
Value string `yaml:"value" json:"value"`
}
RequiredHeader represents a non-auth header that the API requires on most requests (e.g., cal-api-version, Stripe-Version, anthropic-version). Detected automatically from OpenAPI specs when a required header parameter appears on >80% of operations.
type Resource ¶
type Resource struct {
Description string `yaml:"description" json:"description"`
Path string `yaml:"path,omitempty" json:"path,omitempty"` // base path for operations shorthand (e.g., /api/items)
Operations []string `yaml:"operations,omitempty" json:"operations,omitempty"` // shorthand: list, get, create, update, delete, search
// BaseURL overrides the spec-level BaseURL for this resource's
// endpoints. Fixed at generation time. Incompatible with the
// proxy-envelope client pattern, which POSTs every request to a
// single URL.
BaseURL string `yaml:"base_url,omitempty" json:"base_url,omitempty"`
Tier string `yaml:"tier,omitempty" json:"tier,omitempty"`
Endpoints map[string]Endpoint `yaml:"endpoints" json:"endpoints"`
SubResources map[string]Resource `yaml:"sub_resources,omitempty" json:"sub_resources,omitempty"`
}
type ResponseDef ¶
type ResponseDef struct {
Type string `yaml:"type" json:"type"` // object, array
Item string `yaml:"item" json:"item"` // type name
Discriminator *ResponseDiscriminator `yaml:"discriminator,omitempty" json:"discriminator,omitempty"`
}
type ResponseDiscriminator ¶ added in v3.5.0
type ShareConfig ¶
type ShareConfig struct {
}
ShareConfig gates the git-backed snapshot share surface emitted into a printed CLI. When Enabled, the generator emits an internal/share package plus a `share` cobra command (publish, subscribe, export, import). Share is off by default because it is a multi-user feature and most CLIs are single-user; enabling also requires an explicit SnapshotTables allowlist to prevent accidental export of auth or per-user state.
type ThrottleShape ¶ added in v3.1.0
type ThrottleShape string
ThrottleShape names the API-specific cost-bucket parser the generator wires into the GraphQL client. The generic harness (bucket math, retry, --throttle-mode flag) is shape-agnostic; only the parser that reads the API's response into a ThrottleStatus differs per shape, because every API surfaces its calculated cost in a different place. Adding a new shape means: (1) add a constant here, (2) extend validateThrottling to accept it, (3) add the parser block to graphql_client.go.tmpl gated on `eq .Throttling.Shape "<name>"`. No core code changes.
const ( // ThrottleShapeShopify reads `extensions.cost.throttleStatus.{maximumAvailable, // currentlyAvailable,restoreRate}` from each GraphQL response. This is the // only shape supported in v1; GitHub's queryable `rateLimit` field and // Datadog's header-based cost limits will need their own shapes (and the // GitHub case will need a query-rewrite layer, since rateLimit is a schema // field rather than a response extension). ThrottleShapeShopify ThrottleShape = "shopify" )
type ThrottlingConfig ¶ added in v3.1.0
type ThrottlingConfig struct {
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
Shape ThrottleShape `yaml:"shape,omitempty" json:"shape,omitempty"`
}
ThrottlingConfig opts a printed CLI into the cost-based throttling primitives. Enabled turns the surface on (--throttle-mode flag, ThrottleState, budget projection, retry helper); default off so existing CLIs regenerate byte-identically when this field is unset. Shape selects the per-API parser and is required when Enabled is true; see ThrottleShape for the valid values and how to add new ones.
Authors opt in by writing `throttling: { enabled: true, shape: shopify }`.
type TierConfig ¶ added in v3.9.0
type TierConfig struct {
BaseURL string `yaml:"base_url,omitempty" json:"base_url,omitempty"`
Auth AuthConfig `yaml:"auth,omitempty" json:"auth,omitzero"`
AllowCrossHostAuth bool `yaml:"allow_cross_host_auth,omitempty" json:"allow_cross_host_auth,omitempty"`
}
type TierRoutingConfig ¶ added in v3.9.0
type TierRoutingConfig struct {
DefaultTier string `yaml:"default_tier,omitempty" json:"default_tier,omitempty"`
Tiers map[string]TierConfig `yaml:"tiers,omitempty" json:"tiers,omitempty"`
}
type TypeField ¶
type TypeField struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type"`
Enum []string `yaml:"enum,omitempty" json:"enum,omitempty"`
// Selection is an optional GraphQL sub-selection rendered when this field
// is used in a generated GraphQL query. It lets wrapper specs keep the Go
// field simple (for example, totalPriceSet as json.RawMessage) while still
// issuing valid nested GraphQL selections.
Selection string `yaml:"selection,omitempty" json:"selection,omitempty"`
}