diff --git a/fern/products/docs/docs.yml b/fern/products/docs/docs.yml index 6e636477e..6af9aa185 100644 --- a/fern/products/docs/docs.yml +++ b/fern/products/docs/docs.yml @@ -178,6 +178,19 @@ navigation: path: ./pages/ai/overview.mdx - page: Fern Writer path: ./pages/ai/writer.mdx + - section: Fern Writer CLI + slug: fern-writer-cli + hidden: true + contents: + - page: Install and use + path: ./pages/ai/writer-cli/install.mdx + slug: install + - page: Automate with CI/CD + path: ./pages/ai/writer-cli/ci-cd.mdx + slug: ci-cd + - page: Scheduled runs + path: ./pages/ai/writer-cli/scheduled-runs.mdx + slug: scheduled-runs - page: AI-generated examples path: ./pages/ai/ai-examples.mdx slug: ai-examples diff --git a/fern/products/docs/pages/ai/writer-cli/ci-cd.mdx b/fern/products/docs/pages/ai/writer-cli/ci-cd.mdx new file mode 100644 index 000000000..ef6f4deea --- /dev/null +++ b/fern/products/docs/pages/ai/writer-cli/ci-cd.mdx @@ -0,0 +1,159 @@ +--- +title: Automate with CI/CD +description: Use the Fern Writer CLI in GitHub Actions to auto-document pull requests and API changes. +--- + +Integrate the [Fern Writer CLI](/learn/docs/ai-features/fern-writer-cli/install) into your CI/CD pipeline to trigger documentation updates automatically when code changes land. + +## Auto-document pull requests + +This workflow triggers Fern Writer whenever a pull request that modifies your API spec is merged: + +```yaml title=".github/workflows/fern-writer-on-merge.yml" +name: Auto-document merged PRs + +on: + pull_request: + types: [closed] + paths: + - "openapi/**" + - "fern/**" + +jobs: + update-docs: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Install Fern Writer CLI + run: npm install -g @fern-api/fern-writer + + - name: Trigger Fern Writer + env: + FERN_WRITER_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + RESULT=$(fern-writer scribe-api create-scribe-session \ + --prompt "Document the changes from PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}" \ + --github-repo "${{ github.repository }}" \ + --format json) + + SESSION_ID=$(echo "$RESULT" | jq -r '.session_id') + echo "Session started: $SESSION_ID" + + - name: Poll for completion + env: + FERN_WRITER_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + SESSION_ID=$(fern-writer scribe-api list-scribe-sessions --limit 1 --format json | jq -r '.sessions[0].session_id') + + for i in $(seq 1 360); do + STATUS=$(fern-writer scribe-api get-scribe-session-status-endpoint \ + --session-id "$SESSION_ID" \ + --format json) + + STATE=$(echo "$STATUS" | jq -r '.status') + PR_URL=$(echo "$STATUS" | jq -r '.pr_url // empty') + + if [ -n "$PR_URL" ]; then + echo "Docs PR created: $PR_URL" + exit 0 + fi + + if [ "$STATE" = "stopped" ] || [ "$STATE" = "failed" ]; then + echo "Session ended with status: $STATE" + exit 1 + fi + + sleep 30 + done + + echo "Timed out waiting for session" + exit 1 +``` + +### Setup + + + + +Go to your repository's **Settings > Secrets and variables > Actions** and add `FERN_TOKEN` as a repository secret. Get your token with `fern token` from the [Fern CLI](/learn/cli-api-reference/cli-reference/commands#fern-token). + + + + +The [Fern GitHub App](https://github.com/apps/fern-api) must be installed on the repository so Fern Writer can open pull requests. + + + + +Adjust the `paths` filter in the workflow to match where your API definitions live. Common patterns: + +```yaml +paths: + - "openapi/**" # OpenAPI specs + - "fern/**" # Fern definitions + - "swagger/**" # Swagger files + - "*.proto" # Protobuf definitions +``` + + + + +## Trigger on API spec changes + +For repositories where the API spec is the source of truth, trigger on pushes to the default branch: + +```yaml title=".github/workflows/fern-writer-on-spec-change.yml" +name: Update docs on spec change + +on: + push: + branches: [main] + paths: + - "openapi/openapi.yml" + +jobs: + update-docs: + runs-on: ubuntu-latest + steps: + - name: Install Fern Writer CLI + run: npm install -g @fern-api/fern-writer + + - name: Trigger Fern Writer + env: + FERN_WRITER_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + fern-writer scribe-api create-scribe-session \ + --prompt "The API spec has been updated. Review the changes and update the documentation accordingly." \ + --github-repo "${{ github.repository }}" +``` + +## Manual dispatch + +Add `workflow_dispatch` for on-demand runs from the GitHub UI: + +```yaml title=".github/workflows/fern-writer-manual.yml" +name: Trigger Fern Writer + +on: + workflow_dispatch: + inputs: + prompt: + description: "What should Fern Writer do?" + required: true + type: string + +jobs: + run: + runs-on: ubuntu-latest + steps: + - name: Install Fern Writer CLI + run: npm install -g @fern-api/fern-writer + + - name: Trigger Fern Writer + env: + FERN_WRITER_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + fern-writer scribe-api create-scribe-session \ + --prompt "${{ github.event.inputs.prompt }}" \ + --github-repo "${{ github.repository }}" +``` diff --git a/fern/products/docs/pages/ai/writer-cli/install.mdx b/fern/products/docs/pages/ai/writer-cli/install.mdx new file mode 100644 index 000000000..79fa03168 --- /dev/null +++ b/fern/products/docs/pages/ai/writer-cli/install.mdx @@ -0,0 +1,146 @@ +--- +title: Fern Writer CLI +description: Install and use the Fern Writer CLI to trigger documentation updates from your terminal. +--- + +The Fern Writer CLI lets you trigger [Fern Writer](/learn/docs/ai-features/fern-writer) sessions directly from your terminal. It wraps the Fern Writer API into subcommands for creating sessions, polling status, and listing past runs. + +The CLI is generated by Fern's [CLI generator](/learn/cli-generator/get-started/overview) from the Fern Writer OpenAPI spec. It ships as a single statically linked binary with no runtime dependencies. + + +The CLI generator is in early access. [Reach out](https://buildwithfern.com/contact) to get started. + + +## Prerequisites + +- A [Fern token](/learn/cli-api-reference/cli-reference/commands#fern-token) for your organization +- The [Fern GitHub App](https://github.com/apps/fern-api) installed on the target repository + +## Install + +Fern publishes signed binaries to Homebrew, npm, and GitHub Releases on every release. + + + +```bash +brew tap fern-api/tap +brew install fern-writer +``` + + +```bash +npm install -g @fern-api/fern-writer +``` + + +```bash +pnpm add -g @fern-api/fern-writer +``` + + +```bash +curl -fsSL https://cli.buildwithfern.com/install.sh | sh -s -- --cli fern-writer +``` + + + +Verify the installation: + +```bash +fern-writer --version +``` + +## Authentication + +Set your Fern token as an environment variable: + +```bash +export FERN_WRITER_TOKEN= +``` + +For CI environments, store the token as a repository secret and reference it: + +```bash +FERN_WRITER_TOKEN=${{ secrets.FERN_TOKEN }} fern-writer scribe-api create-scribe-session ... +``` + +## Usage + +All Fern Writer commands live under the `scribe-api` subcommand. + +### Create a session + +Start a Fern Writer session against a repository: + +```bash +fern-writer scribe-api create-scribe-session \ + --prompt "Document the new /plants endpoint added in PR #42" \ + --github-repo "acme/docs" +``` + +You can also pass the request body as JSON: + +```bash +fern-writer scribe-api create-scribe-session \ + --json '{"prompt": "Document the new /plants endpoint", "github_repo": "acme/docs"}' +``` + +### Check session status + +Poll a session until it completes and returns a pull request URL: + +```bash +fern-writer scribe-api get-scribe-session-status-endpoint \ + --session-id "sess_abc123" +``` + +### List sessions + +List recent sessions, optionally filtered by repository: + +```bash +fern-writer scribe-api list-scribe-sessions + +# Filter by repository +fern-writer scribe-api list-scribe-sessions --github-repo "acme/docs" + +# Include stopped sessions +fern-writer scribe-api list-scribe-sessions --include-stopped true +``` + +### Output formatting + +All commands support the `--format` flag: + +```bash +# Table view +fern-writer scribe-api list-scribe-sessions --format table + +# JSON (default) +fern-writer scribe-api list-scribe-sessions --format json + +# CSV export +fern-writer scribe-api list-scribe-sessions --format csv > sessions.csv +``` + +### Dry-run mode + +Preview the HTTP request without sending it: + +```bash +fern-writer scribe-api create-scribe-session \ + --prompt "Update the quickstart guide" \ + --github-repo "acme/docs" \ + --dry-run +``` + +## Environment variables + +| Variable | Purpose | +| ---- | --------------- | +| `FERN_WRITER_TOKEN` | Bearer token for authentication | +| `FERN_WRITER_BASE_URL` | Override the API base URL | +| `FERN_WRITER_TIMEOUT_SECS` | Total request timeout | +| `FERN_WRITER_PROXY` | HTTP(S) proxy URL | + +Errors are emitted as structured JSON on stderr. diff --git a/fern/products/docs/pages/ai/writer-cli/scheduled-runs.mdx b/fern/products/docs/pages/ai/writer-cli/scheduled-runs.mdx new file mode 100644 index 000000000..90943f83d --- /dev/null +++ b/fern/products/docs/pages/ai/writer-cli/scheduled-runs.mdx @@ -0,0 +1,128 @@ +--- +title: Scheduled documentation runs +description: Run Fern Writer on a schedule to keep documentation in sync with your codebase. +--- + +Schedule the [Fern Writer CLI](/learn/docs/ai-features/fern-writer-cli/install) to run periodically, catching documentation drift before it compounds. + +## GitHub Actions cron schedule + +Use a [scheduled workflow](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule) to run Fern Writer at a fixed interval: + +```yaml title=".github/workflows/fern-writer-scheduled.yml" +name: Scheduled docs review + +on: + schedule: + # Every Monday at 9:00 UTC + - cron: "0 9 * * 1" + workflow_dispatch: {} + +jobs: + review-docs: + runs-on: ubuntu-latest + steps: + - name: Install Fern Writer CLI + run: npm install -g @fern-api/fern-writer + + - name: Trigger Fern Writer + env: + FERN_WRITER_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + fern-writer scribe-api create-scribe-session \ + --prompt "Review the documentation for accuracy. Check that all API endpoints are documented, code examples are correct, and no pages reference deprecated behavior." \ + --github-repo "${{ github.repository }}" + + - name: Wait for completion + env: + FERN_WRITER_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + # Get the most recent session + SESSION_ID=$(fern-writer scribe-api list-scribe-sessions \ + --limit 1 \ + --format json | jq -r '.sessions[0].session_id') + + for i in $(seq 1 360); do + STATUS=$(fern-writer scribe-api get-scribe-session-status-endpoint \ + --session-id "$SESSION_ID" \ + --format json) + + STATE=$(echo "$STATUS" | jq -r '.status') + PR_URL=$(echo "$STATUS" | jq -r '.pr_url // empty') + + if [ -n "$PR_URL" ]; then + echo "Docs PR created: $PR_URL" + exit 0 + fi + + if [ "$STATE" = "stopped" ] || [ "$STATE" = "failed" ]; then + echo "Session ended with status: $STATE" + exit 0 + fi + + sleep 30 + done +``` + +### Common cron patterns + +| Schedule | Cron expression | Description | +| --- | --- | --- | +| Weekly | `0 9 * * 1` | Every Monday at 9:00 UTC | +| Biweekly | `0 9 1,15 * *` | 1st and 15th of each month | +| Daily | `0 6 * * *` | Every day at 6:00 UTC | +| After releases | Use `workflow_dispatch` | Trigger manually post-release | + +## System cron job + +For environments outside GitHub Actions, use a system cron job: + +```bash title="crontab -e" +# Run Fern Writer every Monday at 9:00 AM UTC +0 9 * * 1 FERN_WRITER_TOKEN= fern-writer scribe-api create-scribe-session --prompt "Review docs for accuracy and completeness." --github-repo "acme/docs" >> /var/log/fern-writer.log 2>&1 +``` + +### Wrapper script + +For more control over logging and error handling: + +```bash title="fern-writer-scheduled.sh" +#!/usr/bin/env bash +set -euo pipefail + +REPO="acme/docs" +PROMPT="Review the documentation for accuracy. Check that all API endpoints are documented and code examples compile." +LOG_FILE="/var/log/fern-writer.log" + +echo "[$(date -u)] Starting scheduled Fern Writer run" >> "$LOG_FILE" + +RESULT=$(fern-writer scribe-api create-scribe-session \ + --prompt "$PROMPT" \ + --github-repo "$REPO" \ + --format json 2>>"$LOG_FILE") + +SESSION_ID=$(echo "$RESULT" | jq -r '.session_id') +echo "[$(date -u)] Session created: $SESSION_ID" >> "$LOG_FILE" +``` + +```bash title="crontab -e" +0 9 * * 1 FERN_WRITER_TOKEN= /path/to/fern-writer-scheduled.sh +``` + +## Prompt examples + +Tailor the prompt to your scheduled run's purpose: + +```bash +# General review +"Review the documentation for accuracy and completeness." + +# Post-release audit +"A new release was shipped. Check that all new endpoints are documented and changelog is up to date." + +# Style enforcement +"Review all documentation pages for consistent formatting, correct code examples, and proper use of components." + +# Stale content detection +"Identify any documentation pages that reference deprecated APIs, removed features, or outdated configuration options." +```