Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/agents/mcp-guide-writer.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Your primary responsibilities:

3. **Ensure Technical Accuracy**: All configuration examples must be valid and tested. Reference the existing ToolHive documentation in the `docs/toolhive/` directory as the source of truth for:
- Available `thv` CLI commands and their syntax (reference: `docs/toolhive/reference/cli/*.md` or run `thv --help`)
- Kubernetes CRD specifications and fields (reference: `static/api-specs/toolhive-crd-api.md`)
- Kubernetes CRD specifications and fields (reference: `static/api-specs/toolhive-crds/*.schema.json`)
- UI configuration options and workflows (reference: `docs/toolhive/guides-ui/*`)

4. **Follow Documentation Standards**: Adhere to the project's writing style guide (`STYLE_GUIDE.md`) including:
Expand Down
21 changes: 11 additions & 10 deletions .claude/skills/upstream-release-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,17 +263,18 @@ Apply the approved changes:

6. **CRD reference updates**: the Kubernetes CRD reference is partially auto-generated. If the release touches CRDs, know the split:

**Fully auto-generated** (do not hand-edit):
- `static/api-specs/crds/*.schema.json` - extracted JSON Schema per CRD
- `static/api-specs/crds/*.example.yaml` - minimal required-fields YAML example
- `static/api-specs/crds/index.json` - metadata + cross-reference graph
- `static/api-specs/crds/sidebar.json` - sidebar fragment consumed by `sidebars.ts`
- `src/components/CRDReference/schemas.ts` - Kind -> schema index imported by the `<CRDFields>` component
- `docs/toolhive/reference/crds/*.mdx` - per-CRD pages (including the landing `index.mdx`)
**Fully auto-generated** (do not hand-edit): the exact paths depend on the project's `crds:` array in `.github/upstream-projects.yaml`. Each entry declares an `out` (static/ schema dir) and `pages` (docs/ MDX dir). For toolhive OSS these are `static/api-specs/toolhive-crds/` and `docs/toolhive/reference/crds/`; for enterprise or gateway CRDs they will differ. Within each pair, the generated files are:
- `<out>/*.schema.json` - extracted JSON Schema per CRD
- `<out>/*.example.yaml` - minimal required-fields YAML example
- `<out>/index.json` - metadata + cross-reference graph
- `<out>/sidebar.json` - sidebar fragment consumed by `sidebars.ts`
- `<pages>/*.mdx` - per-CRD pages (including the landing `index.mdx`)

These come from `scripts/extract-crd-schemas.mjs` + `scripts/generate-crd-pages.mjs`, run by `scripts/update-toolhive-reference.sh`. Regenerating just means re-running the script; do not edit the MDX directly.
Plus one repo-wide generated file spanning all sets: `src/components/CRDReference/all-schemas.ts`, the consolidated Kind -> schema barrel consumed by `<CRDFields>` (emitted by `scripts/generate-crd-barrel.mjs`). Do not hand-edit it.

**Hand-written overrides** (`scripts/lib/crd-intros.mjs`): every CRD in `index.json` publishes automatically using schema-derived defaults. Entries in this file override those defaults to polish a page. All fields are optional:
These come from `scripts/extract-crd-schemas.mjs` + `scripts/generate-crd-pages.mjs` + `scripts/generate-crd-barrel.mjs`, all driven by `scripts/upstream-release/extract-crds.mjs`. Regenerating means re-running: `node scripts/upstream-release/extract-crds.mjs --id <project-id>`. Do not edit the MDX or schema files directly.

**Hand-written overrides** (`scripts/lib/crd-intros.mjs`): every CRD in any project's `index.json` publishes automatically using schema-derived defaults. Entries in this file override those defaults to polish a page. All fields are optional:
- `slug`: URL segment and MDX filename. Default: `Kind.toLowerCase()`.
- `group`: `'core'` or `'shared'`. Default: `'shared'`.
- `summary`: one-sentence DocCard pitch. Default: first sentence of the cleaned upstream schema description.
Expand All @@ -282,7 +283,7 @@ Apply the approved changes:

**When the release adds a new CRD**:
- The release PR auto-publishes the new CRD with schema-derived defaults and flags it in a `[!NOTE]` block. No blocker.
- Review the generated page. If the upstream kubebuilder description is thin or the CRD should live in the `core` group or appear higher on the landing page, add an override entry for that Kind to `crd-intros.mjs` and re-run `node scripts/generate-crd-pages.mjs`. Overridden entries render before defaults-only entries within each group, in the order they are declared in the file.
- Review the generated page. If the upstream kubebuilder description is thin or the CRD should live in the `core` group or appear higher on the landing page, add an override entry for that Kind to `crd-intros.mjs` and re-run `node scripts/upstream-release/extract-crds.mjs --id <project-id>`. Overridden entries render before defaults-only entries within each group, in the order they are declared in the file.
- Commit the intros change plus the regenerated outputs. You can also land this as a follow-up PR after the release PR merges.

**When the release modifies an existing CRD**: the schema/example regenerate automatically. If the CRD has no override entry, the intro prose will track the upstream description automatically. If it does have an override entry, update the `intro` only if the CRD's role materially shifted.
Expand Down
54 changes: 49 additions & 5 deletions .github/upstream-projects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,20 @@
# reacts to those PRs, shallow-clones the upstream, and adds
# source-verified content edits via the upstream-release-docs skill.
#
# For `stacklok/toolhive` specifically, most reference artifacts are
# declared as `assets:` below (synced by sync-assets.mjs) — plus one
# workflow-step in upstream-release-docs.yml that downloads the CRD
# manifests tarball and runs extract-crd-schemas.mjs + generate-crd-
# pages.mjs to produce our opinionated per-CRD MDX pages.
# For projects that ship Kubernetes CRDs, declare a `crds:` array
# alongside `assets:`. Each entry drives one run of extract-crd-schemas.mjs
# + generate-crd-pages.mjs via scripts/upstream-release/extract-crds.mjs.
# Source kinds: `release_asset:` (from the GitHub release tarball) or
# `source:` (directory inside the upstream clone). Required per-entry
# fields: `out` (static/ output dir), `pages` (docs/ MDX output dir).
# Optional: `landing_title`, `landing_description`, `landing_intro` to
# customize the generated landing page.
# This array is the single source of truth for the CRD sets: the remark
# plugin (docusaurus.config.ts), the sidebar fragments (sidebars.ts), and
# the consolidated <CRDFields> schema barrel are all derived from it via
# scripts/lib/crd-sets.mjs, so adding a set is a YAML edit plus a regen.
# Multiple entries per project are supported for suites that ship more
# than one CRD set (e.g. enterprise platform + AI gateway).
#
# You can also edit `version:` by hand (to backfill or reset) and
# dispatch the upstream-release-docs workflow manually in bootstrap
Expand Down Expand Up @@ -66,6 +75,41 @@ projects:
destination: static/api-specs/publisher-provided.schema.json
- release_asset: skill.schema.json
destination: static/api-specs/skill.schema.json
crds:
- release_asset: thv-crds.tar.gz
out: static/api-specs/toolhive-crds
pages: docs/toolhive/reference/crds
landing_title: Kubernetes CRD reference
landing_description: >-
Reference for all ToolHive Kubernetes Operator custom resource
definitions.
landing_intro: >-
The ToolHive operator manages MCP workloads using Kubernetes custom
resources. Each page below documents one resource - its fields,
defaults, validation rules, and a minimal example manifest - and
links to the other resources it references.

- id: stacklok-enterprise-platform
repo: stacklok/stacklok-enterprise-platform
# version: intentionally omitted - no public release cadence yet.
# CRDs are sourced from the local clone via --clone in development
# and will use release_asset: once the platform ships releases.
docs_paths:
- docs/platform
crds:
- source: enterprise/toolhive-enterprise/helm/files/crds
out: static/api-specs/enterprise-crds
pages: docs/platform/reference/crds
landing_title: Platform CRD reference
landing_description: >-
Reference for Stacklok Enterprise authorization custom resource
definitions.
landing_intro: >-
The Stacklok Enterprise platform extends the Kubernetes API with
custom resources for role-based access control and authorization
policy enforcement. Each page below documents one resource - its
fields, defaults, validation rules, and a minimal example manifest
- and links to the other resources it references.

- id: toolhive-studio
repo: stacklok/toolhive-studio
Expand Down
96 changes: 63 additions & 33 deletions .github/workflows/upstream-release-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ name: Upstream Release Docs
# 3. Syncs declared upstream assets into static/ via sync-assets.mjs
# (release-asset downloads, tarball extractions, file-from-clone
# copies — see `assets:` in upstream-projects.yaml)
# 4. For toolhive specifically, downloads the CRD manifests tarball
# and runs extract-crd-schemas.mjs + generate-crd-pages.mjs +
# bundle-upstream-schema.mjs to produce our opinionated reference
# MDX (the CRD tarball and toolhive-core schemas are shipped as
# release assets by stacklok/toolhive#4982)
# 4. For any project that declares a `crds:` key in upstream-projects.yaml,
# runs extract-crds.mjs to drive extract-crd-schemas.mjs +
# generate-crd-pages.mjs for each declared CRD set. Each set writes
# to its own out/pages dirs so multiple CRD sources (OSS operator,
# enterprise platform, AI gateway, etc.) never clobber each other.
# bundle-upstream-schema.mjs also runs here for toolhive specifically.
# 5. Runs two Claude Opus sessions: a generation pass running the
# upstream-release-docs skill, then a fresh-context editorial
# pass running docs-review over the changed files. Both have
Expand Down Expand Up @@ -361,27 +362,28 @@ jobs:
--repo "$REPO" \
--tag "$NEW_TAG"

# toolhive ships CRD manifests as a release asset tarball (see
# stacklok/toolhive#4982). We extract it to a temp dir and run our
# opinionated transforms: extract per-CRD JSON schemas + examples,
# generate MDX reference pages. Bundling the upstream-registry
# schema (resolves the remote MCP-server $refs for our JSON-Schema
# viewer) also runs here.
- name: Extract CRDs + generate reference MDX (toolhive)
if: steps.detect.outputs.id == 'toolhive'
# For any project with a `crds:` key in upstream-projects.yaml, run
# extract-crds.mjs to drive extract-crd-schemas.mjs +
# generate-crd-pages.mjs for each declared CRD set. The script is a
# no-op for projects with no crds: entries, so no `if:` guard is needed.
- name: Extract CRDs + generate reference MDX
env:
PROJECT_ID: ${{ steps.detect.outputs.id }}
CLONE_DIR: ${{ steps.clone.outputs.scratch_dir }}
REPO: ${{ steps.detect.outputs.repo }}
NEW_TAG: ${{ steps.detect.outputs.new_tag }}
run: |
TMP=$(mktemp -d)
gh release download "$NEW_TAG" --repo "$REPO" \
--pattern "thv-crds.tar.gz" --dir "$TMP"
mkdir -p "$TMP/crds"
tar -xzf "$TMP/thv-crds.tar.gz" -C "$TMP/crds"
TOOLHIVE_CRD_DIR="$TMP/crds" node scripts/extract-crd-schemas.mjs
node scripts/generate-crd-pages.mjs
node scripts/bundle-upstream-schema.mjs
rm -rf "$TMP"
node scripts/upstream-release/extract-crds.mjs \
--id "$PROJECT_ID" \
--clone "$CLONE_DIR" \
--repo "$REPO" \
--tag "$NEW_TAG"

# toolhive-specific: bundle the upstream-registry schema to resolve
# remote MCP-server $refs for the JSON-Schema viewer.
- name: Bundle upstream schema (toolhive)
if: steps.detect.outputs.id == 'toolhive'
run: node scripts/bundle-upstream-schema.mjs

# Commit AND PUSH the refreshed reference assets (synced release-
# asset files + regenerated toolhive CRD MDX if applicable) before
Expand Down Expand Up @@ -438,6 +440,22 @@ jobs:
")
echo "docs_paths=$HINTS" >> "$GITHUB_OUTPUT"

# Resolve the CRD pages dirs for this project so the autogen-detect
# step and skill prompts can reference them without hardcoding paths.
# Space-separated; empty string when the project declares no crds:.
- name: Resolve CRD pages dirs
id: crd_pages
env:
PROJECT_ID: ${{ steps.detect.outputs.id }}
run: |
DIRS=$(node -e "
const yaml = require('yaml');
const fs = require('fs');
const p = yaml.parse(fs.readFileSync('.github/upstream-projects.yaml','utf8')).projects.find(x=>x.id===process.env.PROJECT_ID);
console.log((p?.crds ?? []).map(c => c.pages).filter(Boolean).join(' '));
" 2>/dev/null || true)
echo "dirs=$DIRS" >> "$GITHUB_OUTPUT"

# claude-code-action@v1 rejects track_progress: true on
# workflow_dispatch events with "track_progress is only
# supported for events: pull_request, issue_comment, ...".
Expand Down Expand Up @@ -536,8 +554,8 @@ jobs:
${{ steps.clone.outputs.scratch_dir }} instead of
`gh api contents?ref=<tag>` -- it's already at the tag and
doesn't consume API quota. Do not hand-edit auto-generated
reference under docs/toolhive/reference/cli/,
docs/toolhive/reference/crds/, or static/api-specs/ --
reference under static/api-specs/, docs/toolhive/reference/cli/,
or any CRD pages dirs (${{ steps.crd_pages.outputs.dirs }}) --
earlier workflow steps sync those from release assets.

Project dependencies are already installed by an earlier
Expand Down Expand Up @@ -660,9 +678,9 @@ jobs:
new claims; only refine what's already there.

Do NOT re-run /upstream-release-docs. Do NOT touch files
under docs/toolhive/reference/cli/, static/api-specs/,
or docs/toolhive/reference/crds/ — those are
regenerated from release assets and aren't yours to edit.
under static/api-specs/, docs/toolhive/reference/cli/,
or any CRD pages dirs (${{ steps.crd_pages.outputs.dirs }}) --
those are regenerated from release assets and aren't yours to edit.

Do NOT touch GAPS.md, NO_CHANGES.md, or SUMMARY.md at
the repo root if they exist -- they're signal files
Expand Down Expand Up @@ -866,12 +884,20 @@ jobs:
# the staged diff represents skill-introduced changes only.
# The Augment step consumes `touched` directly and composes
# the CAUTION alert itself -- no note block assembled here.
env:
PROJECT_ID: ${{ steps.detect.outputs.id }}
CRD_PAGES_DIRS: ${{ steps.crd_pages.outputs.dirs }}
run: |
git add -A
TOUCHED=$(git diff --cached --name-only -- \
'docs/toolhive/reference/cli/' \
'static/api-specs/' \
'docs/toolhive/reference/crds/' | paste -sd, - || true)
# Always watch: CLI reference (toolhive only) and all static/api-specs/.
# Plus any CRD pages dirs declared in the project's crds: config.
DIFF_ARGS=()
[ "$PROJECT_ID" = "toolhive" ] && DIFF_ARGS+=('docs/toolhive/reference/cli/')
DIFF_ARGS+=('static/api-specs/')
for dir in $CRD_PAGES_DIRS; do
DIFF_ARGS+=("${dir}/")
done
TOUCHED=$(git diff --cached --name-only -- "${DIFF_ARGS[@]}" | paste -sd, - || true)
echo "touched=$TOUCHED" >> "$GITHUB_OUTPUT"

- name: Commit and push
Expand Down Expand Up @@ -997,6 +1023,7 @@ jobs:
GAPS_BLOCK: ${{ steps.signals.outputs.gaps_block }}
SUMMARY_BLOCK: ${{ steps.signals.outputs.summary_block }}
AUTOGEN_TOUCHED: ${{ steps.autogen.outputs.touched }}
CRD_PAGES_DIRS: ${{ steps.crd_pages.outputs.dirs }}
COMPARE_OK: ${{ steps.reviewers.outputs.compare_ok }}
MENTION_BLOCK: ${{ steps.reviewers.outputs.mention_block }}
ASSIGN_LIST: ${{ steps.reviewers.outputs.list }}
Expand Down Expand Up @@ -1235,9 +1262,12 @@ jobs:
echo "auto-fixes are applied after."
echo ""
echo "Auto-synced paths — do not hand-edit these in review:"
echo "- \`docs/toolhive/reference/cli/\`"
echo "- \`docs/toolhive/reference/crds/\`"
echo "- \`static/api-specs/\`"
echo "- \`docs/toolhive/reference/cli/\` (toolhive only)"
# Emit one bullet per CRD pages dir declared in the project config.
for dir in $CRD_PAGES_DIRS; do
echo "- \`${dir}/\`"
done
echo ""
echo "If a \"Gaps needing human context\" section is present above,"
echo "each entry includes a paste-ready **Helper prompt for local"
Expand Down
7 changes: 6 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ ALWAYS use these exact terms and capitalizations. When editing documentation, re
- large language model (LLM)
- Visual Studio Code ("VS Code" after first use)
- Virtual MCP Server (vMCP) - a feature of ToolHive that aggregates multiple MCP servers into a single endpoint; use "Virtual MCP Server (vMCP)" on first use, "vMCP" thereafter
- Stacklok Enterprise - the commercial, enterprise-licensed distribution of ToolHive, adding turnkey IdP integration, centralized policy enforcement, hardened and signed releases, and SLA-backed support
- Stacklok Desktop - the enterprise edition of the ToolHive desktop app, with enterprise lockdown policies controlled by the Enterprise Manager (not "Enterprise UI", "Enterprise Studio", or "Stacklok UI")
- Enterprise Manager - the Stacklok Enterprise component that pushes policy configuration to Stacklok Desktop and the Stacklok CLI
- Enterprise Cloud UI - the Stacklok Enterprise web console for browsing and managing the MCP server catalog
- enterprise authorization - the Stacklok Enterprise capability that compiles RBAC-style custom resources (roles, bindings, and per-server attachment policies) into the Cedar policies ToolHive enforces. It is a feature, not a named component: write it lowercase, capitalizing only at the start of a sentence, heading, or title. Don't treat it as a proper noun like the Enterprise Manager.

If you encounter a term not listed here that appears frequently in the documentation, consider adding it to this list for consistency.

Expand Down Expand Up @@ -299,7 +304,7 @@ Stacklok Enterprise includes turnkey integrations for common identity providers.
```ts title="sidebars.ts"
{
type: 'doc',
id: 'toolhive/guides-enterprise/config-server',
id: 'platform/enterprise-manager/index',
className: 'enterprise-only',
}
```
Loading