diff --git a/.github/workflows/agent-context-ci.yml b/.github/workflows/agent-context-ci.yml new file mode 100644 index 0000000000..76baca8270 --- /dev/null +++ b/.github/workflows/agent-context-ci.yml @@ -0,0 +1,33 @@ +name: Validate agent context + +on: + pull_request: + paths: + - agent-context/** + - .github/workflows/agent-context-ci.yml + - .github/workflows/sync-agent-context.yml + push: + branches: [main] + paths: + - agent-context/** + - .github/workflows/agent-context-ci.yml + - .github/workflows/sync-agent-context.yml + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: 24 + package-manager-cache: false + - run: npm test + working-directory: agent-context + - run: npm run check + working-directory: agent-context + - run: npm run build + working-directory: agent-context diff --git a/.github/workflows/sync-agent-context.yml b/.github/workflows/sync-agent-context.yml new file mode 100644 index 0000000000..790e258002 --- /dev/null +++ b/.github/workflows/sync-agent-context.yml @@ -0,0 +1,132 @@ +name: Sync plugin context + +on: + workflow_dispatch: + push: + branches: [main] + paths: + - agent-context/context/** + - agent-context/targets/** + - agent-context/scripts/** + - agent-context/test/** + - agent-context/package.json + - .github/workflows/sync-agent-context.yml + +permissions: + contents: read + +concurrency: + group: sync-plugin-context + cancel-in-progress: false + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: 24 + package-manager-cache: false + - run: npm test + working-directory: agent-context + - run: npm run check + working-directory: agent-context + + sync: + needs: validate + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - target: codex + repository: mintlify/codex-plugin + repository_name: codex-plugin + mcp_file: .mcp.json + - target: cursor + repository: mintlify/cursor-plugin + repository_name: cursor-plugin + mcp_file: mcp.json + - target: claude + repository: mintlify/mintlify-claude-plugin + repository_name: mintlify-claude-plugin + mcp_file: .mcp.json + + steps: + - name: Check out context source + uses: actions/checkout@v6 + with: + path: source + + - uses: actions/setup-node@v6 + with: + node-version: 24 + package-manager-cache: false + + - name: Create target repository token + id: app-token + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ vars.CONTEXT_SYNC_APP_CLIENT_ID }} + private-key: ${{ secrets.CONTEXT_SYNC_APP_PRIVATE_KEY }} + owner: mintlify + repositories: ${{ matrix.repository_name }} + permission-contents: write + permission-pull-requests: write + + - name: Check out target repository + uses: actions/checkout@v6 + with: + repository: ${{ matrix.repository }} + token: ${{ steps.app-token.outputs.token }} + path: target + + - name: Generate target context + run: node source/agent-context/scripts/sync-target.mjs "${{ matrix.target }}" target + + - name: Detect changes + id: changes + working-directory: target + run: | + if [[ -n "$(git status --porcelain)" ]]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + else + echo "changed=false" >> "$GITHUB_OUTPUT" + fi + + - name: Commit and push sync branch + if: steps.changes.outputs.changed == 'true' + working-directory: target + env: + APP_SLUG: ${{ steps.app-token.outputs.app-slug }} + BRANCH: automation/sync-agent-context + run: | + git config user.name "${APP_SLUG}[bot]" + git config user.email "${APP_SLUG}[bot]@users.noreply.github.com" + git checkout -B "$BRANCH" + git add skills/mintlify .mintlify-agent-context.json "${{ matrix.mcp_file }}" + git commit -m "Sync Mintlify agent context" + git fetch origin "$BRANCH:refs/remotes/origin/$BRANCH" || true + git push --force-with-lease origin "HEAD:$BRANCH" + + - name: Open sync pull request + if: steps.changes.outputs.changed == 'true' + working-directory: target + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + GH_REPO: ${{ matrix.repository }} + BRANCH: automation/sync-agent-context + SOURCE_SHA: ${{ github.sha }} + run: | + BODY="Generated from mintlify/docs at ${SOURCE_SHA} using agent-context. Do not edit generated skill files in this repository." + EXISTING_PR="$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number')" + if [[ -z "$EXISTING_PR" ]]; then + gh pr create \ + --head "$BRANCH" \ + --base main \ + --title "Sync Mintlify agent context" \ + --body "$BODY" + else + gh pr edit "$EXISTING_PR" --body "$BODY" + fi diff --git a/.mintignore b/.mintignore new file mode 100644 index 0000000000..9f4349f4bf --- /dev/null +++ b/.mintignore @@ -0,0 +1,2 @@ +# Internal tooling that compiles context for external agent plugins. +agent-context/ diff --git a/agent-context/.gitignore b/agent-context/.gitignore new file mode 100644 index 0000000000..ba34fb68b6 --- /dev/null +++ b/agent-context/.gitignore @@ -0,0 +1,3 @@ +dist/ +node_modules/ +.DS_Store diff --git a/agent-context/LICENSE b/agent-context/LICENSE new file mode 100644 index 0000000000..dacb79ecce --- /dev/null +++ b/agent-context/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Mintlify + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/agent-context/README.md b/agent-context/README.md new file mode 100644 index 0000000000..62c3453630 --- /dev/null +++ b/agent-context/README.md @@ -0,0 +1,60 @@ +# Mintlify agent context + +Single source of truth, maintained in the Mintlify documentation repository, for the Mintlify skill distributed through the Codex, Cursor, and Claude plugins. + +## Repository structure + +- `context/skills/mintlify/` contains canonical, client-neutral context. +- `context/mcp-servers.json` contains canonical MCP names, URLs, and transport settings. +- `targets/*.json` contains only client packaging differences such as MCP config file and schema names. +- `scripts/build.mjs` renders self-contained plugin artifacts into `dist/`. +- `scripts/sync-target.mjs` replaces only `skills/mintlify/` in a target repository. +- `../.github/workflows/sync-agent-context.yml` opens generated sync pull requests in all three plugin repositories. + +Plugin manifests, assets, READMEs, and Cursor rules remain owned by their target repositories. This project generates the shared skill and each client's MCP configuration file. + +## Local development + +Requires Node.js 22 or newer and has no package dependencies. + +```bash +npm test +npm run check +npm run build +npm run status +``` + +Build one target by passing its ID: + +```bash +node scripts/build.mjs codex +``` + +Preview a sync into a local checkout: + +```bash +node scripts/sync-target.mjs codex ../../codex-plugin +git -C ../../codex-plugin diff +``` + +The sync command replaces `skills/mintlify/`, writes the client-specific MCP configuration file, and writes `.mintlify-agent-context.json` with the source commit. It does not change any other plugin files. + +`npm run status` compares locally checked-out sibling plugin repositories with fresh builds and reports whether each one is current. Pass a workspace root as the final argument if the repositories do not share this repository's parent directory. + +## Publishing setup + +Create a GitHub App installed on these repositories: + +- `mintlify/codex-plugin` +- `mintlify/cursor-plugin` +- `mintlify/mintlify-claude-plugin` + +Grant the app repository **Contents: read and write** and **Pull requests: read and write** permissions. Add its client ID as the `CONTEXT_SYNC_APP_CLIENT_ID` Actions variable and its private key as the `CONTEXT_SYNC_APP_PRIVATE_KEY` Actions secret in the `mintlify/docs` repository. + +Every qualifying push to `main` validates the source and opens or updates the `automation/sync-agent-context` pull request in each repository. The workflow never pushes directly to a target's default branch. + +## Editing rules + +Edit shared knowledge and MCP definitions in `context/`, not in generated plugin copies. Put a value in `targets/` only when a client requires a different packaging format. + +The build rejects retired CLI commands. Tests verify that the skill, detailed references, and MCP definitions remain semantically identical across targets. diff --git a/agent-context/context/mcp-servers.json b/agent-context/context/mcp-servers.json new file mode 100644 index 0000000000..4ade053aa7 --- /dev/null +++ b/agent-context/context/mcp-servers.json @@ -0,0 +1,10 @@ +{ + "Mintlify Search": { + "type": "http", + "url": "https://mintlify.com/docs/mcp" + }, + "Mintlify Admin": { + "type": "http", + "url": "https://mcp.mintlify.com" + } +} diff --git a/agent-context/context/skills/mintlify/SKILL.md b/agent-context/context/skills/mintlify/SKILL.md new file mode 100644 index 0000000000..10c0265c50 --- /dev/null +++ b/agent-context/context/skills/mintlify/SKILL.md @@ -0,0 +1,240 @@ +--- +name: mintlify +description: Comprehensive reference for building Mintlify documentation sites. Use when creating pages, configuring docs.json, adding components, setting up navigation, or working with API references. Routes to detailed reference files for all components and configuration options. +--- + +# Mintlify reference + +Reference for working on Mintlify projects. This file covers essentials that apply to every task. For detailed reference on specific topics, read the files listed in the reference index below. + +## Reference index + +Read these files **only when your task requires them**. They are in the `reference/` directory next to this file. + +| File | When to read | +|------|-------------| +| `reference/components.md` | Adding or modifying components (callouts, cards, steps, tabs, accordions, code groups, fields, frames, icons, tooltips, badges, trees, mermaid, panels, prompts, colors, tiles, updates, views). | +| `reference/configuration.md` | Changing docs.json settings (theme, colors, logo, fonts, appearance, navbar, footer, banner, redirects, SEO, integrations, API config). Also covers snippets, hidden pages, .mintignore, custom CSS/JS, and the complete frontmatter fields table. | +| `reference/navigation.md` | Modifying site navigation structure (groups, tabs, anchors, dropdowns, products, versions, languages, OpenAPI in nav). | +| `reference/api-docs.md` | Setting up API documentation (OpenAPI, AsyncAPI, MDX manual API pages, extensions, playground config). | +| `reference/cli.md` | Running CLI commands (dev, validate, analytics, workflow, score, broken-links, a11y, config, and all flags). | +| `reference/site-discovery.md` | Creating a new documentation site or replacing substantial placeholder content. | + +## MCP servers + +Two Mintlify MCP servers are available. Use them alongside the reference files in this skill. + +### Mintlify Search + +Read-only access to Mintlify's published documentation. Use it when the reference files don't cover a specific detail, when you need an up-to-date component signature, or to verify an unfamiliar config option. + +Tools: +- `search_mintlify` — Search the Mintlify knowledge base by query. Good for finding guides, examples, and API references. +- `query_docs_filesystem_mintlify` — Browse the docs file tree (`ls`, `cat`, `grep`, `find`, etc.). Good for reading a specific docs page. +- `submit_feedback` — Report a docs page that is incorrect, outdated, confusing, or incomplete. + +### Mintlify Admin + +Write access to a Mintlify project. Requires OAuth on first use. Complete authentication in the browser when prompted. + +Use this server when the user wants to edit their Mintlify content, restructure navigation, or open a pull request. All changes happen on a branch and must be reviewed before merging. + +Workflow: call `checkout` first (always), then use `read`/`search`/`edit_page`/`write_page`/`list_nodes`/`create_node`/`update_node`/`move_node`/`delete_node`/`update_config` to make changes, then call `save` to open a PR (or `discard_session` to abandon). + +Key tools: +- **`checkout`** — Start a session on a branch (required first call). Returns an `editorUrl` to preview changes live. +- **`list_branches`** — List existing branches; call before `checkout` to attach to one. +- **`list_deployments`** — Discover which deployment(s) this connection can access. +- **`read`** / **`search`** — Fetch a page's MDX or search across pages. +- **`edit_page`** / **`write_page`** — Apply targeted edits or overwrite a page. +- **`list_nodes`** / **`create_node`** / **`update_node`** / **`move_node`** / **`delete_node`** — Manage the navigation tree. +- **`update_config`** — Modify `docs.json` (theme, nav roots, integrations, SEO). +- **`diff`** — See all changes relative to `main`. +- **`get_session_state`** — Check the current session's status. +- **`save`** — Open a PR (`mode: "pr"`) or push to the branch (`mode: "commit"`). +- **`discard_session`** — Drop all in-session changes. + +Keep each session focused on one change. Smaller sessions produce easier-to-review PRs. Open the `editorUrl` to watch changes render live. + +## Before you start + +For a new site or a broad initial generation, read `reference/site-discovery.md` before planning the content. + +Read the project's `docs.json` file first. It defines the site's navigation, theme, colors, and configuration. + +Search for existing content before creating new pages. You may need to update an existing page, add a section, or link to existing content rather than duplicating. + +Read 2-3 similar pages to match the site's voice, structure, and formatting. + +## File format + +Mintlify uses MDX files (`.mdx` or `.md`) with YAML frontmatter. + +``` +project/ +├── docs.json # Site configuration (required) +├── index.mdx +├── quickstart.mdx +├── guides/ +│ └── example.mdx +├── openapi.yml # API specification (optional) +├── images/ # Static assets +│ └── example.png +└── snippets/ # Reusable components + └── component.jsx +``` + +### File naming + +- Match existing patterns in the directory +- If no existing files or mixed file naming patterns, use kebab-case: `getting-started.mdx` +- Add new pages to `docs.json` navigation or they won't appear in the sidebar + +### Internal links + +- Use root-relative paths without file extensions: `/getting-started/quickstart` +- Do not use relative paths (`../`) or absolute URLs for internal pages + +### Images + +Store images in an `images/` directory. Reference with root-relative paths. All images require descriptive alt text. + +```mdx +![Dashboard showing analytics overview](/images/dashboard.png) +``` + +## Page frontmatter + +Include `title`, `description`, and `keywords` in frontmatter. `title` is technically optional (Mintlify generates one from the file path if omitted), but set it explicitly for clarity and SEO. + +```yaml +--- +title: "Clear, descriptive title" +description: "Concise summary for SEO and navigation." +keywords: ["relevant", "search", "terms"] +--- +``` + +### Common frontmatter fields + +| Field | Type | Description | +|-------|------|-------------| +| `title` | string | Page title in navigation and browser tabs. Auto-generated from the path if omitted. | +| `description` | string | Brief description for SEO. Displays under the title. | +| `sidebarTitle` | string | Short title for sidebar navigation. | +| `icon` | string | Lucide, Font Awesome, or Tabler icon name. Also accepts a URL or file path. | +| `tag` | string | Label next to page title in sidebar (e.g., "NEW"). | +| `hidden` | boolean | Remove from sidebar. Page still accessible by URL. | +| `mode` | string | Page layout: `default`, `wide`, `custom`, `frame`, `center`. | +| `keywords` | array | Search terms for internal search and SEO. | +| `api` | string | API endpoint for interactive playground (e.g., `"POST /users"`). | +| `openapi` | string | OpenAPI endpoint reference (e.g., `"GET /endpoint"`). | + +For the complete list including `searchable`, `boost`, `deprecated`, `related`, `groups`, and more, read `reference/configuration.md`. + +## Quick component reference + +Below are the most commonly used components. For full props and all 25 components, read `reference/components.md`. + +### Callouts + +```mdx +Supplementary information, safe to skip. +Helpful context such as permissions or prerequisites. +Recommendations or best practices. +Potentially destructive actions or important caveats. +Success confirmation or completed status. +Critical warnings about data loss or breaking changes. +``` + +### Steps + +```mdx + + + Instructions for step one. + + + Instructions for step two. + + +``` + +### Tabs and code groups + +```mdx + + + ```bash + npm install package-name + ``` + + + ```bash + yarn add package-name + ``` + + +``` + +```mdx + + +```javascript example.js +const greeting = "Hello, world!"; +``` + +```python example.py +greeting = "Hello, world!" +``` + + +``` + +### Cards and columns + +```mdx + + + Card description text. + + + Card description text. + + +``` + +Use `` to arrange cards (or other content) in a grid. `cols` accepts 1-4. + +### Accordions + +```mdx + + Content one. + Content two. + +``` + +## CLI commands + +Install with `npm i -g mint`. Key commands: `mint dev` (local preview), `mint validate`, `mint broken-links`, `mint a11y`, `mint score`, `mint automations`, `mint deslop`, `mint new`, `mint signup`. Read `reference/cli.md` for full flags and subcommands. + +## Writing standards + +- Second-person voice ("you"). +- Active voice, direct language. +- Sentence case for headings ("Getting started", not "Getting Started"). +- Sentence case for code block titles. +- All code blocks must have language tags. +- All images must have descriptive alt text. +- No marketing language, filler phrases, or emoji. +- Keep code examples simple, practical, and tested. + +## Common mistakes + +- Using `mint.json` — it is deprecated. The config file is always `docs.json`. +- Missing language tag on a code block (use ` ```python `, not ` ``` `). +- Using relative paths (`../page`) instead of root-relative (`/section/page`). +- Forgetting to add new pages to `docs.json` navigation. +- Images without alt text. +- Adding file extensions to internal links (`/page.mdx` instead of `/page`). diff --git a/agent-context/context/skills/mintlify/reference/api-docs.md b/agent-context/context/skills/mintlify/reference/api-docs.md new file mode 100644 index 0000000000..ca44802f11 --- /dev/null +++ b/agent-context/context/skills/mintlify/reference/api-docs.md @@ -0,0 +1,141 @@ +# API documentation reference + +Setting up API documentation with OpenAPI, AsyncAPI, and MDX manual pages. + +## OpenAPI setup + +Add your OpenAPI spec to `docs.json`: + +```json +"api": { + "openapi": "openapi.json" +} +``` + +Multiple specs: + +```json +"api": { + "openapi": ["openapi/v1.json", "openapi/v2.json"] +} +``` + +Reference individual endpoints in navigation: + +```json +{ + "group": "Users", + "openapi": "openapi.json", + "pages": ["GET /users", "POST /users", "GET /users/{id}"] +} +``` + +## OpenAPI extensions + +- `x-hidden`: Creates page but hides from navigation. +- `x-excluded`: Completely excludes endpoint from docs. +- `x-codeSamples`: Custom code examples per endpoint. + +```yaml +paths: + /users: + get: + x-codeSamples: + - lang: "bash" + label: "List users" + source: | + curl https://api.example.com/users +``` + +## MDX manual API pages + +For endpoints without an OpenAPI spec: + +```yaml +--- +title: "Create user" +api: "POST https://api.example.com/users" +--- +``` + +Or with a base URL configured in `docs.json`: + +```yaml +--- +title: "Create user" +api: "POST /users" +--- +``` + +## AsyncAPI + +For WebSocket and event-driven APIs: + +```json +"api": { + "asyncapi": "asyncapi.yaml" +} +``` + +Reference channels in frontmatter: + +```yaml +--- +title: "WebSocket channel" +asyncapi: "/path/to/asyncapi.json channelName" +--- +``` + +## Playground configuration + +Control the API playground behavior in `docs.json`: + +```json +"api": { + "playground": { + "display": "interactive", + "proxy": true + }, + "examples": { + "languages": ["bash", "javascript", "python"], + "defaults": "all", + "prefill": false, + "autogenerate": true + }, + "mdx": { + "server": "https://api.example.com", + "auth": { + "method": "bearer" + } + } +} +``` + +- `playground.display`: `"interactive"`, `"simple"`, `"none"`, or `"auth"`. +- `playground.proxy`: Route requests through Mintlify's proxy. Default: `true`. +- `playground.credentials`: Include cookies and auth headers for cross-origin requests when proxy is `false`. Default: `false`. +- `params.expanded`: Expand all parameters by default. `"all"` or `"closed"` (default). +- `params.post`: OpenAPI schema field keys to surface as pills next to parameter names (array of strings). +- `url`: Set to `"full"` to always show the full base URL. +- `examples.languages`: Supported values — `bash` (cURL), `python`, `javascript`, `node`, `php`, `go`, `java`, `ruby`, `powershell`, `swift`, `csharp`, `dotnet`, `typescript`, `c`, `c++`, `kotlin`, `rust`, `dart`. +- `examples.defaults`: `"required"` or `"all"` (include optional params). +- `examples.prefill`: Pre-fill playground fields with spec example values. Default: `false`. +- `examples.autogenerate`: Generate code samples from API specs. Default: `true`. +- `mdx.auth.method`: `"bearer"`, `"basic"`, `"key"`, `"cobo"`. + +## Response rendering + +The playground renders responses automatically based on the `Content-Type` header: + +- `image/*` — rendered inline as an image. +- `audio/*` — rendered with a built-in audio player. +- `video/*` — rendered with a built-in video player. +- All other types — displayed in a code block. + +## Parameter anchor links + +Every parameter in the playground has a clickable anchor link. Hover over a parameter name to reveal the link icon, then click to copy a direct URL to that parameter. The URL format is `your-docs-url/endpoint-path#parameter-name`. For nested parameters, the anchor includes the parent path. + +## Custom endpoint pages + +Use the `x-mint` extension in your OpenAPI spec to customize individual endpoint pages (metadata, playground behavior, additional content) while keeping all API documentation in one file. Alternatively, create individual MDX pages for full per-page control. diff --git a/agent-context/context/skills/mintlify/reference/cli.md b/agent-context/context/skills/mintlify/reference/cli.md new file mode 100644 index 0000000000..8c90f3534c --- /dev/null +++ b/agent-context/context/skills/mintlify/reference/cli.md @@ -0,0 +1,67 @@ +# CLI reference + +Full reference for every `mint` CLI command and flag. + +Install with `npm i -g mint`. + +## Global flags + +Available on all commands. + +| Flag | Description | +|------|-------------| +| `--telemetry`, `-t` | Enable or disable anonymous usage telemetry. | +| `--help`, `-h` | Display help for the command. | +| `--version`, `-v` | Display the CLI version. Alias for `mint version`. | + +## Local development + +- `mint dev` — Start local preview at localhost:3000. `--port` sets the port. `--no-open` skips browser launch. `--groups ` mocks user groups. `--disable-openapi` skips OpenAPI processing. `--local-schema` allows locally-hosted OpenAPI files over HTTP. +- `mint validate` — Strict build validation; exits non-zero on warnings or errors. `--groups ` mocks user groups. `--disable-openapi` skips OpenAPI processing. `--local-schema` allows local OpenAPI files. +- `mint export` — Export a static site zip for air-gapped deployment. `--output ` sets the output path (default: `export.zip`). `--groups ` includes restricted pages. `--disable-openapi` skips OpenAPI processing. + +## Content quality + +- `mint broken-links` — Check for broken internal links. `--check-anchors` validates `#` anchors. `--check-external` checks external URLs. `--check-redirects` checks that redirect destinations in `docs.json` resolve. `--check-snippets` checks links inside `` components. +- `mint a11y` — Accessibility checks (alt text, color contrast). `--skip-contrast` or `--skip-alt-text` to narrow scope. +- `mint score [url]` — Score a docs site's AI/agent readiness. Checks llms.txt, MCP discoverability, robots.txt, sitemap, structured data, response latency, and more. Requires `mint login`. Defaults to your configured subdomain. `--format` accepts `table` (default), `plain`, or `json`. +- `mint deslop [files...]` — Check pages for AI-sounding prose and get rewrite suggestions. Requires `mint login`. Without `files`, checks the `.md`/`.mdx` pages changed in your working tree (Git diff plus untracked files). Flags: `--format` (`table`/`plain`/`json`), `--subdomain`, `--threshold` (0-1, default 0.5), `--fix-whitespace` (normalizes trailing spaces, blank-line runs, and invisible Unicode outside code blocks/frontmatter). + +## Authentication + +- `mint login` — Authenticate your Mintlify account. +- `mint logout` — Log out of your account. +- `mint status` — Show current authentication status (CLI version, email, org, subdomain). +- `mint signup [flags]` — Create a new Mintlify account from the terminal. Flags: `--firstName`, `--lastName`, `--company`, `--email`; omit any to enter it interactively. Waits until you click the emailed verification link before it logs you in — run as a background process in scripts. + +## Configuration + +- `mint config set ` — Persist a config value. Valid keys: `subdomain`. +- `mint config get ` — Read a stored config value. +- `mint config clear ` — Remove a stored config value. + +## Project setup + +- `mint new [directory]` — Scaffold a new Mintlify docs site. `--name` and `--theme` set initial config. `--template` selects a pre-defined template. `--force` overwrites an existing directory. + +## Automations + +All `mint automations` subcommands share these flags: `--subdomain`, `--format` (table/json; default: table). `mint workflow` and `mint workflows` continue to work as aliases. + +- `mint automations create` — Create an automation. Requires exactly one trigger: `--cron ` for scheduled or `--push-repo ` (repeatable) for push-triggered. Key flags: `--name`, `--type` (one of `changelog`, `source-code-agent`, `translations`, `writing-style`, `typo-check`, `broken-link-detection`, `seo-metadata-audit`, `assistant-docs-updates`, `contextual-feedback-docs-updates`; omit for custom), `--prompt`, `--context-repo` (repeatable, up to 10), `--automerge`, `--file ` (JSON/YAML file overrides inline flags). +- `mint automations list` — List automations for the current deployment. +- `mint automations delete ` — Delete an automation by ID. Use `mint automations list` to get the ID. + +## Maintenance + +- `mint update` — Update the CLI to the latest version. +- `mint version` — Show installed CLI and client versions. + +## Telemetry + +The CLI collects anonymous usage telemetry by default. Opt out with `--telemetry false` or by setting either environment variable: + +| Variable | Value | Description | +|----------|-------|-------------| +| `MINTLIFY_TELEMETRY_DISABLED` | `1` | Disable Mintlify CLI telemetry. | +| `DO_NOT_TRACK` | `1` | Disable telemetry using the Console Do Not Track standard. | diff --git a/agent-context/context/skills/mintlify/reference/components.md b/agent-context/context/skills/mintlify/reference/components.md new file mode 100644 index 0000000000..7633f300e4 --- /dev/null +++ b/agent-context/context/skills/mintlify/reference/components.md @@ -0,0 +1,517 @@ +# Components reference + +Full syntax and props for all Mintlify components. + +## Callouts + +Styled alert boxes for important information. + +```mdx +Supplementary information, safe to skip. +Helpful context such as permissions or prerequisites. +Recommendations or best practices. +Potentially destructive actions or important caveats. +Success confirmation or completed status. +Critical warnings about data loss or breaking changes. +``` + +Custom callout with icon and color: + +```mdx + + Custom callout with specific icon and color. + +``` + +## Banner + +Not an MDX component. A site-wide announcement banner configured via the `banner` field in `docs.json`. See `reference/configuration.md`. + +## Accordions + +Expandable/collapsible content sections. + +```mdx + + Hidden content revealed on click. + +``` + +Group multiple accordions: + +```mdx + + Content one. + Content two. + +``` + +Props: +- `title` (string, required): Header text. +- `description` (string): Detail text below title. +- `defaultOpen` (boolean, default: false): Initially expanded. +- `icon` (string): Icon name. +- `iconType` (string): Font Awesome style. + +## Cards + +Visual containers with titles, icons, and optional links. + +```mdx + + Card description text. + +``` + +```mdx + + Card with image and custom CTA. + +``` + +Props: +- `title` (string, required): Card title. +- `icon` (string): Icon name. +- `iconType` (string): Font Awesome style. +- `color` (string): Hex color for icon. +- `href` (string): Link destination. +- `horizontal` (boolean): Compact horizontal layout. +- `img` (string): Image URL or path for top of card. +- `cta` (string): Custom action button text. +- `arrow` (boolean): Show link arrow. + +## Columns + +Multi-column responsive grid layout. Use with Cards or other content. + +```mdx + + Content + Content + Content + +``` + +Props: +- `cols` (number, default: 2): Number of columns, 1-4. + +## Steps + +Numbered step-by-step procedures. + +```mdx + + + ```bash + npm i -g mint + ``` + + + ```bash + mint new my-docs + ``` + + + ```bash + mint dev + ``` + + +``` + +Step props: +- `title` (string): Step title. +- `icon` (string): Icon name. +- `iconType` (string): Font Awesome style. +- `stepNumber` (number): Override automatic numbering. +- `titleSize` (string, default: "p"): `"p"`, `"h2"`, or `"h3"`. + +## Tabs + +Switchable tabbed content sections. + +```mdx + + + ```bash + npm install package-name + ``` + + + ```bash + yarn add package-name + ``` + + +``` + +Tabs props: +- `sync` (boolean, default: true): Sync tab selection with other tabs and code groups with matching titles. +- `borderBottom` (boolean): Add bottom border and padding. + +Tab props: +- `title` (string, required): Tab name. +- `icon` (string): Icon name. +- `iconType` (string): Font Awesome style. + +## Code groups + +Tabbed code examples in multiple languages. Tabs sync with `` components that have matching titles. + +```mdx + + +```javascript example.js +const greeting = "Hello, world!"; +console.log(greeting); +``` + +```python example.py +greeting = "Hello, world!" +print(greeting) +``` + + +``` + +For dropdown style instead of tabs: + +```mdx + + ...code blocks... + +``` + +## Expandables + +Show/hide nested properties. Primarily used in API documentation. + +```mdx + + Unique identifier. + Display name. + +``` + +Props: +- `title` (string): Toggle label. +- `defaultOpen` (boolean, default: false): Initially expanded. + +## Fields + +Document API parameters and response structures. + +### ParamField + +```mdx + + Maximum number of results to return. + + + + User email address. + + + + Bearer token for authentication. + +``` + +Props: +- First parameter format: `query.name`, `path.name`, `body.name`, or `header.name`. +- `type` (string): `number`, `string`, `boolean`, `object`. Append `[]` for arrays. +- `required` (boolean): Mark as required. +- `deprecated` (boolean): Mark as deprecated. +- `default` (any): Default value. +- `placeholder` (string): Playground input placeholder. + +### ResponseField + +```mdx + + Unique user identifier. + + + + + Record ID. + Current status. + + +``` + +Props: +- `name` (string, required): Field name. +- `type` (string, required): Field type. +- `required` (boolean): Required indicator. +- `deprecated` (boolean): Deprecation flag. +- `default` (string): Default value. +- `pre` (string[]): Labels rendered before the field name. +- `post` (string[]): Labels rendered after the field name. + +## Request and response examples + +Display code examples in the right sidebar on API pages. + +```mdx + + +```bash cURL +curl --request POST \ + --url https://api.example.com/users \ + --header 'Authorization: Bearer TOKEN' +``` + +```python Python +import requests +response = requests.post( + "https://api.example.com/users", + headers={"Authorization": "Bearer TOKEN"} +) +``` + + + + + +```json 200 +{ + "id": "usr_123", + "status": "active" +} +``` + + +``` + +## Frames + +Styled container for images with optional captions. + +```mdx + + Dashboard showing analytics overview + +``` + +Props: +- `caption` (string): Text below image. Supports Markdown. +- `hint` (string): Text above image. + +## Icons + +Display icons inline. + +```mdx + + +Text with inline icon. +``` + +Props: +- `icon` (string, required): Icon name, URL, or file path. +- `iconType` (string): Font Awesome style. +- `size` (number): Pixel size. +- `color` (string): Hex color. + +## Tooltips + +Hover-triggered contextual help. + +```mdx + + API + requests are sent over HTTPS. +``` + +Props: +- `tip` (string, required): Tooltip text. +- `headline` (string): Text above tip. +- `cta` (string): Call-to-action link text. +- `href` (string): Link URL (required if using `cta`). + +## Badge + +Inline labels and status indicators. + +```mdx + + Active + +``` + +Props: +- `color` (string, default: "gray"): `gray`, `blue`, `green`, `yellow`, `orange`, `red`, `purple`, `white`, `surface`. +- `size` (string, default: "md"): `xs`, `sm`, `md`, `lg`. +- `shape` (string, default: "rounded"): `rounded`, `pill`. +- `icon` (string): Icon name. +- `stroke` (boolean): Outline style instead of filled. +- `disabled` (boolean): Reduced opacity. + +## Tree + +Display hierarchical file/folder structures. + +```mdx + + + + + + + + + + +``` + +Tree.Folder props: +- `name` (string, required): Folder name. +- `defaultOpen` (boolean, default: false): Expanded by default. +- `openable` (boolean, default: true): Can expand/collapse. + +Tree.File props: +- `name` (string, required): File name. + +## Mermaid diagrams + +Use mermaid code blocks for flowcharts, sequence diagrams, and more. + +````mdx +```mermaid +flowchart LR + A[Start] --> B{Decision} + B -->|Yes| C[Action] + B -->|No| D[Other action] +``` +```` + +## Panel + +Customize right sidebar content, replacing the table of contents. + +```mdx + + Custom sidebar content goes here. + +``` + +## Prompt + +Display copyable AI prompts. + +```mdx + +You are a technical writer. Generate a README for a Node.js project +that includes installation, usage, and contributing sections. + +``` + +Props: +- `description` (string, required): Card header. Supports Markdown. +- `actions` (array, default: ["copy"]): `"copy"`, `"cursor"`. +- `icon` (string): Icon name. + +## Color + +Display color palettes with click-to-copy. + +```mdx + + + + + +``` + +Table variant with rows: + +```mdx + + + + + + +``` + +## Tiles + +Visual preview cards, typically used in grid layouts. + +```mdx + + + Accordion component preview + + +``` + +Props: +- `href` (string, required): Link destination. +- `title` (string): Tile title. +- `description` (string): Short description. + +## Update + +Display changelog entries and release notes. + +```mdx + + ## What's new + + - Added dark mode support + - Improved search performance + +``` + +Props: +- `label` (string, required): Date or version identifier. +- `description` (string): Version or release name. +- `tags` (string[]): Filterable tags. +- `rss` (object): Custom RSS entry with `title` and `description`. + +## Visibility + +Show different content to humans (web UI) versus AI agents (Markdown output). Content marked `for="humans"` renders on the site but is excluded from `.md` URLs; content marked `for="agents"` is hidden on the site but included in Markdown output. + +```mdx + + Click the **Get started** button in the top-right corner. + + + + To create an account, call `POST /v1/accounts` with a valid email. + +``` + +Props: +- `for` (string, required): `"humans"` or `"agents"`. + +## View + +Language/framework-specific content sections that switch with a multi-view dropdown. + +```mdx + + ```javascript + console.log("Hello from JavaScript!"); + ``` + + + + ```python + print("Hello from Python!") + ``` + +``` + +Props: +- `title` (string, required): View selector label. +- `icon` (string): Icon name. diff --git a/agent-context/context/skills/mintlify/reference/configuration.md b/agent-context/context/skills/mintlify/reference/configuration.md new file mode 100644 index 0000000000..b062ca1be3 --- /dev/null +++ b/agent-context/context/skills/mintlify/reference/configuration.md @@ -0,0 +1,591 @@ +# Configuration reference + +Full docs.json settings, snippets, hidden pages, and custom CSS/JS. + +## docs.json + +The `docs.json` file controls the entire site. Required fields: `theme`, `name`, `colors.primary`, and `navigation`. + +### Splitting configuration with `$ref` + +Use `$ref` at any level of `docs.json` to load configuration from another JSON file. Useful for splitting large configs or sharing navigation across deployments. + +```json +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "mint", + "name": "Your Docs", + "colors": { "primary": "#3B82F6" }, + "navigation": { + "$ref": "./navigation.json" + } +} +``` + +Rules: +- `$ref` must be a relative path to a `.json` file. +- When `$ref` resolves to an object, sibling keys in the same block take precedence over matching keys in the referenced file. +- When `$ref` resolves to a non-object (e.g., an array), sibling keys are ignored. +- Referenced files can contain their own `$ref` entries, resolved relative to that file. +- Paths must stay within the project root. Circular references cause a build error. + +```json +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "mint", + "name": "Your Docs", + "colors": { + "primary": "#3B82F6" + }, + "navigation": { + "groups": [ + { + "group": "Getting started", + "pages": ["index", "quickstart"] + } + ] + } +} +``` + +## Complete frontmatter fields + +The SKILL.md file lists common frontmatter fields. Here is the complete set. All fields are optional; if `title` is omitted, Mintlify generates one from the file path (dashes and underscores become spaces, first letter capitalized). + +| Field | Type | Description | +|-------|------|-------------| +| `title` | string | Page title in navigation and browser tabs. Auto-generated from the path if omitted. | +| `description` | string | Brief description for SEO. Displays under the title. | +| `sidebarTitle` | string | Short title for sidebar navigation. | +| `icon` | string | Lucide, Font Awesome, or Tabler icon name. Also accepts a URL or file path. | +| `iconType` | string | Font Awesome icon style: `regular`, `solid`, `light`, `thin`, `sharp-solid`, `duotone`, `brands`. | +| `tag` | string | Label next to page title in sidebar (e.g., "NEW"). | +| `hidden` | boolean | Remove from sidebar. Page still accessible by URL. Do not set to `false`; remove the field entirely to make a page visible again. | +| `noindex` | boolean | Exclude from site search, sitemaps, search engine indexing, and AI assistant context. Still visible in navigation. | +| `searchable` | boolean | Defaults to `true`. Set `false` to exclude the page from site search and AI assistant context while keeping it indexable externally and visible in navigation. | +| `boost` | number | Multiply the page's in-product search ranking. Values above 1 prioritize, between 0 and 1 de-prioritize. No effect when `searchable: false`. | +| `deprecated` | boolean | Show a "deprecated" label next to the page title. | +| `hideFooterPagination` | boolean | Hide the previous/next navigation links at the bottom of the page. | +| `related` | array or boolean | Related pages shown in the **Related topics** section, or `false` to hide it. Requires the Related pages add-on. | +| `hideApiMarker` | boolean | Hide the HTTP method badge next to the page title in the sidebar. | +| `contextual` | object | Override the site-wide contextual menu (`options`, `display`) for this page. `options: []` disables it. | +| `groups` | string[] | Restrict the page to users in specific groups. Requires authentication configured first. | +| `mode` | string | Page layout: `default`, `wide`, `custom`, `frame`, `center`. | +| `keywords` | array | Search terms for internal search and SEO. | +| `api` | string | API endpoint for interactive playground (e.g., `"POST /users"`). | +| `openapi` | string | OpenAPI endpoint reference (e.g., `"GET /endpoint"`). | +| `url` | string | External URL. Makes the nav entry link externally. | +| `timestamp` | boolean | Override global timestamp setting for this page. | + +Any other key is accepted as custom frontmatter (e.g. `product: "API"`). + +## Page modes + +Control page layout with the `mode` frontmatter field. + +```yaml +# Default: standard layout with sidebar and table of contents +--- +title: "Page title" +--- + +# Wide: hides table of contents for extra horizontal space +--- +title: "Page title" +mode: "wide" +--- + +# Custom: blank canvas, only top navbar visible +--- +title: "Page title" +mode: "custom" +--- + +# Frame: like custom but keeps sidebar (Aspen, Almond, and Luma themes only) +--- +title: "Page title" +mode: "frame" +--- + +# Center: removes sidebar and TOC, centers content (Mint and Linden themes only) +--- +title: "Page title" +mode: "center" +--- +``` + +## Theme + +One of: `mint`, `maple`, `palm`, `willow`, `linden`, `almond`, `aspen`, `sequoia`, `luma`. + +| Theme | Character | +|-------|-----------| +| `mint` | Classic, time-tested | +| `maple` | Modern, clean, good for AI/SaaS | +| `palm` | Sophisticated, fintech-focused | +| `willow` | Stripped-back, minimal | +| `linden` | Retro terminal, monospace | +| `almond` | Card-based, minimalist | +| `aspen` | Modern, supports complex navigation | +| `sequoia` | Minimal, elegant, large-scale content | +| `luma` | Clean, minimal design for polished documentation | + +## Colors + +```json +"colors": { + "primary": "#3B82F6", + "light": "#F8FAFC", + "dark": "#0F172A" +} +``` + +- `primary` (required): Main color, generally for emphasis in light mode. +- `light`: Color for emphasis in dark mode. +- `dark`: Color for buttons and hover states. + +All values must be hex codes starting with `#`. + +## Logo + +```json +"logo": { + "light": "/logo/light.svg", + "dark": "/logo/dark.svg", + "href": "https://example.com" +} +``` + +## Favicon + +Single file or light/dark variants: + +```json +"favicon": "/favicon.ico" +``` + +```json +"favicon": { + "light": "/favicon.png", + "dark": "/favicon-dark.png" +} +``` + +## Icons + +```json +"icons": { + "library": "lucide" +} +``` + +Options: `"fontawesome"` (default), `"lucide"`, or `"tabler"`. You can only use one library per project. Individual icons can still use URLs or file paths regardless of this setting. + +## Fonts + +```json +"fonts": { + "family": "Inter" +} +``` + +Google Fonts load automatically by family name. For custom fonts: + +```json +"fonts": { + "family": "CustomFont", + "source": "/fonts/CustomFont.woff2", + "format": "woff2", + "weight": 400, + "heading": { + "family": "HeadingFont", + "weight": 700 + }, + "body": { + "family": "BodyFont", + "weight": 400 + } +} +``` + +## Appearance + +```json +"appearance": { + "default": "system", + "strict": false +} +``` + +- `default`: `"system"`, `"light"`, or `"dark"`. +- `strict`: Set `true` to hide the light/dark mode toggle. + +## Background + +```json +"background": { + "image": { + "light": "/bg-light.svg", + "dark": "/bg-dark.svg" + }, + "decoration": "gradient", + "color": { + "light": "#FFFFFF", + "dark": "#000000" + } +} +``` + +- `decoration`: `"gradient"`, `"grid"`, or `"windows"`. + +## Styling + +```json +"styling": { + "eyebrows": "breadcrumbs", + "latex": true, + "codeblocks": { + "theme": { + "light": "github-light", + "dark": "github-dark" + } + } +} +``` + +- `eyebrows`: `"section"` (default) or `"breadcrumbs"`. +- `latex`: Override automatic LaTeX detection. +- `codeblocks`: `"system"` (default), `"dark"`, a Shiki theme name, or an object with `light`/`dark` themes. + +## Navbar + +```json +"navbar": { + "links": [ + { + "label": "Community", + "href": "https://example.com/community" + }, + { + "type": "github", + "href": "https://github.com/example/repo" + } + ], + "primary": { + "type": "button", + "label": "Get Started", + "href": "https://example.com/start" + } +} +``` + +Link types: omit `type` for standard text link, `"github"` for repo with star count, `"discord"` for server with online count. + +Primary button types: `"button"`, `"github"`, `"discord"`. + +## Footer + +```json +"footer": { + "socials": { + "x": "https://x.com/example", + "github": "https://github.com/example", + "linkedin": "https://linkedin.com/company/example" + }, + "links": [ + { + "header": "Resources", + "items": [ + { "label": "Blog", "href": "https://example.com/blog" } + ] + } + ] +} +``` + +Valid social keys: `x`, `website`, `facebook`, `youtube`, `discord`, `slack`, `github`, `linkedin`, `instagram`, `hacker-news`, `medium`, `telegram`, `bluesky`, `threads`, `reddit`, `podcast`. + +## Banner + +```json +"banner": { + "content": "Version 2.0 is live! [Learn more](/changelog)", + "dismissible": true, + "type": "info", + "color": { + "light": "#7C3AED", + "dark": "#5B21B6" + } +} +``` + +- `content` (required): Supports basic Markdown (links, bold, italic). Custom components are not supported. +- `dismissible`: Show a close button. Stays hidden for a user until content changes. Default: `false`. +- `type`: Background style. `"info"` (primary color, default), `"warning"` (amber), `"critical"` (red). +- `color`: Custom background hex. Overrides `type`. Object with `light` and `dark` keys, or a single hex string. Banner text is white — choose a dark enough background. + +Language-specific banners can be set inside the `navigation.languages` entries. + +## Variables + +Global content variables substituted at build time using `{{variableName}}` syntax in MDX files. + +```json +"variables": { + "apiVersion": "v2", + "baseUrl": "https://api.example.com" +} +``` + +Keys must be alphanumeric with hyphens only. Values are plain strings. Use in any `.mdx` file: + +```mdx +The current API version is {{apiVersion}}. +``` + +## Redirects + +```json +"redirects": [ + { + "source": "/old-page", + "destination": "/new-page", + "permanent": true + } +] +``` + +## Metadata + +```json +"metadata": { + "timestamp": true +} +``` + +Shows "Last modified on [date]" on all pages. Override per-page with `timestamp` frontmatter. + +## Interaction + +```json +"interaction": { + "drilldown": false +} +``` + +Controls whether clicking a navigation group navigates to its first page (`true`) or only expands/collapses (`false`). + +## SEO + +```json +"seo": { + "metatags": { + "canonical": "https://docs.example.com", + "og:locale": "en_US" + }, + "indexing": "navigable" +} +``` + +- `indexing`: `"navigable"` (only nav pages) or `"all"` (every page including hidden). + +## Search + +```json +"search": { + "prompt": "Search documentation..." +} +``` + +## Contextual menu + +```json +"contextual": { + "options": ["copy", "chatgpt", "claude", "cursor", "vscode"], + "display": "header" +} +``` + +- `options` (required): First item is the default action. Built-in values: `"assistant"`, `"copy"`, `"view"`, `"chatgpt"`, `"claude"`, `"perplexity"`, `"grok"`, `"aistudio"`, `"devin"`, `"windsurf"`, `"mcp"`, `"add-mcp"`, `"cursor"`, `"vscode"`, `"devin-mcp"`. Custom objects accepted with `title`, `description`, `icon`, and `href` fields. +- `display`: Where to show the menu. `"header"` (default) or `"toc"`. + +## Thumbnails + +```json +"thumbnails": { + "appearance": "light", + "background": "/images/thumbnail-bg.svg", + "fonts": { + "family": "Inter" + } +} +``` + +## Error handling + +```json +"errors": { + "404": { + "redirect": true, + "title": "Page not found", + "description": "This page doesn't exist." + } +} +``` + +## API configuration + +```json +"api": { + "openapi": "openapi.json", + "playground": { + "display": "interactive", + "proxy": true + }, + "examples": { + "languages": ["bash", "javascript", "python"], + "defaults": "all", + "prefill": false, + "autogenerate": true + }, + "mdx": { + "server": "https://api.example.com", + "auth": { + "method": "bearer" + } + } +} +``` + +- `openapi`: Single file, array, or object with `source` and `directory`. +- `asyncapi`: Same format as `openapi` for AsyncAPI specs. +- `playground.display`: `"interactive"`, `"simple"`, `"none"`, or `"auth"`. +- `playground.proxy`: Route requests through Mintlify's proxy. Default: `true`. +- `playground.credentials`: Include cookies and auth headers for cross-origin requests when proxy is `false`. Default: `false`. +- `params.expanded`: Expand all parameters by default. `"all"` or `"closed"` (default). +- `params.post`: OpenAPI schema field keys to surface as pills next to parameter names. +- `url`: Set to `"full"` to always show the full base URL (default: only shown when multiple base URLs exist). +- `examples.languages`: `bash`, `go`, `java`, `javascript`, `node`, `php`, `powershell`, `python`, `ruby`, `swift`. +- `examples.defaults`: `"required"` or `"all"` (include optional params). +- `examples.prefill`: Pre-fill playground fields with spec example values. Default: `false`. +- `examples.autogenerate`: Generate code samples from API specs. Default: `true`. +- `mdx.auth.method`: `"bearer"`, `"basic"`, `"key"`, `"cobo"`. + +## Integrations + +```json +"integrations": { + "ga4": { "measurementId": "G-XXXXXXXXXX" }, + "gtm": { "tagId": "GTM-XXXXX" }, + "posthog": { "apiKey": "phc_xxx", "apiHost": "https://app.posthog.com" }, + "amplitude": { "apiKey": "xxx" }, + "mixpanel": { "projectToken": "xxx" }, + "segment": { "key": "xxx" }, + "clarity": { "projectId": "xxx" }, + "fathom": { "siteId": "xxx" }, + "hotjar": { "hjid": "xxx", "hjsv": "xxx" }, + "logrocket": { "appId": "xxx" }, + "heap": { "appId": "xxx" }, + "pirsch": { "id": "xxx" }, + "plausible": { "domain": "xxx", "server": "optional" }, + "hightouch": { "writeKey": "xxx", "apiHost": "optional" }, + "clearbit": { "publicApiKey": "xxx" }, + "intercom": { "appId": "xxx" }, + "frontchat": { "snippetId": "xxx" }, + "telemetry": { "enabled": true }, + "cookies": { "key": "consent_key", "value": "accepted" } +} +``` + +## Reusable snippets + +Store reusable content in the `/snippets/` directory. + +### MDX snippets + +```mdx + +Before you begin, make sure you have: +- Node.js 18+ +- A Mintlify account +``` + +Import in any page: + +```mdx +import Prerequisites from "/snippets/prerequisites.mdx"; + + +``` + +### JSX components + +```jsx +// snippets/counter.jsx +export const Counter = () => { + const [count, setCount] = useState(0); + return ( +
+ + {count} + +
+ ); +}; +``` + +Import in any page using the root-relative path to the file: + +```mdx +import { Counter } from "/snippets/counter.jsx"; + + +``` + +JSX components can live in any directory, not just `/snippets/`. Nested imports between snippet files are not supported. + +## Hidden pages + +Set `hidden: true` in frontmatter to remove from sidebar. Page remains accessible by URL. + +```yaml +--- +title: "Internal reference" +hidden: true +--- +``` + +Or omit the page from `docs.json` navigation entirely. + +## .mintignore + +Exclude files completely from the published docs. Place `.mintignore` in the docs root. Uses `.gitignore` syntax. + +``` +drafts/ +*.draft.mdx +private-notes.md +**/internal/** +!important.mdx +``` + +Files in `.mintignore` are not published, not indexed, and not accessible by URL. + +## Custom CSS and JavaScript + +### CSS + +Add `.css` files to your repository. Class names become available in all MDX files. + +```css +/* styles.css */ +#navbar { + background: #fffff2; +} +``` + +Built-in Tailwind CSS v3 classes are available. Arbitrary values (e.g., `w-[350px]`) are not supported — use inline `style` instead. + +### JavaScript + +Any `.js` file in the content directory is included globally on all pages. diff --git a/agent-context/context/skills/mintlify/reference/navigation.md b/agent-context/context/skills/mintlify/reference/navigation.md new file mode 100644 index 0000000000..ff44a1a236 --- /dev/null +++ b/agent-context/context/skills/mintlify/reference/navigation.md @@ -0,0 +1,352 @@ +# Navigation reference + +All navigation patterns for the `navigation` property in `docs.json`. + +## Pages + +Flat list of pages with no grouping. + +```json +{ + "navigation": { + "pages": ["index", "quickstart", "guides/example"] + } +} +``` + +## Groups + +```json +{ + "navigation": { + "groups": [ + { + "group": "Getting started", + "icon": "rocket", + "pages": ["index", "quickstart"] + }, + { + "group": "Guides", + "icon": "book-open", + "tag": "NEW", + "pages": [ + "guides/overview", + { + "group": "Advanced", + "expanded": false, + "pages": ["guides/advanced/config", "guides/advanced/deploy"] + } + ] + } + ] + } +} +``` + +Group properties: +- `group` (required): Section title. +- `pages` (required): Array of page paths or nested groups. +- `icon`: Icon name. +- `tag`: Label displayed next to group name. +- `root`: Page that opens when clicking the group title. +- `expanded`: Default open state for nested groups (`true`/`false`). Top-level groups are always expanded. +- `directory`: When the group has a `root` page, render a listing of child pages below the root page content. Values: `"none"` (default), `"accordion"` (collapsible list), `"card"` (horizontal cards). Inherits recursively; descendants can override. +- `boost`: Numeric multiplier for in-product search ranking of every page in the group. Use values `> 1` to prioritize, `0–1` to de-prioritize. + +## Tabs + +```json +{ + "navigation": { + "tabs": [ + { + "tab": "Documentation", + "icon": "book-open", + "groups": [ + { + "group": "Getting started", + "pages": ["index", "quickstart"] + } + ] + }, + { + "tab": "API reference", + "icon": "square-terminal", + "pages": ["api/overview", "api/endpoints"] + }, + { + "tab": "Blog", + "icon": "newspaper", + "href": "https://example.com/blog" + } + ] + } +} +``` + +### Menus (within tabs) + +```json +{ + "tab": "Developer tools", + "menu": [ + { + "item": "API reference", + "icon": "rocket", + "groups": [ + { + "group": "Endpoints", + "pages": ["api/get", "api/post"] + } + ] + }, + { + "item": "SDKs", + "icon": "code", + "description": "Client libraries", + "pages": ["sdk/javascript", "sdk/python"] + } + ] +} +``` + +## Anchors + +```json +{ + "navigation": { + "anchors": [ + { + "anchor": "Documentation", + "icon": "book-open", + "groups": [ + { + "group": "Getting started", + "pages": ["quickstart", "tutorial"] + } + ] + }, + { + "anchor": "Blog", + "href": "https://example.com/blog" + } + ] + } +} +``` + +### Global anchors + +Appear on all pages regardless of active section: + +```json +{ + "navigation": { + "global": { + "anchors": [ + { + "anchor": "Changelog", + "icon": "list", + "href": "/changelog" + } + ] + }, + "tabs": [...] + } +} +``` + +## Global navigation + +`navigation.global` supports tabs, anchors, dropdowns, languages, versions, and products that appear on all pages regardless of active section. Useful for persistent switchers and cross-cutting links. + +```json +{ + "navigation": { + "global": { + "tabs": [ + { "tab": "API", "href": "/api-reference", "icon": "square-terminal" } + ], + "anchors": [ + { "anchor": "Changelog", "icon": "list", "href": "/changelog" } + ], + "languages": [ + { "language": "en", "default": true }, + { "language": "es" } + ], + "versions": [ + { "version": "v2", "default": true }, + { "version": "v1" } + ], + "products": [ + { "product": "Core API", "icon": "server" }, + { "product": "Mobile SDK", "icon": "smartphone" } + ] + } + } +} +``` + +Global element properties: +- `global.tabs`: Each entry requires `tab` (string) and `href`. Optional: `icon`, `iconType`, `hidden`. +- `global.anchors`: Each entry requires `anchor` (string) and `href`. Optional: `icon`, `iconType`, `color.light`, `color.dark`, `hidden`. +- `global.dropdowns`: Each entry requires `dropdown` (string) and `href`. Optional: `icon`, `iconType`, `hidden`. +- `global.languages`: Each entry requires `language` (code string). Optional: `default`, `hidden`, `href`. +- `global.versions`: Each entry requires `version` (string). Optional: `default`, `hidden`, `href`. +- `global.products`: Each entry requires `product` (string). Optional: `description`, `icon`, `iconType`. + +## Dropdowns + +```json +{ + "navigation": { + "dropdowns": [ + { + "dropdown": "Documentation", + "icon": "book-open", + "groups": [ + { + "group": "Getting started", + "pages": ["index", "quickstart"] + } + ] + }, + { + "dropdown": "API reference", + "icon": "square-terminal", + "pages": ["api/overview"] + } + ] + } +} +``` + +## Products + +```json +{ + "navigation": { + "products": [ + { + "product": "Core API", + "description": "Core API documentation", + "icon": "server", + "tabs": [ + { + "tab": "Documentation", + "groups": [ + { "group": "Getting started", "pages": ["core/quickstart"] } + ] + } + ] + }, + { + "product": "Mobile SDK", + "icon": "smartphone", + "pages": ["mobile/overview"] + } + ] + } +} +``` + +## Versions + +```json +{ + "navigation": { + "versions": [ + { + "version": "2.0.0", + "default": true, + "tag": "Latest", + "groups": [ + { "group": "Getting started", "pages": ["v2/overview", "v2/quickstart"] } + ] + }, + { + "version": "1.0.0", + "tag": "Deprecated", + "groups": [ + { "group": "Getting started", "pages": ["v1/overview", "v1/quickstart"] } + ] + } + ] + } +} +``` + +Version properties: +- `version` (required): Version label shown in the selector. +- `default`: Set `true` to make this the default version (otherwise the first entry is the default). +- `tag`: Badge label displayed in the version selector dropdown (e.g., `"Latest"`, `"Recommended"`, `"Beta"`). + +## Languages + +```json +{ + "navigation": { + "languages": [ + { + "language": "en", + "groups": [ + { "group": "Getting started", "pages": ["en/overview", "en/quickstart"] } + ] + }, + { + "language": "es", + "groups": [ + { "group": "Comenzando", "pages": ["es/overview", "es/quickstart"] } + ] + } + ] + } +} +``` + +Each language entry can include its own `banner`, `footer`, and `navbar` configuration overrides. + +## OpenAPI in navigation + +```json +{ + "navigation": { + "groups": [ + { + "group": "API reference", + "openapi": "/path/to/openapi.json", + "pages": [ + "overview", + "GET /users", + "POST /users", + { + "group": "Products", + "openapi": "/path/to/openapi-v2.json", + "pages": ["GET /products", "POST /products"] + } + ] + } + ] + } +} +``` + +When you add `openapi` to a navigation element without specifying pages, Mintlify auto-generates pages for all endpoints. + +## Choosing a navigation pattern + +| Pattern | When to use | +|---------|-------------| +| Groups | Default. Single audience, straightforward hierarchy. | +| Tabs | Distinct sections with different audiences or content types. | +| Anchors | Persistent section links at sidebar top. | +| Dropdowns | Multiple sections users switch between. | +| Products | Multi-product company with separate docs per product. | +| Versions | Multiple API/product versions. | +| Languages | Localized content. | + +Navigation elements can nest within each other. Common combinations: +- Tabs containing groups +- Products containing tabs +- Versions containing tabs +- Anchors containing groups diff --git a/agent-context/context/skills/mintlify/reference/site-discovery.md b/agent-context/context/skills/mintlify/reference/site-discovery.md new file mode 100644 index 0000000000..bac809a625 --- /dev/null +++ b/agent-context/context/skills/mintlify/reference/site-discovery.md @@ -0,0 +1,29 @@ +# Product discovery for new documentation sites + +Use this workflow when creating a new site or replacing substantial placeholder content. Skip it for targeted edits to an established site. + +## Build a product brief + +Inspect the repository, supplied URLs, existing pages, and attachments first. Determine what they already establish about: + +- What the product helps people accomplish +- Who the primary documentation reader is and what brings them to the docs +- The first 1–3 tasks that reader must complete +- Why the product was built or chosen over the current approach + +Ask one round of up to four questions for important gaps that only the user can answer. Make each question specific to the source material. When the interface supports choices, suggest 2–4 plausible answers derived from the sources and allow a custom answer. + +Do not ask about facts you can verify yourself. Infer presentation choices such as theme, page grouping, and component usage unless choosing incorrectly would waste substantial work. + +If the user does not answer, state or record reasonable assumptions and continue. Do not repeat the questions later in generation. + +## Use the brief + +Synthesize answers and verified facts into a concise internal brief: + +- `description`: the outcome the product creates +- `primaryAudience`: the main reader and their context +- `jobsToBeDone`: the critical tasks the docs must enable +- `motivation`: the problem, differentiation, or reason the product exists + +Use the brief to prioritize the homepage, introduction, quickstart, navigation, and examples. Preserve the user's terminology. Do not copy the brief mechanically onto every page. diff --git a/agent-context/package.json b/agent-context/package.json new file mode 100644 index 0000000000..eda1e3bb5a --- /dev/null +++ b/agent-context/package.json @@ -0,0 +1,15 @@ +{ + "name": "@mintlify/agent-context", + "version": "0.1.0", + "private": true, + "type": "module", + "engines": { + "node": ">=22" + }, + "scripts": { + "build": "node scripts/build.mjs", + "check": "node scripts/check.mjs", + "status": "node scripts/status.mjs", + "test": "node --test" + } +} diff --git a/agent-context/scripts/build.mjs b/agent-context/scripts/build.mjs new file mode 100644 index 0000000000..a0fb9ce03b --- /dev/null +++ b/agent-context/scripts/build.mjs @@ -0,0 +1,12 @@ +import path from 'node:path'; +import { buildAll, repositoryRoot } from './lib.mjs'; + +const selectedIds = process.argv.slice(2); +const results = await buildAll({ + outputRoot: path.join(repositoryRoot, 'dist'), + selectedIds, +}); + +for (const { provenance } of results) { + console.log(`${provenance.target}: ${provenance.sourceCommit}`); +} diff --git a/agent-context/scripts/check.mjs b/agent-context/scripts/check.mjs new file mode 100644 index 0000000000..d6fa77974b --- /dev/null +++ b/agent-context/scripts/check.mjs @@ -0,0 +1,36 @@ +import assert from 'node:assert/strict'; +import { mkdtemp, readFile, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { buildAll } from './lib.mjs'; + +const outputRoot = await mkdtemp(path.join(tmpdir(), 'mintlify-agent-context-')); + +try { + const results = await buildAll({ outputRoot }); + assert.equal(results.length, 3); + + const sharedFiles = [ + 'api-docs.md', + 'cli.md', + 'components.md', + 'configuration.md', + 'navigation.md', + 'site-discovery.md', + ]; + for (const file of sharedFiles) { + const contents = await Promise.all( + results.map(({ provenance }) => + readFile( + path.join(outputRoot, provenance.target, 'skills', 'mintlify', 'reference', file), + 'utf8', + ), + ), + ); + assert.ok(contents.every((content) => content === contents[0]), `${file} drifted`); + } + + console.log('All generated targets are valid and shared references are identical.'); +} finally { + await rm(outputRoot, { recursive: true, force: true }); +} diff --git a/agent-context/scripts/lib.mjs b/agent-context/scripts/lib.mjs new file mode 100644 index 0000000000..8bcd2a8e6f --- /dev/null +++ b/agent-context/scripts/lib.mjs @@ -0,0 +1,154 @@ +import { execFileSync } from 'node:child_process'; +import { cp, mkdir, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const scriptsDirectory = path.dirname(fileURLToPath(import.meta.url)); +export const repositoryRoot = path.resolve(scriptsDirectory, '..'); + +const contextDirectory = path.join(repositoryRoot, 'context', 'skills', 'mintlify'); +const mcpServersPath = path.join(repositoryRoot, 'context', 'mcp-servers.json'); +const targetsDirectory = path.join(repositoryRoot, 'targets'); + +export async function loadTargets(selectedIds = []) { + const entries = (await readdir(targetsDirectory)) + .filter((entry) => entry.endsWith('.json')) + .sort(); + const targets = await Promise.all( + entries.map(async (entry) => + JSON.parse(await readFile(path.join(targetsDirectory, entry), 'utf8')), + ), + ); + + for (const target of targets) { + if ( + typeof target.id !== 'string' || + typeof target.repository !== 'string' || + !['.mcp.json', 'mcp.json'].includes(target.mcpConfigFile) || + !['mcp_servers', 'mcpServers'].includes(target.mcpConfigKey) + ) { + throw new Error(`Invalid target configuration: ${JSON.stringify(target)}`); + } + } + + const ids = new Set(targets.map((target) => target.id)); + for (const id of selectedIds) { + if (!ids.has(id)) { + throw new Error(`Unknown target: ${id}`); + } + } + + return selectedIds.length === 0 + ? targets + : targets.filter((target) => selectedIds.includes(target.id)); +} + +function markGenerated(skill) { + const frontmatterEnd = skill.indexOf('\n---\n', 4); + if (frontmatterEnd === -1) { + throw new Error('SKILL.md frontmatter is not closed'); + } + + const insertionPoint = frontmatterEnd + '\n---\n'.length; + return `${skill.slice(0, insertionPoint)}\n\n${skill.slice(insertionPoint)}`; +} + +export function sourceCommit() { + if (process.env.GITHUB_SHA) { + return process.env.GITHUB_SHA; + } + + try { + const changes = execFileSync('git', ['status', '--porcelain', '--', '.'], { + cwd: repositoryRoot, + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'ignore'], + }).trim(); + if (changes) { + return 'working-tree'; + } + + return execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: repositoryRoot, + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'ignore'], + }).trim(); + } catch { + return 'working-tree'; + } +} + +function validateSkill(skill, target) { + if (!skill.startsWith('---\n')) { + throw new Error(`${target.id}: SKILL.md must start with YAML frontmatter`); + } + if (!/^name: mintlify$/m.test(skill) || !/^description: .+$/m.test(skill)) { + throw new Error(`${target.id}: SKILL.md requires name and description fields`); + } + if (/mint analytics/.test(skill)) { + throw new Error(`${target.id}: SKILL.md contains retired CLI commands`); + } +} + +export async function buildTarget(target, outputRoot) { + const targetRoot = path.join(outputRoot, target.id); + const skillOutput = path.join(targetRoot, 'skills', 'mintlify'); + await rm(targetRoot, { recursive: true, force: true }); + await mkdir(skillOutput, { recursive: true }); + + const skillTemplate = await readFile(path.join(contextDirectory, 'SKILL.md'), 'utf8'); + const skill = markGenerated(skillTemplate); + validateSkill(skill, target); + await writeFile(path.join(skillOutput, 'SKILL.md'), skill); + await cp(path.join(contextDirectory, 'reference'), path.join(skillOutput, 'reference'), { + recursive: true, + }); + + const mcpServers = JSON.parse(await readFile(mcpServersPath, 'utf8')); + const mcpConfig = { [target.mcpConfigKey]: mcpServers }; + await writeFile( + path.join(targetRoot, target.mcpConfigFile), + `${JSON.stringify(mcpConfig, null, 2)}\n`, + ); + + const provenance = { + schemaVersion: 1, + sourceRepository: 'mintlify/docs', + sourcePath: 'agent-context', + sourceCommit: sourceCommit(), + target: target.id, + }; + await writeFile( + path.join(targetRoot, '.mintlify-agent-context.json'), + `${JSON.stringify(provenance, null, 2)}\n`, + ); + + return { targetRoot, provenance }; +} + +export async function buildAll({ outputRoot, selectedIds = [] } = {}) { + const resolvedOutput = outputRoot ?? path.join(repositoryRoot, 'dist'); + await mkdir(resolvedOutput, { recursive: true }); + const targets = await loadTargets(selectedIds); + return Promise.all(targets.map((target) => buildTarget(target, resolvedOutput))); +} + +export async function copyTargetToRepository(targetId, destination, outputRoot) { + const [target] = await loadTargets([targetId]); + const sourceRoot = path.join(outputRoot, targetId); + const sourceSkill = path.join(sourceRoot, 'skills', 'mintlify'); + const destinationSkill = path.join(destination, 'skills', 'mintlify'); + + await stat(sourceSkill); + await rm(destinationSkill, { recursive: true, force: true }); + await mkdir(path.dirname(destinationSkill), { recursive: true }); + await cp(sourceSkill, destinationSkill, { recursive: true }); + await cp( + path.join(sourceRoot, target.mcpConfigFile), + path.join(destination, target.mcpConfigFile), + ); + await cp( + path.join(sourceRoot, '.mintlify-agent-context.json'), + path.join(destination, '.mintlify-agent-context.json'), + ); +} diff --git a/agent-context/scripts/status.mjs b/agent-context/scripts/status.mjs new file mode 100644 index 0000000000..1f71a8bda6 --- /dev/null +++ b/agent-context/scripts/status.mjs @@ -0,0 +1,37 @@ +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { loadTargets, repositoryRoot, sourceCommit } from './lib.mjs'; + +const workspaceRoot = path.resolve(process.argv[2] ?? path.join(repositoryRoot, '..', '..')); +const targets = await loadTargets(); +const currentSourceCommit = sourceCommit(); +const rows = []; + +for (const target of targets) { + const repositoryName = target.repository.split('/').at(-1); + const pluginRoot = path.join(workspaceRoot, repositoryName); + + try { + const lock = JSON.parse( + await readFile(path.join(pluginRoot, '.mintlify-agent-context.json'), 'utf8'), + ); + rows.push({ + target: target.id, + repository: target.repository, + state: lock.sourceCommit === currentSourceCommit ? 'current' : 'behind', + source: lock.sourceCommit, + }); + } catch { + rows.push({ + target: target.id, + repository: target.repository, + state: 'unavailable', + source: '-', + }); + } +} + +console.table(rows); +if (rows.some((row) => row.state !== 'current')) { + process.exitCode = 1; +} diff --git a/agent-context/scripts/sync-target.mjs b/agent-context/scripts/sync-target.mjs new file mode 100644 index 0000000000..a79ce505a0 --- /dev/null +++ b/agent-context/scripts/sync-target.mjs @@ -0,0 +1,13 @@ +import path from 'node:path'; +import { buildAll, copyTargetToRepository, repositoryRoot } from './lib.mjs'; + +const [targetId, destinationArgument] = process.argv.slice(2); +if (!targetId || !destinationArgument) { + throw new Error('Usage: node scripts/sync-target.mjs '); +} + +const destination = path.resolve(process.cwd(), destinationArgument); +const outputRoot = path.join(repositoryRoot, 'dist'); +await buildAll({ outputRoot, selectedIds: [targetId] }); +await copyTargetToRepository(targetId, destination, outputRoot); +console.log(`Synced ${targetId} context to ${destination}`); diff --git a/agent-context/targets/claude.json b/agent-context/targets/claude.json new file mode 100644 index 0000000000..852b09b3ca --- /dev/null +++ b/agent-context/targets/claude.json @@ -0,0 +1,6 @@ +{ + "id": "claude", + "repository": "mintlify/mintlify-claude-plugin", + "mcpConfigFile": ".mcp.json", + "mcpConfigKey": "mcpServers" +} diff --git a/agent-context/targets/codex.json b/agent-context/targets/codex.json new file mode 100644 index 0000000000..422c70a0c3 --- /dev/null +++ b/agent-context/targets/codex.json @@ -0,0 +1,6 @@ +{ + "id": "codex", + "repository": "mintlify/codex-plugin", + "mcpConfigFile": ".mcp.json", + "mcpConfigKey": "mcp_servers" +} diff --git a/agent-context/targets/cursor.json b/agent-context/targets/cursor.json new file mode 100644 index 0000000000..ca7fca11ee --- /dev/null +++ b/agent-context/targets/cursor.json @@ -0,0 +1,6 @@ +{ + "id": "cursor", + "repository": "mintlify/cursor-plugin", + "mcpConfigFile": "mcp.json", + "mcpConfigKey": "mcpServers" +} diff --git a/agent-context/test/build.test.mjs b/agent-context/test/build.test.mjs new file mode 100644 index 0000000000..af2ed4710d --- /dev/null +++ b/agent-context/test/build.test.mjs @@ -0,0 +1,84 @@ +import assert from 'node:assert/strict'; +import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { buildAll, copyTargetToRepository } from '../scripts/lib.mjs'; + +test('builds all client variants from one canonical skill', async () => { + const outputRoot = await mkdtemp(path.join(tmpdir(), 'mintlify-agent-context-test-')); + + try { + await buildAll({ outputRoot }); + const codex = await readFile( + path.join(outputRoot, 'codex', 'skills', 'mintlify', 'SKILL.md'), + 'utf8', + ); + const cursor = await readFile( + path.join(outputRoot, 'cursor', 'skills', 'mintlify', 'SKILL.md'), + 'utf8', + ); + const claude = await readFile( + path.join(outputRoot, 'claude', 'skills', 'mintlify', 'SKILL.md'), + 'utf8', + ); + const codexMcp = JSON.parse( + await readFile(path.join(outputRoot, 'codex', '.mcp.json'), 'utf8'), + ); + const cursorMcp = JSON.parse( + await readFile(path.join(outputRoot, 'cursor', 'mcp.json'), 'utf8'), + ); + const claudeMcp = JSON.parse( + await readFile(path.join(outputRoot, 'claude', '.mcp.json'), 'utf8'), + ); + + assert.equal(cursor, codex); + assert.equal(claude, codex); + for (const skill of [codex, cursor, claude]) { + assert.match(skill, /Generated from mintlify\/docs\/agent-context/); + assert.match(skill, /### Mintlify Search/); + assert.match(skill, /### Mintlify Admin/); + assert.match(skill, /Complete authentication in the browser when prompted/); + assert.match(skill, /mint automations/); + assert.doesNotMatch(skill, /mint analytics|mint workflow|\{\{/); + } + assert.deepEqual(codexMcp.mcp_servers, cursorMcp.mcpServers); + assert.deepEqual(claudeMcp.mcpServers, cursorMcp.mcpServers); + assert.deepEqual(Object.keys(cursorMcp.mcpServers), [ + 'Mintlify Search', + 'Mintlify Admin', + ]); + } finally { + await rm(outputRoot, { recursive: true, force: true }); + } +}); + +test('sync replaces only generated context paths', async () => { + const root = await mkdtemp(path.join(tmpdir(), 'mintlify-agent-context-sync-test-')); + const outputRoot = path.join(root, 'dist'); + const destination = path.join(root, 'plugin'); + + try { + await mkdir(path.join(destination, 'skills', 'mintlify'), { recursive: true }); + await writeFile(path.join(destination, 'README.md'), 'target-owned\n'); + await writeFile(path.join(destination, 'skills', 'mintlify', 'stale.md'), 'remove me\n'); + await writeFile(path.join(destination, '.mcp.json'), '{"stale":true}\n'); + + await buildAll({ outputRoot, selectedIds: ['codex'] }); + await copyTargetToRepository('codex', destination, outputRoot); + + assert.equal(await readFile(path.join(destination, 'README.md'), 'utf8'), 'target-owned\n'); + await assert.rejects(readFile(path.join(destination, 'skills', 'mintlify', 'stale.md'))); + assert.match( + await readFile(path.join(destination, 'skills', 'mintlify', 'SKILL.md'), 'utf8'), + /### Mintlify Search/, + ); + const mcpConfig = JSON.parse(await readFile(path.join(destination, '.mcp.json'), 'utf8')); + assert.deepEqual(Object.keys(mcpConfig.mcp_servers), [ + 'Mintlify Search', + 'Mintlify Admin', + ]); + } finally { + await rm(root, { recursive: true, force: true }); + } +});