Skip to content

Add hidden Fern instructions pages for coding agents - #7723

Open
michaelpratt-postman wants to merge 4 commits into
mainfrom
devin/1793636034-fern-instructions-pages
Open

michaelpratt-postman wants to merge 4 commits into
mainfrom
devin/1793636034-fern-instructions-pages

Conversation

@michaelpratt-postman

@michaelpratt-postman michaelpratt-postman commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds 42 hidden, agent-facing instruction pages under /learn/home/fern-instructions/.... They're the content for a proposed fern instructions <topic> CLI command (modeled on Mintlify's mint instructions). The command would fetch <topic>.md and print it, so an agent gets curated, task-scoped guidance without first hitting a 404 .md page. The CLI command isn't part of this PR. The pages are useful on their own because any agent can fetch them directly.

Why the pages are hidden. Every page is hidden: true in fern/products/home/home.yml, and no visible page links to them. That keeps them out of the sidebar, site search, the sitemap, and llms.txt, and gives the HTML noindex, nofollow. Direct .md URLs still work, which is all the CLI needs. They don't use <llms-only> because that would also hide them from Ask Fern.

Why a CLI command, and not only MCP, llms.txt or skills. These pages are meant to be the single source of content; the delivery channel is a separate choice, and other channels can point to the same pages.

Channel Setup the agent needs Gets curated task guidance today? Drawback as the main channel
fern instructions <topic> (proposed) None: the Fern CLI is already present in a Fern project Yes, fetched live from these pages Needs a CLI release
Docs MCP (/learn/_mcp/server) MCP client configured for the agent No: searchDocs/fetchPage only, and hidden pages are excluded from search Agents without MCP configured can't use it; serving these pages as MCP prompts/resources would need a fern-platform change, so it's a good follow-up rather than an alternative
llms.txt None No: a full page index, not task-scoped Large, and hidden pages aren't listed
fern-api/skills npx skills add, per repo Partly, through 4 skill reference sets Installs a copy into the user's repo, so it goes stale until reinstalled. Better for always-on rules that point to fern instructions

Topics. The index page (/learn/home/fern-instructions) lists every topic with a "when to use" line:

  • Core: overview, new-site, troubleshoot
  • Docs: docs write, docs write components, docs configure, docs configure navigation, docs configure customization, docs configure seo, docs configure localization, docs api-reference, docs publish, docs publish domain, docs access, docs ai, docs analytics
  • Specs: spec, spec extensions, spec overrides, spec auth, spec sync, spec formats
  • SDKs: sdks, one page per language (typescript, python, go, java, csharp, php, ruby, swift, rust), sdks publish, sdks custom-code, sdks features, sdks local, sdks migrate
  • Other: automate, access team, migrate, cli-generator

Topic words map to URL paths. For example, docs publish domain maps to /learn/home/fern-instructions/docs/publish/domain.md. Released CLIs would depend on these paths, so moved pages get a docs.yml redirect instead of a manifest lookup. Redirects already apply to .md URLs on the live site: /learn/docs/ai/llms-txt.md returns 308 to /learn/docs/ai-features/llms-txt.md, and :slug* wildcards preserve .md the same way. A topic fetch is one request that follows redirects. Only fern instructions with no topic fetches the index. AGENTS.md requires a redirect whenever an instruction page moves or is renamed.

Guest, claim and identity commands (in new-site.mdx, checked against the CLI source in fern-api/fern). These shipped in CLI 5.179.0–5.183.2; until now the only docs were the CLI changelog entries from 2026-10-27 and 2026-10-28.

  • fern generate --docs --guest (and --new-session), which publishes to a temporary drop-<id> site. Guests can't generate SDKs yet, and every page that mentions --guest says so.
  • fern claim and fern claim --org <name>
  • fern whoami and fern whoami --json
  • How guest sessions interact with fern login and FERN_TOKEN
  • Where guest state is stored: fern/.guest-session and ~/.fern/guest-sessions/
  • What guest output is restricted to, how expiry works, and how to recover a session

Each page condenses existing canonical docs and links back to them. Pages follow one structure: workflow steps, the rules agents most often get wrong, and how to verify the result.

Discovery. agents.page-directive in docs.yml now adds "For task-scoped instructions for coding agents working in a Fern project, see https://buildwithfern.com/learn/home/fern-instructions.md" to every .md page. Fern can't list a single hidden page in llms.txt: the only override, agents.llms-txt, replaces the whole generated file.

Keeping the pages current. Hidden pages don't get noticed when they go stale, so AGENTS.md has a new "Agent instruction pages" section. It tells anyone editing a canonical page, or documenting a CLI command change, to search fern-instructions/ for pages that cite it and update them in the same PR. Each instruction page's ## Reference section lists the canonical pages it condenses, which is what makes that search work. The index (topics.mdx) has a frontmatter comment saying it powers fern instructions and must not move, change slug, or change its table format without a matching CLI change.

Reviewer note. The SDK examples use output.path: ../sdks/<language>, the same as the canonical SDK quickstarts. However, sdk-config-reference.mdx says paths with .. segments are rejected, yet its own examples use them. One of the two needs fixing; that's outside this PR.

Testing

  • grep -rl "docs/preview-publish/publishing-your-docs" fern/products/home/pages/fern-instructions/ (the example in AGENTS.md) returns automate.mdx and docs/publish.mdx.
  • fern check: 0 errors. The 10 warnings were already on main.
  • Vale (pre-commit): 0 errors and 0 warnings. 8 suggestions remain: acronyms TTY/WSL, uppercase PHP, and adverbs.
  • Local fern docs dev: all 42 slugs return 200. /learn/home has no fern-instructions links. Hidden pages render with <meta name="robots" content="noindex, nofollow"/>.
  • Preview deployment: all 42 <slug>.md URLs return 200 text/markdown. /home/fern-instructions appears 0 times in llms.txt, home/llms.txt, llms-full.txt, sitemap-en.xml and the /learn/home HTML. Pages render with noindex, nofollow.
  • Redirects and .md, checked on the live site: curl -sI https://buildwithfern.com/learn/docs/ai/llms-txt.md returns 308 with location: /learn/docs/ai-features/llms-txt.md. The wildcard rule /learn/sdks/guides/publish-to-package-managers/:slug* redirects typescript.md to /learn/sdks/generators/typescript.md.

To verify on the preview deployment:

  1. curl -sI <preview>/learn/home/fern-instructions/new-site.md should return content-type: text/markdown.
  2. curl -s <preview>/learn/llms.txt | grep -c /home/fern-instructions should print 0. Grep for the path, not just fern-instructions, because the preview hostname contains the branch name. The Home sidebar should also show no instruction pages.

Link to Devin session: https://app.devin.ai/sessions/c3611c1a7c044b1693dec7cd5e990086
Open in Devin Desktop: https://app.devin.ai/desktop/session/c3611c1a7c044b1693dec7cd5e990086?variant=devin
Requested by: @michaelpratt-postman

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring


## Rules

- Pass `--no-prompt` or `--force` to anything that can prompt. Prompts fail immediately when stdin isn't a TTY or `CI` is set.

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.

📝 [vale] <FernStyles.Acronyms> reported by reviewdog 🐶
'TTY' has no definition.

- Docs from scratch: `fern init --docs --organization <org>`. This creates only `docs.yml` and `fern.config.json`.
- SDKs or an API definition: `fern init --openapi <path-or-url> --organization <org>`. Without `--openapi`, `fern init` writes a sample `openapi.yml`. `fern init` also creates `sdk-config.yml` with one TypeScript target.
- Migrating docs: `fern init --docs --mintlify <path/to/mint.json>` or `fern init --docs --readme <readme-site-url>`.
5. Pass `--organization` in non-interactive shells. Without it `fern init` prompts for the organization name, and prompts fail immediately with a non-zero exit code when stdin isn't a TTY or `CI` is set.

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.

📝 [vale] <FernStyles.Acronyms> reported by reviewdog 🐶
'TTY' has no definition.

@@ -0,0 +1,30 @@
---
title: Generate a PHP SDK with Fern

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.

📝 [vale] <Microsoft.Uppercase> reported by reviewdog 🐶
Don't use all uppercase for emphasis.

---
title: Generate a PHP SDK with Fern
slug: fern-instructions/sdks/php
description: Add, configure, and publish a PHP SDK generated by Fern.

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.

📝 [vale] <Microsoft.Uppercase> reported by reviewdog 🐶
Don't use all uppercase for emphasis.


## Rules

- Fern silently ignores unknown `x-` keys. A misspelled extension does nothing and raises no error. Copy names from the extension pages.

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.

📝 [vale] <FernStyles.Adverbs> reported by reviewdog 🐶
Remove 'silently' if it's not important to the meaning of the statement.

Suggested change
- Fern silently ignores unknown `x-` keys. A misspelled extension does nothing and raises no error. Copy names from the extension pages.
- Fern ignores unknown `x-` keys. A misspelled extension does nothing and raises no error. Copy names from the extension pages.


## Verify

- `fern check` passes. Generated method names, groups and types read naturally, and the API Reference shows examples for every endpoint.

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.

📝 [vale] <FernStyles.Adverbs> reported by reviewdog 🐶
Remove 'naturally' if it's not important to the meaning of the statement.

Suggested change
- `fern check` passes. Generated method names, groups and types read naturally, and the API Reference shows examples for every endpoint.
- `fern check` passes. Generated method names, groups and types read , and the API Reference shows examples for every endpoint.

| Invalid docs URL | The `instances` URL includes `https://` or doesn't end in `docs.buildwithfern.com` |
| MDX parse error | Unclosed tag, or a bare `<` or `{` in prose. Escape it or wrap it in backticks. |
| API Reference is empty or stale | The spec isn't listed in the `api` entry or `generators.yml`, or `fern api update` hasn't pulled the current spec |
| `fern docs dev` fails on Windows | Long path support is off. Enable it or use WSL. |

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.

📝 [vale] <FernStyles.Acronyms> reported by reviewdog 🐶
'WSL' has no definition.

| Symptom | Cause and fix |
|---|---|
| `No fern directory found` | Wrong working directory. Run from the folder that contains `fern/`. |
| Job stops responding, then times out | A prompt is waiting. Add `--no-prompt` (or `--force` for preview `--id` overwrites). Prompts fail immediately when stdin isn't a TTY or `CI` is set. |

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.

📝 [vale] <FernStyles.Acronyms> reported by reviewdog 🐶
'TTY' has no definition.

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

🌿 Preview your docs: https://fern-preview-devin-1793636034-fern-instructions-pages.docs.buildwithfern.com/learn

Here are the markdown pages you've updated:

@adiophir

adiophir commented Nov 3, 2026

Copy link
Copy Markdown

Hidden pages will go out of date, and nobody will see it.

The 42 pages are short copies of the main docs. Think of a copy of a map that nobody looks at. When the roads change, nobody tells you the copy is wrong.

  • No visible page links to these pages, so no human reader will report errors.
  • One page is already at risk. new-site.mdx says each repo keeps its guest session in fern/.guest-session.
  • Open PR feat(cli): fern generate --guest shares one guest session across repos and one drop site per docs project fern#18755 changes this to one guest session for all repos. If it merges, the page is wrong on the first day.
  • Put the fix in the design:
    • Give the pages an owner.
    • Add a CI check that the commands and flags in the pages still exist in the CLI. Or generate those parts of the pages from the CLI code.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@adiophir Thanks, that's a fair point. I checked fern-api/fern#18755. It keeps fern/.guest-session as the per-repo pointer, and that pointer still takes precedence. What it adds is a machine-wide ~/.fern/guest-sessions/current, so a new repo joins the live session instead of minting a new one. It also gives each docs project its own drop-<id> site. So once #18755 merges, new-site becomes incomplete rather than wrong: it would still say each new repo starts its own guest session. Either way it shows the drift risk you describe. I'll update new-site in whichever PR lands second.

On the general fix, these are the options I see:

  • Owner: a CODEOWNERS entry for fern/products/home/pages/fern-instructions/, so CLI-facing changes get a reviewer who knows the pages.
  • CI check: extract each fern <command> --<flag> from the pages and check it against the CLI's yargs definitions, for example via fern <cmd> --help from the CLI version pinned in fern.config.json. This catches renamed or removed flags, but not behaviour changes like this one.
  • Process: add a checklist item to fern-api/fern CLI PRs that change guest, claim or whoami behaviour: "update fern-instructions pages".

I'm checking with @michaelpratt-postman which of these to do in this PR and which to file as follow-ups.

Written by Devin

@adiophir

adiophir commented Nov 3, 2026

Copy link
Copy Markdown

list only the index page in llms.txt as "agent instructions." Humans still won't see the pages, and agents can discover them.

@adiophir

adiophir commented Nov 3, 2026

Copy link
Copy Markdown
  • The PR says these commands are "documented here for the first time." Those merged on 2026-10-27/28 (#18515, #18522, #18523, #18564).
    • If guest mode is ready to document, it needs a visible canonical page. If it isn't ready (the FERN-2 guest RFC had a POC demo due 2026-11-27), agents shouldn't be told to use it yet.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@adiophir Re: listing only the index in llms.txt. As far as I can tell, Fern can't add a single hidden page to the generated llms.txt. The only override is agents.llms-txt, and that replaces the whole file. A cheaper way to make the pages discoverable is one more sentence in agents.page-directive in docs.yml, pointing to https://buildwithfern.com/learn/home/fern-instructions.md. Every .md page would then tell agents the index exists. That's also how Mintlify's agent header points to mint instructions. A real llms.txt opt-in would need a fern-platform change. I'm confirming with @michaelpratt-postman before making the directive change here.

Written by Devin

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@adiophir Re: "documented here for the first time". I meant the first docs page, not the first release. The commands shipped in CLI 5.179.0–5.183.2 (generate-guest-flag, claim-guest-session, whoami-command, guest-docs-publish-via-drop, guest-docs-single-claim-link). The only existing docs are the CLI changelog entries from 2026-10-27 and 2026-10-28; no canonical page covers them. I'll make that wording clearer. Whether agents should be pointed at guest mode before the FERN-2 POC milestone, and whether it needs a visible page first, is a product call for @michaelpratt-postman. I'll update new-site based on that.

Written by Devin

@adiophir

adiophir commented Nov 3, 2026

Copy link
Copy Markdown

The URL couples the CLI to the docs site layout.

  • fern instructions docs publish domain maps to /learn/home/fern-instructions/docs/publish/domain.md. If the docs team reorganizes /learn/home, released CLI versions break, and old CLIs stay in the wild for a long time.
  • Either commit to that path as a stable contract or put a small redirect or manifest in between.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@adiophir Agreed. Deriving the URL from the topic words couples released CLIs to the /learn/home layout. The options I see:

  • Manifest (my recommendation). The CLI fetches only /learn/home/fern-instructions.md and gets each topic's URL from the index table. That one URL is the contract, the pages behind it can move, and adding a topic doesn't need a CLI release. This PR would add a URL column to the index table.
  • Stable aliases. docs.yml redirects from /learn/fern-instructions/<topic> to wherever each page lives. I need to confirm that redirects also apply to .md URLs first.

I'm checking with @michaelpratt-postman which one to use.

Written by Devin

@adiophir

adiophir commented Nov 3, 2026

Copy link
Copy Markdown

The index points to the docs MCP server and llms.txt, and docs ai mentions site "skills." The PR doesn't say why a third channel beats, for example, shipping these pages as MCP prompts or resources, or as a skills bundle. The CLI command may be the right answer, but the comparison should be written down.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@adiophir Good call. I've added a "Why a CLI command, and not only MCP, llms.txt or skills" table to the PR description. In short:

  • The pages are the single source of content. The channel is a separate choice, and every channel can point to these pages.
  • The CLI is the only option that needs no setup in a Fern project and returns task-scoped guidance fetched live.
  • The docs MCP is retrieval only today (searchDocs/fetchPage, and hidden pages are excluded from search), and it only reaches agents that have MCP configured. Serving these pages as MCP prompts or resources would be a good follow-up, but it needs a fern-platform change.
  • llms.txt is a full index rather than task guidance, and hidden pages aren't listed in it.
  • Skills copy content into the user's repo and go stale until reinstalled. They're better used for always-on rules that tell the agent to run fern instructions <topic>.

Happy to change the comparison if you see another trade-off.

Written by Devin

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

@adiophir Re: hidden pages going out of date. fab47dc adds an "Agent instruction pages" section to AGENTS.md. It applies to any change to a canonical page and to any docs change for a CLI command (for example --guest, fern claim or fern whoami): search fern-instructions/ for pages that cite the changed page or command, and update them in the same PR. Each instruction page lists its canonical sources under ## Reference, so the search is a single grep. If you're unsure whether an instruction page is affected, say so in the PR description.

This only covers changes made in this repo. CLI behavior changes such as fern-api/fern#18755 reach this repo through the canonical docs update, at which point the rule applies. A CI check that the commands and flags on these pages still exist in the CLI is still a possible follow-up.

Written by Devin

michaelpratt-postman and others added 2 commits November 3, 2026 17:14
…, mark index as CLI contract

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

@adiophir Following up on the URL coupling: we're going with redirects. I tested redirects that are already live on buildwithfern.com, and they also cover .md URLs:

  • /learn/docs/ai/llms-txt.md returns 308 to /learn/docs/ai-features/llms-txt.md, which serves text/markdown. The .md suffix carries over to the new URL.
  • Wildcards work the same way: /learn/sdks/guides/publish-to-package-managers/typescript.md returns 308 to /learn/sdks/generators/typescript.md.

So the CLI can still build the URL from the topic words and follow redirects, with one request per topic and no index lookup. If a page or folder moves, a docs.yml redirect (or one :slug* rule) keeps released CLIs working. The index is only fetched by fern instructions with no topic, so no URL column is needed.

To make sure this happens, fdfcebd adds a rule to the "Agent instruction pages" section of AGENTS.md: if you move or rename an instruction page, add a redirect from the old path in docs.yml.

Written by Devin

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@adiophir Here's where the remaining threads stand after talking with @michaelpratt-postman:

  • Ownership: @michaelpratt-postman owns the fern-instructions/ pages for now. Over time they'll be shared, like the rest of the docs site. We're not adding a path-specific CODEOWNERS entry, because the repo has only the global * rule and no per-section owners. That rule already sends changes to these pages to the docs owners for review. The AGENTS.md rule from fab47dc covers keeping the pages in sync.
  • Listing only the index in llms.txt: f1457d7 adds the page-directive sentence instead. Every .md page now ends its header with "For task-scoped instructions for coding agents working in a Fern project, see https://buildwithfern.com/learn/home/fern-instructions.md". I checked this on the preview, and the hidden pages still don't appear in llms.txt.
  • Guest mode: it will get a public, visible page in a separate PR. It's in new-site now so the instruction pages don't have to catch up once that page lands. f1457d7 also makes the scope explicit on every page that mentions it: fern generate --docs --guest publishes docs, but guests can't generate SDKs yet.
  • The .. path conflict between sdk-config-reference.mdx and the quickstarts (see the PR description) is out of scope for this PR.

Written by Devin

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.

3 participants