# harvested from https://github.com/PaloAltoNetworks/openapi/blob/659339799ae30a06c3bf1859507a4a6c131814fc/.spectral.yaml on 2026-10-09 — a Spectral ruleset published in the provider's own GitHub repository (PaloAltoNetworks/openapi); found by GitHub code search, fetched verbatim
x-method: harvested
x-stamped: 2026-10-09
x-source-url: https://github.com/PaloAltoNetworks/openapi/blob/659339799ae30a06c3bf1859507a4a6c131814fc/.spectral.yaml
# Spectral ruleset for the Prisma AIRS AI Gateway API.
#
# Two things make this ruleset unusual, and both follow from the grounding
# model rather than from taste:
#
# 1. The stock OpenAPI style guide wants a description on everything. This
# repository wants them EMPTY until an accepted KB claim supports them, so
# those rules are turned off and replaced by a rule asserting the opposite.
# An empty description renders as a visible gap; a plausible invented one
# does not.
#
# 2. Genuine defects inherited from the base specification are NOT silenced
# here. They keep their real severity and are held at their current count
# by .spectral-baseline.json, so existing debt is visible and new debt
# fails CI. See scripts/lint.py.
extends: ["spectral:oas"]
rules:
# --- inverted for grounding -------------------------------------------
# Not style preferences. Writing prose here would bypass the grounding gate,
# which is the one review that makes the spec safe to publish.
operation-description: off
info-description: off
info-contact: off # dropped deliberately; the base pointed at Portkey
# --- the grounding gate, as lint --------------------------------------
# This rule used to assert that prose in openapi.yaml was *empty*, because
# prose lived in overlays/docs-prose.yaml and was applied downstream. It is
# applied upstream now -- openapi.yaml is the published document and carries
# the resolved prose -- so "empty" would fail the moment the first description
# was written, and would have been silenced rather than fixed.
#
# The assertion underneath it survives the move, and gets sharper: prose may
# be here, but not without the claim that supports it. Written summary or
# description, empty `claims`, is the failure the split exists to prevent, and
# on the resolved document it is checkable in one place.
#
# scripts/check.py enforces the other half -- that the prose in openapi.yaml
# is byte-for-byte what the overlay produces, so it cannot be typed in here
# and cannot bypass review. Spectral cannot see the overlay, and info and tag
# descriptions have no provenance block to point at, so they are checked
# there rather than here.
airs-prose-is-grounded:
description: >-
Every published description is an assertion about the API. It ships with
the accepted claim that supports it or it does not ship.
message: "prose without an accepted claim -- see overlays/docs-prose.yaml"
severity: error
given: $.paths[*][get,put,post,delete,options,head,patch,trace]
then:
function: schema
functionOptions:
schema:
type: object
allOf:
- if:
required: [summary]
properties:
summary: { type: string, minLength: 1 }
then:
required: [x-airs-provenance]
properties:
x-airs-provenance:
type: object
required: [claims]
properties:
claims: { type: array, minItems: 1 }
- if:
required: [description]
properties:
description: { type: string, minLength: 1 }
then:
required: [x-airs-provenance]
properties:
x-airs-provenance:
type: object
required: [claims]
properties:
claims: { type: array, minItems: 1 }
# --- the docs URL contract ---------------------------------------------
# A published page address. scripts/check.py owns uniqueness, tag consistency
# and the comparison against _project/hrefs.yaml; presence is here so a
# Spectral run on its own still catches an operation that would generate a
# page nothing can link to.
airs-mint-href-present:
description: >-
Without x-mint.href an operation's page has no stable URL: Mintlify
derives the slug from prose, so it moves when prose lands.
message: "operation is missing x-mint.href"
severity: error
given: $.paths[*][get,put,post,delete,options,head,patch,trace]
then:
field: x-mint.href
function: truthy
# --- provenance, the drift join key -----------------------------------
airs-provenance-present:
description: >-
Without a claim reference on an operation, nothing can tell that the KB
moved and the specification did not.
message: "operation is missing x-airs-provenance"
severity: error
given: $.paths[*][get,put,post,delete,options,head,patch,trace]
then:
field: x-airs-provenance
function: truthy
airs-provenance-well-formed:
description: >-
The shape goes in before there is anything to put in it. Retrofitting it
means reconstructing which claim supported a description after the fact,
which is indistinguishable from inventing it.
severity: error
given: $.paths[*][get,put,post,delete,options,head,patch,trace].x-airs-provenance
then:
function: schema
functionOptions:
schema:
type: object
required: [claims, origin_kind, text_digest]
properties:
claims:
type: array
items:
type: object
required: [id]
properties:
id: { type: string }
revision: { type: [string, "null"] }
origin_kind:
enum: [human, generated, mixed]
text_digest:
type: string
# --- naming ------------------------------------------------------------
airs-tag-naming:
description: >-
Tag names are simultaneously navigation display text and reference keys.
Title Case, spaces not hyphens, initialisms uppercased, "Parent > Child"
for genuine sub-resources. See tags-map.yaml.
message: "tag name '{{value}}' does not match the agreed information architecture"
severity: error
given: $.tags[*].name
then:
function: pattern
functionOptions:
# Word = capitalised, optionally hyphen-joined to further capitalised
# words, so "Fine-Tuning" passes and "Virtual-keys" does not.
match: "^[A-Z][A-Za-z0-9]*(?:-[A-Z][A-Za-z0-9]*)*(?: [A-Z][A-Za-z0-9]*(?:-[A-Z][A-Za-z0-9]*)*)*(?: > [A-Z][A-Za-z0-9]*(?:-[A-Z][A-Za-z0-9]*)*(?: [A-Z][A-Za-z0-9]*(?:-[A-Z][A-Za-z0-9]*)*)*)*$"
airs-tag-initialisms:
description: >-
Casing alone cannot tell that "Api" should be "API". These are the
initialisms the inherited specification got wrong.
message: "tag name '{{value}}' contains a lowercased initialism"
severity: error
given: $.tags[*].name
then:
function: pattern
functionOptions:
notMatch: "\\b(Api|Mcp|Ocr|Sdk|Url|Uri|Http|Https|Json|Yaml|Ai|Llm|Id)\\b"
airs-tag-no-camel-case:
description: >-
Compound tag names are separated by spaces, not run together.
"PromptPartials" is "Prompt Partials".
message: "tag name '{{value}}' runs words together; separate them with a space"
severity: error
given: $.tags[*].name
then:
function: pattern
functionOptions:
notMatch: "[a-z][A-Z]"
# --- inherited debt, held at its current count by the baseline ---------
# Left at real severity on purpose. Silencing them would lose the signal that
# these are defects someone should eventually fix.
operation-operationId: warn
Every ruleset here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for spectral rules
4 MCP tools reach this
find_rulesBrowse and filter every ruleset in the catalog.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This ruleset
curl "https://apis.io/api/v1/rules/palo-alto-networks-openapi-spectral-rules"
All spectral rules
curl "https://apis.io/api/v1/rules?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.