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
131 changes: 33 additions & 98 deletions .claude/skills/test-docs/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,29 @@
---
name: test-docs
description: >
Test ToolHive documentation by executing the steps in tutorials and guides
against a real environment, verifying that examples are correct and ToolHive
has not regressed. Use when the user asks to test, validate, or verify
documentation such as: "test the vault integration tutorial",
"verify the K8s quickstart", "check the CLI install docs",
"test toolhive vault integration in kubernetes", or any request to run
through a doc's instructions to confirm they work. Supports both
Kubernetes-based docs (tutorials, K8s guides) and CLI-based docs.
Test ToolHive documentation by executing the steps in tutorials and guides against a real environment, verifying that examples are correct and ToolHive has not regressed. Use when the user asks to test, validate, or verify documentation such as: "test the vault integration tutorial", "verify the K8s quickstart", "check the CLI install docs", "test toolhive vault integration in kubernetes", or any request to run through a doc's instructions to confirm they work. Supports both Kubernetes-based docs (tutorials, K8s guides) and CLI-based docs.
---

# Test Docs

Test ToolHive documentation by running each step against a live environment,
reporting pass/fail with evidence, and recommending fixes for failures.
Test ToolHive documentation by running each step against a live environment, reporting pass/fail with evidence, and recommending fixes for failures.

## Workflow

1. **Find the documentation** - launch an Explore agent to locate the
relevant doc file
2. **Read and parse** - extract testable steps (bash code blocks, YAML
manifests, expected outputs)
3. **Check prerequisites** - run `scripts/check-prereqs.sh`; confirm the
`thv` version with the user
4. **Prepare the environment** - create a dedicated test namespace unless
the doc specifies otherwise
1. **Find the documentation** - launch an Explore agent to locate the relevant doc file
2. **Read and parse** - extract testable steps (bash code blocks, YAML manifests, expected outputs)
3. **Check prerequisites** - run `scripts/check-prereqs.sh`; confirm the `thv` version with the user
4. **Prepare the environment** - create a dedicated test namespace unless the doc specifies otherwise
5. **Execute steps** - run each step sequentially, capture output
6. **Report results** - pass/fail per step with evidence
7. **Clean up** - delete all resources created during testing
8. **Recommend fixes** - classify failures as doc issues or ToolHive bugs

## Step 1: Find the documentation

If the user provides a **file path** to the doc, use it directly. Assume
you are running in the repository that contains the file.
If the user provides a **file path** to the doc, use it directly. Assume you are running in the repository that contains the file.

Otherwise, use the Task tool with `subagent_type=Explore` to search the
docs directory for the page matching the user's request. Documentation
lives under:
Otherwise, use the Task tool with `subagent_type=Explore` to search the docs directory for the page matching the user's request. Documentation lives under:

- `docs/toolhive/tutorials/` - step-by-step tutorials
- `docs/toolhive/guides-cli/` - CLI how-to guides
Expand All @@ -47,18 +32,15 @@ lives under:
- `docs/toolhive/guides-vmcp/` - Virtual MCP Server guides
- `docs/toolhive/guides-registry/` - registry guides

All doc files use the `.mdx` extension. Search by keywords from the user's
request. If multiple docs match, ask the user which one to test.
All doc files use the `.mdx` extension. Search by keywords from the user's request. If multiple docs match, ask the user which one to test.

## Step 2: Read and parse the doc

Read the full doc file. Extract an ordered list of **testable steps**:

- **Bash code blocks** (`\`\`\`bash`) - commands to execute
- **YAML code blocks** with `title="*.yaml"` - manifests to apply with
`kubectl apply`
- **Expected outputs** - text code blocks (`\`\`\`text`) that follow a
command, or prose describing expected behavior ("You should see...")
- **YAML code blocks** with `title="*.yaml"` - manifests to apply with `kubectl apply`
- **Expected outputs** - text code blocks (`\`\`\`text`) that follow a command, or prose describing expected behavior ("You should see...")

Build a test plan: a numbered list of steps, each with:

Expand All @@ -70,11 +52,7 @@ Present the test plan to the user for approval before executing.

### Handling placeholders

Docs often contain placeholder values like `ghp_your_github_token_here` or
`your-org`. Before executing, scan for obvious placeholders (ALL_CAPS
patterns, "your-\*", "example-\*", "replace-\*") and ask the user for real
values. If a step requires a secret that the user cannot provide, mark it
as **skipped** with a note explaining why.
Docs often contain placeholder values like `ghp_your_github_token_here` or `your-org`. Before executing, scan for obvious placeholders (ALL_CAPS patterns, "your-\*", "example-\*", "replace-\*") and ask the user for real values. If a step requires a secret that the user cannot provide, mark it as **skipped** with a note explaining why.

## Step 3: Check prerequisites

Expand All @@ -86,36 +64,21 @@ bash <skill-path>/scripts/check-prereqs.sh

Where `<skill-path>` is the absolute path to this skill's directory.

If the script reports errors, inform the user and stop. For K8s docs, the
script checks for a kind cluster named "toolhive". For CLI docs, confirm
with the user that the installed `thv` version matches what the doc expects.
If the script reports errors, inform the user and stop. For K8s docs, the script checks for a kind cluster named "toolhive". For CLI docs, confirm with the user that the installed `thv` version matches what the doc expects.

## Step 4: Prepare the environment

For Kubernetes docs, ask the user about existing infrastructure before
deploying anything:
For Kubernetes docs, ask the user about existing infrastructure before deploying anything:

- **Operator CRDs and operator**: if the doc includes steps to install
CRDs or the ToolHive operator, ask the user whether these are already
installed. If so, skip those installation steps and proceed to the
doc-specific content. Use `AskUserQuestion` with options like
"Already installed", "Install fresh", "Reinstall (upgrade)".
- **Namespaces**: create a dedicated namespace `test-docs-<timestamp>`
(e.g., `test-docs-1706886400`) unless the doc explicitly uses a
specific namespace (like `toolhive-system`). If the doc requires
`toolhive-system`, use it but track all resources created for cleanup.
- **Operator CRDs and operator**: if the doc includes steps to install CRDs or the ToolHive operator, ask the user whether these are already installed. If so, skip those installation steps and proceed to the doc-specific content. Use `AskUserQuestion` with options like "Already installed", "Install fresh", "Reinstall (upgrade)".
- **Namespaces**: create a dedicated namespace `test-docs-<timestamp>` (e.g., `test-docs-1706886400`) unless the doc explicitly uses a specific namespace (like `toolhive-system`). If the doc requires `toolhive-system`, use it but track all resources created for cleanup.

For CLI docs:

- Use a temporary directory for any files created
- Note the state of running MCP servers before testing (`thv list`)
- **Use unique server names**: when running `thv run <server>`, always use
`--name <server>-test` to avoid conflicts with existing servers. The
default name is derived from the registry entry, which may already be
running. Example: `thv run --name osv-test osv`
- **Verify registry configuration**: if a registry server isn't found,
confirm with the user that they're using the default registry (not a
custom registry configuration)
- **Use unique server names**: when running `thv run <server>`, always use `--name <server>-test` to avoid conflicts with existing servers. The default name is derived from the registry entry, which may already be running. Example: `thv run --name osv-test osv`
- **Verify registry configuration**: if a registry server isn't found, confirm with the user that they're using the default registry (not a custom registry configuration)

## Step 5: Execute steps

Expand All @@ -129,37 +92,17 @@ Run each step sequentially. For each step:

### Execution rules

- **Wait for readiness**: when a step deploys resources, wait for them
(e.g., `kubectl wait --for=condition=ready`) before proceeding. If the
doc includes a wait command, use it. Otherwise add a reasonable wait
(up to 120s for pods).
- **Variable propagation**: some steps set shell variables used by later
steps (e.g., `VAULT_POD=$(kubectl get pods ...)`). Maintain these
across steps by running in the same shell session.
- **Skip non-testable steps**: informational code blocks (showing file
contents, expected output) are not commands to run. Use them as
verification targets instead.
- **Timeout**: if any command hangs for more than 5 minutes, kill it and
mark the step as failed with a timeout note.
- **Wait for readiness**: when a step deploys resources, wait for them (e.g., `kubectl wait --for=condition=ready`) before proceeding. If the doc includes a wait command, use it. Otherwise add a reasonable wait (up to 120s for pods).
- **Variable propagation**: some steps set shell variables used by later steps (e.g., `VAULT_POD=$(kubectl get pods ...)`). Maintain these across steps by running in the same shell session.
- **Skip non-testable steps**: informational code blocks (showing file contents, expected output) are not commands to run. Use them as verification targets instead.
- **Timeout**: if any command hangs for more than 5 minutes, kill it and mark the step as failed with a timeout note.

### Known pitfalls

- **Server name conflicts**: `thv run <server>` uses the registry entry
name by default, which may already exist. Always use
`thv run --name <server>-test <server>` to create a uniquely-named
instance. This avoids "workload with name already exists" errors.
- **Port-forward needs time**: when testing via `kubectl port-forward`,
wait at least 5 seconds before issuing `curl`. Start the port-forward
in the background, sleep 5, then curl. Kill the port-forward PID
after the check.
- **MCPServer status field**: the MCPServer CRD uses `.status.phase`
(not `.status.state`) for the running state. When polling for
readiness, use:
`kubectl get mcpservers <name> -n <ns> -o jsonpath='{.status.phase}'`
or simply poll `kubectl get mcpservers` and check the STATUS column.
- **MCPServer readiness polling**: after `kubectl apply` for an
MCPServer, it may take 30-60 seconds to reach `Running`. Poll with
5-second intervals up to 120 seconds before declaring a timeout.
- **Server name conflicts**: `thv run <server>` uses the registry entry name by default, which may already exist. Always use `thv run --name <server>-test <server>` to create a uniquely-named instance. This avoids "workload with name already exists" errors.
- **Port-forward needs time**: when testing via `kubectl port-forward`, wait at least 5 seconds before issuing `curl`. Start the port-forward in the background, sleep 5, then curl. Kill the port-forward PID after the check.
- **MCPServer status field**: the MCPServer CRD uses `.status.phase` (not `.status.state`) for the running state. When polling for readiness, use: `kubectl get mcpservers <name> -n <ns> -o jsonpath='{.status.phase}'` or simply poll `kubectl get mcpservers` and check the STATUS column.
- **MCPServer readiness polling**: after `kubectl apply` for an MCPServer, it may take 30-60 seconds to reach `Running`. Poll with 5-second intervals up to 120 seconds before declaring a timeout.

## Step 6: Report results

Expand All @@ -182,15 +125,10 @@ For each **FAIL**, include:
- The command that failed
- Actual output vs expected output
- A classification:
- **Doc issue**: the command or example in the doc is wrong or outdated
(e.g., wrong image tag, deprecated flag, missing step)
- **ToolHive bug**: the doc appears correct but ToolHive behaves
unexpectedly (e.g., crash, wrong output from a correct command)
- **Environment issue**: missing prerequisite, network problem, or
transient error
- A specific recommendation (e.g., "Update image tag from `v0.7.0` to
`v0.8.2`" or "File a bug: MCPServer pods fail to start when Vault
annotations are present")
- **Doc issue**: the command or example in the doc is wrong or outdated (e.g., wrong image tag, deprecated flag, missing step)
- **ToolHive bug**: the doc appears correct but ToolHive behaves unexpectedly (e.g., crash, wrong output from a correct command)
- **Environment issue**: missing prerequisite, network problem, or transient error
- A specific recommendation (e.g., "Update image tag from `v0.7.0` to `v0.8.2`" or "File a bug: MCPServer pods fail to start when Vault annotations are present")

## Step 7: Clean up

Expand All @@ -199,11 +137,9 @@ Always clean up after testing:
- Delete test namespaces: `kubectl delete namespace <test-namespace>`
- Remove Helm releases installed during testing
- Delete any temporary files or directories
- If resources were created in `toolhive-system`, delete them individually
by name
- If resources were created in `toolhive-system`, delete them individually by name

If cleanup fails, report what could not be cleaned up so the user can
handle it manually.
If cleanup fails, report what could not be cleaned up so the user can handle it manually.

## Example session

Expand All @@ -212,8 +148,7 @@ User: "test the vault integration tutorial"
1. Explore agent finds `docs/toolhive/tutorials/vault-integration.mdx`
2. Parse the doc: 5 major steps with 12 bash commands and 1 YAML manifest
3. Run `check-prereqs.sh` - kind cluster "toolhive" exists, thv v0.8.2
4. Ask user: "The doc uses a placeholder GitHub token
`ghp_your_github_token_here`. Provide a real token or skip step 2?"
4. Ask user: "The doc uses a placeholder GitHub token `ghp_your_github_token_here`. Provide a real token or skip step 2?"
5. Present test plan, user approves
6. Execute steps 1-5, report results
7. Clean up: delete vault namespace, remove MCPServer resource
Expand Down
1 change: 0 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"extensions": [
"unifiedjs.vscode-mdx",
"esbenp.prettier-vscode",
"davidanson.vscode-markdownlint",
"redhat.vscode-yaml",
"yzhang.markdown-all-in-one",
"bpruitt-goddard.mermaid-markdown-syntax-highlighting"
Expand Down
3 changes: 1 addition & 2 deletions .github/prompts/doc-review.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,4 @@ You can run `editFiles` to make changes based on your review. You can also run `
- `npm run build` to build the documentation site.
- `npm run start` to start the local development server.
- `npm run prettier` to check formatting.
- `npm run markdownlint` to check for linting errors.
- `npm run eslint` to check for JavaScript/TypeScript linting errors.
- `npm run eslint` to check for JavaScript/TypeScript/MDX linting errors.
3 changes: 0 additions & 3 deletions .github/workflows/_static-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,5 @@ jobs:
- name: Run ESLint
run: npm run eslint

- name: Run markdownlint
run: npm run markdownlint

- name: Run Prettier
run: npm run prettier
2 changes: 1 addition & 1 deletion .lintstagedrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"*.{js,jsx,ts,tsx,mjs,cjs,mdx}": ["npx prettier --write", "npx eslint --fix"],
"*.md": ["npx prettier --write", "npx markdownlint-cli2 --fix"],
"*.md": ["npx prettier --write"],
"*.{css,json,jsonc,yaml,yml}": ["npx prettier --write"]
}
10 changes: 0 additions & 10 deletions .markdownlint-cli2.jsonc

This file was deleted.

37 changes: 0 additions & 37 deletions .markdownlint.json

This file was deleted.

3 changes: 0 additions & 3 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,5 @@ docs/toolhive/reference/cli/**/*.md
static/api-specs/
docs/toolhive/reference/crd-spec.md

# Ignore Claude Code skills (prompts, not documentation)
.claude/

# Ignore templates
.github/pull_request_template.md
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
"options": {
"proseWrap": "always"
}
},
{
"files": ["AGENTS.md", ".claude/**/*.md", ".github/prompts/**/*.md"],
"options": {
"proseWrap": "never"
}
}
]
}
6 changes: 1 addition & 5 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
{
"recommendations": [
"unifiedjs.vscode-mdx",
"esbenp.prettier-vscode",
"davidanson.vscode-markdownlint"
]
"recommendations": ["unifiedjs.vscode-mdx", "esbenp.prettier-vscode"]
}
13 changes: 6 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ Development commands:
Code quality commands (note: pre-commit hooks run these automatically on staged files):

- `npm run prettier` and `npm run prettier:fix`: check and fix code formatting issues (all file types).
- `npm run eslint` and `npm run eslint:fix`: check and fix code quality issues (`.js`, `.jsx`, `.ts`, `.tsx`, `.mdx` files only).
- `npm run markdownlint` and `npm run markdownlint:fix`: check and fix Markdown style issues (`.md` files only - DO NOT use with `.mdx` files).
- `npm run eslint` and `npm run eslint:fix`: check and fix code quality and Markdown style issues (`.js`, `.jsx`, `.ts`, `.tsx`, `.mdx` files).

## Contribution guidelines

Expand All @@ -54,14 +53,14 @@ Code quality commands (note: pre-commit hooks run these automatically on staged

The project uses automated tooling to enforce code quality and formatting standards:

- **Pre-commit hooks**: lint-staged runs automatically on `git commit`, applying prettier and appropriate linters to staged files.
- **GitHub Actions**: All PRs trigger automated checks (ESLint, markdownlint, Prettier).
- **Pre-commit hooks**: lint-staged runs automatically on `git commit`, applying Prettier and appropriate linters to staged files.
- **GitHub Actions**: All PRs trigger automated checks (ESLint, Prettier).
- **No manual formatting needed**: The pre-commit hook handles formatting automatically - you do not need to run formatters manually.

File type to linter mapping (handled automatically by pre-commit hooks):

- `.md` files: Prettier + markdownlint
- `.mdx` files: Prettier + ESLint (NOT markdownlint)
- `.md` files: Prettier only
- `.mdx` files: Prettier + ESLint
- `.js`, `.jsx`, `.ts`, `.tsx` files: Prettier + ESLint
- `.css`, `.json`, `.jsonc`, `.yaml`, `.yml` files: Prettier only

Expand Down Expand Up @@ -180,7 +179,7 @@ If you encounter a term not listed here that appears frequently in the documenta

## Markdown style

Prettier and markdownlint are used to enforce the following Markdown style conventions.
Prettier is used to enforce the following Markdown style conventions.

- Headings: use "ATX-style" headings
- Use unique headings within a document
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,18 @@ having to restart the server.

## Formatting

We use a combination of Prettier, markdownlint, and ESLint to normalize
formatting and syntax. Before you submit a PR, please check for issues:
We use Prettier and ESLint to normalize formatting and syntax. Before you submit
a PR, please check for issues:

```bash
npm run prettier
npm run markdownlint
npm run eslint
```

To automatically fix issues:

```bash
npm run prettier:fix
npm run markdownlint:fix
npm run eslint:fix
```

Expand Down
Loading
Loading