Skip to content

Serve the API reference from Speculoos - #337

Merged
mnemitz merged 7 commits into
mainfrom
speculoos/4-speculoos-reference
Nov 3, 2026
Merged

mnemitz merged 7 commits into
mainfrom
speculoos/4-speculoos-reference

Conversation

@mnemitz

@mnemitz mnemitz commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Stack 4 of 4, splitting #331 for review. Based on #336.

  1. Site fixes (Site fixes ahead of the API reference work #334)
  2. Management reference from the public spec (Build the Management reference from the public spec #335)
  3. Code samples, tested against a mock (Code samples for every Batch and Management operation, tested #336)
  4. API reference on Speculoos ← this PR

When the stack is merged, main matches #331's branch, minus SPECULOOS-PLAN.md (deleted here).

What changes

Every API reference page is rendered by Speculoos (0.1.0-alpha.1) from IR built at build time (npm run build:speculoos-ir, wired into start and build). scripts/generate-speculoos-pages.ts writes one page per REST operation or WebSocket channel into gitignored directories, which the sidebar lists with autogenerated. A page's own prose, which the spec can't express (handshake responses, how a connection closes), lives in partials beside the pages.

Specs

Rendering (src/components/Speculoos/)

  • site.tsx: how this site renders Speculoos. That's the Radix Themes map, with the site's Markdown, the sidebar's badge colours, and types expanded where they're used.
  • SessionPanel.tsx: a channel's session as a compact sequence diagram beside the reference, with each message linking to its section and showing its example on hover. Below lg it comes first, collapsed.
  • OperationPanel.tsx: an operation's code samples, then its examples, each labelled by its status's description ("400 Bad request").
  • Schema.tsx: <Schema> puts the same field tables in guides, headed by the type's name and a link to where the reference uses it. open opens one field among the rest. The Batch and Realtime guides use it in place of the old SchemaNode and AsyncAPI loader.
  • The site's Markdown component moves to src/components/Markdown, on react-markdown 10 with remark-gfm 4 and rehype-raw 7.

Removed: the OpenAPI plugin and theme, its templates and the sidebar filter for Batch paths, the Schema/SchemaItem theme components, the AsyncAPI and OpenAPI schema loaders, and the old WebSocket pages with their generator.

Worth reviewing

  • Redirects: the Batch and Management info pages, the removed Batch log endpoint and post-a-new-project (from Build the Management reference from the public spec #335) are all in redirects.json / vercel.json.
  • Anchors change: message anchors are kebab-case now (#startrecognition → #start-recognition). In-repo links are updated, but external deep links to the old anchors will land at the top of the page; redirects can't cover fragments.
  • CI builds from a clean checkout: partials and src/generated are produced by the build, not committed.
  • Speculoos is an alpha from npm. npm run speculoos:local tries local packs of the Speculoos repo.

Checked

  • npm run build passes, with no broken links.
  • tsc passes once the build has generated src/generated.
  • npm run test:code-samples: all 24 samples pass.

Closes #331 once the stack lands.

🤖 Generated with Claude Code

mnemitz and others added 4 commits November 2, 2026 15:34
- The page body fills its width: its Box was a flex child with no width,
  so it shrank to its content and the layout jumped from page to page.
- Type errors in LinkCard, Tabs and remark-admonition. The controlled
  Tabs root drops a defaultValue that Radix ignores.
- Radix Code drops Infima's leftover border and vertical-align once, in
  reset.css, rather than inline in CodeInline; inline code and
  admonitions use the outline variant.
- The Management API's path is /v1/api-keys in the temporary key
  examples; a guide's link to the Realtime reference drops its .mdx.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
spec/mp.yaml is now the public spec generated upstream (make public-spec
in the Management Platform repo): OpenAPI 3, with the server,
authentication and the descriptions ported upstream from this repo's old
copy. generate-mp-spec.ts reads it as OpenAPI 3: it names its own server,
and the schema titles go on components.schemas.

The new summaries rename one page: post-a-new-project is now
create-a-project, with a redirect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every Batch operation has JavaScript, Python and curl samples, and every
Management operation a curl sample. One injector (scripts/code-samples/
inject.ts) adds them to both specs as x-codeSamples, which the reference
renders as tabs.

npm run test:code-samples runs each one against a mock built from the
spec: requests are checked against the operation's schemas, and the mock
answers with the spec's own examples. The Batch API's comes from an
OpenAPI 3.1 copy (generate-openapi.ts converts static/batch.yaml and
applies spec/batch.overlay.yaml, which adds a success example per
operation and what Swagger 2.0 cannot express). The workflow runs the
tests on any change to the specs, the samples or the harness, with a
read-only token and no secrets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every reference page is now rendered by Speculoos from IR built at build
time (npm run build:speculoos-ir): one page per REST operation or
WebSocket channel, written by scripts/generate-speculoos-pages.ts.

- The Realtime spec is canonical AsyncAPI 3, with its authentication and
  handshake declared; the Agent STT spec is generated from it.
- Batch renders from the OpenAPI 3.1 copy the code-sample tests read;
  Management from the public spec.
- A panel beside each entry: a channel's session as a sequence diagram,
  or an operation's code samples and examples. Below lg a REST panel
  follows the entry and a session comes first, collapsed.
- <Schema> puts the same field tables in guides, headed by the type's
  name and a link to where the reference uses it.
- The site's Markdown component moves to src/components, on
  react-markdown 10.
- The OpenAPI plugin and theme, the AsyncAPI loader, the old WebSocket
  pages and their generator go. Renamed and removed pages redirect;
  message anchors are now kebab-case (#start-recognition).

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

vercel Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Nov 3, 2026 4:49pm UTC

Request Review

@dumitrugutu dumitrugutu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some comments--mainly because I'm unfamiliar with the generator tool, but overall LGTM!

@@ -0,0 +1,23 @@
{/*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need a separate file for stt? looks identical to docs/api-ref/_realtime-connection-close.mdx

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They were previously documented separately. I suspect they are the same but didn't want to assume in case things change. Maybe later we can see about consolidating this elsewhere.

@@ -0,0 +1,58 @@
{/* Agent STT handshake responses, for the end of the reference's Handshake section. */}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question here, do we need this file for stt? looks identical to docs/api-ref/_realtime-handshake-responses.mdx

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main difference is the path /v2/agents. I'm keeping it as close to it was previously as possible, but maybe we can consolidate this in the future.

import SchemaNode from "@theme/Schema";
import batchSpec from "!openapi-schema-loader!@site/spec/batch.yaml";
import { Schema } from "@site/src/components/Speculoos";
import batch from "@site/src/generated/batch.ir.json";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is their extension?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ir stands for intermediate representation. All it means is the JSON file follows the Speculoos schema. It could be named whatever we want (something like batch.speculoos.json might be clearer?)

Comment thread docs/speech-to-text/realtime/output.mdx Resolved
Comment thread spec/agent-stt.yaml
SpeakersResult:
$ref: "#/components/messages/SpeakersResult"
operations:
publish:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I liked the separation of messages between server and client but it appears that is no longer an option in v3?

@mnemitz mnemitz Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still have the split, we've just refactored how it's communicated. Previously it was written from the client perspective, which was apparently against AsyncAPI convention. This creates two operations: receiveClientMessages and sendServerMessages. Same idea but written from the server's perspective and explicitly labeled.

@mnemitz
mnemitz changed the base branch from speculoos/3-code-samples to main November 3, 2026 16:17
@mnemitz
mnemitz merged commit 4c96657 into main Nov 3, 2026
2 checks passed
mnemitz added a commit to speechmatics/speechmatics-js-sdk that referenced this pull request Nov 4, 2026
…240)

- `real-time-client`: Update models based on latest upstream spec
- Spec was refactored in speechmatics/docs#337
to include two operations on a shared channel
- Updated `generate-models.ts` to generate the same types based on this
new spec, including some workarounds for a bug in Modelina preventing
union creation by operation instead of channel
- Bump versions

This branch was successfully deployed

1 active deployment
Preview — 342bcfe9 Deployed Nov 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants