API: OpenAPI spec + Scalar reference site + design refresh (0.5.0) - #18
Merged
Merged
Conversation
Generate a committed, CI-verified OpenAPI spec at docs/api/openapi.{json,yaml}
via an `opf-api-export-openapi` console script, enrich every route and
Pydantic field with descriptions and examples, and ship a Scalar-powered
reference UI both in-app (/scalar) and as a static site under docs/ that
GitHub Actions deploys to Pages.
- api/src/opf_api/scripts/export_openapi.py: console script entry that
imports the app, calls app.openapi(), and writes JSON + YAML to --out.
app.openapi() does not invoke lifespan, so this is cheap in CI.
- api/src/opf_api/main.py: extend FastAPI(title=..., description=...,
contact=..., servers=..., openapi_tags=...) and mount /scalar.
- api/src/opf_api/routes.py: per-route tags, summary, description,
response_description, and example bodies for 400 / 502 responses.
- api/src/opf_api/schemas.py: every Field gets description= and
examples=; every request/response model gets json_schema_extra
examples reused from the previous README examples.
- docs/index.html, docs/guides/*.md, docs/api/openapi.{json,yaml}:
the published reference + narrative companion pages.
- README.md: trim the hand-written API reference section in favour of
the hosted docs; keep the env-vars table inline for operators.
- .github/workflows/openapi.yml: PR check that diffs the committed spec
against a fresh regen and fails on drift, with a remediation hint.
- .github/workflows/pages.yml: regen spec + deploy docs/ to Pages on
pushes to main. Requires Settings -> Pages -> Source = GitHub Actions.
- detect.openapi.json: drop the unused Skyflow Detect API capture.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
privacy-filter/ is the workspace member that provides the `opf` package,
but it's gitignored — the README tells users to clone it as a sibling.
CI runners don't have it, so `uv sync --package opf-api` fails to resolve
the `opf = { workspace = true }` source.
Add a `git clone --depth 1 https://github.com/openai/privacy-filter
privacy-filter` step to both new workflows before `uv sync`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Job only checks out the repo and runs uv. No write surface needed — declare `permissions: contents: read` at workflow level to follow least privilege. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two goals, shipped together:
docs/. In-app/scalarroute alongside/docsand/redoc.Endpoints (after this PR)
/api/find/api/replacemode./api/detectors/api/healthOld
/v1/*paths return 404. Pre-1.0; nobody outside this repo consumes the API yet.Notable changes
Docs / reference
opf-api-export-openapiconsole script regeneratesdocs/api/openapi.{json,yaml}fromapp.openapi()(cheap — no lifespan, no model loads)./scalarroute in api/src/opf_api/main.py viascalar-fastapi.docs/index.html+docs/guides/*.mdcarry overview, detectors, labels, replace-modes, auth-and-env. Token vault guide stays atdocs/token-vault-setup.md.API design (breaking, in successive commits)
categoriesis now a closedCanonicalLabelenum mirroringopf_eval.taxonomy.CANONICAL_LABELS.[]= match nothing;null= no filter; bad value -> 422.options.<detector>namespace.OpfOptionsusesextra=\"forbid\"to catch typos likedecod_mode.DetectorOptionsitself keepsextra=\"ignore\"for forward-compat across new detectors.schema_versionpayload field dropped —info.versionis the only version surface (now0.5.0)./v1/detect->/api/find,/v1/sanitize->/api/replace. Schemas renamed to match (FindRequest/Response,ReplaceRequest/Response,ReplacedSpan,ReplaceMode).sanitized_textresponse field is nowreplaced_text./v1/->/api/. Future versioning will useAPI-Version: 2026-05-13header once contract stabilizes.CI
docs/to Pages on push to main.openai/privacy-filter(gitignored workspace member) beforeuv sync.openapi.ymlscoped tocontents: read.Files
/scalarroute, app mounted at/apifind+replacehandlers, error response examplesCanonicalLabelenum,OpfOptions/DetectorOptions, request/response models, every field carries description + examplescalar-fastapidep,docsextra, console scriptdetect.openapi.json— deleted (stale Skyflow Detect capture)Test plan
uv run --package opf-api opf-api-export-openapi --out /tmp/freshregenerates spec; diff againstdocs/api/openapi.jsonis emptyuvicorn opf_api.main:appboots;/api/health,/api/detectors,/scalar,/docs,/redoc,/openapi.jsonall 200/v1/*paths return 404pytest api/tests/test_routes.py— 21/21 passing, including:[]-> 0 spans,null-> all spans, bad enum -> 422, unknown OPF option -> 422 (extra_forbidden), validoptions.opf.decode_mode-> 200OpenAPI spec freshnessjob passes on latest pushapi/**without regenerating the specVersioning approach
API is pre-1.0.
info.versionis the only version surface today (bumps minor on breaking changes). When the API stabilizes, intent is to move to header-based date-string versioning in the style of Stripe:API-Version: 2026-05-13. URL paths stay unversioned (/api/...) so that switch is purely additive.🤖 Generated with Claude Code