Skip to content

Commit 9e68e26

Browse files
lbliiiclaude
andcommitted
docs(fern): inject local library entry at generate time instead of committing it
A committed path-input library entry breaks 'fern docs dev' and 'fern generate --docs': the docs config parser rejects any 'input.path' library ("'path' input which is not yet supported. Please use 'git' input.") and renders a blank page. Meanwhile 'fern docs md generate --local' only accepts path inputs, so the entry can't live in docs.yml at all. Move the nemo-curator-local entry out of docs.yml and into scripts/generate-library-local.sh, which injects it temporarily, runs the local generation, and restores docs.yml on exit. The npm script and Makefile target now call the script; CI flows are unchanged. Verified in the fern-api/fern source and npm bundles that the parser throw exists in 5.50.4 (our pin) and 5.65.5 (latest), and that 'fern check' does not catch it — only 'docs dev'/builds fail. Signed-off-by: Lawrence Lane <llane@nvidia.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent ce75dbc commit 9e68e26

7 files changed

Lines changed: 64 additions & 17 deletions

File tree

.claude/skills/nemo-curator-docs/SKILL.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,10 @@ This is a temporary maneuver — track the change so it gets reverted.
320320

321321
## Library Reference (Autodocs) and the Fern Cross-Ref Bug
322322

323-
`fern/docs.yml` declares two `libraries:` entries that write to the same output folder (`fern/product-docs/nemo-curator/Full-Library-Reference/`, gitignored):
323+
`fern/docs.yml` declares one `libraries:` entry, and a script provides a second, temporary one (both write to `fern/product-docs/nemo-curator/Full-Library-Reference/`, gitignored):
324324

325-
- **`nemo-curator`** (`input.git`) — used by CI/publish/preview; requires `fern login` or `FERN_TOKEN`. Workflows run `fern docs md generate --library nemo-curator`.
326-
- **`nemo-curator-local`** (`input.path: ../nemo_curator`) — local dev without Fern auth; requires Docker. Run `npm run generate:library:local` from `fern/`.
325+
- **`nemo-curator`** (`input.git`, committed in `docs.yml`) — used by CI/publish/preview; requires `fern login` or `FERN_TOKEN`. Workflows run `fern docs md generate --library nemo-curator`.
326+
- **`nemo-curator-local`** (`input.path: ../nemo_curator`, injected temporarily by `fern/scripts/generate-library-local.sh`) — local dev without Fern auth; requires Docker. Run `npm run generate:library:local` from `fern/`. The entry must NOT be committed to `docs.yml`: `fern docs dev` rejects path-input libraries ("'path' input which is not yet supported") and renders a blank page, while `--local` generation only accepts `path` inputs.
327327

328328
For a full API reference locally (424 pages), use `npm run generate:library`. The local Docker parser is beta and currently produces fewer pages — fine for testing the no-auth flow, not a substitute for CI generation.
329329

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ docs-generate-library:
4545

4646
docs-generate-library-local:
4747
@echo "Generating Python API reference locally under $(FERN_DIR)/product-docs/ (Docker; no Fern auth)..."
48-
cd $(FERN_DIR) && $(FERN) docs md generate --local --library nemo-curator-local
48+
bash $(FERN_DIR)/scripts/generate-library-local.sh
4949

5050
docs-substitute:
5151
@echo "Substituting {{ variables }} in versions/v$(DOCS_VERSION) MDX..."

fern/AUTODOCS_GUIDE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,11 @@ fern docs md generate --library nemo-curator
9292
For local generation without Fern authentication (requires Docker):
9393

9494
```bash
95-
fern docs md generate --local --library nemo-curator-local
95+
npm run generate:library:local # runs scripts/generate-library-local.sh
9696
```
9797

98+
The script temporarily injects a path-input `nemo-curator-local` entry into `docs.yml`, runs `fern docs md generate --local`, and restores `docs.yml`. The entry cannot be committed: `fern docs dev` rejects any `input.path` library and renders a blank page, while `--local` generation only accepts `path` inputs.
99+
98100
Fern will generate markdown under the output path you configured, for example:
99101

100102
```text

fern/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,13 @@ For prose-only iteration, `fern docs dev` is enough. Library reference (`product
9999

100100
### Library reference without Fern login
101101

102-
CI and deploy previews use the `nemo-curator` library (`input.git`) and require `fern login` or `FERN_TOKEN`. For local iteration on the Python API reference without Fern authentication, use the `nemo-curator-local` entry (`input.path`) with Docker:
102+
CI and deploy previews use the `nemo-curator` library (`input.git`) and require `fern login` or `FERN_TOKEN`. For local iteration on the Python API reference without Fern authentication, run:
103103

104104
```bash
105-
npm run generate:library:local
106-
# equivalent: fern docs md generate --local --library nemo-curator-local
105+
npm run generate:library:local # runs scripts/generate-library-local.sh; requires Docker
107106
```
108107

109-
Both libraries write to the same output folder (`product-docs/nemo-curator/Full-Library-Reference`), so previews and publish keep working unchanged. Requires Docker (Fern pulls `fernapi/fern-python-library-docs-parser` on first run).
108+
The script temporarily injects a path-input `nemo-curator-local` entry into `docs.yml`, runs `fern docs md generate --local --library nemo-curator-local`, and restores `docs.yml` afterward. The entry can't live in the committed `docs.yml`: `fern docs dev` and `fern generate --docs` reject any `input.path` library ("'path' input which is not yet supported") and render a blank page, while `--local` generation only accepts `path` inputs. Both flows write to the same output folder (`product-docs/nemo-curator/Full-Library-Reference`), so previews and publish keep working unchanged. Requires Docker (Fern pulls `fernapi/fern-python-library-docs-parser` on first run).
110109

111110
### Variable substitution
112111

@@ -220,7 +219,8 @@ PR titles follow Conventional Commits (e.g. `docs(fern): add rollout collection
220219
| Symptom | Fix |
221220
|---|---|
222221
| `HTTP 403: User does not belong to organization` on library generation | Sign in to https://dashboard.buildwithfern.com first, then re-run `fern login`. Or use `npm run generate:library:local` (no Fern auth; requires Docker). |
223-
| `Folder not found: ./product-docs/...` in `fern docs dev` | Library generation hasn't run; trigger a `fern docs dev` cycle or check the `libraries:` block in `docs.yml` |
222+
| `Folder not found: ./product-docs/...` in `fern docs dev` | Library generation hasn't run; run `npm run generate:library` (or `generate:library:local`) first |
223+
| `Library '...' uses 'path' input which is not yet supported` + blank page in `fern docs dev` | A path-input library entry is committed in `docs.yml` — remove it; local generation injects it temporarily via `scripts/generate-library-local.sh` |
224224
| `fern check` YAML error | 2-space indent; `- page:` inside `contents:`; `path:` is relative to the version YAML |
225225
| Page 404 in preview | `slug:` missing/duplicated in the same section, or `position:` collision in an auto-discovered folder |
226226
| Broken-link warning for cross-version path | False positive in `fern docs dev`; the published site resolves it correctly |

fern/docs.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,11 @@ libraries:
183183
output:
184184
path: ./product-docs/nemo-curator/Full-Library-Reference
185185
lang: python
186-
nemo-curator-local:
187-
input:
188-
path: ../nemo_curator
189-
output:
190-
path: ./product-docs/nemo-curator/Full-Library-Reference
191-
lang: python
186+
# NOTE: do not add a path-input library entry here. `fern docs dev` and
187+
# `fern generate --docs` reject any `input.path` library ("'path' input
188+
# which is not yet supported") and render a blank page. Local no-auth
189+
# generation injects a temporary path entry via
190+
# scripts/generate-library-local.sh instead.
192191

193192
experimental:
194193
mdx-components:

fern/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"dev": "npx -y fern-api@latest docs dev",
88
"generate": "npx -y fern-api@latest generate --docs",
99
"generate:library": "npx -y fern-api@latest docs md generate --library nemo-curator",
10-
"generate:library:local": "npx -y fern-api@latest docs md generate --local --library nemo-curator-local"
10+
"generate:library:local": "bash scripts/generate-library-local.sh"
1111
},
1212
"engines": {
1313
"node": ">=20"
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env bash
2+
# Generate the Python API reference locally, without Fern auth (requires Docker).
3+
#
4+
# Why the temporary docs.yml edit: the Fern CLI has two conflicting rules —
5+
# * `fern docs md generate --local` only accepts libraries with a `path` input
6+
# (git inputs are generated remotely and need auth), but
7+
# * `fern docs dev` / `fern generate --docs` refuse to parse a docs.yml that
8+
# contains any `path` input library ("'path' input which is not yet
9+
# supported. Please use 'git' input.") and render a blank page.
10+
#
11+
# So the path-based entry cannot live in the committed docs.yml. This script
12+
# injects it, runs local generation, and restores docs.yml on exit.
13+
set -euo pipefail
14+
15+
cd "$(dirname "$0")/.."
16+
17+
LIBRARY_NAME="nemo-curator-local"
18+
SOURCE_PATH="../nemo_curator"
19+
OUTPUT_PATH="./product-docs/nemo-curator/Full-Library-Reference"
20+
21+
if ! grep -q '^libraries:' docs.yml; then
22+
echo "error: no 'libraries:' block found in docs.yml" >&2
23+
exit 1
24+
fi
25+
if grep -q "^ ${LIBRARY_NAME}:" docs.yml; then
26+
echo "error: docs.yml already contains '${LIBRARY_NAME}' — remove it; a committed path-input entry breaks 'fern docs dev'" >&2
27+
exit 1
28+
fi
29+
30+
cp docs.yml docs.yml.bak
31+
trap 'mv docs.yml.bak docs.yml' EXIT
32+
33+
awk -v lib="$LIBRARY_NAME" -v src="$SOURCE_PATH" -v out="$OUTPUT_PATH" '
34+
1
35+
/^libraries:/ {
36+
print " " lib ":"
37+
print " input:"
38+
print " path: " src
39+
print " output:"
40+
print " path: " out
41+
print " lang: python"
42+
}
43+
' docs.yml.bak > docs.yml
44+
45+
npx -y "fern-api@$(node -p 'require("./fern.config.json").version')" \
46+
docs md generate --local --library "$LIBRARY_NAME"

0 commit comments

Comments
 (0)