Skip to content

docs: one page per API class, sitemap, and search-engine titles - #637

Merged
jackparmer merged 8 commits into
mainfrom
issue-636-docs-api-pages-seo
Oct 27, 2026
Merged

jackparmer merged 8 commits into
mainfrom
issue-636-docs-api-pages-seo

Conversation

@arsenovic

Copy link
Copy Markdown
Contributor

Summary

Closes #636. Closes #519. Part of #520 (llms.txt still to do).

API pages: one page per class. Members render on the class page under the existing summary tables, whose links now jump to in-page anchors; no more page per method (generated stubs: 1,440 → 146). Class pages drop the generated/ folder: /sdk/instruments/instro.psu.InstroPSU/. _extra/404.html redirects old URLs: class pages to their new path, member pages to their anchor on the class page.

Search engines.

  • sitemap.xml (sphinx-sitemap; content pages only) and _extra/robots.txt.
  • <title> and meta description on every page, set by _add_seo in conf.py and a _templates/base.html override of Shibuya's htmltitle block:
    • Category pages: hand-written seo_title: and description aimed at searches like "python control power supply".
    • Driver pages: generated from card:, e.g. B&K Precision 9115 Python Driver (BK9115) - instro. Their opening line now names the vendor and model.
    • API pages: InstroPSU (instro.psu) - instro Python API, with the docstring summary.
    • Example pages (docs: emit description frontmatter and normalized titles for generated example pages #519): sentence-cased titles; descriptions lead with the title, then the docstring's first prose paragraph.
  • Fixes an existing bug: Shibuya drops docutils <meta> tags without sphinxext-opengraph, so the 56 myst: html_meta: description: values in guide front matter never reached the HTML. They do now.

Page headings, breadcrumbs, and og:title are unchanged. docs/README.md ("Search engines") and docs/AGENTS.md document the conventions.

Type of change

  • Documentation (docs)

Verification

  • just build-docs (strict, -W) passes.
  • All 365 content pages have exactly one <title> and one meta description; all 64 example-page descriptions are distinct; the sitemap lists exactly those 365 pages.
  • Redirects checked in headless Chrome against the built site with a 404 fallback:
Old URL Lands on
/sdk/instruments/generated/instro.psu.InstroPSU/ /sdk/instruments/instro.psu.InstroPSU/
/sdk/instruments/generated/instro.psu.InstroPSU.set_voltage/ .../instro.psu.InstroPSU/#instro.psu.InstroPSU.set_voltage
/python/sdk/instruments/generated/instro.psu.InstroPSU.open/ .../instro.psu.InstroPSU/#instro.psu.InstroPSU.open
/sdk/library/generated/instro.lib.instrument.Instrument._package_command/ .../instro.lib.instrument.Instrument/#..._package_command
/sdk/nope/ "Page not found"

Tests

  • No tests — docs-only; covered by the strict docs build above.

Checklist

  • PR title follows Conventional Commits
  • I have read CONTRIBUTING.md
  • Documentation updated if user-facing behavior changed
  • Code follows the style/conventions of the surrounding code

🤖 Generated with Claude Code

arsenovic and others added 5 commits October 11, 2026 14:12
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Old generated/ URLs redirect from the 404 page: class pages to their new
path, member pages to their anchor on the class page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sphinx-sitemap writes sitemap.xml and robots.txt points crawlers at it.
Shibuya renders a page's description metadata but drops docutils meta
tags, so the html_meta descriptions in front matter never reached the
HTML; they are now copied over, and pages without one fall back to their
first paragraph (the docstring summary on API pages). Example pages take
theirs from the script docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…I pages

Category pages get hand-written seo_title and descriptions aimed at
searches like "python control power supply"; driver pages get them
generated from their card ("B&K Precision 9115 Python Driver (BK9115)"),
and API pages from the object and module. Driver pages open with the
vendor and model.

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

Titles get a capital first letter (identifiers keep their case); each
description leads with the title, so it stays unique, then the
docstring's first prose paragraph.

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

claude Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @arsenovic's task in 56s —— View job


Code review complete

  • Gather context (PR diff, docs/AGENTS.md conventions)
  • Review docs/conf.py SEO/sitemap additions
  • Review docs/_ext/examples.py title/description generation
  • Review template changes (class.rst, base.html, 404.html)
  • Review per-category/driver doc front-matter changes
  • Post findings

Overview

Docs-only PR, no public API/driver surface touched — AGENTS.md driver/base-class/breaking-change axes don't apply here. The work is cohesive and well-scoped:

  • _add_seo in conf.py cleanly layers generated titles/descriptions under explicit front-matter overrides, with a sensible fallback chain (front matter → generated → first-paragraph).
  • The class.rst template rework (member tables + details on one page) is a real simplification over the old per-member-page generation, and the /sdk/**/instro.*.rst gitignore pattern replacing a blanket generated/ ignore is more precise.
  • The 404.html redirect for old generated/ member URLs (HEAD-check class page, fall back to in-page anchor) is a pragmatic client-side solution for a static site with no server-side redirect capability, and matches the documented/verified redirect table in the PR body.
  • Docs for the new conventions (docs/README.md, docs/AGENTS.md) are updated in the same PR per the repo's own documentation-sync rule.

No inline findings — didn't find defects or convention divergences worth flagging. One very minor, non-blocking observation (not filed as a comment since it's speculative and not a confirmed defect): in _extra/404.html's fallback-anchor construction (name.slice(0, name.lastIndexOf("."))), a name with no . would yield lastIndexOf of -1 and silently truncate the last character — currently unreachable since all matched names are fully-qualified module.Class[.member] paths with at least one dot, so not a practical bug today.

@greptile-apps

greptile-apps Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 2/5

[Low impact] Documentation restructuring and search engine optimization.

Fix the external redirect and the rebuild failure in existing docs checkouts before merging.

Findings

  1. P1 Security Docs links leave the site ▶
  2. P1 Existing docs builds fail ▶
Fix with agent prompt
### Issue 1
docs/_extra/404.html:21-25
For `https://instro.nominal.io//attacker.example/generated/name/`, `dir` becomes `//attacker.example`, so `page(name)` points to an attacker-owned site. Even if the cross-site request fails, the catch branch sends the visitor there. This lets an attacker share a trusted-looking docs link that redirects elsewhere. Restrict redirects to SDK paths and check that the destination keeps the current origin.

**How this was verified:** The pathname reaches `location.replace` through `dir` without an origin check, including when `fetch` fails.

### Issue 2
docs/sdk/instruments/psu.md:9
Anyone who built the docs before this change still has class and member files under `generated/`. Moving the stubs leaves both layouts in place. Sphinx discovers the old files too: `exclude_patterns` does not exclude them, and `just build-docs` does not delete them. They document the same objects as the new files, so duplicate-object warnings fail the strict build. Delete the old source stubs before building, or exclude their folders and document the cleanup.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR puts API members on their class pages and adds search-engine titles, descriptions, a sitemap, and redirects for old API URLs.

  • Each API class page now includes its member details and keeps its own URL.
  • Search results now show useful titles and descriptions for the docs.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  SDK[SDK summary pages] --> Class[One page per class]
  Class --> Members[Member details on the class page]
  Old[Old generated API URL] --> Fallback[404 page]
  Fallback --> Check[HEAD request for new page]
  Check --> Class
  Check --> Anchor[Member anchor]
  Metadata[Front matter and docstrings] --> SEO[Page titles and descriptions]
  Pages[Built content pages] --> Sitemap[sitemap.xml]
Loading

Reviews (1) · Last reviewed commit: "docs: sentence-case example titles and d..." · Reviewed by Greptile

Comment thread docs/_extra/404.html Resolved
Comment thread docs/sdk/instruments/psu.md Resolved
arsenovic and others added 2 commits October 14, 2026 10:42
Anchor the old generated/ URL match to /sdk/ paths and instro.* names so a
path like //attacker.example/generated/x/ can't redirect off-site.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@arsenovicAtNominal
arsenovicAtNominal enabled auto-merge (squash) October 27, 2026 14:02
@jackparmer
jackparmer merged commit ec6f4e9 into main Oct 27, 2026
19 checks passed
@jackparmer
jackparmer deleted the issue-636-docs-api-pages-seo branch October 27, 2026 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants