Skip to content

feat: add static OpenAPI reference page with Scalar UI#318

Closed
Aureliolo wants to merge 7 commits into
mainfrom
feat/static-openapi-reference
Closed

feat: add static OpenAPI reference page with Scalar UI#318
Aureliolo wants to merge 7 commits into
mainfrom
feat/static-openapi-reference

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Add static OpenAPI reference page powered by Scalar UI, loaded from a CI-generated openapi.json schema
  • New scripts/export_openapi.py exports the Litestar app's OpenAPI schema to docs/_generated/openapi.json
  • Restructure MkDocs nav: "API Reference" → Scalar REST API page, "Library Reference" → existing mkdocstrings section
  • Update CI workflows (pages.yml, pages-preview.yml) to export OpenAPI schema before MkDocs build
  • Fix hookify rule field names (valuepattern) and add no-future-annotations hookify rule
  • Add ruff per-file-ignores for scripts/**/*.py (allow print and deferred imports)
  • Update documentation across CLAUDE.md, README.md, docs/index.md, docs/architecture/index.md, and docs/design/operations.md to reflect the REST API vs Library Reference split

Test plan

  • Verify uv run python scripts/export_openapi.py generates docs/_generated/openapi.json
  • Verify uv run mkdocs build --strict succeeds with the generated schema
  • Verify Scalar UI loads correctly on the REST API Reference page in local preview
  • Verify CI preview deployment builds successfully
  • Verify all documentation links to API/Library Reference are consistent

Review coverage

Pre-reviewed by 1 agent (docs-consistency), 12 findings addressed (2 CRITICAL, 5 MAJOR, 2 MEDIUM, 1 MINOR, 2 SUGGESTION)

Export the Litestar OpenAPI schema to a static JSON file at build time
and serve it via a Scalar-powered docs page. Renames the mkdocstrings
"API Reference" nav section to "Library Reference" to distinguish
Python library docs from the REST API reference.

- Add scripts/export_openapi.py to generate docs/_generated/openapi.json
- Add docs/rest-api.md + docs/overrides/rest-api.html (Scalar CDN embed)
- Update both pages.yml and pages-preview.yml CI workflows
- Rename API Reference → Library Reference in mkdocs.yml and docs/api/index.md

Closes #296
Fix function-length and missing-logger rules that used `value:` instead
of `pattern:` in conditions (hookify expects `pattern:`). Remove
unsupported `file_content` field from missing-logger rule. Add new
no-future-annotations rule to block `from __future__ import annotations`
(unnecessary on Python 3.14 with PEP 649).
Align CLAUDE.md, README.md, docs/index.md, docs/architecture/index.md,
and docs/design/operations.md with the nav restructuring from the Scalar
OpenAPI reference page addition. Add ruff per-file-ignores for scripts/.

Pre-reviewed by 1 agent, 12 findings addressed
Copilot AI review requested due to automatic review settings March 12, 2026 09:37
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 12, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 12, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added REST API reference documentation with Scalar UI interface for interactive API exploration
  • Documentation

    • Separated API documentation into REST API Reference and Library Reference sections
    • Reorganized navigation structure across documentation
  • Chores

    • Enhanced CI/CD workflows for automatic OpenAPI schema generation
    • Updated project configuration rules and environment settings

Walkthrough

Adds an OpenAPI export script integrated into CI Pages workflows, reorganizes docs to separate REST API and Library references with a custom OpenAPI template, updates hook configurations, CI workflow triggers/environments, ignores generated OpenAPI artifacts, and adds Ruff per-file ignores for scripts.

Changes

Cohort / File(s) Summary
Hook configuration updates
./.claude/hookify.function-length.md, ./.claude/hookify.missing-logger.md
Replaced YAML regex filter keys from value to pattern for several file_path, new_text, and not_contains conditions.
No-future-annotations hook
./.claude/hookify.no-future-annotations.md
New hook that blocks from __future__ import annotations (enabled by default, block action and guidance).
CI Pages / Preview workflows
./.github/workflows/pages.yml, ./.github/workflows/pages-preview.yml
Added scripts/** to triggers, attached environment values to preview jobs, and inserted an "Export OpenAPI schema" step to run scripts/export_openapi.py before MkDocs build.
OpenAPI export script
./scripts/export_openapi.py
New script that boots ai_company.api.app, extracts OpenAPI schema and writes docs/_generated/openapi.json; exposes main(), OUTPUT_DIR, and OUTPUT_FILE.
Generated artifacts & linter ignores
./.gitignore, ./pyproject.toml
Ignored docs/_generated/; added Ruff per-file ignore for scripts/**/*.py (T20, PLC0415).
Documentation navigation & content
./mkdocs.yml, ./README.md, ./docs/index.md, ./docs/api/index.md, ./docs/architecture/index.md, ./docs/design/operations.md, ./CLAUDE.md
Reworked nav: added rest-api.md for REST/OpenAPI reference, introduced a Library Reference section linking generated API docs, and updated docs/CI guidance to mention OpenAPI export and endpoints.
REST API page and custom template
./docs/rest-api.md, ./docs/overrides/rest-api.html
Added rest-api.md with template front-matter and a custom rest-api.html that embeds the Scalar/OpenAPI UI, hides MkDocs chrome, and loads ../_generated/openapi.json.
Workflow environment flags & tooling
./.github/workflows/ci.yml, ./.github/workflows/release.yml, ./.github/workflows/zizmor.yml, .zizmor.yml
Added environment labels to CI/release jobs, updated zizmor workflow triggers and config reference, and added dependabot-cooldown rule in .zizmor.yml.

Sequence Diagram(s)

sequenceDiagram
    participant GH as "GitHub Actions"
    participant Script as "scripts/export_openapi.py"
    participant App as "ai_company.api.app"
    participant FS as "Filesystem"
    participant MkDocs as "MkDocs Build"

    GH->>Script: run scripts/export_openapi.py
    Script->>App: import create_app() & build app
    App-->>Script: return app.openapi_schema.to_schema()
    Script->>FS: write docs/_generated/openapi.json
    Script-->>GH: exit 0 (prints path)
    GH->>MkDocs: run mkdocs build (template reads generated JSON)
    MkDocs->>FS: read docs/_generated/openapi.json
    MkDocs-->>GH: produce site artifacts
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Copilot
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a static OpenAPI reference page with Scalar UI, which is the primary feature introduced across the PR.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, detailing the OpenAPI export, documentation restructuring, hookify fixes, and CI workflow updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/static-openapi-reference
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/static-openapi-reference

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the project's documentation by integrating a static OpenAPI reference page using Scalar UI. It introduces a dedicated script and CI steps to generate and serve the OpenAPI schema, providing a clear distinction between the REST API documentation and the auto-generated Python library reference. This change improves the discoverability and usability of the API documentation for developers and users alike, while also refining internal tooling and documentation structure.

Highlights

  • OpenAPI Reference Page: Added a static OpenAPI reference page powered by Scalar UI, which loads a CI-generated openapi.json schema.
  • OpenAPI Schema Export Script: Introduced a new Python script (scripts/export_openapi.py) to export the Litestar application's OpenAPI schema to docs/_generated/openapi.json.
  • Documentation Navigation Restructure: Restructured the MkDocs navigation to clearly separate 'API Reference' (for the new Scalar REST API page) and 'Library Reference' (for the existing mkdocstrings section).
  • CI Workflow Updates: Updated CI workflows (pages.yml, pages-preview.yml) to include the OpenAPI schema export step before the MkDocs build process.
  • Hookify Rule Enhancements: Fixed hookify rule field names from value to pattern and added a new no-future-annotations hookify rule.
  • Ruff Configuration: Added Ruff per-file ignores for scripts/**/*.py to allow print statements and deferred imports.
  • Documentation Content Updates: Updated various documentation files (CLAUDE.md, README.md, docs/index.md, docs/architecture/index.md, docs/design/operations.md) to reflect the new REST API vs. Library Reference split.
Changelog
  • .claude/hookify.function-length.md
    • Updated hookify rule to use pattern instead of value for regex matching.
  • .claude/hookify.missing-logger.md
    • Refactored hookify rule to use pattern instead of value for regex matching.
    • Removed file_content condition for get_logger.
  • .claude/hookify.no-future-annotations.md
    • Added a new hookify rule to block from __future__ import annotations imports.
  • .gitignore
    • Added docs/_generated/ to ignore generated OpenAPI schema files.
  • CLAUDE.md
    • Updated documentation build instructions to include OpenAPI schema export.
    • Clarified documentation sections, distinguishing between REST API and Library references.
    • Updated CI description to reflect OpenAPI schema export step.
  • README.md
    • Updated the documentation table to split "API Reference" into "API Reference (Scalar/OpenAPI)" and "Library Reference (docstrings)".
  • docs/api/index.md
    • Renamed the page title from "API Reference" to "Library Reference".
  • docs/architecture/index.md
    • Updated navigation links to differentiate between REST API and Library references.
  • docs/design/operations.md
    • Updated the description of interactive API documentation to reflect the new Scalar UI and OpenAPI JSON paths.
  • docs/index.md
    • Updated the main documentation table to distinguish between REST API and Library references.
  • docs/overrides/rest-api.html
    • Added a new HTML template for the Scalar UI OpenAPI reference page.
    • Included styling to hide MkDocs navigation and load the Scalar API reference script.
  • docs/rest-api.md
    • Added a new Markdown file to serve as the entry point for the Scalar UI OpenAPI reference page.
    • Configured it to use the rest-api.html template.
  • mkdocs.yml
    • Restructured the navigation to separate "API Reference" (pointing to the new Scalar UI page) and "Library Reference" (for auto-generated docstrings).
  • pyproject.toml
    • Added Ruff per-file ignores for scripts/**/*.py to allow print statements and deferred imports.
  • scripts/export_openapi.py
    • Added a new Python script to export the Litestar app's OpenAPI schema to a static JSON file.
Ignored Files
  • Ignored by pattern: .github/workflows/** (2)
    • .github/workflows/pages-preview.yml
    • .github/workflows/pages.yml
Activity
  • Pre-reviewed by 1 agent (docs-consistency), 12 findings addressed (2 CRITICAL, 5 MAJOR, 2 MEDIUM, 1 MINOR, 2 SUGGESTION)
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds a static OpenAPI reference page using Scalar UI, which is a great enhancement for API documentation. The changes include a new script to export the OpenAPI schema, updates to CI to run this script, and restructuring of the documentation to differentiate between the REST API reference and the library reference.

My review has two main points:

  1. A security and reliability improvement for the new Scalar UI page by pinning the external script version and using Subresource Integrity (SRI).
  2. A correction to a hookify rule for detecting missing loggers, which appears to have become overly broad and would likely cause a lot of noise for developers.

Overall, the changes are well-structured and the documentation updates are clear. Addressing these points will improve the robustness and developer experience of the new features.

- field: file_content
operator: not_contains
value: "get_logger"
pattern: "^\\s*(?:async\\s+)?(?:def |class )"
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.

high

This missing-logger rule seems to have been made overly broad by the removal of the condition that checks for the presence of get_logger. As it is now, it will trigger a warning for every new class or function, even in files that already have a logger. This is likely to create a lot of unnecessary warnings for developers.

To fix this, I suggest re-introducing the check for the absence of get_logger. You could add the following condition to the list:

  - field: file_content
    operator: not_contains
    pattern: "get_logger"

Comment thread docs/overrides/rest-api.html Outdated
data-url="../_generated/openapi.json"
data-configuration='{"theme": "default"}'
></script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
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.

medium

For better reproducibility and to avoid unexpected breaking changes, it's a good practice to pin the version of external scripts loaded from a CDN.

Additionally, for security, consider adding a Subresource Integrity (SRI) hash to ensure the script hasn't been tampered with. This is especially important for a security-conscious project.

<script
  src="https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.20.11"
  integrity="sha384-your-hash-here"
  crossorigin="anonymous"
></script>

You'll need to generate the correct integrity hash for the script.

<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.20.11"></script>

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.64%. Comparing base (b63cee7) to head (2d73ff9).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #318   +/-   ##
=======================================
  Coverage   93.64%   93.64%           
=======================================
  Files         427      427           
  Lines       19177    19177           
  Branches     1846     1846           
=======================================
  Hits        17959    17959           
  Misses        943      943           
  Partials      275      275           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 12, 2026

Greptile Summary

This PR introduces a static OpenAPI reference page powered by Scalar UI, wired into the MkDocs documentation site. A new scripts/export_openapi.py script instantiates the Litestar app at build time to extract its OpenAPI schema, which is then consumed by a custom MkDocs template (docs/overrides/rest-api.html) that renders the full Scalar UI experience. The CI workflows are updated to run the export step before every MkDocs build, and all documentation links are updated to distinguish the new "API Reference" (REST/Scalar) from "Library Reference" (mkdocstrings/Griffe). Hookify rules are also migrated from the old value: field name to pattern:.

Key changes:

  • scripts/export_openapi.py — New build-time script that instantiates create_app() and writes docs/_generated/openapi.json; deferred import and broad error handling are appropriate for a CI utility script.
  • docs/overrides/rest-api.html — Custom MkDocs template that strips Material constraints and embeds Scalar UI; the CDN script is pinned to @scalar/api-reference@1.48.5.
  • CI workflowspages.yml and pages-preview.yml both add the OpenAPI export step and scripts/** path trigger; ci.yml and release.yml gain named environment: scoping for secrets.
  • Hookify rulesvalue:pattern: rename applied correctly to missing-logger and function-length; new no-future-annotations rule uses a structurally inconsistent top-level pattern: field that may not function as intended (see inline comment).
  • Nav / docs — Clean split of "API Reference" and "Library Reference" across mkdocs.yml, README.md, docs/index.md, and docs/architecture/index.md.

Confidence Score: 4/5

  • PR is safe to merge; core documentation and CI changes are solid, with one likely-inactive hookify rule to fix.
  • The Scalar UI integration, CI pipeline changes, and nav restructure are all well-implemented. The one logic concern is the no-future-annotations hookify rule whose top-level pattern: field is inconsistent with the conditions: schema used by the other rules — it may silently never fire. The export script's unguarded file-write path is a minor style point. Everything else is straightforward and correct.
  • .claude/hookify.no-future-annotations.md — the top-level pattern: field should be moved into a conditions: block to match the hookify schema used by the other rules.

Important Files Changed

Filename Overview
.claude/hookify.no-future-annotations.md New hookify rule to block from __future__ import annotations, but uses a top-level pattern: field instead of a conditions: block — inconsistent with the other hookify rules in this repo; likely a no-op or incorrectly scoped.
scripts/export_openapi.py New script that instantiates the Litestar app, extracts its OpenAPI schema, and writes it to docs/_generated/openapi.json. Import is deferred inside main() to avoid module-level side effects; broad try/except around the app-instantiation path is reasonable. File-write errors fall outside the error-handling block and produce raw tracebacks.
docs/overrides/rest-api.html MkDocs override template that renders the Scalar UI full-width, loading the schema via a relative data-url. CDN script is now pinned to @scalar/api-reference@1.48.5; no SRI hash is present (acceptable for a docs page). Relative ../ path correctly resolves to docs/_generated/openapi.json given MkDocs's use_directory_urls output layout.
.github/workflows/pages.yml Adds scripts/** to the path trigger and inserts an "Export OpenAPI schema" step before the MkDocs build. Clean, minimal change.
.github/workflows/pages-preview.yml Mirrors the pages.yml changes (script trigger, OpenAPI export step) and adds environment: cloudflare-preview to the deploy/cleanup jobs, which correctly gates secrets to the named environment.
mkdocs.yml Nav restructure: "API Reference" now points directly to rest-api.md (the Scalar page), and "Library Reference" becomes the mkdocstrings section. Clean and consistent with the documentation updates.
pyproject.toml Adds a scripts/**/*.py per-file-ignores entry allowing print (T20) and deferred imports (PLC0415) in scripts. Appropriate and consistent with how scripts/export_openapi.py is written.

Sequence Diagram

sequenceDiagram
    participant CI as CI Workflow
    participant Script as export_openapi.py
    participant App as create_app()
    participant FS as docs/_generated/
    participant MkDocs as MkDocs Build
    participant Scalar as Scalar UI (CDN)
    participant Browser as Browser

    CI->>Script: uv run python scripts/export_openapi.py
    Script->>App: import & instantiate
    App-->>Script: app.openapi_schema.to_schema()
    Script->>FS: write openapi.json
    FS-->>CI: docs/_generated/openapi.json

    CI->>MkDocs: uv run mkdocs build --strict
    MkDocs->>FS: copy openapi.json → _site/docs/_generated/
    MkDocs-->>CI: _site/ (static HTML)

    Browser->>MkDocs: GET /docs/rest-api/
    MkDocs-->>Browser: rest-api.html (Scalar template)
    Browser->>Scalar: load @scalar/api-reference@1.48.5 (CDN)
    Scalar-->>Browser: Scalar JS bundle
    Browser->>FS: fetch ../_generated/openapi.json
    FS-->>Browser: openapi.json
    Scalar-->>Browser: render interactive API reference
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: .claude/hookify.no-future-annotations.md
Line: 5-6

Comment:
**Top-level `pattern` field may be silently ignored**

The other two hookify rules in this repo (`function-length.md`, `missing-logger.md`) place all matching criteria inside a `conditions:` array of `{field, operator, pattern}` objects. This rule instead puts `pattern:` at the top level of the frontmatter alongside `event:` and `action:`.

If hookify only evaluates match criteria when they appear inside a `conditions:` block, this top-level `pattern` field will be silently ignored and the rule will **always** fire as a block action on every file-write event (because there are no conditions to fail). Or, depending on hookify's schema validation, it may be treated as a no-op entirely and never fire.

To align with the schema used by the other rules, the condition should be expressed as:

```yaml
conditions:
  - field: new_text
    operator: regex_match
    pattern: "from\\s+__future__\\s+import\\s+annotations"
```

or, if you want to match against the full file content:

```yaml
conditions:
  - field: file_content
    operator: regex_match
    pattern: "from\\s+__future__\\s+import\\s+annotations"
```

Either way, the top-level bare `pattern:` field is inconsistent with the rest of the hookify schema in use here and risks making the rule a no-op.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: scripts/export_openapi.py
Line: 29-34

Comment:
**File write errors produce a raw traceback instead of a clean error message**

The `OUTPUT_DIR.mkdir(...)` and `OUTPUT_FILE.write_text(...)` calls are outside the `try/except` block. If either fails (e.g., permission denied, disk full), Python will emit an unhandled exception traceback directly to stderr with no contextual message, and the exit code will be `1` from Python's default handler — which is correct behaviour, but the error output will be harder to interpret in CI logs than the clean message produced for the import/schema failure path.

Consider wrapping the write phase in the same (or a separate) `try/except` with a diagnostic `print(..., file=sys.stderr)` so both failure modes produce equally readable CI output:

```python
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    try:
        OUTPUT_FILE.write_text(
            json.dumps(schema_dict, indent=2, ensure_ascii=False) + "\n",
            encoding="utf-8",
        )
    except OSError as exc:
        print(f"Failed to write OpenAPI schema to {OUTPUT_FILE}: {exc}", file=sys.stderr)
        return 1
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 2d73ff9

Comment thread .claude/hookify.missing-logger.md
Comment thread docs/overrides/rest-api.html Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a static REST API reference page to the MkDocs site using Scalar, backed by a CI-generated OpenAPI JSON export from the Litestar app. Also updates documentation navigation and CLAUDE/hookify guidance to reflect the new REST vs library reference split.

Changes:

  • Add scripts/export_openapi.py and run it in Pages/Preview workflows to generate docs/_generated/openapi.json before MkDocs builds.
  • Add a new MkDocs page (docs/rest-api.md) using a custom Material template (docs/overrides/rest-api.html) to render Scalar against the generated schema.
  • Update nav/links and contributor docs (README/docs index/CLAUDE) to distinguish REST API reference vs mkdocstrings library reference.

Reviewed changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
scripts/export_openapi.py New CLI script to instantiate the Litestar app and write a static OpenAPI JSON into docs/_generated/.
README.md Updates documentation table links to point to REST API vs library reference pages.
pyproject.toml Relaxes ruff rules for scripts/** (allow print and deferred imports).
mkdocs.yml Adds “API Reference” (REST/Scalar) and renames mkdocstrings output to “Library Reference”.
docs/rest-api.md New MkDocs page that selects the custom rest-api.html template.
docs/overrides/rest-api.html New Material override template embedding Scalar and loading the generated OpenAPI JSON.
docs/index.md Updates docs landing page links to REST API vs library reference.
docs/design/operations.md Corrects referenced interactive docs endpoints to /api (Scalar) and /docs (OpenAPI JSON).
docs/architecture/index.md Updates architecture index links to REST API vs library reference.
docs/api/index.md Renames the mkdocstrings section header to “Library Reference”.
CLAUDE.md Documents the new OpenAPI export step, REST API page, and scripts directory conventions.
.gitignore Ignores docs/_generated/ output produced during docs builds.
.github/workflows/pages.yml Adds scripts/** trigger and runs OpenAPI export before mkdocs build.
.github/workflows/pages-preview.yml Adds scripts/** trigger and runs OpenAPI export before mkdocs build.
.claude/hookify.no-future-annotations.md Adds a hookify rule blocking from __future__ import annotations.
.claude/hookify.missing-logger.md Updates hookify rule fields/structure for logger reminders.
.claude/hookify.function-length.md Updates hookify rule fields/structure for function length reminders.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 25 to 30
operator: not_contains
value: "protocol.py"
pattern: "protocol.py"
- field: new_text
operator: regex_match
value: "^\\s*(?:async\\s+)?(?:def |class )"
- field: file_content
operator: not_contains
value: "get_logger"
pattern: "^\\s*(?:async\\s+)?(?:def |class )"
action: warn
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

This missing-logger hook no longer checks whether the module actually lacks get_logger/logger = get_logger(__name__) (the prior file_content not_contains get_logger condition was removed). As written, it will warn on any change that adds/modifies a def/class in src/ai_company/** even when the logger is already present, which doesn’t match the rule’s intent/message. Consider reintroducing a file_content condition (or equivalent) to only warn when the logger import/assignment is missing, or update the rule text/name to reflect the new behavior.

Copilot uses AI. Check for mistakes.
Comment thread docs/overrides/rest-api.html Outdated
data-url="../_generated/openapi.json"
data-configuration='{"theme": "default"}'
></script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The Scalar UI bundle is loaded from jsDelivr without a pinned version. This is a supply-chain / reproducibility risk (the docs can change or break when the CDN content updates). Consider pinning @scalar/api-reference to an explicit version and ideally adding Subresource Integrity (or vendoring the asset) so the rendered API docs are deterministic and safer.

Suggested change
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.25.109"></script>

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/hookify.missing-logger.md:
- Around line 27-29: The rule currently fires on any change where field
"new_text" matches the regex pattern for leading "def" or "class" but doesn't
check that the logger import and instantiation are absent; update the predicate
for the hook (the "new_text" regex_match rule) to include negative content
checks that verify the module does NOT contain the lines "from
ai_company.observability import get_logger" and "logger = get_logger(__name__)"
before warning. Concretely, add negative regex_match (or regex_not_match)
predicates that search the file content for those exact symbols (get_logger
import and logger = get_logger(__name__)) so the hook only triggers when both
are missing.

In `@docs/overrides/rest-api.html`:
- Line 31: The CDN script URL is unpinned (src uses `@scalar/api-reference`) so it
will float to newest releases; update the script tag source to a fixed version
(e.g., change "@scalar/api-reference" to a specific release like
"@scalar/api-reference@<major>.<minor>.<patch>" or the exact bundled file URL)
to lock the API reference, then commit the updated src so the docs load a known
stable version; ensure the same pinned version is used wherever
"@scalar/api-reference" appears.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b0dbf579-66cb-46d7-bdfe-f4d11f986618

📥 Commits

Reviewing files that changed from the base of the PR and between b63cee7 and 5f6bb2e.

📒 Files selected for processing (18)
  • .claude/hookify.function-length.md
  • .claude/hookify.missing-logger.md
  • .claude/hookify.no-future-annotations.md
  • .github/workflows/pages-preview.yml
  • .github/workflows/pages.yml
  • .gitignore
  • CLAUDE.md
  • README.md
  • docs/api/index.md
  • docs/architecture/index.md
  • docs/design/operations.md
  • docs/index.md
  • docs/overrides/.gitkeep
  • docs/overrides/rest-api.html
  • docs/rest-api.md
  • mkdocs.yml
  • pyproject.toml
  • scripts/export_openapi.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Agent
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (2)
pyproject.toml

📄 CodeRabbit inference engine (CLAUDE.md)

All versions in pyproject.toml must use == for pinned versions

Files:

  • pyproject.toml
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do NOT use from __future__ import annotations — Python 3.14 has PEP 649 native lazy annotations
Use except A, B: (no parentheses) — PEP 758 except syntax enforced by ruff on Python 3.14
Include type hints on all public functions and classes; ensure mypy strict mode compliance
Use Google-style docstrings on all public classes and functions (enforced by ruff D rules)
Never mutate existing objects; create new objects instead. For non-Pydantic internal collections, use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model
Use Pydantic v2 with BaseModel, model_validator, computed_field, and ConfigDict. Use @computed_field for derived values instead of storing redundant fields. Use NotBlankStr for all identifier/name fields
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (multiple tool invocations, parallel agent calls). Use structured concurrency over bare create_task
Keep functions under 50 lines; keep files under 800 lines
Handle errors explicitly; never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)
Line length: 88 characters (enforced by ruff)

Files:

  • scripts/export_openapi.py
🧠 Learnings (5)
📚 Learning: 2026-03-12T08:11:41.492Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-12T08:11:41.492Z
Learning: ALWAYS read the relevant `docs/design/` page before implementing any feature or planning any issue. The design spec is the starting point for architecture, data models, and behavior

Applied to files:

  • docs/architecture/index.md
📚 Learning: 2026-03-12T08:11:41.492Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-12T08:11:41.492Z
Learning: Applies to src/ai_company/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation and internal flow

Applied to files:

  • .claude/hookify.function-length.md
  • .claude/hookify.missing-logger.md
📚 Learning: 2026-03-12T08:11:41.492Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-12T08:11:41.492Z
Learning: Applies to **/*.py : Do NOT use `from __future__ import annotations` — Python 3.14 has PEP 649 native lazy annotations

Applied to files:

  • .claude/hookify.no-future-annotations.md
📚 Learning: 2026-03-12T08:11:41.492Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-12T08:11:41.492Z
Learning: Applies to src/ai_company/**/*.py : Always use `logger` as the variable name (not `_logger`, not `log`)

Applied to files:

  • .claude/hookify.missing-logger.md
📚 Learning: 2026-03-12T08:11:41.492Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-12T08:11:41.492Z
Learning: Applies to src/ai_company/**/*.py : Every module with business logic MUST import and use `from ai_company.observability import get_logger` and create `logger = get_logger(__name__)`. Never use `import logging`, `logging.getLogger()`, or `print()`

Applied to files:

  • .claude/hookify.missing-logger.md
🧬 Code graph analysis (1)
scripts/export_openapi.py (1)
src/ai_company/api/app.py (1)
  • create_app (284-401)
🪛 GitHub Actions: Workflow Security
.github/workflows/pages-preview.yml

[warning] 167-167: Secrets referenced without a dedicated environment (CLOUDFLARE_API_TOKEN).


[warning] 168-168: Secrets referenced without a dedicated environment (CLOUDFLARE_ACCOUNT_ID).


[warning] 262-262: Secrets referenced without a dedicated environment (CLOUDFLARE_API_TOKEN).


[warning] 263-263: Secrets referenced without a dedicated environment (CLOUDFLARE_ACCOUNT_ID).

🪛 HTMLHint (1.9.2)
docs/overrides/rest-api.html

[error] 1-1: Doctype must be declared before any non-comment content.

(doctype-first)

🪛 LanguageTool
CLAUDE.md

[style] ~55-~55: A comma is missing here.
Context: ...docs/overrides/(MkDocscustom_dir— e.g.rest-api.html` for the Scalar API page...

(EG_NO_COMMA)


[uncategorized] ~59-~59: The official name of this software platform is spelled with a capital “H”.
Context: ...**: mkdocs.yml at repo root - CI: .github/workflows/pages.yml — exports OpenAPI ...

(GITHUB)

🪛 markdownlint-cli2 (0.21.0)
.claude/hookify.no-future-annotations.md

[warning] 9-9: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🔇 Additional comments (20)
.claude/hookify.function-length.md (1)

8-11: Pattern-based matching looks right here.

This keeps the reminder scoped to Python files under src/ai_company/ and only fires when a function definition is part of the change.

.gitignore (1)

56-58: LGTM!

The ignore rule correctly excludes the generated OpenAPI schema directory, preventing CI-generated artifacts from being committed. The comment clearly documents the source script.

pyproject.toml (1)

139-142: LGTM!

The per-file ignores are appropriate for CLI scripts:

  • T20 allows print() for script output
  • PLC0415 allows deferred imports, which is useful for scripts that need to import heavy modules only when executed
docs/design/operations.md (1)

945-945: LGTM!

The documentation accurately reflects the OpenAPI configuration: /api for Scalar UI and /docs for the raw OpenAPI JSON schema. This is consistent with the OpenAPIConfig in src/ai_company/api/app.py.

.claude/hookify.no-future-annotations.md (1)

1-14: LGTM!

The hookify rule correctly enforces the project's coding guideline against from __future__ import annotations. The regex pattern accurately matches the import statement, and the explanation clearly communicates why this import is forbidden (PEP 649 native lazy annotations in Python 3.14).

The markdownlint warning about missing top-level heading is a false positive — hookify configuration files use YAML frontmatter as their structure.

docs/overrides/rest-api.html (1)

1-32: Template structure and implementation look good.

The HTMLHint doctype warning is a false positive — this is a Jinja2 template that extends main.html, not a standalone HTML document. The parent template provides the doctype.

The CSS correctly provides full viewport width for Scalar while hiding MkDocs navigation, and the relative path to openapi.json will resolve correctly from the rendered page location.

.github/workflows/pages-preview.yml (2)

14-14: LGTM!

Adding scripts/** to path triggers ensures preview builds are triggered when the OpenAPI export script changes.


50-52: LGTM!

The OpenAPI schema export step is correctly positioned before the MkDocs build, ensuring the generated openapi.json is available when Scalar renders the REST API reference page.

.github/workflows/pages.yml (2)

13-13: LGTM!

Consistent with the preview workflow — script changes will trigger production builds.


48-50: LGTM!

The OpenAPI export step mirrors the preview workflow, ensuring consistent behavior between preview and production deployments.

scripts/export_openapi.py (1)

18-30: LGTM! Clean implementation of OpenAPI schema export.

The script correctly:

  • Defers the heavy import inside main() (appropriate for a CLI script)
  • Creates a minimal app instance for schema extraction
  • Uses the correct Litestar API (app.openapi_schema.to_schema())
  • Ensures the output directory exists
  • Writes pretty-printed JSON with proper encoding

Note: create_app() without arguments will log a warning about missing services, but this is acceptable since only the OpenAPI schema is needed, not runtime functionality.

docs/api/index.md (1)

1-1: LGTM!

The heading rename from "API Reference" to "Library Reference" correctly reflects the documentation restructure, distinguishing mkdocstrings-generated source code docs from the new Scalar/OpenAPI REST API reference.

docs/architecture/index.md (1)

65-66: LGTM!

The new links correctly point to the REST API and Library Reference pages with appropriate relative paths and consistent descriptions.

docs/rest-api.md (1)

1-5: LGTM!

Clean setup using MkDocs front matter to specify a custom template. The rest-api.html template (in docs/overrides/) will render the Scalar UI with the OpenAPI schema.

docs/index.md (1)

124-125: LGTM!

The "Further Reading" table correctly splits the previous single API Reference entry into two distinct entries with appropriate relative paths.

README.md (1)

121-122: LGTM!

Paths correctly include the docs/ prefix for links from the repository root, and descriptions are consistent with other documentation files.

mkdocs.yml (1)

124-140: LGTM!

The navigation restructure cleanly separates the REST API reference (Scalar/OpenAPI) from the Library Reference (mkdocstrings). The Library Reference section properly groups all module documentation pages.

CLAUDE.md (3)

41-41: LGTM!

Correctly documents the new OpenAPI export command that must run before mkdocs build.


48-59: LGTM!

Comprehensive documentation of the new REST API reference workflow, including:

  • REST API reference page with Scalar UI
  • Library reference (mkdocstrings)
  • Custom templates directory
  • Scripts directory with relaxed ruff rules
  • CI workflow update for OpenAPI export

183-183: LGTM!

CI documentation accurately reflects the updated Pages workflow that now exports the OpenAPI schema and includes scripts/** in triggers.

Comment on lines 27 to +29
- field: new_text
operator: regex_match
value: "^\\s*(?:async\\s+)?(?:def |class )"
- field: file_content
operator: not_contains
value: "get_logger"
pattern: "^\\s*(?:async\\s+)?(?:def |class )"
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n ".claude/hookify.missing-logger.md"

Repository: Aureliolo/synthorg

Length of output: 1157


This hook no longer detects a missing logger.

The rule warns on any change to a qualifying src/ai_company/ module that contains a def or class, regardless of whether the required logger setup exists. It needs negative content predicates to verify that from ai_company.observability import get_logger and logger = get_logger(__name__) are actually absent before firing the warning.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/hookify.missing-logger.md around lines 27 - 29, The rule currently
fires on any change where field "new_text" matches the regex pattern for leading
"def" or "class" but doesn't check that the logger import and instantiation are
absent; update the predicate for the hook (the "new_text" regex_match rule) to
include negative content checks that verify the module does NOT contain the
lines "from ai_company.observability import get_logger" and "logger =
get_logger(__name__)" before warning. Concretely, add negative regex_match (or
regex_not_match) predicates that search the file content for those exact symbols
(get_logger import and logger = get_logger(__name__)) so the hook only triggers
when both are missing.

Comment thread docs/overrides/rest-api.html Outdated
- Restore file_content/get_logger guard in missing-logger hookify rule
  (was accidentally removed, causing false positives on every file)
- Pin Scalar CDN to v1.48.5 for reproducibility
- Improve Scalar UI: full-page layout, modern theme, hide footer/sidebar
- Add error handling to export_openapi.py for CI failures
- Fix endpoint URLs: Scalar UI is at /docs/api, not /api
- Complete CLAUDE.md Pages trigger list (add site/**, pyproject.toml, uv.lock)
- Remove no-op tabs block and misplaced comment from rest-api.html
- Add `environment:` declarations to jobs using secrets:
  - ci.yml test job → `ci` environment (CODECOV_TOKEN)
  - pages-preview.yml deploy/cleanup → `cloudflare-preview` (Cloudflare secrets)
  - release.yml release-please → `release` (RELEASE_PLEASE_TOKEN)
- Add .zizmor.yml config to suppress dependabot-cooldown (daily is intentional)
- Add .zizmor.yml and .github/dependabot.yml to zizmor workflow path triggers
Copilot AI review requested due to automatic review settings March 12, 2026 09:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 22 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/export_openapi.py
Comment on lines +25 to +27
except Exception as exc:
print(f"Failed to export OpenAPI schema: {exc}", file=sys.stderr)
return 1
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The exception handler only prints str(exc), which drops the traceback and makes CI failures hard to diagnose. Consider logging/printing the full traceback (e.g., via traceback.print_exception(exc) or logger.exception(...)) before returning a non-zero exit code.

Copilot uses AI. Check for mistakes.
.md-content__inner {
min-height: calc(100vh - 3.6rem);
display: flex;
flex-direction: column;
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

This loads Scalar from a third-party CDN without Subresource Integrity (SRI) and without a local fallback. For a docs site this is still a supply-chain risk; consider vendoring the asset in the repo (or at least adding an integrity attribute + crossorigin) so the rendered API reference can't be silently altered by a compromised CDN.

Copilot uses AI. Check for mistakes.
Comment thread docs/design/operations.md
or similar). Not a priority -- the API is fully self-sufficient. To be determined whether a
dedicated CLI is warranted or whether `curl`/`httpie` and the interactive Scalar docs at
`/docs/api` suffice.
`/docs/api` (Scalar UI) and `/docs` (OpenAPI JSON) suffice.
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

These paths look inconsistent with the Litestar OpenAPI config in ai_company.api.app.create_app() (OpenAPI config path is /docs and Scalar UI is configured at /api). If this section is referring to the running API server, the correct URLs should match the actual routes (e.g., Scalar at /api and schema at something like /docs/openapi.json).

Suggested change
`/docs/api` (Scalar UI) and `/docs` (OpenAPI JSON) suffice.
`/api` (Scalar UI) and `/docs/openapi.json` (OpenAPI JSON) suffice.

Copilot uses AI. Check for mistakes.
Comment thread scripts/export_openapi.py
Comment on lines +29 to +34
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
OUTPUT_FILE.write_text(
json.dumps(schema_dict, indent=2, ensure_ascii=False) + "\n",
encoding="utf-8",
)
print(f"Wrote OpenAPI schema to {OUTPUT_FILE.relative_to(REPO_ROOT)}")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

File write errors produce a raw traceback instead of a clean error message

The OUTPUT_DIR.mkdir(...) and OUTPUT_FILE.write_text(...) calls are outside the try/except block. If either fails (e.g., permission denied, disk full), Python will emit an unhandled exception traceback directly to stderr with no contextual message, and the exit code will be 1 from Python's default handler — which is correct behaviour, but the error output will be harder to interpret in CI logs than the clean message produced for the import/schema failure path.

Consider wrapping the write phase in the same (or a separate) try/except with a diagnostic print(..., file=sys.stderr) so both failure modes produce equally readable CI output:

    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    try:
        OUTPUT_FILE.write_text(
            json.dumps(schema_dict, indent=2, ensure_ascii=False) + "\n",
            encoding="utf-8",
        )
    except OSError as exc:
        print(f"Failed to write OpenAPI schema to {OUTPUT_FILE}: {exc}", file=sys.stderr)
        return 1
Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/export_openapi.py
Line: 29-34

Comment:
**File write errors produce a raw traceback instead of a clean error message**

The `OUTPUT_DIR.mkdir(...)` and `OUTPUT_FILE.write_text(...)` calls are outside the `try/except` block. If either fails (e.g., permission denied, disk full), Python will emit an unhandled exception traceback directly to stderr with no contextual message, and the exit code will be `1` from Python's default handler — which is correct behaviour, but the error output will be harder to interpret in CI logs than the clean message produced for the import/schema failure path.

Consider wrapping the write phase in the same (or a separate) `try/except` with a diagnostic `print(..., file=sys.stderr)` so both failure modes produce equally readable CI output:

```python
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    try:
        OUTPUT_FILE.write_text(
            json.dumps(schema_dict, indent=2, ensure_ascii=False) + "\n",
            encoding="utf-8",
        )
    except OSError as exc:
        print(f"Failed to write OpenAPI schema to {OUTPUT_FILE}: {exc}", file=sys.stderr)
        return 1
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.zizmor.yml:
- Around line 4-5: The .zizmor.yml uses an unsupported rule field "action: skip"
for the dependabot-cooldown rule; replace that line with "disable: true" so the
rule becomes disabled (update the dependabot-cooldown entry to use disable: true
instead of action: skip).

In `@docs/overrides/rest-api.html`:
- Around line 31-44: The .rest-api-banner currently uses a container-level
opacity which dims all children; remove the opacity property from
.rest-api-banner and instead lower perceived contrast by adjusting only the
background or border color (e.g., use a semi-transparent background color or
color variable with alpha) while keeping text and inline .rest-api-banner code
at full opacity; ensure .rest-api-banner code retains its own background and
font-color so code chips remain fully legible.
- Around line 47-58: The page relies on the dynamic `@scalar/api-reference` script
(script element with id "api-reference" and
data-url="../_generated/openapi.json") and currently has no non-JS fallback; add
a simple noscript fallback that exposes the bundled OpenAPI JSON (the same
../_generated/openapi.json) as either a direct link and/or inline preformatted
JSON so users without JS or blocked CDN can still access the static schema;
ensure the fallback references the same data-url value and is placed near the
existing api-reference script element.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 11a8fe34-6d91-407a-b01a-a1ba8f6888b2

📥 Commits

Reviewing files that changed from the base of the PR and between dbcaf1f and 2d73ff9.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .github/workflows/pages-preview.yml
  • .github/workflows/release.yml
  • .github/workflows/zizmor.yml
  • .zizmor.yml
  • docs/overrides/rest-api.html
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
🪛 GitHub Actions: Workflow Security
.zizmor.yml

[error] 5-5: Zizmor configuration error: unknown field action, expected one of disable, ignore, config at line 5 column 5 in .zizmor.yml.

🪛 HTMLHint (1.9.2)
docs/overrides/rest-api.html

[error] 1-1: Doctype must be declared before any non-comment content.

(doctype-first)

🔇 Additional comments (7)
.github/workflows/release.yml (1)

13-13: Good hardening for the release job.

Scoping this secret-using job to the release environment is a solid defense-in-depth change and aligns the workflow with environment-based policy controls.

.github/workflows/ci.yml (1)

51-51: LGTM! Good security improvement for secrets handling.

Adding environment: ci to the test job addresses the zizmor secrets-outside-env finding by ensuring that secrets.CODECOV_TOKEN (used at lines 83 and 91) is accessed within a declared environment context. This is a security best practice that enables environment protection rules.

Ensure the ci environment is created in the repository settings (Settings → Environments) if it doesn't already exist, otherwise this job will fail.

.github/workflows/pages-preview.yml (4)

14-14: LGTM!

Adding scripts/** to the path triggers ensures the workflow runs when the OpenAPI export script or other doc-related scripts are modified, which is necessary since the build now depends on scripts/export_openapi.py.


50-52: LGTM!

The OpenAPI export step is correctly positioned after dependency installation and before the MkDocs build, ensuring the schema is available when docs are built. The step uses uv run consistently with other Python commands in the workflow.


149-149: LGTM!

Adding environment: cloudflare-preview scopes secrets access to this environment context, addressing the zizmor secrets-outside-env security finding. This is a best practice for jobs that use sensitive credentials.


227-227: LGTM!

Consistent with the deploy-preview job, adding the environment declaration here properly scopes the Cloudflare secrets used for deployment cleanup.

.github/workflows/zizmor.yml (1)

8-9: Explicit config wiring and path filters look good.

Re-running on .zizmor.yml / .github/dependabot.yml changes and passing config: .zizmor.yml makes the workflow react to policy updates and avoids relying on config auto-discovery.

Also applies to: 14-15, 36-37

Comment thread .zizmor.yml
Comment on lines +4 to +5
dependabot-cooldown:
action: skip
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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

zizmor configuration schema rule options disable ignore

💡 Result:

In zizmor.yml, per-rule configuration lives under rules.<id> and you typically have three knobs: disable, ignore, and (sometimes) config. [1]

Disable a rule (turn the audit off entirely)

rules:
  template-injection:
    disable: true

This disables that audit completely. [1]

Ignore specific findings (preferred vs disabling)

rules.<id>.ignore is an array of locations in the form:
filename.yml[:line[:column]] (line/column are optional and 1-based). [1]

rules:
  template-injection:
    ignore:
      - ci.yml:100        # ignore any column on line 100
      - tests.yml         # ignore entire file
      - pypi.yml:12:10    # ignore a specific line+column

Note: composite-action findings can’t currently be ignored via zizmor.yml; use inline comments for those. [1]

Ignore via inline comments (one-off suppression)

You can ignore an individual finding inline with:

  • # zizmor: ignore[rulename]
  • multiple rules: # zizmor: ignore[rule1,rule2] [2]

Per-rule options (when supported)

Some audits expose additional settings under:

rules:
  unpinned-uses:
    config: { ... }

(Only some rules are configurable; it depends on the audit.) [1]

“Configuration schema”

As of zizmor v1.20.0, zizmor’s configuration has an official JSON schema (intended to be available via SchemaStore). [3]

Sources: [1] [2] [3]


🏁 Script executed:

# Search for zizmor repository and configuration documentation
# First, let's look for any zizmor-related files in the current repository
git ls-files | head -20

Repository: Aureliolo/synthorg

Length of output: 684


🌐 Web query:

zizmor dependabot-cooldown rule documentation

💡 Result:

zizmor’s dependabot-cooldown audit is documented on the Audit Rules page under the “dependabot-cooldown” section. It flags Dependabot configs that omit cooldown or set an insufficient cooldown.default-days. [1]

  • Docs (direct): https://docs.zizmor.sh/audits/#dependabot-cooldown [1]
  • Config knob: rules.dependabot-cooldown.config.days (minimum acceptable cooldown.default-days; default: 7) [1]
  • Suggested remediation (example):
    cooldown:
      default-days: 7
    [1]

For the underlying Dependabot cooldown syntax/options, see GitHub’s docs section “Setting up a cooldown period for dependency updates.” [2]

Sources: [1] https://docs.zizmor.sh/audits/ , [2] https://docs.github.com/en/code-security/tutorials/secure-your-dependencies/optimizing-pr-creation-version-updates


🏁 Script executed:

# Search for zizmor repository structure to understand rule definitions
curl -s https://api.github.com/repos/nozaq/zizmor/contents | head -50 2>/dev/null || echo "Cannot access GitHub API"

Repository: Aureliolo/synthorg

Length of output: 341


Replace the unsupported zizmor rule field.

action: skip is not valid here; zizmor rule configuration only accepts disable, ignore, or config. This causes the workflow to fail parsing .zizmor.yml. Use disable: true to turn off the dependabot-cooldown rule entirely.

🧰 Tools
🪛 GitHub Actions: Workflow Security

[error] 5-5: Zizmor configuration error: unknown field action, expected one of disable, ignore, config at line 5 column 5 in .zizmor.yml.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.zizmor.yml around lines 4 - 5, The .zizmor.yml uses an unsupported rule
field "action: skip" for the dependabot-cooldown rule; replace that line with
"disable: true" so the rule becomes disabled (update the dependabot-cooldown
entry to use disable: true instead of action: skip).

Comment on lines +31 to +44
/* Disclaimer banner */
.rest-api-banner {
padding: 0.75rem 1.5rem;
font-size: 0.85rem;
opacity: 0.7;
border-bottom: 1px solid var(--md-default-fg-color--lightest);
flex-shrink: 0;
}
.rest-api-banner code {
background: var(--md-code-bg-color);
padding: 0.1rem 0.4rem;
border-radius: 0.2rem;
font-size: 0.8rem;
}
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.

⚠️ Potential issue | 🟡 Minor

Avoid reducing banner contrast with container opacity.

Applying opacity to the whole banner dims all text and code chips. For a page-level disclaimer, this is easy to miss in low-contrast themes.

Proposed fix
   .rest-api-banner {
     padding: 0.75rem 1.5rem;
     font-size: 0.85rem;
-    opacity: 0.7;
+    color: var(--md-default-fg-color--light);
     border-bottom: 1px solid var(--md-default-fg-color--lightest);
     flex-shrink: 0;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* Disclaimer banner */
.rest-api-banner {
padding: 0.75rem 1.5rem;
font-size: 0.85rem;
opacity: 0.7;
border-bottom: 1px solid var(--md-default-fg-color--lightest);
flex-shrink: 0;
}
.rest-api-banner code {
background: var(--md-code-bg-color);
padding: 0.1rem 0.4rem;
border-radius: 0.2rem;
font-size: 0.8rem;
}
/* Disclaimer banner */
.rest-api-banner {
padding: 0.75rem 1.5rem;
font-size: 0.85rem;
color: var(--md-default-fg-color--light);
border-bottom: 1px solid var(--md-default-fg-color--lightest);
flex-shrink: 0;
}
.rest-api-banner code {
background: var(--md-code-bg-color);
padding: 0.1rem 0.4rem;
border-radius: 0.2rem;
font-size: 0.8rem;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/overrides/rest-api.html` around lines 31 - 44, The .rest-api-banner
currently uses a container-level opacity which dims all children; remove the
opacity property from .rest-api-banner and instead lower perceived contrast by
adjusting only the background or border color (e.g., use a semi-transparent
background color or color variable with alpha) while keeping text and inline
.rest-api-banner code at full opacity; ensure .rest-api-banner code retains its
own background and font-color so code chips remain fully legible.

Comment on lines +47 to +58
<div class="rest-api-banner">
This is a static snapshot of the OpenAPI schema.
When the server is running, interactive docs are available at
<code>/docs/api</code> (Scalar) and <code>/docs</code> (OpenAPI JSON).
</div>

<script
id="api-reference"
data-url="../_generated/openapi.json"
data-configuration='{"theme": "default", "layout": "modern"}'
></script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.48.5"></script>
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.

⚠️ Potential issue | 🟠 Major

Add a fallback path to the bundled schema.

If JS is disabled or jsDelivr is blocked, this page loses its primary content even though the static openapi.json is present in the build. Expose that file directly so the snapshot stays usable.

Proposed fix
 <div class="rest-api-banner">
   This is a static snapshot of the OpenAPI schema.
+  Download the bundled snapshot at <a href="../_generated/openapi.json"><code>_generated/openapi.json</code></a>.
   When the server is running, interactive docs are available at
   <code>/docs/api</code> (Scalar) and <code>/docs</code> (OpenAPI JSON).
 </div>
+
+<noscript>
+  <div class="rest-api-banner">
+    JavaScript is required to render Scalar here. You can still use
+    <a href="../_generated/openapi.json"><code>_generated/openapi.json</code></a>.
+  </div>
+</noscript>
 
 <script
   id="api-reference"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/overrides/rest-api.html` around lines 47 - 58, The page relies on the
dynamic `@scalar/api-reference` script (script element with id "api-reference" and
data-url="../_generated/openapi.json") and currently has no non-JS fallback; add
a simple noscript fallback that exposes the bundled OpenAPI JSON (the same
../_generated/openapi.json) as either a direct link and/or inline preformatted
JSON so users without JS or blocked CDN can still access the static schema;
ensure the fallback references the same data-url value and is placed near the
existing api-reference script element.

@Aureliolo
Copy link
Copy Markdown
Owner Author

Closing to create a fresh PR with the final implementation (standalone Scalar UI page + all review fixes).

@Aureliolo Aureliolo closed this Mar 12, 2026
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 12, 2026 10:19 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants