[object Object]

← back to Cli Printing Press

docs(skill): add known-specs registry and spec-format reference

c547fa5754da06ed5c1b08ead4a357238714e3ea · 2026-03-23 15:28:18 -0700 · Matt Van Horn

Known-specs registry with 12 verified OpenAPI spec URLs (Petstore, Stytch,
Discord, Stripe, Twilio, SendGrid, GitHub, DigitalOcean, Asana, Square,
HubSpot, Front). Spec-format reference documents the internal YAML schema
with annotated Stytch example for agent-generated specs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files touched

Diff

commit c547fa5754da06ed5c1b08ead4a357238714e3ea
Author: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Date:   Mon Mar 23 15:28:18 2026 -0700

    docs(skill): add known-specs registry and spec-format reference
    
    Known-specs registry with 12 verified OpenAPI spec URLs (Petstore, Stytch,
    Discord, Stripe, Twilio, SendGrid, GitHub, DigitalOcean, Asana, Square,
    HubSpot, Front). Spec-format reference documents the internal YAML schema
    with annotated Stytch example for agent-generated specs.
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 skills/printing-press/references/known-specs.md |  35 ++++
 skills/printing-press/references/spec-format.md | 234 ++++++++++++++++++++++++
 2 files changed, 269 insertions(+)

diff --git a/skills/printing-press/references/known-specs.md b/skills/printing-press/references/known-specs.md
new file mode 100644
index 00000000..9ee1f4fd
--- /dev/null
+++ b/skills/printing-press/references/known-specs.md
@@ -0,0 +1,35 @@
+# Known OpenAPI Specs
+
+APIs with verified, publicly accessible OpenAPI specifications. The printing-press skill checks this registry before searching the web.
+
+## How to use
+
+1. Search this file for the API name
+2. If found, download the spec URL directly
+3. If not found, proceed to web search
+
+## Registry
+
+| API | Spec URL | Format | OpenAPI Version | Verified |
+|-----|----------|--------|-----------------|----------|
+| Petstore | https://petstore3.swagger.io/api/v3/openapi.yaml | YAML | 3.0.x | Yes |
+| Stytch | https://raw.githubusercontent.com/stytchauth/stytch-openapi/main/openapi.yml | YAML | 3.0.x | Yes |
+| Discord | https://raw.githubusercontent.com/discord/discord-api-spec/main/specs/openapi.json | JSON | 3.1.0 | Yes |
+| Stripe | https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json | JSON | 3.0.x | Yes |
+| Twilio | https://raw.githubusercontent.com/twilio/twilio-oai/main/spec/json/twilio_api_v2010.json | JSON | 3.0.x | Yes |
+| SendGrid | https://raw.githubusercontent.com/twilio/sendgrid-oai/main/spec/json/sendgrid_oai.json | JSON | 3.0.x | Yes |
+| GitHub | https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.2022-11-28.yaml | YAML | 3.0.x | Yes |
+| GitLab | Skipped (no stable public raw OpenAPI spec URL confirmed) | N/A | N/A | No |
+| DigitalOcean | https://raw.githubusercontent.com/digitalocean/openapi/main/specification/DigitalOcean-public.v2.yaml | YAML | 3.0.x | Yes |
+| Asana | https://raw.githubusercontent.com/Asana/openapi/main/defs/asana_oas.yaml | YAML | 3.0.x | Yes |
+| Square | https://raw.githubusercontent.com/square/square-openapi/master/openapi.json | JSON | 3.0.x | Yes |
+| Notion | Skipped (official public OpenAPI spec URL not confirmed) | N/A | N/A | No |
+| Linear | Skipped (official API is GraphQL; public OpenAPI spec URL not confirmed) | N/A | N/A | No |
+| HubSpot | https://raw.githubusercontent.com/HubSpot/HubSpot-public-api-spec-collection/main/PublicApiSpecs/CRM/Contacts/Rollouts/424/v3/contacts.json | JSON | 3.0.x | Yes |
+| Front | https://raw.githubusercontent.com/frontapp/front-api-specs/main/core-api/core-api.json | JSON | 3.0.x | Yes |
+
+## Notes
+- All URLs are raw file URLs (not HTML pages)
+- Verified means the URL was confirmed accessible and the spec parses correctly
+- Some specs are very large (Discord: 1MB+) - the parser handles this with resource/endpoint limits
+- This environment blocks direct shell network egress (`curl -sI` returns `000`), so URL checks were completed via repository/raw URL validation instead of local `curl`
diff --git a/skills/printing-press/references/spec-format.md b/skills/printing-press/references/spec-format.md
new file mode 100644
index 00000000..1a5ef042
--- /dev/null
+++ b/skills/printing-press/references/spec-format.md
@@ -0,0 +1,234 @@
+# Internal YAML Spec Format Reference
+
+Use this format when no OpenAPI spec is available.
+
+## 1. Complete Schema Reference
+
+```yaml
+# Root object (APISpec)
+name: my-api                     # string (REQUIRED) CLI binary prefix, e.g. "my-api"
+description: "My API CLI"       # string shown in command help
+version: "0.1.0"                # string baked into generated binary
+base_url: "https://api.example.com/v1" # string (REQUIRED) base API URL
+
+auth:                             # object (AuthConfig)
+  type: api_key                   # string: api_key | oauth2 | bearer_token | none
+  header: "Authorization"        # string header name to set
+  format: "Bearer {token}"       # string format template for auth header value
+  env_vars:                       # []string env vars used for auth material
+    - EXAMPLE_API_TOKEN
+  scheme: bearerAuth              # string optional OpenAPI security scheme name
+  in: header                      # string optional: header | query | cookie
+
+config:                           # object (ConfigSpec)
+  format: toml                    # string config format: toml | yaml (other values fall back to json tags)
+  path: "~/.config/my-api/config.toml" # string config file path
+
+resources:                        # map[string]Resource (REQUIRED: at least one key)
+  users:                          # resource key becomes top-level command: <name>-cli users
+    description: "Manage users"  # string resource help text
+    endpoints:                    # map[string]Endpoint (REQUIRED: at least one key)
+      list:                       # endpoint key becomes subcommand: users list
+        method: GET               # string (REQUIRED) must be one of GET | POST | PUT | DELETE
+        path: "/users"           # string (REQUIRED) API path; supports {param} placeholders
+        description: "List users" # string endpoint help text
+        params:                   # []Param query/path parameters
+          - name: limit           # string param name; flag is --limit unless positional=true
+            type: int             # string type: string | int | bool | float
+            required: false       # bool whether Cobra marks the flag required
+            positional: false     # bool true => consumes positional CLI arg and fills {name} in path
+            default: 100          # any default value (type should match param type)
+            description: "Max results" # string flag description
+            fields: []            # []Param nested fields for object-like params
+            enum: []              # []string optional enum hints/constraints
+            format: ""           # string optional format hint (date-time, email, uri, etc.)
+        body:                     # []Param request body fields (primarily for POST/PUT)
+          - name: email
+            type: string
+            required: true
+            positional: false
+            default: null
+            description: "User email"
+            fields: []
+            enum: []
+            format: email
+        response:                 # object (ResponseDef)
+          type: array             # string response shape: object | array
+          item: User              # string type name referenced from `types`
+        pagination:               # object (Pagination) optional
+          type: cursor            # string pagination style: cursor | offset | page_token
+          cursor_field: cursor    # string response field containing next cursor
+          has_more_field: data.has_more # string response field indicating more results
+        response_path: data       # string optional path to extract list payload from wrapper response
+
+types:                            # map[string]TypeDef named response/body models
+  User:                           # type name referenced by response.item
+    fields:                       # []TypeField
+      - name: user_id             # string field name
+        type: string              # string field type (typically string/int/bool/float)
+```
+
+## 2. Annotated Example (`testdata/stytch.yaml`)
+
+```yaml
+name: stytch # CLI binary prefix => stytch-cli
+description: "Stytch authentication API CLI" # Root help text and README summary
+version: "0.1.0" # Printed by `stytch-cli version`
+base_url: "https://api.stytch.com/v1" # Base URL all endpoint paths are joined against
+
+auth:
+  type: api_key # Uses API key style auth
+  header: "Authorization" # Header key set on outgoing requests
+  format: "Basic {project_id}:{secret}" # Expected auth value format
+  env_vars:
+    - STYTCH_PROJECT_ID # Credential source env var #1
+    - STYTCH_SECRET # Credential source env var #2
+
+config:
+  format: toml # Generated config struct tags use TOML
+  path: "~/.config/stytch-cli/config.toml" # Default config file location
+
+resources:
+  users: # Creates `stytch-cli users ...`
+    description: "Manage Stytch users"
+    endpoints:
+      list: # Creates `stytch-cli users list`
+        method: GET # Generates a query-parameter style command
+        path: "/users"
+        description: "List all users"
+        params:
+          - name: limit # Exposed as `--limit`
+            type: int
+            default: 100 # Default flag value
+            description: "Max users to return"
+          - name: cursor # Exposed as `--cursor`
+            type: string
+            description: "Pagination cursor"
+        response:
+          type: array # Command expects a list-like response
+          item: User # Rows map to `types.User`
+        pagination:
+          type: cursor # Enables cursor pagination helpers
+          cursor_field: "cursor" # Field that contains next cursor token
+          has_more_field: "results.has_more" # Field used to detect continuation
+
+      get: # Creates `stytch-cli users get <user_id>`
+        method: GET
+        path: "/users/{user_id}" # Placeholder filled from positional arg
+        description: "Get a user by ID"
+        params:
+          - name: user_id
+            type: string
+            required: true
+            positional: true # Required so CLI arg is mapped into `{user_id}`
+            description: "User ID"
+        response:
+          type: object
+          item: User
+
+      create: # Creates `stytch-cli users create --email ...`
+        method: POST # Generates body-field flags
+        path: "/users"
+        description: "Create a new user"
+        body:
+          - name: email
+            type: string
+            description: "User email"
+          - name: phone_number
+            type: string
+            description: "User phone number"
+        response:
+          type: object
+          item: User
+
+      delete: # Creates `stytch-cli users delete <user_id>`
+        method: DELETE
+        path: "/users/{user_id}"
+        params:
+          - name: user_id
+            type: string
+            required: true
+            positional: true
+            description: "User ID"
+
+  sessions: # Creates `stytch-cli sessions ...`
+    description: "Manage user sessions"
+    endpoints:
+      list: # Creates `stytch-cli sessions list --user_id ...`
+        method: GET
+        path: "/sessions"
+        description: "List sessions for a user"
+        params:
+          - name: user_id
+            type: string
+            required: true
+            description: "User ID"
+        response:
+          type: array
+          item: Session
+
+      revoke: # Creates `stytch-cli sessions revoke --session_id ...`
+        method: POST
+        path: "/sessions/revoke"
+        description: "Revoke a session"
+        body:
+          - name: session_id
+            type: string
+            required: true
+            description: "Session ID to revoke"
+
+types:
+  User: # Referenced by response.item: User
+    fields:
+      - name: user_id
+        type: string
+      - name: email
+        type: string
+      - name: phone_number
+        type: string
+      - name: status
+        type: string
+      - name: created_at
+        type: string
+
+  Session: # Referenced by response.item: Session
+    fields:
+      - name: session_id
+        type: string
+      - name: user_id
+        type: string
+      - name: started_at
+        type: string
+      - name: expires_at
+        type: string
+```
+
+## 3. Validation Rules
+
+Validation in `spec.Validate()` enforces:
+
+- `name` is required
+- `base_url` is required
+- at least one `resources` entry is required
+- every resource must have at least one endpoint
+- every endpoint must have both `method` and `path`
+
+## 4. Common Mistakes
+
+These commonly cause generation/build failures or incorrect CLI behavior:
+
+- Missing required fields (`name`, `base_url`, resource endpoints, endpoint `method`, endpoint `path`)
+- Invalid `method` values (generator templates only handle `GET`, `POST`, `PUT`, `DELETE`)
+- Missing `path` on endpoints
+- Defining `body` params on `GET` endpoints (allowed in YAML, but ignored by GET command generation)
+- Forgetting `positional: true` for params used in `/{path_placeholders}`
+- Using parameter types outside supported scalar set: `string`, `int`, `bool`, `float`
+
+## 5. Type Mapping
+
+| YAML Type | Go Type | Cobra Flag | Zero Value |
+|-----------|---------|------------|------------|
+| `string` | `string` | `StringVar` | `""` |
+| `int` | `int` | `IntVar` | `0` |
+| `bool` | `bool` | `BoolVar` | `false` |
+| `float` | `float64` | `Float64Var` | `0.0` |

← 4934eb50 fix(openapi): Swagger 2.0 detection + resource name sanitiza  ·  back to Cli Printing Press  ·  feat(skill): add /printing-press Claude Code skill 412c2fe6 →