diff --git a/AGENTS.md b/AGENTS.md index 01099a369c..cf404ecf8b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -203,6 +203,18 @@ After documenting any new functionality, before declaring the work done: 5. If the functionality has dashboard settings, verify `fern/products/dashboard/pages/` covers them — usually folded into the most relevant existing page, not a new page. 6. Verify every link you wrote — see *Link checking* above for URL construction. +## Agent instruction pages + +`fern/products/home/pages/fern-instructions/` holds hidden pages written for coding agents. They're served at `/learn/home/fern-instructions/.md`, and they're the content behind the proposed `fern instructions ` CLI command. Each page condenses the canonical pages listed in its `## Reference` section. The pages are hidden from the sidebar, search and `llms.txt`, so readers won't notice when they go stale. Keep them in sync in the same PR as the change that affects them. + +- When you change a canonical page, find the instruction pages that cite it and update them too. Search for the page's `/learn/...` URL path, for example `grep -rl "docs/preview-publish/publishing-your-docs" fern/products/home/pages/fern-instructions/`. +- When you document a CLI command, flag or behavior change, also search the instruction pages for the command name, for example `fern generate --guest`, `fern claim` or `fern whoami`. Some pages describe commands without linking a canonical page. +- Edit only the steps, rules and checks that changed. Keep each page short and scoped to one task. +- To add a topic, add the page with `hidden: true` in `fern/products/home/home.yml` and add a row to the index in `topics.mdx`. Don't link instruction pages from visible pages. +- The index page, `topics.mdx` (served at `/learn/home/fern-instructions.md`), is a contract with the Fern CLI and with `agents.page-directive` in `docs.yml`. Don't move it, change its slug, or change the format of its topic tables unless the CLI in `fern-api/fern` is updated too. +- The proposed CLI builds each topic's URL from its name, for example `fern instructions docs publish domain` fetches `/learn/home/fern-instructions/docs/publish/domain.md`, so released CLI versions depend on those paths. If you move or rename an instruction page, add a redirect in `docs.yml` from the old path to the new one. Redirects also apply to the `.md` URL, and a `:slug*` wildcard covers a moved folder. +- If you aren't sure whether a change affects an instruction page, say so in the PR description. + ## Generated files Automation owns some paths in this repo. Never write to them by hand, and never delete or reformat what automation put there: the next sync reverts the edit, and a hand-written change collides with the automated pull request that maintains the file. diff --git a/fern/docs.yml b/fern/docs.yml index 2ee032f0ff..7790cdd1ad 100644 --- a/fern/docs.yml +++ b/fern/docs.yml @@ -200,7 +200,7 @@ js: strategy: afterInteractive agents: - page-directive: "For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt." + page-directive: "For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt. For task-scoped instructions for coding agents working in a Fern project, see https://buildwithfern.com/learn/home/fern-instructions.md." analytics: # posthog: diff --git a/fern/products/home/home.yml b/fern/products/home/home.yml index a6b3c9dfd1..ce073720a8 100644 --- a/fern/products/home/home.yml +++ b/fern/products/home/home.yml @@ -3,4 +3,130 @@ navigation: path: ./pages/welcome.mdx - page: Get started with a coding agent path: ./pages/agent-onboarding.mdx - hidden: true \ No newline at end of file + hidden: true + - page: Fern instructions + path: ./pages/fern-instructions/topics.mdx + hidden: true + - page: How a Fern project works + path: ./pages/fern-instructions/overview.mdx + hidden: true + - page: Start a new Fern project + path: ./pages/fern-instructions/new-site.mdx + hidden: true + - page: Troubleshoot Fern errors + path: ./pages/fern-instructions/troubleshoot.mdx + hidden: true + - page: Write Fern docs pages + path: ./pages/fern-instructions/docs/write.mdx + hidden: true + - page: Use Fern docs components + path: ./pages/fern-instructions/docs/write/components.mdx + hidden: true + - page: Configure a Fern docs site + path: ./pages/fern-instructions/docs/configure.mdx + hidden: true + - page: Configure Fern docs navigation + path: ./pages/fern-instructions/docs/configure/navigation.mdx + hidden: true + - page: Customize a Fern docs site + path: ./pages/fern-instructions/docs/configure/customization.mdx + hidden: true + - page: Configure SEO for Fern docs + path: ./pages/fern-instructions/docs/configure/seo.mdx + hidden: true + - page: Localize Fern docs + path: ./pages/fern-instructions/docs/configure/localization.mdx + hidden: true + - page: Generate an API Reference in Fern docs + path: ./pages/fern-instructions/docs/api-reference.mdx + hidden: true + - page: Preview and publish Fern docs + path: ./pages/fern-instructions/docs/publish.mdx + hidden: true + - page: Set up a custom domain for Fern docs + path: ./pages/fern-instructions/docs/publish/domain.mdx + hidden: true + - page: Restrict access to Fern docs + path: ./pages/fern-instructions/docs/access.mdx + hidden: true + - page: Configure AI features in Fern docs + path: ./pages/fern-instructions/docs/ai.mdx + hidden: true + - page: Add analytics to Fern docs + path: ./pages/fern-instructions/docs/analytics.mdx + hidden: true + - page: Prepare an API spec for Fern + path: ./pages/fern-instructions/spec.mdx + hidden: true + - page: Use Fern OpenAPI extensions + path: ./pages/fern-instructions/spec/extensions.mdx + hidden: true + - page: Change a spec you can't edit + path: ./pages/fern-instructions/spec/overrides.mdx + hidden: true + - page: Define auth and servers in an API spec + path: ./pages/fern-instructions/spec/auth.mdx + hidden: true + - page: Keep an API spec in sync + path: ./pages/fern-instructions/spec/sync.mdx + hidden: true + - page: Use AsyncAPI, gRPC, OpenRPC, or a Fern Definition + path: ./pages/fern-instructions/spec/formats.mdx + hidden: true + - page: Generate SDKs with Fern + path: ./pages/fern-instructions/sdks.mdx + hidden: true + - page: Generate a TypeScript SDK with Fern + path: ./pages/fern-instructions/sdks/typescript.mdx + hidden: true + - page: Generate a Python SDK with Fern + path: ./pages/fern-instructions/sdks/python.mdx + hidden: true + - page: Generate a Go SDK with Fern + path: ./pages/fern-instructions/sdks/go.mdx + hidden: true + - page: Generate a Java SDK with Fern + path: ./pages/fern-instructions/sdks/java.mdx + hidden: true + - page: Generate a C# SDK with Fern + path: ./pages/fern-instructions/sdks/csharp.mdx + hidden: true + - page: Generate a PHP SDK with Fern + path: ./pages/fern-instructions/sdks/php.mdx + hidden: true + - page: Generate a Ruby SDK with Fern + path: ./pages/fern-instructions/sdks/ruby.mdx + hidden: true + - page: Generate a Swift SDK with Fern + path: ./pages/fern-instructions/sdks/swift.mdx + hidden: true + - page: Generate a Rust SDK with Fern + path: ./pages/fern-instructions/sdks/rust.mdx + hidden: true + - page: Publish Fern SDKs + path: ./pages/fern-instructions/sdks/publish.mdx + hidden: true + - page: Keep custom code in Fern SDKs + path: ./pages/fern-instructions/sdks/custom-code.mdx + hidden: true + - page: Configure Fern SDK features + path: ./pages/fern-instructions/sdks/features.mdx + hidden: true + - page: Generate and test Fern SDKs locally + path: ./pages/fern-instructions/sdks/local.mdx + hidden: true + - page: Migrate Fern SDK configuration + path: ./pages/fern-instructions/sdks/migrate.mdx + hidden: true + - page: Automate Fern in CI + path: ./pages/fern-instructions/automate.mdx + hidden: true + - page: Manage a Fern organization + path: ./pages/fern-instructions/access-team.mdx + hidden: true + - page: Migrate docs to Fern + path: ./pages/fern-instructions/migrate.mdx + hidden: true + - page: Generate a CLI from an API definition + path: ./pages/fern-instructions/cli-generator.mdx + hidden: true diff --git a/fern/products/home/pages/fern-instructions/access-team.mdx b/fern/products/home/pages/fern-instructions/access-team.mdx new file mode 100644 index 0000000000..072cc99079 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/access-team.mdx @@ -0,0 +1,29 @@ +--- +title: Manage a Fern organization +slug: fern-instructions/access/team +description: Manage Fern Dashboard members and permissions, organization tokens, SSO, custom domains, and the connected GitHub repository. +--- + +Use this for organization-level access, not for gating docs readers (see `docs access`). + +## Workflow + +1. Check the identity in use with `fern whoami`. +2. Members and roles are managed in the [Fern Dashboard](https://dashboard.buildwithfern.com). The user does this in the browser. +3. Tokens for CI: `fern token` creates one. `fern org token list`, `fern org token create` and `fern org token revoke` manage them. +4. Organization settings: `fern org get` shows them, and `fern org set cli-version` / `fern org unset cli-version` control the CLI version policy. +5. Dashboard settings cover SSO, API keys, the connected GitHub repo, custom domains, password protection and PDF export. + +## Rules + +- Only organization admins can change members, tokens and settings. If a command fails with a permission error, the user needs an admin. +- Revoke tokens that leak or are no longer used. + +## Reference + +- [Dashboard overview](https://buildwithfern.com/learn/dashboard/getting-started/overview.md) +- [Permissions](https://buildwithfern.com/learn/dashboard/configuration/permissions.md) +- [API keys](https://buildwithfern.com/learn/dashboard/configuration/api-keys.md) +- [SSO](https://buildwithfern.com/learn/dashboard/configuration/sso.md) +- [GitHub repository](https://buildwithfern.com/learn/dashboard/configuration/github-repo.md) +- [General CLI commands](https://buildwithfern.com/learn/cli-api-reference/cli-reference/general-commands.md) diff --git a/fern/products/home/pages/fern-instructions/automate.mdx b/fern/products/home/pages/fern-instructions/automate.mdx new file mode 100644 index 0000000000..457679b377 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/automate.mdx @@ -0,0 +1,35 @@ +--- +title: Automate Fern in CI +slug: fern-instructions/automate +description: Run fern check on pull requests, publish docs previews per pull request, publish docs on merge, and release SDKs from CI with FERN_TOKEN. +--- + +Use this to set up or fix a CI workflow that runs the Fern CLI. + +## Workflow + +1. Create an organization token with `fern token` and store it as a CI secret named `FERN_TOKEN`. Never print or commit it. +2. Pin a concrete CLI `version` in `fern.config.json` so CI and local runs match. Install the CLI in CI with `fern-api/setup-fern-cli@v1` (GitHub Actions) or `npm install -g fern-api`. +3. Add the jobs the user needs: + - Pull requests: `fern check`. + - Docs preview per pull request: `fern generate --docs --preview --id --no-prompt`, then post the printed URL (`Published docs to `, on stderr) as a comment. + - Docs on merge to the default branch: `fern generate --docs --no-prompt`. + - SDK release: `fern generate --target --version --force` (or `--group` for `generators.yml`). +4. Skip secret-dependent jobs on fork and Dependabot pull requests, which don't receive secrets. +5. To keep the spec current, add the `fern-api/sync-openapi` action. See `spec sync`. + +## Rules + +- Pass `--no-prompt` or `--force` to anything that can prompt. Prompts fail immediately when stdin isn't a TTY or `CI` is set. +- Don't use `fern login` or `--guest` in CI. Use `FERN_TOKEN`. +- Run the command from the folder that contains `fern/`. + +## Verify + +- `fern whoami` in a CI step reports an organization token. The workflow passes on a test pull request and posts a working preview link. + +## Reference + +- [Publish your docs](https://buildwithfern.com/learn/docs/preview-publish/publishing-your-docs.md) +- [Preview changes](https://buildwithfern.com/learn/docs/preview-publish/preview-changes.md) +- [Sync your OpenAPI spec](https://buildwithfern.com/learn/api-definitions/openapi/sync-your-open-api-specification.md) diff --git a/fern/products/home/pages/fern-instructions/cli-generator.mdx b/fern/products/home/pages/fern-instructions/cli-generator.mdx new file mode 100644 index 0000000000..1deb4511b3 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/cli-generator.mdx @@ -0,0 +1,28 @@ +--- +title: Generate a CLI from an API definition +slug: fern-instructions/cli-generator +description: Generate a command-line tool for an API with Fern, configure commands and auth, and publish it. +--- + +Use this when the user wants a CLI for their API, not to use the Fern CLI itself. + +## Workflow + +1. Follow the CLI generator quickstart to add the generator to the project. +2. Configure commands, auth and output from the configuration, authentication and customization pages. Add custom commands where the generated ones aren't enough. +3. Generate locally to try it, then set up publishing. + +## Rules + +- Command names come from the spec. Fix them there or with the generator's OpenAPI extensions. +- Look up configuration keys on the CLI generator pages. Don't reuse SDK keys. + +## Reference + +- [Overview](https://buildwithfern.com/learn/cli-generator/get-started/overview.md) +- [Quickstart](https://buildwithfern.com/learn/cli-generator/get-started/quickstart.md) +- [Configuration](https://buildwithfern.com/learn/cli-generator/get-started/configuration.md) +- [Authentication](https://buildwithfern.com/learn/cli-generator/get-started/authentication.md) +- [Custom commands](https://buildwithfern.com/learn/cli-generator/get-started/custom-commands.md) +- [Local generation](https://buildwithfern.com/learn/cli-generator/get-started/local-generation.md) +- [Publishing](https://buildwithfern.com/learn/cli-generator/get-started/publishing.md) diff --git a/fern/products/home/pages/fern-instructions/docs/access.mdx b/fern/products/home/pages/fern-instructions/docs/access.mdx new file mode 100644 index 0000000000..d7b70a7670 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/access.mdx @@ -0,0 +1,41 @@ +--- +title: Restrict access to Fern docs +slug: fern-instructions/docs/access +description: Gate Fern docs with a password, SSO, JWT, or OAuth, show content by role with RBAC, and inject readers' API keys into the API Explorer. +--- + +Use this to make some or all of a site private. + +## Pick a method + +| Need | Method | +|---|---| +| Quick gate with a shared password, no per-user accounts | Password protection (several passwords can map to roles) | +| Internal docs behind the company's login (Okta, Google Workspace and others) | SSO | +| Use the product's own login and control the flow yourself | JWT | +| Use the product's own login, with Fern running the flow through the OAuth provider | OAuth | + +JWT, OAuth and SSO set a `fern_token` cookie that tells Fern who the reader is and which roles they have. Add RBAC to show different pages, sections or content to different roles, and API key injection to pre-fill the reader's key in the API Explorer. + +## Workflow + +1. Confirm the method with the user. Most methods need setup by Fern or values only the user has, such as an identity provider, a signing secret or OAuth client credentials. Don't invent them. +2. Follow the setup page for that method. +3. For RBAC, define roles in `docs.yml` and restrict navigation entries or page content to them, as described on the RBAC page. +4. Preview with `fern docs dev`. It includes a role selector and password login for sites that use them. + +## Rules + +- Never commit secrets such as JWT signing keys to the repo. +- Hiding a page (`hidden: true`) doesn't protect it. Anyone with the URL can open it. Use one of the methods above for content that must stay private. + +## Verify + +- Signed out, protected pages redirect to login or ask for the password. Signed in with each role, the reader sees exactly that role's content. + +## Reference + +- [Authentication overview](https://buildwithfern.com/learn/docs/authentication/overview.md) +- [Password protection](https://buildwithfern.com/learn/docs/authentication/setup/password-protection.md), [SSO](https://buildwithfern.com/learn/docs/authentication/setup/sso.md), [JWT](https://buildwithfern.com/learn/docs/authentication/setup/jwt.md), [OAuth](https://buildwithfern.com/learn/docs/authentication/setup/oauth.md) +- [RBAC](https://buildwithfern.com/learn/docs/authentication/features/rbac.md) +- [API key injection](https://buildwithfern.com/learn/docs/authentication/features/api-key-injection.md) diff --git a/fern/products/home/pages/fern-instructions/docs/ai.mdx b/fern/products/home/pages/fern-instructions/docs/ai.mdx new file mode 100644 index 0000000000..ca4bc7e9e1 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/ai.mdx @@ -0,0 +1,44 @@ +--- +title: Configure AI features in Fern docs +slug: fern-instructions/docs/ai +description: Control llms.txt, Markdown access, agent directives, Ask Fern, the docs MCP server, and hosted agent skills on a Fern site. +--- + +Use this to change what AI agents and the site's AI assistant see. + +## What every Fern site serves + +- `/llms.txt`: an index of pages, each with a `.md` link. +- `.md`: any page as Markdown. Agents should fetch this rather than HTML. +- `/_mcp/server`: an MCP server with `searchDocs` and `fetchPage` tools. For example, Fern's own docs: `https://buildwithfern.com/learn/_mcp/server`. + +## Workflow + +1. Agent-facing settings go under `agents` in `docs.yml`: + - `agents.page-directive`: the instruction added to the top of every `.md` page. + - `agents.page-description-source`: where page descriptions in `llms.txt` come from. + - `agents.llms-txt` and `agents.robots-txt`: control those files. +2. Content for one audience only: wrap it in `` (shown to agents in `.md`, hidden on the site) or `` (shown on the site, left out of `.md`). +3. Ask Fern, the site's AI chat, is configured under `ai-search`: `datasources` (extra sites to index), `system-prompt`, `disclaimer`, `mask-pii`. Add guidance and content sources from the Dashboard or the Ask Fern API. +4. Run `fern docs dev` and open a page's `.md` URL to check the output. + +## Rules + +- `` content is also hidden from Ask Fern. Don't put content there that Ask Fern needs to answer from. +- `hidden: true` and `noindex: true` pages are left out of `llms.txt`, but their `.md` URL still works. +- Keep the page directive short. It's prepended to every page. + +## Verify + +- `/llms.txt` lists the expected pages, and `.md` shows the expected content and directive after publishing. + +## Reference + +- [AI features overview](https://buildwithfern.com/learn/docs/ai-features/overview.md) +- [llms.txt](https://buildwithfern.com/learn/docs/ai-features/llms-txt.md) +- [Markdown access](https://buildwithfern.com/learn/docs/ai-features/markdown.md) +- [Agent directives](https://buildwithfern.com/learn/docs/ai-features/agent-directives.md) +- [Customize LLM output](https://buildwithfern.com/learn/docs/ai-features/customize-llm-output.md) +- [Ask Fern](https://buildwithfern.com/learn/docs/ai-features/ask-fern/overview.md) +- [MCP server](https://buildwithfern.com/learn/docs/ai-features/mcp-server.md) +- [Host agent skills](https://buildwithfern.com/learn/docs/ai-features/host-skills.md) diff --git a/fern/products/home/pages/fern-instructions/docs/analytics.mdx b/fern/products/home/pages/fern-instructions/docs/analytics.mdx new file mode 100644 index 0000000000..0c98303915 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/analytics.mdx @@ -0,0 +1,37 @@ +--- +title: Add analytics to Fern docs +slug: fern-instructions/docs/analytics +description: Connect PostHog, Google Analytics and Tag Manager, Segment, Mixpanel, FullStory, or Intercom to a Fern docs site. +--- + +Use this to track readers or add a support widget. + +## Workflow + +1. Ask the user which tool they use and for its public key or ID. Don't invent IDs. +2. Add it under `analytics` (or `integrations` for support tools) in `docs.yml`, using the key names from that tool's page. For example: + + ```yaml + analytics: + posthog: + api-key: phc_xxxxxxxx + gtm: + container-id: GTM-XXXXXXX + ``` + +3. Publish and confirm events arrive in the tool. + +## Rules + +- Use the built-in integrations rather than adding tracking scripts through `js`. +- Fern also has built-in web analytics in the Dashboard and `llms.txt` analytics. Check whether those already answer the user's question. + +## Verify + +- After publishing, page views show in the tool. The analytics events page lists what Fern sends. + +## Reference + +- [Integrations overview](https://buildwithfern.com/learn/docs/integrations/overview.md) +- [PostHog](https://buildwithfern.com/learn/docs/integrations/analytics/posthog.md), [Google](https://buildwithfern.com/learn/docs/integrations/analytics/google.md), [Segment](https://buildwithfern.com/learn/docs/integrations/analytics/segment.md), [Mixpanel](https://buildwithfern.com/learn/docs/integrations/analytics/mixpanel.md), [FullStory](https://buildwithfern.com/learn/docs/integrations/analytics/fullstory.md), [Intercom](https://buildwithfern.com/learn/docs/integrations/support/intercom.md) +- [Analytics events](https://buildwithfern.com/learn/docs/integrations/analytics/events.md) diff --git a/fern/products/home/pages/fern-instructions/docs/api-reference.mdx b/fern/products/home/pages/fern-instructions/docs/api-reference.mdx new file mode 100644 index 0000000000..bf6177c8ad --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/api-reference.mdx @@ -0,0 +1,51 @@ +--- +title: Generate an API Reference in Fern docs +slug: fern-instructions/docs/api-reference +description: Add API Reference pages generated from OpenAPI, AsyncAPI, gRPC, GraphQL, or OpenRPC, and control their layout, audiences, and API Explorer. +--- + +Use this to add or change generated API Reference pages. + +## Workflow + +1. Make sure the spec is in the `fern/` folder and valid (`fern check`). Fix spec problems in the spec. See `spec`. +2. Point the docs at the spec. Either list it in `generators.yml`: + + ```yaml title="generators.yml" + api: + specs: + - openapi: ./openapi.yml + ``` + + or reference it straight from navigation, in which case Fern ignores `generators.yml` for this reference: + + ```yaml title="docs.yml" + navigation: + - api: API Reference + specs: + - type: openapi + path: ./openapi.yml + ``` + +3. Add `- api: API Reference` to navigation if it isn't there. With several APIs in separate folders, add one entry each with `api-name: `. +4. Adjust the layout on the `api` entry: order sections and endpoints, rename or flatten sections, paginate, hide endpoints, add overview pages, custom sections, pages and links. Use `audiences` to publish a subset of endpoints. +5. Run `fern check` and review in `fern docs dev`. Use `--skip-api` to skip API pages when you're only editing prose. + +## Rules + +- Generated endpoint pages can't be edited as MDX. Change descriptions and examples in the spec, an overlay, or an override. +- Add request and response examples to the spec. Otherwise Fern generates them with AI. +- WebSocket and webhook references come from AsyncAPI and OpenAPI `webhooks`; gRPC, GraphQL and OpenRPC each have their own setup page. +- Links to endpoint pages follow the API Reference navigation, not the spec's paths. + +## Verify + +- Every endpoint you expect appears, with examples, and the API Explorer sends requests to the right base URL. + +## Reference + +- [Generate an API Reference](https://buildwithfern.com/learn/docs/api-references/generate-api-ref.md) +- [Customize the layout](https://buildwithfern.com/learn/docs/api-references/customize-api-reference-layout.md) +- [Audiences](https://buildwithfern.com/learn/docs/api-references/audiences.md) +- [API Explorer](https://buildwithfern.com/learn/docs/api-references/api-explorer.md) +- [WebSocket](https://buildwithfern.com/learn/docs/api-references/generate-websocket-ref.md), [webhooks](https://buildwithfern.com/learn/docs/api-references/generate-webhook-ref.md), [gRPC](https://buildwithfern.com/learn/docs/api-references/generate-grpc-ref.md), [GraphQL](https://buildwithfern.com/learn/docs/api-references/generate-graphql-ref.md), [OpenRPC](https://buildwithfern.com/learn/docs/api-references/generate-openrpc-ref.md) diff --git a/fern/products/home/pages/fern-instructions/docs/configure.mdx b/fern/products/home/pages/fern-instructions/docs/configure.mdx new file mode 100644 index 0000000000..bbb382afa4 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/configure.mdx @@ -0,0 +1,57 @@ +--- +title: Configure a Fern docs site +slug: fern-instructions/docs/configure +description: Change site-level settings in docs.yml, such as title, logo, favicon, colors, layout, theme, and search. +--- + +Use this to change how the whole site looks or behaves. For the sidebar, see `docs configure navigation`. For CSS, JavaScript and components, see `docs configure customization`. + +## Workflow + +1. Open `fern/docs.yml`. Site-level settings are top-level keys in this file, even when navigation lives in product or version files. +2. Change the relevant key: + + ```yaml + title: Plant Store Docs + favicon: ./assets/favicon.svg + logo: + light: ./assets/logo-light.svg + dark: ./assets/logo-dark.svg + href: https://example.com + colors: + accent-primary: + light: "#0A7D5A" + dark: "#3DDC97" + ``` + +3. Run `fern check` and review the result in `fern docs dev`. + +## Main keys + +| Key | Controls | +|---|---| +| `instances` | Where the site publishes: `url` and optional `custom-domain` | +| `title`, `favicon`, `logo` | Browser title, icon, and header logo (`light`, `dark`, `href`, `height`) | +| `colors` | `accent-primary`, `background`, `border`, `sidebar-background`, `header-background`, `card-background`, each with `light` and `dark` values | +| `typography` | Fonts | +| `layout` | Page, content and sidebar widths, header height, search bar and tab placement, breadcrumbs | +| `theme` | Sidebar, body, tabs, page actions and footer nav styles | +| `navbar-links`, `footer`, `header` | Header buttons and links, and the footer | +| `settings` | Search, API Explorer proxy, dark-mode code, HTTP snippet languages, analytics | +| `metadata` | Site-wide SEO defaults | +| `landing-page`, `background-image`, `default-language`, `global-theme` | Other site-level options | +| `check` | Severity of `fern check` rules | + +## Rules + +- Asset paths are relative to `docs.yml`. +- Look up a key in the reference before adding it. `fern check` rejects unknown keys. + +## Verify + +- `fern check` passes and the change shows in `fern docs dev` in both light and dark mode. + +## Reference + +- [Site-level settings](https://buildwithfern.com/learn/docs/configuration/site-level-settings.md) +- [Configuration overview](https://buildwithfern.com/learn/docs/configuration/overview.md) diff --git a/fern/products/home/pages/fern-instructions/docs/configure/customization.mdx b/fern/products/home/pages/fern-instructions/docs/configure/customization.mdx new file mode 100644 index 0000000000..023a6681b0 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/configure/customization.mdx @@ -0,0 +1,36 @@ +--- +title: Customize a Fern docs site +slug: fern-instructions/docs/configure/customization +description: Add custom CSS and JavaScript, custom React components, an announcement banner, custom header and footer, search settings, and hidden content. +--- + +Use this when `docs.yml` settings aren't enough. Try `docs configure` first. + +## Workflow + +1. Custom CSS: create `fern/styles.css` and add `css: ./styles.css` to `docs.yml`. `css` also takes a list of files. Target elements with the selectors in the CSS selectors reference. +2. Custom JavaScript: add `js: ./custom.js` to `docs.yml`. +3. Custom React components: write the component in the project, list its folder under `experimental.mdx-components` in `docs.yml`, then use it in MDX like a built-in component. These render on the server and are indexed by search engines; scripts added with `js` aren't. +4. Announcement banner: add an `announcement` block with a `message` to `docs.yml`. +5. Hide content: `hidden: true` on a navigation entry, or `noindex: true` in page frontmatter. See `docs configure navigation`. +6. Run `fern check`, then check every change in `fern docs dev` in light and dark mode. + +## Rules + +- Use built-in settings (colors, layout, theme) before custom CSS. Selectors not in the reference can change without notice. +- Don't load third-party scripts for analytics with `js`. Use the built-in integrations. See `docs analytics`. +- Prefer React components over `js` for content readers or search engines need to see. + +## Verify + +- `fern docs dev` shows the change with no console errors, on desktop and mobile widths. + +## Reference + +- [Custom CSS and JavaScript](https://buildwithfern.com/learn/docs/customization/custom-css-js.md) +- [CSS selectors](https://buildwithfern.com/learn/docs/customization/css-selectors-reference.md) +- [Custom React components](https://buildwithfern.com/learn/docs/customization/custom-react-components.md) +- [Announcement banner](https://buildwithfern.com/learn/docs/customization/announcement-banner.md) +- [Header and footer](https://buildwithfern.com/learn/docs/customization/header-and-footer.md) +- [Search](https://buildwithfern.com/learn/docs/customization/search.md) +- [Hiding content](https://buildwithfern.com/learn/docs/customization/hiding-content.md) diff --git a/fern/products/home/pages/fern-instructions/docs/configure/localization.mdx b/fern/products/home/pages/fern-instructions/docs/configure/localization.mdx new file mode 100644 index 0000000000..06919e316f --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/configure/localization.mdx @@ -0,0 +1,30 @@ +--- +title: Localize Fern docs +slug: fern-instructions/docs/configure/localization +description: Publish Fern docs in more than one language and keep translations up to date. +--- + +Use this to add a language or update translations. Localization is an Enterprise feature in early access. + +## Workflow + +1. Confirm the user's plan includes localization. If not, they should contact support@buildwithfern.com. +2. Run `fern upgrade`. Localization needs the newest CLI release. +3. Add a `translations` key to `docs.yml` listing each language code (such as `ja` or `pt-BR`), with one marked as the default. +4. Create `fern/translations//` and put translated pages and navigation files there, at the same relative paths as the originals. In translated navigation files, include only the fields you translate (`display-name`, `section`, `page`, and so on). +5. To update a translation, edit the translated copy of the page. Keep its frontmatter, slugs and component structure the same as the source. +6. Run `fern docs dev` and switch languages from the header dropdown. + +## Rules + +- Fern doesn't translate content. The user supplies translations. +- Pages without a translation fall back to the default language. +- Ask Fern, `fern check` errors and API Reference pages don't support localization yet. + +## Verify + +- Each locale has its own URL path, and the language switcher shows every configured language. + +## Reference + +- [Localization](https://buildwithfern.com/learn/docs/localization/overview.md) diff --git a/fern/products/home/pages/fern-instructions/docs/configure/navigation.mdx b/fern/products/home/pages/fern-instructions/docs/configure/navigation.mdx new file mode 100644 index 0000000000..2037d5289b --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/configure/navigation.mdx @@ -0,0 +1,60 @@ +--- +title: Configure Fern docs navigation +slug: fern-instructions/docs/configure/navigation +description: Add, move, rename, and hide pages, sections, folders, tabs, versions, and products in docs.yml navigation. +--- + +Use this to change the sidebar or any page URL. + +## Workflow + +1. Find where navigation lives. A single-product site has `navigation:` in `fern/docs.yml`. With products or versions, each product or version has its own `.yml` file, referenced from `docs.yml`. Paths in a YAML file are relative to that file. +2. Add the entry: + + ```yaml + navigation: + - section: Guides + contents: + - page: Rotate API keys + path: ./pages/guides/rotate-keys.mdx + - folder: ./pages/tutorials # every .mdx in the folder, in filename order + - link: Status page + href: https://status.example.com + - api: API Reference + ``` + +3. Work out the new URL: `//
/`. Each level's slug is its `slug:` if set, otherwise derived from its display name (lowercased, hyphenated). In a `folder:`, page slugs come from filenames. A frontmatter `slug:` replaces the whole path within the product. `skip-slug: true` drops a level. +4. If an existing page's URL changes, add a redirect from the old URL. See `docs configure seo`. +5. Run `fern check` and open the page in `fern docs dev`. + +## Options + +| Key | Effect | +|---|---| +| `hidden: true` | On a page, section, tab or version: removed from the sidebar, search, sitemap and `llms.txt`, but reachable by URL | +| `collapsed: true` | Section or folder starts collapsed | +| `icon` | Sidebar icon, for example `fa-solid fa-key` | +| `availability` | Badge such as `beta` or `deprecated` | +| `slug`, `skip-slug` | Control the URL segment | +| `tabs` + `tab:` entries | Top-level tabs, each with its own navigation | +| `versions` | Versioned docs, each version with its own `.yml` navigation | +| `products` | Product switcher. Each product has its own `.yml`, and the top-level `docs.yml` then has no `navigation` of its own. Requires a Team or Enterprise plan. | + +## Rules + +- Renaming a section, tab or version without an explicit `slug:` changes every URL under it. +- Don't guess URLs from the directory layout. Section slugs often differ from folder names. +- Every `path:` must point at an existing file. `fern check` reports missing ones. + +## Verify + +- `fern check` passes. +- The sidebar in `fern docs dev` matches the intended structure, and moved pages redirect from their old URLs. + +## Reference + +- [Navigation](https://buildwithfern.com/learn/docs/configuration/navigation.md) +- [Tabs](https://buildwithfern.com/learn/docs/configuration/tabs.md) +- [Versions](https://buildwithfern.com/learn/docs/configuration/versions.md) +- [Products](https://buildwithfern.com/learn/docs/configuration/products.md) +- [Hiding content](https://buildwithfern.com/learn/docs/customization/hiding-content.md) diff --git a/fern/products/home/pages/fern-instructions/docs/configure/seo.mdx b/fern/products/home/pages/fern-instructions/docs/configure/seo.mdx new file mode 100644 index 0000000000..0ce16f3507 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/configure/seo.mdx @@ -0,0 +1,43 @@ +--- +title: Configure SEO for Fern docs +slug: fern-instructions/docs/configure/seo +description: Set page and site metadata, control slugs, add redirects, and manage robots.txt in a Fern docs site. +--- + +Use this to change metadata, URLs, redirects, or crawler access. + +## Workflow + +1. Metadata: set `title` and `description` in each page's frontmatter. Site-wide defaults go in the `metadata` section of `docs.yml`. +2. Slugs: set `slug:` on a navigation entry, or in page frontmatter to override the whole path. +3. Redirects: whenever a published URL changes, add an entry to `redirects` in `docs.yml`: + + ```yaml + redirects: + - source: "/learn/old-path" + destination: "/learn/new-path" + - source: "/learn/old-section/:slug*" + destination: "/learn/new-section/:slug*" + ``` + + Redirects are permanent (308) by default. Add `permanent: false` for a temporary (307) redirect. Large sites can move redirects to separate files, each with a top-level `redirects` list. +4. Run `fern check`. It warns when a moved or removed page has no redirect. + +## Rules + +- Include the base path (such as `/learn`) in `source` and `destination`. +- Don't create loops or chains. `fern check` fails on a redirect whose source equals its destination, or on a circular chain. +- `hidden: true` in navigation removes a page from the sidebar and search and sets `noindex`. `noindex: true` in frontmatter keeps the page in the sidebar but out of search engines and `llms.txt`. + +## Verify + +- `fern check` passes with no redirect warnings. +- After publishing, the old URL returns a redirect to the new one. + +## Reference + +- [SEO overview](https://buildwithfern.com/learn/docs/seo/overview.md) +- [Metadata](https://buildwithfern.com/learn/docs/seo/setting-seo-metadata.md) +- [Slugs](https://buildwithfern.com/learn/docs/seo/configuring-slugs.md) +- [Redirects](https://buildwithfern.com/learn/docs/seo/redirects.md) +- [robots.txt](https://buildwithfern.com/learn/docs/seo/robots-txt.md) diff --git a/fern/products/home/pages/fern-instructions/docs/publish.mdx b/fern/products/home/pages/fern-instructions/docs/publish.mdx new file mode 100644 index 0000000000..9b46c9299e --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/publish.mdx @@ -0,0 +1,33 @@ +--- +title: Preview and publish Fern docs +slug: fern-instructions/docs/publish +description: Preview docs locally, create shareable preview links, publish to staging or production, and confirm a change is live. +--- + +Use this to see a change before it ships, or to ship it. + +## Workflow + +1. Validate: `fern check`. +2. Preview locally: `fern docs dev`. It hot-reloads and needs no login. On large sites, `--skip-api` skips parsing API specs and `--skip-validation` skips validation. Use `--port` to change the port. +3. Share a preview: `fern generate --docs --preview`. Add `--id ` for a stable URL (`-preview-.docs.buildwithfern.com`) that each run overwrites. Outside GitHub Actions, add `--force` or `--no-prompt` to skip the overwrite prompt. List and delete previews with `fern docs preview list` and `fern docs preview delete`. +4. Publish: `fern generate --docs`. With several `instances` in `docs.yml` (for example staging and production), choose one with `--instance `. +5. Without a Fern account, `fern generate --docs --guest` publishes to a temporary Fern Drop site. See `new-site`. + +## Rules + +- Publishing and preview links need `fern login`, `FERN_TOKEN`, or `--guest`. `fern docs dev` and `fern check` don't. +- `fern generate --docs` fails on any `fern check` rule set to `error`. +- In CI, set `FERN_TOKEN` and pass `--no-prompt`. See `automate`. +- Don't publish to production when the user asked for a preview. + +## Verify + +- The command prints `Published docs to `. Open that URL and confirm the change. +- For production, check the page on the custom domain too, if there is one. + +## Reference + +- [Preview changes](https://buildwithfern.com/learn/docs/preview-publish/preview-changes.md) +- [Publish your docs](https://buildwithfern.com/learn/docs/preview-publish/publishing-your-docs.md) +- [Docs commands](https://buildwithfern.com/learn/cli-api-reference/cli-reference/docs-commands.md) diff --git a/fern/products/home/pages/fern-instructions/docs/publish/domain.mdx b/fern/products/home/pages/fern-instructions/docs/publish/domain.mdx new file mode 100644 index 0000000000..3e91320c88 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/publish/domain.mdx @@ -0,0 +1,43 @@ +--- +title: Set up a custom domain for Fern docs +slug: fern-instructions/docs/publish/domain +description: Serve Fern docs on a custom subdomain, an apex domain, or a subpath behind a reverse proxy, and combine docs from several repos on one domain. +--- + +Use this to put a Fern site on the user's own domain. + +## Workflow + +1. Choose the shape: + - Subdomain, such as `docs.example.com`: DNS only. + - Subpath, such as `example.com/docs`: needs a reverse proxy in front of the user's site. + - Several repos on one domain: multi-source docs. +2. Add `custom-domain` to the instance in `docs.yml` and publish: + + ```yaml + instances: + - url: example.docs.buildwithfern.com + custom-domain: docs.example.com + ``` + + For a subpath, follow the reverse proxy guide for the `custom-domain` value. +3. Subdomain: the user contacts Fern (Slack channel or support@buildwithfern.com) for the TXT record values, then adds a `CNAME` from the subdomain to `cname.ferndocs.com` plus the two TXT records (`_cf-custom-hostname.` and `_acme-challenge.`). +4. Subpath: configure the user's proxy (Cloudflare Workers, Vercel, Netlify, Nginx or AWS CloudFront) to forward the subpath to Fern, following the provider steps in the reverse proxy guide. +5. Publish again with `fern generate --docs`. + +## Rules + +- You can't create DNS records or obtain TXT values for the user. Tell them exactly which records to add and that Fern supplies the TXT values. +- Keep `url` on `docs.buildwithfern.com`. The custom domain is an addition, not a replacement. +- Don't cache HTML responses from Fern in the proxy. + +## Verify + +- `dig CNAME docs.example.com` returns `cname.ferndocs.com`. +- The custom domain serves the site over HTTPS, and a deep link such as `/.md` returns Markdown. + +## Reference + +- [Set up a custom domain](https://buildwithfern.com/learn/docs/preview-publish/setting-up-your-domain.md) +- [Reverse proxy](https://buildwithfern.com/learn/docs/preview-publish/reverse-proxy.md) +- [Multi-source docs](https://buildwithfern.com/learn/docs/preview-publish/multi-source-docs.md) diff --git a/fern/products/home/pages/fern-instructions/docs/write.mdx b/fern/products/home/pages/fern-instructions/docs/write.mdx new file mode 100644 index 0000000000..d2916783c8 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/write.mdx @@ -0,0 +1,66 @@ +--- +title: Write Fern docs pages +slug: fern-instructions/docs/write +description: Create and edit MDX pages, frontmatter, reusable snippets, and changelog entries in a Fern docs site. +--- + +Use this before creating a page or writing more than a few sentences. + +## Workflow + +1. Search the repo for a page that already covers the topic. Prefer editing it over adding a new page. +2. Create the page as an `.mdx` file in the project's pages folder, starting with frontmatter: + + ```mdx + --- + title: Rotate API keys + description: Rotate an API key without downtime. + --- + + Body text starts here. Don't repeat the title as an H1. + ``` + +3. Add the page to `docs.yml` navigation, or it won't appear. See `docs configure navigation`. +4. Link to other pages by URL path (for example `/learn/docs/seo/redirects`), derived from navigation and `slug` values, never from file paths. +5. Run `fern check`, then `fern docs dev` to see the page. + +## Frontmatter + +Common fields: `title`, `sidebar-title`, `subtitle`, `description`, `slug`, `image`, `last-updated`, `edit-this-page-url`, `hide-toc`, `max-toc-depth`, `hide-nav-links`, `hide-feedback`, `hide-page-actions`, `logo`, `layout`, `availability`, `search-metadata`, `noindex`, `tags` (changelogs). Don't invent other fields. A frontmatter `slug` is absolute within its product and replaces the section path. + +## Snippets + +Put content used on several pages in a snippet file, conventionally `fern/snippets/.mdx`, and include it with a path relative to the `fern` folder: + +```mdx + +``` + +Pass values to `{{placeholder}}` variables in the snippet as props on ``. Check for an existing snippet before writing boilerplate such as a support line or prerequisites. + +## Changelog entries + +- One file per date in the `changelog/` folder, named `YYYY-MM-DD.mdx`. Subfolders are ignored. +- The filename date is the title and sets the sort order. Don't add an H1. +- Add a `tags` array in frontmatter, reusing existing tags. +- If a file for that date exists, add a `##` section to it instead of creating a second file. + +## Rules + +- MDX is strict: close every tag, and escape or backtick bare `<`, `{` and `}` in prose. +- Use sentence case for headings. Anchors only work for real `##` and `###` headings, not component `title` props. +- If a change moves, renames or deletes a published page, add a redirect. See `docs configure seo`. +- Images: put them under the project, reference them by relative path, and add alt text. +- Use components where they help the reader, not for decoration. See `docs write components`. + +## Verify + +- `fern check` passes with no new errors. +- The page renders in `fern docs dev` at the URL you expect, and every internal link resolves. + +## Reference + +- [Markdown basics](https://buildwithfern.com/learn/docs/writing-content/markdown-basics.md) +- [Frontmatter](https://buildwithfern.com/learn/docs/configuration/page-level-settings.md) +- [Reusable snippets](https://buildwithfern.com/learn/docs/writing-content/reusable-snippets.md) +- [Changelogs](https://buildwithfern.com/learn/docs/configuration/changelogs.md) diff --git a/fern/products/home/pages/fern-instructions/docs/write/components.mdx b/fern/products/home/pages/fern-instructions/docs/write/components.mdx new file mode 100644 index 0000000000..2350624699 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/docs/write/components.mdx @@ -0,0 +1,43 @@ +--- +title: Use Fern docs components +slug: fern-instructions/docs/write/components +description: Pick the right built-in MDX component for callouts, steps, tabs, cards, code, API snippets, and content migrated from Mintlify. +--- + +Use this when a page needs more than Markdown. Fern components are available in every `.mdx` page without imports. + +## Pick a component + +| Need | Component | +|---|---| +| Aside the reader must not miss | ``, ``, ``, ``, ``, ``, ``, `` | +| Ordered procedure | `` with `` | +| Alternatives (languages, platforms) | `` with `` | +| Optional or long detail | `` with `` | +| Links to other pages | `` with `` | +| Code | Fenced code blocks with a `title`; `` for one example in several languages | +| Parameters or fields | `` | +| Request or response from the API definition | ``, ``, ``, `` | +| File tree | `` with `` and `` | +| Images with captions | `` | +| Hover definitions | `` | +| Content for some readers only | `` | +| Prompt to copy into an AI tool | `` | + +## Rules + +- Use a component only when it helps the reader. A paragraph is usually better than a one-line callout. +- Don't wrap a single link in a callout. Put the link in a sentence. +- Anchor links don't work for component `title` props. Use a `##` heading when something needs a stable anchor. +- Mintlify components mostly work as-is or through aliases. Prefer the Fern names when editing. +- Check the component's page for props before using one. Don't invent props. + +## Verify + +- `fern check` passes, and the page renders in `fern docs dev` without MDX errors. + +## Reference + +- [Components overview](https://buildwithfern.com/learn/docs/writing-content/components/overview.md) +- [Callouts](https://buildwithfern.com/learn/docs/writing-content/components/callouts.md) +- [Mintlify compatibility](https://buildwithfern.com/learn/docs/writing-content/components/mintlify-compatibility.md) diff --git a/fern/products/home/pages/fern-instructions/migrate.mdx b/fern/products/home/pages/fern-instructions/migrate.mdx new file mode 100644 index 0000000000..febce4f977 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/migrate.mdx @@ -0,0 +1,27 @@ +--- +title: Migrate docs to Fern +slug: fern-instructions/migrate +description: Move an existing docs site to Fern from Mintlify, ReadMe, or another platform. +--- + +Use this when the user's docs live on another platform. + +## Workflow + +1. From Mintlify: `fern init --docs --mintlify `. Most Mintlify components work as-is or through aliases. +2. From ReadMe: `fern init --docs --readme `. +3. From anything else: `fern init --docs`, then move pages into MDX, rebuild navigation in `docs.yml`, and copy branding. See `docs write` and `docs configure navigation`. +4. Add the API spec and an `api` navigation entry. See `docs api-reference`. +5. Add `redirects` from every old URL that changes. See `docs configure seo`. +6. Run `fern check`, review in `fern docs dev`, then publish a preview with `fern generate --docs --preview`. + +## Rules + +- Keep the old URLs working with redirects before switching the domain. +- Review migrated MDX for components the importer didn't convert. `fern check` reports them. +- Enterprise customers can ask Fern for a managed migration. + +## Reference + +- [Mintlify compatibility](https://buildwithfern.com/learn/docs/writing-content/components/mintlify-compatibility.md) +- [`fern init`](https://buildwithfern.com/learn/cli-api-reference/cli-reference/general-commands.md) diff --git a/fern/products/home/pages/fern-instructions/new-site.mdx b/fern/products/home/pages/fern-instructions/new-site.mdx new file mode 100644 index 0000000000..6dfc18673b --- /dev/null +++ b/fern/products/home/pages/fern-instructions/new-site.mdx @@ -0,0 +1,80 @@ +--- +title: Start a new Fern project +slug: fern-instructions/new-site +description: Create a fern folder, publish docs without a Fern account using guest sessions, claim a guest session, and check which identity the CLI is using. +--- + +Use this to create a Fern project, to run the CLI before the user has a Fern account, or to work out why the CLI says it isn't authenticated. + +## Workflow + +1. Check for an existing project. If the repo already has a `fern/` folder with `fern.config.json`, the project exists. Skip to the task the user asked for. +2. Install the CLI: `npm install -g fern-api` (or `brew install fern-api`). Run it as `fern`. +3. Ask the user which product they want (Docs, SDKs, or both), whether they have an OpenAPI spec, and where it lives. +4. Create the `fern/` folder. Pick one: + - Docs from the starter template (default for Docs): `gh repo create /fern-docs --template fern-api/docs-starter --private --clone`. It includes sample pages, an OpenAPI spec, a changelog and a GitHub Actions workflow. + - Docs from scratch: `fern init --docs --organization `. This creates only `docs.yml` and `fern.config.json`. + - SDKs or an API definition: `fern init --openapi --organization `. 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 ` or `fern init --docs --readme `. +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. +6. Choose how the CLI authenticates (see the next section), then preview or generate. + +## Choose how the CLI authenticates + +Run `fern whoami` (or `fern whoami --json`) to see what the CLI acts as in the current repo. It reports one of: logged in as a user, using an organization token from `FERN_TOKEN`, or not logged in. It also reports the repo's guest session, if any: session ID, guest organization, expiry, whether it's still live, and the claim link. It never prints the guest token. + +| Situation | Use | +|---|---| +| The user has a Fern account and a browser | `fern login`. Use `fern login --device-code` on a remote machine, or `fern login --email
` for enterprise SSO. | +| CI or another non-interactive environment | `FERN_TOKEN=`. Create one with `fern token`. | +| No account yet, or the user wants to try Fern Docs first | `fern generate --docs --guest`. Guests can't generate SDKs yet. | + +`fern docs dev` and `fern check` don't need authentication. Run them before choosing. + +## Guest sessions + +`--guest` lets the CLI publish docs without a login or `FERN_TOKEN`. Guest sessions can't generate SDKs yet, so SDK generation needs `fern login` or `FERN_TOKEN`. + +- The first `fern generate --docs --guest` in a repo starts a temporary guest session with its own `guest-` organization. The CLI prints the session ID, the expiry time, and a link: `Claim it to keep this work: `. Give that link to the user. +- Later runs in the same repo reuse the session. The CLI stores it in `fern/.guest-session` (gitignored) and keeps the credential in `~/.fern/guest-sessions/`. It warns when less than an hour is left, and a run that crosses the deadline fails. +- While running as a guest, the CLI ignores the `organization` in `fern.config.json` (with a warning) and doesn't change the file. +- `fern generate --docs --guest` publishes the docs to a temporary `drop-` site that the guest session owns. It ignores the `instances` URL in `docs.yml`. The CLI prints the site URL and the claim link. +- `--guest` fails if `FERN_TOKEN` is set or a login is saved. Unset `FERN_TOKEN` or run `fern logout` to continue as a guest, or drop `--guest` to use the existing credentials. +- `fern generate --docs --guest --new-session` discards the recorded session and starts a new guest organization. Earlier guest output isn't carried over. Use it when the old session was claimed, revoked, or expired. + +## Claiming a guest session + +To keep guest work, the user claims the session in either of two ways: open the claim link in a browser, or run: + +```bash +fern login +fern claim # turn the guest organization into the user's own +fern claim --org # or move the work into an existing organization the user administers +``` + +`fern claim` requires a login. It points `fern.config.json` at the organization that owns the work after the claim and forgets the guest session. After claiming, the guest token stops working, so later runs need `fern login` or `FERN_TOKEN` (without `--guest`). + +Common `fern claim` failures: +- No guest session recorded for the repo: run `fern generate --docs --guest` first. +- The session expired, was taken down, or was already claimed: start a new one with `fern generate --docs --guest --new-session`. +- `--org` names an organization the user isn't an admin of. + +## Rules + +- Never invent an organization name. Ask the user. Use only letters, numbers, hyphens and underscores. +- Don't commit `fern/.guest-session` or anything from `~/.fern/`. +- Don't print or store `FERN_TOKEN` values. Store them as CI secrets. +- The `organization` in `fern.config.json` must match the user's organization in the [Fern Dashboard](https://dashboard.buildwithfern.com), or publishing with a login fails. + +## Verify + +- `fern whoami` shows the expected identity. +- `fern check` passes. +- Docs: `fern docs dev` starts and prints a local URL that renders the site. +- Guest runs: the output includes a claim link and an expiry. Tell the user both, and that unclaimed work disappears after the expiry. + +## Reference + +- [Docs quickstart](https://buildwithfern.com/learn/docs/getting-started/quickstart.md) +- [SDKs quickstart](https://buildwithfern.com/learn/sdks/overview/quickstart.md) +- [General CLI commands](https://buildwithfern.com/learn/cli-api-reference/cli-reference/general-commands.md) diff --git a/fern/products/home/pages/fern-instructions/overview.mdx b/fern/products/home/pages/fern-instructions/overview.mdx new file mode 100644 index 0000000000..72fe6e57c0 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/overview.mdx @@ -0,0 +1,54 @@ +--- +title: How a Fern project works +slug: fern-instructions/overview +description: Start here. How a Fern project is laid out, which file controls what, and the facts coding agents most often get wrong. +--- + +Use this before changing anything in a Fern project. + +## Layout + +Everything Fern reads lives in a `fern/` folder: + +| File | Controls | +|---|---| +| `fern.config.json` | `organization` (the Fern organization that owns the project) and `version` (the CLI version). Required. | +| `docs.yml` | The docs site: `instances` (where it publishes), `navigation`, branding, layout, redirects, integrations, access control, AI settings | +| `openapi.yml` or another spec | The API definition: OpenAPI, AsyncAPI, OpenRPC, gRPC protos, or a Fern Definition | +| `sdk-config.yml` | SDK targets (languages, output, publishing) and the specs they use, under `source.specs`. Created by `fern init`. | +| `generators.yml` | Older projects: lists specs under `api.specs` and configures SDKs under `groups`. Still supported. | +| `pages/`, `assets/`, `snippets/`, `changelog/` | MDX pages, images, reusable snippets, and changelog entries | + +A repo can hold several APIs, each in its own folder under `fern/apis/`. Commands then need `--api `. + +## Facts agents get wrong + +- A page appears on the site only if `docs.yml` navigation references it. Creating the `.mdx` file isn't enough. +- Page URLs come from navigation (section and page titles, or `slug` overrides), not from file paths. Derive links from `docs.yml` and frontmatter. +- `fern` and `changelog` are reserved folder names. Don't rename them. +- The `instances` URL in `docs.yml` has no `https://` and ends in `docs.buildwithfern.com`. Custom domains go in `custom-domain`. +- `organization` in `fern.config.json` must match the organization in the [Fern Dashboard](https://dashboard.buildwithfern.com). Never invent one. +- The CLI runs the version pinned in `fern.config.json`, whatever version is installed globally. Change it with `fern upgrade`. +- API Reference pages are generated from the spec. Fix the spec (or an overlay or override), not the rendered page. +- Generated SDK code is overwritten on every run. Protect hand-written files with `.fernignore` or Replay. +- `.yml` and `.yaml` are treated the same. +- Pages are MDX: close every tag, and escape `<` and `{` in prose. + +## Commands to know + +| Command | Does | +|---|---| +| `fern check` | Validates the project. Run it before every generate. No login needed. | +| `fern docs dev` | Local preview with hot reload. No login needed. | +| `fern generate --docs` | Publishes the docs. `--preview` makes a preview link instead. | +| `fern generate` | Generates SDKs. `--group ` or `--api ` to narrow it. | +| `fern whoami` | Shows the login, `FERN_TOKEN` or guest session in use | +| `fern generate --docs --guest` | Publishes docs without a Fern account. Guests can't generate SDKs yet. See `fern instructions new-site`. | + +Add `--log-level debug` to any command to see what it's doing. + +## Next + +- New project or authentication questions: `new-site`. +- An error: `troubleshoot`. +- Topic list: `fern instructions` or [the index](https://buildwithfern.com/learn/home/fern-instructions.md). diff --git a/fern/products/home/pages/fern-instructions/sdks.mdx b/fern/products/home/pages/fern-instructions/sdks.mdx new file mode 100644 index 0000000000..36334add99 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks.mdx @@ -0,0 +1,67 @@ +--- +title: Generate SDKs with Fern +slug: fern-instructions/sdks +description: Add SDK targets in sdk-config.yml, run fern generate, generate one language, and upgrade generators. +--- + +Use this to add an SDK, change SDK configuration, or run SDK generation. + +## Workflow + +1. Find the SDK config. New projects use `fern/sdk-config.yml`. Older projects configure SDKs under `groups` in `fern/generators.yml`. If both exist, ask the user which to change. Don't add `groups` to a project that uses `sdk-config.yml`. +2. Confirm the spec is listed under `source.specs` (each entry has an `id`, a `type` such as `openapi` or `asyncapi`, and a `path` or `url`). +3. Add one entry under `targets` per language. Each language appears once: + + ```yaml title="sdk-config.yml" + schemaVersion: sdk-config/v1 + sdkName: Plant Store + source: + specs: + - id: plant-store + type: openapi + path: ./openapi.yml + targets: + - language: typescript + package: + packageName: "@plant-store/sdk" + output: + delivery: files + path: ../sdks/typescript + - language: python + package: + packageName: plant-store + output: + delivery: files + path: ../sdks/python + ``` + +4. Put settings every language shares (`api.auth`, `client.retry`, `client.timeoutMs`, `package`) at the top level. A target inherits them and overrides only the fields it sets. A target's `output` replaces the top-level `output`. +5. Run `fern check`, then generate: + - `fern generate` generates every target. + - `fern generate --target python` generates one language. Repeat `--target` for several. + - Legacy projects: `fern generate --group `. + - `fern generate --preview` writes output locally without publishing. +6. To move a legacy project to `sdk-config.yml`, run `fern sdk migrate --dry-run`, review the proposed changes, then `fern sdk migrate`. + +## Rules + +- Never put a literal secret in the config. Credential fields take an environment expression such as `${NPM_TOKEN}`. +- Paths in `sdk-config.yml` are relative to the file. +- Pin `targets[].generatorVersion` (or `version` in `generators.yml`) so output is reproducible. Read the generator changelog before a major upgrade. +- Don't edit generated files unless they're protected. See `sdks custom-code`. +- Generation needs authentication (`fern login` or `FERN_TOKEN`). Guest sessions can't generate SDKs yet. `--local` runs generators with Docker on the user's machine. +- Fix naming problems such as `postUsers` methods in the spec, not in generated code. See `spec`. + +## Verify + +- `fern check` passes. +- The output directory or repository contains the generated SDK, and it builds with the language's normal tooling. +- New endpoints appear as methods on the client. + +## Reference + +- [SDKs quickstart](https://buildwithfern.com/learn/sdks/overview/quickstart.md) +- [`sdk-config.yml` reference](https://buildwithfern.com/learn/sdks/reference/sdk-config.md) +- [How SDK generation works](https://buildwithfern.com/learn/sdks/overview/how-it-works.md) +- [Project structure](https://buildwithfern.com/learn/sdks/overview/project-structure.md) +- Language pages: `fern instructions sdks ` diff --git a/fern/products/home/pages/fern-instructions/sdks/csharp.mdx b/fern/products/home/pages/fern-instructions/sdks/csharp.mdx new file mode 100644 index 0000000000..17bdab7811 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/csharp.mdx @@ -0,0 +1,30 @@ +--- +title: Generate a C# SDK with Fern +slug: fern-instructions/sdks/csharp +description: Add, configure, and publish a C# SDK generated by Fern. +--- + +Use this for C#-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: csharp + output: + delivery: files + path: ../sdks/csharp + ``` + +2. Set the package name and other C# options from the C# configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target csharp --preview` and build the output with the usual C# tooling. +4. To publish to NuGet, follow `sdks publish` and the C# publishing page. + +## Reference + +- [C# quickstart](https://buildwithfern.com/learn/sdks/generators/csharp/quickstart.md) +- [C# configuration](https://buildwithfern.com/learn/sdks/generators/csharp/configuration.md) +- [Publish to NuGet](https://buildwithfern.com/learn/sdks/generators/csharp/publishing.md) +- [C# custom code](https://buildwithfern.com/learn/sdks/generators/csharp/custom-code.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/custom-code.mdx b/fern/products/home/pages/fern-instructions/sdks/custom-code.mdx new file mode 100644 index 0000000000..b30e920d00 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/custom-code.mdx @@ -0,0 +1,35 @@ +--- +title: Keep custom code in Fern SDKs +slug: fern-instructions/sdks/custom-code +description: Preserve hand-written code in generated SDKs with .fernignore for whole files or Replay for line-level edits. +--- + +Use this before editing any file in a generated SDK. + +## Pick an approach + +| Approach | Use when | Trade-off | +|---|---|---| +| `.fernignore` | The user owns a whole file: a hand-written module, README, or workflow | Fern stops updating that file entirely | +| Replay | Small edits inside generated files | Fern reapplies the edits with a 3-way merge on every regeneration | + +## Workflow + +1. `.fernignore`: add the file paths to `.fernignore` at the root of the SDK repo (gitignore syntax). GitHub delivery creates the file. Each SDK has its own. +2. Replay: enable it (`replay.enabled: true` in `sdk-config.yml`), commit the edits in the SDK repo, and regenerate. If a merge conflicts, resolve it with `fern replay resolve`. `fern replay forget` drops a recorded edit. +3. Regenerate and confirm the custom code survived. + +## Rules + +- Don't edit generated files that aren't protected by one of these. The next generation overwrites them. +- `.fernignore` applies only to SDKs. It has no effect on docs. +- Prefer fixing names and behavior in the spec or SDK config over custom code. + +## Verify + +- After `fern generate`, the custom files and edits are unchanged and the SDK still builds. + +## Reference + +- [Custom code](https://buildwithfern.com/learn/sdks/overview/custom-code.md) +- [Migrate to Replay](https://buildwithfern.com/learn/sdks/overview/replay-migration.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/features.mdx b/fern/products/home/pages/fern-instructions/sdks/features.mdx new file mode 100644 index 0000000000..05b9c76374 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/features.mdx @@ -0,0 +1,33 @@ +--- +title: Configure Fern SDK features +slug: fern-instructions/sdks/features +description: Find the setup page for SDK auth, global headers, pagination, retries, idempotency, WebSockets, SSE, webhook signature verification, and other SDK features. +--- + +Use this to turn on an SDK capability. Most are driven by the spec, and some by the SDK config. + +| Feature | Set up with | +|---|---| +| Auth and environment variable fallbacks | Spec security schemes and `x-fern-*` auth extensions, or `api.auth` in `sdk-config.yml`. See `spec auth`. | +| Dynamic or refreshing auth | [Dynamic authentication](https://buildwithfern.com/learn/sdks/deep-dives/dynamic-authentication.md) | +| Global headers | `x-fern-global-headers`. [Global headers](https://buildwithfern.com/learn/sdks/deep-dives/global-headers.md) | +| Auto-pagination | `x-fern-pagination`. [Pagination](https://buildwithfern.com/learn/sdks/deep-dives/auto-pagination.md) | +| Retries with backoff | `client.retry` in `sdk-config.yml` or `x-fern-retries`. [Retries](https://buildwithfern.com/learn/sdks/deep-dives/retries-with-backoff.md) | +| Idempotency | `x-fern-idempotent` and `x-fern-idempotency-headers`. [Idempotency](https://buildwithfern.com/learn/sdks/deep-dives/idempotency.md) | +| Method names | `operationId` or `x-fern-sdk-method-name`. [Method names](https://buildwithfern.com/learn/sdks/deep-dives/customize-method-names.md) | +| Subset of endpoints | Audiences. [Audiences](https://buildwithfern.com/learn/sdks/deep-dives/audiences.md) | +| Server URL templating | [Server URL templating](https://buildwithfern.com/learn/sdks/deep-dives/server-url-templating.md) | +| WebSocket clients | AsyncAPI. [WebSockets](https://buildwithfern.com/learn/sdks/deep-dives/websocket-clients.md) | +| Server-sent events | `x-fern-streaming`. [SSE](https://buildwithfern.com/learn/sdks/deep-dives/sse-metadata.md) | +| Webhook signature verification | [Webhook verification](https://buildwithfern.com/learn/sdks/deep-dives/webhook-signature-verification.md) | +| README content | `docs.readme`. [README](https://buildwithfern.com/learn/sdks/deep-dives/readme.md) | +| XML bodies | [XML types](https://buildwithfern.com/learn/sdks/deep-dives/xml-encoded-types.md) | + +## Workflow + +1. Open the feature's page and follow it. +2. Run `fern check`, then `fern generate --preview` and inspect the generated client. + +## Reference + +- [SDK capabilities](https://buildwithfern.com/learn/sdks/overview/capabilities.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/go.mdx b/fern/products/home/pages/fern-instructions/sdks/go.mdx new file mode 100644 index 0000000000..f284ac2540 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/go.mdx @@ -0,0 +1,30 @@ +--- +title: Generate a Go SDK with Fern +slug: fern-instructions/sdks/go +description: Add, configure, and publish a Go SDK generated by Fern. +--- + +Use this for Go-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: go + output: + delivery: files + path: ../sdks/go + ``` + +2. Set the package name and other Go options from the Go configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target go --preview` and build the output with the usual Go tooling. +4. To publish to the Go module proxy, follow `sdks publish` and the Go publishing page. + +## Reference + +- [Go quickstart](https://buildwithfern.com/learn/sdks/generators/go/quickstart.md) +- [Go configuration](https://buildwithfern.com/learn/sdks/generators/go/configuration.md) +- [Publish to the Go module proxy](https://buildwithfern.com/learn/sdks/generators/go/publishing.md) +- [Go custom code](https://buildwithfern.com/learn/sdks/generators/go/custom-code.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/java.mdx b/fern/products/home/pages/fern-instructions/sdks/java.mdx new file mode 100644 index 0000000000..a48caf8604 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/java.mdx @@ -0,0 +1,30 @@ +--- +title: Generate a Java SDK with Fern +slug: fern-instructions/sdks/java +description: Add, configure, and publish a Java SDK generated by Fern. +--- + +Use this for Java-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: java + output: + delivery: files + path: ../sdks/java + ``` + +2. Set the package name and other Java options from the Java configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target java --preview` and build the output with the usual Java tooling. +4. To publish to Maven Central, follow `sdks publish` and the Java publishing page. + +## Reference + +- [Java quickstart](https://buildwithfern.com/learn/sdks/generators/java/quickstart.md) +- [Java configuration](https://buildwithfern.com/learn/sdks/generators/java/configuration.md) +- [Publish to Maven Central](https://buildwithfern.com/learn/sdks/generators/java/publishing.md) +- [Java custom code](https://buildwithfern.com/learn/sdks/generators/java/custom-code.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/local.mdx b/fern/products/home/pages/fern-instructions/sdks/local.mdx new file mode 100644 index 0000000000..36cb3666de --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/local.mdx @@ -0,0 +1,32 @@ +--- +title: Generate and test Fern SDKs locally +slug: fern-instructions/sdks/local +description: Run Fern SDK generators locally with Docker, create local previews, test generated SDKs, and self-host generation. +--- + +Use this to generate without Fern's servers, try an SDK before publishing, or test it. + +## Workflow + +1. Preview without publishing: `fern generate --preview` (or `--target --preview`). Output goes to `fern/.preview/` (`--output ` to change it) and nothing is pushed or published. +2. Run generators on the user's machine: `fern generate --local`. This needs a running Docker daemon (or another runtime selected with `--runner`). `sdk-config.yml` targets run Fern's on-prem generator locally and need a minimum generator version per language. +3. Point output at a folder with `output.delivery: files` and `output.path` in `sdk-config.yml`, then build or install the SDK from there. +4. Test the SDK against the API, or against generated tests and mocks, as described in the testing page. +5. For air-gapped or regulated environments, follow the self-hosted generation pages. + +## Rules + +- Without `generatorVersion`, local runs use the minimum supported version while remote runs use the newest. Pin it so local and remote output match. +- `fern generate --package` builds an installable artifact (for example `.tgz` or `.whl`) in `fern-dist/` for targets with file output. +- On CI runners without Docker, use remote generation. + +## Verify + +- The SDK builds and its tests pass in the output folder. + +## Reference + +- [Local previews](https://buildwithfern.com/learn/sdks/deep-dives/local-previews.md) +- [Testing](https://buildwithfern.com/learn/sdks/deep-dives/testing.md) +- [Self-hosted generation](https://buildwithfern.com/learn/sdks/deep-dives/self-hosted.md) +- [SDK commands](https://buildwithfern.com/learn/cli-api-reference/cli-reference/sdk-commands.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/migrate.mdx b/fern/products/home/pages/fern-instructions/sdks/migrate.mdx new file mode 100644 index 0000000000..14bd67286a --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/migrate.mdx @@ -0,0 +1,30 @@ +--- +title: Migrate Fern SDK configuration +slug: fern-instructions/sdks/migrate +description: Move from generators.yml groups to sdk-config.yml, upgrade generators across major versions, and handle breaking configuration changes. +--- + +Use this for config migrations and major generator or CLI upgrades. + +## Move to sdk-config.yml + +1. Preview: `fern sdk migrate --dry-run`. Narrow it with `--group`, `--language` or `--api`. `--strict` treats mapping problems as errors. +2. Apply: `fern sdk migrate`. It creates or merges `sdk-config.yml` beside the legacy configuration (`--output` to choose the path). +3. Run `fern check` and `fern generate --preview`, and compare the output with the current SDK. + +## Upgrade the CLI and generators + +1. `fern upgrade` updates `version` in `fern.config.json` and runs migrations. `fern downgrade` reverts it. +2. Read the CLI and generator changelogs for breaking changes before a major upgrade. +3. Update generator versions (`targets[].generatorVersion`, or `fern generator upgrade` for `generators.yml`). +4. Generate a preview and diff it against the published SDK before releasing. + +## Rules + +- Release major generator upgrades as a new major SDK version when the public API changes. +- Keep `.fernignore` and Replay settings when moving config. + +## Reference + +- [SDK Config migration guide](https://buildwithfern.com/learn/sdks/legacy/generators/migration-guides/sdk-config.md) +- [`sdk-config.yml` reference](https://buildwithfern.com/learn/sdks/reference/sdk-config.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/php.mdx b/fern/products/home/pages/fern-instructions/sdks/php.mdx new file mode 100644 index 0000000000..4743f5606a --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/php.mdx @@ -0,0 +1,30 @@ +--- +title: Generate a PHP SDK with Fern +slug: fern-instructions/sdks/php +description: Add, configure, and publish a PHP SDK generated by Fern. +--- + +Use this for PHP-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: php + output: + delivery: files + path: ../sdks/php + ``` + +2. Set the package name and other PHP options from the PHP configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target php --preview` and build the output with the usual PHP tooling. +4. To publish to Packagist, follow `sdks publish` and the PHP publishing page. + +## Reference + +- [PHP quickstart](https://buildwithfern.com/learn/sdks/generators/php/quickstart.md) +- [PHP configuration](https://buildwithfern.com/learn/sdks/generators/php/configuration.md) +- [Publish to Packagist](https://buildwithfern.com/learn/sdks/generators/php/publishing.md) +- [PHP custom code](https://buildwithfern.com/learn/sdks/generators/php/custom-code.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/publish.mdx b/fern/products/home/pages/fern-instructions/sdks/publish.mdx new file mode 100644 index 0000000000..6f221c8d18 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/publish.mdx @@ -0,0 +1,49 @@ +--- +title: Publish Fern SDKs +slug: fern-instructions/sdks/publish +description: Deliver generated SDKs to GitHub repositories and publish them to npm, PyPI, Maven Central, NuGet, RubyGems, crates.io, and other registries. +--- + +Use this to move an SDK from local output to a GitHub repo and a package registry. + +## Workflow + +1. Create one GitHub repository per SDK and install the [Fern GitHub App](https://github.com/apps/fern-api) on it. +2. Set the target's output to GitHub and add publishing in `sdk-config.yml`: + + ```yaml + targets: + - language: typescript + package: + packageName: "@acme/sdk" + output: + delivery: github + github: + repository: acme/acme-typescript + mode: pull-request + publish: + registry: npm + token: ${NPM_TOKEN} + ``` + + `mode` is one of `release`, `pull-request`, `push`, `commit` or `commit-and-release`. Legacy `generators.yml` projects configure the same thing under each generator's `output` and `github`. +3. Add the registry credential as a GitHub Actions secret in the SDK repo (for example `NPM_TOKEN`). npm also supports trusted publishing (OIDC) with `trustedPublishing: true` instead of a token. +4. Generate with a version: `fern generate --target typescript --version 1.2.0`. Without `--version`, Fern picks one. +5. Merge the generated pull request (or let `release` mode publish). The SDK repo's workflow publishes the package. + +## Rules + +- Credentials must be environment expressions such as `${NPM_TOKEN}`, never literal values. +- Package names must be available on the registry. Ask the user before choosing one. +- Guest sessions can't generate or publish SDKs. Claim the session or log in first. See `new-site`. +- If a release exists but the package isn't on the registry, debug the publish workflow in the SDK repo. + +## Verify + +- The SDK repo has the generated commit or pull request, and the package version appears on the registry after the workflow runs. + +## Reference + +- [Project structure and GitHub setup](https://buildwithfern.com/learn/sdks/overview/project-structure.md) +- [`sdk-config.yml` output and publish](https://buildwithfern.com/learn/sdks/reference/sdk-config.md) +- Per-language publishing pages: `fern instructions sdks ` diff --git a/fern/products/home/pages/fern-instructions/sdks/python.mdx b/fern/products/home/pages/fern-instructions/sdks/python.mdx new file mode 100644 index 0000000000..0ccb0ca843 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/python.mdx @@ -0,0 +1,30 @@ +--- +title: Generate a Python SDK with Fern +slug: fern-instructions/sdks/python +description: Add, configure, and publish a Python SDK generated by Fern. +--- + +Use this for Python-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: python + output: + delivery: files + path: ../sdks/python + ``` + +2. Set the package name and other Python options from the Python configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target python --preview` and build the output with the usual Python tooling. +4. To publish to PyPI, follow `sdks publish` and the Python publishing page. + +## Reference + +- [Python quickstart](https://buildwithfern.com/learn/sdks/generators/python/quickstart.md) +- [Python configuration](https://buildwithfern.com/learn/sdks/generators/python/configuration.md) +- [Publish to PyPI](https://buildwithfern.com/learn/sdks/generators/python/publishing.md) +- [Python custom code](https://buildwithfern.com/learn/sdks/generators/python/custom-code.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/ruby.mdx b/fern/products/home/pages/fern-instructions/sdks/ruby.mdx new file mode 100644 index 0000000000..76c60d9bba --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/ruby.mdx @@ -0,0 +1,30 @@ +--- +title: Generate a Ruby SDK with Fern +slug: fern-instructions/sdks/ruby +description: Add, configure, and publish a Ruby SDK generated by Fern. +--- + +Use this for Ruby-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: ruby + output: + delivery: files + path: ../sdks/ruby + ``` + +2. Set the package name and other Ruby options from the Ruby configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target ruby --preview` and build the output with the usual Ruby tooling. +4. To publish to RubyGems, follow `sdks publish` and the Ruby publishing page. + +## Reference + +- [Ruby quickstart](https://buildwithfern.com/learn/sdks/generators/ruby/quickstart.md) +- [Ruby configuration](https://buildwithfern.com/learn/sdks/generators/ruby/configuration.md) +- [Publish to RubyGems](https://buildwithfern.com/learn/sdks/generators/ruby/publishing.md) +- [Ruby custom code](https://buildwithfern.com/learn/sdks/generators/ruby/custom-code.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/rust.mdx b/fern/products/home/pages/fern-instructions/sdks/rust.mdx new file mode 100644 index 0000000000..cde3c47c36 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/rust.mdx @@ -0,0 +1,29 @@ +--- +title: Generate a Rust SDK with Fern +slug: fern-instructions/sdks/rust +description: Add, configure, and publish a Rust SDK generated by Fern. +--- + +Use this for Rust-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: rust + output: + delivery: files + path: ../sdks/rust + ``` + +2. Set the package name and other Rust options from the Rust configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target rust --preview` and build the output with the usual Rust tooling. +4. To publish to crates.io, follow `sdks publish` and the Rust publishing page. + +## Reference + +- [Rust quickstart](https://buildwithfern.com/learn/sdks/generators/rust/quickstart.md) +- [Rust configuration](https://buildwithfern.com/learn/sdks/generators/rust/configuration.md) +- [Publish to crates.io](https://buildwithfern.com/learn/sdks/generators/rust/publishing.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/swift.mdx b/fern/products/home/pages/fern-instructions/sdks/swift.mdx new file mode 100644 index 0000000000..1b622afbd4 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/swift.mdx @@ -0,0 +1,29 @@ +--- +title: Generate a Swift SDK with Fern +slug: fern-instructions/sdks/swift +description: Add, configure, and publish a Swift SDK generated by Fern. +--- + +Use this for Swift-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: swift + output: + delivery: files + path: ../sdks/swift + ``` + +2. Set the package name and other Swift options from the Swift configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target swift --preview` and build the output with the usual Swift tooling. +4. To publish to Swift Package Manager, follow `sdks publish` and the Swift publishing page. + +## Reference + +- [Swift quickstart](https://buildwithfern.com/learn/sdks/generators/swift/quickstart.md) +- [Swift configuration](https://buildwithfern.com/learn/sdks/generators/swift/configuration.md) +- [Publish to Swift Package Manager](https://buildwithfern.com/learn/sdks/generators/swift/publishing.md) diff --git a/fern/products/home/pages/fern-instructions/sdks/typescript.mdx b/fern/products/home/pages/fern-instructions/sdks/typescript.mdx new file mode 100644 index 0000000000..90f8e55397 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/sdks/typescript.mdx @@ -0,0 +1,30 @@ +--- +title: Generate a TypeScript SDK with Fern +slug: fern-instructions/sdks/typescript +description: Add, configure, and publish a TypeScript SDK generated by Fern. +--- + +Use this for TypeScript-specific SDK setup. For what applies to every language, see `sdks`. + +## Workflow + +1. Add a target to `sdk-config.yml`: + + ```yaml + targets: + - language: typescript + output: + delivery: files + path: ../sdks/typescript + ``` + +2. Set the package name and other TypeScript options from the TypeScript configuration page. Look up each option there; don't guess names. +3. Run `fern check`, then `fern generate --target typescript --preview` and build the output with the usual TypeScript tooling. +4. To publish to npm, follow `sdks publish` and the TypeScript publishing page. + +## Reference + +- [TypeScript quickstart](https://buildwithfern.com/learn/sdks/generators/typescript/quickstart.md) +- [TypeScript configuration](https://buildwithfern.com/learn/sdks/generators/typescript/configuration.md) +- [Publish to npm](https://buildwithfern.com/learn/sdks/generators/typescript/publishing.md) +- [TypeScript custom code](https://buildwithfern.com/learn/sdks/generators/typescript/custom-code.md) diff --git a/fern/products/home/pages/fern-instructions/spec.mdx b/fern/products/home/pages/fern-instructions/spec.mdx new file mode 100644 index 0000000000..9ef44919a3 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/spec.mdx @@ -0,0 +1,41 @@ +--- +title: Prepare an API spec for Fern +slug: fern-instructions/spec +description: Get an OpenAPI spec ready for Fern SDKs and docs, with good operationIds, tags, reusable schemas, examples, and error responses. +--- + +Use this when editing the OpenAPI (or AsyncAPI) file Fern reads, or when SDK names or docs content need to change at the spec level. + +## Workflow + +1. Find the spec. It's listed under `source.specs` in `sdk-config.yml`, `api.specs` in `generators.yml`, or `specs` on an `api` entry in `docs.yml`. Check for overlays or overrides listed next to it. +2. Decide where the change goes. If the spec is downloaded from an `origin` or generated from code, put Fern changes in an overlay instead of editing it. See `spec overrides`. +3. Fix what drives SDK and docs quality: + - `operationId` on every operation. It becomes the SDK method name. + - `tags` group operations into SDK clients and API Reference sections. + - Shared shapes live in `components.schemas` and are used with `$ref`. Inline objects become auto-named types. + - `required` and `nullable` are accurate. + - Request and response `examples` for each operation. Otherwise Fern generates them. + - Response schemas for error status codes, so SDKs get typed errors. + - `securitySchemes` and `servers`. See `spec auth`. +4. Use `x-fern-*` extensions for anything OpenAPI can't express. See `spec extensions`. +5. Run `fern check` after every change. Add `--warnings` to see missing `operationId` and similar warnings. +6. Preview the effect: `fern docs dev` for docs, `fern generate --preview` for SDKs. + +## Rules + +- Fern silently ignores unknown `x-` keys. A misspelled extension does nothing and raises no error. Copy names from the extension pages. +- Don't put credentials or private hostnames in a spec that's published. +- Use OpenAPI 3.x where possible. Swagger 2.0 works but loses detail. + +## Verify + +- `fern check` passes. Generated method names, groups and types read naturally, and the API Reference shows examples for every endpoint. + +## Reference + +- [OpenAPI overview](https://buildwithfern.com/learn/api-definitions/openapi/overview.md) +- [Authentication](https://buildwithfern.com/learn/api-definitions/openapi/authentication.md) +- [Servers](https://buildwithfern.com/learn/api-definitions/openapi/servers.md) +- [Extensions](https://buildwithfern.com/learn/api-definitions/openapi/extensions/overview.md) +- [API definitions overview](https://buildwithfern.com/learn/api-definitions/overview/what-is-an-api-definition.md) diff --git a/fern/products/home/pages/fern-instructions/spec/auth.mdx b/fern/products/home/pages/fern-instructions/spec/auth.mdx new file mode 100644 index 0000000000..a815ddca65 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/spec/auth.mdx @@ -0,0 +1,55 @@ +--- +title: Define auth and servers in an API spec +slug: fern-instructions/spec/auth +description: Model API authentication schemes, environments, and multiple base URLs in an OpenAPI spec for Fern SDKs and docs. +--- + +Use this when the SDK's constructor options, auth headers or environments are wrong. + +## Workflow + +1. Declare every scheme in `components.securitySchemes` and apply it with top-level or per-operation `security`: + + ```yaml + components: + securitySchemes: + ApiKey: + type: apiKey + in: header + name: X-API-Key + x-fern-header: + name: apiKey + env: ACME_API_KEY + security: + - ApiKey: [] + ``` + + `x-fern-bearer`, `x-fern-header` and `x-fern-basic` rename the SDK parameter and set an environment variable fallback. OAuth client credentials flows are supported too. +2. List environments in `servers` and name each with `x-fern-server-name`. The names become SDK environment options: + + ```yaml + servers: + - url: https://api.acme.com + x-fern-server-name: Production + - url: https://api.staging.acme.com + x-fern-server-name: Staging + ``` + +3. For APIs with several base URLs, or URL variables, follow the servers page. +4. With `sdk-config.yml`, auth can also be set once under `api.auth`. +5. Run `fern check` and generate a preview to check the client's constructor. + +## Rules + +- Don't put real keys or private hosts in a published spec. +- Each scheme needs a stable name. Renaming it changes SDK parameters. + +## Verify + +- The generated client takes the expected credentials, reads the environment variable fallback, and offers the named environments. + +## Reference + +- [Authentication](https://buildwithfern.com/learn/api-definitions/openapi/authentication.md) +- [Servers](https://buildwithfern.com/learn/api-definitions/openapi/servers.md) +- [Server names and URL templating](https://buildwithfern.com/learn/api-definitions/openapi/extensions/server-names-and-url-templating.md) diff --git a/fern/products/home/pages/fern-instructions/spec/extensions.mdx b/fern/products/home/pages/fern-instructions/spec/extensions.mdx new file mode 100644 index 0000000000..64b71714b7 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/spec/extensions.mdx @@ -0,0 +1,63 @@ +--- +title: Use Fern OpenAPI extensions +slug: fern-instructions/spec/extensions +description: Pick the right x-fern extension for SDK names, ignored elements, pagination, examples, audiences, availability, retries, idempotency, and global headers. +--- + +Use this when OpenAPI alone can't express what the SDK or docs need. + +## Pick an extension + +| Need | Extension | +|---|---| +| SDK method and group names | `x-fern-sdk-method-name`, `x-fern-sdk-group-name` | +| Type, property and parameter names | `x-fern-type-name`, `x-fern-property-name`, `x-fern-parameter-name` | +| Enum value names and descriptions | `x-fern-enum` | +| Leave something out of SDKs and docs | `x-fern-ignore` | +| Auto-pagination | `x-fern-pagination` | +| Request and response examples | `x-fern-examples` | +| Publish a subset to some audiences | `x-fern-audiences` | +| Beta, deprecated and similar badges | `x-fern-availability` | +| Retries | `x-fern-retries` | +| Idempotency | `x-fern-idempotent`, `x-fern-idempotency-headers` | +| Headers or parameters on every request | `x-fern-global-headers`, `x-fern-global-parameters` | +| Variables set once on the client | `x-fern-sdk-variables` | +| Streaming responses | `x-fern-streaming` | +| Server names, URL templates, base path | `x-fern-server-name`, `x-fern-base-path` | +| SDK namespaces | `x-fern-sdk-namespace` | +| API Explorer behavior | `x-fern-explorer` | +| API version header | `x-fern-version` | + +Example: + +```yaml +paths: + /plants: + get: + operationId: listPlants + x-fern-sdk-group-name: plants + x-fern-sdk-method-name: list + x-fern-pagination: + cursor: $request.cursor + next_cursor: $response.next_cursor + results: $response.data +``` + +## Workflow + +1. Open the extension's page and copy the exact name and shape. +2. Add it to the spec, or to an overlay if the spec is downloaded or generated. See `spec overrides`. +3. Run `fern check`, then preview the SDK or docs. + +## Rules + +- Unknown or misspelled `x-` keys are ignored without an error. +- Prefer standard OpenAPI (`operationId`, `tags`, `deprecated`) when it does the job, and add an extension only to change the result. + +## Verify + +- The generated SDK or API Reference reflects the extension, for example the new method name or pagination iterator. + +## Reference + +- [Extensions overview](https://buildwithfern.com/learn/api-definitions/openapi/extensions/overview.md) (links to every extension page) diff --git a/fern/products/home/pages/fern-instructions/spec/formats.mdx b/fern/products/home/pages/fern-instructions/spec/formats.mdx new file mode 100644 index 0000000000..4a756605f5 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/spec/formats.mdx @@ -0,0 +1,34 @@ +--- +title: Use AsyncAPI, gRPC, OpenRPC, or a Fern Definition +slug: fern-instructions/spec/formats +description: Specifics for API definitions other than OpenAPI in Fern - AsyncAPI channels, gRPC protos, OpenRPC methods, and the Fern Definition. +--- + +Use this when the API isn't (only) described with OpenAPI. + +## Formats + +| Format | Use for | Notes | +|---|---|---| +| AsyncAPI | WebSocket and event APIs | Channels, messages and bindings map to WebSocket clients and reference pages. Supports Fern extensions such as audiences and availability. | +| gRPC | Protobuf services | Point the project at the `.proto` root. `fern init --grpc` (sample) or `fern init --proto ` creates a project with a C# SDK, the only SDK language with native gRPC output. | +| OpenRPC | JSON-RPC APIs | Methods become SDK methods. Has its own extensions. | +| Fern Definition | APIs defined directly in Fern's YAML format | `fern init --fern-definition` creates a sample. | + +## Workflow + +1. Add the definition to the `fern/` folder and list it with its type, for example `asyncapi: ./asyncapi.yml` under `api.specs` in `generators.yml`, or `type: asyncapi` in `sdk-config.yml` and `docs.yml` spec entries. +2. Run `fern check`. +3. Preview with `fern docs dev` or `fern generate --preview`. + +## Rules + +- OpenAPI and AsyncAPI specs can sit side by side in one API. That's how to describe REST plus WebSocket. +- Check the format's extensions page before adding `x-fern-*` keys. Not every OpenAPI extension exists for every format. + +## Reference + +- [AsyncAPI](https://buildwithfern.com/learn/api-definitions/asyncapi/overview.md) +- [gRPC](https://buildwithfern.com/learn/api-definitions/grpc/overview.md) +- [OpenRPC](https://buildwithfern.com/learn/api-definitions/openrpc/overview.md) +- [API definitions overview](https://buildwithfern.com/learn/api-definitions/overview/what-is-an-api-definition.md) diff --git a/fern/products/home/pages/fern-instructions/spec/overrides.mdx b/fern/products/home/pages/fern-instructions/spec/overrides.mdx new file mode 100644 index 0000000000..943ff79038 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/spec/overrides.mdx @@ -0,0 +1,59 @@ +--- +title: Change a spec you can't edit +slug: fern-instructions/spec/overrides +description: Customize an OpenAPI spec for Fern with overlays or overrides when the source spec is downloaded, generated, or shared. +--- + +Use this when the spec comes from somewhere else (a URL, a code generator, another team) and edits to it would be lost. + +## Pick an approach + +| Approach | When | +|---|---| +| Edit the spec | The user owns the file and nothing regenerates it | +| Overlay (preferred) | The spec is downloaded, generated from code, or shared with other tools. Uses the [OpenAPI Overlay](https://spec.openapis.org/overlay/v1.0.0) standard: JSONPath `target` plus `update` or `remove`. | +| Overrides | Existing Fern projects that already use them. A Fern-specific YAML file that mirrors the spec's structure and is deep-merged into it. | + +## Workflow + +1. Create the overlay: + + ```yaml title="overlays/sdk.yml" + overlay: 1.0.0 + info: + title: SDK customizations + version: 1.0.0 + actions: + - target: $.paths['/plants'].get + update: + x-fern-sdk-group-name: plants + x-fern-sdk-method-name: list + ``` + +2. Reference it next to the spec, for example in `generators.yml`: + + ```yaml + api: + specs: + - openapi: ./openapi.json + overlays: ./overlays/sdk.yml + ``` + + In `sdk-config.yml` or a `docs.yml` `api` entry, add the file to the spec entry's `overlays` or `overrides` list. +3. For overrides, `fern write-overrides` scaffolds an `overrides.yml` from the spec. +4. Run `fern check`. + +## Rules + +- Both fields take a single path or a list, applied in order. Overrides apply before overlays. +- A `target` that matches nothing changes nothing. Check the JSONPath against the spec. +- Keep the source spec untouched so `fern api update` can refresh it. See `spec sync`. + +## Verify + +- `fern check` passes and the generated SDK or API Reference shows the change. + +## Reference + +- [Overlays](https://buildwithfern.com/learn/api-definitions/openapi/overlays.md) +- [Overrides](https://buildwithfern.com/learn/api-definitions/openapi/overrides.md) diff --git a/fern/products/home/pages/fern-instructions/spec/sync.mdx b/fern/products/home/pages/fern-instructions/spec/sync.mdx new file mode 100644 index 0000000000..a1e238e94e --- /dev/null +++ b/fern/products/home/pages/fern-instructions/spec/sync.mdx @@ -0,0 +1,37 @@ +--- +title: Keep an API spec in sync +slug: fern-instructions/spec/sync +description: Refresh a Fern project's spec from its source with fern api update, and automate it with the sync-openapi GitHub Action. +--- + +Use this when the API spec lives elsewhere and the Fern project's copy needs to stay current. + +## Workflow + +1. Record where the spec comes from by adding `origin` to the spec entry in `generators.yml`: + + ```yaml + api: + specs: + - openapi: ./openapi.json + origin: https://api.example.com/openapi.json + ``` + +2. Run `fern api update` (add `--api ` in multi-API projects). It downloads every spec with an `origin` over the local file, which must already exist. +3. Review the diff and run `fern check`. +4. To automate it, add the `fern-api/sync-openapi` GitHub Action. It runs on a schedule or trigger and opens a pull request with the spec changes. The spec sync guide has the workflow file. + +## Rules + +- Keep Fern customizations in overlays or overrides, not in the downloaded file. `fern api update` overwrites it. +- The action needs a token that can open pull requests in the repo. + +## Verify + +- After `fern api update`, the local spec matches the source, and `fern check` passes. + +## Reference + +- [Sync your OpenAPI spec](https://buildwithfern.com/learn/api-definitions/openapi/sync-your-open-api-specification.md) +- [Sync an AsyncAPI spec](https://buildwithfern.com/learn/api-definitions/asyncapi/sync-your-async-api-specification.md) +- [`fern api update`](https://buildwithfern.com/learn/cli-api-reference/cli-reference/general-commands.md) diff --git a/fern/products/home/pages/fern-instructions/topics.mdx b/fern/products/home/pages/fern-instructions/topics.mdx new file mode 100644 index 0000000000..a3d48ea1e0 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/topics.mdx @@ -0,0 +1,69 @@ +--- +# Powers the `fern instructions` CLI command. Don't move this page, change its slug, or change the topic table format +# without updating the CLI in fern-api/fern. See "Agent instruction pages" in AGENTS.md. +title: Fern instructions +slug: fern-instructions +description: Index of task-scoped instructions for coding agents working in a Fern project, with when to use each topic. +--- + +Each topic below is a short, task-scoped workflow for a coding agent: the steps to follow, the rules agents most often break, and how to verify the result. Fetch a topic by appending its path and `.md` to `https://buildwithfern.com/learn/home/fern-instructions/`. For example, `docs publish domain` is at `https://buildwithfern.com/learn/home/fern-instructions/docs/publish/domain.md`. + +Start with `overview` when you're new to a Fern project. For anything a topic doesn't cover, search the full docs through the [page index](https://buildwithfern.com/learn/llms.txt) or the docs MCP server at `https://buildwithfern.com/learn/_mcp/server`. + +## Core + +| Topic | When to use | +|---|---| +| `overview` | Start here: how a Fern project is laid out, which file controls what, facts agents get wrong | +| `new-site` | New project, `fern init`, no account, `--guest`, claiming a guest session, `fern login`, `fern whoami` | +| `troubleshoot` | An error from `fern check` or `fern generate`, a failed publish, or output that looks wrong | + +## Docs + +| Topic | When to use | +|---|---| +| `docs write` | Before creating a page or writing more than a few sentences; frontmatter, snippets, changelogs | +| `docs write components` | Callouts, cards, steps, tabs, accordions, code blocks, endpoint snippets, Mintlify-style components | +| `docs configure` | Changing `docs.yml`: title, colors, logo, favicon, layout, theme | +| `docs configure navigation` | Sections, pages, folders, tabs, versions, products, moving or renaming pages | +| `docs configure customization` | Custom CSS and JavaScript, React components, banner, hiding content, search, header and footer | +| `docs configure seo` | Metadata, slugs, redirects, `robots.txt` | +| `docs configure localization` | Adding a language or updating translations | +| `docs api-reference` | API Reference pages for REST, webhooks, WebSocket, gRPC, GraphQL, OpenRPC; layout, audiences, API Explorer | +| `docs publish` | Local preview, preview links, `fern generate --docs`, checking whether a change is live | +| `docs publish domain` | Custom domain, `/docs` subpath, reverse proxy, multi-source docs | +| `docs access` | Private docs: password, SSO, JWT, OAuth, RBAC, API key injection | +| `docs ai` | `llms.txt`, Markdown access, agent directives, Ask Fern, the site's MCP server and skills | +| `docs analytics` | PostHog, Google, Segment, Mixpanel, Intercom, analytics events | + +## API definitions + +| Topic | When to use | +|---|---| +| `spec` | Getting an OpenAPI spec ready for Fern: `operationId`, tags, `$ref` schemas, examples, errors | +| `spec extensions` | Any `x-fern-*` extension: names, ignore, pagination, audiences, availability, retries, idempotency | +| `spec overrides` | Changing a spec you can't edit: overlays versus overrides | +| `spec auth` | Security schemes, servers, environments, multiple base URLs | +| `spec sync` | Keeping the spec current: `fern api update`, the `sync-openapi` GitHub Action | +| `spec formats` | AsyncAPI, gRPC, OpenRPC, and Fern Definition specifics | + +## SDKs + +| Topic | When to use | +|---|---| +| `sdks` | Adding an SDK, `generators.yml` groups and config, `fern generate`, upgrading generators | +| `sdks ` | Language-specific setup and config: `typescript`, `python`, `go`, `java`, `csharp`, `php`, `ruby`, `swift`, `rust` | +| `sdks publish` | npm, PyPI, Maven Central, NuGet, RubyGems, Packagist, crates.io; GitHub output modes; Autorelease | +| `sdks custom-code` | Keeping hand-written code: `.fernignore` versus Replay | +| `sdks features` | Auth, global headers, pagination, retries, idempotency, WebSockets, SSE, webhook verification | +| `sdks local` | Local generation with Docker, local previews, testing, self-hosted generation | +| `sdks migrate` | Major generator upgrades and breaking configuration changes | + +## CI and other products + +| Topic | When to use | +|---|---| +| `automate` | CI: pin the CLI, `FERN_TOKEN`, `fern check` on pull requests, preview per pull request, publish on merge, SDK release on tag | +| `access team` | Dashboard members, permissions, organization tokens, SSO, Git repository connection | +| `migrate` | Moving docs to Fern from Mintlify, ReadMe, or another platform | +| `cli-generator` | Generating a command-line tool from an API definition | diff --git a/fern/products/home/pages/fern-instructions/troubleshoot.mdx b/fern/products/home/pages/fern-instructions/troubleshoot.mdx new file mode 100644 index 0000000000..8142f1be49 --- /dev/null +++ b/fern/products/home/pages/fern-instructions/troubleshoot.mdx @@ -0,0 +1,69 @@ +--- +title: Troubleshoot Fern errors +slug: fern-instructions/troubleshoot +description: Diagnose fern check and fern generate failures, failed docs publishes, authentication errors, and CI-only failures. +--- + +Use this when a Fern command fails or the output looks wrong. + +## Workflow + +1. Re-run the failing command with `--log-level debug`. Compare the CLI version printed at the start with `version` in `fern.config.json`. +2. Run `fern check`. Fix every error before anything else. It reports the file and YAML path of each problem. +3. Run `fern whoami` if the error mentions a token, login, organization or permission. +4. Find the symptom below. If it isn't listed, search the docs for the exact error text. +5. Fix the cause in the source: the spec, `docs.yml`, `sdk-config.yml` or `generators.yml`. Don't patch generated output. +6. Re-run the original command. + +## Authentication and organization + +| Symptom | Cause and fix | +|---|---| +| `No token found. Please set the FERN_TOKEN environment variable or run fern login.` | Not authenticated. Run `fern login`, set `FERN_TOKEN`, or, for docs only, try `fern generate --docs --guest`. See `new-site`. | +| `401` or `Unauthorized` in CI | `FERN_TOKEN` is missing from the step's environment, empty on fork or Dependabot runs, or revoked. Create a new one with `fern token`. | +| Publishing fails with an organization error | `organization` in `fern.config.json` doesn't match the user's organization in the Dashboard, or the user isn't a member. | +| `--guest` refuses to run | `FERN_TOKEN` is set or a login is saved. Unset it or run `fern logout`, or drop `--guest`. | +| SDK generation fails with `--guest` | Guests can't generate SDKs yet. Run `fern login`, set `FERN_TOKEN`, or claim the session with `fern claim` first. | +| Guest session expired, revoked or already claimed | `fern generate --docs --guest --new-session` | +| `fern claim` finds no session | Run it in the repo where `fern generate --docs --guest` ran, or run that first. | + +## Docs + +| Symptom | Cause and fix | +|---|---| +| Page missing from the site | It isn't referenced in `docs.yml` navigation, or it's `hidden: true` | +| Link returns 404 | The link was built from the file path. Rebuild it from the navigation titles and `slug` values. | +| 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. | +| Change not visible after publishing | Confirm the command printed `Published docs to ` for the expected instance, then reload without the cache | + +## SDKs + +| Symptom | Cause and fix | +|---|---| +| `Unrecognized key` in the SDK config | The key doesn't exist for that generator version. Check the language's configuration page or upgrade the generator. | +| `repository not found` or push fails | The [Fern GitHub App](https://github.com/apps/fern-api) isn't installed on the SDK repo, or the repository name is wrong | +| `workflows` permission error | The token can't write `.github/workflows`. Grant the `workflow` scope or stop generating workflows. | +| Hand-written code overwritten | The file isn't in `.fernignore` and Replay isn't on. See `sdks custom-code`. | +| Endpoint missing from the SDK | Filtered by audiences or `x-fern-ignore`, or the spec wasn't refreshed | +| Methods named like `postUsers` | No `operationId`. Add one or use `x-fern-sdk-method-name`. See `spec`. | +| Errors aren't typed | The spec has no response schemas for error status codes | +| `Cannot connect to the Docker daemon` | `--local` needs a running Docker daemon. Start Docker or generate remotely. | +| Release created but package not on the registry | The publish job in the SDK repo failed. Check that repo's Actions, not the config repo. | +| Different output on each run | The generator version or the CLI version isn't pinned. Pin both. | + +## CI only + +| 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. | +| Works locally, `Unrecognized key` in CI | Different CLI versions. Pin a concrete `version` in `fern.config.json`. | +| `fetch failed` installing or upgrading the CLI | The runner can't reach the npm registry. Check `HTTPS_PROXY`, the npm registry setting and `NODE_EXTRA_CA_CERTS`. | + +## Reference + +- [CLI commands](https://buildwithfern.com/learn/cli-api-reference/cli-reference/general-commands.md) +- [Docs commands](https://buildwithfern.com/learn/cli-api-reference/cli-reference/docs-commands.md)