Skip to content

fix: add local Fern theme fallback#768

Merged
andreatnvidia merged 2 commits into
mainfrom
andreatgretel/fix/fern-local-theme-auth
Jun 25, 2026
Merged

fix: add local Fern theme fallback#768
andreatnvidia merged 2 commits into
mainfrom
andreatgretel/fix/fern-local-theme-auth

Conversation

@andreatnvidia

Copy link
Copy Markdown
Contributor

📋 Summary

make serve-fern-docs-locally currently renders a broken local Fern preview when the developer's Fern account cannot fetch the NVIDIA global-theme. This PR keeps the real global theme as the preferred path, but falls back to a temporary local preview config with close NVIDIA-style styling so contributors can still iterate on docs without a privileged FERN_TOKEN.

🔗 Related Issue

N/A

🔄 Changes

  • Add a Fern theme access preflight and route local serving through either the real theme path or a local fallback path.
  • Add serve-local-docs-preview.py to generate a temporary fern/docs.yml without mutating the publish config.
  • Add local-preview.css for a small NVIDIA-style local-only approximation.
  • Document the fallback behavior and how to restore real theme access in fern/README.md.

🧪 Testing

  • .venv/bin/ruff check --fix .
  • .venv/bin/ruff format .
  • make check-fern-docs
  • NPM_CONFIG_CACHE=/private/tmp/codex-npm-cache .venv/bin/python fern/scripts/serve-local-docs-preview.py --root fern -- npx -y fern-api@5.41.1 check
  • make serve-fern-docs-locally reached Docs preview server ready on http://localhost:3000 with the fallback path, then was stopped.
  • make test passes (not run - docs tooling change)
  • Unit tests added/updated (N/A - targeted docs serve checks cover this change)
  • E2E tests added/updated (N/A)

✅ Checklist

  • Follows commit message conventions
  • Commits are signed off (DCO)
  • Architecture docs updated (N/A - docs tooling only)

Signed-off-by: Andre Manoel <amanoel@nvidia.com>
@andreatnvidia
andreatnvidia requested a review from a team as a code owner June 25, 2026 18:21
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Fern preview: Fern preview failed or skipped; see workflow logs.

Fern previews include the docs-website version archive with PR changes synced into latest. Notebook tutorials are rendered without execution outputs in previews.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a Fern theme access preflight to make serve-fern-docs-locally so contributors without a privileged FERN_TOKEN can still iterate on docs locally using a close NVIDIA-style CSS fallback, without touching the publish config.

  • Makefile: new check-fern-theme-access target probes fern docs theme list; serve-fern-docs-dev routes to either the real fern docs dev path or the local-fallback path based on the probe's exit code.
  • serve-local-docs-preview.py: builds a temp directory with absolute-path symlinks to all fern/ children (except docs.yml), writes a modified docs.yml with global-theme removed and local CSS injected, then execs the Fern CLI from that temp root — leaving the real fern/docs.yml untouched.
  • local-preview.css and fern/README.md: standalone NVIDIA-style approximation CSS (not referenced from docs.yml) and updated docs describing the fallback and how to restore real theme access.

Confidence Score: 5/5

Safe to merge — all changes are dev-tooling only and do not affect any published output or production config.

The fallback logic is sound: check-fern-theme-access exits 0 when no global theme is configured and only probes the Fern API when a theme is present; the Python script builds a clean temp tree without mutating the real docs.yml; symlinks use resolved absolute paths; signal forwarding and temp-dir cleanup are handled correctly via tempfile.TemporaryDirectory.

No files require special attention.

Important Files Changed

Filename Overview
Makefile Adds check-fern-theme-access, serve-fern-docs-dev, and serve-fern-docs-local-theme targets; routes serve-fern-docs-locally through a preflight that silently falls back to the local preview path when theme auth fails. Logic is correct.
fern/scripts/serve-local-docs-preview.py New script that creates a temp directory with absolute-path symlinks to all fern/ children except docs.yml, writes a modified docs.yml (global-theme removed, local styles injected), then runs the supplied command from that dir. Signal handling and cleanup via context manager are correct.
fern/styles/local-preview.css New standalone CSS file providing NVIDIA-style visual approximation for local preview; scoped to local preview only and not referenced from docs.yml.
fern/README.md Adds a Troubleshooting section describing the fallback behavior and how to restore real theme access; also documents the local-preview.css file scope.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[make serve-fern-docs-locally] --> B[install-docs-deps]
    B --> C[prepare-fern-docs]
    C --> D[serve-fern-docs-dev]
    D --> E{check-fern-theme-access FERN_GLOBAL_THEME set?}
    E -- No global-theme in docs.yml --> F[fern docs dev real theme path]
    E -- global-theme present --> G{fern docs theme list succeeds?}
    G -- yes --> F
    G -- no --> H[serve-fern-docs-local-theme]
    H --> I[serve-local-docs-preview.py --root fern]
    I --> J[Create temp dir with symlinks and modified docs.yml]
    J --> K[fern docs dev from temp preview root]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[make serve-fern-docs-locally] --> B[install-docs-deps]
    B --> C[prepare-fern-docs]
    C --> D[serve-fern-docs-dev]
    D --> E{check-fern-theme-access FERN_GLOBAL_THEME set?}
    E -- No global-theme in docs.yml --> F[fern docs dev real theme path]
    E -- global-theme present --> G{fern docs theme list succeeds?}
    G -- yes --> F
    G -- no --> H[serve-fern-docs-local-theme]
    H --> I[serve-local-docs-preview.py --root fern]
    I --> J[Create temp dir with symlinks and modified docs.yml]
    J --> K[fern docs dev from temp preview root]
Loading

Reviews (2): Last reviewed commit: "fix: address Fern fallback review feedba..." | Re-trigger Greptile

Comment thread fern/README.md Outdated

| Symptom | Fix |
|---------|-----|
| Local preview uses the local fallback theme | Sign in to https://dashboard.buildwithfern.com, run `cd fern && npx -y fern-api@5.41.1 login`, then retry. If it still falls back, export a privileged `DOCS_FERN_TOKEN` as `FERN_TOKEN`. |

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.

P2 Hardcoded Fern version will drift with fern.config.json

The troubleshooting instruction uses the literal version fern-api@5.41.1. When the pinned version in fern.config.json is bumped, contributors following this table will run a different CLI version than the Makefile uses — which can cause subtle mismatches (e.g., a fern login token stored for the old version that doesn't authenticate the new one). The Makefile already derives FERN_VERSION dynamically from fern.config.json, so the README should reference that fact or use a generic form like npx -y fern-api@<version-from-fern.config.json> to keep the two in sync.

Prompt To Fix With AI
This is a comment left during a code review.
Path: fern/README.md
Line: 187

Comment:
**Hardcoded Fern version will drift with `fern.config.json`**

The troubleshooting instruction uses the literal version `fern-api@5.41.1`. When the pinned version in `fern.config.json` is bumped, contributors following this table will run a different CLI version than the Makefile uses — which can cause subtle mismatches (e.g., a `fern login` token stored for the old version that doesn't authenticate the new one). The Makefile already derives `FERN_VERSION` dynamically from `fern.config.json`, so the README should reference that fact or use a generic form like `npx -y fern-api@<version-from-fern.config.json>` to keep the two in sync.

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

@github-actions

Copy link
Copy Markdown
Contributor

Code Review: PR #768fix: add local Fern theme fallback

Author: andreatgretel (Andre Manoel) · Base: main · +196 / −3 · 4 files

Summary

make serve-fern-docs-locally renders a broken local preview when a contributor's
Fern account can't fetch the privileged NVIDIA global-theme. This PR adds a
preflight (check-fern-theme-access) and routes local serving through one of two
paths:

  • Real theme when Fern auth can reach the global theme (unchanged behavior).
  • Local fallback otherwise — a new Python helper (serve-local-docs-preview.py)
    builds a temporary docs root that symlinks every fern/ child except docs.yml,
    writes a modified docs.yml with global-theme removed and NVIDIA-approximate
    styling/CSS injected, and runs fern docs dev against it.

The publish config (fern/docs.yml) is never mutated, which is the right call — it
preserves the global-theme contract documented in that file and avoids the
css:-gets-dropped trap called out in the existing comments (#713/#715).

This is a docs-tooling-only change. No product/runtime code is touched, consistent
with the LOW structural-impact assessment.

Findings

🔴 Blocking

  1. Missing SPDX license header on the new Python file
    fern/scripts/serve-local-docs-preview.py. Every other script in
    fern/scripts/ carries the shebang + SPDX-FileCopyrightText /
    SPDX-License-Identifier: Apache-2.0 block. The new file starts directly with
    its docstring. I confirmed locally that make check-license-headers flags this
    file as missing, and that target runs in CI (.github/workflows/ci.yml:255),
    so this will fail the build. Fix: run make update-license-headers (or copy the
    3-line header from a sibling script). AGENTS.md also calls this out explicitly for
    new files.

🟡 Should fix

  1. config.get("logo") truthiness drops a list-shaped logo.
    In write_local_docs_config, dict(config.get("logo") or {}) assumes logo
    is a mapping. The current docs.yml logo is a mapping, so this works today,
    but if logo were ever a string/list the dict(...) call would raise or silently
    discard it. Minor robustness nit given the controlled input, but worth a guard or
    a comment noting the mapping assumption.

  2. build_preview_root symlinks may break Fern's relative resolution.
    The preview root symlinks each child of fern/ individually. docs.yml references
    experimental.mdx-components: ./components and versions/latest.yml, and the new
    CSS path ./styles/local-preview.css. Symlinked dirs generally resolve fine, but
    Fern/Node tooling occasionally resolves through symlinks to the real path, which
    could place the temp docs.yml "outside" the resolved tree. The PR description says
    make serve-fern-docs-locally reached "ready," so this likely works — but it's the
    most fragile part of the design and the thing most likely to silently regress when
    Fern updates. A one-line comment documenting why per-child symlinking (vs. copying)
    was chosen would help future maintainers.

🟢 Nits / observations

  1. No license header is the only hard correctness issue; CSS uses !important
    liberally.
    That's acceptable here — it's a local-only approximation overriding a
    theme, never published — and the README correctly documents that
    styles/local-preview.css is not referenced from docs.yml. Fine as-is.

  2. run_command handles KeyboardInterrupt but not SIGTERM. For an
    interactive Ctrl-C dev server this is sufficient; if the Make process is killed
    the child fern docs dev could orphan briefly. Low priority for a local dev tool.

  3. parse_args REMAINDER handling is correct — the ["--"] strip is needed
    because argparse.REMAINDER keeps the separator. Good. The parser.error on empty
    command is a nice guard.

  4. pyyaml dependency is satisfied — declared in
    packages/data-designer-config/pyproject.toml and present in the docs venv, so the
    import yaml is safe under DOCS_PYTHON.

  5. Makefile .PHONY additions are completeserve-fern-docs-dev,
    serve-fern-docs-local-theme, and check-fern-theme-access are all registered.
    The check-fern-theme-access target is invoked twice (once via
    $(MAKE) ... >/dev/null 2>&1 in serve-fern-docs-dev for the boolean, and
    suggested again in the error text), meaning the fern docs theme list network call
    runs as a preflight on every local serve. Acceptable, but it does add a round-trip
    to the happy path.

Test coverage

No automated tests — appropriate for a docs-serve tooling change (matches the PR's
N/A justifications). The author manually verified fern check and that the fallback
server reaches "ready." The one gap is the license-header CI gate, which the
manual ruff/fern check testing wouldn't have surfaced.

Structural Impact (graphify, 2.4s)

Risk: LOW (localized change)

  • 1 Python files, 0 AST entities, 0/83 clusters

Verdict

Request changes (one blocking item). The design is sound and well-scoped: it
preserves the publish config, documents the fallback clearly in the README, and keeps
the change confined to docs tooling. The missing SPDX license header on
serve-local-docs-preview.py will fail CI
and must be added before merge
(make update-license-headers). Findings #2 and #3 are worth a quick look for
robustness but are not blockers. Once the header is added, this is good to merge.

nabinchha
nabinchha previously approved these changes Jun 25, 2026
Signed-off-by: Andre Manoel <amanoel@nvidia.com>
@andreatnvidia
andreatnvidia merged commit e7aaccf into main Jun 25, 2026
62 checks passed
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