diff --git a/.github/workflows/framework-tests.yml b/.github/workflows/framework-tests.yml new file mode 100644 index 00000000..ceaf1249 --- /dev/null +++ b/.github/workflows/framework-tests.yml @@ -0,0 +1,150 @@ +# Hugo + Hextra docs-framework harness, run against kagent's Hugo docs site. +# +# kagent-dev/website is a mixed repo: a Next.js marketing worker at the root and +# a Hugo docs site under docs-site/ that consumes docs-theme-extras. Only the +# docs site is in scope here — every build/config path below is under docs-site/. +# +# One Hugo build feeds two Playwright projects (defined in docs-theme-extras' +# playwright.config.ts): +# --project=static layout / theme-behavior specs (render the theme) +# --project=content scanners that depend on the consumer's real content +# (markdown-leaks walks the built HTML for rendering +# leaks; curl-quotes lints source markdown) +# The `content` scanners are the reason this workflow's path filter includes +# CONTENT paths (docs-site/content/**), not just layout paths: a content PR must +# still run the leak scan, since that's the kind of PR that introduces content +# rendering breaks. docs-site/content is GENERATED from the MDX source by +# `make gen-docs`, and is committed, so a regenerated-content PR touches it and +# triggers here. Both projects share one build, so running the (fast, mostly +# fixture-bound) layout specs on a content PR too costs almost nothing. +# +# The harness lives in solo-io/docs-theme-extras and is checked out at the +# version pinned in docs-site/go.mod. Layouts and tests stay in lockstep — +# bumping the module pin is one PR that updates both. +# +# NOTE: this workflow assumes docs-site/go.mod pins a RELEASED docs-theme-extras +# version with no local `replace` directive. A local `replace` (absolute path) +# used for dev will fail the Hugo build here — remove it and bump the pin first. +# +# Marked continue-on-error while allowlists and fixture-aware specs settle. +# Promote to a required check once it stays green for a sustained run. + +name: Framework tests + +on: + pull_request: + paths: + # Content — so the `content` scanners run on content-only PRs. + - 'docs-site/content/**' + # Layout / build inputs. + - 'docs-site/layouts/**' + - 'docs-site/static/**' + - 'docs-site/assets/**' + - 'docs-site/go.mod' + - 'docs-site/go.sum' + - 'docs-site/hugo.yaml' + - 'docs-site/.docs-test.toml' + - '.github/workflows/framework-tests.yml' + workflow_dispatch: + +jobs: + framework-test: + name: Static + content checks + runs-on: ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + with: + go-version: 'stable' + cache: false + - uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3 + with: + hugo-version: '0.160.1' + extended: true + + - name: Resolve docs-theme-extras ref from docs-site/go.mod + id: theme-sha + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Pull the version field for the module's `require` line. exit-on-first + # match takes `require` (which precedes any `replace`) so a dev-only + # replace line doesn't shadow it. Handles tags, prereleases, and Go + # pseudo-versions. + version=$(awk -v pkg="github.com/solo-io/docs-theme-extras" ' + /^replace/ { next } + { for (i=1; i<=NF; i++) if ($i == pkg) { print $(i+1); exit } } + ' docs-site/go.mod) + if [ -z "$version" ]; then + echo "Could not extract docs-theme-extras version from docs-site/go.mod" >&2 + exit 1 + fi + # Pseudo-version shape: ends with .<14-digit timestamp>-<12-hex short SHA>. + if echo "$version" | grep -qE -- '\.[0-9]{14}-[0-9a-f]{12}$'; then + short=$(echo "$version" | grep -oE '[0-9a-f]{12}$') + ref=$(gh api "repos/solo-io/docs-theme-extras/commits/${short}" --jq .sha) + if [ -z "$ref" ]; then + echo "Could not resolve full SHA for short=${short}" >&2 + exit 1 + fi + else + ref="$version" + fi + echo "ref=$ref" >> "$GITHUB_OUTPUT" + + - name: Check out docs-theme-extras at module pin + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: solo-io/docs-theme-extras + ref: ${{ steps.theme-sha.outputs.ref }} + path: docs-theme-extras + + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: 'docs-theme-extras/package-lock.json' + + - name: Build docs-site with Hugo + working-directory: docs-site + run: | + # docs-site's CSS pipeline shells out to tooling in its own + # devDependencies, so install them first so Hugo finds the binaries. + npm ci + # Capture the build log so hugo-warnings.spec can scan it for ERROR / + # WARN lines; surface it and fail if the build itself fails. Mirrors + # the Makefile's build-docs target (hugo --config hugo.yaml --gc --minify). + hugo --config hugo.yaml --gc --minify > .build.log 2>&1 || { cat .build.log; exit 1; } + + - name: Install harness dependencies + working-directory: docs-theme-extras + run: npm ci + + - name: Run static + content specs + working-directory: docs-theme-extras + env: + DOCS_TEST_CONFIG: ${{ github.workspace }}/docs-site/.docs-test.toml + run: | + # One invocation runs both projects against the single build above. + npx playwright test --project=static --project=content --reporter=list,html 2>&1 | tee playwright-output.txt + + - name: Append summary to PR check + if: always() + working-directory: docs-theme-extras + run: | + { + echo "## Framework tests (informational)" + echo "" + echo '```' + tail -25 playwright-output.txt 2>/dev/null || echo "No test output captured." + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + + - name: Upload report + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: framework-test-report + path: docs-theme-extras/playwright-report + retention-days: 7 diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 00e5010d..5dac3ba7 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -1,4 +1,11 @@ name: Deploy Preview + +# Runs on every PR to main. Builds the combined site (Hugo docs + Next.js +# marketing Worker) and uploads it as an isolated Worker VERSION with its own +# preview URL. It deliberately uses `wrangler versions upload`, NOT `deploy`, so +# production traffic is never shifted — the currently-deployed version keeps +# serving prod. Promotion to production happens only via production.yaml +# (on merge to main). on: pull_request: types: @@ -7,6 +14,11 @@ on: branches: - main +# Cancel superseded preview runs for the same PR. +concurrency: + group: preview-${{ github.ref }} + cancel-in-progress: true + jobs: deploy: runs-on: ubuntu-latest @@ -18,11 +30,27 @@ jobs: with: node-version: 20.x + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.24' + + - name: Setup Hugo + uses: peaceiris/actions-hugo@v3 + with: + hugo-version: '0.160.1' + extended: true + - name: Install dependencies - run: npm ci + run: | + npm ci + cd docs-site && npm ci - - name: Build the site - run: npm run build:worker + # Builds the Hugo docs, injects them into public/docs, then builds the + # OpenNext Worker (which bundles public/ as static assets). HUGO=hugo uses + # the Hugo installed above instead of the local hugo160 alias. + - name: Build (Hugo docs + inject into /docs + Worker) + run: make build HUGO=hugo # Derive a stable preview alias from the PR branch name. Cloudflare preview # aliases must be a valid subdomain label (lowercase alphanumerics and @@ -38,7 +66,7 @@ jobs: echo "alias=$alias" >> "$GITHUB_OUTPUT" echo "Preview alias: $alias" - - name: Create website preview + - name: Upload preview version (does NOT touch production) id: deploy uses: cloudflare/wrangler-action@v3.14.1 with: diff --git a/.github/workflows/update-ref-docs.yaml b/.github/workflows/update-ref-docs.yaml index 718d4878..327db70c 100644 --- a/.github/workflows/update-ref-docs.yaml +++ b/.github/workflows/update-ref-docs.yaml @@ -11,6 +11,12 @@ concurrency: group: update-ref-docs cancel-in-progress: false +# The docs are a Hugo site under docs-site/ (served at /docs). This workflow +# generates the reference pages directly as Hugo markdown into docs-site/content: +# - kagent CRD API ref -> docs-site/content/kagent/resources/api-ref.md +# - kmcp CRD API ref -> docs-site/content/kmcp/reference/api-ref.md +# - kagent Helm ref -> docs-site/content/kagent/resources/helm.md +# Each page uses plain Hugo YAML frontmatter (no MDX `export const metadata`). jobs: generate-api-docs: runs-on: ubuntu-latest @@ -18,7 +24,13 @@ jobs: permissions: contents: write pull-requests: write - + + # Target Hugo content paths (relative to the website checkout). + env: + KAGENT_API_PAGE: docs-site/content/kagent/resources/api-ref.md + KMCP_API_PAGE: docs-site/content/kmcp/reference/api-ref.md + HELM_PAGE: docs-site/content/kagent/resources/helm.md + steps: - name: Checkout kagent repository uses: actions/checkout@v4 @@ -77,7 +89,7 @@ jobs: echo "Error: crd-ref-docs-config.yaml not found in scripts directory" exit 1 fi - + envsubst < scripts/crd-ref-docs-config.yaml > crd-ref-docs-config.yaml echo "Changed to docs repository: $PWD" @@ -100,41 +112,33 @@ jobs: # Remove the temporary config file so it is not included in the PR rm -f crd-ref-docs-config.yaml - # Create index file with frontmatter - echo '---' > src/app/docs/kagent/resources/api-ref/page.mdx - echo 'title: "API docs"' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo 'pageOrder: 1' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo 'description: "kagent API reference documentation"' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo '---' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo '' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo 'export const metadata = {' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo ' title: "API docs",' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo ' description: "kagent API reference documentation",' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo ' author: "kagent.dev"' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo '};' >> src/app/docs/kagent/resources/api-ref/page.mdx - echo '' >> src/app/docs/kagent/resources/api-ref/page.mdx - cat "./out.md" >> src/app/docs/kagent/resources/api-ref/page.mdx - - # Remove temporary file + # Fix problematic angle brackets in the generated markdown. + # Goldmark (unsafe: true) would otherwise treat stray <...> as raw HTML + # and silently swallow it, so convert bare angle brackets to HTML + # entities (they render literally). Preserve legitimate
tags. + echo "Fixing problematic angle brackets in generated markdown..." + sed -i 's/
/__BR_TAG__/g' "./out.md" + sed -i 's//\>/g' "./out.md" + sed -i 's/__BR_TAG__/
/g' "./out.md" + + # Write the Hugo page: plain YAML frontmatter + generated body. + mkdir -p "$(dirname "$KAGENT_API_PAGE")" + cat > "$KAGENT_API_PAGE" <<'EOF' + --- + title: API Reference + linkTitle: API docs + description: kagent API reference documentation + weight: 1 + author: kagent.dev + --- + + EOF + cat "./out.md" >> "$KAGENT_API_PAGE" rm -f "./out.md" - # Fix problematic angle brackets in the generated MDX file - # Convert literal angle brackets to HTML entities to prevent MDX parsing errors - # But preserve legitimate HTML tags like
, , etc. - echo "Fixing problematic angle brackets in generated MDX..." - - # First, temporarily replace legitimate HTML tags with placeholders - sed -i 's/
/__BR_TAG__/g' "src/app/docs/kagent/resources/api-ref/page.mdx" - - # Convert remaining angle brackets to HTML entities - sed -i 's//\>/g' "src/app/docs/kagent/resources/api-ref/page.mdx" - - # Restore legitimate HTML tags - sed -i 's/__BR_TAG__/
/g' "src/app/docs/kagent/resources/api-ref/page.mdx" - # Verify the output file was created - if [ ! -f "src/app/docs/kagent/resources/api-ref/page.mdx" ]; then + if [ ! -f "$KAGENT_API_PAGE" ]; then echo "Error: Failed to create API docs page" exit 1 fi @@ -158,7 +162,7 @@ jobs: echo "Error: crd-ref-docs-config.yaml not found in scripts directory" exit 1 fi - + envsubst < scripts/crd-ref-docs-config.yaml > crd-ref-docs-config.yaml echo "Changed to docs repository: $PWD" @@ -181,41 +185,30 @@ jobs: # Remove the temporary config file so it is not included in the PR rm -f crd-ref-docs-config.yaml - # Create index file with frontmatter - echo '---' > src/app/docs/kmcp/reference/api-ref/page.mdx - echo 'title: "API docs"' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo 'pageOrder: 5' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo 'description: "kmcp API reference documentation"' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo '---' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo '' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo 'export const metadata = {' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo ' title: "API docs",' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo ' description: "kmcp API reference documentation",' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo ' author: "kagent.dev"' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo '};' >> src/app/docs/kmcp/reference/api-ref/page.mdx - echo '' >> src/app/docs/kmcp/reference/api-ref/page.mdx - cat "./out.md" >> src/app/docs/kmcp/reference/api-ref/page.mdx - - # Remove temporary file + # Fix problematic angle brackets (see the kagent step for rationale). + echo "Fixing problematic angle brackets in generated markdown..." + sed -i 's/
/__BR_TAG__/g' "./out.md" + sed -i 's//\>/g' "./out.md" + sed -i 's/__BR_TAG__/
/g' "./out.md" + + # Write the Hugo page: plain YAML frontmatter + generated body. + mkdir -p "$(dirname "$KMCP_API_PAGE")" + cat > "$KMCP_API_PAGE" <<'EOF' + --- + title: API Reference + linkTitle: API docs + description: kmcp API reference documentation + weight: 5 + author: kagent.dev + --- + + EOF + cat "./out.md" >> "$KMCP_API_PAGE" rm -f "./out.md" - # Fix problematic angle brackets in the generated MDX file - # Convert literal angle brackets to HTML entities to prevent MDX parsing errors - # But preserve legitimate HTML tags like
, , etc. - echo "Fixing problematic angle brackets in generated MDX..." - - # First, temporarily replace legitimate HTML tags with placeholders - sed -i 's/
/__BR_TAG__/g' "src/app/docs/kmcp/reference/api-ref/page.mdx" - - # Convert remaining angle brackets to HTML entities - sed -i 's//\>/g' "src/app/docs/kmcp/reference/api-ref/page.mdx" - - # Restore legitimate HTML tags - sed -i 's/__BR_TAG__/
/g' "src/app/docs/kmcp/reference/api-ref/page.mdx" - # Verify the output file was created - if [ ! -f "src/app/docs/kmcp/reference/api-ref/page.mdx" ]; then + if [ ! -f "$KMCP_API_PAGE" ]; then echo "Error: Failed to create KMCP API docs page" exit 1 fi @@ -226,133 +219,95 @@ jobs: run: | echo "Looking for Helm directory:" ls -la "$GITHUB_WORKSPACE/kagent/helm" || echo "Helm directory not found!" - + # Update docs repository cd "$GITHUB_WORKSPACE/website" echo "Changed to docs repository: $PWD" - # Create directory for Helm docs - mkdir -p src/app/docs/kagent/resources/helm/ - # Generate Helm Docs for kagent chart if [ ! -d "$GITHUB_WORKSPACE/kagent/helm/kagent" ]; then echo "Error: kagent Helm chart directory not found" exit 1 fi - + echo "Processing kagent Helm chart..." - + echo "Chart directory contents:" ls -la "$GITHUB_WORKSPACE/kagent/helm/kagent/" - + # Generate Chart.yaml from template for helm-docs to work echo "Generating Chart.yaml from template..." cd "$GITHUB_WORKSPACE/kagent/helm/kagent" - + # Get the version from git or use a default VERSION=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo "0.5.5") echo "Using version: $VERSION" - + # Copy template and substitute version cp Chart-template.yaml Chart.yaml sed -i "s/\${VERSION}/$VERSION/g" Chart.yaml - + echo "Generated Chart.yaml contents:" cat Chart.yaml - + # Go back to website directory cd "$GITHUB_WORKSPACE/website" - + echo "Chart.yaml contents:" cat "$GITHUB_WORKSPACE/kagent/helm/kagent/Chart.yaml" || echo "Chart.yaml not found!" - + echo "Values.yaml contents (first 20 lines):" head -20 "$GITHUB_WORKSPACE/kagent/helm/kagent/values.yaml" || echo "values.yaml not found!" - + # Generate the helm documentation echo "Running helm-docs..." - - # Debug: Show all available paths - echo "Available paths:" - echo "GITHUB_WORKSPACE: $GITHUB_WORKSPACE" - echo "Current directory: $PWD" - echo "kagent repo path: $GITHUB_WORKSPACE/kagent" - echo "kagent helm path: $GITHUB_WORKSPACE/kagent/helm" - echo "kagent chart path: $GITHUB_WORKSPACE/kagent/helm/kagent" - - # List all helm directories to see what's available - echo "All helm directories:" find "$GITHUB_WORKSPACE/kagent/helm" -name "Chart.yaml" -type f 2>/dev/null | head -10 - - # Check if the specific chart directory exists and what's in it - echo "Checking chart directory:" - if [ -d "$GITHUB_WORKSPACE/kagent/helm/kagent" ]; then - echo "Chart directory exists" - ls -la "$GITHUB_WORKSPACE/kagent/helm/kagent/" - echo "Chart.yaml exists: $([ -f "$GITHUB_WORKSPACE/kagent/helm/kagent/Chart.yaml" ] && echo "YES" || echo "NO")" - echo "Values.yaml exists: $([ -f "$GITHUB_WORKSPACE/kagent/helm/kagent/values.yaml" ] && echo "YES" || echo "NO")" - else - echo "Chart directory does NOT exist" - fi - - # Generate the helm documentation + go run github.com/norwoodj/helm-docs/cmd/helm-docs@v1.14.2 \ --chart-search-root "$GITHUB_WORKSPACE/kagent/helm/kagent" \ - --dry-run > "src/app/docs/kagent/resources/helm/temp.mdx" - - # Go back to website directory - cd "$GITHUB_WORKSPACE/website" + --dry-run > "helm-temp.md" echo "Generated helm-docs output (first 50 lines):" - head -50 "src/app/docs/kagent/resources/helm/temp.mdx" - - echo "Generated helm-docs output (last 50 lines):" - tail -50 "src/app/docs/kagent/resources/helm/temp.mdx" - + head -50 "helm-temp.md" echo "Total lines generated:" - wc -l "src/app/docs/kagent/resources/helm/temp.mdx" + wc -l "helm-temp.md" + + # Remove the badge line and following empty line + # (might be replaced by a helm-docs template in the future). + sed -i '/!\[Version:/,/^$/d' "helm-temp.md" - # Remove badge line and following empty line - # (might be replaced by helm docs template in the future) - sed -i '/!\[Version:/,/^$/d' "src/app/docs/kagent/resources/helm/temp.mdx" + # Drop the leading `# ` H1: Hextra renders the frontmatter + # title as the page H1, so a body H1 would duplicate it. + sed -i '0,/^# /{/^# /d}' "helm-temp.md" - # Wrap version placeholders in inline code so they show literally in MDX + # Wrap version placeholders in inline code so they show literally. python - <<'PY' from pathlib import Path - path = Path("src/app/docs/kagent/resources/helm/temp.mdx") + path = Path("helm-temp.md") text = path.read_text() for placeholder in ("${KMCP_VERSION}", "${SUBSTRATE_VERSION}", "${SUBSTRATE_REPO}"): text = text.replace(placeholder, "`" + placeholder + "`") path.write_text(text) PY - # Add frontmatter - echo '---' > "src/app/docs/kagent/resources/helm/page.mdx" - echo 'title: "Helm Chart Configuration"' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo 'pageOrder: 2' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo 'description: "kagent Helm chart configuration reference"' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo '---' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo '' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo 'export const metadata = {' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo ' title: "Helm Chart Configuration",' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo ' description: "kagent Helm chart configuration reference",' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo ' author: "kagent.dev"' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo '};' >> "src/app/docs/kagent/resources/helm/page.mdx" - echo '' >> "src/app/docs/kagent/resources/helm/page.mdx" - - # Append the processed helm documentation - cat "src/app/docs/kagent/resources/helm/temp.mdx" >> "src/app/docs/kagent/resources/helm/page.mdx" - - # Clean up temporary file - rm -f "src/app/docs/kagent/resources/helm/temp.mdx" - - echo "=== Debug: After creating index file ===" - echo "Content directory structure:" - ls -la src/app/docs/kagent/resources/helm/ - + # Write the Hugo page: plain YAML frontmatter + generated body. + mkdir -p "$(dirname "$HELM_PAGE")" + cat > "$HELM_PAGE" <<'EOF' + --- + title: kagent + linkTitle: Helm Chart Configuration + description: kagent Helm chart configuration reference + weight: 2 + author: kagent.dev + --- + + EOF + cat "helm-temp.md" >> "$HELM_PAGE" + rm -f "helm-temp.md" + echo "Final generated file contents (first 50 lines):" - head -50 "src/app/docs/kagent/resources/helm/page.mdx" + head -50 "$HELM_PAGE" - name: Create Pull Request uses: peter-evans/create-pull-request@v6 @@ -366,11 +321,11 @@ jobs: Automated API and kagent Helm chart documentation update based on the latest commits: - **kagent**: [`${{ env.KAGENT_COMMIT }}`](https://github.com/${{ github.repository_owner }}/kagent/commit/${{ env.KAGENT_COMMIT }}) - **kmcp**: [`${{ env.KMCP_COMMIT }}`](https://github.com/${{ github.repository_owner }}/kmcp/commit/${{ env.KMCP_COMMIT }}) - + This PR was automatically generated by the [**Update Reference documentation** workflow](https://github.com/${{ github.repository_owner }}/website/actions/workflows/update-ref-docs.yaml). branch: api-gen-update delete-branch: true base: main labels: | documentation - automated pr \ No newline at end of file + automated pr diff --git a/.gitignore b/.gitignore index 8daea5ce..644a4de3 100644 --- a/.gitignore +++ b/.gitignore @@ -28,10 +28,8 @@ bundler *.pem # debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* + +*.log* # env files (can opt-in for committing if needed) .env* @@ -42,3 +40,19 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# converter staging output (scripts/mdx-to-hugo.mjs --out); never committed +/content-gen/ + +# hugo docs site (docs-site/) — build artifacts + local deps +/docs-site/public +/docs-site/resources +/docs-site/node_modules +/docs-site/hugo_stats.json +/docs-site/.hugo_build.lock + +# docs static output injected into the web app at build time (make inject-docs). +# Generated from docs-site/; keep only the tracked assets (versions/). +/public/docs/* +!/public/docs/versions/ + diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index 511a3e1c..a6088651 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -34,19 +34,20 @@ By participating in this project, you agree to abide by our [Code of Conduct](CO ```bash git checkout -b feature/your-feature-name ``` -5. Install dependencies: +5. Install dependencies (web + docs npm packages and Hugo modules): ```bash - npm install - # or - yarn install + make install ``` -6. Start the development server: +6. Start a development server: ```bash - npm run dev - # or - yarn dev + make serve-web # Next.js marketing site -> http://localhost:3000 + make serve-docs # Hugo docs -> http://localhost:1313/docs/ + make preview # combined build via wrangler -> http://localhost:3000 ``` +See [DEVELOPMENT.md](DEVELOPMENT.md) for the full architecture (Next.js marketing +site + Hugo docs) and authoring conventions. + ## Pull Request Process 1. Update your fork with the latest changes from upstream: @@ -139,11 +140,25 @@ To add an existing blog post, you can add a new entry into the `external-blog-po ## Documentation -- Update documentation for any changes to APIs, CLIs, or user-facing features -- Add examples for new features -- Update the README if necessary -- Add comments to your code explaining complex logic -- Keep documentation in sync with code changes +The documentation is a [Hugo](https://gohugo.io/) site under `docs-site/`, built +with the Hextra theme and the shared `docs-theme-extras` overlay, and served under +the `/docs` path. To contribute: + +- Edit the markdown directly under `docs-site/content/` — the directory tree maps + to the URL and drives the sidebar. Preview with `make serve-docs`. +- Use GitHub-flavored alert blockquotes (`> [!NOTE]`, `> [!TIP]`, `> [!WARNING]`) + for callouts; Hextra renders them as callouts and they also render on GitHub. +- Bump dependency versions in the single snippet file under + `docs-site/assets/versions/` and reference them with the + `{{}}` shortcode rather than + hardcoding version numbers. +- Do not hand-edit the auto-generated reference pages (`kagent/resources/api-ref.md`, + `kmcp/reference/api-ref.md`, `kagent/resources/helm.md`); they are regenerated + nightly from the source repos. +- Update documentation for any changes to APIs, CLIs, or user-facing features, and + add examples for new features. + +See [DEVELOPMENT.md](DEVELOPMENT.md) for the full authoring conventions. ## Testing diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index d5bcde9b..4e95d59d 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -2,140 +2,170 @@ This document provides guidelines and instructions for those who want to contribute to the kagent website and documentation. -## Prerequisites +## Architecture + +The site is two stacks served from one origin (`kagent.dev`): + +- **Marketing site** (home, blog, agents, tools, community, enterprise) — a + Next.js app in `src/`, deployed as an [OpenNext](https://opennext.js.org/cloudflare) + Cloudflare Worker. +- **Documentation** — a [Hugo](https://gohugo.io/) site in `docs-site/`, built + with the [Hextra](https://imfing.github.io/hextra/) theme and the shared + [docs-theme-extras](https://github.com/solo-io/docs-theme-extras) overlay + (the same stack as the other Solo OSS docs sites, e.g. agentgateway). It is + served entirely under the `/docs` subpath. -Before you begin development, ensure you have the following installed: +`make build` builds the Hugo docs, injects the static output into `public/docs/` +so the Worker serves it as static assets, then builds the Worker. One build, one +deploy, one origin. Cloudflare serves the static `/docs/*` assets before the +Worker runs, so the docs shadow any old Next.js `/docs` routes. + +## Prerequisites -- [Node.js](https://nodejs.org/) (v18 or later recommended) -- [npm](https://www.npmjs.com/) (v8 or later) or [yarn](https://yarnpkg.com/) (v1.22 or later) +- [Node.js](https://nodejs.org/) (v18.18.2 or later) and [npm](https://www.npmjs.com/) - [Git](https://git-scm.com/) +- [Hugo extended](https://gohugo.io/installation/) — use the version-pinned + `hugo160` binary that the Solo docs repos standardize on. CI can fall back to a + bare `hugo` on PATH with `make ... HUGO=hugo`. +- [Go](https://go.dev/) — required by Hugo to fetch the `docs-theme-extras` + module. -## Setting Up the Development Environment +## Setting up the development environment 1. **Clone the repository** ```bash git clone https://github.com/kagent-dev/website.git - cd src + cd website ``` -2. **Install dependencies** +2. **Install dependencies** (web + docs npm packages and Hugo modules) ```bash - npm install - # or - yarn install + make install ``` -3. **Start the development server** +The `Makefile` at the repo root orchestrates both stacks. Run `make help` to list +every target. - ```bash - npm run dev - # or - yarn dev - ``` +## Working on the marketing site (Next.js) - This will start the Next.js development server. Open [http://localhost:3000](http://localhost:3000) to view the site in your browser. +```bash +make serve-web # Next.js dev server at http://localhost:3000 +``` +Marketing pages live in `src/app/` and blog posts in `src/blogContent/`. -## Documentation Development +## Working on the documentation (Hugo) -The documentation is built using MDX files. To contribute to the documentation: +Edit the markdown directly under `docs-site/content/`. The directory tree maps to +the URL, so `docs-site/content/kagent/introduction/installation.md` is served at +`/docs/kagent/introduction/installation/`. Hextra builds the sidebar +automatically from the tree plus each page's `weight`. -1. Navigate to the `src/app/docs/` directory -2. Edit existing .mdx files or create new ones -3. If adding a new page, ensure it's properly linked in the navigation (layout.tsx) +```bash +make serve-docs # Hugo docs only, at http://localhost:1313/docs/ +``` + +To preview the docs and marketing site together the way they deploy (so +cross-stack links and the shared top nav behave), build and serve the combined +site through wrangler: + +```bash +make preview # combined build, served at http://localhost:3000 +``` -## Code Style and Linting +### Authoring conventions -This project uses ESLint and Prettier for code formatting and linting. +- **Frontmatter** is plain YAML: `title` (the page H1 / sidebar name), + optional `linkTitle` (short sidebar name when the H1 is longer), `description`, + `weight` (ordering), and `author`. +- **Shortcodes** from Hextra / docs-theme-extras are available, including + `{{}}` / `{{}}`, `{{}}` / `{{}}`, + and `{{}}`. +- **Callouts** use GitHub-flavored alert blockquotes, which Hextra renders as + callouts (and which also render on GitHub): -- Run linting check: + ```markdown + > [!TIP] + > This is a tip. - ```bash - npm run lint - # or - yarn lint + > [!WARNING] + > This is a warning. ``` -- Format code: +- **Versions** are single-sourced as reuse snippets, one file per version under + `docs-site/assets/versions/` (e.g. `agent-substrate.md` contains just `0.0.6`), + matching the convention on the other Solo docs sites. Reference a version with + the `reuse` shortcode. This replaces the old `{VERSIONS.key}` placeholders that + were sourced from `src/app/docs/_constants.ts`. Because the `reuse` shortcode + trims trailing whitespace, the bare value drops cleanly into prose and code + fences: + + ```markdown + Install Agent Substrate v{{}}. ```bash - npm run format - # or - yarn format + helm install substrate ... --version {{}} + ``` ``` -## Building for Production + To bump a dependency version across the docs, edit the one snippet file under + `docs-site/assets/versions/`. A snippet may reference another snippet, so a + composed value can nest a base version rather than duplicating it. -To build the site for production: +### Auto-generated reference docs -```bash -npm run build -# or -yarn build -``` +The kagent/kmcp CRD API references and the kagent Helm chart reference are +generated nightly from the upstream source repos by the +[Update Reference Documentation workflow](.github/workflows/update-ref-docs.yaml), +which opens a PR against `main`. **Do not hand-edit** these files, because the +next run overwrites them: -To preview the production build locally: +- `docs-site/content/kagent/resources/api-ref.md` +- `docs-site/content/kmcp/reference/api-ref.md` +- `docs-site/content/kagent/resources/helm.md` -```bash -npm run start -# or -yarn start -``` +### The MDX converter (migration tool) -## Keeping the lock file in sync +`scripts/mdx-to-hugo.mjs` converted the original Next.js `src/app/docs/**/page.mdx` +docs into the Hugo `docs-site/content/` tree during the migration. It is kept for +reference and re-runs (`make gen-docs`), but `docs-site/content/` is now the +source of truth — a blind `make gen-docs` overwrites hand edits, so only use it to +regenerate into a scratch dir and diff. -Cloudflare Pages runs `npm ci`, which requires `package-lock.json` to match `package.json` exactly. If you change dependencies in `package.json`, update the lock file and commit it: +## Building for production ```bash -npm install -git add package-lock.json -git commit -m "chore: update package-lock.json" +make build # docs + inject into /docs + build the Worker ``` -If the Cloudflare build fails with errors like "lock file's X does not satisfy X" or "Missing: X from lock file", run `npm install` in the website directory and commit the updated `package-lock.json`. - ## Deployment -The site is automatically deployed when changes are pushed to the main branch. The deployment process includes: - -1. Linting and testing the code -2. Building the Next.js application -3. Deploying to the hosting platform - -## Contributing Workflow +`make deploy` builds everything and deploys the Worker to Cloudflare. The site is +also deployed automatically when changes land on `main`. -1. **Fork the repository** -2. **Create a new branch** for your feature or bugfix - ```bash - git checkout -b feature/your-feature-name - ``` +## Keeping the lock files in sync -3. **Make your changes** -4. **Commit your changes** with descriptive commit messages following [Conventional Commits](https://www.conventionalcommits.org/) - ```bash - git commit -m "feat: add new documentation section" - ``` -5. **Push your branch** - ```bash - git push origin feature/your-feature-name - ``` -6. **Create a Pull Request** against the main branch +Cloudflare runs `npm ci`, which requires each `package-lock.json` to match its +`package.json` exactly. If you change dependencies, run `npm install` in the +affected directory (repo root for the web app, `docs-site/` for the docs) and +commit the updated lock file. If a build fails with "lock file's X does not +satisfy X" or "Missing: X from lock file", regenerate and commit the lock file. -## Pull Request Guidelines +## Code style and linting -- Include a clear description of the changes -- Reference any relevant issues -- Update documentation if necessary -- Add tests for new features +The Next.js app uses ESLint and Prettier: -## Getting Help +```bash +npm run lint +npm run format +``` -If you need assistance, you can: +## Getting help - Create an issue on GitHub - Reach out to project maintainers - [Join our community discussion](https://bit.ly/kagentdiscord) on Discord -Thank you for contributing to the kagent project! \ No newline at end of file +Thank you for contributing to the kagent project! diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..7d87d382 --- /dev/null +++ b/Makefile @@ -0,0 +1,87 @@ +# kagent.dev — combined build (Next.js marketing worker + Hugo docs) +# +# Architecture: the marketing site (home, blog, agents, tools, community, +# enterprise) is a Next.js app deployed as an opennextjs Cloudflare Worker. The +# documentation is a Hugo site in docs-site/, served entirely under the /docs +# subpath (its baseURL carries the /docs prefix). `make build` builds the Hugo +# docs, injects the static output into public/docs/ so the Worker serves it as +# static assets, then builds the Worker. One build, one deploy, one origin. +# +# Hugo binary: defaults to the version-pinned `hugo160` used across the Solo docs +# repos. CI can override with `make ... HUGO=hugo` if a bare hugo is on PATH. + +HUGO ?= hugo160 +DOCS_DIR := docs-site +DOCS_OUT := $(DOCS_DIR)/public +# Where the docs static assets are injected in the Next app. Served at /docs. +WEB_DOCS := public/docs +# Optional Hugo baseURL override. Empty = use hugo.yaml's prod baseURL +# (https://kagent.dev/docs/). `make preview` sets this to the local wrangler host +# so internal absolute links (section cards, assets) stay on localhost instead of +# jumping to production. The port matches `dev:worker` (wrangler --port 3000). +DOCS_BASEURL ?= + +.DEFAULT_GOAL := help + +.PHONY: help +help: ## List available targets + @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \ + | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}' + +# ── Setup ────────────────────────────────────────────────────────────────── +.PHONY: install +install: ## Install web + docs dependencies (npm) and Hugo modules + npm install + cd $(DOCS_DIR) && npm install + cd $(DOCS_DIR) && $(HUGO) mod get ./... + +# ── Docs (Hugo) ──────────────────────────────────────────────────────────── +.PHONY: gen-docs +gen-docs: ## Regenerate Hugo docs content from src/app/docs (the MDX source) + node scripts/mdx-to-hugo.mjs --out $(DOCS_DIR)/content + +.PHONY: build-docs +build-docs: ## Build the Hugo docs site -> docs-site/public + cd $(DOCS_DIR) && $(HUGO) --config hugo.yaml $(if $(DOCS_BASEURL),--baseURL "$(DOCS_BASEURL)") --gc --minify + +.PHONY: inject-docs +inject-docs: ## Copy built docs into public/docs (preserves tracked assets, e.g. versions/) + @mkdir -p $(WEB_DOCS) + rsync -a --delete --filter='protect versions/**' --filter='protect versions/' \ + $(DOCS_OUT)/ $(WEB_DOCS)/ + +.PHONY: serve-docs +serve-docs: ## Preview the docs alone at http://localhost:1313/docs/ + cd $(DOCS_DIR) && $(HUGO) server --config hugo.yaml -D --disableFastRender + +# ── Web (Next.js) ────────────────────────────────────────────────────────── +.PHONY: serve-web +serve-web: ## Run the Next.js marketing dev server (http://localhost:3000) + npm run dev + +.PHONY: build-web +build-web: ## Build the opennextjs Cloudflare Worker (bundles public/ as assets) + npm run build:worker + +# ── Combined ─────────────────────────────────────────────────────────────── +.PHONY: build +build: build-docs inject-docs build-web ## Build docs + inject into /docs + build the Worker + +.PHONY: preview +# Target-specific var (inherited by the `build` prerequisite -> build-docs) so the +# docs are built with the local host; keeps card/asset links on localhost. +preview: DOCS_BASEURL := http://localhost:3000/docs/ +preview: build ## Build everything and serve the combined site via wrangler dev + npm run dev:worker + +.PHONY: deploy +deploy: build ## Build everything and deploy the Worker to Cloudflare + npx wrangler deploy --minify + +# ── Housekeeping ─────────────────────────────────────────────────────────── +.PHONY: clean +clean: ## Remove build artifacts (keeps tracked assets under public/docs) + rm -rf $(DOCS_OUT) $(DOCS_DIR)/resources $(DOCS_DIR)/hugo_stats.json + rm -rf .open-next .wrangler + @# Drop injected docs but keep tracked files (versions/ etc.) + find $(WEB_DOCS) -mindepth 1 -maxdepth 1 ! -name versions -exec rm -rf {} + 2>/dev/null || true diff --git a/docs-site/.docs-test.toml b/docs-site/.docs-test.toml new file mode 100644 index 00000000..fdde7f01 --- /dev/null +++ b/docs-site/.docs-test.toml @@ -0,0 +1,62 @@ +# Configuration for the docs-theme-extras harness when run against kagent's +# Hugo docs site (the docs-site/ subtree of kagent-dev/website). +# +# The harness lives in github.com/solo-io/docs-theme-extras and reads this file +# via the DOCS_TEST_CONFIG env var (set by CI). All relative paths are resolved +# against this file's directory (docs-site/). The harness does NOT build the +# site — `hugo --config hugo.yaml` runs first and writes to builtRoot. +# +# NOTE: docs-site/content is GENERATED from the Next.js MDX source under +# src/app/docs by `make gen-docs` (scripts/mdx-to-hugo.mjs --out docs-site/content). +# These checks run against the generated Hugo output, which is the right place +# to catch shortcode/rendering breaks — but a content fix must land in the MDX +# source (or the converter), not in docs-site/content, or `gen-docs` overwrites it. + +version = "1" +name = "kagent-oss" +brand = "oss" + +# Where the consumer's built HTML lives. Hugo writes to docs-site/public at the +# tree root (the /docs baseURL subpath lives in hrefs, not the filesystem), so +# builtRoot is ./public and baseURL is "/" for file mapping. +builtRoot = "./public" +baseURL = "/" + +# Hugo build log for hugo-warnings.spec. The CI build step writes the Hugo build +# output here; the spec scans it for ERROR / WARN lines (filtered by +# [allowlists].hugoWarnings). +buildLog = "./.build.log" + +# Source-tree roots for author-side lints (curl-quotes, tab-syntax, +# shortcode-args). Points at the generated Hugo content — the lints target Hugo +# shortcode syntax, which only exists post-conversion, so scanning the generated +# output is what catches converter bugs. +scanRoots = [ + "./content", +] + +# NOTE: kagent docs are a flat, unversioned set (/
//) with no +# version segment. There is intentionally no [versioning] block — version-aware +# specs detect the absence and skip gracefully (same mechanism agentregistry's +# and ambientmesh's flat docs rely on). + +# All checks default to enabled. No [checks] overrides are needed: kagent runs +# the full default set. (The former `smoke`/`crossBrowser` toggles were removed +# from the harness — smoke folded into the `content` project scoped by +# CONTENT_DIR, and cross-browser is now selected per Playwright project.) + +# Allowlists for known-benign noise that surfaces against real content (the +# module's bundled fixture has none of this). +[allowlists] +hugoWarnings = [ + "\\.Site\\.Data was deprecated", + "'items' parameter of the 'tabs' shortcode is deprecated", +] +# consoleErrors is intentionally empty: CI runs only the static + content +# projects, which don't launch the third-party page scripts. Populate this when +# the browser / console-error projects are enabled for kagent (they'll surface +# the analytics/search backends that fail in the offline test environment). The +# Hextra main.js null-deref that other consumers allowlisted here does NOT occur: +# docs-theme-extras' module footer renders the hidden hamburger/sidebar stand-ins +# site-wide (confirmed present on the built docs pages after the beta.4 bump). +consoleErrors = [] diff --git a/docs-site/.gitignore b/docs-site/.gitignore new file mode 100644 index 00000000..d2c815ce --- /dev/null +++ b/docs-site/.gitignore @@ -0,0 +1,6 @@ +/public/ +/resources/ +/node_modules/ +/hugo_stats.json +.hugo_build.lock +.DS_Store diff --git a/docs-site/assets/css/chatbot.css b/docs-site/assets/css/chatbot.css new file mode 100644 index 00000000..5c755f69 --- /dev/null +++ b/docs-site/assets/css/chatbot.css @@ -0,0 +1,497 @@ +/* Chatbot CSS - Animations and Dynamic Content Styling */ + +/* ===== Animations ===== */ +@keyframes dialogSlideIn { + from { + opacity: 0; + transform: scale(0.95) translateY(10px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +@keyframes messageSlideIn { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@keyframes bounceSingle { + 0% { + transform: translateY(0); + } + 50% { + transform: translateY(-3px); + } + 100% { + transform: translateY(0); + } +} + +@keyframes blink { + 0%, 50% { opacity: 1; } + 51%, 100% { opacity: 0; } +} + + +@keyframes codeLine { + from { + opacity: 0; + transform: translateY(-2px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* ===== Component States ===== */ +.chatbot-dialog.expanded { + height: 80vh; +} + +/* Unified input card focus glow */ +.chatbot-input-card:focus-within { + border-color: #8b5cf6; + box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.15); +} + +/* User message - shrink-wrap to text content */ +.chatbot-message.user { + width: fit-content; + max-width: 100%; + word-break: break-word; + overflow-wrap: break-word; + background: linear-gradient(135deg, #7c3aed, #6d28d9); + color: #fff; + box-shadow: 0 2px 8px rgba(124, 58, 237, 0.2); +} + +.dark .chatbot-message.user { + box-shadow: 0 2px 8px rgba(124, 58, 237, 0.3); +} + +/* ===== Avatar Loading Animation ===== */ +.chatbot-avatar.loading img { + width: 75%; + height: 75%; +} + +.chatbot-avatar.loading::after { + content: ''; + position: absolute; + inset: 0; + border-radius: 30px; + border: 2px solid transparent; + border-top-color: #7c3aed; + border-right-color: #7c3aed; + animation: spin 0.8s linear infinite; +} + +.dark .chatbot-avatar.loading::after { + border-top-color: #a78bfa; + border-right-color: #a78bfa; +} + +/* ===== Thinking Animation ===== */ +.thinking-dots { + color: #7c3aed; + font-size: 1.5rem; +} + +.dark .thinking-dots { + color: #a78bfa; +} + +.thinking-dots .dot { + display: inline-block; + transition: transform 0.3s ease-in-out; +} + +.thinking-dots .dot.bouncing { + animation: bounceSingle 0.6s ease-in-out; +} + +/* ===== Code Block Animations ===== */ +.chatbot-code-cursor { + display: inline-block; + width: 8px; + height: 1em; + background: #7c3aed; + margin-left: 2px; + vertical-align: text-bottom; + animation: blink 1s step-end infinite; +} + +.dark .chatbot-code-cursor { + background: #a78bfa; +} + +.chatbot-code-line { + display: block; + animation: codeLine 0.15s ease-out forwards; +} + +/* ===== Scrollbar Styling ===== */ +.chatbot-messages { + scrollbar-width: thin; + scrollbar-color: rgba(156, 163, 175, 0.3) transparent; +} + +.chatbot-messages::-webkit-scrollbar { + width: 6px; +} + +.chatbot-messages::-webkit-scrollbar-track { + background: transparent; +} + +.chatbot-messages::-webkit-scrollbar-thumb { + background: rgba(156, 163, 175, 0.3); + border-radius: 3px; +} + +.chatbot-messages::-webkit-scrollbar-thumb:hover { + background: rgba(156, 163, 175, 0.5); +} + +.dark .chatbot-messages { + scrollbar-color: rgba(107, 114, 128, 0.3) transparent; +} + +.dark .chatbot-messages::-webkit-scrollbar-thumb { + background: rgba(107, 114, 128, 0.3); +} + +.dark .chatbot-messages::-webkit-scrollbar-thumb:hover { + background: rgba(107, 114, 128, 0.5); +} + +textarea { + scrollbar-width: thin; + scrollbar-color: rgba(156, 163, 175, 0.3) transparent; +} + +textarea::-webkit-scrollbar { + width: 6px; +} + +textarea::-webkit-scrollbar-track { + background: transparent; +} + +textarea::-webkit-scrollbar-thumb { + background: rgba(156, 163, 175, 0.3); + border-radius: 3px; +} + +textarea::-webkit-scrollbar-thumb:hover { + background: rgba(156, 163, 175, 0.5); +} + +.dark textarea { + scrollbar-color: rgba(107, 114, 128, 0.3) transparent; +} + +.dark textarea::-webkit-scrollbar-thumb { + background: rgba(107, 114, 128, 0.3); +} + +.dark textarea::-webkit-scrollbar-thumb:hover { + background: rgba(107, 114, 128, 0.5); +} + +/* ===== Markdown Content Styling ===== */ +.chatbot-response { + font-size: 0.875rem; + line-height: 1.6; + color: #111827; +} + +.dark .chatbot-response { + color: #e5e7eb; +} + +.chatbot-response h1, +.chatbot-response h2, +.chatbot-response h3, +.chatbot-response h4 { + margin-top: 1.25rem; + margin-bottom: 0.5rem; + font-weight: 600; + line-height: 1.3; + color: #111827; +} + +.dark .chatbot-response h1, +.dark .chatbot-response h2, +.dark .chatbot-response h3, +.dark .chatbot-response h4 { + color: #f9fafb; +} + +.chatbot-response h1 { font-size: 1.375rem; } +.chatbot-response h2 { font-size: 1.25rem; } +.chatbot-response h3 { font-size: 1.125rem; } +.chatbot-response h4 { font-size: 1rem; } + +.chatbot-response h1:first-child, +.chatbot-response h2:first-child, +.chatbot-response h3:first-child, +.chatbot-response h4:first-child { + margin-top: 0; +} + +.chatbot-response p { + margin: 0.625rem 0; +} + +.chatbot-response p:first-child { + margin-top: 0; +} + +.chatbot-response p:last-child { + margin-bottom: 0; +} + +.chatbot-response ul, +.chatbot-response ol { + margin: 0.625rem 0; + padding-left: 1.5rem; +} + +.chatbot-response li { + margin: 0.25rem 0; +} + +.chatbot-response code { + background: #f3f4f6; + padding: 0.125rem 0.375rem; + border-radius: 4px; + font-size: 0.875em; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; + border: none; +} + +.dark .chatbot-response code { + background: #374151; +} + +.chatbot-response pre { + background: #f6f8fa; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 1rem; + overflow-x: auto; + margin: 0.75rem 0; +} + +.dark .chatbot-response pre { + background: #0d1117; + border-color: #30363d; +} + +.chatbot-response pre code { + background: transparent; + padding: 0; + font-size: 0.8125rem; + line-height: 1.5; + color: #24292f; + border: none; + border-radius: 0; + display: block; +} + +.dark .chatbot-response pre code { + color: #e6edf3; + background: transparent; + border: none; +} + +.chatbot-response blockquote { + border-left: 3px solid #7c3aed; + padding-left: 1rem; + margin: 0.75rem 0; + color: #6b7280; +} + +.dark .chatbot-response blockquote { + color: #9ca3af; +} + +.chatbot-response a { + color: #7c3aed; + text-decoration: none; +} + +.chatbot-response a:hover { + text-decoration: underline; +} + +.chatbot-response table { + border-collapse: collapse; + width: 100%; + margin: 0.75rem 0; + font-size: 0.875rem; +} + +.chatbot-response th, +.chatbot-response td { + border: 1px solid #e5e7eb; + padding: 0.5rem 0.75rem; + text-align: left; +} + +.dark .chatbot-response th, +.dark .chatbot-response td { + border-color: #374151; +} + +.chatbot-response th { + background: #f9fafb; + font-weight: 600; +} + +.dark .chatbot-response th { + background: #1f2937; +} + +.chatbot-response hr { + border: none; + border-top: 1px solid #e5e7eb; + margin: 1rem 0; +} + +.dark .chatbot-response hr { + border-top-color: #374151; +} + +/* ===== Code Copy Button ===== */ +.chatbot-code-block { + position: relative; +} + +.chatbot-code-copy { + position: absolute; + top: 0.5rem; + right: 0.5rem; + display: flex; + align-items: center; + justify-content: center; + width: 1.75rem; + height: 1.75rem; + background: rgba(255, 255, 255, 0.9); + border: 1px solid #e5e7eb; + border-radius: 6px; + color: #6b7280; + cursor: pointer; + opacity: 0; + transition: opacity 0.15s, color 0.15s, background 0.15s; + z-index: 1; +} + +.chatbot-code-block:hover .chatbot-code-copy { + opacity: 1; +} + +.chatbot-code-copy:hover, +.chatbot-code-copy.copied { + color: #7c3aed; + background: #fff; +} + +.dark .chatbot-code-copy { + background: rgba(17, 24, 39, 0.9); + border-color: #374151; + color: #9ca3af; +} + +.dark .chatbot-code-block:hover .chatbot-code-copy { + opacity: 1; +} + +.dark .chatbot-code-copy:hover, +.dark .chatbot-code-copy.copied { + color: #a78bfa; + background: #111827; +} + +/* ===== @ Mention Autocomplete ===== */ +.chatbot-mention-menu { + max-height: 280px; +} + +.chatbot-mention-list { + scrollbar-width: thin; + scrollbar-color: rgba(156, 163, 175, 0.3) transparent; +} + +.chatbot-mention-list::-webkit-scrollbar { + width: 5px; +} + +.chatbot-mention-list::-webkit-scrollbar-track { + background: transparent; +} + +.chatbot-mention-list::-webkit-scrollbar-thumb { + background: rgba(156, 163, 175, 0.3); + border-radius: 3px; +} + +.chatbot-mention-list::-webkit-scrollbar-thumb:hover { + background: rgba(156, 163, 175, 0.5); +} + +.dark .chatbot-mention-list { + scrollbar-color: rgba(107, 114, 128, 0.3) transparent; +} + +.dark .chatbot-mention-list::-webkit-scrollbar-thumb { + background: rgba(107, 114, 128, 0.3); +} + +.dark .chatbot-mention-list::-webkit-scrollbar-thumb:hover { + background: rgba(107, 114, 128, 0.5); +} + +.chatbot-mention-item.active, +.chatbot-mention-item:hover { + background: #f5f3ff; +} + +.dark .chatbot-mention-item.active, +.dark .chatbot-mention-item:hover { + background: rgba(139, 92, 246, 0.1); +} + +/* ===== Responsive Overrides ===== */ +@media (max-width: 640px) { + .chatbot-dialog { + height: 60vh; + max-height: 95vh; + border-radius: 12px; + } + + .chatbot-dialog.expanded { + height: 95vh; + } + + .chatbot-avatar { + width: 28px; + height: 28px; + } +} diff --git a/docs-site/assets/css/custom.css b/docs-site/assets/css/custom.css new file mode 100644 index 00000000..1be553e0 --- /dev/null +++ b/docs-site/assets/css/custom.css @@ -0,0 +1,487 @@ +/* Sticky side-rail offset (left sidebar + right TOC). + extras pins the rails to `--solo-rail-top = --navbar-height + --hextra-banner-height`. + The extras navbar is h-24 (6rem), so --navbar-height must be 6rem (Hextra + defaults it to 4rem, which tucked the rails under the taller navbar). Hextra + also defaults --hextra-banner-height to 2rem assuming an announcement banner; + kagent has none, so that 2rem was phantom space pushing both rails ~2rem below + the content column. Zero it so the rails line up with the breadcrumb/content. */ +:root { + --navbar-height: 6rem; + /* Small offset so the sidebar/TOC first lines sit on the breadcrumb line + (the breadcrumb row sits ~1.1rem below the content pad). Not a real banner. */ + --hextra-banner-height: 1.1rem; +} + +/* Horizontal divider between the top nav and page content (matches agw-oss). + The extras navbar is transparent with only a soft blur shadow; add an + explicit hairline so the nav reads as a distinct bar. */ +.hextra-nav-container { + border-bottom: 1px solid #e5e7eb; +} +.dark .hextra-nav-container { + border-bottom-color: #374151; +} + +/* Theme-toggle icon visibility — explicit fallback for the Tailwind v4 + hx:group-data-[theme=*]:hidden variant. The v4 rule uses :is()/:where() + which can lose the battle against Tailwind v3's svg{display:block} preflight + when both pipelines run. This direct descendant selector with !important + guarantees only the current-theme icon renders. */ +.hx\:group[data-theme="light"] .hx\:group-data-\[theme\=light\]\:hidden, +.hx\:group[data-theme="dark"] .hx\:group-data-\[theme\=dark\]\:hidden, +.hx\:group[data-theme="system"] .hx\:group-data-\[theme\=system\]\:hidden { + display: none !important; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: 'Open Sans', 'ui-sans-serif', 'system-ui', 'sans-serif', "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +} + +.nav-container { + font-family: 'Open Sans', 'ui-sans-serif', 'system-ui', 'sans-serif', "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +} + +/* Test Status Badge - Modern gradient style */ +.test-status-badge { + position: relative; + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.3rem 0.75rem; + border: 1px solid #d1d5db; + border-radius: 6px; + font-size: 0.7rem; + font-weight: 600; + line-height: 1; + margin-top: 0.5rem; + margin-bottom: 1rem; + letter-spacing: 0.03em; + text-transform: none; + transition: all 0.2s ease; + cursor: default; +} + +.test-status-passed { + background: none; + color: #111827; + box-shadow: none; +} + +.test-status-passed:hover { + transform: translateY(-1px); +} + +.test-status-passed .test-status-icon { + fill: #059669; +} + +.dark .test-status-passed { + background: none; + color: #f9fafb; + box-shadow: none; + border-color: #9ca3af; +} + +.dark .test-status-passed:hover { + box-shadow: none; +} + +.dark .test-status-passed .test-status-icon { + fill: #34d399; +} + +.test-status-icon { + width: 0.7rem; + height: 0.7rem; + fill: currentColor; + flex-shrink: 0; +} + +.test-status-text { + white-space: nowrap; +} + +/* Modern tooltip */ +.test-status-tooltip { + position: absolute; + left: 50%; + top: 100%; + transform: translateX(-50%) translateY(8px); + padding: 0.5rem 0.75rem; + background: #1f2937; + color: #ffffff; + font-size: 0.8rem; + font-weight: 500; + line-height: 1.4; + letter-spacing: normal; + text-transform: none; + white-space: nowrap; + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1); + opacity: 0; + visibility: hidden; + transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease; + z-index: 50; + pointer-events: none; +} + +.test-status-tooltip::before { + content: ''; + position: absolute; + left: 50%; + bottom: 100%; + transform: translateX(-50%); + border: 6px solid transparent; + border-bottom-color: #1f2937; +} + +.test-status-badge:hover .test-status-tooltip { + opacity: 1; + visibility: visible; + transform: translateX(-50%) translateY(6px); +} + +.dark .test-status-tooltip { + background: #374151; + color: #f3f4f6; +} + +.dark .test-status-tooltip::before { + border-bottom-color: #374151; +} + +/* Theme-toggle dropdown — fix checkmark/text overlap. + Hextra's hx:ltr:pl-3, hx:ltr:pr-9, hx:py-1.5, and hx:ltr:right-3 live inside + @layer utilities in main.css. Tailwind v3's unlayered button { padding:0 } + preflight in styles.css beats any @layer rule regardless of specificity, so the + right padding that makes room for the checkmark never applies. Override with + explicit values here (unlayered + !important beats everything). */ +.hextra-theme-toggle-options button[role="menuitemradio"] { + padding-left: 0.75rem !important; /* hx:ltr:pl-3 — 3 × 0.25rem */ + padding-right: 2.25rem !important; /* hx:ltr:pr-9 — 9 × 0.25rem */ + padding-top: 0.375rem !important; /* hx:py-1.5 — 1.5 × 0.25rem */ + padding-bottom: 0.375rem !important; +} +.hextra-theme-toggle-options button[role="menuitemradio"] > span { + right: 0.75rem !important; /* hx:ltr:right-3 — 3 × 0.25rem */ +} + +/* Theme-toggle dropdown container — hx:border and hx:shadow-lg also live in + @layer utilities, so the same @layer vs unlayered-preflight conflict applies. + Tailwind v3's * { border-width: 0 } erases the dropdown border, and + * { --tw-shadow: 0 0 #0000 } zeros the variable used by hx:shadow-lg, so + no shadow renders. Dark-mode border color also needs a fix because + * { border-color: #e5e7eb } (light gray) beats the layered neutral-700. */ +.hextra-theme-toggle-options { + border-width: 1px !important; + border-style: solid !important; + border-color: var(--hx-color-gray-200) !important; + box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1) !important; +} +.dark .hextra-theme-toggle-options { + border-color: var(--hx-color-neutral-700) !important; +} + +/* Dark mode code block scrollbar track */ +.dark pre::-webkit-scrollbar-track { + background: #1e1e1e; +} +.dark pre::-webkit-scrollbar { + height: 8px; +} +.dark pre::-webkit-scrollbar-thumb { + background: #444; + border-radius: 4px; +} +.dark pre { + scrollbar-color: #444 #1e1e1e; +} + +.dark .provider-icon-invert-dark { + filter: invert(1); +} + +/* Sidebar link styling — match TOC text color */ +.sidebar-link:not(.sidebar-active-item) { + color: #6b7280; +} +.sidebar-link:not(.sidebar-active-item):hover { + color: #111827; + background: #f3f4f6; +} +.sidebar-link.sidebar-active-item { + color: #1e40af; + background: #dbeafe; +} +.dark .sidebar-link:not(.sidebar-active-item) { + color: #9ca3af !important; +} +.dark .sidebar-link:not(.sidebar-active-item):hover { + color: #e5e7eb !important; + background: rgba(255,255,255,0.05) !important; +} +.dark .sidebar-link.sidebar-active-item { + color: #c7d2fe !important; + background: rgba(99,102,241,0.1) !important; +} + +.dark .sidebar-container { + background-color: #111 !important; +} +.sidebar-nav { + color: #6b7280; +} +.dark .sidebar-nav { + color: #9ca3af !important; +} + +/* Hextra tabs - data-state show/hide and active styling */ +.hextra-tabs-panel { + display: none; +} +.hextra-tabs-panel[data-state="selected"] { + display: block; + padding-top: 1.5rem; +} +.hextra-tabs-toggle { + cursor: pointer; + padding: 0.5rem; + margin-right: 0.5rem; + font-weight: 500; + border-bottom: 2px solid transparent; + color: #4b5563; + background: none; + border-top: none; + border-left: none; + border-right: none; + transition: color 0.15s, border-color 0.15s; +} +.hextra-tabs-toggle:hover { + color: #000; + border-bottom-color: #d1d5db; +} +.hextra-tabs-toggle[data-state="selected"] { + color: hsl(212, 100%, 45%); + border-bottom-color: hsl(212, 100%, 50%); +} +.dark .hextra-tabs-toggle { + color: #d1d5db; +} +.dark .hextra-tabs-toggle:hover { + color: #fff; + border-bottom-color: #4b5563; +} +.dark .hextra-tabs-toggle[data-state="selected"] { + color: hsl(212, 100%, 60%); + border-bottom-color: hsl(212, 100%, 50%); +} + +/* Light/dark image toggling */ +.light-only { display: block; } +.dark-only { display: none; } +.dark .light-only { display: none; } +.dark .dark-only { display: block; } + +/* Dark mode: page, sidebar, footer, toc, AND the navbar share one bg (#030712). + The navbar's bg lives on .hextra-nav-container-blur, which Hextra hardcodes to + var(--hx-color-dark) (#111) with !important — a lighter gray than the page — so + it must be listed here (higher specificity + !important) to match. Otherwise + the top nav reads as a different shade than the rest of the page in dark mode. */ +.dark body, +.dark .hextra-footer, +.dark .sidebar-container, +.dark .hextra-toc, +.dark .hextra-nav-container-blur { + background-color: #030712 !important; +} + +/* Center all footer content on all screen sizes */ +.hextra-custom-footer { + margin-left: auto; + margin-right: auto; +} +.hextra-footer > .hextra-max-footer-width:not(.hextra-custom-footer) { + justify-content: center !important; +} +.hextra-footer > .hextra-max-footer-width:not(.hextra-custom-footer) > div { + align-items: center !important; +} + +/* Generated card grids — top-align content */ +.section-cards .section-card { + justify-content: flex-start !important; +} +.section-cards .section-card > .hx\:mt-auto { + margin-top: 0 !important; +} + +/* {{< cards >}} shortcode — responsive grid */ +.section-cards { + display: grid; + gap: 1rem; + margin-top: 1rem; + grid-template-columns: 1fr; +} + +@media (min-width: 640px) { + .section-cards { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 1024px) { + .section-cards { + grid-template-columns: repeat(var(--section-cards-cols, 3), minmax(0, 1fr)); + } +} + + + +/* Spacing between headings and following content. Needed because reuse + shortcode output has no

wrapper, so there's no margin-top from + the next element. Using padding-bottom avoids doubling up with + margin collapsing when a proper

does follow. */ +/* Space between headings and following content. Needed because reuse + shortcode output often has no

wrapper, leaving bare text/links + with no margin-top to create a gap after the heading. */ +.content :is(h1, h2, h3, h4, h5, h6) { + margin-bottom: 0.75rem !important; +} + +/* Space between text and code blocks inside list items and after bare text */ +.content li > .hextra-code-block, +.content li > pre { + margin-top: 0.75rem; +} + +/* Sidebar child indent border - dark mode */ +.dark .sidebar-container ul[style*="border-left"] { + border-left-color: #374151 !important; +} + + + +/* ── Print styles ─────────────────────────────────────────────────────── */ +@media print { + @page { margin: 1.5cm 2cm; } + + /* Hide UI chrome — sidebar/TOC already have hx:print:hidden from hextra */ + .copy-md-wrapper, + .navbar, + .desktop-navbar, + .mobile-nav-bar, + .mobile-nav, + .hextra-nav-container, + footer, + .hextra-component-issue, + [class*="pager"], + [class*="page-feedback"], + [class*="last-updated"], + [class*="comments"], + #chatbot-widget { display: none !important; } + + /* Let article fill the printable area */ + body, html { overflow: visible !important; } + article { + display: block !important; + width: 100% !important; + max-width: 100% !important; + padding-right: 0 !important; + min-height: 0 !important; + } + article > main { + max-width: 100% !important; + padding-left: 0 !important; + padding-right: 0 !important; + } + + /* Fix the main cause: code blocks clip at the paper edge on screen overflow */ + pre, code { + white-space: pre-wrap !important; + overflow: visible !important; + word-break: break-word !important; + max-width: 100% !important; + } + + /* Chroma lntable: the general pre/code rules above collapse the line-number + column at page breaks, causing two-digit numbers to split across lines. + Undo word-break and max-width constraints for that column only. */ + .lntable { width: 100%; } + .lntable .lntd:first-child pre, + .lntable .lntd:first-child code { + white-space: pre !important; + word-break: normal !important; + overflow-wrap: normal !important; + max-width: none !important; + min-width: 2.5em; + } + + /* Avoid breaking inside short blocks; don't force headings to next page */ + blockquote, figure, img { break-inside: avoid; } +} + + +/* ── Top-nav dropdown popover (Docs → kagent/kmcp) ───────────────────── + The Docs menu item has child entries, so Hextra renders it as a dropdown + whose popover is

    . Hextra styles that + popover with hx: utility classes for the background, border, radius, and + shadow, but in this extras/Tailwind build the border/shadow rely on runtime + --tw-* vars that do not materialize here, so the box renders invisibly (white + on the white page). Style it explicitly — same values as agw-oss' + .navbar-dropdown-content — so the popover reads as a distinct card. */ +.hextra-nav-menu-items { + padding: 0.5rem; + background-color: white; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 0.5rem; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); +} +:where(.dark, .dark *) .hextra-nav-menu-items { + background-color: rgb(17, 24, 39); /* gray-900 */ + border-color: rgba(255, 255, 255, 0.1); +} + +/* Dropdown item spacing lives here, NOT in hx: utility classes: ad-hoc hx: + spacing values (gap-3, px-4, py-2.5, …) that Hextra core doesn't already use + are not generated in this Tailwind build, so they silently no-op. */ +.hextra-nav-menu-items a { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.5rem 1rem; + border-radius: 0.375rem; +} + +/* Product icons in the Docs dropdown (assets/icons/nav-*.svg, inlined by + navbar-link.html). Fixed-width, right-aligned icon column so (a) the labels + line up and (b) the gap to each label is uniform even though the marks differ + in aspect ratio (kagent is wide, kmcp square). Icons inherit currentColor. */ +.nav-menu-icon { + width: 1.4rem; + flex: none; + justify-content: flex-end; +} +.nav-menu-icon svg { + height: 1rem; + width: auto; + max-width: 100%; + display: block; +} + +/* ── Navbar logo light/dark switch ──────────────────────────────────────── + The two logo s rely on Hextra utilities (hx:md:block, hx:md:dark:block, + hx:dark:hidden) to show exactly one per theme, but several of those aren't in + Hextra's prebuilt main.css, so the switch fails and BOTH render (most visibly + in dark mode). Drive it explicitly off the .dark class, keyed on the SVG src. + Scoped to md+ so the existing mobile behavior (no navbar logo) is untouched. */ +@media (min-width: 768px) { + .hextra-nav-container img[src*="kagent-logo-light"] { display: block; } + .hextra-nav-container img[src*="kagent-logo-dark"] { display: none; } + :where(.dark, .dark *) .hextra-nav-container img[src*="kagent-logo-light"] { display: none; } + :where(.dark, .dark *) .hextra-nav-container img[src*="kagent-logo-dark"] { display: block; } +} diff --git a/docs-site/assets/css/postcss.config.js b/docs-site/assets/css/postcss.config.js new file mode 100644 index 00000000..86f7c7b7 --- /dev/null +++ b/docs-site/assets/css/postcss.config.js @@ -0,0 +1,21 @@ +const themeDir = __dirname + '/../../'; + +module.exports = { + plugins: [ + require('postcss-import')({ + path: [themeDir] + }), + require('tailwindcss/nesting'), + require('tailwindcss')(themeDir + 'assets/css/tailwind.config.js'), + ...(process.env.HUGO_ENVIRONMENT === 'production' ? [require('autoprefixer')({ + // Hugo runs PostCSS with Node filesystem permissions. Keep Browserslist + // from walking parent directories for config or browserslist-stats.json. + stats: {}, + overrideBrowserslist: [ + '> 0.5%', + 'last 2 versions', + 'not dead' + ] + }),] : []) + ] +} diff --git a/docs-site/assets/css/styles.css b/docs-site/assets/css/styles.css new file mode 100644 index 00000000..cdcd0102 --- /dev/null +++ b/docs-site/assets/css/styles.css @@ -0,0 +1,16 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@import 'chatbot.css'; +@import 'custom.css'; + +.nav-container a img { + height: 25px; + width: 165px; +} + +.content, .sidebar-container, .hextra-toc, .hx-text-base { + font-family: 'Open Sans', 'ui-sans-serif', 'system-ui', 'sans-serif', '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Noto Color Emoji"' +} + diff --git a/docs-site/assets/css/tailwind.config.js b/docs-site/assets/css/tailwind.config.js new file mode 100644 index 00000000..cbde6f10 --- /dev/null +++ b/docs-site/assets/css/tailwind.config.js @@ -0,0 +1,55 @@ +const themeDir = __dirname + '/../../'; +// const defaultTheme = require('tailwindcss/defaultTheme') + +const disabledCss = { + 'code::before': false, + 'code::after': false, + 'blockquote p:first-of-type::before': false, + 'blockquote p:last-of-type::after': false, + pre: false, + code: false, + 'pre code': false, + 'code::before': false, + 'code::after': false, +} + +module.exports = { + darkMode: 'class', + content: [ + `${themeDir}/hugo_stats.json`, + ], + theme: { + extend: { + colors: { + 'primary-bg': '#030712', + 'secondary-bg': '#10141f', + 'tertiary-bg': '#1c2029', + 'primary-text': 'rgb(249, 250, 251)', + 'secondary-text': 'rgb(156, 163, 175)', + 'tertiary-text': '#7734be', + 'primary-border': 'rgba(139, 92, 246, 0.5)', + 'secondary-border': '#1F2937' + }, + spacing: { + '25': '6.25rem', + '50': '12.5rem', + }, + typography: { + DEFAULT: { css: disabledCss }, + base: { css: disabledCss }, + sm: { css: disabledCss }, + lg: { css: disabledCss }, + xl: { css: disabledCss }, + '2xl': { css: disabledCss }, + }, + backgroundImage: { + 'hero-pattern': "url('/hero-pattern.svg')", + }, + fontFamily: { + 'sans': ['ui-sans-serif', 'system-ui', 'sans-serif', '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Noto Color Emoji"'], + } + }, + }, + variants: {}, + plugins: [require('@tailwindcss/typography'),] +} \ No newline at end of file diff --git a/docs-site/assets/icons/nav-kagent.svg b/docs-site/assets/icons/nav-kagent.svg new file mode 100644 index 00000000..b901c4df --- /dev/null +++ b/docs-site/assets/icons/nav-kagent.svg @@ -0,0 +1 @@ + diff --git a/docs-site/assets/icons/nav-kmcp.svg b/docs-site/assets/icons/nav-kmcp.svg new file mode 100644 index 00000000..10cff4c7 --- /dev/null +++ b/docs-site/assets/icons/nav-kmcp.svg @@ -0,0 +1 @@ + diff --git a/docs-site/assets/versions/agent-substrate.md b/docs-site/assets/versions/agent-substrate.md new file mode 100644 index 00000000..1750564f --- /dev/null +++ b/docs-site/assets/versions/agent-substrate.md @@ -0,0 +1 @@ +0.0.6 diff --git a/docs-site/assets/versions/jaeger.md b/docs-site/assets/versions/jaeger.md new file mode 100644 index 00000000..c966188e --- /dev/null +++ b/docs-site/assets/versions/jaeger.md @@ -0,0 +1 @@ +4.4.7 diff --git a/docs-site/assets/versions/kagent.md b/docs-site/assets/versions/kagent.md new file mode 100644 index 00000000..7e310bae --- /dev/null +++ b/docs-site/assets/versions/kagent.md @@ -0,0 +1 @@ +0.9.9 diff --git a/docs-site/assets/versions/kmcp.md b/docs-site/assets/versions/kmcp.md new file mode 100644 index 00000000..0d91a54c --- /dev/null +++ b/docs-site/assets/versions/kmcp.md @@ -0,0 +1 @@ +0.3.0 diff --git a/docs-site/assets/versions/loki.md b/docs-site/assets/versions/loki.md new file mode 100644 index 00000000..2496b04b --- /dev/null +++ b/docs-site/assets/versions/loki.md @@ -0,0 +1 @@ +6.24.0 diff --git a/docs-site/assets/versions/tempo.md b/docs-site/assets/versions/tempo.md new file mode 100644 index 00000000..15b989e3 --- /dev/null +++ b/docs-site/assets/versions/tempo.md @@ -0,0 +1 @@ +1.16.0 diff --git a/docs-site/content/_index.md b/docs-site/content/_index.md new file mode 100644 index 00000000..3d338eca --- /dev/null +++ b/docs-site/content/_index.md @@ -0,0 +1,8 @@ +--- +title: "Documentation" +linkTitle: "Docs" +cascade: + type: docs +--- + +kagent and kmcp documentation. diff --git a/docs-site/content/kagent/_index.md b/docs-site/content/kagent/_index.md new file mode 100644 index 00000000..3174841b --- /dev/null +++ b/docs-site/content/kagent/_index.md @@ -0,0 +1,36 @@ +--- +title: kagent +description: Complete documentation for kagent - the AI agent platform for Kubernetes. +weight: 1 +author: kagent.dev +--- + +Your complete guide to the AI agent platform for Kubernetes + +## What is kagent? + +kagent is an innovative AI agent platform designed specifically for Kubernetes environments. +It empowers developers and operations teams to create intelligent, autonomous agents that can +monitor, manage, and automate complex Kubernetes workloads using the power of large language models (LLMs). + +kagent was created at [Solo.io](https://www.solo.io) in 2025 and is a [Cloud Native Computing Foundation](https://www.cncf.io) sandbox project. + +## Key Features + +- **AI-Powered Automation** - Create intelligent agents that understand natural language and can perform complex Kubernetes operations +- **Multi-Provider Support** - Works with OpenAI, Anthropic, Google Vertex AI, Azure OpenAI, Ollama, and custom models +- **Tool Integration** - Supports Model Context Protocol (MCP) tools, built-in Kubernetes tools, and custom HTTP tools +- **Agent-to-Agent Communication** - Enable sophisticated workflows through A2A (Agent-to-Agent) interactions +- **Comprehensive Observability** - Built-in tracing and monitoring to understand agent behavior and performance +- **Cloud Native** - Designed from the ground up to run natively in Kubernetes environments + +## Why Choose kagent? + +Whether you're looking to automate routine operations, implement intelligent monitoring, +or create sophisticated multi-agent workflows, kagent provides the tools and framework +to bring AI to your Kubernetes infrastructure. Start with simple automation and scale +to complex, intelligent systems that can reason about your cluster's state and make +informed decisions. + +## Explore the Documentation + diff --git a/docs-site/content/kagent/concepts/_index.md b/docs-site/content/kagent/concepts/_index.md new file mode 100644 index 00000000..faa838ba --- /dev/null +++ b/docs-site/content/kagent/concepts/_index.md @@ -0,0 +1,25 @@ +--- +title: Core Concepts +description: Understand the fundamental concepts and architecture of kagent. +weight: 4 +author: kagent.dev +--- + +Learn about the AI agent and kagent concepts + +{{< cards >}} +{{< card link="/docs/kagent/introduction/what-is-kagent" title="What is kagent" subtitle="Learn about the kagent features." >}} +{{< card link="/docs/kagent/concepts/architecture" title="Architecture" subtitle="Learn about the architecture of kagent." >}} +{{< card link="/docs/kagent/concepts/agents" title="Agents" subtitle="Learn about AI agents." >}} +{{< card link="/docs/kagent/concepts/tools" title="Tools" subtitle="Learn about tools and MCP." >}} +{{< card link="/docs/kagent/concepts/agent-harness" title="Agent Harness" subtitle="Run OpenClaw and Hermes coding-agent sandboxes on Agent Substrate and chat with them over ACP." >}} +{{< card link="/docs/kagent/concepts/agent-substrate" title="Agent Substrate" subtitle="Run declarative agents on a Kubernetes-native runtime with fast startup, efficient resource usage, and secure gVisor-sandboxed execution." >}} +{{< card link="/docs/kagent/resources/tools-ecosystem" title="Tools Ecosystem" subtitle="Comprehensive catalog of built-in tools for Kubernetes, Helm, Istio, Prometheus, Grafana, Cilium, and Argo Rollouts." >}} +{{< card link="/docs/kagent/examples/human-in-the-loop" title="Human-in-the-Loop" subtitle="Configure tool approval gates and interactive user prompts for agent oversight." >}} +{{< card link="/docs/kagent/concepts/agent-memory" title="Agent Memory" subtitle="Enable vector-backed long-term memory for agents to learn from past interactions." >}} +{{< card link="/docs/kagent/concepts/agents#prompt-templates" title="Prompt Templates" subtitle="Compose reusable prompt fragments from ConfigMaps using Go template syntax." >}} +{{< card link="/docs/kagent/examples" title="Multi-Runtime Support" subtitle="Choose between Go and Python ADK runtimes for your agents." >}} +{{< card link="/docs/kagent/concepts/agents#git-based-skills" title="Git-Based Skills" subtitle="Load markdown knowledge documents from Git repositories to guide agent behavior." >}} +{{< card link="/docs/kagent/concepts/agents#context-management" title="Context Management" subtitle="Automatically manage conversation history to stay within LLM context windows." >}} +{{< /cards >}} + diff --git a/docs-site/content/kagent/concepts/agent-harness.md b/docs-site/content/kagent/concepts/agent-harness.md new file mode 100644 index 00000000..ab4455fe --- /dev/null +++ b/docs-site/content/kagent/concepts/agent-harness.md @@ -0,0 +1,97 @@ +--- +title: Agent Harness +description: Understand AgentHarness resources, Substrate-backed execution environments, and how kagent talks to them over the Agent Client Protocol (ACP). +weight: 4 +author: kagent.dev +--- + +An `AgentHarness` is a Kubernetes custom resource that asks kagent to provision a long-running remote execution environment on [Agent Substrate](/docs/kagent/concepts/agent-substrate). It is useful when you want a managed sandbox that runs a coding agent (such as OpenClaw or Hermes) that you can chat with and connect to messaging channels, but you do not want kagent to package and run a full agent runtime inside the workload. + +`AgentHarness` resources appear alongside agents in kagent APIs and status views, but they are not the same thing as `Agent` or `SandboxAgent`. + +## How it differs from agents + +- `Agent` runs a kagent-managed agent runtime, such as a declarative agent or a bring-your-own container. +- `SandboxAgent` runs a (Go) declarative agent runtime inside a sandboxed Agent Substrate actor. +- `AgentHarness` provisions the execution environment itself and runs a third-party coding agent inside it. The selected backend decides what is installed and how the environment is bootstrapped. + +Think of `AgentHarness` as lifecycle management for a remote coding-agent sandbox. It gives kagent a Kubernetes-native handle for creating, tracking, deleting, and surfacing that environment, plus a standard chat surface to interact with it. + +## Backend model + +The `spec.backend` field selects the backend implementation. + +| Backend | Purpose | +| --- | --- | +| `openclaw` | Provisions an OpenClaw-compatible sandbox and writes OpenClaw configuration when a `ModelConfig` is referenced. | +| `hermes` | Provisions a Hermes sandbox and writes Hermes configuration plus environment files for supported messaging channels. | + +All backends use the same top-level `AgentHarness` shape: `backend`, `substrate`, `description`, `image`, `env`, `modelConfigRef`, and `channels`. + +## Runtime: Agent Substrate + +Every `AgentHarness` runs on [Agent Substrate](/docs/kagent/concepts/agent-substrate). The `spec.substrate` field is required and configures the Substrate provisioning stack: + +- `workerPoolRef` — references an existing `WorkerPool` in the harness namespace. When unset, the controller uses its configured default WorkerPool. +- `snapshotsConfig` — configures where actor memory snapshots are stored. Defaults to `gs://ate-snapshots//` when unset. +- `workloadImage` — overrides the default backend sandbox image used in the generated `ActorTemplate`. + +When the controller reconciles an `AgentHarness`, it generates a per-harness `ActorTemplate` and waits for its golden snapshot to become Ready. A single shared actor is then created on demand from that template on the first chat connection. Every chat is multiplexed as an ACP session inside that one long-lived actor. + +## Lifecycle and status + +The resource reports these primary conditions: + +- `Accepted` tells you whether kagent accepted the spec and could hand it to the selected backend. +- `Ready` tells you whether the harness `ActorTemplate` golden snapshot is ready. Once ready, the harness can serve chat sessions. + +`.status.backendRef` records the backend and instance ID, and `.status.connection.endpoint` contains the connection hint returned by kagent. + +## Chatting with a harness over ACP + +kagent talks to harness backends using the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/), a JSON-RPC protocol for driving coding agents. Both OpenClaw and Hermes implement ACP. + +Because Substrate exposes only network ingress into actors (no SSH or exec), kagent runs an in-sandbox `acp-shim` that bridges the agent's stdio ACP server to a WebSocket endpoint. The kagent controller connects to that endpoint and exposes the harness as a regular agent in the kagent UI and API: + +```mermaid +flowchart TB + client["kagent UI / A2A client"] + controller["kagent controller
    A2A↔ACP bridge (ACP client)"] + subgraph actor["Substrate actor"] + shim["acp-shim (WS ↔ stdio)"] + backend["openclaw acp / hermes acp"] + shim --> backend + end + client -->|"A2A (JSON-RPC over HTTP/SSE)"| controller + controller -->|"ACP over WebSocket (Substrate ingress)"| shim + client:::external + controller:::internal + shim:::internal + backend:::internal + classDef internal stroke:#a78bfa,fill:transparent + classDef external stroke:#fb923c,fill:transparent + style actor stroke:#2962FF,fill:transparent +``` + +This means you can open a harness in the kagent UI and chat with it like any other agent — see streamed tool activity and answer tool-approval prompts — without any backend-specific UI. Tool approvals from the harness map onto kagent's human-in-the-loop flow. + +## Models and images + +`spec.modelConfigRef` points at a kagent `ModelConfig`. OpenClaw-compatible backends translate that model configuration into OpenClaw bootstrap config. Hermes uses the referenced model while building its Hermes configuration. + +If `spec.image` is omitted, kagent uses the default sandbox base image for the selected backend. Set `spec.image` only when you have a backend-compatible custom image. + +## Channels + +`spec.channels` declares the external messaging platform (such as Slack) that you want to integrate with the harness. Each channel has a stable `name`, a `type`, and exactly one matching channel spec. + +Slack has backend-specific settings because OpenClaw and Hermes use Slack differently: + +- OpenClaw settings live under `slack.openclaw` and configure channel access, allowlisted Slack channels, and interactive replies. +- Hermes settings live under `slack.hermes` and configure allowed Slack users plus the home channel used for scheduled messages. + +The API uses CEL validation to ensure Slack settings match the selected backend. A Hermes harness must use `slack.hermes`; an OpenClaw harness must use `slack.openclaw`. + +## Next steps + +For enabling Agent Substrate so the controller can provision harnesses, see [Enable AgentHarness support](/docs/kagent/introduction/installation#enable-agentharness-support). For complete YAML examples, including Slack token references and backend-specific Slack settings, see the [Agent Harness example](/docs/kagent/examples/agent-harness). For the generated schema, see the [API reference](/docs/kagent/resources/api-ref#agentharness). diff --git a/docs-site/content/kagent/concepts/agent-memory.md b/docs-site/content/kagent/concepts/agent-memory.md new file mode 100644 index 00000000..3e85e470 --- /dev/null +++ b/docs-site/content/kagent/concepts/agent-memory.md @@ -0,0 +1,188 @@ +--- +title: Agent Memory +description: Enable vector-backed long-term memory for agents to learn from past interactions. +weight: 6 +author: kagent.dev +--- + +With agent memory, your agents can automatically save and retrieve relevant context across conversations using vector similarity search. Memory is built on top of the Google ADK memory implementation. + +## Overview + +Agent memory provides the following capabilities. + +- **Vector-backed.** A basic vector store uses embedding models to encode memories as 768-dimensional vectors. +- **Searchable.** Agents retrieve relevant memories via cosine similarity. +- **Automatic.** Agents extract and save user intent, key learnings, and preferences without explicit user action. +- **Time-bounded.** Memories expire after a configurable time to live (TTL), which defaults to 15 days. +- **Metadata.** Memories include timestamps and source session references. +- **Shared storage.** Memory uses the kagent database (PostgreSQL), not a separate database. + +## Configure memory + +### Install kagent with Postgres + +To use memory, you must install kagent with a Postgres database that has the `pgvector` extension installed and vector enabled. For more information, see the [Database configuration](/docs/kagent/operations/operational-considerations#database-configuration) section. + +Example Helm configuration for your own external Postgres: + +```yaml +database: + postgres: + urlFile: /var/secrets/db-url + vectorEnabled: true + bundled: + enabled: false +controller: + volumes: + - name: db-secret + secret: + secretName: my-postgres-url-secret + volumeMounts: + - name: db-secret + mountPath: /var/secrets + readOnly: true +``` + +### Enable memory on an agent + +To enable memory, set the `memory` field on the declarative agent spec, as shown in the following YAML example. The `modelConfig` field references a `ModelConfig` object whose embedding provider generates memory vectors. + +You can also configure memory in the kagent UI when you create or edit an agent. In the UI, select an embedding model and set the memory TTL. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: Agent +metadata: + name: memory-agent + namespace: kagent +spec: + type: Declarative + declarative: + modelConfig: default-model-config + systemMessage: "You are a helpful assistant with long-term memory." + memory: + modelConfig: default-model-config # References the embedding provider +``` + +The embedding `ModelConfig` does not have to use the same provider as the agent's main LLM. kagent supports several embedding providers, including Amazon Bedrock as shown in the following section. + +### ModelConfig example: Amazon Bedrock + +To use [Amazon Bedrock Titan embedding models](https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html), create a `ModelConfig` with `provider: Bedrock`. + +The Bedrock provider uses the standard AWS credential chain, so no API key secret is required. The agent's pod must have AWS credentials with the `bedrock:InvokeModel` permission for the chosen model. On Kubernetes, the recommended setup is [EKS IRSA on the agent ServiceAccount](/docs/kagent/supported-providers/amazon-bedrock#step-3-configure-the-agent-to-use-an-iam-role). + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: bedrock-embed + namespace: kagent +spec: + provider: Bedrock + model: amazon.titan-embed-text-v2:0 + bedrock: + region: us-east-1 +``` + +| Setting | Description | +| --- | --- | +| `provider` | Set to `Bedrock`. | +| `model` | The Bedrock embedding model ID, such as `amazon.titan-embed-text-v2:0` or `amazon.titan-embed-text-v1`. Note that Titan v1 produces 1536-dimensional vectors and Titan v2 produces 1024-dimensional vectors. kagent truncates and L2-normalizes both to the 768-dimensional vector store, so no model-specific dimension setting is required. | +| `bedrock.region` | The AWS region where the model is available, for example `us-east-1`. | + +Reference the embedding `ModelConfig` from the agent's `memory.modelConfig` field: + +```yaml +spec: + declarative: + memory: + modelConfig: bedrock-embed +``` + +### Optional: Custom TTL + +To change the default memory retention period of 15 days, set the `ttlDays` field. + +```yaml +memory: + modelConfig: default-model-config + ttlDays: 30 # Memories expire after 30 days instead of the default 15 +``` + +## Work with memories + +Review the following sections to understand what your agents can do with memory. + +### Automatic save cycle + +1. The agent processes user messages normally. +2. Every 5th user message, the agent automatically extracts key information such as user intent, key learnings, and preferences. +3. The agent summarizes extracted memories and encodes them as embedding vectors. +4. The agent stores the vectors in the database with metadata and timestamps. + +### Memory retrieval (prefetch) + +Before generating a response, the agent performs the following steps. + +1. Encodes the current user message as an embedding vector. +2. Searches stored memories by cosine similarity. +3. Injects the most relevant memories into the agent's context. + +### Memory tools + +When you enable memory, the agent receives three additional tools. + +| Tool | Description | +|------|-------------| +| `save_memory` | Explicitly save a piece of information. | +| `load_memory` | Search for relevant memories by query. | +| `prefetch_memory` | Automatically run before the agent generates a response to retrieve relevant memories. | + +You can also instruct the agent to use `save_memory` or `load_memory` explicitly during a conversation. + +### View memories in the UI + +In the kagent UI, you can view the memories that an agent has saved. With saved memories, you can inspect what the agent has learned and retained from past interactions. + +### Manage memories via API + +The following API endpoints let you manage memories programmatically. + +Add a memory: + +``` +POST /api/memories/sessions +``` + +Add memories in batch: + +``` +POST /api/memories/sessions/batch +``` + +Search memories by cosine similarity: + +``` +POST /api/memories/search +``` + +List memories: + +``` +GET /api/memories?agent_name=X&user_id=Y +``` + +Delete all memories for an agent: + +``` +DELETE /api/memories?agent_name=X&user_id=Y +``` + +## Known limitations + +- **No per-memory deletion.** You can delete all memories for an agent, but you cannot delete individual memory entries. +- **No cross-agent memory sharing.** Each agent has its own isolated memory store. You cannot share memories across agents. +- **Not pluggable.** Memory is built on the Google ADK memory implementation and cannot be swapped for an alternative memory solution (such as Cognee). However, if an alternative memory solution exposes an [MCP server](/docs/kagent/concepts/tools#mcp-tools), you can add it as a tool and instruct the agent to use it instead of the built-in memory. + diff --git a/docs-site/content/kagent/concepts/agent-substrate.md b/docs-site/content/kagent/concepts/agent-substrate.md new file mode 100644 index 00000000..85e7ff20 --- /dev/null +++ b/docs-site/content/kagent/concepts/agent-substrate.md @@ -0,0 +1,76 @@ +--- +title: Agent Substrate +description: Run declarative agents on Agent Substrate — a Kubernetes-native runtime that delivers fast startup, efficient resource usage, and secure sandboxed execution. +weight: 5 +author: kagent.dev +--- + +Agent Substrate is a Kubernetes-native runtime for running AI agents and other stateful workloads efficiently. Instead of dedicating one pod per agent — which wastes capacity while agents sit idle — Substrate decouples an agent's lifecycle from pod infrastructure. Idle agents are snapshotted to object storage and rehydrated on demand, so a small pool of pre-warmed workers can host far more agents than there are pods. + +kagent can run workloads on Agent Substrate in two ways: + +- **Declarative agents** — A declarative `Agent` describes its model, instructions, and tools (see [Agents](/docs/kagent/concepts/agents)). Its sandboxed variant, the [`SandboxAgent`](/docs/kagent/resources/api-ref) CRD, lets you run a (Go) declarative agent on Agent Substrate. +- **AgentHarness** — The [`AgentHarness`](/docs/kagent/concepts/agent-harness) CRD provisions a long-running execution environment for a coding agent (OpenClaw or Hermes). It always runs on Agent Substrate: kagent generates a per-harness `ActorTemplate` and creates an `Actor` from it on demand, referencing a `WorkerPool` for capacity. + +## Why Agent Substrate + +- **Fast startup** — Agents cold-start by restoring a compressed snapshot rather than booting a fresh pod, so they resume in a fraction of the time. +- **Efficient resource usage** — A pool of pre-warmed workers multiplexes many actors across far fewer pods, persisting idle actors to object storage instead of holding a pod each. +- **Secure execution** — Each workload runs inside a gVisor sandbox, isolating untrusted agent code from the host and from other actors. +- **Declarative management** — WorkerPools and ActorTemplates are Kubernetes CRDs, so the runtime is configured and versioned with the same GitOps workflow as the rest of your platform. + +## Core concepts + +| Term | Definition | +| --- | --- | +| **Actor** | An individual agent instance with isolated state, managed by Substrate. | +| **WorkerPool** | A CRD declaring the pool of pre-warmed gVisor worker pods that host actors. | +| **ActorTemplate** | A CRD defining an actor's configuration and lifecycle behavior. kagent generates one per `AgentHarness`. | +| **Snapshot** | A compressed (Zstd) checkpoint of actor state in object storage that enables suspension and fast restoration. | +| **Session** | The execution context that tracks an actor's activity and checkpoints. | + +## How it works + +When an agent is invoked, Substrate restores its actor onto an available worker from the WorkerPool — rehydrating from a snapshot if the actor was idle. The agent runs inside a gVisor sandbox for the duration of the session. When the actor goes idle, its state is checkpointed back to object storage and the worker is freed to host another actor. This snapshot-and-restore cycle is what lets a single worker pool serve many more agents than a pod-per-agent model. + +## Architecture + +Agent Substrate is composed of a control plane, a data plane, and snapshot storage: + +**Control plane** + +- `ateapi` — gRPC API and workflow engine, backed by Redis. +- `atecontroller` — the Kubernetes reconciler for `WorkerPool` and `ActorTemplate` resources. + +**Data plane** + +- `atenet` — an L7 proxy and DNS routing layer that directs traffic to actors. +- `atelet` — a DaemonSet that manages snapshot uploads and downloads on each node. +- `ateom` — the worker-pod supervisor that communicates with the gVisor runtime. + +**Storage** + +- Zstd-compressed checkpoint snapshots stored in object storage (GCS or S3). + +## Using Agent Substrate with AgentHarness and Declarative agents + +### Declarative agents + +Run a (Go) declarative agent on Agent Substrate by creating a `SandboxAgent` resource. It carries the same spec as a regular `Agent`, but the kagent controller runs it as a sandboxed workload on the runtime instead of a plain Deployment. + +### AgentHarness + +An `AgentHarness` always runs on Agent Substrate; `spec.substrate` is required. The key fields are: + +- `workerPoolRef` — references an existing WorkerPool in the harness namespace. When unset, the controller uses its configured default WorkerPool. +- `snapshotsConfig` — configures where actor memory snapshots are stored. Defaults to `gs://ate-snapshots//` when unset. +- `workloadImage` — overrides the default OpenClaw or Hermes sandbox image used in the generated ActorTemplate. + +kagent talks to the harness over the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/) so you can chat with it from the kagent UI. See the [Agent Harness concept page](/docs/kagent/concepts/agent-harness) for details. + +See the [API reference](/docs/kagent/resources/api-ref) for the full `AgentHarnessSubstrateSpec` schema. + +## Learn more + +- [Run a declarative agent on Agent Substrate](/docs/kagent/examples/agent-substrate) — end-to-end walkthrough on a kind cluster. +- For a deeper dive into the runtime internals, see the [Agent Substrate documentation](https://learn.agentsubstrate.dev/). diff --git a/docs-site/content/kagent/concepts/agents.md b/docs-site/content/kagent/concepts/agents.md new file mode 100644 index 00000000..9cd432b2 --- /dev/null +++ b/docs-site/content/kagent/concepts/agents.md @@ -0,0 +1,333 @@ +--- +title: Agents +description: Dive into the concept of AI agents in kagent, their components (instructions, tools, skills), and how they can even use other agents as tools. +weight: 2 +author: kagent.dev +--- + +An AI agent is an application that can interact with users in natural language. Agents use LLMs to generate responses to user queries and can also execute actions on behalf of the user. + +Each agent consists of the following components: + +- Agent instructions: A set of instructions that define the agent's behavior and capabilities. This is also called a system prompt. +- Tools: Functions that the agent can use to interact with its environment. kagent features built-in tools and has support for accessing tools over the [MCP](https://github.com/modelcontextprotocol). +- Skills: Descriptions of capabilities that help the agent act more autonomously and guide its tool usage and planning. + +## Agent Instructions + +Agent instructions tell the agent what its role is, how to interact with the user, what actions it can take, how to behave and respond to user queries, and how to interact with other agents. Here's an example of simple agent instructions: + +```yaml +You're a Kubernetes agent that can help users manage their Kubernetes resources. +Your responses should be clear and concise; you should provide helpful information and guidance to users. +``` + +Instructions are an important part of the agent's behavior. They define the agent's role and capabilities and help the agent understand its environment and the tasks it can perform. + +Writing good instructions is an art and a science. It requires a good understanding of the task at hand, the tools available, and the user's needs. In order to make it easier to write good instructions, we've created a [system prompt tutorial](/docs/kagent/getting-started/system-prompts) that can help you get started. + +### Prompt templates + +You can use Go `text/template` syntax in system messages to compose reusable fragments stored in ConfigMaps. Instead of duplicating safety guidelines and tool usage instructions across every agent, store them once and reference them with `{{include "alias/key"}}` syntax. The controller resolves templates during reconciliation, so the final system message is fully expanded before reaching the agent runtime. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: Agent +metadata: + name: k8s-agent + namespace: kagent +spec: + type: Declarative + declarative: + modelConfig: default-model-config + promptTemplate: + dataSources: + - kind: ConfigMap + name: kagent-builtin-prompts + alias: builtin + - kind: ConfigMap + name: my-custom-prompts + systemMessage: | + You are a Kubernetes management agent named {{.AgentName}}. + + {{include "builtin/safety-guardrails"}} + {{include "builtin/tool-usage-best-practices"}} + {{include "my-custom-prompts/k8s-specific-rules"}} + + Your tools: {{.ToolNames}} + Your skills: {{.SkillNames}} +``` + +The `kagent-builtin-prompts` ConfigMap ships with five reusable templates. + +| Template Key | Description | +|-------------|-------------| +| `skills-usage` | Instructions for discovering and using skills. | +| `tool-usage-best-practices` | Best practices for tool invocation. | +| `safety-guardrails` | Safety and operational guardrails. | +| `kubernetes-context` | Kubernetes-specific operational context. | +| `a2a-communication` | Agent-to-agent communication guidelines. | + +The following template variables are available in system messages. + +| Variable | Description | +|----------|-------------| +| `{{.AgentName}}` | Name of the Agent resource. | +| `{{.AgentNamespace}}` | Namespace of the Agent resource. | +| `{{.Description}}` | Agent description. | +| `{{.ToolNames}}` | Comma-separated list of tool names. | +| `{{.SkillNames}}` | Comma-separated list of skill names. | + +> **Security Note:** Only ConfigMaps are supported as data sources. Secret references are intentionally excluded to avoid leaking sensitive data into prompts sent to LLM providers. + +## Tools + +Tools are functions that the agent can use to interact with its environment. For example, a Kubernetes agent might have tools to list pods, get pod logs, and describe services. + +Tools definitions and their descriptions are made available to the agent and are sent to the LLMs together with the instructions. Based on the user query, the agent can use the tools to interact with the environment and generate responses. + +For example, we could add the **list_resources** tool to agent that would allow it to list resources in the Kubernetes cluster. The agent will determine based on the user input if it makes sense to invoke any of the available tools. + +If the user asks "List all pods in the cluster", the agent can use the **list_resources** tool to list all pods in the cluster. Note that depending on how the instructions/tools are written and configure, the agent might list all the namespaces first then list all the pods in each namespace. Alternatively, if the **list_resources** tool allows listing resources across namespaces, the agent will pick that option. + +Some tools support additional configuration that can be set in when adding the tool to the agent. For example, any Grafana or Prometheus tools will require an API endpoint URL to be set. + +kagent comes with a set of built-in tools that you can use to interact with your environment. kagent also supports the [MCP (Model Configuration Protocol)](https://modelcontextprotocol.io/introduction) tools. Using MCP, you can bring any external tool into kagent and make it available for your agents to run. + +## Human-in-the-Loop + +kagent supports Human-in-the-Loop (HITL) to keep humans in control of agent actions. You can require user approval before an agent executes sensitive tools, and agents can ask users questions when they need clarification. + +For a hands-on tutorial that walks through setting up HITL with tool approval and the `ask_user` tool, see the [Human-in-the-Loop example](/docs/kagent/examples/human-in-the-loop). + +### Tool approval + +Add `requireApproval` to your agent's tool specification to gate destructive operations. Tools listed in `requireApproval` pause execution and present Approve/Reject buttons in the UI. Tools not listed run without waiting for approval. + +```yaml +tools: + - type: McpServer + mcpServer: + name: kagent-tool-server + kind: RemoteMCPServer + apiGroup: kagent.dev + toolNames: + - k8s_get_resources # runs immediately + - k8s_describe_resource # runs immediately + - k8s_delete_resource # pauses for approval + - k8s_apply_manifest # pauses for approval + requireApproval: + - k8s_delete_resource + - k8s_apply_manifest +``` + +When you reject a tool call, you can provide a reason. This reason is passed back to the LLM as context, so the agent can adjust its approach. + +### Ask User + +Every agent automatically has the built-in `ask_user` tool. It allows agents to pause and ask users questions with optional predefined choices, which is useful for clarifying ambiguous requests or collecting configuration preferences. No configuration for the `ask_user` tool is required. + +## Skills + +Skills are descriptions or even executable implementations of the capabilities that an agent has to act more autonomously. They make the LLM's responses more than just reactions to prompts by orienting them toward goals. + +In some frameworks, skills are expressed as wrapped functions, reusable prompt templates, or even a synonym for a tool. + +Think of skills like a catalog that expresses what the agent is capable of doing for a user. Unlike tools, skills are not a specific function that produces an output, like "fetch a website" or "tell the weather." Unlike system instructions, they are not rules that apply to all interactions, such as "Follow my company's style guide." + +Instead, skills are building blocks that guide the agent's tool usage and planning. They help the agent understand what its goals are, and when and how to use tools effectively. + +For example, two agents may share the same tools but use them differently based on their skills: + +- A troubleshooting agent might use a `describe` tool to check the events of a crashing pod before taking a recovery action, such as restarting the pod. +- A research agent might use the same `describe` tool to gather details about a pod in order to answer a user's question. + +Skills can refer to two broad types: + +* **A2A skills**: Metadata-based skills that are defined inline in the agent specification. +* **kagent's container-based skills**: Executable skills packaged as container images and loaded from registries, for reuse across agents. You can use the [agentregistry project](https://github.com/agentregistry-dev/agentregistry) to build and push skills to a registry. + +### A2A skills metadata + +Actions-to-actions (A2A) skills are metadata—structured descriptions of capabilities, not executable code. Think of A2A skills as a machine-readable catalog entry about what a tool can do. + +A2A skills metadata describes: + +- What a capability is +- What the capability can do +- The inputs and outputs +- Safety requirements +- How a model should think about the capability + +A2A skills metadata does not: + +- Provide runtime code +- Execute actions +- Bundle actual logic for performing the skill + +In kagent, you define A2A skills in `a2aConfig.skills`. These consist of a description, examples, ID, and tags that help guide the agent's behavior. The description and examples provide context for both humans and the agent itself, often incorporated into system instructions. The ID and tags help you manage skills, such as by making it simpler to compare and reuse them across agents. + +A2A skills are instructions about capabilities, not the capabilities themselves. That is why A2A is sometimes described as "just metadata"—it's descriptive information, not executable code. + +### Container-based skills + +kagent's container-based skills are executable skill implementations packaged as container images. These are runnable procedural logic that the agent can use as an extension of itself. + +Container-based skills include: + +- Executable code snippets or procedures +- Behavior modules that the agent can call at inference time +- Validation and step-by-step behaviors +- Reusable functions +- Direct execution capabilities + +These skills contain instructions, scripts, and resources that are loaded from container registries and made available to the agent at runtime. You can build and push skills as container images, then reference them in `spec.skills.refs` to load them into your agents. + +Container-based skills are actual, callable capabilities—not just descriptions of capabilities. + +kagent's skills are similar to [Claude's Agent Skills](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview), but with a key advantage: you can use kagent's skills with any LLM provider, not just Anthropic Claude. This means your agents can use skills with OpenAI, Google Vertex AI, Azure OpenAI, Ollama, and any other LLM provider that kagent supports. + +### Git-based skills + +You can also load skills directly from Git repositories, as an alternative to OCI images. + +```yaml +skills: + gitRefs: + - url: https://github.com/myorg/agent-skills.git + ref: main + - url: https://github.com/myorg/monorepo.git + ref: main + path: skills/kubernetes # Use a subdirectory +``` + +For private repositories, configure authentication via HTTPS token or SSH key. + +```yaml +skills: + gitAuthSecretRef: + name: git-credentials # Secret containing a `token` key + gitRefs: + - url: https://github.com/myorg/private-skills.git + ref: main +``` + +A single `gitAuthSecretRef` applies to all Git repositories in the agent. You can combine Git and OCI skills in the same agent by specifying both `refs` and `gitRefs`. + +### Best practices for skills + +Containerize and store your skills in a specialized registry so that you can reuse them across agents. You can use the [agentregistry project](https://github.com/agentregistry-dev/agentregistry) to build and push skills to a registry. + +When creating skills for your agents, consider the following best practices. Agentregistry also has a [repo of example skills](https://github.com/agentregistry-dev/skills) based on Claude Skills that you can use as a starting point. + +1. **Be specific**: Each skill should represent a distinct capability. +2. **Provide good examples**: Include diverse examples that cover different ways users might express the need for that skill. +3. **Use descriptive tags**: Tags help organize skills and make them easier to manage. +4. **Align with tools**: Ensure your skills align with the tools available to the agent. If you have a skill that centers around writing docs in markdown, you might want to align it with the `write-markdown` tool (as opposed to a `generate-pdf` tool). +5. **Keep skills focused**: Each skill should have a clear, focused purpose. For example, a document-generating skill might be too broad, but a skill that focuses on creating a specific type of document, such as a `.docx` file or alternatively a genre like a getting started guide, might be more appropriate. + +To learn more about using skills in your agents, see the [Skills example guide](/docs/kagent/examples/skills). + +## Runtime + +You can choose between two Agent Development Kit (ADK) runtimes for declarative agents: **Python** (default) and **Go**. + +| Feature | Python ADK | Go ADK | +|---------|-----------|--------| +| Startup time | ~15 seconds | ~2 seconds | +| Ecosystem | Google ADK, LangGraph, CrewAI integrations | Native Go implementation | +| Resource usage | Higher (Python runtime) | Lower (compiled binary) | +| Default | Yes | No | +| Memory support | Yes | Yes | +| MCP support | Yes | Yes | +| HITL support | Yes | Yes | + +Select the runtime via the `runtime` field in the declarative agent spec. + +```yaml +spec: + type: Declarative + declarative: + runtime: go # or "python" (default) + modelConfig: default-model-config + systemMessage: "You are a helpful agent." +``` + +**Choose Go when** fast startup matters (autoscaling, cold starts), lower resource consumption is important, or you don't need Python-specific framework integrations. + +**Choose Python when** you need Google ADK-native features, CrewAI/LangGraph/OpenAI framework integrations, or Python-based custom tools. + +For more benchmarks and details, see the [Go vs Python runtime blog post](https://kagent.dev/blog/go-vs-python-runtime). + +## Memory + +Your agents can save and retrieve relevant context across conversations using vector similarity search. When you enable memory on an agent, it receives three additional tools (`save_memory`, `load_memory`, `prefetch_memory`) and automatically extracts key information every 5th user message. + +For configuration details, supported storage backends, API endpoints, and limitations, see [Agent Memory](/docs/kagent/concepts/agent-memory). + +## Context Management + +Long conversations can exceed LLM context windows. The context window is the maximum amount of text (tokens) that an LLM can process in a single request. You can enable **event compaction** to automatically summarize older messages while preserving key information. + +```yaml +spec: + type: Declarative + declarative: + modelConfig: default-model-config + systemMessage: "You are a helpful agent for extended sessions." + context: + compaction: + compactionInterval: 5 # Compact every 5 user invocations +``` + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `compactionInterval` | integer | `5` | Number of new user invocations before triggering a compaction. | +| `overlapSize` | integer | `2` | Number of preceding invocations to include for context overlap. | +| `eventRetentionSize` | integer | — | Number of most recent events to always retain. | +| `tokenThreshold` | integer | — | Post-invocation token threshold that triggers compaction. | +| `summarizer` | object | — | Optional LLM-based summarizer configuration. When set, uses an LLM to generate a summary of compacted events instead of discarding them. Requires a `modelConfig` reference. | + +Compaction removes older conversation events to free up space in the context window. By default, compacted events are discarded. To preserve a summary of compacted events, configure the `summarizer` field with a `modelConfig` reference. Enable compaction for agents that handle long-running conversations, call many tools with large outputs, or need to support extended interactions. + +## Sandboxed Agents + +You can run a declarative agent in an isolated sandbox by creating a `SandboxAgent` resource instead of a regular `Agent`. A `SandboxAgent` runs on [Agent Substrate](/docs/kagent/concepts/agent-substrate): the kagent controller runs it as a gVisor-sandboxed actor instead of a Deployment, snapshotting it to object storage when idle and rehydrating it on demand. The spec mirrors the `Agent` spec, with a few constraints: sandboxed agents always use the Go ADK runtime, and `spec.skills` and `BYO` agents are not supported. Configure substrate placement with the optional `spec.substrate` field (for example, `workerPoolRef`). + +For setup steps, see the [Agent Substrate example](/docs/kagent/examples/agent-substrate). + +## Agents as Tools + +kagent also supports using agents as tools. Any agent you create can be referenced and used by other agents you have. An example use case would be to have a PromQL agent that knows how to create PromQL queries from natural language. Then you'd create a second agent that would use the PromQL agent whenever it needs to create a PromQL query. + +Here's how you could reference an existing agent (`promql-agent`) as a tool: + +```yaml +... + # Referencing existing tools + tools: + - type: McpServer + mcpServer: + name: kagent-tool-server + # Or a Kubernetes Service with "appProtocol: mcp", labels, and annotations for MCP + # Or an MCPServer + kind: RemoteMCPServer + toolNames: + - k8s_get_resources + - k8s_get_available_api_resources + # Referencing an existing agent as a tool (same namespace) + - type: Agent + agent: + name: promql-agent + # Referencing an agent in another namespace + - type: Agent + agent: + name: promql-agent + namespace: other-namespace +``` + +### MCP server endpoint + +A2A-enabled agents are automatically exposed as an MCP server on the kagent controller. The MCP endpoint is available at `/mcp` on the same port as the A2A endpoint (default 8083). + +For more information, see the [MCP tools](/docs/kagent/examples/agents-mcp) guide. diff --git a/docs-site/content/kagent/concepts/architecture.md b/docs-site/content/kagent/concepts/architecture.md new file mode 100644 index 00000000..e6dd9deb --- /dev/null +++ b/docs-site/content/kagent/concepts/architecture.md @@ -0,0 +1,67 @@ +--- +title: kagent Architecture +linkTitle: Architecture +description: Explore the high-level architecture of kagent, including its core components like the Controller, App/Engine, CLI, and Dashboard. +weight: 1 +author: kagent.dev +--- + +kagent consists of multiple components running inside and outside of Kubernetes cluster. + +![Architecture](/images/arch.png "kagent architecture") + +## Controller + +The kagent controller is a Kubernetes controller, written in Go, that knows how to handle custom CRDs for creating and managing AI agents in the cluster. + +In the future, we envision more features for the controller, such as: +- Native MCP server for our built-in tools + +## App/Engine + +The kagent engine is the core component of kagent. It runs the agent's conversation loop and supports two runtimes: + +- **Python ADK** (default) — Built on top of the [Google ADK](https://google.github.io/adk-docs/) framework. Supports Google ADK-native features and integrations with CrewAI, LangGraph, and OpenAI frameworks. +- **Go ADK** — A native Go implementation that provides faster startup (~2 seconds vs ~15 seconds) and lower resource consumption. + +Select the runtime by setting the `runtime` field in the agent spec (e.g., `runtime: go`). Both runtimes support MCP tools, HITL, and agent memory. For more details, see [Agents](/docs/kagent/concepts/agents#runtime). + +For more information on the Google ADK framework: + +- [Agents](https://google.github.io/adk-docs/agents/) +- [Tools](https://google.github.io/adk-docs/tools/) +- [Context](https://google.github.io/adk-docs/context/) + +## CLI + +kagent CLI is one of the entry points to kagent. The CLI connects to the engine and allows you to manage resources and interact with agents. + +The CLI offers a way to interact with the engine for those who prefer a CLI interface to the UI dashboard. + +## Dashboard (UI) + +kagent dashboard provides a web interface for managing and working with AI agents. Is it the simplest way to get started with kagent. + +{{< tabs >}} +{{< tab name="kagent dashboard" >}} +```shell + kagent dashboard + ``` +{{< /tab >}} +{{< tab name="kubectl port-forward" >}} +1. Enable port-forwarding on the `kagent` service. + + ```shell + kubectl -n kagent port-forward svc/kagent 8001:80 + ``` + +2. Open your browser to [http://localhost:8001](http://localhost:8001). +{{< /tab >}} +{{< /tabs >}} + +![kagent dashboard](/images/kagent-landing.png "kagent landing page") + +## Next Steps + +- Try [building your own agent](/docs/kagent/getting-started/first-agent) +- Join our [Community](https://discord.gg/Fu3k65f2k3) diff --git a/docs-site/content/kagent/concepts/tools.md b/docs-site/content/kagent/concepts/tools.md new file mode 100644 index 00000000..ccc8ceea --- /dev/null +++ b/docs-site/content/kagent/concepts/tools.md @@ -0,0 +1,89 @@ +--- +title: Tools +description: Understand the different types of tools kagent can use, including built-in, MCP, and HTTP tools, and how tool discovery works. +weight: 3 +author: kagent.dev +--- + +Tools are functions that the agent can use to interact with its environment. For example, a Kubernetes agent might have tools to list pods, get pod logs, and describe services. + +kagent comes with a set of built-in tools that you can use to interact with your environment. kagent also supports the MCP (Model Configuration Protocol) tools. Using MCP, you can bring any external tool into kagent and make it available for your agents to run. + +## Built-in Tools + +You can check out the full list of [built-in tools](https://kagent.dev/tools), or see the [Tools Ecosystem](/docs/kagent/resources/tools-ecosystem) reference for a detailed catalog of tools organized by MCP server. + +The built-in tools are meant as a good starting point for any agents running in kubernetes, however we don't envision them covering all possible use-cases, so we support multiple tool extension points to allow you to bring in your own tools. + +### Cross-namespace tool references + +You can refer to tools from MCP servers in other namespaces by using the `namespace/name` format. This way, you can share tool servers across namespaces without duplicating them. + +Example: Reference to a RemoteMCPServer in the `tools` namespace. + +```yaml +tools: + - type: McpServer + mcpServer: + name: kagent-tool-server + namespace: tools + kind: RemoteMCPServer + toolNames: + - k8s_get_resources +``` + +The same format applies when referring to Services or MCPServers in other namespaces. + +### Headers for tool calls + +You can add headers to requests sent from an agent to a tool using `headersFrom`. This ability is useful for passing API keys, authentication tokens, or other per-request metadata to MCP servers. Header values are resolved from Secrets or ConfigMaps in the same namespace as the Agent. + +Example: Add an API key header when calling a tool. + +```yaml +tools: + - type: McpServer + mcpServer: + name: kagent-tool-server + kind: RemoteMCPServer + toolNames: + - k8s_get_resources + headersFrom: + - name: Authorization + valueFrom: + type: Secret + name: tool-api-secret + key: api-key +``` + +Headers specified in `headersFrom` override any headers of the same name configured on the tool itself. + +## Agents as Tools + +You also have an option of using agents as tools. Any agent you create can be referenced and used by other agents you have. You can refer to agents in other namespaces by using the `namespace/name` format. + +```yaml +tools: + - type: Agent + agent: + name: promql-agent + namespace: other-namespace +``` + +## MCP Tools + +MCP stands for [Model Context Protocol](https://modelcontextprotocol.io/introduction). It is a protocol, originally created by Anthropic, which is meant as a flexible way to provide tools and other information to Agents. In the year or so since its inception, it has begun to gain traction and more and more tools are adopting it. The [servers](https://github.com/modelcontextprotocol/servers) repository has a list of MCP servers that you can use immediately with kagent! Of course there are more than just the ones listed there, so we also support bringing in your own MCP servers. + +**Note:** Double check any community servers before running them in your environment. + +## HTTP Tools + +HTTP tools are another way to bring external tools into kagent. Simply put, given a URL and a schema, kagent will send the user query to the URL and return the response. kagent has the ability to discovery HTTP tools from services running in the cluster, assuming they are OpenAPI Compliant. + +## Build your own tools with kmcp + +A subproject of kagent, kmcp provides a powerful CLI tool with built-in boilerplates to speed up the local development of MCP servers and MCP tools. Then, you can use the kmcp control plane to quickly spin up and deploy your MCP servers in your cloud-native environment, such as Kubernetes. + +By default, kmcp is installed with kagent. If you already installed kmcp separately, you can set `kmcp.enabled=false` in your `values.yaml` file or `--set` commands for both the `kagent` and `kagent-crds` charts. + +Planning to use your kmcp resources later with kagent and agentgateway? Add the `kagent.dev/discovery=disabled` label to your MCPServer resource. Then, kagent does not automatically discover MCP servers. This way, you can have agentgateway in front of your kmcp servers so that the agent-tool traffic is routed correctly through agentgateway. diff --git a/docs-site/content/kagent/examples/_index.md b/docs-site/content/kagent/examples/_index.md new file mode 100644 index 00000000..89093a4b --- /dev/null +++ b/docs-site/content/kagent/examples/_index.md @@ -0,0 +1,9 @@ +--- +title: Examples +description: Explore practical examples and use cases for kagent. +weight: 5 +author: kagent.dev +--- + +Explore practical examples of using kagent to build AI-powered apps. + diff --git a/docs-site/content/kagent/examples/a2a-agents.md b/docs-site/content/kagent/examples/a2a-agents.md new file mode 100644 index 00000000..08fb2670 --- /dev/null +++ b/docs-site/content/kagent/examples/a2a-agents.md @@ -0,0 +1,238 @@ +--- +title: Exposing agents through A2A protocol +linkTitle: A2A Agents +description: Discover how to implement Agent-to-Agent (A2A) communication and collaboration with kagent. +weight: 1 +author: kagent.dev +--- + +Every AI agent created with kagent implements the [A2A protocol](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/) and can be invoked by an A2A client. + +Let's look at how this works in kagent! + +## Prerequisites + +Install kagent by following the [quick start](/docs/kagent/getting-started/quickstart) guide. + +## Creating an AI agent that supports A2A + +Create a simple agent (`k8s-a2a-agent`) that can retrieve resources from a Kubernetes cluster. Note the definition of the agent follows the Agent CRD with the `a2aConfig` section added that describes the skills the agent can perform. + +```yaml +kubectl apply -f - <Note that you could also expose the A2A endpoint publicly by using a gateway. + + ```bash + kubectl port-forward svc/kagent-controller 8083:8083 -n kagent + ``` + +2. To test that the agent is available and has an agent card, send a request to the `.well-known/agent.json` endpoint. Note the API endpoint follows the pattern `/api/a2a/{namespace}/{agent-name}/.well-known/agent.json`. + + ```bash + curl localhost:8083/api/a2a/kagent/k8s-a2a-agent/.well-known/agent.json + ``` + + Example output: This JSON object describes the agent as per the [A2A protocol](https://a2a.guide/protocol/agent-card.html). + + ```json + { + "name": "k8s_a2a_agent", + "description": "An example A2A agent that knows how to use Kubernetes tools.", + "url": "http://127.0.0.1:8083/api/a2a/kagent/k8s-a2a-agent/", + "version": "", + "capabilities": { + "streaming": true, + "pushNotifications": false, + "stateTransitionHistory": true + }, + "defaultInputModes": [ + "text" + ], + "defaultOutputModes": [ + "text" + ], + "skills": [ + { + "id": "get-resources-skill", + "name": "Get Resources", + "description": "Get resources in the Kubernetes cluster", + "tags": [ + "k8s", + "resources" + ], + "examples": [ + "Get all resources in the Kubernetes cluster", + "Get the pods in the default namespace", + "Get the services in the istio-system namespace", + "Get the deployments in the istio-system namespace", + "Get the jobs in the istio-system namespace", + "Get the cronjobs in the istio-system namespace", + "Get the statefulsets in the istio-system namespace" + ], + "inputModes": [ + "text" + ], + "outputModes": [ + "text" + ] + } + ] + } + ``` + +## Invoking the agent + +You can invoke the agent in several ways, including the kagent dashboard, kagent CLI, and the A2A host CLI. + +### Dashboard + +Launch the dashboard with `kagent dashboard`, find your `k8s-a2a-agent`, and start chatting. For complete steps, see the [Your First Agent](/docs/kagent/getting-started/first-agent) guide. + +### kagent CLI + +To use the kagent CLI, make sure that the controller is still being port-forwarded. + +Then, use the invoke command. For more options, run `kagent help invoke`. + +```shell +kagent invoke --agent k8s-a2a-agent --task "Get the pods in the kagent namespace" +``` + +Example output: The output includes both the response as well as the details of the response. The formatting is in JSON but can be quite long, depending on the call and the agent configuration. + +```json +{ + "artifacts": [ + { + "artifactId": "c08e6186-6e6b-4b93-9042-bf9121863707", + "parts": [ + { + "kind": "text", + "text": "There are 59 pods in your cluster." + } + ] + } + ] +... +} +``` + +### A2A host CLI + +You can use the A2A host CLI to invoke the agent. This CLI is part of the [A2A samples repository](https://github.com/a2aproject/a2a-samples/tree/main/samples/python/hosts/cli). + +1. Clone the A2A samples repository. + + ```bash + git clone https://github.com/a2aproject/a2a-samples.git + ``` + +2. From the `a2a-samples/samples/python/hosts/cli` directory, point the CLI to the kagent endpoint. + + ```bash + cd a2a-samples/samples/python/hosts/cli + uv run . --agent http://127.0.0.1:8083/api/a2a/kagent/k8s-a2a-agent + ``` + + Example output: The CLI connects to the kagent, displays the agent card and prompts you for input. + + ```console + ======= Agent Card ======== + {"name":"my-a2a-agent","description":"An example A2A agent that knows how to use Kubernetes tools.","url":"http://127.0.0.1:8083/api/a2a/kagent/my-a2a-agent","version":"1","capabilities":{"streaming":false,"pushNotifications":false,"stateTransitionHistory":false},"defaultInputModes":["text"],"defaultOutputModes":["text"],"skills":[{"id":"kagent-k8s-agent","name":"Get Resources","description":"Get resources in the Kubernetes cluster","examples":["Get all resources in the Kubernetes cluster","Get the pods in the default namespace","Get the services in the istio-system namespace","Get the deployments in the istio-system namespace","Get the jobs in the istio-system namespace","Get the cronjobs in the istio-system namespace","Get the statefulsets in the istio-system namespace"],"inputModes":["text"],"outputModes":["text"]}]} + ========= starting a new task ======== + + What do you want to send to the agent? (:q or quit to exit): + ``` + +3. Send the task `"Get the pods in the kagent namespace"` to the agent. You'll be also prompted to optionally attach a file to the request, but just hit enter to skip this step. + + Example output: The `result` section contains the result of the task and the `artifacts` section contains the output of the task and it shows the pods running inside the kagent namespace. + + ```json + { + "jsonrpc": "2.0", + "id": "0df6761ed3394b43a2dee2bd6572bc94", + "result": { + "id": "89bae00376e44ed094a2174e163da9f6", + "sessionId": "d966626d06ab42b19bd3999e65333311", + "status": { + "state": "completed", + "message": { + "role": "agent", + "parts": [ + { + "type": "text", + "text": "Processed result: There is one pod running in the \"kagent\" namespace:\n\n- Pod Name: kagent-748fb675c6-9ddsz\n- Status: Running\n- Ready Containers: 3 out of 3\n- Restarts: 0\n- Age: 31 minutes\n- Pod IP: 10.244.0.11\n- Node: kagent-control-plane\n\nLet me know if you need more details or want to perform any actions on this pod." + } + ] + }, + "timestamp": "2025-05-06T22:27:31+00:00" + }, + "artifacts": [ + { + "name": "Task Result", + "description": "The result of the task processing", + "parts": [ + { + "type": "text", + "text": "There is one pod running in the \"kagent\" namespace:\n\n- Pod Name: kagent-748fb675c6-9ddsz\n- Status: Running\n- Ready Containers: 3 out of 3\n- Restarts: 0\n- Age: 31 minutes\n- Pod IP: 10.244.0.11\n- Node: kagent-control-plane\n\nLet me know if you need more details or want to perform any actions on this pod." + } + ], + "index": 0, + "lastChunk": true + } + ] + } + } + ``` + +The agent has processed the request and returned the result. diff --git a/docs-site/content/kagent/examples/a2a-byo.md b/docs-site/content/kagent/examples/a2a-byo.md new file mode 100644 index 00000000..532a9892 --- /dev/null +++ b/docs-site/content/kagent/examples/a2a-byo.md @@ -0,0 +1,347 @@ +--- +title: Bringing your own ADK agent to kagent +linkTitle: BYO ADK Agents +description: Bring your own ADK agent to kagent +weight: 1 +author: kagent.dev +--- + +Bring your own custom agents. This example uses the [Agent Development Kit (ADK)](https://google.github.io/adk-docs/), but you can also try out the [LangGraph guide](/docs/kagent/examples/langchain-byo/). Such frameworks give you more control over the agent behavior and are well-suited for complex workflows and integration with external systems and APIs. + +Unlike declarative agents that are defined by kagent resources with components such as system instructions, models, and tools written inline, these BYO agents give you full control over agent logic. If you have your own agent, no need to decompose its functions into separate kagent resources. kagent can invoke your agent directly through the A2A protocol. + +## Prerequisites + +1. Install kagent by following the [quick start](/docs/kagent/getting-started/quickstart) guide. +2. Use [Google ADK](https://github.com/google/adk-python) version 1.22.1 or later. + +## Building a custom agent + +The following example builds a simple agent from the [kagent code repository](https://github.com/kagent-dev/kagent). The sample app is built with Google's ADK framework and performs two basic tasks: rolls a die with a specified number of sides and determines whether a number in a list is prime. It uses Google's Gemini model as the underlying LLM provider. + +1. Clone the kagent code repository. + + ```bash + git clone https://github.com/kagent-dev/kagent.git + cd kagent + ``` + +2. Build the custom agent image and push it to your Docker registry. This example assumes that you want to push the image to the ghcr.io registry. + ```bash + cd python/samples/adk/basic + docker build . -t ghcr.io/my-org:$latest \ + --build-arg DOCKER_REGISTRY=ghcr.io \ + --build-arg VERSION=latest \ + --push + ``` + + If you do not have a Docker registry, you can use the `make helm-install` command to create one as part of installing kagent in your kind cluster. +Then, change `ghcr.io` to `localhost:5001`. + +## Creating a BYO Agent resource + +Now that you have your own custom agent image, you can create a BYO Agent resource for kagent to manage. + +1. Save the API key for your LLM provider, such as Gemini, in an environment variable. + + ```bash + export GOOGLE_API_KEY=your-api-key-here + ``` + +2. Create a secret with the API key. + + ```bash + kubectl create secret generic kagent-google -n kagent --from-literal=GOOGLE_API_KEY=$GOOGLE_API_KEY --dry-run=client -oyaml | kubectl apply -f - + ``` + +3. Create a BYO Agent resource. + +{{< tabs >}} +{{< tab name="Without imagePullSecrets" >}} +```yaml + kubectl apply -f - <}} +{{< tab name="With imagePullSecrets" >}} +For agent images that are in private container registries, you can use an image pull secret with the credentials to the registry. + + First, create the Secret. + ```sh + kubectl create secret docker-registry my-registry-secret --docker-server= --docker-username= --docker-password= -n kagent + ``` + + Then, add `imagePullSecrets` to refer to the Secret that you just created. + ```yaml + kubectl apply -f - <}} +{{< /tabs >}} + +## Testing the A2A endpoint + +The A2A endpoint is exposed on the port `8083` of the kagent controller service. + +1. Enable port-forwarding on the `kagent-controller` service. + + >Note that you could also expose the A2A endpoint publicly by using a gateway. + + ```bash + kubectl port-forward svc/kagent-controller 8083:8083 -n kagent + ``` + +2. To test that the agent is available and has an agent card, send a request to the `.well-known/agent.json` endpoint. Note the API endpoint follows the pattern `/api/a2a/{namespace}/{agent-name}/.well-known/agent.json`. + + ```bash + curl localhost:8083/api/a2a/kagent/basic-agent/.well-known/agent.json + ``` + + Example output: This JSON object describes the agent as per the [A2A protocol](https://a2a.guide/protocol/agent-card.html). + + ```json + { + "name": "basic_agent", + "description": "This agent can do anything.", + "url": "http://127.0.0.1:8083/api/a2a/kagent/basic-agent/", + "version": "", + "capabilities": { + "streaming": true, + "pushNotifications": false, + "stateTransitionHistory": true + }, + "defaultInputModes": [ + "text" + ], + "defaultOutputModes": [ + "text" + ], + "skills": [] + } + ``` + +## Invoking the agent + +You can invoke the agent in several ways, including the kagent dashboard, kagent CLI, and the A2A host CLI. + +### Dashboard + +Launch the dashboard with `kagent dashboard`, find your `basic-agent`, and start chatting. For complete steps, see the [Your First Agent](/docs/kagent/getting-started/first-agent) guide. + +![BYO Agent](/images/byo-basic.png "Chat with your basic agent") + +### kagent CLI + +To use the kagent CLI, make sure that the controller is still being port-forwarded. + +Then, use the invoke command. For more options, run `kagent help invoke`. + +```shell +kagent invoke --agent basic-agent --task "Roll a die with 6 sides" +``` + +Example output: The output includes both the response as well as the details of the response. The formatting is in JSON but can be quite long, depending on the call and the agent configuration. + +```json +{ + "artifacts": [ + { + "artifactId": "2d44a62e-d079-4dae-8ee8-f8759add9ffe", + "parts": [ + { + "kind": "text", + "text": "I rolled a 4 on the 6-sided die.\n" + } + ] + } + ], +... +``` + +### A2A host CLI + +You can use the A2A host CLI to invoke the agent. This CLI is part of the [A2A samples repository](https://github.com/a2aproject/a2a-samples/tree/main/samples/python/hosts/cli). + +1. Clone the A2A samples repository. + + ```bash + git clone https://github.com/a2aproject/a2a-samples.git + ``` + +2. From the `a2a-samples/samples/python/hosts/cli` directory, point the CLI to the kagent endpoint. + + ```bash + cd a2a-samples/samples/python/hosts/cli + uv run . --agent http://127.0.0.1:8083/api/a2a/kagent/basic-agent + ``` + + Example output: The CLI connects to the kagent, displays the agent card and prompts you for input. + + ```console + ======= Agent Card ======== + {"capabilities":{"pushNotifications":false,"stateTransitionHistory":true,"streaming":true},"defaultInputModes":["text"],"defaultOutputModes":["text"],"description":"This agent can do anything.","name":"basic_agent","protocolVersion":"0.2.6","skills":[],"url":"http://127.0.0.1:8083/api/a2a/kagent/basic-agent/","version":""} + ========= starting a new task ======== + + What do you want to send to the agent? (:q or quit to exit): + ``` + +3. Send the task `"Roll a die with 6 sides"` to the agent. You'll be also prompted to optionally attach a file to the request, but just hit enter to skip this step. + + Example output: You get a stream of events that include the prompt and the agent's response, such as the following. + + ```json + { + "contextId": "157a0834df2c459d9cee45316ffbfb5b", + "final": false, + "kind": "status-update", + "metadata": { + "adk_app_name": "kagent__NS__basic_agent", + "adk_author": "hello_world_agent", + "adk_invocation_id": "e-8619b200-2f0a-4257-bd6b-b08bd1b139fd", + "adk_session_id": "157a0834df2c459d9cee45316ffbfb5b", + "adk_usage_metadata": { + "candidatesTokenCount": 15, + "candidatesTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 15 + } + ], + "promptTokenCount": 415, + "promptTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 415 + } + ], + "totalTokenCount": 430 + }, + "adk_user_id": "admin@kagent.dev" + }, + "status": { + "message": { + "kind": "message", + "messageId": "dd05c3cd-2dc3-4efd-9791-d7124be6dd52", + "parts": [ + { + "kind": "text", + "text": "I rolled a 6-sided die and got a 5.\n" + } + ], + "role": "agent" + }, + "state": "working", + "timestamp": "2025-08-14T22:15:04.276358+00:00" + }, + "taskId": "59d2b071-04e9-4fef-a0dd-e925dd13cceb" + } + ``` + +## More options + +Review more options that you might want to configure for your BYO ADK agents. + +### Lifespan hooks + +Lifespan hooks initialize or clean up tasks when your BYO agent starts up or shuts down. This feature is useful for tasks like connecting to external services, loading configuration, or cleaning up resources. + +To use lifespan hooks in your ADK agent, create a lifespan function and pass it to `KAgentApp`. + +1. Create a lifespan function in your agent code, such as the following python example. The lifespan function is an async context manager that runs in either startup or shutdown code. + + - **Startup code** (before `yield`): Executes when the agent container starts. + + - **Shutdown code** (after `yield`): Executes when the agent container stops. + + ```python + # basic/lifespan.py + import logging + from contextlib import asynccontextmanager + from typing import Any + + @asynccontextmanager + async def lifespan(app: Any): + # Startup: runs when the agent starts + logging.info("Lifespan: setup - initializing resources") + # Perform initialization tasks here + # For example: connect to databases, load configuration, etc. + + try: + yield # Agent is running + finally: + # Shutdown: runs when the agent stops + logging.info("Lifespan: teardown - cleaning up resources") + # Perform cleanup tasks here + # For example: close connections, save state, etc. + ``` + +2. Import and pass the lifespan to `KAgentApp`. + + ```python + # main.py or similar + from kagent.adk import KAgentApp + from basic import agent, lifespan # Import your agent and lifespan + + app = KAgentApp( + root_agent=agent.root_agent, + agent_card=agent.agent_card, + kagent_url=os.getenv("KAGENT_URL", "http://kagent-controller.kagent.svc.cluster.local:8083"), + app_name="basic_agent", + lifespan=lifespan.lifespan # Pass the lifespan function + ) + ``` + +### A2A max payload size + +BYO agents accept A2A requests with a default maximum payload size of 10 MB. For agents that need to handle larger payloads (for example, when processing large file attachments), set the `A2A_MAX_CONTENT_LENGTH` environment variable in the agent deployment. + +Example: Allow 50 MB payloads: + +```yaml +spec: + type: BYO + byo: + deployment: + image: ghcr.io/my-org:latest + env: + - name: A2A_MAX_CONTENT_LENGTH + value: "52428800" # 50 MB in bytes +``` + +Set to `0`, `none`, or `unlimited` for no limit (use with caution). diff --git a/docs-site/content/kagent/examples/agent-harness.md b/docs-site/content/kagent/examples/agent-harness.md new file mode 100644 index 00000000..7272b3fe --- /dev/null +++ b/docs-site/content/kagent/examples/agent-harness.md @@ -0,0 +1,220 @@ +--- +title: Agent Harness +description: Provision OpenClaw and Hermes sandboxes on Agent Substrate with the AgentHarness API. +weight: 8 +author: kagent.dev +--- + +`AgentHarness` creates a long-running remote execution environment on [Agent Substrate](/docs/kagent/concepts/agent-substrate). Unlike an `Agent` or `SandboxAgent`, it does not package a kagent runtime into the workload. The backend provisions a sandbox that runs a coding agent (OpenClaw or Hermes), which you can chat with from the kagent UI and wire into messaging channels. + +Use `AgentHarness` when you want kagent to manage the lifecycle of an OpenClaw or Hermes sandbox and surface it in the kagent API/UI alongside regular agents. + +## Before you begin + +1. Install kagent v0.9.9 or later by following the [quick start](/docs/kagent/getting-started/quickstart) guide. +2. Install Agent Substrate and enable the substrate integration in kagent. For Helm-based setup instructions, see [Enable AgentHarness support](/docs/kagent/introduction/installation#enable-agentharness-support) and the [Agent Substrate example](/docs/kagent/examples/agent-substrate). + +When the substrate integration is not enabled, the controller cannot provision AgentHarness resources. + +## Choose a backend + +`spec.backend` selects the sandbox backend. + +- `openclaw` provisions an OpenClaw-compatible sandbox. When `modelConfigRef` is set, kagent translates the referenced `ModelConfig` and writes OpenClaw configuration into the sandbox. +- `hermes` provisions a Hermes sandbox. kagent writes Hermes configuration and environment files into the sandbox and wires supported messaging channels into Hermes environment variables. + +Both backends share the same top-level `AgentHarness` shape: `backend`, required `substrate`, optional `description`, optional `image`, optional `env`, optional `modelConfigRef`, and optional `channels`. + +## Create an OpenClaw harness + +The following resource creates an OpenClaw harness on Agent Substrate. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: AgentHarness +metadata: + name: openclaw-shell + namespace: kagent +spec: + backend: openclaw + description: "OpenClaw shell for platform experiments" + modelConfigRef: default-model-config + substrate: + workerPoolRef: + name: kagent-default +``` + +`spec.substrate` is required. Set `workerPoolRef` to an existing `WorkerPool`, or omit it to use the controller's configured default WorkerPool. You can also set `substrate.snapshotsConfig.location` (a `gs://` prefix) and `substrate.workloadImage` to override the default backend image. + +Apply the resource and wait for it to become ready. + +```bash +kubectl apply -f openclaw-shell.yaml +kubectl -n kagent get agentharness openclaw-shell +``` + +Example output: + +```txt +NAME BACKEND READY ID AGE +openclaw-shell openclaw True kagent-openclaw-shell 30s +``` + +## Create a Hermes harness + +Hermes uses the same `AgentHarness` API with `spec.backend: hermes`. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: AgentHarness +metadata: + name: hermes-shell + namespace: kagent +spec: + backend: hermes + description: "Hermes shell for scheduled and chat-driven workflows" + modelConfigRef: default-model-config + substrate: + workerPoolRef: + name: kagent-default +``` + +If `spec.image` is omitted, kagent uses the backend's default sandbox base image. Set `spec.image` only when you need a custom image that is compatible with the selected backend. + +## Configure Slack + +Slack channels require a bot token and an app-level token. Store them in a Kubernetes `Secret` and reference them from the harness. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: slack-tokens + namespace: kagent +type: Opaque +stringData: + bot-token: xoxb-your-bot-token + app-token: xapp-your-app-token +``` + +Backend-specific Slack settings are nested under the backend name. The API validates this with CEL: + +- `backend: hermes` requires `slack.hermes` and rejects `slack.openclaw`. +- `backend: openclaw` requires `slack.openclaw` and rejects `slack.hermes`. + +### OpenClaw Slack + +OpenClaw Slack settings control channel access and interactive replies. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: AgentHarness +metadata: + name: openclaw-slack + namespace: kagent +spec: + backend: openclaw + modelConfigRef: default-model-config + substrate: + workerPoolRef: + name: kagent-default + channels: + - name: platform + type: slack + slack: + botToken: + valueFrom: + type: Secret + name: slack-tokens + key: bot-token + appToken: + valueFrom: + type: Secret + name: slack-tokens + key: app-token + openclaw: + channelAccess: allowlist + allowlistChannels: + - C0123456789 + interactiveReplies: true +``` + +Set `channelAccess` to `open`, `allowlist`, or `disabled`. When `channelAccess` is `allowlist`, `allowlistChannels` must include at least one Slack channel ID. + +### Hermes Slack + +Hermes Slack settings control allowed users and the home channel used for scheduled messages. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: AgentHarness +metadata: + name: hermes-slack + namespace: kagent +spec: + backend: hermes + modelConfigRef: default-model-config + substrate: + workerPoolRef: + name: kagent-default + channels: + - name: platform + type: slack + slack: + botToken: + valueFrom: + type: Secret + name: slack-tokens + key: bot-token + appToken: + valueFrom: + type: Secret + name: slack-tokens + key: app-token + hermes: + allowedUserIDs: + - U01234567 + - U89ABCDEF + homeChannel: C0123456789 + homeChannelName: platform-alerts +``` + +Use `allowedUserIDsFrom` instead of `allowedUserIDs` when you want to load the Slack member allowlist from a Secret or ConfigMap key. The two fields are mutually exclusive. + +## Check status + +Use `kubectl` to confirm the harness was accepted and is ready. + +```bash +kubectl -n kagent get agentharnesses +kubectl -n kagent describe agentharness hermes-slack +``` + +The `Accepted` condition reports whether kagent accepted the spec. The `Ready` condition reports whether the harness `ActorTemplate` golden snapshot is ready. Once ready, `.status.backendRef` identifies the harness instance and `.status.connection.endpoint` shows the connection hint returned by kagent. + +## Chat with the harness + +Once the harness is `Ready`, it appears in the kagent UI alongside your other agents. kagent talks to the backend over the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/): an in-sandbox `acp-shim` bridges the agent's stdio ACP server to a WebSocket endpoint, and the controller exposes it through the standard agent chat surface. + +1. Port-forward the kagent UI. + + ```bash + kubectl port-forward -n kagent svc/kagent-ui 8001:8080 + ``` + +2. Open [http://localhost:8001](http://localhost:8001), select your harness (for example `kagent/openclaw-shell`) from the Agents list, and send a message. + +The first chat connection creates a shared Substrate actor from the harness template; every chat is multiplexed as an ACP session inside that actor. You see streamed tool activity, and any tool-approval prompts the backend raises are surfaced through kagent's [human-in-the-loop](/docs/kagent/examples/human-in-the-loop) flow. + +## Troubleshooting + +If the harness is not accepted or ready, check these common causes. + +- The kagent controller was not installed with the Agent Substrate integration enabled, so AgentHarness resources cannot be provisioned. +- The referenced `WorkerPool` does not exist, or no default WorkerPool is configured. +- The `ActorTemplate` golden snapshot has not finished building yet — wait for the `Ready` condition. +- `modelConfigRef` points to a missing or unsupported `ModelConfig`. +- A Slack channel has the wrong backend settings, such as `slack.hermes` on an OpenClaw harness or `slack.openclaw` on a Hermes harness. +- A Slack credential uses neither `value` nor `valueFrom`, or sets both. + +For the complete generated schema, see the [API reference](/docs/kagent/resources/api-ref#agentharness). diff --git a/docs-site/content/kagent/examples/agent-substrate.md b/docs-site/content/kagent/examples/agent-substrate.md new file mode 100644 index 00000000..312048d2 --- /dev/null +++ b/docs-site/content/kagent/examples/agent-substrate.md @@ -0,0 +1,217 @@ +--- +title: Agent Substrate +description: Run a declarative agent on Agent Substrate — a Kubernetes-native runtime that snapshots idle agents and rehydrates them inside gVisor sandboxes. +weight: 9 +author: kagent.dev +--- + +In this guide, you install Agent Substrate and kagent on a local kind cluster, then deploy a declarative `SandboxAgent` that runs inside a gVisor actor. All components come from published OCI charts — no source builds or repo clones required. + +By the end, you will have: + +- Agent Substrate v{{< reuse "versions/agent-substrate.md" >}} running in the `ate-system` namespace. +- kagent v0.9.7 or later installed with the substrate integration enabled. Earlier kagent releases do not include the controller wiring that lets a `SandboxAgent` target substrate. +- A `SandboxAgent` running on substrate, reachable from the kagent UI. + +For background on what substrate is and how it differs from a per-pod agent runtime, see the [Agent Substrate concept page](/docs/kagent/concepts/agent-substrate). This guide does not cover the `AgentHarness` path on substrate. + +## Before you begin + +You need: + +- `kind`, `kubectl`, and `helm` on your `PATH`. +- A running Docker daemon (Docker Desktop or equivalent). +- An OpenAI API key exported in your shell. + +```bash +export OPENAI_API_KEY="sk-..." +``` + +## Step 1: Create a kind cluster + +```bash +kind create cluster --name kagent-substrate +``` + +The substrate v{{< reuse "versions/agent-substrate.md" >}} chart defaults to JWT auth backed by Kubernetes ServiceAccount tokens, so a vanilla kind cluster works — no feature gates or custom kind config are required. + +## Step 2: Install Agent Substrate + +Install the CRDs first, then the substrate control plane and data plane. + +```bash +helm upgrade --install substrate-crds \ + oci://ghcr.io/kagent-dev/substrate/helm/substrate-crds \ + --version {{< reuse "versions/agent-substrate.md" >}} \ + --namespace ate-system --create-namespace --wait + +helm upgrade --install substrate \ + oci://ghcr.io/kagent-dev/substrate/helm/substrate \ + --version {{< reuse "versions/agent-substrate.md" >}} \ + --namespace ate-system --wait --timeout 10m +``` + +Verify the substrate pods are running. + +```bash +kubectl get pods -n ate-system +``` + +You should see `ate-api-server`, `ate-controller`, `atelet-*`, `atenet-router`, `valkey-cluster-{0..5}`, and `rustfs` all `Running`, plus a few `Completed` init jobs. + +## Step 3: Install kagent with substrate enabled + +> [!WARNING] +> Pin the chart to v0.9.7 or later. Earlier versions do not include the `controller.substrate.*` and `substrateWorkerPool.*` values; against an older chart they are silently ignored and the controller starts without the substrate integration. + +Confirm the OpenAI key is set in this shell before you run Helm. If the key is empty, the install runs silently with no `kagent-openai` Secret and the default agent pods land in `CreateContainerConfigError`. + +```bash +[[ -n "${OPENAI_API_KEY:-}" ]] && echo "key is set (len=${#OPENAI_API_KEY})" || echo "OPENAI_API_KEY is empty — export it first" +``` + +> [!TIP] +> Do not combine the export and the Helm command on one line — `OPENAI_API_KEY="$(cat ...)" helm ... --set providers.openAI.apiKey="${OPENAI_API_KEY}"` evaluates `${OPENAI_API_KEY}` before the inline assignment runs and passes an empty string. Either `export` on its own line first, or splice the value directly with `--set providers.openAI.apiKey="$(cat ~/path/to/key)"`. + +Install the CRDs, then kagent with the substrate flags. + +```bash +helm upgrade --install kagent-crds \ + oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds \ + --version {{< reuse "versions/kagent.md" >}} \ + --namespace kagent --create-namespace --wait + +helm upgrade --install kagent \ + oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --version {{< reuse "versions/kagent.md" >}} \ + --namespace kagent --timeout 10m --wait \ + --set providers.openAI.apiKey="${OPENAI_API_KEY}" \ + --set providers.default=openAI \ + --set controller.substrate.enabled=true \ + --set controller.substrate.ateApiEndpoint=dns:///api.ate-system.svc:443 \ + --set controller.substrate.ateApiInsecure=true \ + --set substrateWorkerPool.create=true \ + --set substrateWorkerPool.replicas=1 \ + --set substrateWorkerPool.ateomImage=ghcr.io/kagent-dev/substrate/ateom-gvisor:v{{< reuse "versions/agent-substrate.md" >}} +``` + +The `controller.substrate.*` and `substrateWorkerPool.*` flags turn on the substrate integration. The rest is a standard kagent install. + +If Helm hits its `--timeout 10m` while waiting on the cold-start pod startup race (the controller restarts a couple of times waiting on postgres), wait for the controller manually and continue. + +```bash +kubectl wait deploy/kagent-controller -n kagent --for=condition=Available --timeout=10m +``` + +Sanity-check that the key landed and the default agents are healthy. + +```bash +kubectl get secret kagent-openai -n kagent # should exist with 1 data entry +kubectl get pods -n kagent | grep -v Running # only header + Completed jobs expected +``` + +If you see `CreateContainerConfigError` on the default agent pods, the secret did not get created — re-run the kagent Helm command with `--reuse-values --set providers.openAI.apiKey="$(cat ~/path/to/key)"` to patch it in. The deployments roll to new pods automatically. + +### Tune the WorkerPool size + +`substrateWorkerPool.replicas=1` is the chart default. One worker is enough for a declarative-only walkthrough: session actors release their slot the moment they snapshot back to object storage, so a single worker can serve many sequential sessions. Increase the replica count when: + +- You add a long-lived `AgentHarness`. Its shared actor is created on the first chat connect and then pins a slot, so you need at least `1 + (number of active harnesses)`. +- You want simultaneous, overlapping declarative sessions. + +You can change the size three ways, depending on how permanent you want the change. + +```bash +# 1) Quick, ephemeral — scale the live CR. Reverts on the next helm upgrade. +kubectl scale workerpool kagent-default -n kagent --replicas=3 + +# 2) Stick it into the helm release — survives upgrades. +helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --version {{< reuse "versions/kagent.md" >}} --namespace kagent --reuse-values \ + --set substrateWorkerPool.replicas=3 + +# 3) Fresh install — change the value on the Step 3 install command above. +``` + +## Step 4: Open the kagent UI + +```bash +kubectl port-forward -n kagent svc/kagent-ui 8001:8080 +``` + +Open [http://localhost:8001](http://localhost:8001). Skip the first-run wizard if it appears. + +## Step 5: Create a declarative agent on substrate + +A `SandboxAgent` runs as a substrate actor instead of a plain Deployment. Set `substrate.workerPoolRef` to target a specific WorkerPool, or omit it to use the controller's default. Pick one of the two paths below. + +### Option A: Via the UI + +1. **Create** → **Agent** → choose **Declarative** as the type. +2. Set the basics: + - **Name**: `hello-substrate` + - **Namespace**: `kagent` + - **Model config**: `default-model-config` + - **Runtime**: `Go` (required — the Python ADK is not supported on substrate today) + - **System message**: + ``` + You are a friendly assistant living inside an Agent Substrate sandbox. + When asked who you are, say "I am hello-substrate, a Go ADK declarative + agent running inside a gVisor actor." + ``` +3. In the **Sandbox** section, select the worker pool `kagent-default`. +4. Save. + +### Option B: Via kubectl + +```yaml +kubectl apply -f - < *What are you, and where are you running? Answer in one sentence.* + +Expected reply: + +> *I am hello-substrate, a Go ADK declarative agent running inside a gVisor actor.* + +Behind the scenes, a per-session gVisor actor was restored from the golden snapshot, ran the LLM call, and snapshotted itself back to object storage. Open **View → Substrate** to see the actor in the inventory — between requests it sits `Suspended`. + +## Cleanup + +```bash +kind delete cluster --name kagent-substrate +``` + +## Next steps + +- [Agent Substrate concept page](/docs/kagent/concepts/agent-substrate) — runtime architecture and how snapshots, actors, and worker pools fit together. +- [AgentHarness](/docs/kagent/examples/agent-harness) — provision long-running OpenClaw and Hermes coding-agent sandboxes on Agent Substrate and chat with them over ACP. diff --git a/docs-site/content/kagent/examples/agentgateway.md b/docs-site/content/kagent/examples/agentgateway.md new file mode 100644 index 00000000..010a4554 --- /dev/null +++ b/docs-site/content/kagent/examples/agentgateway.md @@ -0,0 +1,141 @@ +--- +title: Using agentgateway with kagent +linkTitle: agentgateway +description: Add governance to your kagent deployment with agentgateway +weight: 1 +author: kagent.dev +--- + +As your kagent deployment grows, you might need governance over how your agents communicate with LLM providers. [Agentgateway](https://agentgateway.dev) is a proxy purpose-built for AI workloads that sits between your kagent agents and your LLM provider. This way, you can apply AgentgatewayPolicy for things like access control, rate limiting, audit logging, and observability. + +## Prerequisites + +1. A running kagent installation. If you haven't installed kagent yet, follow the [quick start](/docs/kagent/getting-started/quickstart) guide first. +2. Follow the [agentgateway installation guide](https://agentgateway.dev/docs/kubernetes/latest/quickstart/install/) to install agentgateway in your cluster. +3. Set up an LLM provider with agentgateway. This guide uses [the Ollama setup](https://agentgateway.dev/docs/kubernetes/latest/llm/providers/ollama/) as an example. + +## Architecture + +Once set up, kagent agent pods route all LLM requests through agentgateway (running in the `agentgateway-system` namespace). Agentgateway enforces your policies, auth/authz, rate limiting, audit logging, and observability. Before forwarding requests to Ollama on the host. + +```mermaid +flowchart LR + subgraph KindCluster["kind cluster"] + kagentPods["kagent agent pods"] + agentGateway["agentgateway
    (agentgateway-system ns)
    • auth / authz
    • rate limiting
    • audit logging
    • observability"] + end + kagentPods --> agentGateway + agentGateway --> ollama["Ollama
    (host)"] + kagentPods:::internal + agentGateway:::internal + ollama:::external + classDef cluster stroke:#818cf8,fill:transparent + classDef internal stroke:#a78bfa,fill:transparent + classDef external stroke:#fb923c,fill:transparent + style kagentPods stroke:#a78bfa,fill:transparent + style agentGateway fill:transparent,stroke:#AA00FF + style ollama fill:transparent,stroke:#00C853 + style KindCluster stroke:#2962FF,fill:transparent +``` + +## Configure kagent to use agentgateway + +With agentgateway installed, point kagent at the agentgateway proxy instead of directly at Ollama. + +1. If you installed kagent without agentgateway, upgrade your installation to route through the proxy. + + ```shell + helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --reuse-values \ + --namespace kagent \ + --set providers.default=ollama \ + --set providers.ollama.baseUrl=http://agentgateway-proxy.agentgateway-system.svc.cluster.local/v1 \ + --set providers.ollama.apiKey=dummy + ``` + +2. Create a `ModelConfig` that points to Ollama via the agentgateway proxy. + + ```yaml + kubectl apply -f- <}} +{{< tab name="Cloud Provider LoadBalancer" >}} +```shell + export INGRESS_GW_ADDRESS=$(kubectl get svc -n kagent kagent-ui -o jsonpath="{.spec.clusterIP}") + echo $INGRESS_GW_ADDRESS + ``` +{{< /tab >}} +{{< tab name="Port-forward for local testing" >}} +```shell + kubectl port-forward -n kagent service/kagent-ui 8082:8080 + ``` +{{< /tab >}} +{{< /tabs >}} + +4. [Open the kagent UI](/docs/kagent/observability/launch-ui). +5. Start a chat with an agent such as `k8s-agent` to confirm that requests flow through agentgateway. + + ![kagent default k8s-agent UI](/images/kagent-default-k8s-agent.png "kagent default k8s-agent UI") + +## Apply governance policies + +With agentgateway in place, you can now apply policies to govern how your kagent agents interact with your LLM provider. + +### Block requests with PII + +1. Create an `AgentgatewayPolicy` resource to reject any request that contains PII, such as an email address. For more policy examples, see the [agentgateway guardrails docs](https://agentgateway.dev/docs/kubernetes/latest/llm/guardrails/regex/#block-requests-with-pii). + + ```yaml + kubectl apply -f - </mcp`. + +## Setting up + +Connect your MCP client to the kagent MCP endpoint using the Streamable HTTP transport. + +### Local Development + +If you are running kagent locally, you can port-forward the control plane service: + +```bash +kubectl port-forward -n kagent svc/kagent-controller 8083:8083 +``` + +Then use `http://localhost:8080/mcp` as your MCP endpoint. Otherwise, use the IP address of your kagent control plane. + +### Example: Cursor Configuration + +Add the following to your Cursor MCP settings: + +```json +{ + "mcpServers": { + "kagent-agents": { + "url": "http://localhost:8083/mcp" + } + } +} +``` + +_Note: Ensure the port matches your local setup (e.g., 8083)._ + +### Example: Claude Code + +To add kagent to Claude Code: + +```bash +claude mcp add --transport http kagent http://localhost:8083/mcp +``` + +Add `--scope project` to limit the configuration to the current project. + +> SSE (Server-Sent Events) is currently not supported. You must use Streamable HTTP. Future updates will include stdio support via the CLI. + +## Using the MCP Server + +The MCP server exposes two core tools: + +1. `list_agents`: Lists all available agents. +2. `invoke_agent`: Runs a specific agent by name with a given input. Supports `sessionID` for continuing conversations. + +This architecture enables MCP clients (like Cursor or other agents) to discover and orchestrate kagent agents as "sub-agents," delegating specialized tasks or cluster actions securely. + +### Tools Overview + +![List Tools](/images/agent-mcp-tools.png "List tools") + +### Example Usage + +Here is an example of asking Claude about a Kubernetes cluster: + +![Ask Claude](/images/agent-mcp-claude.png "Ask Claude") + +In this workflow, the client first calls `list_agents` to discover capabilities, then calls `invoke_agent` to execute the `k8s-agent` with the user's query. + +Try it out and see what you can do! Feel free to open issues for feedback or suggestions. diff --git a/docs-site/content/kagent/examples/crewai-byo.md b/docs-site/content/kagent/examples/crewai-byo.md new file mode 100644 index 00000000..322ba174 --- /dev/null +++ b/docs-site/content/kagent/examples/crewai-byo.md @@ -0,0 +1,259 @@ +--- +title: Bringing your own CrewAI agent to kagent +linkTitle: BYO CrewAI Agents +description: Bring your own CrewAI agent to kagent +weight: 1 +author: kagent.dev +--- + +Bring your own custom agents. This example uses [CrewAI](https://www.crewai.com/), but you can also try out the [ADK guide](/docs/kagent/examples/a2a-byo/) or [LangGraph guide](/docs/kagent/examples/langchain-byo/). Such frameworks give you more control over the agent behavior and are well-suited for complex workflows and integration with external systems and APIs. + +Unlike declarative agents that are defined by kagent resources with components such as system instructions, models, and tools written inline, these BYO agents give you full control over agent logic. If you have your own agent, no need to decompose its functions into separate kagent resources. kagent can invoke your agent directly through the A2A protocol. + +## Prerequisites + +Install kagent by following the [quick start](/docs/kagent/getting-started/quickstart) guide. + +## Building a custom agent + +The following example builds a research crew agent from the [kagent code repository](https://github.com/kagent-dev/kagent). The sample app is built with CrewAI framework and performs research tasks using web search capabilities. It uses OpenAI's GPT models as the underlying LLM provider and Serper for web search. + +1. Clone the kagent code repository. + + ```bash + git clone https://github.com/kagent-dev/kagent.git + cd kagent + ``` + +2. Build the custom agent image and push it to your Docker registry. This example assumes that you want to push the image to the ghcr.io registry. + ```bash + cd python/samples/crewai/research-crew + docker build . -t ghcr.io/research-crew:latest --push + ``` + + If you do not have a Docker registry, you can use the `make helm-install` command to create one as part of installing kagent in your kind cluster. +Then, change `ghcr.io` to `localhost:5001`. + +### Adapting your own CrewAI agent + +A quickstart and detailed guide for adapting existing CrewAI crews and flows to work with kagent is available in the [package's README](https://github.com/kagent-dev/kagent/tree/main/python/packages/kagent-crewai). +This provides a simple way to setup A2A server, tracing, and session-aware memory and state persistence. + +The `kagent-crewai` package is published and available on PyPI. + +To install in your CrewAI project: + +```bash +pip install kagent-crewai +``` + +Two complete examples are available in the `python/samples/crewai/` directory: + +- [**Crew Example**](https://github.com/kagent-dev/kagent/tree/main/python/samples/crewai/research-crew): A multi-agent crew for web research and analysis +- [**Flow Example**](https://github.com/kagent-dev/kagent/tree/main/python/samples/crewai/poem_flow): A CrewAI flow that generates and continues poems + +## Creating a BYO Agent resource + +Now that you have your own custom agent image, you can create a BYO Agent resource for kagent to manage. +You will need a Serper API Key that you can get for free [from their website](https://serper.dev). Serper is a Google Search API used by most CrewAI examples and tutorials, but you can also plug in your own tools. + +1. Save the API keys for your LLM provider and web search service in environment variables. + + ```bash + export OPENAI_API_KEY=your-openai-api-key-here + export SERPER_API_KEY=your-serper-api-key-here + ``` + +2. Create secrets with the API keys. + + ```bash + kubectl create secret generic kagent-openai -n kagent \ + --from-literal=OPENAI_API_KEY=$OPENAI_API_KEY \ + --dry-run=client -o yaml | kubectl apply -f - + + kubectl create secret generic kagent-serper -n kagent \ + --from-literal=SERPER_API_KEY=$SERPER_API_KEY \ + --dry-run=client -o yaml | kubectl apply -f - + ``` + +3. Create a BYO Agent resource. + + ```yaml + kubectl apply -f - < Note that you could also expose the A2A endpoint publicly by using a gateway. + + ```bash + kubectl port-forward svc/kagent-controller 8083:8083 -n kagent + ``` + +2. To test that the agent is available and has an agent card, send a request to the `.well-known/agent.json` endpoint. Note the API endpoint follows the pattern `/api/a2a/{namespace}/{agent-name}/.well-known/agent.json`. + + ```bash + curl localhost:8083/api/a2a/kagent/research-crew/.well-known/agent.json + ``` + + Example output: This JSON object describes the agent as per the [A2A protocol](https://a2a.guide/protocol/agent-card.html). + + ```json + { + "name": "research_crew", + "description": "A research crew with multiple specialized agents for web research and analysis.", + "url": "http://127.0.0.1:8083/api/a2a/kagent/research-crew/", + "version": "", + "capabilities": { + "streaming": true, + "pushNotifications": false, + "stateTransitionHistory": true + }, + "defaultInputModes": ["text"], + "defaultOutputModes": ["text"], + "skills": [] + } + ``` + +## Invoking the agent + +You can invoke the agent in several ways, including the kagent dashboard, kagent CLI, and the A2A host CLI. + +### Dashboard + +Launch the dashboard with `kagent dashboard`, find your `research-crew`, and start chatting. For complete steps, see the [Your First Agent](/docs/kagent/getting-started/first-agent) guide. + +### kagent CLI + +To use the kagent CLI, make sure that the controller is still being port-forwarded. + +Then, use the invoke command. For more options, run `kagent help invoke`. + +```shell +kagent invoke --agent research-crew --task "Research topics on AI reliability and provide a summary." +``` + +Example output: The output includes both the response as well as the details of the response. The formatting is in JSON but can be quite long, depending on the call and the agent configuration. + +```json +{ + "artifacts": [ + { + "artifactId": "2d44a62e-d079-4dae-8ee8-f8759add9ffe", + "parts": [ + { + "kind": "text", + "text": "After researching AI reliability, I found that it encompasses aspects like robustness, safety, and trustworthiness..." + } + ] + } + ], +... +} +``` + +### A2A host CLI + +You can use the A2A host CLI to invoke the agent. This CLI is part of the [A2A samples repository](https://github.com/a2aproject/a2a-samples/tree/main/samples/python/hosts/cli). + +1. Clone the A2A samples repository. + + ```bash + git clone https://github.com/a2aproject/a2a-samples.git + ``` + +2. From the `a2a-samples/samples/python/hosts/cli` directory, point the CLI to the kagent endpoint. + + ```bash + cd a2a-samples/samples/python/hosts/cli + uv run . --agent http://127.0.0.1:8083/api/a2a/kagent/research-crew + ``` + + Example output: The CLI connects to the kagent, displays the agent card and prompts you for input. + + ```console + ======= Agent Card ======== + {"capabilities":{"pushNotifications":false,"stateTransitionHistory":true,"streaming":true},"defaultInputModes":["text"],"defaultOutputModes":["text"],"description":"A research crew with multiple specialized agents for web research and analysis.","name":"research_crew","protocolVersion":"0.2.6","skills":[],"url":"http://127.0.0.1:8083/api/a2a/kagent/research-crew/","version":""} + ========= starting a new task ======== + + What do you want to send to the agent? (:q or quit to exit): + ``` + +3. Send the task `"Research topics on AI reliability and provide a summary."` to the agent. You'll be also prompted to optionally attach a file to the request, but just hit enter to skip this step. + + Example output: You get a stream of events that include the prompt and the agent's response, such as the following. + + ```json + { + "contextId": "157a0834df2c459d9cee45316ffbfb5b", + "final": false, + "kind": "status-update", + "metadata": { + "crewai_app_name": "kagent__NS__research_crew", + "crewai_author": "research_agent", + "crewai_invocation_id": "e-8619b200-2f0a-4257-bd6b-b08bd1b139fd", + "crewai_session_id": "157a0834df2c459d9cee45316ffbfb5b", + "crewai_usage_metadata": { + "candidatesTokenCount": 150, + "candidatesTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 150 + } + ], + "promptTokenCount": 500, + "promptTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 500 + } + ], + "totalTokenCount": 650 + }, + "crewai_user_id": "admin@kagent.dev" + }, + "status": { + "message": { + "kind": "message", + "messageId": "dd05c3cd-2dc3-4efd-9791-d7124be6dd52", + "parts": [ + { + "kind": "text", + "text": "After researching AI reliability, I found that it encompasses aspects like robustness, safety, and trustworthiness..." + } + ], + "role": "agent" + }, + "state": "working", + "timestamp": "2025-08-14T22:15:04.276358+00:00" + }, + "taskId": "59d2b071-04e9-4fef-a0dd-e925dd13cceb" + } + ``` diff --git a/docs-site/content/kagent/examples/discord-a2a.md b/docs-site/content/kagent/examples/discord-a2a.md new file mode 100644 index 00000000..283c44ff --- /dev/null +++ b/docs-site/content/kagent/examples/discord-a2a.md @@ -0,0 +1,157 @@ +--- +title: Integrating kagent with Discord +linkTitle: Discord and A2A +description: Learn how to create a Discord bot that interacts with kagent via A2A +weight: 4 +author: kagent.dev +--- + +}; + +kagent enables you to create AI agents that run inside your Kubernetes cluster. They can access a variety of [built-in tools](/docs/kagent/concepts/tools) and use other [external tools via MCP](/docs/kagent/examples/documentation). + +This guide shows how to connect a Discord bot to one of your agents using the A2A protocol, enabling natural conversations and command execution inside Discord. + +> GitHub Repository: [lekkerelou/kagent-a2a-discord](https://github.com/lekkerelou/kagent-a2a-discord) + +![Discord - A2A - kagent](/images/discord-a2a/discord-a2a-kagent.png) + +We’ll walk through: + +1. Setting up a Discord bot. +2. Connecting it to a kagent agent via A2A. +3. Running and testing the integration locally or in Docker. + +--- + +## Creating a Discord Bot + +1. Visit the [Discord Developer Portal](https://discord.com/developers/applications) +2. Click **New Application**, give it a name, and save. +![Discord Developer Portal](/images/discord-a2a/discord-portal.png) +3. Go to the **Bot** tab → **Reset Token** and save the Discord Bot Token +![Discord Developer Portal : Bot Reset Token](/images/discord-a2a/discord-token.png) +4. Under **Privileged Gateway Intents**, enable **Message Content Intent**. This allows the bot to receive Discord message content. +![Discord Developer Portal : Bot Message Intents](/images/discord-a2a/discord-intents.png) +5. Copy your bot token, you'll need it for your `.env` file. + +Under the **OAuth2 → OAuth2 URL Generator**, check: +- `bot` under scopes +- `Send Messages`, `Read Message History` under bot permissions + +![Discord Developer Portal : Bot OAuth2 1](/images/discord-a2a/discord-oauth2-1.png) +![Discord Developer Portal : Bot OAuth2 2](/images/discord-a2a/discord-oauth2-2.png) + +> Make sure the "Integration Type" is set to Guild Install. + +Use the generated URL to invite your bot to your server. + +--- + +## Setting up the bot code + +1. Clone the repository: + +```bash +git clone https://github.com/lekkerelou/kagent-a2a-discord.git +cd kagent-a2a-discord +``` + +2. Copy the example environment file and fill in your values: + +```bash +cp .env.example .env +``` + +Edit `.env`: + +```dotenv +DISCORD_BOT_TOKEN=your_token +KAGENT_A2A_URL=http://127.0.0.1:8083/api/a2a/kagent/my-k8s-agent +``` + +3. Create and activate a virtual environment: + +```bash +uv venv +``` + +4. Install dependencies: + +```bash +uv sync +``` + +5. Run the bot: + +```bash +uv run main.py +# or +python main.py +``` + +You should see logs indicating the bot is online. + +--- + +## Running with Docker + +If you prefer Docker, you can use the pre-built image: + +```bash +docker pull ghcr.io/lekkerelou/kagent-a2a-discord:latest +docker run --env-file .env ghcr.io/lekkerelou/kagent-a2a-discord:latest +``` + +> You can also build the image locally if needed: +> +> ```bash +> docker build -t a2a-discord-bot . +> docker run --env-file .env a2a-discord-bot +> ``` + +--- + +## Bot Behavior + +The bot listens to messages in all channels unless restricted by environment variables. + +### Optional `.env` keys + +You can customize the bot's behavior with the following optional environment variables: + +- `DISCORD_MENTION_ONLY`: Set to `true` to make the bot respond only when mentioned. +- `DISCORD_CHANNEL_ONLY`: A comma-separated list of channel IDs where the bot is allowed to respond. + +When a message is received, it’s sent to the A2A endpoint (`KAGENT_A2A_URL`), and the agent’s response is posted back in Discord. + +--- + +## Agent Setup + +If you haven’t deployed your agent yet, follow the instructions in [Deploying an Agent](/docs/kagent/examples/slack-a2a#deploying-an-agent). You can reuse the same agent across Slack and Discord integrations. + +Be sure to port-forward your agent if running locally: + +```bash +kubectl port-forward -n kagent svc/kagent-service 8083:8083 +``` + +Set `KAGENT_A2A_URL` accordingly in your `.env`: + +``` +http://127.0.0.1:8083/api/a2a/kagent/my-k8s-agent +``` + +--- + +## Conclusion + +You now have a working Discord bot connected to your kagent agent via A2A. From here, you can: + +- Customize the bot behavior +- Extend the agent with new tools +- Deploy in production + +For questions or support, join our [Discord community](https://discord.gg/Fu3k65f2k3), +or open an issue on [GitHub](https://github.com/lekkerelou/kagent-a2a-discord/issues). diff --git a/docs-site/content/kagent/examples/documentation.md b/docs-site/content/kagent/examples/documentation.md new file mode 100644 index 00000000..d8841ca5 --- /dev/null +++ b/docs-site/content/kagent/examples/documentation.md @@ -0,0 +1,296 @@ +--- +title: Creating an agent leveraging documentation +linkTitle: Documentation Agent +description: See an example of a kagent agent built to help with documentation-related tasks. +weight: 2 +author: kagent.dev +--- + +In this example, we're going to crawl a documentation website, store the content in a vector database and leverage it to answer questions about the documentation. + +## Create the vector database + +We're going to use the [doc2vec](https://github.com/kagent-dev/doc2vec) project to crawl the [MCP documentation](https://modelcontextprotocol.io/) website and store the content in a [SQLite-vec](https://github.com/asg017/sqlite-vec) database. + +Clone the `doc2vec` repo: + +```shell +git clone https://github.com/kagent-dev/doc2vec.git +``` + +Install the dependencies: + +```shell +cd doc2vec +npm install +``` + +Set the `OPENAI_API_KEY` environment variable: + +```bash +export OPENAI_API_KEY= +``` + +Update the configuration file to crawl the MCP documentation: + +```bash +cat < config.yaml +sources: + - type: website + product_name: 'mcp' + version: 'latest' + url: 'https://modelcontextprotocol.io/' + max_size: 1048576 + database_config: + type: 'sqlite' + params: + db_path: './mcp.db' +EOF +``` + +Launch the process: + +```bash +npm start +``` + +It will take several minutes to complete. + +## Create an MCP server to use the MCP documentation database + +Now that we have the database, we can create an MCP server to leverage it. + +The goal is to deploy it on Kubernetes to allow our agent to use it. + +To simplify the process, we're going to store the database in the Docker image. + +Let's build and push the Docker image: + +```bash +cd mcp +cp ../mcp.db . +docker build -t . +docker push . +``` + +> ** Important: Dockerfile Modifications Required** +> +> Make sure you add these essential lines to the Dockerfile before building: +> +> ```dockerfile +> # Add this environment variable +> ENV SQLITE_DB_DIR=/data +> +> # Create the data directory and copy your database +> RUN mkdir -p /data +> COPY mcp.db /data/mcp.db +> +> # Update the ownership to include /data +> RUN chown -R kagent:nodejs /app /data +> ``` +> +> These changes ensure the MCP server can locate your custom documentation database in the `/data` directory. + +## Deploy the MCP server + +Create a Secret for the OpenAI API Key which is going to be used to create the embeddings: + +```bash +kubectl create secret generic mcp-secrets \ + --from-literal=OPENAI_API_KEY= \ + -n kagent +``` + +Create a ConfigMap for the Database Configuration: + +```bash +kubectl create configmap mcp-config \ + --from-literal=SQLITE_DB_DIR=/data \ + --from-literal=PORT=3001 \ + -n kagent +``` + +Create a file named `deployment.yaml`: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mcp-sqlite-vec + namespace: kagent + labels: + app: mcp-sqlite-vec +spec: + replicas: 1 + selector: + matchLabels: + app: mcp-sqlite-vec + template: + metadata: + labels: + app: mcp-sqlite-vec + spec: + containers: + - name: mcp-sqlite-vec + image: + imagePullPolicy: Always + ports: + - containerPort: 3001 + env: + - name: OPENAI_API_KEY + valueFrom: + secretKeyRef: + name: mcp-secrets + key: OPENAI_API_KEY + - name: SQLITE_DB_DIR + valueFrom: + configMapKeyRef: + name: mcp-config + key: SQLITE_DB_DIR + - name: PORT + valueFrom: + configMapKeyRef: + name: mcp-config + key: PORT +``` + +Apply it: +```bash +kubectl apply -f deployment.yaml +``` + +Create a file named `service.yaml`: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: mcp-sqlite-vec + namespace: kagent +spec: + selector: + app: mcp-sqlite-vec + ports: + - port: 3001 + targetPort: 3001 + type: ClusterIP +``` + +Apply it: +```bash +kubectl apply -f service.yaml +``` + +## Use the MCP server in kagent + +You can configure the MCP server in kagent using either the web UI or YAML manifests. + +### Option 1: Using the kagent dashboard + +![manage tool servers](/images/manage-tool-servers.png "Manage tool servers") + +In the kagent UI, click on the `Create` dropdown menu and select `New Tool Server`. + +Call it `sqlite-vec`. + +Select `URL` and use `http://mcp-sqlite-vec.kagent:3001/mcp`. + +![add tool server](/images/add-tool-server.png "Add tool server") + +Click on `Add Server`. + +After refreshing the page, you should see the `query-documentation` tool being discovered. + +![list tool servers](/images/list-tool-servers.png "List tool servers") + +### Option 2: Using YAML CRDs + +Create a `remote-mcpserver.yaml` file: + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: RemoteMCPServer +metadata: + name: live-demo + namespace: kagent +status: +spec: + description: '' + protocol: STREAMABLE_HTTP + sseReadTimeout: 5m0s + terminateOnClose: true + timeout: 5s + url: http://mcp-sqlite-vec.kagent:3001/mcp +``` + +Apply the ToolServer: + +```bash +kubectl apply -f toolserver.yaml +``` + +## Create the MCP agent + +### Option 1: Using the kagent dashboard + +Click on the `Create` dropdown menu and select `New Agent`. + +Use the following information: + +- Agent Name: mcp-agent +- Description: The MCP agent is answering questions about MCP, using the MCP documentation +- Agent Instructions: Use your tool to answer any question about the Model Context Protocol (MCP). Use `mcp` for the product and `latest` for the version. + +Click on `Add Tools`. + +Select the `query-documentation` tool. + +### Option 2: Using YAML CRDs + +Create an `agent.yaml` file: + +```yaml +# kagent Agent Configuration +# This defines an AI agent that can answer questions about MCP documentation +apiVersion: kagent.dev/v1alpha2 +kind: Agent +metadata: + name: sqlite-vec + namespace: kagent +spec: + declarative: + modelConfig: default-model-config + stream: true + systemMessage: ' Use your tool to answer any question about the Model Context Protocol (MCP). Use mcp for the product and latest for the version' + tools: + - mcpServer: + apiGroup: kagent.dev + kind: RemoteMCPServer + name: live-demo + toolNames: + - query_documentation + type: McpServer + description: | + The MCP agent is answering questions about MCP, using the MCP documentation + type: Declarative +``` + +Apply the Agent: + +```bash +kubectl apply -f agent.yaml +``` + +![list agents](/images/list-agents.png "List agents") + +Congratulations, the agent is ready! + +## Use the MCP agent + +Click on the agent and ask a question. + +For example, `How can you build an MCP server using sse?` + +![mcp agent](/images/mcp-agent.png "MCP agent") + +As you can see, the agent has used the `query-documentation` tool to answer the question. \ No newline at end of file diff --git a/docs-site/content/kagent/examples/human-in-the-loop.md b/docs-site/content/kagent/examples/human-in-the-loop.md new file mode 100644 index 00000000..adb42fcf --- /dev/null +++ b/docs-site/content/kagent/examples/human-in-the-loop.md @@ -0,0 +1,241 @@ +--- +title: Human-in-the-Loop with kagent +linkTitle: Human-in-the-Loop +description: Build a Kubernetes-native AI agent that pauses and asks for your approval before taking destructive actions. +weight: 7 +author: kagent.dev +--- + +AI agents that can take action are powerful — but you don't always want them acting without your say-so. This tutorial walks you through building a Kubernetes-native AI agent that **pauses and asks for your approval** before doing anything destructive. + +## What You'll Build + +By the end of this tutorial, you'll have an agent running on a local Kind cluster that: + +- **Reads cluster resources** freely (no approval needed) +- **Pauses for your approval** before creating, modifying, or deleting resources +- **Asks you questions** when it needs more information + +--- + +## Prerequisites + +Make sure you have these installed before starting: + +| Tool | Install Link | +|------|-------------| +| Docker | [get-docker](https://docs.docker.com/get-docker/) | +| Kind | [quick-start](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) | +| kubectl | [install-tools](https://kubernetes.io/docs/tasks/tools/) | +| Helm | [install](https://helm.sh/docs/intro/install/) | + +You'll also need an **OpenAI API key**. + +--- + +## Step 1 — Create a Kind Cluster + +Spin up a local Kubernetes cluster: + +```bash +kind create cluster --name kagent-hitl +``` + +Verify it's running: + +```bash +kubectl cluster-info --context kind-kagent-hitl +``` + +You should see the control plane address printed. If so, you're good to go. + +--- + +## Step 2 — Install kagent + +There are two Helm charts to install: the CRDs first, then kagent itself. + +**Install the CRDs:** + +```bash +helm install kagent-crds oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds \ + --namespace kagent \ + --create-namespace +``` + +**Set your API key:** + +```bash +export OPENAI_API_KEY="your-api-key-here" +``` + +**Install kagent:** + +```bash +helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set providers.default=openAI \ + --set providers.openAI.apiKey=$OPENAI_API_KEY +``` + +**Wait for everything to come up:** + +```bash +kubectl wait --for=condition=ready pod --all -n kagent --timeout=120s +``` + +Once all pods report `condition met`, move on. + +--- + +## Step 3 — Deploy the Agent + +HITL is just additional configuration on the agent's tool references. You can enable HITL on a new agent, or add the `requireApproval` list to an existing agent's `spec.declarative.tools` entries to gate specific tools without changing anything else about the agent. + +This step is the core of the tutorial. You create an agent that uses kagent's built-in Kubernetes tools (served via the kagent tool server), with approval gates on the destructive ones. + +Save this as `hitl-agent.yaml`: + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: Agent +metadata: + name: hitl-agent + namespace: kagent +spec: + description: A Kubernetes agent with human-in-the-loop approval for destructive operations. + type: Declarative + declarative: + modelConfig: default-model-config + systemMessage: | + You are a Kubernetes management agent. You help users inspect and manage + resources in the cluster. Before making any changes, explain what you + plan to do. If the user's request is ambiguous, use the ask_user tool + to clarify before proceeding. + tools: + - type: McpServer + mcpServer: + name: kagent-tool-server + kind: RemoteMCPServer + apiGroup: kagent.dev + toolNames: + - k8s_get_resources + - k8s_describe_resource + - k8s_get_pod_logs + - k8s_get_events + - k8s_get_resource_yaml + - k8s_apply_manifest + - k8s_delete_resource + - k8s_patch_resource + requireApproval: + - k8s_apply_manifest + - k8s_delete_resource + - k8s_patch_resource +``` + +Create the agent: + +```bash +kubectl apply -f hitl-agent.yaml +``` + +**Here's what each tool does:** + +| Tool | What Happens | +|------|-------------| +| `k8s_get_resources` | Runs immediately — lists pods, services, deployments, etc. | +| `k8s_describe_resource` | Runs immediately — shows resource details | +| `k8s_get_pod_logs` | Runs immediately — reads pod logs | +| `k8s_get_events` | Runs immediately — shows cluster events | +| `k8s_get_resource_yaml` | Runs immediately — exports resource YAML | +| `k8s_apply_manifest` | **Pauses for approval** — creates or updates resources | +| `k8s_delete_resource` | **Pauses for approval** — deletes resources | +| `k8s_patch_resource` | **Pauses for approval** — modifies resources | +| `ask_user` | Built-in on every agent — asks you questions anytime | + +The key is `requireApproval` — any tool listed there will pause execution until you explicitly approve it. Read-only tools run freely; write operations need your sign-off. + +--- + +## Step 4 — Open the UI + +Port-forward the kagent dashboard: + +```bash +kubectl port-forward -n kagent svc/kagent-ui 8080:8080 +``` + +Open [http://localhost:8080](http://localhost:8080) in your browser. You should see the kagent UI with your **hitl-agent** listed. + +--- + +## Step 5 — Try It Out + +Now for the fun part. Run through these tests to see human-in-the-loop in action. + +### Test 1: Read Without Approval + +1. Select the **hitl-agent** in the UI +2. Type: `List all pods in the kagent namespace` +3. The agent calls `k8s_get_resources` — it runs **immediately** with no approval prompt +4. You see the pod listing right away + +This shows that read-only tools are not gated. + +### Test 2: Approve a Create + +1. Type: `Create a ConfigMap called test-config in the default namespace with the key message set to "hello from kagent"` +2. The agent calls `k8s_apply_manifest` — execution **pauses** +3. You'll see **Approve / Reject** buttons appear, along with the YAML it wants to apply +4. Click **Approve** +5. The agent creates the ConfigMap and confirms + +### Test 3: Reject a Delete + +1. Type: `Delete the ConfigMap test-config in the default namespace` +2. The agent calls `k8s_delete_resource` — execution **pauses** +3. Click **Reject** and enter a reason: `I want to keep this ConfigMap for now` +4. The agent sees your reason and responds accordingly — it doesn't delete anything + +### Test 4: Agent Asks You a Question + +1. Type: `Set up a namespace for my application` +2. The request is vague, so the agent calls `ask_user` to clarify (e.g., "What should the namespace be called?") +3. Answer the question and the agent continues with your input + +--- + +## How It Works + +The flow is straightforward: + +``` +You send a message + -> Agent decides which tool to call + -> Is the tool in requireApproval? + -> YES: Execution pauses, you see Approve/Reject in the UI + -> Approve: tool runs normally + -> Reject: agent receives your reason and adapts + -> NO: Tool runs immediately +``` + +The `ask_user` tool works the same way — the agent pauses, you answer, and it continues. Both use the same underlying confirmation mechanism, which keeps things simple. + +--- + +## Cleanup + +Delete the cluster when you're done: + +```bash +kind delete cluster --name kagent-hitl +``` + +--- + +## Key Takeaways + +- **`requireApproval`** is all you need — list the tools that need human sign-off +- **Read-only tools run freely**, write operations pause for approval +- **`ask_user`** is built-in on every agent — no extra config required +- **Rejection reasons** are sent back to the LLM so it can adjust its approach diff --git a/docs-site/content/kagent/examples/langchain-byo.md b/docs-site/content/kagent/examples/langchain-byo.md new file mode 100644 index 00000000..4e4ac6a5 --- /dev/null +++ b/docs-site/content/kagent/examples/langchain-byo.md @@ -0,0 +1,158 @@ +--- +title: Bringing your own LangGraph agent to kagent +linkTitle: BYO LangGraph Agents +description: Bring your own LangGraph agent to kagent +weight: 1 +author: kagent.dev +--- + +You can bring your own LangGraph agent to kagent by configuring the kagentCheckpointer in your LangGraph agent code. The [kagentCheckpointer](https://github.com/kagent-dev/kagent/blob/main/python/samples/langgraph/currency/currency/agent.py#L13) stores the LangGraph state in kagent and enables distributed execution and session recovery. + +## Prerequisites + +Install kagent by following the [quick start](/docs/kagent/getting-started/quickstart) guide. + +## Building a LangGraph agent + +The following example builds a simple LangGraph agent from the [kagent code repository](https://github.com/kagent-dev/kagent). The sample app is built with [LangGraph SDK](https://docs.langchain.com/langgraph-platform/sdk) and performs a currency exchange lookup task. It uses Google's Gemini model as the underlying LLM provider. + +1. Clone the kagent code repository. + + ```bash + git clone https://github.com/kagent-dev/kagent.git + cd kagent + ``` + +2. Build the custom agent image and push it to your Docker registry. This example assumes that you want to push the image to the ghcr.io registry. + ```bash + cd python + docker build . -f samples/langgraph/currency/Dockerfile\ + -t ghcr.io/langgraph-currency:latest \ + --build-arg DOCKER_REGISTRY=ghcr.io \ + --build-arg VERSION=latest \ + --push + ``` + + If you do not have a Docker registry, you can use the `make helm-install` command to create one as part of installing kagent in your kind cluster. +Then, change `ghcr.io` to `localhost:5001`. + +## Creating a BYO Agent resource + +Now that you have your own custom agent image, you can create a BYO Agent resource for kagent to manage. + +1. Save the API key for your LLM provider, such as Gemini, in an environment variable. + + ```bash + export GOOGLE_API_KEY=your-api-key-here + ``` + +2. Create a secret with the API key. + + ```bash + kubectl create secret generic kagent-google -n kagent \ + --from-literal=GOOGLE_API_KEY=$GOOGLE_API_KEY \ + --dry-run=client -oyaml | kubectl apply -f - + ``` + +3. Create a BYO Agent resource. + + ```yaml + kubectl apply -f - <Note that you could also expose the A2A endpoint publicly by using a gateway. + + ```bash + kubectl port-forward svc/kagent-controller 8083:8083 -n kagent + ``` + +2. To test that the agent is available and has an agent card, send a request to the `.well-known/agent.json` endpoint. Note the API endpoint follows the pattern `/api/a2a/{namespace}/{agent-name}/.well-known/agent.json`. + + ```bash + curl localhost:8083/api/a2a/kagent/langgraph-agent/.well-known/agent.json + ``` + + Example output: This JSON object describes the agent as per the [A2A protocol](https://a2a.guide/protocol/agent-card.html). + + ```json + { + "name": "langgraph_agent", + "description": "This is Langgraph currency agent.", + "url": "http://127.0.0.1:8083/api/a2a/kagent/langgraph-agent/", + "version": "", + "capabilities": { + "streaming": true, + "pushNotifications": false, + "stateTransitionHistory": true + }, + "defaultInputModes": [ + "text" + ], + "defaultOutputModes": [ + "text" + ], + "skills": [] + } + ``` + +## Invoking the agent + +You can invoke the agent through the kagent dashboard or kagent CLI. + +### Dashboard + +Launch the dashboard with `kagent dashboard`, find your `langgraph-agent`, and start chatting. For complete steps, see the [Your First Agent](/docs/kagent/getting-started/first-agent) guide. + +![BYO Agent](/images/byo-langgraph.png "Chat with your LangGraph agent") + +### kagent CLI + +To use the kagent CLI, make sure that the controller is still being port-forwarded. + +Then, use the invoke command. For more options, run `kagent help invoke`. + +```shell +kagent invoke --agent langgraph-agent --task "Show me latest exchange rate between EUR and USD" +``` + +Example output: The output includes both the response as well as the details of the response. The formatting is in JSON but can be quite long, depending on the call and the agent configuration. + +```json +{ + "artifacts": [ + { + "artifactId": "4d8a78c8-7e15-41c2-9b00-6bd27a156663", + "parts": [ + { + "kind": "text", + "text": "The latest exchange rate between EUR and USD is 1 EUR = 1.1793 USD." + } + ] + } + ], +... +``` \ No newline at end of file diff --git a/docs-site/content/kagent/examples/skills.md b/docs-site/content/kagent/examples/skills.md new file mode 100644 index 00000000..fd66647f --- /dev/null +++ b/docs-site/content/kagent/examples/skills.md @@ -0,0 +1,377 @@ +--- +title: Add skills to agents +linkTitle: Skills +description: Learn how to add skills to your agents to guide their behavior and tool usage. +weight: 6 +author: kagent.dev +--- + +Skills are descriptions of capabilities that help agents act more autonomously. They guide the agent's tool usage and planning by orienting responses toward goals rather than just reacting to prompts. + +In this guide, you learn how to add container-based skills to your agents in kagent. + +> [!TIP] +> Want to containerize and manage your skills? Try out the [agentregistry project](https://github.com/agentregistry-dev/agentregistry) to build and push skills to a secure, AI-first container registry. Agentregistry also has a [repo of example skills](https://github.com/agentregistry-dev/skills) based on Claude Skills that you can use as a starting point. + +## Before you begin + +1. Install kagent by following the [quick start](/docs/kagent/getting-started/quickstart) guide. + +2. Review the concepts of [agents and skills](/docs/kagent/concepts/agents) in kagent. + +## Container-based skills + +Container-based skills are executable skill implementations packaged as container images. These skills contain instructions, scripts, and other resources that the agent can discover and use at runtime. This way, you can reuse skills across agents. + +### Step 1: Build a skill container + +To create a container-based skill, package your skill files into a container image. This example creates a skill named `k8s-deploy-skill` that can deploy simple applications to Kubernetes. The skill takes an app name and container image (and optional replica count and port) from the user, runs a Python script that generates a combined Deployment and Service manifest, and then applies the generated manifest to the cluster. + +1. Create a skill directory with your skill files. + + ```bash + mkdir k8s-deploy-skill + cd k8s-deploy-skill + ``` + +2. Create a `SKILL.md` file with skill metadata and instructions. The file must start with `---` and include YAML frontmatter with the skill name and description, followed by `---`, then detailed instructions for the agent. + + ```bash + cat > SKILL.md <<'EOF' + --- + name: k8s-deploy-skill + description: Deploy simple applications to Kubernetes with customizable replicas and port + --- + # Kubernetes simple deploy skill + + Use this skill when users want to deploy a basic app on the Kubernetes cluster. + + ## Instructions + + - Expect the user to provide the name for an app they wish to deploy, along with a docker image reference. + Optionally they may supply number of replicas and port number, but these are not required, and have defaults. + - Call the script `scripts/deploy-app.py` passing the supplied name, image, and optional parameters (# of replicas and port number) if supplied, in that order. + - The script generates a correct two-resource manifest (Deployment + Service) and writes it to the file `temp-manifest.yaml`. + + You, the **agent**, are expected to apply the generated manifest `temp-manifest.yaml` against the current Kubernetes context. + + ## Example + + User: Deploy an app called "nginx" using image "docker/nginx" with 2 replicas on port 8080. + Agent: Invokes `scripts/deploy-app.py nginx docker/nginx 2 8080` + + The skill creates a manifest named `temp-manifest.yaml` consisting of a Deployment + Service in one shot. + The agent in turn applies the generated temp-manifest.yaml to the cluster. + EOF + ``` + + The agent learns how to use the skill by reading this file. The instructions tell the agent when to use the skill, what parameters to expect, and how to invoke the scripts. + +3. Add any scripts or resources your skill needs. + + ```bash + mkdir scripts + cat > scripts/deploy-app.py <<'EOF' + #!/usr/bin/env python3 + + # deploy-app.py + + import sys + from pathlib import Path + from textwrap import dedent + + def generate_manifest(app_name, image, replicas=1, port=80): + """Generate valid Kubernetes YAML using only built-in Python""" + + manifest = f"""\ + apiVersion: apps/v1 + kind: Deployment + metadata: + name: {app_name} + labels: + app: {app_name} + spec: + replicas: {replicas} + selector: + matchLabels: + app: {app_name} + template: + metadata: + labels: + app: {app_name} + spec: + containers: + - name: {app_name} + image: {image} + ports: + - containerPort: {port} + --- + apiVersion: v1 + kind: Service + metadata: + name: {app_name} + labels: + app: {app_name} + spec: + type: ClusterIP + selector: + app: {app_name} + ports: + - port: 80 + targetPort: {port} + protocol: TCP + """ + + # Clean dedent + write + clean_yaml = dedent(manifest).strip() + "\n" + file_path = Path("temp-manifest.yaml") + file_path.write_text(clean_yaml, encoding="utf-8") + return str(file_path) + + def print_usage(): + print("""Kubernetes Zero-Dependency Deploy + + Usage: + python deploy-app.py [replicas] [port] + + Examples: + python deploy-app.py web nginx:latest + python deploy-app.py api ghcr.io/myorg/api:v2 3 5000 + python deploy-app.py redis redis:7.2 1 6379 + + No pip, no yaml, no problem. + + """) + + if __name__ == "__main__": + args = sys.argv[1:] + + if not args or "-h" in args or "--help" in args: + print_usage() + sys.exit(0) + + if len(args) < 2: + print("Error: Need ") + print_usage() + sys.exit(1) + + app_name = args[0] + image = args[1] + + replicas = 1 + port = 80 + + # Parse optional positional numeric args: [replicas] [port] + if len(args) > 2: + if args[2].isdigit(): + replicas = int(args[2]) + else: + print(f"Error: replicas must be a number, got '{args[2]}'") + sys.exit(1) + + if len(args) > 3: + if args[3].isdigit(): + port = int(args[3]) + else: + print(f"Error: port must be a number, got '{args[3]}'") + sys.exit(1) + + if len(args) > 4: + print("Error: Too many arguments") + print_usage() + sys.exit(1) + + # Optional: validate reasonable ranges + if replicas < 1: + print("Error: replicas must be >= 1") + sys.exit(1) + if not (1 <= port <= 65535): + print("Error: port must be between 1 and 65535") + sys.exit(1) + + print(f"Deploying {app_name}") + print(f" Image: {image}") + print(f" Replicas: {replicas}") + print(f" Container port: {port} → Service port: 80") + print() + + path = generate_manifest(app_name, image, replicas, port) + print(f"Manifest saved → {path}") + print() + print("Next:") + print(f" kubectl apply -f {path}") + EOF + chmod +x scripts/deploy-app.py + ``` + + The scripts perform the actual work. In this example, `deploy-app.py` generates Kubernetes manifests based on the parameters provided. + +4. Create a Dockerfile. + + ```bash + cat > Dockerfile <<'EOF' + FROM scratch + COPY . / + EOF + ``` + +5. For local testing, start a Docker registry on your local host. Before building and pushing to a localhost registry, check if you already have one running. + + ```bash + docker ps | grep registry + ``` + + - If you see a registry container, note the port mapping (for example, `127.0.0.1:5001->5000/tcp` means the registry is accessible on port 5001). + - If no registry is running, start one. + + ```bash + docker run -d -p 5000:5000 --restart=always --name local-registry registry:2 + ``` + + If your registry is on a different port (like 5001), use that port in the following commands instead of 5000. + +6. Build and push the image to a container registry. You can push skill containers to any container registry: + + - Localhost registry: `localhost:PORT/skill-name:tag` + - Docker Hub: `docker.io/username/skill-name:tag` + - GitHub Container Registry: `ghcr.io/username/skill-name:tag` + - Google Container Registry: `gcr.io/project/skill-name:tag` + - Amazon ECR: `123456789012.dkr.ecr.region.amazonaws.com/skill-name:tag` + - Any private registry: `registry.example.com/skill-name:tag` + + ```bash + docker build -t localhost:5000/k8s-deploy-skill:latest . + docker push localhost:5000/k8s-deploy-skill:latest + ``` + +### Step 2: Use container-based skills in an agent + +To load container-based skills into your agent, reference them in the `spec.skills.refs` field. + +> [!TIP] +> For development and testing such as in a local Docker registry, you can use the `insecureSkipVerify` option. Note that for Kind clusters, use `kind-registry:5000` instead of `localhost:5000`. + +```yaml +kubectl apply -f - <Note that these instructions might change, so make sure you check out the latest instructions on the [Slack website](https://api.slack.com/quickstart). + +1. From the Your Apps page click the "Create an app" button. + +![Create an app](/images/slack-a2a/1-create-slack-app.png) + +2. Choose "From scratch" options and give your app a name (we'll use `My kagent app`) and pick a workspace. + +![Configure your app](/images/slack-a2a/2-name-workspace.png) + +3. Click Create App to create the app. + +You'll be redirected to the app's basic information page. Next, we need to give app the permissions it needs to send or view messages, for example: + +1. Click the OAuth & Permissions tab from the left sidebar. +2. Scroll down to the "Scopes" section. +3. Click "Add an OAuth Scope" in the "Bot Token Scopes" section. +4. From the dropdown menu add the following scopes (you can add more scopes if you want to experiment with other features): + - `chat:write` + - `commands` + +![Bot Token Scopes](/images/slack-a2a/bot-token-scopes.png) + +These scopes will allow the app to send messages as the "My kagent app" and with the commands we'll be able to configure slash commands users can invoke. + +Now that we have the scopes set up, we can install the app (that won't do anything yet) to the workspace. Scroll up to the top of the page to the "OAuth Tokens" section and click "Install to `your_workspace_name`" button. + +You'll be redirected to the app's installation page. Make sure you select a channel where the app will be able to post messages and click "Allow" to install the app to your workspace. + +![Install to workspace](/images/slack-a2a/install-app.png) + +If you open your Slack workspaces you'll notice the "My kagent app" is added to the list of apps. + +![kagent app installed in Slack](/images/slack-a2a/app-in-slack.png) + +Let's go back to the "OAuth & Permissions" page - notice the Bot User OAuth Token (`SLACK_BOT_TOKEN`). Copy it and save it somewhere as we'll use it later. + +Click on the "Basic Information" and go to the "App-Level Tokens" section and click the "Generate token and Scopes" button. From the dialog, name your token (`mytoken`) and click the Add Scope and add the `connections:write` scope as shown below. + +![Generate app-level token](/images/slack-a2a/app-level-token.png) + +Click "Generate", copy the token and save it somewhere as we'll use it later (`SLACK_APP_TOKEN`). + +Before we go and write some code, we'll also need to set up the events. For the sake of simplicity, we'll use the "Socket Mode" - this allows us to use the events API without deploying the bot a publicly accessible URL - it greatly simplifies the development process. However, once you're ready to deploy your bot to production, you'll need to set up the Slack bot app on a publicly accessible URL. + +To enable "Socket Mode": + +1. Click the "Socket Mode" tab from the left sidebar. +2. Click the "Enable Socket Mode" toggle to enable it. + +Lastly we'll add a slash command that will allow us to invoke the bot directly using the `/mykagent` command: + +1. Click the "Slash Commands" tab from the left sidebar. +2. Click "Create New Command" button. +3. Fill out the form with the following values: + ![Create slash command](/images/slack-a2a/slash-commands.png) +4. Click Save. + +## Writing a Slack bot + +Armed with two tokens, we can now go and write some code! We'll be using Bolt for Python, but you can also use Bolt for other languages. Start by cloning the [A2A Slack template](https://github.com/kagent-dev/a2a-slack-template.git). + +1. Clone the repository: + +```shell +git clone https://github.com/kagent-dev/a2a-slack-template.git +cd a2a-slack-template +``` + +2. Copy the `.env.example` file to `.env`: + +```shell +cp .env.example .env +``` + +3. Open the `.env` file and add your tokens (don't worry about the `KAGENT_A2A_URL` variable for now, we'll set it later): + +```shell +SLACK_BOT_TOKEN=xoxb-... +SLACK_APP_TOKEN=xapp-... +``` + +4. Create a virtual environment and install the dependencies: + +```shell +uv venv +source .venv/bin/activate +uv sync +``` + +(Note: If you don't have `uv` installed, you can typically install it using `pip install uv`.) + +5. Run the bot: + +```shell +uv run main.py +``` + +The bot should start and the output should look like this: + +```console +INFO:root:Starting kagent Slack bot +DEBUG:asyncio:Using selector: KqueueSelector +⚡️ Bolt app is running! +``` + +If you go to the Slack channel where you installed the app, you should see the bot online and you can try the `/mykagent` command. + +## Deploying an agent + +Before deploying an agent, make sure you have installed kagent in your cluster. If you haven't, you can install it by following the instructions [here](https://kagent.dev/docs/kagent/getting-started/quickstart). Make sure that you also install the `kmcp` CRDs as shown in that guide so that you can create an MCPServer. + +Next, we'll deploy a sample agent to the cluster that will be exposed through the A2A protocol and then we'll be able to call it from the Slack bot. The agent is a simple Kubernetes agent that has access to a couple of tools and is configured to answer questions about Kubernetes. + +Let's deploy it: + +```shell +kubectl apply -f - < + +### Architecture Overview + +Here’s what we’re building: + + Architecture + +--- + +## Steps + +### Step 1: Create Your Telegram Bot + +1. Open Telegram, search for **@BotFather**. +2. Send `/newbot`, pick a name and username. +3. Copy the **bot token** it gives you. + +--- + +### Step 2: Deploy a kagent Agent + +> **Prerequisite:** kagent running in your cluster with `kmcp` CRDs installed. If not, hit the [quickstart](https://kagent.dev/docs/kagent/getting-started/quickstart) first. + +This agent has Kubernetes tools, Helm tools, and Prometheus — and it's exposed over A2A so any client (our Telegram bot, or anything else) can talk to it. Feel free to make changes as you please: + +```shell +kubectl apply -f - <=21.0 +httpx>=0.27.0 +``` + +#### main.py + +```python +"""Telegram bot that forwards messages to a kagent A2A agent.""" + +from pathlib import Path + +from telegram import Update +from telegram.ext import Application, CommandHandler, MessageHandler, filters + +logging.basicConfig(level=logging.INFO) + +TELEGRAM_BOT_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"] +KAGENT_A2A_URL = os.environ["KAGENT_A2A_URL"] + +async def send_a2a_task(message_text: str, session_id: str) -> str: + """Send a message to the kagent A2A endpoint and return the response.""" + task_id = str(uuid.uuid4()) + payload = { + "jsonrpc": "2.0", + "id": task_id, + "method": "message/send", + "params": { + "id": task_id, + "message": { + "role": "user", + "parts": [{"kind": "text", "text": message_text}], + }, + }, + } + async with httpx.AsyncClient(timeout=120.0) as client: + resp = await client.post( + KAGENT_A2A_URL, + json=payload, + headers={"Content-Type": "application/json"}, + ) + resp.raise_for_status() + data = resp.json() + + result = data.get("result", {}) + artifacts = result.get("artifacts", []) + if artifacts: + parts = artifacts[-1].get("parts", []) + texts = [p.get("text", "") for p in parts if p.get("kind") == "text"] + if texts: + return "\n".join(texts) + return "Agent returned no text response." + +# Per-user session tracking +user_sessions: dict[int, str] = {} + +def get_session(user_id: int) -> str: + if user_id not in user_sessions: + user_sessions[user_id] = str(uuid.uuid4()) + return user_sessions[user_id] + +async def start_command(update: Update, _) -> None: + await update.message.reply_text( + "Hello! I'm connected to a kagent Kubernetes agent.\n\n" + "Send me any message and I'll forward it to the agent.\n\n" + "Commands:\n" + "/start - Show this message\n" + "/new - Reset your conversation session" + ) + +async def new_command(update: Update, _) -> None: + user_id = update.effective_user.id + user_sessions[user_id] = str(uuid.uuid4()) + await update.message.reply_text("Session reset. Starting fresh conversation.") + +async def handle_message(update: Update, _) -> None: + user_id = update.effective_user.id + session_id = get_session(user_id) + thinking_msg = await update.message.reply_text("Thinking...") + try: + response = await send_a2a_task(update.message.text, session_id) + for i in range(0, len(response), 4000): # Telegram 4096 char limit + chunk = response[i : i + 4000] + if i == 0: + await thinking_msg.edit_text(chunk) + else: + await update.message.reply_text(chunk) + except Exception as e: + await thinking_msg.edit_text(f"Error contacting agent: {e}") + +def main() -> None: + app = Application.builder().token(TELEGRAM_BOT_TOKEN).build() + app.add_handler(CommandHandler("start", start_command)) + app.add_handler(CommandHandler("new", new_command)) + app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message)) + Path("/tmp/bot-healthy").touch() # For k8s probes + app.run_polling(drop_pending_updates=True) + +if __name__ == "__main__": + main() +``` + +It uses polling — no ingress, no webhooks, no TLS to set up. Each Telegram user gets their own session so conversations keep context. Long responses get chunked automatically (Telegram's 4096-char limit). The `/tmp/bot-healthy` file is there for Kubernetes liveness probes. + +#### Dockerfile + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY main.py . +CMD ["python", "main.py"] +``` + +```shell +docker build -t your-registry/telegram-kagent-bot:latest . +docker push your-registry/telegram-kagent-bot:latest +``` + +--- + +### Step 4: Test It Locally + +Before you deploy anything, make sure it actually works. + +```shell +# Terminal 1: port-forward kagent +kubectl port-forward -n kagent svc/kagent-controller 8083:8083 + +# Terminal 2: run the bot +pip install -r requirements.txt +export TELEGRAM_BOT_TOKEN=your_token_from_botfather +export KAGENT_A2A_URL=http://127.0.0.1:8083/api/a2a/kagent/telegram-k8s-agent/ +python main.py +``` + +Open Telegram, find your bot, send "What pods are running?" — if you get a real answer, you're golden. + +--- + +### Step 5: Deploy to Kubernetes + +Store the bot token: + +```shell +kubectl create secret generic telegram-bot-token -n kagent \ + --from-literal=TELEGRAM_BOT_TOKEN="your_token_from_botfather" +``` + +
    +Using External Secrets Operator instead? + +```yaml +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: telegram-bot-token + namespace: kagent +spec: + refreshInterval: "1h" + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: telegram-bot-token + creationPolicy: Owner + data: + - secretKey: TELEGRAM_BOT_TOKEN + remoteRef: + key: telegram + property: api_key +``` + +
    + +Deploy the bot: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: telegram-bot + namespace: kagent + labels: + app: telegram-bot +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: telegram-bot + template: + metadata: + labels: + app: telegram-bot + spec: + containers: + - name: bot + image: your-registry/telegram-kagent-bot:latest + env: + - name: TELEGRAM_BOT_TOKEN + valueFrom: + secretKeyRef: + name: telegram-bot-token + key: TELEGRAM_BOT_TOKEN + - name: KAGENT_A2A_URL + value: "http://kagent-controller.kagent.svc.cluster.local:8083/api/a2a/kagent/telegram-k8s-agent/" + livenessProbe: + exec: + command: ["cat", "/tmp/bot-healthy"] + initialDelaySeconds: 10 + periodSeconds: 30 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +``` + +The strategy is `Recreate` on purpose — Telegram polling doesn't support multiple consumers. Two pods polling the same bot token means duplicate or missed messages. + +```shell +kubectl apply -f deployment.yaml +``` + +--- + +### Take It Further + +The interesting part isn't the Telegram bot — it's the pattern. The bot is just a transport layer. A2A is the interface. That means: + +- **Multiple agents, one bot.** Add Telegram commands like `/k8s`, `/istio`, `/security` that route to different kagent agents. +- **Any chat platform.** Swap `python-telegram-bot` for `discord.py` or `slack-bolt`. Everything else stays the same. +- **Multi-modal.** kagent supports image parts — screenshot a Grafana dashboard and ask "what's wrong here?" +- **AgentGateway.** Put [AgentGateway](https://agentgateway.dev) in front of the A2A endpoint for rate limiting, auth, and observability. + +Questions? Come find us on [Discord](https://discord.gg/Fu3k65f2k3). diff --git a/docs-site/content/kagent/getting-started/_index.md b/docs-site/content/kagent/getting-started/_index.md new file mode 100644 index 00000000..ce5b3877 --- /dev/null +++ b/docs-site/content/kagent/getting-started/_index.md @@ -0,0 +1,9 @@ +--- +title: Getting Started +description: Guides to help you get started with kagent, from quick setup to your first agent and tool. +weight: 2 +author: kagent.dev +--- + +Guides to help you get started with kagent, from quick setup to your first agent and tool. + diff --git a/docs-site/content/kagent/getting-started/first-agent.md b/docs-site/content/kagent/getting-started/first-agent.md new file mode 100644 index 00000000..1302e4d3 --- /dev/null +++ b/docs-site/content/kagent/getting-started/first-agent.md @@ -0,0 +1,94 @@ +--- +title: Creating your first agent +linkTitle: Your First Agent +description: Learn how to create your first AI agent using the kagent dashboard. +weight: 2 +author: kagent.dev +--- + +In this guide, you'll learn how to create your first AI agent using the kagent dashboard. + +## Prerequisites + +Before you begin make sure you have a Kubernetes cluster with kagent installed. If you haven't done this yet, check out the [installation guide](/docs/kagent/introduction/installation) or the [quickstart guide](/docs/kagent/getting-started/quickstart). + +We'll be working in the kagent dashboard, so use the kagent CLI to open the dashboard: + +```bash +$ kagent dashboard +``` + +![kagent UI](/images/kagent-landing.png "kagent dashboard main page") + +## Creating the agent + +Let's create an agent that can use Kubernetes tools to interact with the cluster. + +1. From the top menu bar, click **+ Create > New Agent**. The **Create New Agent** form opens. + +2. For the **Agent Name**, enter `k8sagent`. + +3. For the **Agent Namespace**, select the namespace that you installed kagent in, `kagent`. + +4. Although optional, enter a description for the agent. The description can help you remember what the agent does and why you created it. + + ```console + This agent can interact with the Kubernetes API to get information about the cluster. + ``` + +5. Fill out the **Agent Instructions**. Together with tools, agent instructions are what agent uses to interact with the user. They play an important role in instructing and guiding the agent on how and when to use tools, how to interact with the user, and what to do in certain scenarios. Think of these instructions as if you'd be giving them to a colleague who's new to the job. + + >Note that the way you structure your instructions is up to you. You can add more details, or simplify them as needed. It's important to make sure the instructions are clear and easy to follow. + + ```md + You're a friendly and helpful agent that uses Kubernetes tools to answer users questions about the cluster. + + # Instructions + + - If user question is unclear, ask for clarification before running any tools + - Always be helpful and friendly + - If you don't know how to answer the question DO NOT make things up + respond with "Sorry, I don't know how to answer that" and ask the user to further clarify the question + + # Response format + - ALWAYS format your response as Markdown + - Your response will include a summary of actions you took and an explanation of the result + ``` + +6. For the **Model**, select the default `gpt-4.1-mini` default model. + +![Create new agent](/images/kagent-new.png "Create a new agent") + +## Adding tools + +Tools are an essential building block of the agent. They are the commands that the agent can run to interact with the environment. As LLMs don't have the ability to run commands, tools are the way to bridge the gap between the agent and the environment. kagent provides a set of built-in tools that you can use to interact with Kubernetes, Istio, Prometheus and projects. You can also [build your own tools](https://kagent.dev/tools)! + +1. Click **Add Tools & Agents**. The selection panel opens. +2. In the search bar, enter `k8s` to filter the available tools. +3. Scroll through the list and select some tools, such as the following: + + * `k8s_get_available_api_resources`: Let the agent list the available API resources in the cluster. + * `k8s_get_resources`: Let the agent list the resources running in the cluster. + +4. Click **Save Selection** to add the tools to the agent. + + ![Add tools](/images/kagent-tools-add.png "Add tools to the agent") + +## Testing the agent + +Now that you set up all the details for your agent, you're ready to finish creating and trying it out. + +1. Click **Create Agent** to create the agent. + +2. From the kagent UI landing page, find your `kagent/k8sagent` agent. You might have to refresh the page. + + ![kagent agent list](/images/kagent-landing.png "Your first agent") + +3. Click your agent, then enter a message such as "What API resources are running in my cluster?", and click **Send**. The agent uses the available tools as shown in the to help answer the question. + + ![kagent chat](/images/k8s-agent-first-chat.png "Chat with your agent") + +## Next Steps + +- Learn more about [Core Concepts](/docs/kagent/concepts) +- Join our [Community](https://discord.gg/Fu3k65f2k3) diff --git a/docs-site/content/kagent/getting-started/first-mcp-tool.md b/docs-site/content/kagent/getting-started/first-mcp-tool.md new file mode 100644 index 00000000..40e4c890 --- /dev/null +++ b/docs-site/content/kagent/getting-started/first-mcp-tool.md @@ -0,0 +1,181 @@ +--- +title: Adding MCP Tools to Your First kagent Agent +linkTitle: Your First MCP tool +description: Learn how to add an MCP (Model Context Protocol) tool to your kagent agent. +weight: 3 +author: kagent.dev +--- + +[MCP (Model Context Protocol)](https://modelcontextprotocol.io/introduction) tools extend the agent's abilities by calling external services to perform tasks that require logic or access outside the cluster. + +In this guide, you'll learn how to add an MCP tool to your first AI agent using the kagent resources. + +## Prerequisites + +1. Install kagent in a Kubernetes cluster. If you haven't done this yet, check out the [installation guide](/docs/kagent/introduction/installation) or the [quickstart guide](/docs/kagent/getting-started/quickstart). + +2. Make sure that you have the kagent custom resources in your cluster. + + ```shell + kubectl get crd | grep kagent.dev + ``` + +## Creating an agent + +To create an agent, follow the [Your First Agent guide](/docs/kagent/getting-started/first-agent). + +Take a look at the Agent custom resource for your first agent, such as with the following command. + +```shell +kubectl get agent my-first-k8s-agent -n kagent -o yaml +``` + +Example output: Pay attention to the following details: + +* The `type` field is set to `Declarative`. This means that the agent is using a declarative model configuration and system message, as opposed to `BYO` where you can bring your own agent configuration separately. +* The `declarative` field contains the model configuration and system message. +* The `systemMessage` field contains the system message that the agent will use. Note that the way you structure your instructions is up to you. You can add more details, or simplify them as needed. It's important to make sure the instructions are clear and easy to follow. +* The `tools` field contains the tools that the agent can run to interact with the environment. The tools refer to a RemoteMCPServer, because these tools are built in to kagent. However, you can also create your own MCPServer or regular Kubernetes Service and designate the Service as for MCP use. +* The `status` shows that the agent is accepted and ready. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: Agent +metadata: + creationTimestamp: "2025-08-13T18:05:07Z" + generation: 1 + name: my-first-k8s-agent + namespace: kagent +spec: + description: This agent can interact with the Kubernetes API to get information + about the cluster. + type: Declarative + declarative: + modelConfig: default-model-config + systemMessage: |- + You're a friendly and helpful agent that uses Kubernetes tools to answer users questions about the cluster. + + # Instructions + - If user question is unclear, ask for clarification before running any tools + - Always be helpful and friendly + - If you don't know how to answer the question DO NOT make things up + respond with "Sorry, I don't know how to answer that" and ask the user to further clarify the question + If you are unable to help, or something goes wrong, refer the user to https://kagent.dev for more information or support. + + # Response format + - ALWAYS format your response as Markdown + - Your response will include a summary of actions you took and an explanation of the result + tools: + - mcpServer: + apiGroup: kagent.dev + kind: RemoteMCPServer + name: kagent-tool-server + toolNames: + - k8s_get_available_api_resources + type: McpServer + - mcpServer: + apiGroup: kagent.dev + kind: RemoteMCPServer + name: kagent-tool-server + toolNames: + - k8s_get_resources + type: McpServer +status: + conditions: + - lastTransitionTime: "2025-08-13T18:05:07Z" + message: "" + reason: AgentReconciled + status: "True" + type: Accepted + - lastTransitionTime: "2025-08-13T18:05:23Z" + message: Deployment is ready + reason: DeploymentReady + status: "True" + type: Ready + configHash: 297ryAv8Xqp/ib2XUWNeDphuiqwA1wk7DAxt+E1vQhQ= + observedGeneration: 1 +``` + +## Configuring MCP tools + +Now that you've reviewed an existing agent that uses MCP tools, let's create our own from scratch. + +The following example creates an agent that can retrieve information from a website. You create a [simple MCP example server](https://modelcontextprotocol.io/examples) that only has one tool, the fetch tool. The fetch tool takes a URL as input and returns the contents of the page. + +1. Create an MCPServer resource with kmcp for the fetch tool. + + ```yaml + kubectl apply -f - < +``` + +Then, let's change into the project directory. If you skip this step, just remember to add the project directory in each `kagent` command later, like `kagent build myagent`. + +```shell +cd myagent +``` + +Let's build the agent: + +```shell +kagent build +``` + +>Note the agent is automatically tagged with the `localhost:5001` registry, so make sure your Kubernetes cluster later on is configured to use this registry or push the image to a remote registry. + +Now you can run the agent locally and test it out by running the following command with the `myagent` project directory: + +```shell +kagent run +``` + +This will launch the terminal UI where you can interact with the agent. + +![kagent terminal UI](/images/localdev-run-tui.png "kagent run terminal UI") + +You can press CTRL+C to exit the terminal UI and stop the agent. If you make changes to the agent code, you can run `kagent build` and then `kagent run` again to see the changes. + +## Add an MCP server to the agent + +Now let's add an MCP server to the agent. We'll use the `add` tool from the `@modelcontextprotocol/server-everything` MCP server. You can add an stdio or remote MCP server to the agent project using the `add-mcp` command. The `add-mcp` command has a terminal UI, but you can also pass specific arguments to the command: + +```shell +kagent add-mcp server-everything --command npx --arg @modelcontextprotocol/server-everything +``` + +This command adds an entry to the `kagent.yaml` file and creates a new directory in the `myagent` project directory called `server-everything`. The directory has an agentgateway configuration file for serving the MCP tool locally and a `Dockerfile` for building the MCP server image. + +>The configuration file and Dockerfile are only used for local development. When deploying the agent and MCP servers to a Kubernetes cluster, the MCP server will be deployed as a separate Kubernetes resource. + +Whenever you add a new MCP server to the agent, the `docker-compose.yaml` file is updated to include the new MCP server. For example, after adding the above MCP server, the entry for it in the `docker-compose.yaml` file will look like this: + +```bash +cat docker-compose.yaml +``` + +Example output: +```yaml + server-everything: + image: localhost:5001/myagent-server-everything:latest + build: + context: ./server-everything + dockerfile: Dockerfile + expose: + - "3000" +``` + +By default, all tools from the MCP server will be automatically available and added to the agent. You can also filter the tools by name or by using a predicate. + +The `mcp_tools.py` file is automatically generated when you add an MCP server that has the `get_mcp_tools` function. + +The generated `agent.py` file already includes the import statement: + +```python +from .mcp_tools import get_mcp_tools +``` + +Open the `agent.py` file and find the line where `mcp_tools` is defined (usually near the bottom of the file) to filter specific tools. + +For example, to only add the `add` tool from the `server-everything` MCP server: +* Replace this line: + ```python + mcp_tools = get_mcp_tools() + ``` + +* with this line: + + ```python + mcp_tools = get_mcp_tools(server_filters={"server-everything": ["add"]}) + ``` + +This filter only includes the `add` tool from the `server-everything` MCP server. + +After updating your code, rebuild and run the project with + +``` +kagent build && kagent run +``` + +Then repeat your question to check that the agent has access to the `add` tool. +```console +You: what can you do? + +Agent: +As myagent_agent, I have several capabilities. Here are some of the things I can do: + +1. Roll dice of different sizes: You specify the number of sides, and I can roll a die with that many sides. + +2. Check if numbers are prime: After rolling a die or dice, I can check if the outcomes of the rolls are prime numbers. + +3. Add numbers: I can perform addition operations as well. + +In order to achieve these, I employ tools to perform specific functions like roll_die, check_prime, or add. I'm here to help, so feel +free to ask me to perform any of these tasks! +``` + +The agent has access to the `add` tool as it specified in the response to the user query. You can also try asking the agent to add two numbers, for example `add 2 + 2` and see if it works. + +## Deploying the project to a Kubernetes cluster + +Now let's deploy the project to a Kubernetes cluster. We'll use the `kagent deploy` command to deploy the agent and MCP servers to a Kubernetes cluster. Make sure you have a Kubernetes cluster and kagent installed in it. + +We'll preprate a `.env.production` file and include the OpenAI API key in it: + +```shell +cat << EOF > .env.production +OPENAI_API_KEY= +EOF +``` + +When deploying, we'll reference the `.env.production` file using the `--env-file` flag and the CLI will create a Secret with the API key (and any other environment variables defined in the file) and then include them in the Agent resource. + +Let's try the `--dry-run` flag to see what will be deployed. As our agent depends on an OpenAI API key, we need to provide it using the `--api-key` flag: + +```shell +kagent deploy . --env-file .env.production --dry-run +``` + +```yaml +--- +apiVersion: v1 +data: + OPENAI_API_KEY: +kind: Secret +metadata: + name: myagent-env + namespace: default +--- +apiVersion: kagent.dev/v1alpha2 +kind: Agent +metadata: + name: myagent + namespace: default +spec: + byo: + deployment: + env: + - name: OPENAI_API_KEY + valueFrom: + secretKeyRef: + key: OPENAI_API_KEY + name: myagent-env + image: localhost:5001/myagent:latest + type: BYO +status: + observedGeneration: 0 +--- +apiVersion: kagent.dev/v1alpha1 +kind: MCPServer +metadata: + name: server-everything + namespace: default +spec: + deployment: + args: + - '@modelcontextprotocol/server-everything' + cmd: npx + image: node:24-alpine3.21 + port: 3000 + stdioTransport: {} + transportType: stdio +status: {} +``` + +Note that the Agent image is tagged with the `localhost:5001` registry, so make sure you have either a local Docker registry running or push the image to a remote registry and then modify the agent image tag. You can also use `kagent build myagent --image ghcr.io/myorg/my-agent:v1.0.0 --push` to build the image with a specifiy name and also push it to a remote registry. + +To deploy both the agent and MCP servers to a Kubernetes cluster, you can use the same `deploy` command, but omit the `--dry-run` flag: + +```shell +kagent deploy . --env-file .env.production +``` + +The command will rebuild the images and then create and deploy the Agent and MCPServer resources to the Kubernetes cluster. + +```shell +kubectl get agent,mcpserver +``` + +```console +NAME TYPE READY ACCEPTED +agent.kagent.dev/myagent BYO True True + +NAME READY AGE +mcpserver.kagent.dev/server-everything True 112s +``` + +You can now test the deployed agent and the MCP server through kagent UI. + +## Troubleshooting + +If you run into any issues, you can start by checking the logs from the agent and/or MCP server containers. You can check the running containers using `docker ps` command and then use the `docker logs [container_id]` command to view the logs from individual container. + diff --git a/docs-site/content/kagent/getting-started/quickstart.md b/docs-site/content/kagent/getting-started/quickstart.md new file mode 100644 index 00000000..de8cc6c0 --- /dev/null +++ b/docs-site/content/kagent/getting-started/quickstart.md @@ -0,0 +1,152 @@ +--- +title: Quick Start +description: A quick guide to get kagent installed and running with your first AI agent. +weight: 1 +author: kagent.dev +--- + +This guide will help you get started with [kagent](https://github.com/kagent-dev/kagent), an open-source framework that brings the power of agentic AI to cloud-native environments. We'll walk through setting up the environment and deploying your first AI agent. + +## Prerequisites + +Before you begin, make sure you have the following tools installed: + +- [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) for creating and running a local Kubernetes cluster +- [Helm](https://helm.sh/docs/intro/install/) - for installing the kagent chart +- [kubectl](https://kubernetes.io/docs/tasks/tools/) - for interacting with your cluster + +To run the AI agents you'll also need an [OpenAI](https://openai.com) API key. You can [get one here](https://platform.openai.com/account/api-keys). + +## Installing kagent + +1. Set the OpenAI API key as an environment variable. + + ```bash + export OPENAI_API_KEY="your-api-key-here" + ``` + +2. Download the kagent CLI. By default, the latest version {{< reuse "versions/kagent.md" >}} of kagent is installed. + + ```bash + brew install kagent + ``` + + or + + ```bash + curl https://raw.githubusercontent.com/kagent-dev/kagent/refs/heads/main/scripts/get-kagent | bash + ``` + +3. Install kagent to the cluster by using the CLI. The following command installs a demo profile with agents and MCP tools preloaded for you. If you don't want these default agents, include the `--profile minimal` flag. + + ```bash + kagent install --profile demo + ``` + + Example output: + + ```console + kagent installed successfully + ``` + +## Accessing the kagent dashboard (UI) + +1. To open the kagent dashboard, run the dashboard command from the CLI. The CLI sets up the port-forward to the UI service running inside the cluster and opens the dashboard. + + ```bash + kagent dashboard + ``` + + ```console + kagent dashboard is available at http://localhost:8082 + Press Enter to stop the port-forward... + ``` + +2. Click **Let's Get Started** in the welcome wizard. + + ![kagent welcome wizard](/images/kagent-wizard.png "kagent welcome wizard") + +3. Walk through the wizard screen by screen to set up your first agent. At any time, you can exit out of the wizard by clicking **Skip wizard**. + + * **Step 1: Configure AI Model**: Choose an existing model such as `gpt-4.1-mini`. + * **Step 2: Set up the AI Agent**: Review the default details for a basic Kubernetes agent. + * **Step 3: Select Tools**: Review the preselected tools for your first agent. + * **Step 4: Review Agent Configuration**: Review the details of your selections, then click **Create kagent/my-first-k8s-agent & Finish**. + + ![kagent agent creation](/images/kagent-wizard-review.png "Review and finish your first wizard in the kagent wizard") + +Good job! You created your first agent. You can share your success, or click **Finish & Go to Agent**. + +## Running Your First AI Agent + +Once you're in the kagent UI, you can start interacting with the pre-configured sample agents. You can click on the agent card to view the agent details and start a conversation. + +1. From the kagent UI landing page, find your `kagent/my-first-k8s-agent` agent. You might have to refresh the page. + + ![kagent agent list](/images/kagent-landing.png "Your first agent") + +2. Click your agent, then enter a message such as "What API resources are running in my cluster?", and click **Send**. The agent uses the available tools as shown in the to help answer the question. + + ![kagent chat](/images/k8s-agent-first-chat.png "Chat with your agent") + +3. Click around to explore the UI some more. + + * The menu shows a history of your chats as well as the ability to start a **New Chat**. + * The **Agent Details** panel shows the tools that the agent uses to respond to your messages. + * The chat interface includes **Arguments** and **Results** that you can expand to see more details about how your question was answered. For example, the **Results** show the output of the `kubectl` terminal commands that the agent ran to list the API resources in your cluster. + + ![kagent chat details](/images/k8s-agent-results.png "Explore features of the chat UI, such as results that show the output of terminal commands") + +## Using the CLI + +Interact with kagent in your terminal. + +1. Review the available commands. + + ```shell + kagent help + + Available Commands: + bug-report Generate a bug report + completion Generate the autocompletion script for the specified shell + dashboard Open the kagent dashboard + get Get a kagent resource + help Help about any command + install Install kagent + invoke Invoke a kagent agent + uninstall Uninstall kagent + version Print the kagent version + ``` + +2. List the current agents. + + ```shell + kagent get agent + +---+---------------------+----+----------------------------+ + | # | NAME | ID | CREATED | + +---+---------------------+----+----------------------------+ + | 0 | helm-agent | 2 | 2025-03-13T19:08:14.527935 | + | 1 | observability-agent | 3 | 2025-03-13T19:08:14.348957 | + | 2 | istio-agent | 1 | 2025-03-13T19:08:13.794848 | + +---+---------------------+----+----------------------------+ + ``` + +3. Interact with an agent with the `invoke` command. The agent is called and a conversation starts. + + ```shell + kagent invoke -t "What Helm charts are in my cluster?" --agent helm-agent + ``` + + In the output, verify that the agent found the `kagent` Helm chart release. If any other Helm charts are in your cluster, it finds those, too. Keep chatting with the agent to see what other things it can do :) + +## Next Steps + +- Create your [first agent](/docs/kagent/getting-started/first-agent) +- Learn about [Core Concepts](/docs/kagent/concepts) +- Join our [Community](https://discord.gg/Fu3k65f2k3) + +## Need Help? + +- Visit our [GitHub repository](https://github.com/kagent-dev/kagent) +- Ask a question on [Discord](https://discord.gg/Fu3k65f2k3) +- Check out the [FAQ](/docs/kagent/resources/faq) \ No newline at end of file diff --git a/docs-site/content/kagent/getting-started/system-prompts.md b/docs-site/content/kagent/getting-started/system-prompts.md new file mode 100644 index 00000000..a0265743 --- /dev/null +++ b/docs-site/content/kagent/getting-started/system-prompts.md @@ -0,0 +1,192 @@ +--- +title: System Prompts +linkTitle: Writing System Prompts +description: Learn the art and science of writing effective system prompts for your kagent agents. +weight: 5 +author: kagent.dev +--- + +Writing good system prompts is one of the most important aspects of building an agent. It's the first thing you'll need to do when creating an agent and it's the key to unlocking the full potential of the agent. Unfortunately, it's also the most challenging part of building an agent. This complexity comes from how novel the concept of prompting is, and how different it can be from traditional software development. + +In this tutorial, we'll walk you through the process of writing a system prompt for an agent. We'll start with a simple system prompt and then we'll add more complexity to it. + +## Core concepts + +Before we start writing a system prompt, it's important to understand the core concepts of an agent. + +1. **Agent instructions** - Agent instructions are the core of an agent. They define the agent's role, capabilities, and behavior. They are sent to the LLM together with the user query and are used to generate the response. + +2. **Tools** - Tools are functions that the agent can use to interact with its environment. For example, a Kubernetes agent might have tools to list pods, get pod logs, and describe services. + +3. **User query** - The user query is the query that the user makes to the agent. It is the input that the agent will use to generate the response. + +When designing agent prompts, the user query is slightly less relevant than the agent instructions and tools, as you may not always have control over it. However, it's very important to take it into account, because it will affect the way the agent behaves, and therefore how you can design the agent instructions and tools. + +## Prompt structure + +When sitting down to write a prompt, it's important to understand exactly what you want the agent to do. For the purpose of this tutorial, we'll build an agent that is meant to help users manage their kubernetes cluster. + +Here's a simple prompt that we can start with: + +```md +You're a Kubernetes agent. You help users manage their kubernetes cluster. +``` + +This is a good start, but it's not enough to build a useful agent. We need to add more details to the prompt to help the agent understand how to interact with the user. + +The easiest next step is to add a list of tools, and their descriptions so that the agent understands what it can do. + +```md +You're a Kubernetes agent. You help users manage their kubernetes cluster. + +You can use the following tools to help the user manage their kubernetes cluster: + +- list_resources: List all resources of a given type in the cluster +- get_all_resources: Get all resource types in the cluster +- get_pod_logs: Get the logs of a pod +- apply_resource: Apply a resource to the cluster +- delete_resource: Delete a resource from the cluster +``` + +Now that we have the tools added, the agent will be much better at understanding the user's query when it has to do with the specific scenarios we mentioned. However, we can do better. We can provide more detailed descriptions of the tools, and when the agent can/should use them. + +```md +You're a Kubernetes agent. You help users manage their kubernetes cluster. + +You can use the following tools to help the user manage their kubernetes cluster: + +1. list_resources +Get the list of resources of a given type in the cluster. +Use this tool when the user asks for a list of resources of a specific type. +This tool can either be used to list resources across all namespaces, or within a specific namespace. + +2. get_all_resources +Get the list of all resource types in the cluster. +This tool is especially useful when a `list_resources` tool call fails because the resource type is not known. + +3. get_pod_logs +Get the logs of a pod. +Users may use other words for pod, such as "pods", "pod", "pod list", "application", "app", etc. +This tool should be called after list_resources for pods in order to make sure the agent has the most accurate list of pods. + +4. apply_resource +Apply a resource to the cluster. +Use this tool when the prompt asks to apply a resource to the cluster. +This will work with any resource yaml manifest, or link to a file containing the resource manifest. + +5. delete_resource +Delete a resource from the cluster. +Use this tool when the user asks to delete a resource from the cluster. +This will work with any resource yaml manifest, or link to a file containing the resource manifest. +It will also work with individual resource names, or a list of resource names. +``` + +Ok, now we have a much better prompt. The agent will now better understand how and when to use the tools, in response to its own internal queries, or user prompts. + +We can still do better. One major thing that was left out of the above prompt is the agent's behavior. LLMs are statistical models that output the most likely next token, this means that being explicit about the agent's behavior makes it more likely that the agent will behave as expected. + +Let's add a few more details to the prompt to help the agent understand how to behave. + +```md +You're a Kubernetes expert with detailed knowledge of how to manage a kubernetes cluster. Your goal is to help the user manage their kubernetes cluster. + +Operational Protocol: +1. Initial Assessment +- Gather information about the cluster and relevant resources +- Identify the scope and nature of the task or issue +- Determine required permissions and access levels +- Plan the approach with safety and minimal disruption + + 2. Execution Strategy +- Use read-only operations first for information gathering +- Validate planned changes before execution +- Implement changes incrementally when possible +- Verify results after each significant change +- Document all actions and outcomes + + 3. Troubleshooting Methodology +- Systematically narrow down problem sources +- Analyze logs, events, and metrics +- Check resource configurations and relationships +- Review recent changes and deployments + +Safety Guidelines: + +1. Cluster Operations +- Prioritize non-disruptive operations +- Verify contexts before executing changes +- Understand blast radius of all operations +- Backup critical configurations before modifications +- Consider scaling implications of all changes + +You should always use the following tools when applicable: + +1. list_resources +Get the list of resources of a given type in the cluster. +Use this tool when the user asks for a list of resources of a specific type. +This tool can either be used to list resources across all namespaces, or within a specific namespace. + +2. get_all_resources +Get the list of all resource types in the cluster. +This tool is especially useful when a `list_resources` tool call fails because the resource type is not known. + +3. get_pod_logs +Get the logs of a pod. +Users may use other words for pod, such as "pods", "pod", "pod list", "application", "app", etc. +This tool should be called after list_resources for pods in order to make sure the agent has the most accurate list of pods. + +4. apply_resource +Apply a resource to the cluster. +Use this tool when the prompt asks to apply a resource to the cluster. +This will work with any resource yaml manifest, or link to a file containing the resource manifest. + +5. delete_resource +Delete a resource from the cluster. +Use this tool when the user asks to delete a resource from the cluster. +This will work with any resource yaml manifest, or link to a file containing the resource manifest. +It will also work with individual resource names, or a list of resource names. +``` + +Notice how much information we've added to the prompt. We've added a detailed operational protocol, and safety guidelines. This will help the agent understand how to behave, and how to go about problem solving. + +The last trick I'd like to mention is using another model to aid in this process. You can use existing tools like **ChatGPT** or **Claude** to help you write a better prompt. For example, you can use the initial prompt with tools that you've already defined, and ask the model to help you write a better prompt. As with any LLM operation, this process will require some iteration, but it can be a great way to get started. + +## Using ConfigMap and Secrets to store prompts + +If you wish to reuse prompts across multiple agents or decouple the prompt from the agent definition, you can use a `ConfigMap` or `Secret` to store the prompt. An example is shown below: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-agent-config + namespace: kagent +data: + system-message: "You are an expert Kubernetes agent that uses tools to help users." +``` + +When creating the agent, you can reference the ConfigMap or Secret that contains the prompt. Note that `systemMessageFrom` (reference) and `systemMessage` (inline) are mutually exclusive, and you can only use one of them. + +```yaml +... + declarative: + systemMessageFrom: + type: ConfigMap + name: my-agent-config + key: system-message +``` + +```yaml +... + declarative: + systemMessageFrom: + type: Secret + name: my-agent-secret + key: system-message +``` + +## Reference + +There are many resources available online that can help you write better prompts. Here are some of the most useful ones: + +- [Prompt Engineering For Unbeatable AI Agents](https://aiablog.medium.com/prompt-engineering-for-unbeatable-ai-agents-df4a1abf4bd8) \ No newline at end of file diff --git a/docs-site/content/kagent/introduction/_index.md b/docs-site/content/kagent/introduction/_index.md new file mode 100644 index 00000000..a03baa77 --- /dev/null +++ b/docs-site/content/kagent/introduction/_index.md @@ -0,0 +1,16 @@ +--- +title: Introduction +description: Welcome to kagent! Start here to understand what kagent is, how to install it, and how to contribute. +weight: 1 +author: kagent.dev +--- + +Welcome to kagent! Start here to understand what kagent is, how to install it, and how to contribute. + +{{< cards >}} +{{< card link="/docs/kagent/introduction/what-is-kagent" title="What is kagent?" subtitle="Learn about the core concepts and capabilities of kagent." >}} +{{< card link="/docs/kagent/introduction/installation" title="Installation" subtitle="Follow our guide to set up kagent." >}} +{{< card link="https://github.com/kagent-dev/kagent/blob/main/README.md#roadmap" title="Feature Roadmap" subtitle="See what we're planning for the future." >}} +{{< card link="https://github.com/kagent-dev/kagent/blob/main/CONTRIBUTING.md" title="Contributing" subtitle="Find out how you can help improve kagent." >}} +{{< /cards >}} + diff --git a/docs-site/content/kagent/introduction/features.md b/docs-site/content/kagent/introduction/features.md new file mode 100644 index 00000000..29559aad --- /dev/null +++ b/docs-site/content/kagent/introduction/features.md @@ -0,0 +1,23 @@ +--- +title: Features +description: A complete overview of kagent platform capabilities. +weight: 3 +author: kagent.dev +--- + +Everything works with a single `helm install`. No add-ons, no extra databases, no waiting for enterprise. + +{{< feature-cards >}} +{{< feature-card title="Agent lifecycle via CRDs" desc="Define, version, and roll out agents with kubectl and GitOps — the same workflow as every other workload." >}} +{{< feature-card title="Multi-runtime support" desc="Go and Python ADK runtimes. Pick the language that fits, or mix both in the same cluster." >}} +{{< feature-card title="BYO frameworks" desc="LangGraph, CrewAI, Google ADK, or your own — bring any agent framework and kagent orchestrates it." >}} +{{< feature-card title="Long-term memory" desc="Persistent vector-backed memory across sessions. Agents remember context, not just the last prompt." >}} +{{< feature-card title="Human-in-the-loop" desc="Tool approval gates, agent-initiated questions, and cascading HITL — humans stay in control." >}} +{{< feature-card title="Agent-to-Agent (A2A)" desc="Agents discover and invoke each other. Compose multi-agent workflows with first-class delegation." >}} +{{< feature-card title="Skills from Git" desc="Load markdown knowledge from Git repos at startup. Agents learn your runbooks, ADRs, and internal docs." >}} +{{< feature-card title="Prompt templates" desc="Reusable prompt fragments stored as ConfigMaps. DRY your system prompts across agents." >}} +{{< feature-card title="Context compaction" desc="Auto-summarization of long conversation histories. Agents stay coherent without blowing token budgets." >}} +{{< feature-card title="Sandbox & security" desc="Agent sandboxing, RBAC, and security hardening out of the box. Run untrusted code safely." >}} +{{< feature-card title="Full observability" desc="OTel tracing, Prometheus metrics, structured logs. See every prompt, every tool call, every token." >}} +{{< feature-card title="Postgres storage" desc="Production-grade Postgres-backed storage with reviewable migrations. No proprietary database lock-in." >}} +{{< /feature-cards >}} diff --git a/docs-site/content/kagent/introduction/installation.md b/docs-site/content/kagent/introduction/installation.md new file mode 100644 index 00000000..d495aab0 --- /dev/null +++ b/docs-site/content/kagent/introduction/installation.md @@ -0,0 +1,311 @@ +--- +title: Installing kagent +description: Learn how to install kagent +weight: 1 +author: kagent.dev +--- + +This guide covers ways to install and configure kagent in your Kubernetes environment. For a quick setup, check out our [Quick Start Guide](/docs/kagent/getting-started/quickstart). For enterpise offerings, check out [Solo Enterprise for kagent](/docs/kagent/introduction/what-is-kagent/#enterprise-distributions). + +## Installation Methods + +Install kagent by using the kagent CLI or Helm. + +> **Note**: As of [version 0.7](/docs/kagent/resources/release-notes#kmcp-installed-by-default), the kmcp subproject is included by default with kagent. To use an existing kmcp installation that you already set up separately, set `kmcp.enabled=false` in your `values.yaml` file or `--set` commands for both the `kagent` and `kagent-crds` charts. + +### Using kagent CLI (Recommended) + +1. Set the OpenAI API key as an environment variable. + + ```bash + export OPENAI_API_KEY="your-api-key-here" + ``` + +2. Download the kagent CLI. By default, the latest version {{< reuse "versions/kagent.md" >}} of kagent is installed. + + ```bash + brew install kagent + ``` + + or + + ```bash + curl https://raw.githubusercontent.com/kagent-dev/kagent/refs/heads/main/scripts/get-kagent | bash + ``` + +3. Install kagent to the cluster by using the CLI. The following command installs a demo profile with agents and MCP tools preloaded for you. If you don't want these default agents, include the `--profile minimal` flag. + + ```bash + kagent install --profile demo + ``` + + ```console + kagent installed successfully + ``` + +4. Optionally: Open the kagent dashboard. + ```bash + kagent dashboard + ``` + + Example output: + ```console + kagent dashboard is available at http://localhost:8082 + Press Enter to stop the port-forward... + ``` + +### Using Helm + +Another way to install kagent is using Helm. + +1. Install the kagent Helm chart with CRDs. + + ```bash + helm install kagent-crds oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds \ + --namespace kagent \ + --create-namespace + ``` + +2. Optionally prepare a Helm values file or `--set` flags to use for your installation. For example, you might set up your default LLM provider, or configure resource requests and limits or disable the default agents. For options, refer to the [Helm reference docs](/docs/kagent/resources/helm). + +{{< tabs >}} +{{< tab name="OpenAI" >}} +3. Set the `OPENAI_API_KEY` environment variable: + + ```bash + export OPENAI_API_KEY="your-api-key-here" + ``` + +4. Install the kagent Helm chart: + + ```bash + helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set providers.default=openAI \ + --set providers.openAI.apiKey=$OPENAI_API_KEY + ``` + +5. Optionally: Port-forward the kagent UI on port 8080. + ```bash + kubectl port-forward -n kagent svc/kagent-ui 8080:8080 + ``` + +6. Open the [kagent UI](http://localhost:8080). +{{< /tab >}} +{{< tab name="Anthropic" >}} +3. Set the `ANTHROPIC_API_KEY` environment variable: + + ```bash + export ANTHROPIC_API_KEY="your-api-key-here" + ``` + +4. Install the kagent Helm chart: + + ```bash + helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set providers.default=anthropic \ + --set providers.anthropic.apiKey=$ANTHROPIC_API_KEY + ``` + +5. Optionally: Port-forward the kagent UI on port 8080. + ```bash + kubectl port-forward -n kagent svc/kagent-ui 8080:8080 + ``` + +6. Open the [kagent UI](http://localhost:8080). +{{< /tab >}} +{{< tab name="Gemini" >}} +3. Set the `GEMINI_API_KEY` environment variable: + + ```bash + export GEMINI_API_KEY="your-api-key-here" + ``` + +4. Install the kagent Helm chart: + + ```bash + helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set providers.default=gemini \ + --set providers.gemini.apiKey=$GEMINI_API_KEY + ``` + +5. Optionally: Port-forward the kagent UI on port 8080. + ```bash + kubectl port-forward -n kagent svc/kagent-ui 8080:8080 + ``` + +6. Open the [kagent UI](http://localhost:8080). +{{< /tab >}} +{{< tab name="Azure OpenAI" >}} +3. Set the `OPENAI_API_KEY` environment variable: + + ```bash + export OPENAI_API_KEY="your-api-key-here" + ``` + +4. Install the kagent Helm chart: + + ```bash + helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set providers.default=azureOpenAI \ + --set providers.azureOpenAI.apiKey=$OPENAI_API_KEY + ``` + +5. Optionally: Port-forward the kagent UI on port 8080. + ```bash + kubectl port-forward -n kagent svc/kagent-ui 8080:8080 + ``` + +6. Open the [kagent UI](http://localhost:8080). +{{< /tab >}} +{{< tab name="Ollama" >}} +3. Install the kagent Helm chart: + + ```bash + helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set providers.default=ollama + ``` + +4. Optionally: Port-forward the kagent UI on port 8080. + ```bash + kubectl port-forward -n kagent svc/kagent-ui 8080:8080 + ``` + +5. Open the [kagent UI](http://localhost:8080). +{{< /tab >}} +{{< /tabs >}} + +## Advanced Configuration + +Review the following advanced configuration options that you might want to set up for your kagent installation. + +### Enable AgentHarness support + +`AgentHarness` resources run on [Agent Substrate](/docs/kagent/concepts/agent-substrate). To enable them, install Agent Substrate and turn on the substrate integration in kagent. When the integration is disabled, the controller cannot provision AgentHarness resources. + +1. Install Agent Substrate (CRDs, then the control plane and data plane). + + ```bash + helm upgrade --install substrate-crds \ + oci://ghcr.io/kagent-dev/substrate/helm/substrate-crds \ + --namespace ate-system --create-namespace --wait + + helm upgrade --install substrate \ + oci://ghcr.io/kagent-dev/substrate/helm/substrate \ + --namespace ate-system --wait --timeout 10m + ``` + +2. Install (or upgrade) kagent with the substrate integration and a WorkerPool enabled. + + **Helm values file:** + + ```yaml + controller: + substrate: + enabled: true + ateApiEndpoint: dns:///api.ate-system.svc:443 + ateApiInsecure: true + substrateWorkerPool: + create: true + replicas: 1 + ``` + + **Helm `--set` flags:** + + ```bash + helm upgrade --install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set controller.substrate.enabled=true \ + --set controller.substrate.ateApiEndpoint=dns:///api.ate-system.svc:443 \ + --set controller.substrate.ateApiInsecure=true \ + --set substrateWorkerPool.create=true \ + --set substrateWorkerPool.replicas=1 + ``` + + Pin the kagent chart to v0.9.9 or later — earlier versions do not include the `controller.substrate.*` and `substrateWorkerPool.*` values. + +For an end-to-end walkthrough on a kind cluster, see the [Agent Substrate example](/docs/kagent/examples/agent-substrate). For more information about creating harness resources, see [Agent Harness](/docs/kagent/examples/agent-harness). + +### Database configuration + +For production environments, set up kagent with an external PostgreSQL instance. For more information, see the [Database configuration guide](/operations/operational-considerations/#database-configuration). + +### Configure controller environment variables + +You can configure the controller by using environment variables for settings such as service names, connection details, and more. + +#### Configure the controller service name + +By default, kagent uses `kagent-controller` as the controller service name when constructing URLs for agent deployments. If you need to customize this name, set the `KAGENT_CONTROLLER_NAME` environment variable on the controller pod. + +**Helm `--set` flag:** + +```bash +helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set controller.env[0].name=KAGENT_CONTROLLER_NAME \ + --set controller.env[0].value=my-kagent +``` + +**Helm values file:** + +```yaml +controller: + env: + - name: KAGENT_CONTROLLER_NAME + value: my-kagent +``` + +#### More environment variables + +You can add custom environment variables to the controller by using the `controller.env` field. + +**Helm `--set` flag:** + +```bash +helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set controller.env[0].name=KAGENT_CONTROLLER_NAME \ + --set controller.env[0].value=my-kagent \ + --set controller.env[1].name=LOG_LEVEL \ + --set controller.env[1].value=debug +``` + +**Helm values file:** + +```yaml +controller: + env: + - name: KAGENT_CONTROLLER_NAME + value: my-kagent + - name: LOG_LEVEL + value: debug + - name: CUSTOM_VAR + value: custom-value +``` + +#### Using secrets for environment variables + +You can also reference Kubernetes secrets for environment variables by using the `envFrom` field in Helm. + +```yaml +controller: + envFrom: + - secretRef: + name: controller-secrets +``` + +This example loads all key-value pairs from the `controller-secrets` secret as environment variables in the controller pod. + +## Uninstallation + +Refer to the [Uninstall](/docs/kagent/operations/uninstall) guide. + +## Next Steps + +- [Create your first agent](/docs/kagent/getting-started/first-agent) +- [Explore available agents](https://kagent.dev/agents) diff --git a/docs-site/content/kagent/introduction/what-is-kagent.md b/docs-site/content/kagent/introduction/what-is-kagent.md new file mode 100644 index 00000000..8fa3390e --- /dev/null +++ b/docs-site/content/kagent/introduction/what-is-kagent.md @@ -0,0 +1,75 @@ +--- +title: Introducing kagent +linkTitle: What is kagent +description: Understand what kagent is and its core purpose. +weight: 2 +author: kagent.dev +--- + +kagent is an open-source programming framework that brings the power of agentic AI to cloud-native environments. Built specifically for DevOps and platform engineers, kagent enables AI agents to run directly in Kubernetes clusters to automate operations, troubleshoot issues, and solve complex cloud-native challenges. + +kagent was created at [Solo.io](https://www.solo.io) in 2025 and is a [Cloud Native Computing Foundation](https://www.cncf.io) sandbox project. + +## What is kagent? + +Unlike traditional chatbots, kagent leverages advanced reasoning and iterative planning capabilities to autonomously handle multi-step problems in cloud-native environments. It transforms AI insights into concrete actions, helping teams tackle common operational challenges like: + +- Diagnosing connectivity issues across multiple service hops +- Troubleshooting application performance degradation +- Automating alert generation from Prometheus metrics +- Debugging Gateway and HTTPRoute configurations +- Managing progressive rollouts with Argo Rollouts + +## Core Components + +kagent's architecture consists of three main components: + +- **Tools**: Any MCP-style function that agents can leverage to interact with cloud-native systems. kagent comes with pre-built tools that include capabilities like displaying pod logs, querying Prometheus metrics, generating resources and more. You can check the available tools in the [tool registry](https://kagent.dev/tools). +- **Agents**: Autonomous systems that plan, execute, and analyze tasks using the available tools. These agents can chain multiple operations together to solve complex problems. Each agent can have access to one or more tools to accomplish its work. Agents can also be grouped into teams where a planning agent comes up with a plan and assigns tasks to individual agents in the team. +- **Framework**: A flexible interface that allows running agents either through a UI or declaratively. Built on Google's ADK framework, it provides extensive customization options. + +## Why kagent? + +kagent addresses the growing complexity of cloud-native operations by: + +- Automating routine troubleshooting and operational tasks +- Reducing the need for specialist intervention in common scenarios +- Enabling teams to formalize and share their operational expertise +- Providing a platform for building and sharing custom AI agents + +## Platform features + +Everything works with a single `helm install`. No add-ons, no extra databases, no waiting for enterprise. + +{{< feature-cards >}} +{{< feature-card title="Agent lifecycle via CRDs" desc="Define, version, and roll out agents with kubectl and GitOps — the same workflow as every other workload." >}} +{{< feature-card title="Multi-runtime support" desc="Go and Python ADK runtimes. Pick the language that fits, or mix both in the same cluster." >}} +{{< feature-card title="BYO frameworks" desc="LangGraph, CrewAI, Google ADK, or your own — bring any agent framework and kagent orchestrates it." >}} +{{< feature-card title="Long-term memory" desc="Persistent vector-backed memory across sessions. Agents remember context, not just the last prompt." >}} +{{< feature-card title="Human-in-the-loop" desc="Tool approval gates, agent-initiated questions, and cascading HITL — humans stay in control." >}} +{{< feature-card title="Agent-to-Agent (A2A)" desc="Agents discover and invoke each other. Compose multi-agent workflows with first-class delegation." >}} +{{< feature-card title="Skills from Git" desc="Load markdown knowledge from Git repos at startup. Agents learn your runbooks, ADRs, and internal docs." >}} +{{< feature-card title="Prompt templates" desc="Reusable prompt fragments stored as ConfigMaps. DRY your system prompts across agents." >}} +{{< feature-card title="Context compaction" desc="Auto-summarization of long conversation histories. Agents stay coherent without blowing token budgets." >}} +{{< feature-card title="Sandbox & security" desc="Agent sandboxing, RBAC, and security hardening out of the box. Run untrusted code safely." >}} +{{< feature-card title="Full observability" desc="OTel tracing, Prometheus metrics, structured logs. See every prompt, every tool call, every token." >}} +{{< feature-card title="Postgres storage" desc="Production-grade Postgres-backed storage with reviewable migrations. No proprietary database lock-in." >}} +{{< /feature-cards >}} + +## Enterprise distributions + +Check out [Solo Enterprise for kagent](https://www.solo.io/products/kagent-enterprise), a comprehensive agent management interface for creating, validating, debugging, deploying, and monitoring AI agents across federated Kubernetes clusters. Solo Enterprise for kagent adds enterprise-grade capabilities on top of the kagent open source project, including advanced management features, observability tools, and multicluster federation support. + +## Getting Started + +To start using kagent in your environment, check out the [Quick Start Guide](/docs/kagent/getting-started/quickstart) guide. For a deeper understanding of how kagent works, refer to the [kagent architecture](/docs/kagent/concepts/architecture). + +Ready to contribute? Visit our [Github repository](https://github.com/kagent-dev) to learn how you can help expand the ecosystem of cloud-native AI agents. + +## Community + +Join the kagent community: +- Explore our repositories on [GitHub](https://github.com/kagent-dev) +- Join the discussion in the #kagent channel on CNCF Slack +- Check our [FAQ](/docs/kagent/resources/faq) for common questions +- Follow our [Feature Roadmap](https://github.com/kagent-dev/kagent/blob/main/README.md#roadmap) for upcoming developments diff --git a/docs-site/content/kagent/observability/_index.md b/docs-site/content/kagent/observability/_index.md new file mode 100644 index 00000000..39484fc7 --- /dev/null +++ b/docs-site/content/kagent/observability/_index.md @@ -0,0 +1,9 @@ +--- +title: Observability +description: Monitor and observe your kagent installation with dashboards and audit logs. +weight: 6 +author: kagent.dev +--- + +Monitor and observe your kagent installation with dashboards and audit logs. + diff --git a/docs-site/content/kagent/observability/audit-prompts.md b/docs-site/content/kagent/observability/audit-prompts.md new file mode 100644 index 00000000..c4301fc3 --- /dev/null +++ b/docs-site/content/kagent/observability/audit-prompts.md @@ -0,0 +1,328 @@ +--- +title: Audit kagent prompts +description: Review and audit prompts used by kagent agents. +weight: 1 +author: kagent.dev +--- + +Audit all prompts (inputs) and replies (outputs) from your agents. + +Such auditing capability can help security, compliance, and similar teams examine how your users interact with your kagent environment. For example, you might check that users are not sharing personally identifiable information (PII) or other sensitive information when chatting with LLMs, or follow up on past conversations with agents to understand what systems have been interacted with. + +## About auditing prompts + +kagent integrates with OpenTelemetry (OTel) systems to emit input/output messages as log events, which you can ingest into your logging or security information and event management (SIEM) systems for auditing purposes. + +kagent supports logging input/output messages for the following LLM providers: + +- OpenAI +- Anthropic + +## Before you begin + +1. [Install kagent](/docs/kagent/introduction/installation) in your cluster. + +2. Add the OpenTelemetry Helm repository. + + ```bash + helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts + helm repo update + ``` + +3. Set up a logging backend that supports OpenTelemetry's OTLP protocol, such as Grafana Loki, Datadog, Splunk, or other OTLP-compatible systems. Example Loki configuration: + + ```yaml + helm upgrade --install loki loki \ + --repo https://grafana.github.io/helm-charts \ + --version {{< reuse "versions/loki.md" >}} \ + --namespace telemetry \ + --create-namespace \ + --values - <}} \ + --namespace telemetry \ + --create-namespace \ + --values - <` with the endpoint of your logging backend. For example: + - Grafana Loki in the same cluster: `http://loki.telemetry.svc.cluster.local:3100` + - Datadog: `https://api.datadoghq.com` + - A custom OTLP endpoint: `https://your-otel-endpoint.com:4317` + + - **Tracing OTLP receiver, exporter, and pipeline** that you can point to your tracing backend. Replace `` with the endpoint of your tracing backend. For example: + - Tempo in the same cluster: `http://tempo.telemetry.svc.cluster.local:4317` + - Jaeger: `http://jaeger.telemetry.svc.cluster.local:6831` + - Zipkin: `http://zipkin.telemetry.svc.cluster.local:9411` + - A custom OTLP endpoint: `https://your-otel-endpoint.com:4317` + + ```yaml + cat > otel-collector-audit.yaml < values.yaml + ``` + +2. Update the Helm values file to including the following endpoints. Replace the logging and tracing endpoint with the OTel collector endpoints that you previously set up. Make sure that you use a supported LLM provider, such as OpenAI or Anthropic. + + > **Note**: If you find the traces emitted by default too verbose, you can disable them by setting `otel.tracing.enabled=false`. Logging still works even if tracing is disabled. + + ```yaml + providers: + # OpenAI or Anthropic are supported for auditing + default: openAI + openAI: + apiKey: $OPENAI_API_KEY + otel: + tracing: + enabled: true + exporter: + otlp: + endpoint: http://opentelemetry-collector-audit.telemetry.svc.cluster.local:4317 + timeout: 15 + insecure: true + logging: + enabled: true + exporter: + otlp: + endpoint: http://opentelemetry-collector-audit.telemetry.svc.cluster.local:4317 + timeout: 15 + insecure: true + ``` + +3. Upgrade kagent with the updated Helm values. Replace `` with the version of kagent that you want to upgrade to. + + ```bash + helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --version $VERSION \ + -f values.yaml + ``` + +## Verify the setup + +1. Generate some traffic by invoking an agent that uses OpenAI or Anthropic. For example, you might ask the Helm agent how many Helm releases are currently deployed in your cluster. + +2. Check that logs are being collected by the OpenTelemetry collector. + + ```bash + kubectl -n telemetry logs -l app.kubernetes.io/name=opentelemetry-collector + ``` + + Example output: + + ```console + Trace ID: c421bc11e93daaceee59b9e5ff8aa6d0 + Span ID: 02552aea76988990 + Flags: 1 + LogRecord #115 + ObservedTimestamp: 2026-01-12 16:02:13.278948633 +0000 UTC + Timestamp: 2026-01-12 16:02:13.278943258 +0000 UTC + SeverityText: + SeverityNumber: Info(9) + Body: Map({"content":"NAME \tNAMESPACE\tREVISION\tUPDATED \tSTATUS \tCHART \tAPP VERSION\nkagent \tkagent \t3 \t2026-01-12 09:40:29.568344 -0500 -0500\tdeployed\tkagent-0.7.8 \t \nkagent-crds\tkagent \t1 \t2026-01-09 11:31:00.362347 -0500 -0500\tdeployed\tkagent-crds-0.7.8\t \n"}) + Attributes: + -> gen_ai.system: Str(openai) + -> event.name: Str(gen_ai.tool.message) + Trace ID: c421bc11e93daaceee59b9e5ff8aa6d0 + Span ID: 02552aea76988990 + Flags: 1 + LogRecord #116 + ObservedTimestamp: 2026-01-12 16:02:13.278959716 +0000 UTC + Timestamp: 2026-01-12 16:02:13.278954424 +0000 UTC + SeverityText: + SeverityNumber: Info(9) + Body: Map({"content":"NAME \tNAMESPACE\tREVISION\tUPDATED \tSTATUS \tCHART \tAPP VERSION\nloki \ttelemetry\t1 \t2026-01-09 11:08:29.179771 -0500 -0500\tdeployed\tloki-6.24.0 \t3.3.2 \nopentelemetry-collector-audit\ttelemetry\t2 \t2026-01-12 09:40:18.82713 -0500 -0500 \tdeployed\topentelemetry-collector-0.143.0\t0.143.0 \ntempo \ttelemetry\t1 \t2026-01-09 11:24:31.685855 -0500 -0500\tdeployed\ttempo-1.16.0 \t2.6.1 \n"}) + Attributes: + -> gen_ai.system: Str(openai) + -> event.name: Str(gen_ai.tool.message) + Trace ID: c421bc11e93daaceee59b9e5ff8aa6d0 + Span ID: 02552aea76988990 + Flags: 1 + LogRecord #117 + ObservedTimestamp: 2026-01-12 16:02:13.278976383 +0000 UTC + Timestamp: 2026-01-12 16:02:13.278964341 +0000 UTC + SeverityText: + SeverityNumber: Info(9) + Body: Map({"content":"In the kagent and telemetry namespaces."}) + Attributes: + -> gen_ai.system: Str(openai) + -> event.name: Str(gen_ai.user.message) + ... + ``` + +## Cleanup + +To remove the OpenTelemetry collector: + +```bash +helm uninstall opentelemetry-collector-audit -n telemetry +kubectl delete namespace telemetry +``` + +To disable logging and tracing in kagent: + +```bash +helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --reuse-values \ + --version $VERSION \ + --set otel.logging.enabled=false \ + --set otel.tracing.enabled=false +``` diff --git a/docs-site/content/kagent/observability/launch-ui.md b/docs-site/content/kagent/observability/launch-ui.md new file mode 100644 index 00000000..66308306 --- /dev/null +++ b/docs-site/content/kagent/observability/launch-ui.md @@ -0,0 +1,56 @@ +--- +title: Launch the UI +description: Open the kagent dashboard using the CLI or port-forwarding. +weight: 0 +author: kagent.dev +--- + +Access the kagent dashboard to manage your agents, tools, and models. You can open the dashboard by using the kagent CLI command or by port-forwarding the kagent UI service. + +## Before you begin + +Make sure that kagent is installed in your cluster and the kagent UI service is running. + +```bash +kubectl get svc -n kagent kagent-ui +``` + +## Launch the UI with the CLI + +The easiest way to launch the kagent dashboard is by using the `kagent dashboard` command. This command automatically sets up port-forwarding and opens the dashboard in your browser. + +> **Note**: The `kagent dashboard` command is currently available on macOS. On other platforms, use the port-forwarding method described in the next section. + +1. Run the dashboard command: + + ```bash + kagent dashboard + ``` + + The command port-forwards the `kagent-ui` service to `localhost:8082` and opens the dashboard in your default browser. + +2. Access the dashboard at `http://localhost:8082`. + +3. When you're done, press `Enter` in the terminal to stop the port-forward. + +## Launch the UI with port-forwarding + +If you prefer to manually set up port-forwarding, or if you're on a platform where the `kagent` CLI isn't available, you can port-forward the service yourself. + +1. Port-forward the `kagent-ui` service to your local machine. The following command forwards port 8080 from the service to port 8082 on your local machine. + + ```bash + kubectl port-forward -n kagent service/kagent-ui 8082:8080 + ``` + +2. In your browser, open the dashboard at [http://localhost:8082](http://localhost:8082). + +3. When you're done, stop the port-forward by pressing `Ctrl+C` in the terminal where the port-forward is running. + +## Next steps + +You can use the UI to view and manage your agents, tools, and models. For more information, see the following guides: + +- [Create your first agent](/docs/kagent/getting-started/first-agent) +- [Add MCP tools to your agents](/docs/kagent/getting-started/first-mcp-tool) +- [Configure LLM providers](/docs/kagent/supported-providers) diff --git a/docs-site/content/kagent/observability/tracing.md b/docs-site/content/kagent/observability/tracing.md new file mode 100644 index 00000000..fa4a97e3 --- /dev/null +++ b/docs-site/content/kagent/observability/tracing.md @@ -0,0 +1,145 @@ +--- +title: Tracing +description: A guide to tracing your kagent agents. +weight: 6 +author: kagent.dev +--- + +Set up tracing for your kagent agents. + +## Before you begin + +[Install kagent](/docs/kagent/introduction/installation). + +## Install Jaeger + +Install a tracing tool, such as Jaeger. The following example installs Jaeger in all-in-one mode so that you can try out basic tracing capabilities without needing to install any other components. + +1. Create a `jaeger.yaml` configuration file. + + ```yaml + cat << 'EOF' > jaeger.yaml + provisionDataStore: + cassandra: false + allInOne: + enabled: true + storage: + type: memory + agent: + enabled: false + collector: + enabled: false + query: + enabled: false + EOF + ``` + +2. Install Jaeger. + + ```bash + helm repo add jaegertracing https://jaegertracing.github.io/helm-charts + helm repo update + helm upgrade --install jaeger jaegertracing/jaeger \ + --namespace jaeger \ + --create-namespace \ + --history-max 3 \ + --values jaeger.yaml \ + --version {{< reuse "versions/jaeger.md" >}} + ``` + +## Upgrade kagent + +Upgrade your kagent Helm release to enable tracing. + +1. Get your current Helm release values. + + ```shell + helm get values kagent -n kagent > values.yaml + ``` + +2. In the values file, enable tracing with the following settings. + + ```yaml + otel: + tracing: + enabled: true + exporter: + otlp: + endpoint: http://jaeger.jaeger.svc.cluster.local:4317 + ``` + +3. Upgrade the kagent Helm chart with the tracing details. + + ```bash + helm upgrade -i kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --values values.yaml + ``` + +## Trace your first agent + +Now that you installed kagent with Jaeger, learn how to trace requests to an agent. + +### Generate tracing data + +To generate tracing data, you can chat with a pre-configured agent such as `k8s-agent`. For more information about agents, see the [Your First Agent](/docs/kagent/getting-started/first-agent) guide. + +1. Launch the kagent dashboard. + + ```bash + kagent dashboard + ``` + + Example output: + + ```console + kagent dashboard is available at http://localhost:8082 + Press Enter to stop the port-forward... + ``` + + ![kagent UI](/images/kagent-landing.png "kagent dashboard main page") + +2. Click the pre-configured `k8s-agent` agent. + +3. In the conversation box, enter a query such as "What pods are running in my cluster?". + + ![kagent UI](/images/k8s-agent-query-light.png "Chatting with an agent") + +### Review tracing data in Jaeger + +Review the tracing data in Jaeger for the agent queries that you just sent. + +1. In your terminal, enable port-forwarding for the Jaeger service. + + ```bash + kubectl port-forward -n jaeger svc/jaeger 16686:16686 + ``` + +2. In your browser, open the Jaeger UI: [http://localhost:16686](http://localhost:16686). + +3. From the Jaeger **Search** menu, in the **Service** dropdown, select the `kagent` service. + +4. In the **Operation** dropdown, select `agent_run [k8s-agent]` to filter for traces specific to the agent. + +5. Click **Find Traces**. + +6. Review the traces for the `kagent` service. + + ![Jaeger UI](/images/jaeger-landing.png "Jaeger results page") + +7. Click on a trace to see more details. + + ![Jaeger UI](/images/jaeger-trace.png "Jaeger trace details") + +That's it! You've now traced your first agent. + +## Next Steps + +- Learn about [Core Concepts](/docs/kagent/concepts) +- Try out some [Example](/docs/kagent/examples) guides + +## Need Help? + +- Visit our [GitHub repository](https://github.com/kagent-dev/kagent) +- Ask a question on [Discord](https://discord.gg/Fu3k65f2k3) +- Check out the [FAQ](/docs/kagent/resources/faq) \ No newline at end of file diff --git a/docs-site/content/kagent/operations/_index.md b/docs-site/content/kagent/operations/_index.md new file mode 100644 index 00000000..fea7b7ac --- /dev/null +++ b/docs-site/content/kagent/operations/_index.md @@ -0,0 +1,9 @@ +--- +title: Operations +description: Manage your kagent installation with upgrade, uninstall, and operational tasks. +weight: 7 +author: kagent.dev +--- + +Manage your kagent installation across its lifecycle. + diff --git a/docs-site/content/kagent/operations/debug.md b/docs-site/content/kagent/operations/debug.md new file mode 100644 index 00000000..6abcaedb --- /dev/null +++ b/docs-site/content/kagent/operations/debug.md @@ -0,0 +1,41 @@ +--- +title: Debug kagent +description: Find solutions to common issues and troubleshooting tips for kagent. +weight: 0 +author: kagent.dev +--- + +Troubleshoot and debug issues with your kagent installation. + +## My agent doesn't seem to be working + +If your agent is not showing up even though you applied the manifest, it's likely because the agent has been rejected by the engine. This error should be reported on the status of the agent. + +Run the following command to get the status of the agent: + +```shell +kubectl get agent -n kagent [agent-name] -o yaml +``` + +This should give you the reason why the agent was rejected. + +If it's not there, you can try to get the logs of the agent: + +```shell +kubectl logs -n kagent deployment/kagent-controller +kubectl logs -n kagent deployment/kagent-ui +``` + +You can also set the logging level to `DEBUG` to get more detailed logs from the agent pod. To do that, edit the agent resource and add the `LOG_LEVEL` environment variable to the `deployment` field: + +```yaml +spec: + declarative: + deployment: + env: + - name: LOG_LEVEL + value: debug +.. +``` + +You can also ask for help in the [community](https://discord.gg/Fu3k65f2k3) or log an issue on [GitHub](https://github.com/kagent-dev/kagent). You can create a bug report using the kagent CLI by running `kagent bug-report`. Before attaching files to your bug report, make sure they don't contain any sensitive information! diff --git a/docs-site/content/kagent/operations/operational-considerations.md b/docs-site/content/kagent/operations/operational-considerations.md new file mode 100644 index 00000000..9e2cd8b5 --- /dev/null +++ b/docs-site/content/kagent/operations/operational-considerations.md @@ -0,0 +1,231 @@ +--- +title: Operational considerations +description: Important operational considerations when running kagent in production. +weight: 1 +author: kagent.dev +--- + +Review the following operational considerations when running kagent in production environments, including database configuration, high availability, and secret management. + +## Automatic agent restart on secret updates + +kagent automatically restarts agents when you update the secrets that the agents reference. This restart ensures that agents pick up new API keys, TLS certificates, and other secret values without manual intervention. + +The following secret updates trigger automatic agent restarts: + +- **API keys**: Secrets referenced in `ModelConfig` resources (e.g., `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) +- **TLS certificates**: Secrets referenced in `ModelConfig` TLS configuration (e.g., CA certificates) +- **Environment variables**: Any secrets referenced via `secretKeyRef` in agent deployment specifications + +## Leader election when controller is scaled + +When you scale the kagent controller to multiple replicas for high availability, leader election is automatically enabled. This ensures that only one controller instance actively reconciles resources at a time, preventing conflicts and duplicate operations. + +### Leader election scenarios + +- **Single replica**: No leader election needed; the single controller instance handles all operations. +- **Multiple replicas**: Leader election is automatically enabled when `controller.replicas > 1`. +- **Active leader**: Only the elected leader performs reconciliation operations. +- **Standby replicas**: Other replicas remain ready but do not perform reconciliation until they become the leader. + +### Enable high availability + +You can set the number of controller replicas to enable high availability. + +**Helm `--set` flag:** + +```bash +helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set controller.replicas=3 +``` + +**Helm values file:** + +```yaml +controller: + replicas: 3 +``` + +### More considerations for HA + +- **Database requirement**: PostgreSQL is the default database backend and supports multiple controller replicas. The bundled PostgreSQL instance is deployed automatically unless you configure an external PostgreSQL. +- **Leader election**: Leader election uses Kubernetes leases and is handled automatically. +- **Failover**: If the leader fails, another replica automatically becomes the leader. + +## Database configuration + +kagent uses PostgreSQL as the database backend. + +By default, a bundled PostgreSQL instance is deployed when you install kagent. This bundled instance works out of the box without any external prerequisites. It is a simple instance that is meant for demos, local development, and short proofs of concept. + +> **Note:** The default bundled image (`postgres:18`) does not include the pgvector extension. If you need vector features such as long-term memory, either use an external PostgreSQL with pgvector installed and set `database.postgres.vectorEnabled: true`, or override the bundled image to a pgvector image. + +For production deployments, bring your own external PostgreSQL instance. + +### How database connection is determined + +The `database.postgres.bundled.enabled` and `database.postgres.url`/`database.postgres.urlFile` settings are independent controls. + +- **`bundled.enabled`** controls whether the bundled PostgreSQL pod and its PVC are deployed. It does not affect which database the controller connects to. +- **`url` / `urlFile`** controls what the controller connects to. When either is set, the controller uses it. When both are empty, the controller connects to the bundled instance. + +**Connection precedence (controller):** + +``` +urlFile > url > bundled connection string +``` + +| Scenario | `bundled.enabled` | `url` / `urlFile` | Bundled pod deployed? | Controller connects to | +|---|---|---|---|---| +| Default (dev/eval) | `true` | unset | yes | bundled | +| External DB, no bundled pod | `false` | set | no | external | +| External DB, bundled pod kept running | `true` | set | yes | external | +| Bundled disabled, no external set | `false` | unset | no | error (misconfigured) | + +**Migration**: This means that you can keep the bundled pod running while the controller points at an external database, which is useful for migrating data. + +### Bundled PostgreSQL + +The bundled PostgreSQL instance is deployed by default (`database.postgres.bundled.enabled: true`). The database name, username, and password are all hardcoded to `kagent`. Credentials are stored in a Kubernetes Secret. + +You can customize the storage size and image of the bundled instance when you [install](/docs/kagent/introduction/installation) or upgrade kagent. + +1. Add the bundled database settings to your Helm values file for kagent. + + ```yaml + database: + postgres: + bundled: + enabled: true # default + storage: 500Mi + image: + registry: docker.io + repository: library + name: postgres + tag: "18" + ``` + +2. Apply the values to the kagent Helm release. + + ```bash + helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --values kagent.yaml + ``` + +### External PostgreSQL + +For production environments, use an external PostgreSQL instance instead of the bundled one. Set `database.postgres.bundled.enabled: false` and configure the connection with `database.postgres.url` or `database.postgres.urlFile`. + +> **Note**: If your external PostgreSQL has the `pgvector` extension installed and you want to use vector-based memory features, set `database.postgres.vectorEnabled: true`. The default is `false`. + +**Helm `--set` flag:** + +```bash +helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set database.postgres.bundled.enabled=false \ + --set database.postgres.url=postgres://user:password@postgres-host:5432/kagent \ + --set database.postgres.vectorEnabled=true \ + --set controller.replicas=3 +``` + +**Helm values file:** + +```yaml +database: + postgres: + url: postgres://user:password@postgres-host:5432/kagent + vectorEnabled: true # Set to true if your external PostgreSQL has pgvector + bundled: + enabled: false +controller: + replicas: 3 +``` + +**Using a secret for the database URL:** Mount a Kubernetes secret that contains the PostgreSQL connection string using `controller.volumes` and `controller.volumeMounts`, then reference the mount path with `urlFile`. This keeps credentials out of Helm values. + +```yaml +database: + postgres: + urlFile: /var/secrets/db-url + vectorEnabled: true + bundled: + enabled: false +controller: + volumes: + - name: db-secret + secret: + secretName: my-postgres-url-secret + volumeMounts: + - name: db-secret + mountPath: /var/secrets + readOnly: true +``` + +## Secure execution environment + +kagent supports Kubernetes security contexts to run agents and tool servers with reduced privileges. Configure `securityContext` and `podSecurityContext` on your Agent or ToolServer resources to enforce secure execution. + +Common settings include: + +- **`runAsNonRoot: true`**: Ensures the container does not run as root. +- **`runAsUser`**: Specifies the user ID for the container process. +- **`readOnlyRootFilesystem`**: Mounts the root filesystem as read-only when possible. + +At the Helm chart level, you can set global defaults with `podSecurityContext` and `securityContext` in your values. For more information, see the [Kubernetes SecurityContext documentation](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). + +{{< tabs >}} +{{< tab name="Declarative agents" >}} +Set these in `spec.declarative.deployment.podSecurityContext` and `spec.declarative.deployment.securityContext`. + +```yaml +spec: + type: Declarative + declarative: + deployment: + podSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false +``` +{{< /tab >}} +{{< tab name="BYO agents" >}} +Set these in `spec.byo.deployment.podSecurityContext` and `spec.byo.deployment.securityContext`. + +```yaml +spec: + type: BYO + byo: + deployment: + podSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false +``` +{{< /tab >}} +{{< /tabs >}} + +## Proxy configuration for agent traffic + +When agents and MCP servers run behind an API gateway or proxy, you can configure kagent to route agent-to-agent and agent-to-MCP traffic through that proxy. Set `proxy.url` in your Helm values to the proxy endpoint. + +The proxy applies to: + +- Agent-to-agent traffic (when one agent invokes another agent as a tool) +- Agent-to-MCP-server traffic (when agents call ToolServers, Services, or RemoteMCPServers with internal Kubernetes URLs) + +Example Helm configuration: + +```yaml +proxy: + url: "http://proxy.kagent.svc.cluster.local:8080" +``` + +The controller rewrites internal URLs to use the proxy and sets the `x-kagent-host` header so the proxy can route requests to the correct backend. External URLs (for example, RemoteMCPServers pointing to `https://external.example.com`) are not rewritten. + diff --git a/docs-site/content/kagent/operations/uninstall.md b/docs-site/content/kagent/operations/uninstall.md new file mode 100644 index 00000000..ed009b5c --- /dev/null +++ b/docs-site/content/kagent/operations/uninstall.md @@ -0,0 +1,46 @@ +--- +title: Uninstall kagent +description: Learn how to uninstall kagent from your Kubernetes cluster. +weight: 2 +author: kagent.dev +--- + +Remove kagent from your Kubernetes cluster using the kagent CLI or Helm. + +> **Warning**: Uninstalling kagent deletes all kagent resources across all namespaces in your cluster, including agents, tools, and configurations. This action cannot be undone. + +## Before you begin + +- Ensure that you have administrative access to your cluster. +- Back up any agent configurations or data that you want to preserve. +- Review any agents or tools that depend on kagent before uninstalling. + +## Uninstall with the kagent CLI + +Remove kagent by using the CLI. For more options, see the [`kagent uninstall` command reference](/docs/kagent/resources/cli/kagent-uninstall). + +```bash +kagent uninstall +``` + +Example output: + +```console +kagent uninstalled successfully +``` + +## Uninstall with Helm + +To uninstall kagent using Helm, remove the Helm releases in the correct order. + +1. Uninstall the kagent chart. + + ```bash + helm uninstall kagent -n kagent + ``` + +2. Remove all kagent CRDs and resources across your cluster. + + ```bash + helm uninstall kagent-crds -n kagent + ``` \ No newline at end of file diff --git a/docs-site/content/kagent/operations/upgrade.md b/docs-site/content/kagent/operations/upgrade.md new file mode 100644 index 00000000..80d7891f --- /dev/null +++ b/docs-site/content/kagent/operations/upgrade.md @@ -0,0 +1,196 @@ +--- +title: Upgrade kagent +description: Learn how to upgrade kagent to the latest version. +weight: 1 +author: kagent.dev +--- + +Follow these steps to upgrade kagent to the latest version and keep your cluster up to date with new features and bug fixes. + +## Before you begin + +1. Save the version that you want to upgrade to in an environment variable. For available versions, refer to the [kagent releases](https://github.com/kagent-dev/kagent/releases). + + ```bash + export NEW_VERSION= + ``` + +2. Read the [release notes](/docs/kagent/resources/release-notes) for the version you are upgrading to. Pay attention to any breaking changes or deprecations that might affect your configuration. + +3. Back up your current configuration, including the following: + - Agent definitions + - Any custom settings + - PostgreSQL database: You can take a snapshot now so that you have a restore point if the upgrade fails. For the database connection string, see [Database configuration](/docs/kagent/operations/operational-considerations#database-configuration). + + ```bash + pg_dump "postgres://:@:5432/" \ + --format=custom \ + --file=kagent-pre-upgrade-snapshot.dump + ``` + +4. **v0.9.0 and later**: You must be running at least v0.8.0 before upgrading to v0.9.0. Check the [release notes](/docs/kagent/resources/release-notes#v09) for 0.9-specific upgrades related to database migrations and RBAC scope. + +## Upgrade kagent + +1. Get the Helm values file for your current kagent release. + + ```bash + helm get values kagent -n kagent -o yaml > values.yaml + ``` + +2. Compare your current Helm chart values with the version that you want to upgrade to. + + * **Show all values**: + + ```bash + helm show values oci://ghcr.io/kagent-dev/kagent/helm/kagent --version $NEW_VERSION + ``` + + * **Get a file with all values** + + ```bash + helm pull oci://ghcr.io/kagent-dev/kagent/helm/kagent --version $NEW_VERSION + tar -xvf kagent-$NEW_VERSION.tgz + open kagent/values.yaml + ``` + +3. Make any changes that you want by editing your `values.yaml` Helm values file or preparing `--set` flags for the upgrade commands. + + > **Note**: As of [version 0.7](/docs/kagent/resources/release-notes#kmcp-installed-by-default), the kmcp subproject is included by default with kagent. To use an existing kmcp installation that you already set up separately, set `kmcp.enabled=false` in your `values.yaml` file or `--set` commands for both the `kagent` and `kagent-crds` charts. + +4. Upgrade the kagent-crds chart. + + ```bash + helm upgrade kagent-crds oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds \ + --namespace kagent \ + --version $NEW_VERSION + ``` + +5. Upgrade the kagent chart. If you made changes to your values, add them with `--set` flags or `-f values.yaml`. + + ```bash + helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + -f values.yaml \ + --version $NEW_VERSION + ``` + +## Verify the upgrade + +After upgrading, verify that kagent is running. + +```bash +kubectl get pods -n kagent +``` + +## Roll back kagent + +If you need to roll back to a previous version after a successful upgrade, use the following steps. + +### Rollback compatibility window + +As of v0.9, kagent guarantees `n-1` application compatibility with the database: an application at version `n-1` can start against a database schema applied by version `n`. This means that you can roll back the application without manually resetting the database first, as long as you stay within the supported window: + +- **Supported**: Roll back one minor version (for example, `v0.10.x` → `v0.9.x`). +- **Requires DB reset, one minor at a time**: Roll back more than one minor version. Be sure to roll back only one minor version at a time, as skipping a minor version can result in data loss. + +When the controller detects that the database schema is ahead of its own migration files, it starts in compatibility mode and skips migration application. The database schema is left unchanged. + +### Steps to roll back + +1. Save the kagent version you want to roll back to in an environment variable. + ```bash + export ROLLBACK_VERSION= + ``` + +2. Roll back the kagent chart. + ```bash + helm upgrade kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + -f values.yaml \ + --version $ROLLBACK_VERSION + ``` + +3. Roll back the kagent-crds chart. + ```bash + helm upgrade kagent-crds oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds \ + --namespace kagent \ + --version $ROLLBACK_VERSION + ``` + +4. Verify that the rollback succeeded. + ```bash + kubectl get pods -n kagent + ``` + +### Reset the database before rolling back further + +If you need to roll back more than one minor kagent version, be sure to roll back one minor version at a time. Kagent guarantees backwards compatibility of only one minor version, so skipping minor versions can result in data loss. + +You have two options for resetting the database schema at each step. + +#### Option 1: Restore from snapshot + +If you took a snapshot before upgrading, you can restore it directly. This is simpler than running down migrations, but any data written after the snapshot was taken is lost. + +```bash +pg_restore \ + --clean \ + --dbname="postgres://:@:5432/" \ + kagent-pre-upgrade-snapshot.dump +``` + +After restoring, follow the steps to [roll back the kagent application](#steps-to-roll-back). + +#### Option 2: Run down migrations + +Use `golang-migrate` to run down migrations one minor version at a time. This preserves data written after the snapshot but requires more steps. + +The source must be the current (newer) version that you are rolling back from, because it contains the down migrations needed to reverse the schema changes. The `goto` target is the highest migration sequence number present in the version that you are rolling back to. + +For example, `v0.9.9` has migrations up to `000005_a2a_protocol_version.up.sql` and `v0.9.3` has migrations up to `000004_feedback_single_pk.up.sql`. To roll back from `v0.9.9` to `v0.9.3`, you set `CURRENT_VERSION=0.9.9`, `ROLLBACK_VERSION=0.9.3`, and run `goto 4` because you want to go back to migration sequence 4 (v0.9.3's `000004`). + +1. Save your current kagent version and the kagent version you want to roll back to in environment variables. + ```bash + export CURRENT_VERSION= + export ROLLBACK_VERSION= + ``` + +2. Install [`golang-migrate`](https://github.com/golang-migrate/migrate/tree/master/cmd/migrate). + +3. Stop the kagent controller. + ```bash + kubectl -n kagent scale deploy/kagent-controller --replicas=0 + ``` + +4. Open the core migration directory for your rollback version and save the sequence number of the highest-numbered file in an environment variable, such as `4` from the previous v0.9.3 `goto 4` example. + ```bash + open "https://github.com/kagent-dev/kagent/tree/v${ROLLBACK_VERSION}/go/core/pkg/migrations/core/" + ``` + ```bash + export ROLLBACK_MIGRATION_VERSION= + ``` + +5. Reset the core track. The `github://` source references the migration files directly from the release tag without a local checkout. For the database connection string, see [Database configuration](/docs/kagent/operations/operational-considerations#database-configuration). + ```bash + migrate \ + -source "github://kagent-dev/kagent/go/core/pkg/migrations/core#v$CURRENT_VERSION" \ + -database "postgres://:@:5432/?sslmode=require&x-migrations-table=schema_migrations" \ + goto $ROLLBACK_MIGRATION_VERSION + ``` + +6. If vector features are enabled, reset the vector track as well. + 1. Open the vector migration directory for your rollback version and save the sequence number of the highest-numbered file in an environment variable. + ```bash + open "https://github.com/kagent-dev/kagent/tree/v${ROLLBACK_VERSION}/go/core/pkg/migrations/vector/" + export ROLLBACK_VECTOR_MIGRATION_VERSION= + ``` + 2. Reset the vector track. + ```bash + migrate \ + -source "github://kagent-dev/kagent/go/core/pkg/migrations/vector#v$CURRENT_VERSION" \ + -database "postgres://:@:5432/?sslmode=require&x-migrations-table=vector_schema_migrations" \ + goto $ROLLBACK_VECTOR_MIGRATION_VERSION + ``` + +7. After the database is at the correct schema version, follow the steps to [roll back the kagent application](#steps-to-roll-back). diff --git a/docs-site/content/kagent/resources/_index.md b/docs-site/content/kagent/resources/_index.md new file mode 100644 index 00000000..b41f5c91 --- /dev/null +++ b/docs-site/content/kagent/resources/_index.md @@ -0,0 +1,22 @@ +--- +title: Resources +description: Find helpful resources and FAQs for kagent. Access guides, community links, and more. +weight: 7 +author: kagent.dev +--- + +Find helpful resources and FAQs for kagent. Access guides, community links, and more. + +{{< cards >}} +{{< card link="/docs/kagent/resources/cli" title="CLI docs" subtitle="Complete reference for the kagent CLI commands" >}} +{{< card link="/docs/kagent/resources/api-ref" title="API docs" subtitle="kagent API reference docs" >}} +{{< card link="/docs/kagent/resources/helm" title="Helm Chart Configuration" subtitle="kagent Helm chart configuration reference" >}} +{{< card link="/docs/kagent/resources/tools-ecosystem" title="Tools Ecosystem" subtitle="Comprehensive catalog of built-in tools for Kubernetes, Helm, Istio, Prometheus, Grafana, Cilium, and Argo Rollouts." >}} +{{< card link="/docs/kagent/resources/faq" title="Frequently Asked Questions" subtitle="Find answers to common questions about kagent." >}} +{{< card link="/docs/kagent/resources/release-notes" title="Release Notes" subtitle="Review the release notes for kagent." >}} +{{< card link="/docs/kagent/getting-started/quickstart" title="Quick Start Guide" subtitle="Get up and running quickly with kagent." >}} +{{< card link="https://github.com/kagent-dev/kagent" title="Official GitHub Repository" subtitle="Access the source code and contribute to kagent development." >}} +{{< card link="https://github.com/kagent-dev/kagent/blob/main/CONTRIBUTING.md" title="Contribution Guide" subtitle="Learn how to contribute to the kagent project." >}} +{{< card link="https://discord.gg/Fu3k65f2k3" title="Join our Discord Community" subtitle="Connect with other kagent users and developers." >}} +{{< /cards >}} + diff --git a/docs-site/content/kagent/resources/api-ref.md b/docs-site/content/kagent/resources/api-ref.md new file mode 100644 index 00000000..b569cc88 --- /dev/null +++ b/docs-site/content/kagent/resources/api-ref.md @@ -0,0 +1,1273 @@ +--- +title: API Reference +linkTitle: API docs +description: kagent API reference documentation +weight: 1 +author: kagent.dev +--- + +## Packages +- [kagent.dev/v1alpha2](#kagentdevv1alpha2) + +## kagent.dev/v1alpha2 + +Package v1alpha1 contains API Schema definitions for the agent v1alpha1 API group. + +### Resource Types +- [Agent](#agent) +- [AgentHarness](#agentharness) +- [ModelConfig](#modelconfig) +- [ModelProviderConfig](#modelproviderconfig) +- [RemoteMCPServer](#remotemcpserver) +- [SandboxAgent](#sandboxagent) + +#### A2AConfig + +_Appears in:_ +- [DeclarativeAgentSpec](#declarativeagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `skills` _[AgentSkill](#agentskill) array_ | | | MinItems: 1
    | + +#### Agent + +Agent is the Schema for the agents API. + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `kagent.dev/v1alpha2` | | | +| `kind` _string_ | `Agent` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
    Servers may infer this from the endpoint the client submits requests to.
    Cannot be updated.
    In CamelCase.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
    Servers should convert recognized schemas to the latest internal value, and
    may reject unrecognized values.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[AgentSpec](#agentspec)_ | | | | +| `status` _[AgentStatus](#agentstatus)_ | | | | + +#### AgentHarness + +AgentHarness is a generic remote execution environment provisioned by a +backend (OpenClaw or Hermes) running on Agent Substrate. + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `kagent.dev/v1alpha2` | | | +| `kind` _string_ | `AgentHarness` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
    Servers may infer this from the endpoint the client submits requests to.
    Cannot be updated.
    In CamelCase.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
    Servers should convert recognized schemas to the latest internal value, and
    may reject unrecognized values.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[AgentHarnessSpec](#agentharnessspec)_ | | | | +| `status` _[AgentHarnessStatus](#agentharnessstatus)_ | | | | + +#### AgentHarnessBackendType + +_Underlying type:_ _string_ + +AgentHarnessBackendType selects which sandbox control plane provisions the +environment. Additional backends may be added in the future. + +_Validation:_ +- Enum: [openclaw hermes] + +_Appears in:_ +- [AgentHarnessSpec](#agentharnessspec) +- [AgentHarnessStatusRef](#agentharnessstatusref) + +| Field | Description | +| --- | --- | +| `openclaw` | | +| `hermes` | | + +#### AgentHarnessChannel + +AgentHarnessChannel declares one messenger binding inside a harness VM. + +_Appears in:_ +- [AgentHarnessSpec](#agentharnessspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name is a stable id for this binding (OpenClaw channels.*.accounts key). | | MinLength: 1
    | +| `type` _[AgentHarnessChannelType](#agentharnesschanneltype)_ | | | Enum: [telegram slack]
    | +| `telegram` _[AgentHarnessTelegramChannelSpec](#agentharnesstelegramchannelspec)_ | | | | +| `slack` _[AgentHarnessSlackChannelSpec](#agentharnessslackchannelspec)_ | Slack configures Slack when type is Slack. | | | + +#### AgentHarnessChannelAccess + +_Underlying type:_ _string_ + +AgentHarnessChannelAccess controls whether the bot listens broadly or only on an allowlist. + +_Validation:_ +- Enum: [allowlist open disabled] + +_Appears in:_ +- [AgentHarnessOpenClawSlackOptions](#agentharnessopenclawslackoptions) + +| Field | Description | +| --- | --- | +| `allowlist` | | +| `open` | | +| `disabled` | | + +#### AgentHarnessChannelCredential + +AgentHarnessChannelCredential supplies a token from an inline value or a Secret/ConfigMap key. + +_Appears in:_ +- [AgentHarnessSlackChannelSpec](#agentharnessslackchannelspec) +- [AgentHarnessTelegramChannelSpec](#agentharnesstelegramchannelspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `value` _string_ | | | MaxLength: 8192
    | +| `valueFrom` _[ValueSource](#valuesource)_ | | | | + +#### AgentHarnessChannelType + +_Underlying type:_ _string_ + +AgentHarnessChannelType selects a messenger integration for OpenClaw harness VMs. + +_Validation:_ +- Enum: [telegram slack] + +_Appears in:_ +- [AgentHarnessChannel](#agentharnesschannel) + +| Field | Description | +| --- | --- | +| `telegram` | | +| `slack` | | + +#### AgentHarnessConnection + +AgentHarnessConnection describes how clients reach the provisioned harness VM. + +_Appears in:_ +- [AgentHarnessStatus](#agentharnessstatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `endpoint` _string_ | Endpoint is the backend-specific address (gRPC target, SSH host:port,
    ...) clients should use to reach the harness. | | | + +#### AgentHarnessHermesSlackOptions + +AgentHarnessHermesSlackOptions configures Hermes-specific Slack settings (env vars in the sandbox). + +_Appears in:_ +- [AgentHarnessSlackChannelSpec](#agentharnessslackchannelspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `allowedUserIDs` _string array_ | AllowedUserIDs restricts which Slack member IDs may interact with the bot (SLACK_ALLOWED_USERS). | | MaxItems: 1024
    | +| `allowedUserIDsFrom` _[ValueSource](#valuesource)_ | | | | +| `homeChannel` _string_ | HomeChannel is the default Slack channel ID for cron/scheduled messages (SLACK_HOME_CHANNEL). | | | +| `homeChannelName` _string_ | HomeChannelName is a human-readable label for HomeChannel (SLACK_HOME_CHANNEL_NAME). | | | + +#### AgentHarnessOpenClawSlackOptions + +AgentHarnessOpenClawSlackOptions configures OpenClaw-specific Slack routing. + +_Appears in:_ +- [AgentHarnessSlackChannelSpec](#agentharnessslackchannelspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `channelAccess` _[AgentHarnessChannelAccess](#agentharnesschannelaccess)_ | | | Enum: [allowlist open disabled]
    | +| `allowlistChannels` _string array_ | AllowlistChannels is required when channelAccess is allowlist. | | MaxItems: 1024
    | +| `interactiveReplies` _boolean_ | | true | | + +#### AgentHarnessSlackChannelSpec + +AgentHarnessSlackChannelSpec configures Slack when AgentHarnessChannel.type is Slack. +Backend-specific settings live under the matching backend key; AgentHarnessSpec validation +requires the key to match spec.backend. + +_Appears in:_ +- [AgentHarnessChannel](#agentharnesschannel) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `botToken` _[AgentHarnessChannelCredential](#agentharnesschannelcredential)_ | | | | +| `appToken` _[AgentHarnessChannelCredential](#agentharnesschannelcredential)_ | | | | +| `openclaw` _[AgentHarnessOpenClawSlackOptions](#agentharnessopenclawslackoptions)_ | OpenClaw configures OpenClaw-specific Slack routing. | | | +| `hermes` _[AgentHarnessHermesSlackOptions](#agentharnesshermesslackoptions)_ | Hermes configures Hermes-specific Slack settings. | | | + +#### AgentHarnessSpec + +AgentHarnessSpec describes a generic remote execution environment that agents +(or human operators) can attach to via exec or SSH. + +An AgentHarness is distinct from a SandboxAgent: it has no agent runtime baked +in. The backend is responsible for provisioning an environment that stays +ready to accept incoming commands. + +_Appears in:_ +- [AgentHarness](#agentharness) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `backend` _[AgentHarnessBackendType](#agentharnessbackendtype)_ | Backend selects the control plane to use. Required. | | Enum: [openclaw hermes]
    | +| `substrate` _[AgentHarnessSubstrateSpec](#agentharnesssubstratespec)_ | Substrate configures the Agent Substrate provisioning stack. Required. | | | +| `description` _string_ | Description is a short human-readable summary shown in the UI (e.g. agents list). | | | +| `image` _string_ | Image is the container image to run in the harness VM, if the backend
    supports per-resource images. Backend openclaw pins the image
    to the OpenClaw sandbox base when this field is empty; backend hermes pins
    to the Hermes sandbox base image when empty. | | | +| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core) array_ | Env is a list of environment variables injected into the harness workload.
    Values use the Kubernetes EnvVar shape; ValueFrom references are
    resolved server-side where supported. | | | +| `modelConfigRef` _string_ | ModelConfigRef is the reference to the ModelConfig used to configure the harness.
    The controller registers the gateway provider and, after the harness is Ready,
    writes OpenClaw config inside the VM (~/.openclaw/openclaw.json) and starts the gateway. | | | +| `channels` _[AgentHarnessChannel](#agentharnesschannel) array_ | Channels configures Telegram and Slack integrations for OpenClaw inside the harness VM. | | MaxItems: 1024
    | + +#### AgentHarnessStatus + +AgentHarnessStatus is the observed state of an AgentHarness. + +_Appears in:_ +- [AgentHarness](#agentharness) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `observedGeneration` _integer_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#condition-v1-meta) array_ | | | | +| `backendRef` _[AgentHarnessStatusRef](#agentharnessstatusref)_ | BackendRef points at the harness instance on the backend control
    plane, once Ensure has succeeded at least once. | | | +| `connection` _[AgentHarnessConnection](#agentharnessconnection)_ | Connection is populated by the controller when the harness is ready. | | | + +#### AgentHarnessStatusRef + +AgentHarnessStatusRef identifies a harness instance on an external control plane. + +_Appears in:_ +- [AgentHarnessStatus](#agentharnessstatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `backend` _[AgentHarnessBackendType](#agentharnessbackendtype)_ | | | Enum: [openclaw hermes]
    | +| `id` _string_ | | | | + +#### AgentHarnessSubstrateSnapshotsConfig + +AgentHarnessSubstrateSnapshotsConfig points at a GCS prefix for actor memory snapshots. +Substrate currently expects a gs:// location (see Agent Substrate SnapshotsConfig). + +_Appears in:_ +- [AgentHarnessSubstrateSpec](#agentharnesssubstratespec) +- [SandboxSubstrateSpec](#sandboxsubstratespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `location` _string_ | Location is the GCS URI prefix for golden and incremental snapshots.
    Example: gs://ate-snapshots/kagent/my-namespace/my-harness/ | | Pattern: `^gs://`
    | + +#### AgentHarnessSubstrateSpec + +AgentHarnessSubstrateSpec configures Agent Substrate (WorkerPool + ActorTemplate + Actor). + +kagent generates a per-harness ActorTemplate and creates an Actor from it. WorkerPool +capacity is referenced from workerPoolRef or the controller default; it is not +created or deleted by the AgentHarness controller. + +_Appears in:_ +- [AgentHarnessSpec](#agentharnessspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `workerPoolRef` _[TypedLocalReference](#typedlocalreference)_ | WorkerPoolRef references an existing ate.dev WorkerPool in the harness namespace.
    When unset, the controller uses its configured default WorkerPool. | | | +| `snapshotsConfig` _[AgentHarnessSubstrateSnapshotsConfig](#agentharnesssubstratesnapshotsconfig)_ | SnapshotsConfig configures actor memory snapshots. Defaults to
    gs://ate-snapshots/<namespace>/<agentharnessname> when unset. | | | +| `workloadImage` _string_ | WorkloadImage overrides the default openclaw sandbox image in the ActorTemplate. | | | + +#### AgentHarnessTelegramChannelSpec + +AgentHarnessTelegramChannelSpec configures Telegram when AgentHarnessChannel.type is Telegram. + +_Appears in:_ +- [AgentHarnessChannel](#agentharnesschannel) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `botToken` _[AgentHarnessChannelCredential](#agentharnesschannelcredential)_ | | | | +| `allowedUserIDs` _string array_ | | | MaxItems: 1024
    | +| `allowedUserIDsFrom` _[ValueSource](#valuesource)_ | | | | + +#### AgentProvider + +AgentProvider identifies the organization responsible for an agent on its A2A AgentCard. + +_Appears in:_ +- [AgentSpec](#agentspec) +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `organization` _string_ | Organization is the name of the agent provider's organization. | | MinLength: 1
    | +| `url` _string_ | URL is a URL for the agent provider's website or relevant documentation. | | Format: uri
    | + +#### AgentSkill + +AgentSkill describes a specific capability or function of the agent. + +_Appears in:_ +- [A2AConfig](#a2aconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | ID is the unique identifier for the skill. | | | +| `name` _string_ | Name is the human-readable name of the skill. | | MinLength: 1
    | +| `description` _string_ | Description is an optional detailed description of the skill. | | | +| `tags` _string array_ | Tags are optional tags for categorization. | | MaxItems: 20
    | +| `examples` _string array_ | Examples are optional usage examples. | | MaxItems: 20
    | +| `inputModes` _string array_ | InputModes are the supported input MIME types for this skill, overriding the agent's defaults. | | | +| `outputModes` _string array_ | OutputModes are the supported output MIME types for this skill, overriding the agent's defaults. | | | + +#### AgentSpec + +AgentSpec defines the desired state of Agent. + +_Appears in:_ +- [Agent](#agent) +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `type` _[AgentType](#agenttype)_ | | Declarative | Enum: [Declarative BYO]
    | +| `byo` _[BYOAgentSpec](#byoagentspec)_ | BYO configures a "bring your own" agent backed by a user-provided
    container image. Kagent deploys the image and expects it to serve the
    agent over the A2A protocol on port 8080.
    Required if type is BYO. | | | +| `declarative` _[DeclarativeAgentSpec](#declarativeagentspec)_ | Declarative configures an agent that is fully described by this resource
    (model, instructions, tools) and runs on one of kagent's built-in runtimes.
    Required if type is Declarative. | | | +| `description` _string_ | | | | +| `iconUrl` _string_ | IconURL is a URL to an icon representing the agent. It is surfaced on the
    agent's A2A AgentCard. | | Format: uri
    | +| `documentationUrl` _string_ | DocumentationURL is a URL to human-readable documentation for the agent. It
    is surfaced on the agent's A2A AgentCard. | | Format: uri
    | +| `version` _string_ | Version is the agent's version string, surfaced on the A2A AgentCard. | | | +| `provider` _[AgentProvider](#agentprovider)_ | Provider identifies the organization responsible for the agent. It is
    surfaced on the agent's A2A AgentCard. | | | +| `skills` _[SkillForAgent](#skillforagent)_ | Skills to load into the agent. They will be pulled from the specified container images.
    and made available to the agent under the `/skills` folder. | | | +| `sandbox` _[SandboxConfig](#sandboxconfig)_ | Sandbox configures sandboxed execution behavior shared across runtimes.
    This is intended for sandboxed declarative execution today, and can also
    be consumed by BYO agents. | | | +| `allowedNamespaces` _[AllowedNamespaces](#allowednamespaces)_ | AllowedNamespaces defines which namespaces are allowed to reference this Agent as a tool.
    This follows the Gateway API pattern for cross-namespace route attachments.
    If not specified, only Agents in the same namespace can reference this Agent as a tool.
    This field only applies when this Agent is used as a tool by another Agent.
    See: https://gateway-api.sigs.k8s.io/guides/multiple-ns/#cross-namespace-route-attachment | | | + +#### AgentStatus + +AgentStatus defines the observed state of Agent. + +_Appears in:_ +- [Agent](#agent) +- [SandboxAgent](#sandboxagent) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `observedGeneration` _integer_ | | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#condition-v1-meta) array_ | | | | + +#### AgentType + +_Underlying type:_ _string_ + +AgentType represents the agent type + +_Validation:_ +- Enum: [Declarative BYO] + +_Appears in:_ +- [AgentSpec](#agentspec) +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | +| --- | --- | +| `Declarative` | | +| `BYO` | | + +#### AllowedNamespaces + +AllowedNamespaces defines which namespaces are allowed to reference this resource. +This mechanism provides a bidirectional handshake for cross-namespace references, +following the pattern used by Gateway API for cross-namespace route attachments. + +By default (when not specified), only references from the same namespace are allowed. + +_Appears in:_ +- [AgentSpec](#agentspec) +- [RemoteMCPServerSpec](#remotemcpserverspec) +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `from` _[FromNamespaces](#fromnamespaces)_ | From indicates where references to this resource can originate.
    Possible values are:
    * All: References from all namespaces are allowed.
    * Same: Only references from the same namespace are allowed (default).
    * Selector: References from namespaces matching the selector are allowed. | Same | Enum: [All Same Selector]
    | +| `selector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#labelselector-v1-meta)_ | Selector is a label selector for namespaces that are allowed to reference this resource.
    Only used when From is set to "Selector". | | | + +#### AnthropicConfig + +AnthropicConfig contains Anthropic-specific configuration options + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `baseUrl` _string_ | Base URL for the Anthropic API (overrides default) | | | +| `maxTokens` _integer_ | Maximum tokens to generate | | | +| `temperature` _string_ | Temperature for sampling | | | +| `topP` _string_ | Top-p sampling parameter | | | +| `topK` _integer_ | Top-k sampling parameter | | | + +#### AnthropicVertexAIConfig + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `projectID` _string_ | The project ID | | | +| `location` _string_ | The project location | | | +| `temperature` _string_ | Temperature | | | +| `topP` _string_ | Top-p sampling parameter | | | +| `topK` _string_ | Top-k sampling parameter | | | +| `stopSequences` _string array_ | Stop sequences | | | +| `maxTokens` _integer_ | Maximum tokens to generate | | | + +#### AzureOpenAIConfig + +AzureOpenAIConfig contains Azure OpenAI-specific configuration options + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `azureEndpoint` _string_ | Endpoint for the Azure OpenAI API | | | +| `apiVersion` _string_ | API version for the Azure OpenAI API | | | +| `azureDeployment` _string_ | Deployment name for the Azure OpenAI API | | | +| `azureAdToken` _string_ | Azure AD token for authentication | | | +| `temperature` _string_ | Temperature for sampling | | | +| `maxTokens` _integer_ | Maximum tokens to generate | | | +| `topP` _string_ | Top-p sampling parameter | | | + +#### BYOAgentSpec + +_Appears in:_ +- [AgentSpec](#agentspec) +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `deployment` _[ByoDeploymentSpec](#byodeploymentspec)_ | Deployment configures the Kubernetes Deployment created for the BYO agent container. | | | + +#### BaseVertexAIConfig + +_Appears in:_ +- [AnthropicVertexAIConfig](#anthropicvertexaiconfig) +- [GeminiVertexAIConfig](#geminivertexaiconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `projectID` _string_ | The project ID | | | +| `location` _string_ | The project location | | | +| `temperature` _string_ | Temperature | | | +| `topP` _string_ | Top-p sampling parameter | | | +| `topK` _string_ | Top-k sampling parameter | | | +| `stopSequences` _string array_ | Stop sequences | | | + +#### BedrockConfig + +BedrockConfig contains AWS Bedrock-specific configuration options. + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `region` _string_ | AWS region where the Bedrock model is available (e.g., us-east-1, us-west-2) | | | +| `additionalModelRequestFields` _[JSON](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#json-v1-apiextensions-k8s-io)_ | AdditionalModelRequestFields passes model-specific parameters to Bedrock's
    additionalModelRequestFields in the Converse API. Use this for provider-specific
    options that are not part of the standard InferenceConfiguration block, such as
    Claude extended thinking or top_k. Values are forwarded as-is to the API.
    Example: \{"top_k": 5, "thinking": \{"type": "enabled", "budget_tokens": 16000\}\} | | | +| `promptCaching` _boolean_ | PromptCaching enables Bedrock prompt caching by appending a CachePoint
    block at the end of the Converse request's `system` content array and
    the end of the `toolConfig.tools` array. Bedrock will cache the prefix up to and
    including those cache points across requests in the same region for
    roughly 5 minutes after first use, billing the cached portion at a
    reduced rate on cache hits.

    Recommended for tool-using agents that make many Converse calls per
    task with a stable system prompt and tool set — the per-call input
    token count can drop by 70-90% on hit. Has no effect on models that
    don't support caching; the marker is ignored by Bedrock for those.

    See https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html
    for the current list of supported models and minimum prefix sizes. | false | | +| `cacheTTL` _string_ | CacheTTL controls how long Bedrock retains a cached prefix when
    PromptCaching is enabled. Only meaningful when PromptCaching is true.

    - "5m" (default): Bedrock's standard 5-minute sliding cache. Each cache
    hit refreshes the window. Supported by all prompt-caching models.
    - "1h": extended-TTL caching, useful for tasks whose Converse calls are
    spaced more than 5 minutes apart.

    NOTE: "1h" is NOT strictly better than "5m". Extended-TTL cache writes are
    billed at a higher per-token rate than 5-minute writes, and 1h is supported
    on a narrower set of models. Only choose "1h" when calls are spaced far
    enough apart that a 5-minute cache would expire between them; otherwise the
    higher write cost is wasted. See the AWS prompt-caching docs above. | 5m | Enum: [5m 1h]
    | + +#### ByoDeploymentSpec + +_Appears in:_ +- [BYOAgentSpec](#byoagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `image` _string_ | Image is the container image of the BYO agent.
    The image is expected to serve the agent over the A2A protocol on port 8080. | | MinLength: 1
    | +| `cmd` _string_ | Cmd overrides the container entrypoint (the container's command). | | | +| `args` _string array_ | Args are the arguments passed to the container entrypoint. | | | +| `workingDir` _string_ | workingDir sets the container working directory. Defaults to the image WORKDIR when omitted. | | | +| `replicas` _integer_ | Replicas is the number of desired agent pods. Defaults to 1. | | | +| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core) array_ | ImagePullSecrets are references to secrets in the agent's namespace
    used for pulling the agent container image. | | | +| `volumes` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volume-v1-core) array_ | Volumes are additional volumes added to the agent pod. | | | +| `volumeMounts` _[VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volumemount-v1-core) array_ | VolumeMounts are additional volume mounts added to the agent container. | | | +| `labels` _object (keys:string, values:string)_ | Labels are additional labels added to the agent pods. | | | +| `annotations` _object (keys:string, values:string)_ | Annotations are additional annotations added to the agent pods. | | | +| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core) array_ | Env are additional environment variables set on the agent container. | | | +| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | | | | +| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | | +| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core) array_ | Tolerations applied to the agent pods. | | | +| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | | | | +| `nodeSelector` _object (keys:string, values:string)_ | NodeSelector restricts the nodes the agent pods can be scheduled on. | | | +| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | | +| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podsecuritycontext-v1-core)_ | | | | +| `serviceAccountName` _string_ | ServiceAccountName specifies the name of an existing ServiceAccount to use.
    If this field is set, the Agent controller will not create a ServiceAccount for the agent.
    This field is mutually exclusive with ServiceAccountConfig. | | | +| `serviceAccountConfig` _[ServiceAccountConfig](#serviceaccountconfig)_ | ServiceAccountConfig configures the ServiceAccount created by the Agent controller.
    This field can only be used when ServiceAccountName is not set.
    If ServiceAccountName is not set, a default ServiceAccount (named after the agent)
    is created, and this config will be applied to it. | | | +| `extraContainers` _[Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#container-v1-core) array_ | ExtraContainers is a list of additional containers to run alongside the main agent container.
    Useful for sidecars such as token proxies, log shippers, or security agents. | | | + +#### ContextCompressionConfig + +ContextCompressionConfig configures event history compaction/compression. + +_Appears in:_ +- [ContextConfig](#contextconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `compactionInterval` _integer_ | The number of *new* user-initiated invocations that, once fully represented in the session's events, will trigger a compaction. | 5 | Minimum: 1
    | +| `overlapSize` _integer_ | The number of preceding invocations to include from the end of the last compacted range. This creates an overlap between consecutive compacted summaries, maintaining context. | 2 | Minimum: 0
    | +| `summarizer` _[ContextSummarizerConfig](#contextsummarizerconfig)_ | Summarizer configures an LLM-based summarizer for event compaction.
    If not specified, compacted events are dropped from the context without summarization. | | | +| `tokenThreshold` _integer_ | Post-invocation token threshold trigger. If set, ADK will attempt a post-invocation compaction when the most recently
    observed prompt token count meets or exceeds this threshold. | | | +| `eventRetentionSize` _integer_ | EventRetentionSize is the number of most recent events to always retain. | | | + +#### ContextConfig + +ContextConfig configures context management for an agent. + +_Appears in:_ +- [DeclarativeAgentSpec](#declarativeagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `compaction` _[ContextCompressionConfig](#contextcompressionconfig)_ | Compaction configures event history compaction.
    When enabled, older events in the conversation are compacted (compressed/summarized)
    to reduce context size while preserving key information. | | | + +#### ContextSummarizerConfig + +ContextSummarizerConfig configures the LLM-based event summarizer. + +_Appears in:_ +- [ContextCompressionConfig](#contextcompressionconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `modelConfig` _string_ | ModelConfig is the name of a ModelConfig resource to use for summarization.
    Must be in the same namespace as the Agent.
    If not specified, uses the agent's own model. | | | +| `promptTemplate` _string_ | PromptTemplate is a custom prompt template for the summarizer.
    See the ADK LlmEventSummarizer for template details:
    https://github.com/google/adk-python/blob/main/src/google/adk/apps/llm_event_summarizer.py | | | + +#### DeclarativeAgentSpec + +_Appears in:_ +- [AgentSpec](#agentspec) +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `runtime` _[DeclarativeRuntime](#declarativeruntime)_ | Runtime specifies which ADK implementation to use for this agent.
    - "go": Uses the Go ADK (default, faster startup, most features supported)
    - "python": Uses the Python ADK (slower startup, full feature set)
    The runtime determines both the container image and readiness probe configuration. | go | Enum: [python go]
    | +| `systemMessage` _string_ | SystemMessage is a string specifying the system message for the agent.
    When PromptTemplate is set, this field is treated as a Go text/template
    with access to an include("source/key") function and agent context variables
    such as .AgentName, .AgentNamespace, .Description, .ToolNames, and .SkillNames. | | | +| `systemMessageFrom` _[ValueSource](#valuesource)_ | SystemMessageFrom is a reference to a ConfigMap or Secret containing the system message.
    When PromptTemplate is set, the resolved value is treated as a Go text/template. | | | +| `promptTemplate` _[PromptTemplateSpec](#prompttemplatespec)_ | PromptTemplate enables Go text/template processing on the systemMessage field.
    When set, systemMessage is treated as a Go template with access to the include function
    and agent context variables. | | | +| `modelConfig` _string_ | The name of the model config to use.
    If not specified, the default value is "default-model-config".
    Must be in the same namespace as the Agent. | | | +| `stream` _boolean_ | Whether to stream the response from the model.
    If not specified, the default value is false. | | | +| `tools` _[Tool](#tool) array_ | | | MaxItems: 20
    | +| `a2aConfig` _[A2AConfig](#a2aconfig)_ | A2AConfig instantiates an A2A server for this agent,
    served on the HTTP port of the kagent kubernetes
    controller (default 8083).
    The A2A server URL will be served at
    <kagent-controller-ip>:8083/api/a2a/<agent-namespace>/<agent-name>
    Read more about the A2A protocol here: https://github.com/a2aproject/A2A | | | +| `deployment` _[DeclarativeDeploymentSpec](#declarativedeploymentspec)_ | | | | +| `executeCodeBlocks` _boolean_ | Allow code execution for python code blocks with this agent.
    If true, the agent will automatically execute python code blocks in the LLM responses.
    Code will be executed in a sandboxed environment.
    due to a bug in adk (https://github.com/google/adk-python/issues/3921 ), this field is ignored for now. | | | +| `memory` _[MemorySpec](#memoryspec)_ | Memory configuration for the agent. | | | +| `shareTools` _boolean_ | ShareTools enables the built-in share link tools for this agent.
    When true, the agent gains create_share_link, list_share_links, and delete_share_link tools
    that allow it to manage share tokens for the current session. | | | +| `context` _[ContextConfig](#contextconfig)_ | Context configures context management for this agent.
    This includes event compaction (compression) and context caching. | | | + +#### DeclarativeDeploymentSpec + +_Appears in:_ +- [DeclarativeAgentSpec](#declarativeagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `imageRegistry` _string_ | | | | +| `replicas` _integer_ | Replicas is the number of desired agent pods. Defaults to 1. | | | +| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core) array_ | ImagePullSecrets are references to secrets in the agent's namespace
    used for pulling the agent container image. | | | +| `volumes` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volume-v1-core) array_ | Volumes are additional volumes added to the agent pod. | | | +| `volumeMounts` _[VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volumemount-v1-core) array_ | VolumeMounts are additional volume mounts added to the agent container. | | | +| `labels` _object (keys:string, values:string)_ | Labels are additional labels added to the agent pods. | | | +| `annotations` _object (keys:string, values:string)_ | Annotations are additional annotations added to the agent pods. | | | +| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core) array_ | Env are additional environment variables set on the agent container. | | | +| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | | | | +| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | | +| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core) array_ | Tolerations applied to the agent pods. | | | +| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | | | | +| `nodeSelector` _object (keys:string, values:string)_ | NodeSelector restricts the nodes the agent pods can be scheduled on. | | | +| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | | +| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podsecuritycontext-v1-core)_ | | | | +| `serviceAccountName` _string_ | ServiceAccountName specifies the name of an existing ServiceAccount to use.
    If this field is set, the Agent controller will not create a ServiceAccount for the agent.
    This field is mutually exclusive with ServiceAccountConfig. | | | +| `serviceAccountConfig` _[ServiceAccountConfig](#serviceaccountconfig)_ | ServiceAccountConfig configures the ServiceAccount created by the Agent controller.
    This field can only be used when ServiceAccountName is not set.
    If ServiceAccountName is not set, a default ServiceAccount (named after the agent)
    is created, and this config will be applied to it. | | | +| `extraContainers` _[Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#container-v1-core) array_ | ExtraContainers is a list of additional containers to run alongside the main agent container.
    Useful for sidecars such as token proxies, log shippers, or security agents. | | | + +#### DeclarativeRuntime + +_Underlying type:_ _string_ + +DeclarativeRuntime represents the runtime implementation for declarative agents + +_Validation:_ +- Enum: [python go] + +_Appears in:_ +- [DeclarativeAgentSpec](#declarativeagentspec) + +| Field | Description | +| --- | --- | +| `python` | | +| `go` | | + +#### FromNamespaces + +_Underlying type:_ _string_ + +FromNamespaces specifies namespace from which references to this resource are allowed. +This follows the same pattern as Gateway API's cross-namespace route attachment. +See: https://gateway-api.sigs.k8s.io/guides/multiple-ns/#cross-namespace-route-attachment + +_Validation:_ +- Enum: [All Same Selector] + +_Appears in:_ +- [AllowedNamespaces](#allowednamespaces) + +| Field | Description | +| --- | --- | +| `All` | NamespacesFromAll allows references from all namespaces.
    | +| `Same` | NamespacesFromSame only allows references from the same namespace as the target resource (default).
    | +| `Selector` | NamespacesFromSelector allows references from namespaces matching the selector.
    | + +#### GDCHServiceAccountConfig + +GDCHServiceAccountConfig holds GDCH-specific token exchange parameters. + +_Appears in:_ +- [TokenExchangeConfig](#tokenexchangeconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `audience` _string_ | Audience is the token exchange audience URL (the GDC inference gateway base URL) | | | + +#### GeminiConfig + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +#### GeminiVertexAIConfig + +GeminiVertexAIConfig contains Gemini Vertex AI-specific configuration options + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `projectID` _string_ | The project ID | | | +| `location` _string_ | The project location | | | +| `temperature` _string_ | Temperature | | | +| `topP` _string_ | Top-p sampling parameter | | | +| `topK` _string_ | Top-k sampling parameter | | | +| `stopSequences` _string array_ | Stop sequences | | | +| `maxOutputTokens` _integer_ | Maximum output tokens | | | +| `candidateCount` _integer_ | Candidate count | | | +| `responseMimeType` _string_ | Response mime type | | | + +#### GitRepo + +GitRepo specifies a single Git repository to fetch skills from. + +_Appears in:_ +- [SkillForAgent](#skillforagent) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `url` _string_ | URL of the git repository (HTTPS or SSH). | | | +| `ref` _string_ | Git reference: branch name, tag, or commit SHA. | main | | +| `path` _string_ | Subdirectory within the repo to use as the skill root. The API validates
    this input path, but treats repository contents as trusted: symlinks under
    this path are dereferenced when materializing the skill. | | | +| `name` _string_ | Name for the skill directory under /skills. If omitted, defaults to the last
    segment of Path when Path is set; otherwise defaults to the repo name (last
    URL path segment, without .git). | | | + +#### MCPTool + +_Appears in:_ +- [RemoteMCPServerStatus](#remotemcpserverstatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | | | | +| `description` _string_ | | | | + +#### McpServerTool + +_Appears in:_ +- [Tool](#tool) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `kind` _string_ | | | | +| `apiGroup` _string_ | | | | +| `name` _string_ | | | | +| `namespace` _string_ | | | | +| `toolNames` _string array_ | The names of the tools to be provided by the ToolServer
    For a list of all the tools provided by the server,
    the client can query the status of the ToolServer object after it has been created | | MaxItems: 50
    | +| `requireApproval` _string array_ | RequireApproval lists tool names that require human approval before
    execution. Each name must also appear in ToolNames. When a tool in
    this list is invoked by the agent, execution pauses and the user is
    prompted to approve or reject the call. | | MaxItems: 50
    | +| `allowedHeaders` _string array_ | AllowedHeaders specifies which headers from the A2A request should be
    propagated to MCP tool calls. Header names are case-insensitive.

    Authorization header behavior:
    - Authorization headers CAN be propagated if explicitly listed in allowedHeaders
    - When STS token propagation is enabled, STS-generated Authorization headers
    will take precedence and replace any Authorization header from the A2A request
    - This is a security measure to prevent request headers from overwriting
    authentication tokens generated by the STS integration

    Example: ["x-user-email", "x-tenant-id"] | | | + +#### MemorySpec + +MemorySpec enables long-term memory for an agent. + +_Appears in:_ +- [DeclarativeAgentSpec](#declarativeagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `modelConfig` _string_ | ModelConfig is the name of the ModelConfig object whose embedding
    provider will be used to generate memory vectors. | | | +| `ttlDays` _integer_ | TTLDays controls how many days a stored memory entry remains valid before
    it is eligible for pruning. Defaults to 15 days when unset or zero. | | Minimum: 1
    | + +#### ModelConfig + +ModelConfig is the Schema for the modelconfigs API. + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `kagent.dev/v1alpha2` | | | +| `kind` _string_ | `ModelConfig` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
    Servers may infer this from the endpoint the client submits requests to.
    Cannot be updated.
    In CamelCase.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
    Servers should convert recognized schemas to the latest internal value, and
    may reject unrecognized values.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[ModelConfigSpec](#modelconfigspec)_ | | | | +| `status` _[ModelConfigStatus](#modelconfigstatus)_ | | | | + +#### ModelConfigSpec + +ModelConfigSpec defines the desired state of ModelConfig. + +_Appears in:_ +- [ModelConfig](#modelconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `model` _string_ | | | | +| `apiKeySecret` _string_ | The name of the secret that contains the API key. Must be a reference to the name of a secret in the same namespace as the referencing ModelConfig.
    For the SAPAICore provider, the secret must contain two keys: "client_id" and "client_secret"
    (the OAuth2 client credentials for SAP AI Core). The apiKeySecretKey field is not used for SAPAICore. | | | +| `apiKeySecretKey` _string_ | The key in the secret that contains the API key.
    Not used for the SAPAICore provider (which always reads "client_id" and "client_secret" from the secret). | | | +| `apiKeyPassthrough` _boolean_ | APIKeyPassthrough enables forwarding the Bearer token from incoming A2A requests
    directly to the LLM provider as the API key. This is useful for organizations
    with federated identity that want to avoid separate secret management.
    Mutually exclusive with apiKeySecret. | | | +| `defaultHeaders` _object (keys:string, values:string)_ | | | | +| `provider` _[ModelProvider](#modelprovider)_ | The provider of the model | OpenAI | Enum: [Anthropic OpenAI AzureOpenAI Ollama Gemini GeminiVertexAI AnthropicVertexAI Bedrock SAPAICore]
    | +| `openAI` _[OpenAIConfig](#openaiconfig)_ | OpenAI-specific configuration | | | +| `anthropic` _[AnthropicConfig](#anthropicconfig)_ | Anthropic-specific configuration | | | +| `azureOpenAI` _[AzureOpenAIConfig](#azureopenaiconfig)_ | Azure OpenAI-specific configuration | | | +| `ollama` _[OllamaConfig](#ollamaconfig)_ | Ollama-specific configuration | | | +| `gemini` _[GeminiConfig](#geminiconfig)_ | Gemini-specific configuration | | | +| `geminiVertexAI` _[GeminiVertexAIConfig](#geminivertexaiconfig)_ | Gemini Vertex AI-specific configuration | | | +| `anthropicVertexAI` _[AnthropicVertexAIConfig](#anthropicvertexaiconfig)_ | Anthropic-specific configuration | | | +| `bedrock` _[BedrockConfig](#bedrockconfig)_ | AWS Bedrock-specific configuration | | | +| `sapAICore` _[SAPAICoreConfig](#sapaicoreconfig)_ | SAP AI Core-specific configuration | | | +| `tls` _[TLSConfig](#tlsconfig)_ | TLS configuration for provider connections.
    Enables agents to connect to internal LiteLLM gateways or other providers
    that use self-signed certificates or custom certificate authorities. | | | + +#### ModelConfigStatus + +ModelConfigStatus defines the observed state of ModelConfig. + +_Appears in:_ +- [ModelConfig](#modelconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#condition-v1-meta) array_ | | | | +| `observedGeneration` _integer_ | | | | +| `secretHash` _string_ | The secret hash stores a hash of any secrets required by the model config (i.e. api key, tls cert) to ensure agents referencing this model config detect changes to these secrets and restart if necessary. | | | + +#### ModelProvider + +_Underlying type:_ _string_ + +ModelProvider represents the model provider type + +_Validation:_ +- Enum: [Anthropic OpenAI AzureOpenAI Ollama Gemini GeminiVertexAI AnthropicVertexAI Bedrock SAPAICore] + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) +- [ModelProviderConfigSpec](#modelproviderconfigspec) + +| Field | Description | +| --- | --- | +| `Anthropic` | | +| `AzureOpenAI` | | +| `OpenAI` | | +| `Ollama` | | +| `Gemini` | | +| `GeminiVertexAI` | | +| `AnthropicVertexAI` | | +| `Bedrock` | | +| `SAPAICore` | | + +#### ModelProviderConfig + +ModelProviderConfig is the Schema for the modelproviderconfigs API. +It represents a model provider configuration with automatic model discovery. + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `kagent.dev/v1alpha2` | | | +| `kind` _string_ | `ModelProviderConfig` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
    Servers may infer this from the endpoint the client submits requests to.
    Cannot be updated.
    In CamelCase.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
    Servers should convert recognized schemas to the latest internal value, and
    may reject unrecognized values.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[ModelProviderConfigSpec](#modelproviderconfigspec)_ | | | | +| `status` _[ModelProviderConfigStatus](#modelproviderconfigstatus)_ | | | | + +#### ModelProviderConfigSpec + +ModelProviderConfigSpec defines the desired state of ModelProviderConfig. + +_Appears in:_ +- [ModelProviderConfig](#modelproviderconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `type` _[ModelProvider](#modelprovider)_ | Type is the model provider type (OpenAI, Anthropic, etc.) | | Enum: [Anthropic OpenAI AzureOpenAI Ollama Gemini GeminiVertexAI AnthropicVertexAI Bedrock SAPAICore]
    | +| `endpoint` _string_ | Endpoint is the API endpoint URL for the provider.
    If not specified, the default endpoint for the provider type will be used. | | Pattern: `^https?://.*`
    | +| `secretRef` _[SecretReference](#secretreference)_ | SecretRef references the Kubernetes Secret containing the API key.
    Optional for providers that don't require authentication (e.g., local Ollama). | | | + +#### ModelProviderConfigStatus + +ModelProviderConfigStatus defines the observed state of ModelProviderConfig. + +_Appears in:_ +- [ModelProviderConfig](#modelproviderconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `observedGeneration` _integer_ | ObservedGeneration reflects the generation of the most recently observed ModelProviderConfig spec | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#condition-v1-meta) array_ | Conditions represent the latest available observations of the ModelProviderConfig's state | | | +| `discoveredModels` _string array_ | DiscoveredModels is the cached list of model IDs available from this model provider | | | +| `modelCount` _integer_ | ModelCount is the number of discovered models (for kubectl display) | | | +| `lastDiscoveryTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#time-v1-meta)_ | LastDiscoveryTime is the timestamp of the last successful model discovery | | | +| `secretHash` _string_ | SecretHash is a hash of the referenced secret data, used to detect secret changes | | | + +#### NetworkConfig + +NetworkConfig configures outbound network access for sandboxed execution paths. + +_Appears in:_ +- [SandboxConfig](#sandboxconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `allowedDomains` _string array_ | AllowedDomains lists the domains that sandboxed execution may contact.
    Wildcards such as *.example.com are supported by the sandbox runtime. | | | + +#### OllamaConfig + +OllamaConfig contains Ollama-specific configuration options + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `host` _string_ | Host for the Ollama API | | | +| `options` _object (keys:string, values:string)_ | Options for the Ollama API | | | + +#### OpenAIConfig + +OpenAIConfig contains OpenAI-specific configuration options + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `baseUrl` _string_ | Base URL for the OpenAI API (overrides default) | | | +| `organization` _string_ | Organization ID for the OpenAI API | | | +| `temperature` _string_ | Temperature for sampling | | | +| `maxTokens` _integer_ | Maximum tokens to generate | | | +| `topP` _string_ | Top-p sampling parameter | | | +| `frequencyPenalty` _string_ | Frequency penalty | | | +| `presencePenalty` _string_ | Presence penalty | | | +| `seed` _integer_ | Seed value | | | +| `n` _integer_ | N value | | | +| `timeout` _integer_ | Timeout | | | +| `reasoningEffort` _[OpenAIReasoningEffort](#openaireasoningeffort)_ | Reasoning effort | | Enum: [minimal low medium high]
    | +| `tokenExchange` _[TokenExchangeConfig](#tokenexchangeconfig)_ | TokenExchange configures dynamic bearer token acquisition via credential exchange.
    Requires apiKeySecret (used as the service account secret) and is mutually exclusive with apiKeyPassthrough. | | | + +#### OpenAIReasoningEffort + +_Underlying type:_ _string_ + +OpenAIReasoningEffort represents how many reasoning tokens the model generates before producing a response. + +_Validation:_ +- Enum: [minimal low medium high] + +_Appears in:_ +- [OpenAIConfig](#openaiconfig) + +#### PromptSource + +PromptSource references a ConfigMap whose keys are available as prompt fragments. +In systemMessage templates, use include("alias/key") (or include("name/key") if no alias is set) +to insert the value of a specific key from this source. + +_Appears in:_ +- [PromptTemplateSpec](#prompttemplatespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `kind` _string_ | | | | +| `apiGroup` _string_ | | | | +| `name` _string_ | | | | +| `alias` _string_ | Alias is an optional short identifier for use in include directives.
    If set, use include("alias/key") instead of include("name/key"). | | | + +#### PromptTemplateSpec + +PromptTemplateSpec configures prompt template processing for an agent's system message. + +_Appears in:_ +- [DeclarativeAgentSpec](#declarativeagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `dataSources` _[PromptSource](#promptsource) array_ | DataSources defines the ConfigMaps whose keys can be included in the systemMessage
    using Go template syntax, e.g. include("alias/key") or include("name/key"). | | MaxItems: 20
    | + +#### RemoteMCPServer + +RemoteMCPServer is the Schema for the RemoteMCPServers API. + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `kagent.dev/v1alpha2` | | | +| `kind` _string_ | `RemoteMCPServer` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
    Servers may infer this from the endpoint the client submits requests to.
    Cannot be updated.
    In CamelCase.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
    Servers should convert recognized schemas to the latest internal value, and
    may reject unrecognized values.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[RemoteMCPServerSpec](#remotemcpserverspec)_ | | | | +| `status` _[RemoteMCPServerStatus](#remotemcpserverstatus)_ | | | | + +#### RemoteMCPServerProtocol + +_Underlying type:_ _string_ + +_Validation:_ +- Enum: [SSE STREAMABLE_HTTP] + +_Appears in:_ +- [RemoteMCPServerSpec](#remotemcpserverspec) + +| Field | Description | +| --- | --- | +| `SSE` | | +| `STREAMABLE_HTTP` | | + +#### RemoteMCPServerSpec + +RemoteMCPServerSpec defines the desired state of RemoteMCPServer. + +_Appears in:_ +- [RemoteMCPServer](#remotemcpserver) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `description` _string_ | | | | +| `protocol` _[RemoteMCPServerProtocol](#remotemcpserverprotocol)_ | | STREAMABLE_HTTP | Enum: [SSE STREAMABLE_HTTP]
    | +| `url` _string_ | | | MinLength: 1
    | +| `headersFrom` _[ValueRef](#valueref) array_ | | | | +| `timeout` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#duration-v1-meta)_ | | 30s | | +| `sseReadTimeout` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#duration-v1-meta)_ | | | | +| `terminateOnClose` _boolean_ | | true | | +| `allowedNamespaces` _[AllowedNamespaces](#allowednamespaces)_ | AllowedNamespaces defines which namespaces are allowed to reference this RemoteMCPServer.
    This follows the Gateway API pattern for cross-namespace route attachments.
    If not specified, only Agents in the same namespace can reference this RemoteMCPServer.
    See: https://gateway-api.sigs.k8s.io/guides/multiple-ns/#cross-namespace-route-attachment

    A cross-namespace-permitting value (from: All or from: Selector) is
    mutually exclusive with spec.tls.caCertSecretRef (enforced by a spec-level
    XValidation rule): a pinned CA Secret is mounted onto the consuming agent's
    pod by bare name and Kubernetes resolves it in the agent's namespace, not
    this RemoteMCPServer's, so a CA-pinning RemoteMCPServer cannot be referenced
    cross-namespace. from: Same (the default) is always allowed. | | | +| `tls` _[TLSConfig](#tlsconfig)_ | TLS configuration for the upstream MCP server connection.
    Use this for HTTPS upstreams that present a certificate the agent's
    system trust store does not include (corporate CA, self-signed cert
    on a test fixture, internal MCP gateway). Reuses the same TLSConfig
    type as ModelConfig.spec.tls — disableVerify turns off certificate
    validation entirely, caCertSecretRef + caCertSecretKey point at a
    PEM bundle Secret in the same namespace, and disableSystemCAs
    trusts only the named bundle.

    Note one asymmetry with ModelConfig: a spec-level XValidation rule
    on RemoteMCPServer rejects spec.tls when spec.url has the http://
    scheme (a TLS opinion contradicts a plaintext URL). ModelConfig has
    no equivalent rule, so a TLS block can sit alongside any baseUrl. | | | + +#### RemoteMCPServerStatus + +RemoteMCPServerStatus defines the observed state of RemoteMCPServer. + +_Appears in:_ +- [RemoteMCPServer](#remotemcpserver) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `observedGeneration` _integer_ | INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    Important: Run "make" to regenerate code after modifying this file | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#condition-v1-meta) array_ | | | | +| `discoveredTools` _[MCPTool](#mcptool) array_ | | | | +| `secretHash` _string_ | SecretHash stores a hash of the TLS Secret referenced by spec.tls so
    agents that consume this RemoteMCPServer can detect cert rotation and
    roll on the next reconcile. Empty when spec.tls.caCertSecretRef is unset. | | | + +#### SAPAICoreConfig + +SAPAICoreConfig contains SAP AI Core-specific configuration options. + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `baseUrl` _string_ | Base URL for the SAP AI Core API (e.g., https://api.ai.prod.eu-central-1.aws.ml.hana.ondemand.com) | | | +| `resourceGroup` _string_ | Resource group in SAP AI Core | default | | +| `authUrl` _string_ | OAuth2 token endpoint URL (e.g., https://tenant.authentication.eu10.hana.ondemand.com) | | | + +#### SandboxAgent + +SandboxAgent declares an agent that runs in an isolated sandbox on Agent Substrate. + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `kagent.dev/v1alpha2` | | | +| `kind` _string_ | `SandboxAgent` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
    Servers may infer this from the endpoint the client submits requests to.
    Cannot be updated.
    In CamelCase.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
    Servers should convert recognized schemas to the latest internal value, and
    may reject unrecognized values.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[SandboxAgentSpec](#sandboxagentspec)_ | | | | +| `status` _[AgentStatus](#agentstatus)_ | | | | + +#### SandboxAgentSpec + +_Appears in:_ +- [SandboxAgent](#sandboxagent) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `type` _[AgentType](#agenttype)_ | | Declarative | Enum: [Declarative BYO]
    | +| `byo` _[BYOAgentSpec](#byoagentspec)_ | BYO configures a "bring your own" agent backed by a user-provided
    container image. Kagent deploys the image and expects it to serve the
    agent over the A2A protocol on port 8080.
    Required if type is BYO. | | | +| `declarative` _[DeclarativeAgentSpec](#declarativeagentspec)_ | Declarative configures an agent that is fully described by this resource
    (model, instructions, tools) and runs on one of kagent's built-in runtimes.
    Required if type is Declarative. | | | +| `description` _string_ | | | | +| `iconUrl` _string_ | IconURL is a URL to an icon representing the agent. It is surfaced on the
    agent's A2A AgentCard. | | Format: uri
    | +| `documentationUrl` _string_ | DocumentationURL is a URL to human-readable documentation for the agent. It
    is surfaced on the agent's A2A AgentCard. | | Format: uri
    | +| `version` _string_ | Version is the agent's version string, surfaced on the A2A AgentCard. | | | +| `provider` _[AgentProvider](#agentprovider)_ | Provider identifies the organization responsible for the agent. It is
    surfaced on the agent's A2A AgentCard. | | | +| `skills` _[SkillForAgent](#skillforagent)_ | Skills to load into the agent. They will be pulled from the specified container images.
    and made available to the agent under the `/skills` folder. | | | +| `sandbox` _[SandboxConfig](#sandboxconfig)_ | Sandbox configures sandboxed execution behavior shared across runtimes.
    This is intended for sandboxed declarative execution today, and can also
    be consumed by BYO agents. | | | +| `allowedNamespaces` _[AllowedNamespaces](#allowednamespaces)_ | AllowedNamespaces defines which namespaces are allowed to reference this Agent as a tool.
    This follows the Gateway API pattern for cross-namespace route attachments.
    If not specified, only Agents in the same namespace can reference this Agent as a tool.
    This field only applies when this Agent is used as a tool by another Agent.
    See: https://gateway-api.sigs.k8s.io/guides/multiple-ns/#cross-namespace-route-attachment | | | +| `substrate` _[SandboxSubstrateSpec](#sandboxsubstratespec)_ | Substrate is optional Agent Substrate-specific settings. | | | + +#### SandboxConfig + +SandboxConfig configures sandboxed execution behavior. + +_Appears in:_ +- [AgentSpec](#agentspec) +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `network` _[NetworkConfig](#networkconfig)_ | Network configures outbound network access for sandboxed execution paths.
    When unset or when allowedDomains is empty, outbound access is denied by default. | | | + +#### SandboxSubstrateSpec + +SandboxSubstrateSpec configures Agent Substrate for a SandboxAgent. +WorkerPool capacity is referenced from workerPoolRef or the controller default. + +_Appears in:_ +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `workerPoolRef` _[TypedLocalReference](#typedlocalreference)_ | WorkerPoolRef references an existing ate.dev WorkerPool. | | | +| `snapshotsConfig` _[AgentHarnessSubstrateSnapshotsConfig](#agentharnesssubstratesnapshotsconfig)_ | SnapshotsConfig configures actor memory snapshots.
    Defaults to gs://ate-snapshots/<namespace>/<agentname> when unset. | | | + +#### SecretReference + +SecretReference references a Kubernetes Secret that must contain exactly one data key +holding the API key or credential. + +_Appears in:_ +- [ModelProviderConfigSpec](#modelproviderconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name is the name of the secret in the same namespace as the ModelProviderConfig. | | | + +#### ServiceAccountConfig + +_Appears in:_ +- [ByoDeploymentSpec](#byodeploymentspec) +- [DeclarativeDeploymentSpec](#declarativedeploymentspec) +- [SharedDeploymentSpec](#shareddeploymentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `labels` _object (keys:string, values:string)_ | Labels are additional labels added to the created ServiceAccount. | | | +| `annotations` _object (keys:string, values:string)_ | Annotations are additional annotations added to the created ServiceAccount. | | | + +#### SharedDeploymentSpec + +_Appears in:_ +- [ByoDeploymentSpec](#byodeploymentspec) +- [DeclarativeDeploymentSpec](#declarativedeploymentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `replicas` _integer_ | Replicas is the number of desired agent pods. Defaults to 1. | | | +| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core) array_ | ImagePullSecrets are references to secrets in the agent's namespace
    used for pulling the agent container image. | | | +| `volumes` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volume-v1-core) array_ | Volumes are additional volumes added to the agent pod. | | | +| `volumeMounts` _[VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volumemount-v1-core) array_ | VolumeMounts are additional volume mounts added to the agent container. | | | +| `labels` _object (keys:string, values:string)_ | Labels are additional labels added to the agent pods. | | | +| `annotations` _object (keys:string, values:string)_ | Annotations are additional annotations added to the agent pods. | | | +| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core) array_ | Env are additional environment variables set on the agent container. | | | +| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | | | | +| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | | +| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core) array_ | Tolerations applied to the agent pods. | | | +| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | | | | +| `nodeSelector` _object (keys:string, values:string)_ | NodeSelector restricts the nodes the agent pods can be scheduled on. | | | +| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | | +| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podsecuritycontext-v1-core)_ | | | | +| `serviceAccountName` _string_ | ServiceAccountName specifies the name of an existing ServiceAccount to use.
    If this field is set, the Agent controller will not create a ServiceAccount for the agent.
    This field is mutually exclusive with ServiceAccountConfig. | | | +| `serviceAccountConfig` _[ServiceAccountConfig](#serviceaccountconfig)_ | ServiceAccountConfig configures the ServiceAccount created by the Agent controller.
    This field can only be used when ServiceAccountName is not set.
    If ServiceAccountName is not set, a default ServiceAccount (named after the agent)
    is created, and this config will be applied to it. | | | +| `extraContainers` _[Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#container-v1-core) array_ | ExtraContainers is a list of additional containers to run alongside the main agent container.
    Useful for sidecars such as token proxies, log shippers, or security agents. | | | + +#### SkillForAgent + +_Appears in:_ +- [AgentSpec](#agentspec) +- [SandboxAgentSpec](#sandboxagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `insecureSkipVerify` _boolean_ | Fetch images insecurely from registries (allowing HTTP and skipping TLS verification).
    Meant for development and testing purposes only. | | | +| `refs` _string array_ | The list of skill images to fetch. | | MaxItems: 20
    MinItems: 1
    | +| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core) array_ | ImagePullSecrets is a list of references to secrets in the same namespace to use for
    pulling skill images from private registries. Each referenced secret must be of type
    kubernetes.io/dockerconfigjson. The credentials from all secrets are merged and made
    available to the skills-init container at /.kagent/.docker/config.json; krane will
    use them automatically when pulling images. | | MaxItems: 20
    | +| `gitAuthSecretRef` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core)_ | Reference to a Secret containing git credentials.
    Applied to all gitRefs entries.
    The secret should contain a `token` key for HTTPS auth,
    or `ssh-privatekey` for SSH auth. | | | +| `gitRefs` _[GitRepo](#gitrepo) array_ | Git repositories to fetch skills from. | | MaxItems: 20
    MinItems: 1
    | +| `initContainer` _[SkillsInitContainer](#skillsinitcontainer)_ | Configuration for the skills-init init container. | | | + +#### SkillsInitContainer + +SkillsInitContainer configures the skills-init init container. + +_Appears in:_ +- [SkillForAgent](#skillforagent) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | Resource requirements for the skills-init init container. | | | +| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core) array_ | Additional environment variables for the skills-init init container. | | | + +#### TLSConfig + +TLSConfig contains TLS/SSL configuration options for outbound HTTPS +connections from the agent (model provider, RemoteMCPServer). The +XValidation rules below apply at admission to every CRD field that +uses TLSConfig, so callers don't need to re-declare them per spec. + +_Appears in:_ +- [ModelConfigSpec](#modelconfigspec) +- [RemoteMCPServerSpec](#remotemcpserverspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `disableVerify` _boolean_ | DisableVerify disables SSL certificate verification entirely.
    When false (default), SSL certificates are verified.
    When true, SSL certificate verification is disabled.
    WARNING: This should ONLY be used in development/testing environments.
    Production deployments MUST use proper certificates. | false | | +| `caCertSecretRef` _string_ | CACertSecretRef is a reference to a Kubernetes Secret containing
    CA certificate(s) in PEM format. The Secret must be in the same
    namespace as the resource referencing it (ModelConfig,
    RemoteMCPServer, or any future consumer of TLSConfig).
    When set, the certificate will be used to verify the upstream's
    SSL certificate. | | | +| `caCertSecretKey` _string_ | CACertSecretKey is the key within the Secret that contains the
    CA certificate data (PEM-encoded). Required when CACertSecretRef
    is set — admission rejects ref-without-key regardless of
    DisableVerify (see the TLSConfig-level XValidation rules). | | | +| `disableSystemCAs` _boolean_ | DisableSystemCAs disables the use of system CA certificates.
    When false (default), system CA certificates are used for verification (safe behavior).
    When true, only the custom CA from CACertSecretRef is trusted.
    This allows strict security policies where only corporate CAs should be trusted. | false | | + +#### TokenExchangeConfig + +TokenExchangeConfig configures dynamic bearer token acquisition before model calls. + +_Appears in:_ +- [OpenAIConfig](#openaiconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `type` _[TokenExchangeType](#tokenexchangetype)_ | | | Enum: [GDCHServiceAccount]
    | +| `gdchServiceAccount` _[GDCHServiceAccountConfig](#gdchserviceaccountconfig)_ | | | | + +#### TokenExchangeType + +_Underlying type:_ _string_ + +TokenExchangeType identifies the token exchange mechanism + +_Validation:_ +- Enum: [GDCHServiceAccount] + +_Appears in:_ +- [TokenExchangeConfig](#tokenexchangeconfig) + +| Field | Description | +| --- | --- | +| `GDCHServiceAccount` | | + +#### Tool + +_Appears in:_ +- [DeclarativeAgentSpec](#declarativeagentspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `type` _[ToolProviderType](#toolprovidertype)_ | | | Enum: [McpServer Agent]
    | +| `mcpServer` _[McpServerTool](#mcpservertool)_ | | | | +| `agent` _[TypedReference](#typedreference)_ | | | | +| `headersFrom` _[ValueRef](#valueref) array_ | HeadersFrom specifies a list of configuration values to be added as
    headers to requests sent to the Tool from this agent. The value of
    each header is resolved from either a Secret or ConfigMap in the same
    namespace as the Agent. Headers specified here will override any
    headers of the same name/key specified on the tool. | | | + +#### ToolProviderType + +_Underlying type:_ _string_ + +ToolProviderType represents the tool provider type + +_Validation:_ +- Enum: [McpServer Agent] + +_Appears in:_ +- [Tool](#tool) + +| Field | Description | +| --- | --- | +| `McpServer` | | +| `Agent` | | + +#### TypedLocalReference + +_Appears in:_ +- [AgentHarnessSubstrateSpec](#agentharnesssubstratespec) +- [PromptSource](#promptsource) +- [SandboxSubstrateSpec](#sandboxsubstratespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `kind` _string_ | | | | +| `apiGroup` _string_ | | | | +| `name` _string_ | | | | + +#### TypedReference + +_Appears in:_ +- [McpServerTool](#mcpservertool) +- [Tool](#tool) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `kind` _string_ | | | | +| `apiGroup` _string_ | | | | +| `name` _string_ | | | | +| `namespace` _string_ | | | | + +#### ValueRef + +ValueRef represents a configuration value + +_Appears in:_ +- [RemoteMCPServerSpec](#remotemcpserverspec) +- [Tool](#tool) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | | | | +| `value` _string_ | | | | +| `valueFrom` _[ValueSource](#valuesource)_ | | | | + +#### ValueSource + +ValueSource defines a source for configuration values from a Secret or ConfigMap + +_Appears in:_ +- [AgentHarnessChannelCredential](#agentharnesschannelcredential) +- [AgentHarnessHermesSlackOptions](#agentharnesshermesslackoptions) +- [AgentHarnessTelegramChannelSpec](#agentharnesstelegramchannelspec) +- [DeclarativeAgentSpec](#declarativeagentspec) +- [ValueRef](#valueref) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `type` _[ValueSourceType](#valuesourcetype)_ | | | Enum: [ConfigMap Secret]
    | +| `name` _string_ | The name of the ConfigMap or Secret. | | MaxLength: 253
    | +| `key` _string_ | The key of the ConfigMap or Secret. | | MaxLength: 253
    | + +#### ValueSourceType + +_Underlying type:_ _string_ + +_Appears in:_ +- [ValueSource](#valuesource) + +| Field | Description | +| --- | --- | +| `ConfigMap` | | +| `Secret` | | + diff --git a/docs-site/content/kagent/resources/cli/_index.md b/docs-site/content/kagent/resources/cli/_index.md new file mode 100644 index 00000000..aa2b9e24 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/_index.md @@ -0,0 +1,8 @@ +--- +title: CLI docs +description: Complete reference docs for the kagent CLI commands +weight: 1 +--- + +Review the kagent CLI commands and learn how to use them effectively. + diff --git a/docs-site/content/kagent/resources/cli/kagent-add-mcp.md b/docs-site/content/kagent/resources/cli/kagent-add-mcp.md new file mode 100644 index 00000000..563e80c2 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-add-mcp.md @@ -0,0 +1,57 @@ +--- +title: kagent add-mcp +description: kagent add-mcp command +weight: 10 +--- + +Add an MCP server entry to `kagent.yaml`. + +```bash +kagent add-mcp [name] [args...] [flags] +``` + +**Arguments:** +- `name` - Name of the MCP server +- `args` - Command arguments (optional) + +**Flags:** +- `--arg` - Command argument (repeatable) +- `--build` - Construct image specification (e.g., `docker build`) +- `--command` - Command to run MCP server (e.g., `npx`, `uvx`, `kmcp`) +- `--env` - Environment variable in KEY=VALUE format (repeatable) +- `--header` - HTTP header for remote MCP in KEY=VALUE format (repeatable, supports `${VAR}` for env vars) +- `--image` - Container image (optional; mutually exclusive with `--build`) +- `--project-dir` - Project directory (default: current directory) +- `--remote` - Remote MCP server URL (`http://` or `https://`) + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## About `kagent add-mcp` + +Adds an MCP server entry to your `kagent.yaml` file. Use flags for non-interactive setup or run without flags to open the wizard. + +## Example + +Add a remote MCP server: + +```bash +kagent add-mcp my-mcp-server --remote https://mcp.example.com +``` + +Add an MCP server with a command: + +```bash +kagent add-mcp my-mcp-server --command npx --arg @modelcontextprotocol/server-filesystem +``` + +Add an MCP server with custom environment variables: + +```bash +kagent add-mcp my-mcp-server --command my-server --env API_KEY=secret --env LOG_LEVEL=debug +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-bug-report.md b/docs-site/content/kagent/resources/cli/kagent-bug-report.md new file mode 100644 index 00000000..700e9287 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-bug-report.md @@ -0,0 +1,36 @@ +--- +title: kagent bug-report +description: kagent bug-report command +weight: 10 +--- + +Generate a bug report for troubleshooting. + +```bash +kagent bug-report [flags] +``` + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## About `kagent bug-report` + +This command generates a comprehensive bug report that includes: +- kagent CLI version +- kagent server version +- Kubernetes cluster information +- Resource status and logs +- Configuration details + +## Example + +Generate a bug report: + +```bash +kagent bug-report +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-build.md b/docs-site/content/kagent/resources/cli/kagent-build.md new file mode 100644 index 00000000..4610e231 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-build.md @@ -0,0 +1,60 @@ +--- +title: kagent build +description: kagent build command +weight: 10 +--- + +Build a Docker image for an agent project. + +```bash +kagent build [project-directory] [flags] +``` + +**Arguments:** +- `project-directory` - The directory containing the agent project with `kagent.yaml` + +**Flags:** +- `--image` - Full image specification (e.g., ghcr.io/myorg/my-agent:v1.0.0) +- `--platform` - Target platform for Docker build (e.g., linux/amd64, linux/arm64) +- `--push` - Push the image to the registry + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## About `kagent build` + +The `kagent build` command builds Docker images for an agent project created with the `init` command. It looks for a `kagent.yaml` file in the specified project directory and builds Docker images using `docker build`. + +**Image naming:** +- If `--image` is provided, it is used as the full image specification (e.g., `ghcr.io/myorg/my-agent:v1.0.0`) +- Otherwise, defaults to `localhost:5001/{agentName}:latest` where `agentName` is loaded from `kagent.yaml` + +## Example + +Build a Docker image: + +```bash +kagent build ./my-agent +``` + +Build and tag a Docker image: + +```bash +kagent build ./my-agent --image ghcr.io/myorg/my-agent:v1.0.0 +``` + +Build and push an image to a registry: + +```bash +kagent build ./my-agent --image ghcr.io/myorg/my-agent:v1.0.0 --push +``` + +Build for a specific platform: + +```bash +kagent build ./my-agent --platform linux/amd64 --image ghcr.io/myorg/my-agent:v1.0.0 +``` diff --git a/docs-site/content/kagent/resources/cli/kagent-completion.md b/docs-site/content/kagent/resources/cli/kagent-completion.md new file mode 100644 index 00000000..d6674520 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-completion.md @@ -0,0 +1,23 @@ +--- +title: kagent completion +description: kagent completion command +weight: 40 +--- + +Generate the autocompletion script for kagent for the specified shell. See each sub-command's help for details on how to use the generated script. + +```bash +kagent completion [command] +``` + +**Global Flags:** +- `--config` - config file +- `--kagent-url` - KAgent URL (default "http://localhost:8083") +- `--timeout` - Timeout (default 5m0s) + +**Subcommands:** +- `bash` - Generate the autocompletion script for bash +- `fish` - Generate the autocompletion script for fish +- `powershell` - Generate the autocompletion script for powershell +- `zsh` - Generate the autocompletion script for zsh + diff --git a/docs-site/content/kagent/resources/cli/kagent-dashboard.md b/docs-site/content/kagent/resources/cli/kagent-dashboard.md new file mode 100644 index 00000000..0eacf911 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-dashboard.md @@ -0,0 +1,27 @@ +--- +title: kagent dashboard +description: kagent dashboard command +weight: 10 +--- + +Open the kagent dashboard in your default web browser. + +```bash +kagent dashboard [flags] +``` + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## Example + +Open the dashboard: + +```bash +kagent dashboard +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-deploy.md b/docs-site/content/kagent/resources/cli/kagent-deploy.md new file mode 100644 index 00000000..afb16479 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-deploy.md @@ -0,0 +1,76 @@ +--- +title: kagent deploy +description: kagent deploy command +weight: 10 +--- + +Deploy an agent to Kubernetes. + +```bash +kagent deploy [project-directory] [flags] +``` + +**Arguments:** +- `project-directory` - The directory containing the agent project with `kagent.yaml` + +**Flags:** +- `--api-key` - API key for the model provider (convenience option to create secret) +- `--api-key-secret` - Name of existing secret containing API key (recommended) +- `--dry-run` - Output YAML manifests without applying them to the cluster +- `--image, -i` - Image to use (defaults to `localhost:5001/{agentName}:latest`) +- `--namespace` - Kubernetes namespace to deploy to +- `--platform` - Target platform for Docker build (e.g., linux/amd64, linux/arm64) + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## About `kagent deploy` + +The `kagent deploy` command deploys an agent to Kubernetes by performing the following steps: + +1. Loads the agent configuration from `kagent.yaml` +2. Either creates a new secret with the provided API key or verifies an existing secret +3. Creates an `Agent` Custom Resource Definition (CRD) with the appropriate configuration + +**API Key Options:** +- `--api-key`: Convenience option to create a new secret with the provided API key +- `--api-key-secret`: Recommended way to reference an existing secret by name + +**Dry-Run Mode:** +Use the `--dry-run` flag to output YAML manifests without applying them to the cluster. This is useful for previewing changes or for use with GitOps workflows. + +## Example + +Deploy using an existing secret: + +```bash +kagent deploy ./my-agent --api-key-secret "my-existing-secret" +``` + +Deploy and create a new secret: + +```bash +kagent deploy ./my-agent --api-key "your-api-key-here" --image "myregistry/myagent:v1.0" +``` + +Deploy to a specific namespace: + +```bash +kagent deploy ./my-agent --api-key-secret "my-secret" --namespace "my-namespace" +``` + +Generate manifests without deploying: + +```bash +kagent deploy ./my-agent --api-key "your-api-key" --dry-run > manifests.yaml +``` + +Deploy with a specific platform for the Docker build: + +```bash +kagent deploy ./my-agent --env-file .env --platform linux/amd64 +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-get.md b/docs-site/content/kagent/resources/cli/kagent-get.md new file mode 100644 index 00000000..ee3c9d53 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-get.md @@ -0,0 +1,56 @@ +--- +title: kagent get +description: kagent get command +weight: 10 +--- + +Get kagent resources. + +```bash +kagent get [resource-type] [resource-name] [flags] +``` + +**Subcommands:** +- `agent [agent_name]` - Get an agent by name or list all agents +- `session [session_id]` - Get a session by ID or list all sessions +- `tool` - List all available tools + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## Example + +List all agents: + +```bash +kagent get agent +``` + +Get a specific agent: + +```bash +kagent get agent k8s-agent +``` + +List all sessions: + +```bash +kagent get session +``` + +Get a specific session: + +```bash +kagent get session abc123 +``` + +List all tools: + +```bash +kagent get tool +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-help.md b/docs-site/content/kagent/resources/cli/kagent-help.md new file mode 100644 index 00000000..43673a48 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-help.md @@ -0,0 +1,17 @@ +--- +title: kagent help +description: kagent help command +weight: 150 +--- + +Help provides help for any command in the `kagent` CLI. + +```bash +kagent help [command] [flags] +``` + +**Global Flags:** +- `--config` - config file +- `--kagent-url` - KAgent URL (default "http://localhost:8083") +- `--timeout` - Timeout (default 5m0s) + diff --git a/docs-site/content/kagent/resources/cli/kagent-init.md b/docs-site/content/kagent/resources/cli/kagent-init.md new file mode 100644 index 00000000..ea12cadd --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-init.md @@ -0,0 +1,62 @@ +--- +title: kagent init +description: kagent init command +weight: 10 +--- + +Initialize a new agent project with the specified framework and language. + +```bash +kagent init [framework] [language] [agent-name] [flags] +``` + +**Arguments:** +- `framework` - The framework to use (currently supports `adk`) +- `language` - The programming language to use (supports `python`) +- `agent-name` - The name of the agent project + +**Flags:** +- `--description` - Description for the agent +- `--instruction-file` - Path to file containing custom instructions for the root agent +- `--model-name` - Model name (e.g., gpt-4, claude-3-5-sonnet, gemini-2.0-flash) (default: "gemini-2.0-flash") +- `--model-provider` - Model provider (OpenAI, Anthropic, Gemini) (default: "Gemini") + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## About `kagent init` + +The `kagent init` command creates a bootstrap agent project. Select a specific model using the `--model-provider` and `--model-name` flags. You can also customize the root agent instructions by using the `--instruction-file` flag. + +If no custom instruction file is provided, a default dice-rolling instruction is used. If no model is specified, the agent can be configured later. + +Currently supported model providers are the models that are supported in the models configuration: +- OpenAI +- Anthropic +- AzureOpenAI +- Gemini + +## Example + +Create a new agent project: + +```bash +kagent init adk python dice +``` + +Create a new agent project with custom instructions: + +```bash +kagent init adk python dice --instruction-file instructions.md +``` + +Create a new agent project with a specific model: + +```bash +kagent init adk python dice --model-provider Gemini --model-name gemini-2.0-flash +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-install.md b/docs-site/content/kagent/resources/cli/kagent-install.md new file mode 100644 index 00000000..4f724ade --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-install.md @@ -0,0 +1,42 @@ +--- +title: kagent install +description: kagent install command +weight: 10 +--- + +Install kagent in a Kubernetes cluster. + +```bash +kagent install [flags] +``` + +**Flags:** +- `--profile` - Installation profile (minimal|demo) + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## Example + +Install kagent with the default profile: + +```bash +kagent install +``` + +Install kagent with the minimal profile: + +```bash +kagent install --profile minimal +``` + +Install kagent with the demo profile: + +```bash +kagent install --profile demo +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-invoke.md b/docs-site/content/kagent/resources/cli/kagent-invoke.md new file mode 100644 index 00000000..19d70175 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-invoke.md @@ -0,0 +1,47 @@ +--- +title: kagent invoke +description: kagent invoke command +weight: 10 +--- + +Invoke a kagent agent to perform a task. + +```bash +kagent invoke [flags] +``` + +**Flags:** +- `--agent, -a` - Agent to invoke +- `--file, -f` - File to read the task from +- `--session, -s` - Session +- `--stream, -S` - Stream the response +- `--task, -t` - Task to perform +- `--url-override, -u` - URL override + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## Example + +Invoke an agent with a task: + +```bash +kagent invoke --agent "k8s-agent" --task "Get all the pods in the kagent namespace" +``` + +Invoke with streaming output: + +```bash +kagent invoke --agent "k8s-agent" --task "Get all the pods" --stream +``` + +Invoke from a task file: + +```bash +kagent invoke --agent "k8s-agent" --file task.txt +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-mcp.md b/docs-site/content/kagent/resources/cli/kagent-mcp.md new file mode 100644 index 00000000..1b1a65ff --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-mcp.md @@ -0,0 +1,42 @@ +--- +title: kagent mcp +description: kagent mcp command +weight: 10 +--- + +Model Context Protocol (MCP) server management commands for creating and managing MCP servers with dynamic tool loading. + +```bash +kagent mcp [subcommand] [flags] +``` + +**Subcommands:** +- `init` - Initialize a new MCP server project +- `build` - Build a Docker image for your MCP server +- `deploy` - Deploy your MCP server to a Kubernetes cluster +- `add-tool` - Generate an MCP tool boilerplate +- `run` - Run an MCP server locally +- `secrets` - Manage secrets for MCP server projects + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## About `kagent mcp` + +The `kagent mcp` command provides a set of subcommands for managing MCP servers. This is useful for creating and managing tools that can be used by kagent agents. + +## Example + +See the kagent mcp documentation for detailed examples of each subcommand: + +- [kagent mcp init](/docs/kmcp/reference/kmcp-init) - Create a scaffold for your MCP server +- [kagent mcp build](/docs/kmcp/reference/kmcp-build) - Build a Docker image +- [kagent mcp deploy](/docs/kmcp/reference/kmcp-deploy) - Deploy to Kubernetes +- [kagent mcp add-tool](/docs/kmcp/reference/kmcp-add-tool) - Generate tool boilerplate +- [kagent mcp run](/docs/kmcp/reference/kmcp-run) - Run locally +- [kagent mcp secrets](/docs/kmcp/reference/kmcp-secrets) - Manage secrets + diff --git a/docs-site/content/kagent/resources/cli/kagent-run.md b/docs-site/content/kagent/resources/cli/kagent-run.md new file mode 100644 index 00000000..71b90a27 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-run.md @@ -0,0 +1,62 @@ +--- +title: kagent run +description: kagent run command +weight: 10 +--- + +Run an agent project locally with docker-compose and launch an interactive chat interface. + +```bash +kagent run [project-directory] [flags] +``` + +**Arguments:** +- `project-directory` - The directory containing the agent project (default: current directory) + +**Flags:** +- `--build` - Rebuild the Docker image before running +- `--project-dir` - Project directory (default: current directory) + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## About `kagent run` + +The `kagent run` command runs an agent project locally using `docker-compose` and launches an interactive chat session. This way, you can test and interact with your agent before deploying it to a Kubernetes cluster. + +### Rebuilding before running + +Use the `--build` flag to rebuild the Docker image before running the agent. This is useful when you've made changes to your agent code and want to test the updated version without manually running `kagent build` first. + +```bash +kagent run --build +``` + +This command rebuilds the agent image and then starts the interactive chat interface. It's equivalent to running `kagent build` followed by `kagent run`. + +## Example + +Run an agent project from the current directory: + +```bash +kagent run +``` + +Run an agent project from a specific directory: + +```bash +kagent run ./my-agent +``` + +Rebuild the image and run the agent: + +```bash +kagent run --build +``` + +This is useful after making code changes to ensure you're testing the latest version of your agent. + diff --git a/docs-site/content/kagent/resources/cli/kagent-uninstall.md b/docs-site/content/kagent/resources/cli/kagent-uninstall.md new file mode 100644 index 00000000..41f7b8b1 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-uninstall.md @@ -0,0 +1,27 @@ +--- +title: kagent uninstall +description: kagent uninstall command +weight: 10 +--- + +Uninstall kagent from a Kubernetes cluster. + +```bash +kagent uninstall [flags] +``` + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## Example + +Uninstall kagent: + +```bash +kagent uninstall +``` + diff --git a/docs-site/content/kagent/resources/cli/kagent-version.md b/docs-site/content/kagent/resources/cli/kagent-version.md new file mode 100644 index 00000000..094f0628 --- /dev/null +++ b/docs-site/content/kagent/resources/cli/kagent-version.md @@ -0,0 +1,31 @@ +--- +title: kagent version +description: kagent version command +weight: 10 +--- + +Print the kagent version information. + +```bash +kagent version [flags] +``` + +**Global Flags:** +- `--kagent-url` - kagent URL (default: "http://localhost:8083") +- `--namespace, -n` - Namespace (default: "kagent") +- `--output-format, -o` - Output format (default: "table") +- `--timeout` - Timeout duration (default: 300s) +- `--verbose, -v` - Verbose output + +## About `kagent version` + +This command prints the kagent CLI version. The CLI attempts to connect to the kagent server to retrieve server version information. Versions unable to be obtained from the remote kagent server are reported as "unknown". + +## Example + +Print version information: + +```bash +kagent version +``` + diff --git a/docs-site/content/kagent/resources/faq.md b/docs-site/content/kagent/resources/faq.md new file mode 100644 index 00000000..9d554b22 --- /dev/null +++ b/docs-site/content/kagent/resources/faq.md @@ -0,0 +1,27 @@ +--- +title: Frequently Asked Questions +linkTitle: FAQs +description: Find answers to frequently asked questions about kagent. +weight: 5 +author: kagent.dev +--- + +## What's the best way to get started with kagent? + +The best way to get started with kagent is to follow the [quickstart guide](/docs/kagent/getting-started/quickstart). This will give you a basic understanding of how kagent works and how to use it. + +## What differentiates kagent from other LLM frameworks? + +kagent is special for a few core reasons: + +- **Declarative**: kagent is designed from the ground up to be declarative. You define the agents, tools, and instructions and kagent will take care of the rest. Most other frameworks are procedural and require you to write code to tell the LLM what to do. +- **Kubernetes Native**: kagent is designed to be used in a Kubernetes environment, and integrates seamlessly with services already running in the cluster. +- **Easy To Use**: kagent abstracts all of the "hard" parts of building an agent, so you can focus on connecting your business logic to the agent. + +## How do I report bugs or request features? + +The best way to report bugs or request features is to create an issue on the [GitHub repository](https://github.com/kagent-dev/kagent/issues). + +## How do I contribute to the kagent project? + +The best way to contribute is to check out the [contribution guide](https://github.com/kagent-dev/kagent/blob/main/CONTRIBUTING.md) and submit a PR. diff --git a/docs-site/content/kagent/resources/helm.md b/docs-site/content/kagent/resources/helm.md new file mode 100644 index 00000000..e69413f3 --- /dev/null +++ b/docs-site/content/kagent/resources/helm.md @@ -0,0 +1,349 @@ +--- +title: kagent +linkTitle: Helm Chart Configuration +description: kagent Helm chart configuration reference +weight: 2 +author: kagent.dev +--- + +A Helm chart for kagent, built with Google ADK + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| `${SUBSTRATE_REPO}` | substrate | `${SUBSTRATE_VERSION}` | +| file://../agents/argo-rollouts | argo-rollouts-agent | | +| file://../agents/cilium-debug | cilium-debug-agent | | +| file://../agents/cilium-manager | cilium-manager-agent | | +| file://../agents/cilium-policy | cilium-policy-agent | | +| file://../agents/helm | helm-agent | | +| file://../agents/istio | istio-agent | | +| file://../agents/k8s | k8s-agent | | +| file://../agents/kgateway | kgateway-agent | | +| file://../agents/observability | observability-agent | | +| file://../agents/promql | promql-agent | | +| file://../tools/grafana-mcp | grafana-mcp | | +| file://../tools/querydoc | querydoc | | +| https://oauth2-proxy.github.io/manifests | oauth2-proxy | ~7.0.0 | +| oci://ghcr.io/kagent-dev/kmcp/helm | kmcp | `${KMCP_VERSION}` | +| oci://ghcr.io/kagent-dev/tools/helm | kagent-tools | 0.2.1 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| annotations | object | `{}` | Additional annotations to add to all Kubernetes deployment resources | +| argo-rollouts-agent.enabled | bool | `true` | | +| argo-rollouts-agent.memory.enabled | bool | `false` | | +| argo-rollouts-agent.memory.modelConfigRef | string | `""` | | +| argo-rollouts-agent.memory.ttlDays | int | `15` | | +| argo-rollouts-agent.modelConfigRef | string | `""` | | +| argo-rollouts-agent.resources.limits.memory | string | `"256Mi"` | | +| argo-rollouts-agent.resources.requests.cpu | string | `"50m"` | | +| argo-rollouts-agent.resources.requests.memory | string | `"128Mi"` | | +| cilium-debug-agent.enabled | bool | `true` | | +| cilium-debug-agent.memory.enabled | bool | `false` | | +| cilium-debug-agent.memory.modelConfigRef | string | `""` | | +| cilium-debug-agent.memory.ttlDays | int | `15` | | +| cilium-debug-agent.modelConfigRef | string | `""` | | +| cilium-debug-agent.resources.limits.memory | string | `"256Mi"` | | +| cilium-debug-agent.resources.requests.cpu | string | `"50m"` | | +| cilium-debug-agent.resources.requests.memory | string | `"128Mi"` | | +| cilium-manager-agent.enabled | bool | `true` | | +| cilium-manager-agent.memory.enabled | bool | `false` | | +| cilium-manager-agent.memory.modelConfigRef | string | `""` | | +| cilium-manager-agent.memory.ttlDays | int | `15` | | +| cilium-manager-agent.modelConfigRef | string | `""` | | +| cilium-manager-agent.resources.limits.memory | string | `"256Mi"` | | +| cilium-manager-agent.resources.requests.cpu | string | `"50m"` | | +| cilium-manager-agent.resources.requests.memory | string | `"128Mi"` | | +| cilium-policy-agent.enabled | bool | `true` | | +| cilium-policy-agent.memory.enabled | bool | `false` | | +| cilium-policy-agent.memory.modelConfigRef | string | `""` | | +| cilium-policy-agent.memory.ttlDays | int | `15` | | +| cilium-policy-agent.modelConfigRef | string | `""` | | +| cilium-policy-agent.resources.limits.memory | string | `"256Mi"` | | +| cilium-policy-agent.resources.requests.cpu | string | `"50m"` | | +| cilium-policy-agent.resources.requests.memory | string | `"128Mi"` | | +| controller.a2aBaseUrl | string | `http://-controller..svc.cluster.local:` | The base URL of the A2A Server endpoint, as advertised to clients. | +| controller.a2aClientTimeout | string | "" (no timeout) | HTTP client timeout for A2A requests from the controller to agent pods. 0 (the default) means no timeout, which is correct for SSE-based streaming agents that can run for an arbitrarily long time. The previous implicit default was 3m (inherited from the a2a-go SDK), which caused `context deadline exceeded` errors for agents that take longer than 3 minutes to complete. Set a positive Go duration string (e.g. "30m", "1h") only if you need a hard upper bound on individual A2A calls. | +| controller.agentDeployment | object | `{"host":"","podLabels":{},"serviceAccountName":""}` | Global deployment defaults applied to all agent pods. Per-agent settings in the Agent CRD take precedence over these defaults. | +| controller.agentDeployment.host | string | "" (controller falls back to "0.0.0.0"; "::" when ipv6.enabled) | Default host address for agent pods to bind to. Leave empty to use the controller's default fallback of "0.0.0.0". Automatically set to "::" when ipv6.enabled is true. Can be explicitly overridden here regardless of the ipv6 flag. | +| controller.agentDeployment.podLabels | object | {} (no extra labels) | Default labels applied to all agent pod templates. Per-agent labels in the Agent CRD take precedence over these defaults. | +| controller.agentDeployment.serviceAccountName | string | "" (auto-create per-agent ServiceAccount) | Default ServiceAccount name for agent pods. When set, agent pods that don't specify an explicit serviceAccountName will use this ServiceAccount instead of creating a per-agent one. Useful for Workload Identity (GCP, AWS IRSA, Azure Workload Identity). Precedence: agent-level serviceAccountName > this default > auto-created SA. | +| controller.agentImage.pullPolicy | string | `""` | | +| controller.agentImage.registry | string | `""` | | +| controller.agentImage.repository | string | `"kagent-dev/kagent/app"` | | +| controller.agentImage.tag | string | `""` | | +| controller.annotations | object | `{}` | Additional annotations to add to the controller Deployment metadata | +| controller.auth.mode | string | `"unsecure"` | | +| controller.auth.userIdClaim | string | `""` | | +| controller.env | list | `[]` | | +| controller.envFrom | list | `[]` | | +| controller.image.pullPolicy | string | `""` | | +| controller.image.registry | string | `""` | | +| controller.image.repository | string | `"kagent-dev/kagent/controller"` | | +| controller.image.tag | string | `""` | | +| controller.loglevel | string | `"info"` | | +| controller.mcpEgressPlaintext | bool | `false` | Rewrite RemoteMCPServer tool URLs and the controller's tool-discovery dial from `https://host[:port]` to `http://host:` so MCP traffic egresses in plaintext to a proxy that originates TLS upstream off by default. | +| controller.metrics | object | disabled | Prometheus-style /metrics endpoint for the controller manager. When enabled, provisions a dedicated metrics Service plus the ClusterRoles required for authenticated scrapes. Bind `-metrics-reader` to your Prometheus ServiceAccount to grant scrape access. Use `bindAddress` for any port change: the Service `targetPort` and the pod `containerPort` are derived from it at template time, so overriding `METRICS_BIND_ADDRESS` via `controller.env` shifts only the runtime listener and leaves the rendered Service pointing at the chart-time port. Setting `bindAddress: "0"` (or empty) is treated as a disable signal — equivalent to `enabled: false` — to keep faith with the controller binary's documented contract for `--metrics-bind-address`. | +| controller.nodeSelector | object | `{}` | Node labels to match for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | +| controller.podAnnotations | object | `{}` | | +| controller.readinessProbe | object | httpGet /health on port http, periodSeconds=30 | Custom readiness probe for the controller container. Setting a value replaces the default probe entirely — include a handler (httpGet / exec / tcpSocket / grpc) when overriding. | +| controller.replicas | int | `1` | | +| controller.resources.limits.cpu | int | `2` | | +| controller.resources.limits.memory | string | `"512Mi"` | | +| controller.resources.requests.cpu | string | `"100m"` | | +| controller.resources.requests.memory | string | `"128Mi"` | | +| controller.service.annotations | object | `{}` | | +| controller.service.ports.port | int | `8083` | | +| controller.service.ports.targetPort | int | `8083` | | +| controller.service.type | string | `"ClusterIP"` | | +| controller.skillsInitImage | object | `{"pullPolicy":"","registry":"","repository":"kagent-dev/kagent/skills-init","tag":""}` | The image used by the skills-init container to clone skills from Git and pull OCI skill images. | +| controller.startupProbe | object | httpGet /health on port http, periodSeconds=15, initialDelaySeconds=15 | Custom startup probe for the controller container. Setting a value replaces the default probe entirely — include a handler (httpGet / exec / tcpSocket / grpc) when overriding. | +| controller.streaming | string | `nil` | @deprecated Removed in 0.10.0. The A2A SDK now handles SSE buffering and timeouts internally. These values have no effect and will be removed in a future release. | +| controller.substrate.ateApiEndpoint | string | `""` | | +| controller.substrate.ateApiInsecure | bool | `false` | | +| controller.substrate.ateApiServer.namespace | string | `"ate-system"` | | +| controller.substrate.ateApiServer.serviceAccount | string | `"ate-api-server"` | | +| controller.substrate.ateApiTokenAudience | string | `"api.ate-system.svc"` | | +| controller.substrate.ateApiTokenExpirationSeconds | int | `3600` | | +| controller.substrate.ateApiTokenFile | string | `"/var/run/secrets/tokens/ate-api/token"` | | +| controller.substrate.atenetRouterURL | string | `""` | | +| controller.substrate.defaultWorkerPool.name | string | `""` | | +| controller.substrate.defaultWorkerPool.namespace | string | `""` | | +| controller.substrate.enabled | bool | `false` | | +| controller.tolerations | list | `[]` | Node taints which will be tolerated for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | +| controller.volumeMounts | list | `[]` | | +| controller.volumes | list | `[]` | | +| controller.watchNamespaces | list | [] (watches all available namespaces) | Namespaces the controller should watch. If empty, the controller will watch ALL available namespaces. | +| database.postgres.bundled | object | `{"enabled":true,"image":{"name":"postgres","pullPolicy":"IfNotPresent","registry":"docker.io","repository":"library","tag":"18.3-alpine"},"podSecurityContext":{"fsGroup":999,"runAsGroup":999,"runAsNonRoot":true,"runAsUser":999,"seccompProfile":{"type":"RuntimeDefault"}},"resources":{"limits":{"cpu":"500m","memory":"512Mi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]}},"storage":"500Mi","storageClassName":""}` | Bundled PostgreSQL instance — for development and evaluation only. Not suitable for production. Deployed when enabled is true and url/urlFile are not set. | +| database.postgres.bundled.enabled | bool | `true` | Set to false to disable the bundled database and provide your own via url or urlFile. | +| database.postgres.bundled.image.name | string | `"postgres"` | Bundled PostgreSQL image name | +| database.postgres.bundled.image.pullPolicy | string | `"IfNotPresent"` | Bundled PostgreSQL image pull policy | +| database.postgres.bundled.image.registry | string | `"docker.io"` | Bundled PostgreSQL image registry | +| database.postgres.bundled.image.repository | string | `"library"` | Bundled PostgreSQL image repository (org/namespace) | +| database.postgres.bundled.image.tag | string | `"18.3-alpine"` | Bundled PostgreSQL image tag | +| database.postgres.bundled.podSecurityContext | object | `{"fsGroup":999,"runAsGroup":999,"runAsNonRoot":true,"runAsUser":999,"seccompProfile":{"type":"RuntimeDefault"}}` | Pod-level security context for the bundled PostgreSQL deployment. | +| database.postgres.bundled.resources | object | `{"limits":{"cpu":"500m","memory":"512Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | Resource requests/limits for the demo PostgreSQL container | +| database.postgres.bundled.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]}}` | Container-level security context for the bundled PostgreSQL container. | +| database.postgres.bundled.storage | string | `"500Mi"` | PersistentVolumeClaim size for demo PostgreSQL data | +| database.postgres.bundled.storageClassName | string | `""` | StorageClass for the PostgreSQL PVC. Defaults to the cluster default when empty. | +| database.postgres.skipMigrations | bool | `false` | Skip running database migrations at controller startup. The controller instead verifies the database is already migrated and fails if it is not. Migrations must be applied out-of-band (e.g. from a CI/CD pipeline) before install/upgrade. | +| database.postgres.url | string | `""` | External PostgreSQL connection string. Is always used if set regardless of the `.bundled.enabled` field. | +| database.postgres.urlFile | string | `""` | Path to a file containing the database URL. Takes precedence over url when set. Is always used if set regardless of the `.bundled.enabled` field. | +| database.postgres.vectorEnabled | bool | `false` | Enable the pgvector migration Required to use features that depend on database vector capability. (e.g. long-term memory) Set to true when using an external PostgreSQL that has the pgvector extension installed. | +| fullnameOverride | string | `""` | | +| grafana-mcp.enabled | bool | `true` | | +| grafana-mcp.grafana.serviceAccountToken | string | `""` | | +| grafana-mcp.grafana.url | string | `"grafana.kagent:3000/api"` | | +| grafana-mcp.resources.limits.cpu | string | `"500m"` | | +| grafana-mcp.resources.limits.memory | string | `"512Mi"` | | +| grafana-mcp.resources.requests.cpu | string | `"100m"` | | +| grafana-mcp.resources.requests.memory | string | `"128Mi"` | | +| helm-agent.enabled | bool | `true` | | +| helm-agent.memory.enabled | bool | `false` | | +| helm-agent.memory.modelConfigRef | string | `""` | | +| helm-agent.memory.ttlDays | int | `15` | | +| helm-agent.modelConfigRef | string | `""` | | +| helm-agent.resources.limits.memory | string | `"256Mi"` | | +| helm-agent.resources.requests.cpu | string | `"50m"` | | +| helm-agent.resources.requests.memory | string | `"128Mi"` | | +| imagePullPolicy | string | `"IfNotPresent"` | | +| imagePullSecrets | list | `[]` | | +| ipv6 | object | false | Enable IPv6/dual-stack support. When true, configures all components for dual-stack (IPv4+IPv6) networking: - nginx listens on both IPv4 and IPv6 (adds `listen [::]:8080`) - Next.js binds to `::` instead of `0.0.0.0` - Agent pods bind to `::` for dual-stack reachability Leave disabled on clusters where IPv6 is disabled at the kernel level. | +| istio-agent.enabled | bool | `true` | | +| istio-agent.memory.enabled | bool | `false` | | +| istio-agent.memory.modelConfigRef | string | `""` | | +| istio-agent.memory.ttlDays | int | `15` | | +| istio-agent.modelConfigRef | string | `""` | | +| istio-agent.resources.limits.memory | string | `"256Mi"` | | +| istio-agent.resources.requests.cpu | string | `"50m"` | | +| istio-agent.resources.requests.memory | string | `"128Mi"` | | +| k8s-agent.enabled | bool | `true` | | +| k8s-agent.memory.enabled | bool | `false` | | +| k8s-agent.memory.modelConfigRef | string | `""` | | +| k8s-agent.memory.ttlDays | int | `15` | | +| k8s-agent.modelConfigRef | string | `""` | | +| k8s-agent.resources.limits.memory | string | `"256Mi"` | | +| k8s-agent.resources.requests.cpu | string | `"50m"` | | +| k8s-agent.resources.requests.memory | string | `"128Mi"` | | +| kagent-tools.enabled | bool | `true` | | +| kagent-tools.nameOverride | string | `"tools"` | | +| kagent-tools.podSecurityContext.runAsNonRoot | bool | `true` | | +| kagent-tools.podSecurityContext.seccompProfile.type | string | `"RuntimeDefault"` | | +| kagent-tools.replicaCount | int | `1` | | +| kagent-tools.resources.limits.memory | string | `"256Mi"` | | +| kagent-tools.resources.requests.cpu | string | `"50m"` | | +| kagent-tools.resources.requests.memory | string | `"128Mi"` | | +| kagent-tools.securityContext.allowPrivilegeEscalation | bool | `false` | | +| kagent-tools.securityContext.capabilities.drop[0] | string | `"ALL"` | | +| kagent-tools.securityContext.readOnlyRootFilesystem | bool | `true` | | +| kagent-tools.tools.loglevel | string | `"debug"` | | +| kagent-tools.tools.metrics.port | int | `8085` | | +| kgateway-agent.enabled | bool | `true` | | +| kgateway-agent.memory.enabled | bool | `false` | | +| kgateway-agent.memory.modelConfigRef | string | `""` | | +| kgateway-agent.memory.ttlDays | int | `15` | | +| kgateway-agent.modelConfigRef | string | `""` | | +| kgateway-agent.resources.limits.memory | string | `"256Mi"` | | +| kgateway-agent.resources.requests.cpu | string | `"50m"` | | +| kgateway-agent.resources.requests.memory | string | `"128Mi"` | | +| kmcp.enabled | bool | `true` | | +| kmcp.fullnameOverride | string | `""` | | +| kmcp.nameOverride | string | `"kmcp"` | | +| kmcp.namespaceOverride | string | `""` | | +| labels | object | `{}` | Additional labels to add to all Kubernetes resources | +| nameOverride | string | `""` | | +| namespaceOverride | string | `.Release.Namespace` | Override the namespace | +| nodeSelector | object | `{}` | Node labels to match for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | +| oauth2-proxy.config.clientID | string | `""` | | +| oauth2-proxy.config.clientSecret | string | `""` | | +| oauth2-proxy.config.cookieSecret | string | `""` | | +| oauth2-proxy.config.existingSecret | string | `""` | | +| oauth2-proxy.enabled | bool | `false` | | +| oauth2-proxy.extraArgs.approval-prompt | string | `"auto"` | | +| oauth2-proxy.extraArgs.cookie-samesite | string | `"lax"` | | +| oauth2-proxy.extraArgs.cookie-secure | bool | `true` | | +| oauth2-proxy.extraArgs.custom-templates-dir | string | `"/templates"` | | +| oauth2-proxy.extraArgs.email-domain | string | `"*"` | | +| oauth2-proxy.extraArgs.oidc-issuer-url | string | `"$(OIDC_ISSUER_URL)"` | | +| oauth2-proxy.extraArgs.pass-authorization-header | bool | `true` | | +| oauth2-proxy.extraArgs.provider | string | `"oidc"` | | +| oauth2-proxy.extraArgs.redirect-url | string | `"$(OIDC_REDIRECT_URL)"` | | +| oauth2-proxy.extraArgs.scope | string | `"openid profile email groups"` | | +| oauth2-proxy.extraArgs.set-authorization-header | bool | `true` | | +| oauth2-proxy.extraArgs.skip-auth-regex | string | `"^/(login|_next/static|_next/image|login-bg\\.(jpg|png|webp)|logo-.*\\.png|favicon\\.ico|api/agentharnesses/.*/gateway).*$"` | | +| oauth2-proxy.extraArgs.skip-auth-route | string | `"^/(health|login)$"` | | +| oauth2-proxy.extraArgs.skip-jwt-bearer-tokens | bool | `true` | | +| oauth2-proxy.extraArgs.upstream | string | `"$(UPSTREAM_URL)"` | | +| oauth2-proxy.extraEnv[0].name | string | `"OIDC_ISSUER_URL"` | | +| oauth2-proxy.extraEnv[0].value | string | `""` | | +| oauth2-proxy.extraEnv[1].name | string | `"OIDC_REDIRECT_URL"` | | +| oauth2-proxy.extraEnv[1].value | string | `""` | | +| oauth2-proxy.extraEnv[2].name | string | `"UPSTREAM_URL"` | | +| oauth2-proxy.extraEnv[2].value | string | `"http://kagent-ui:8080"` | | +| oauth2-proxy.extraVolumeMounts[0].mountPath | string | `"/templates"` | | +| oauth2-proxy.extraVolumeMounts[0].name | string | `"custom-templates"` | | +| oauth2-proxy.extraVolumeMounts[0].readOnly | bool | `true` | | +| oauth2-proxy.extraVolumes[0].configMap.name | string | `"kagent-oauth2-proxy-templates"` | | +| oauth2-proxy.extraVolumes[0].name | string | `"custom-templates"` | | +| oauth2-proxy.redis.enabled | bool | `false` | | +| oauth2-proxy.service.portNumber | int | `4180` | | +| oauth2-proxy.service.type | string | `"ClusterIP"` | | +| oauth2-proxy.sessionStorage.type | string | `"cookie"` | | +| observability-agent.enabled | bool | `true` | | +| observability-agent.memory.enabled | bool | `false` | | +| observability-agent.memory.modelConfigRef | string | `""` | | +| observability-agent.memory.ttlDays | int | `15` | | +| observability-agent.modelConfigRef | string | `""` | | +| observability-agent.resources.limits.memory | string | `"256Mi"` | | +| observability-agent.resources.requests.cpu | string | `"50m"` | | +| observability-agent.resources.requests.memory | string | `"128Mi"` | | +| otel.logging.enabled | bool | `false` | | +| otel.logging.exporter.otlp.endpoint | string | `""` | | +| otel.logging.exporter.otlp.insecure | bool | `true` | | +| otel.logging.exporter.otlp.timeout | int | `15000` | | +| otel.tracing.enabled | bool | `false` | | +| otel.tracing.exporter.otlp.endpoint | string | `""` | | +| otel.tracing.exporter.otlp.insecure | bool | `true` | | +| otel.tracing.exporter.otlp.protocol | string | `"grpc"` | | +| otel.tracing.exporter.otlp.timeout | int | `15000` | | +| podAnnotations | object | `{}` | | +| podSecurityContext | object | `{"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}` | Security context for all pods | +| promql-agent.enabled | bool | `true` | | +| promql-agent.memory.enabled | bool | `false` | | +| promql-agent.memory.modelConfigRef | string | `""` | | +| promql-agent.memory.ttlDays | int | `15` | | +| promql-agent.modelConfigRef | string | `""` | | +| promql-agent.resources.limits.memory | string | `"256Mi"` | | +| promql-agent.resources.requests.cpu | string | `"50m"` | | +| promql-agent.resources.requests.memory | string | `"128Mi"` | | +| providers.anthropic.apiKeySecretKey | string | `"ANTHROPIC_API_KEY"` | | +| providers.anthropic.apiKeySecretRef | string | `"kagent-anthropic"` | | +| providers.anthropic.model | string | `"claude-haiku-4-5"` | | +| providers.anthropic.provider | string | `"Anthropic"` | | +| providers.azureOpenAI.apiKeySecretKey | string | `"AZUREOPENAI_API_KEY"` | | +| providers.azureOpenAI.apiKeySecretRef | string | `"kagent-azure-openai"` | | +| providers.azureOpenAI.config.apiVersion | string | `"2023-05-15"` | | +| providers.azureOpenAI.config.azureAdToken | string | `""` | | +| providers.azureOpenAI.config.azureDeployment | string | `""` | | +| providers.azureOpenAI.config.azureEndpoint | string | `""` | | +| providers.azureOpenAI.model | string | `"gpt-4.1-mini"` | | +| providers.azureOpenAI.provider | string | `"AzureOpenAI"` | | +| providers.default | string | `"openAI"` | | +| providers.gemini.apiKeySecretKey | string | `"GOOGLE_API_KEY"` | | +| providers.gemini.apiKeySecretRef | string | `"kagent-gemini"` | | +| providers.gemini.model | string | `"gemini-2.0-flash-lite"` | | +| providers.gemini.provider | string | `"Gemini"` | | +| providers.ollama.config.host | string | `"host.docker.internal:11434"` | | +| providers.ollama.config.options.num_ctx | string | `"64000"` | | +| providers.ollama.model | string | `"llama3.2"` | | +| providers.ollama.provider | string | `"Ollama"` | | +| providers.openAI.apiKeySecretKey | string | `"OPENAI_API_KEY"` | | +| providers.openAI.apiKeySecretRef | string | `"kagent-openai"` | | +| providers.openAI.model | string | `"gpt-4.1-mini"` | | +| providers.openAI.provider | string | `"OpenAI"` | | +| proxy.url | string | `""` | | +| querydoc.enabled | bool | `true` | | +| querydoc.image.pullPolicy | string | `"IfNotPresent"` | | +| querydoc.image.registry | string | `"ghcr.io"` | | +| querydoc.image.repository | string | `"kagent-dev/doc2vec/mcp"` | | +| querydoc.image.tag | string | `"1.1.14"` | | +| querydoc.openai.apiKey | string | `""` | | +| querydoc.replicas | int | `1` | | +| querydoc.resources.limits.cpu | string | `"500m"` | | +| querydoc.resources.limits.memory | string | `"512Mi"` | | +| querydoc.resources.requests.cpu | string | `"100m"` | | +| querydoc.resources.requests.memory | string | `"128Mi"` | | +| rbac.namespaces | list | `[]` | Namespaces in which to create Role and RoleBinding resources. If empty (default), the chart creates cluster-scoped ClusterRole and ClusterRoleBinding resources and the controller watches all namespaces. If set, the chart creates a Role + RoleBinding per listed namespace and the controller's WATCH_NAMESPACES is derived from this list (unless controller.watchNamespaces is set explicitly, which always takes precedence). | +| registry | string | `"ghcr.io"` | | +| securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true}` | Security context for all containers | +| substrate.enabled | bool | `false` | | +| substrateWorkerPool | object | `{"ateomImage":"","create":false,"labels":{},"name":"kagent-default","replicas":1,"sandboxClass":"gvisor","template":{}}` | Optional Agent Substrate WorkerPool installed by this chart. This is platform capacity and is not owned by individual AgentHarness resources. | +| tag | string | `""` | | +| tolerations | list | `[]` | Node taints which will be tolerated for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | +| ui.additionalForwardedHeaders | list | `[]` | Additional request headers (beyond Authorization) the UI proxy will forward to the backend. Names are case-insensitive. Hop-by-hop headers (Connection, Transfer-Encoding, etc.) are silently dropped. | +| ui.annotations | object | `{}` | Additional annotations to add to the UI Deployment metadata | +| ui.auth.ssoRedirectPath | string | `"/oauth2/start"` | | +| ui.backendInternalUrl | string | `""` | | +| ui.env | object | `{}` | | +| ui.externalUrl | string | "" (share tools return paths only) | Public-facing base URL of the UI (e.g. https://kagent.example.com). When set, the controller injects KAGENT_UI_URL into agent pods so that share link tools return full clickable URLs instead of relative paths. | +| ui.httpRoute | object | `{"annotations":{},"enabled":false,"hostnames":[],"labels":{},"parentRefs":[],"rules":[]}` | Gateway API `HTTPRoute` for the UI. Requires the Gateway API CRDs (`gateway.networking.k8s.io/v1`) and an existing `Gateway` to attach to via `parentRefs`. Disabled by default; enable to front the UI with a Gateway API implementation (kgateway, Istio, Envoy Gateway, etc.) instead of the OpenShift Route or bundled oauth2-proxy. | +| ui.httpRoute.annotations | object | `{}` | Annotations to add to the `HTTPRoute`. | +| ui.httpRoute.hostnames | list | `[]` | Hostnames matched by the route. | +| ui.httpRoute.labels | object | `{}` | Extra labels to add to the `HTTPRoute` (merged with the chart labels). | +| ui.httpRoute.parentRefs | list | `[]` | Gateways this route attaches to. Required when `enabled` is `true`. | +| ui.httpRoute.rules | list | `[]` | Routing rules. When a rule omits `backendRefs`, it defaults to the UI `Service` on `ui.service.ports.port`. Each rule may also set `matches`, `filters`, and `timeouts`. | +| ui.image.pullPolicy | string | `""` | | +| ui.image.registry | string | `""` | | +| ui.image.repository | string | `"kagent-dev/kagent/ui"` | | +| ui.image.tag | string | `""` | | +| ui.nginx | object | `{"proxyReadTimeout":"1800s","proxySendTimeout":"1800s"}` | Nginx proxy timeout configuration for the UI sidecar (values are passed directly to the corresponding nginx directives, e.g. "1800s"). | +| ui.nginx.proxyReadTimeout | string | `"1800s"` | proxy_read_timeout: max time between two successive reads from the upstream. | +| ui.nginx.proxySendTimeout | string | `"1800s"` | proxy_send_timeout: max time between two successive writes to the upstream. | +| ui.nodeSelector | object | `{}` | Node labels to match for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | +| ui.openshiftRoute.annotations."haproxy.router.openshift.io/timeout" | string | `"120m"` | | +| ui.podAnnotations | object | `{}` | | +| ui.podSecurityContext | object | (uses global podSecurityContext) | Pod-level security context for the UI pod. Overrides the global podSecurityContext. | +| ui.publicBackendUrl | string | `"/api"` | | +| ui.readinessProbe | object | httpGet /health on port http, periodSeconds=30 | Custom readiness probe for the UI container. Override to adjust thresholds, use exec-based probes, or change the health path. | +| ui.replicas | int | `1` | | +| ui.resources.limits.cpu | string | `"1000m"` | | +| ui.resources.limits.memory | string | `"1Gi"` | | +| ui.resources.requests.cpu | string | `"100m"` | | +| ui.resources.requests.memory | string | `"256Mi"` | | +| ui.route | object | `{"enabled":true}` | Gates the OpenShift `Route` for the UI. Additionally conditional on the `route.openshift.io/v1` API being present, so it is a no-op off-OpenShift. Set to `false` to front the UI with your own Route/ingress or the bundled oauth2-proxy instead of the chart's edge-terminated Route. | +| ui.securityContext | object | (uses global securityContext) | Container-level security context for the UI container. Overrides the global securityContext. | +| ui.service.annotations | object | `{}` | | +| ui.service.ports.port | int | `8080` | | +| ui.service.ports.targetPort | int | `8080` | | +| ui.service.type | string | `"ClusterIP"` | | +| ui.startupProbe | object | httpGet /health on port http, periodSeconds=1, initialDelaySeconds=1 | Custom startup probe for the UI container. Override to adjust thresholds, use exec-based probes, or change the health path. | +| ui.streamTimeoutSeconds | int | `1800` | Client-side chat stream inactivity timeout (seconds). The browser aborts a streaming response if no event is received within this window. Should be >= ui.nginx.proxyReadTimeout so nginx isn't the silent limit. Default 1800 (30m). | +| ui.tolerations | list | `[]` | Node taints which will be tolerated for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | +| ui.volumes | object | `{"nextjsCache":"100Mi","tmp":"50Mi"}` | EmptyDir volume sizes for Next.js UI workload (typically used when enabling readOnlyRootFilesystem) | +| ui.volumes.nextjsCache | string | `"100Mi"` | Size limit for Next.js build cache (.next/cache). Default 100Mi is sufficient for typical Next.js apps with moderate caching needs. | +| ui.volumes.tmp | string | `"50Mi"` | Size limit for temporary files (/tmp). Default 50Mi provides ample space for Next.js runtime temporary data. | + diff --git a/docs-site/content/kagent/resources/release-notes.md b/docs-site/content/kagent/resources/release-notes.md new file mode 100644 index 00000000..2ec77f66 --- /dev/null +++ b/docs-site/content/kagent/resources/release-notes.md @@ -0,0 +1,691 @@ +--- +title: Release Notes +description: Review the release notes for kagent. +weight: 5 +author: kagent.dev +--- + +The kagent documentation shows information only for the latest release. If you run an older version, review the release notes to understand the main changes from version to version. + +For more details on the changes between versions, review the [kagent GitHub releases](https://github.com/kagent-dev/kagent/releases). + +## v0.9 + +Review this summary of significant changes from kagent version 0.8 to v0.9. + +**Before you upgrade:** + +* You must be running at least v0.8.0 before upgrading to v0.9.0. +* Back up your PostgreSQL database before upgrading. For details on your database configuration, see the [Database configuration guide](/docs/kagent/operations/operational-considerations/#database-configuration). +* The `rbac.clusterScoped` Helm value is removed. RBAC scope is now derived from `rbac.namespaces`. If you set `rbac.clusterScoped` in your Helm values, update your configuration to use `rbac.namespaces` instead. + +**What's included:** + +* Agent Sandbox — run agents in isolated sandboxes with network controls using the Kubernetes agent-sandbox project. +* OIDC proxy authentication — optional enterprise authentication via oauth2-proxy with support for Cognito, Okta, Dex, and other OIDC providers. +* SAP AI Core provider — new model provider for SAP AI Core via the Orchestration Service. +* Database migration tooling — the database backend is refactored from GORM + AutoMigrate to golang-migrate + sqlc. +* Bedrock embedding support — native Bedrock embedding models for agent memory. + +### Agent Sandbox + +You can now run agents in isolated sandboxes using the [Kubernetes agent-sandbox](https://github.com/kubernetes-sigs/agent-sandbox) project. A new `SandboxAgent` CRD creates sandboxed agent instances with restricted filesystem and network access, providing stronger isolation for untrusted or experimental workloads. + +Sandbox agents support configurable network allowlists for both Go and Python runtimes, so you can control which external endpoints the agent is permitted to reach. + +To use agent sandboxes, install the agent-sandbox controller in your cluster: + +```bash +export VERSION="v0.3.10" +kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${VERSION}/manifest.yaml +kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${VERSION}/extensions.yaml +``` + +Then create a `SandboxAgent` resource with the same spec as a regular `Agent` resource. + +### OIDC Proxy Authentication + +kagent now supports optional OIDC proxy-based authentication through an [oauth2-proxy](https://oauth2-proxy.github.io/oauth2-proxy/) subchart. This feature enables integration with enterprise identity providers such as Cognito, Okta, and Dex. + +When `controller.auth.mode` is set to `"proxy"`, the controller trusts JWT tokens from the `Authorization` header injected by oauth2-proxy and extracts user identity from configurable JWT claims. The default mode remains `"unsecure"`, which preserves the existing behavior with no authentication required. + +This release adds authentication only. Access control is not yet implemented. + +**What's included:** + +* A `ProxyAuthenticator` backend that extracts user identity (email, name, groups) from JWT claims. +* An `/api/me` endpoint that returns the current user's identity. +* A login page with SSO redirect and a user menu in the UI. +* NetworkPolicies that restrict UI and controller access to oauth2-proxy when auth is enabled. + +To enable OIDC authentication: + +```yaml +controller: + auth: + mode: proxy + +oauth2-proxy: + enabled: true + extraEnv: + - name: OIDC_ISSUER_URL + value: "https://your-idp.example.com" + - name: OIDC_REDIRECT_URL + value: "https://kagent.example.com/oauth2/callback" +``` + +### SAP AI Core Provider + +You can now use [SAP AI Core](https://help.sap.com/docs/sap-ai-core) as a model provider via the Orchestration Service. Configure a ModelConfig resource with the SAP AI Core provider to use SAP-hosted models with your agents. + +### Database migrations + +v0.9.0 replaces GORM `AutoMigrate` with versioned SQL migrations managed by [golang-migrate](https://github.com/golang-migrate/migrate) and [sqlc](https://sqlc.dev/). Migration history is tracked in two new tables, `schema_migrations` and `vector_schema_migrations`. + +Review the following before upgrading: + +- **Minimum prior version**: You must be on v0.8.0 or later. Upgrades from earlier versions are not supported. +- **Existing data is preserved**: Tables created by GORM are reused +- **Back up first**: Take a snapshot or backup of your database before upgrading. A fresh install on a fresh database is the cleanest path. Restore from your backup if anything goes wrong. +- **Automatic rollback on failure**: If a migration fails partway through, changes are rolled back before the controller exits non-zero. On the initial run from a GORM database, rollback to version 0 is skipped to protect pre-existing tables. +- **pgvector pre-check**: When `database.postgres.vectorEnabled: true` is set, the migration runner verifies that the `pgvector` extension is available before running any migrations. A missing extension cannot leave core tables in a partial state. +- **Safe with multiple replicas**: Migrations use a PostgreSQL session-level advisory lock, so only one controller instance applies migrations at a time. The lock releases automatically if the process crashes. If a crash leaves a dirty migration state, the next startup detects it and rolls back before retrying. + +### RBAC scope + +The `rbac.clusterScoped` Helm value was removed in v0.9.0. RBAC scope is now derived from `rbac.namespaces`: + +| `rbac.namespaces` | Resulting RBAC | Watched namespaces | +| --- | --- | --- | +| `[]` (empty, default) | Cluster-scoped `ClusterRole` and `ClusterRoleBinding` | All namespaces | +| Non-empty list | Namespaced `Role` and `RoleBinding` per listed namespace | The same list, unless `controller.watchNamespaces` is set explicitly | + +The empty-list default is unchanged from previous releases that used `rbac.clusterScoped: true`. When `controller.watchNamespaces` is set, it always takes precedence over the auto-derived list. + +The chart fails in the following cases: + +- You still have `rbac.clusterScoped` in your Helm values. +- `rbac.namespaces` is non-empty but does not include the install namespace. + +Before you upgrade: + +1. Remove `rbac.clusterScoped` from your Helm values. +2. If you previously set `rbac.clusterScoped: false` with a custom namespace list, make sure `rbac.namespaces` includes your install namespace (typically `kagent`): + + ```yaml + rbac: + namespaces: + - kagent + - team-a + - team-b + ``` + +3. To keep cluster-scoped RBAC, leave `rbac.namespaces` empty (the default). No values change is required. + +### Additional changes in v0.9 + +* **Default model update** — the retired `claude-3-5-haiku-20241022` model is replaced with `claude-haiku-4-5`. +* **Bedrock embedding support** — native Bedrock embedding models are now available for agent memory, extending the existing AWS Bedrock provider. +* **Token exchange for model auth** — a new authentication mechanism that supports token exchange for model configurations. +* **Prompt templates in UI** — prompt templates are now manageable directly in the UI. +* **Require approval toggle in UI** — you can now enable or disable the `requireApproval` setting for tools directly in the UI. +* **Enhanced Go ADK model config** — broader model and provider support in the Go runtime. +* **IPv6/dual-stack support** — agent bind host and UI probes now support IPv6 and dual-stack configurations. +* **AWS LoadBalancer annotations** — the UI Service now supports AWS LoadBalancer service annotations for easier AWS deployment. +* **SSH auth for git-based skills** — fixed SSH authentication when loading skills from private Git repositories. +* **MCP connection error handling** — MCP connection errors are now returned to the LLM as context instead of raising exceptions. +* **RemoteMCPServer TLS (v0.9.6)** — you can now connect to an MCP server that uses a private CA, self-signed certificate, or corporate internal CA by setting the `spec.tls` field on a `RemoteMCPServer`. The `spec.tls` shape mirrors the `ModelConfig` TLS configuration. + +## v0.8 + +Review this summary of significant changes from kagent version 0.7 to v0.8. + +* Human-in-the-Loop (HITL) — tool approval gates and interactive `ask_user` tool. +* Agent Memory — vector-backed long-term memory for agents. +* Go ADK runtime — new Go-based agent runtime for faster startup and lower resource usage. +* Agents as MCP servers — expose A2A agents via MCP for cross-tool interoperability. +* Skills — markdown knowledge documents loaded from OCI images or Git repositories. +* Go workspace restructure — the Go codebase is split into `api`, `core`, and `adk` modules for composability. +* Prompt templates — reusable prompt fragments from ConfigMaps using Go template syntax. +* Context management — automatic event compaction for long conversations. +* AWS Bedrock support — new model provider for AWS Bedrock. +* **PostgreSQL-only database backend** — SQLite support has been removed. PostgreSQL is now the only supported database backend. + +### Human-in-the-Loop (HITL) + +You can now use two Human-in-the-Loop mechanisms that can pause agent execution and wait for user input. + +**Tool Approval** — You can mark specific tools as requiring user confirmation before execution by using the `requireApproval` field in the Agent CR. When the agent calls a tool that requires approval, the UI presents Approve/Reject buttons. The reason provided for rejection gets used as context for the LLM. + +**Ask User** — A built-in `ask_user` tool is automatically added to every agent. Agents can pose questions to users with predefined choices (single-select, multi-select) or free-text input during execution. + +For more information, see the [Human-in-the-Loop example](/docs/kagent/examples/human-in-the-loop) and the [blog post](https://kagent.dev/blog/human-in-the-loop-kagent). + +### Agent Memory + +Your agents can now automatically save and retrieve relevant context across conversations using vector similarity search. Memory is built on the Google ADK memory implementation and uses the same kagent database (PostgreSQL). + +When you enable memory on an agent, it receives three additional tools: `save_memory`, `load_memory`, and `prefetch_memory`. Every 5th user message, the agent automatically extracts key information, such as user intent, key learnings, preferences. + +You can configure memory in the Agent CR or through the UI when you create or edit an agent by selecting an embedding model and TTL. + +For more information, see [Agent Memory](/docs/kagent/concepts/agent-memory). + +### Go ADK Runtime + +You can now choose between two Agent Development Kit runtimes: **Python** (default) and **Go**. The Go ADK provides significantly faster startup (~2 seconds vs ~15 seconds for Python) and lower resource consumption. + +Select the runtime via the `runtime` field in the declarative agent spec. + +```yaml +spec: + type: Declarative + declarative: + runtime: go +``` + +The Go ADK includes built-in tools: `SkillsTool`, `BashTool`, `ReadFile`, `WriteFile`, and `EditFile`. + +For more information, see [Agents](/docs/kagent/concepts/agents#runtime) and the [blog post](https://kagent.dev/blog/go-vs-python-runtime). + +### Agents as MCP Servers + +Agent-to-Agent (A2A) agents are now exposed as MCP servers via the kagent controller HTTP server. This enables cross-tool interoperability — any MCP-compatible client can consume agents, not just the A2A protocol. + +### Skills + +Your agents can now load markdown-based knowledge documents (skills) that provide domain-specific instructions, best practices, and procedures. Skills load at agent startup and are discoverable through the built-in `SkillsTool`. + +You can load skills from two sources. + +- **OCI images.** Container images containing skill files. +- **Git repositories.** Clone skills directly from Git repos, with support for private repos via HTTPS token or SSH key authentication. + +For more information, see [Agents](/docs/kagent/concepts/agents#git-based-skills). + +### Go Workspace Restructure + +The Go code now uses a Go workspace with three modules: `api`, `core`, and `adk`. This makes the codebase more composable for you if you want to pull in parts of kagent (such as the API types or ADK) without importing all dependencies. + +| Module | Purpose | +|--------|---------| +| `go/api` | Shared types: CRDs, ADK config types, database models, HTTP client. Import this module to work with kagent's API types without pulling in the full codebase. | +| `go/core` | Infrastructure: controllers, HTTP server, CLI. This module contains the main kagent controller logic. | +| `go/adk` | Go Agent Development Kit runtime. Import this module to build custom Go-based agents. | + +### Prompt Templates + +Agent system messages now support Go `text/template` syntax. You can store common prompt fragments, such as safety guardrails or tool usage best practices, in ConfigMaps and reference them with `{{include "alias/key"}}` syntax. + +The `kagent-builtin-prompts` ConfigMap ships with five reusable templates: `skills-usage`, `tool-usage-best-practices`, `safety-guardrails`, `kubernetes-context`, and `a2a-communication`. + +For more information, see [Agents](/docs/kagent/concepts/agents#prompt-templates). + +### Context Management + +Long conversations can now be automatically compacted to stay within LLM context windows. You can configure the `context.compaction` field to enable periodic summarization of older events while preserving key information. + +For more information, see [Agents](/docs/kagent/concepts/agents#context-management). + +### AWS Bedrock Support + +You can now use AWS Bedrock as a model provider, allowing your agents to use Bedrock-hosted models. + +### PostgreSQL-Only Database Backend + +SQLite support has been removed from kagent. PostgreSQL is now the only supported database backend. + +**What changed:** +- The `database.type` configuration option is removed. +- SQLite-related Helm values (`database.sqlite.*`) are removed. +- A bundled PostgreSQL instance is deployed by default via `database.postgres.bundled.enabled: true`. The bundled image is `postgres:18` (standard PostgreSQL without pgvector). +- `database.postgres.vectorEnabled` now defaults to `false`. Set it to `true` only when using a PostgreSQL server that has the pgvector extension installed. +- `database.postgres.bundled.enabled` and `url`/`urlFile` are now independent controls. You can keep the bundled pod running while pointing the controller at an external database, which is useful for migration. +- The bundled instance database name, username, and password are hardcoded to `kagent`. Credentials are stored in a Kubernetes Secret instead of a ConfigMap. +- The `database.postgres.bundled.database`, `bundled.user`, and `bundled.password` configuration options are removed. + +**Why this change:** +- SQLite lacks pgvector support, requiring separate code paths for memory and vector search. +- SQLite's single-writer constraint prevents horizontal scaling of the controller. +- Divergent SQL dialects between SQLite and PostgreSQL required maintaining duplicate code paths. +- PostgreSQL was already the recommended production backend. + +**Migration:** + +If you were using the default SQLite backend, no migration is needed. The bundled PostgreSQL is deployed automatically. You can optionally customize the bundled instance via `database.postgres.bundled.*` (storage size, image) as needed. See the [Database configuration guide](/docs/kagent/operations/operational-considerations/#database-configuration) for details. + +Note that for production deployments, use your own external PostgreSQL instance. If you already are, you can keep your `database.postgres.url` or `database.postgres.urlFile` settings as before. If your external PostgreSQL has the pgvector extension and you were using vector-based memory features, set `database.postgres.vectorEnabled: true` since the default has changed to `false`. + +### Additional Changes + +- **API key passthrough** for ModelConfig. +- **Custom service account** override in agent CRDs. +- **Voice support** for agents. +- **UI dynamic provider model discovery** for easier model configuration. +- **CLI `--token` flag** for `kagent invoke` API key passthrough. +- **CVE fixes** across Go, Python, and container images. + +## v0.7 + +Review the main changes from kagent version 0.6 to v0.7, then continue reading for more detailed information. + +* kmcp is installed by default when you install kagent +* New feature to develop agents locally without a Kubernetes cluster +* New `kgateway.dev/discovery` label +* Installation profiles + +### kmcp installed by default + +Now, kmcp is installed automatically with kagent, so you can use kmcp functionality out of the box. + +This change is enabled by the new default values of `kmcp.enabled=true` in both the `kagent` and `kagent-crds` Helm charts. + +#### Existing kmcp installations + +If you already have kmcp installed separately, upgrade your existing Helm releases with the `kmcp.enabled=false` flag set for both the kagent and kagent-crds charts. + +Example commands: + +`kagent-crds` Helm release: + +```bash +helm upgrade --install kagent-crds oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds \ + --namespace kagent \ + --set kmcp.enabled=false +``` + +`kagent` Helm release: + +```bash +helm upgrade --install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \ + --namespace kagent \ + --set kmcp.enabled=false +``` + +### Local agent development + +Develop and test agents locally on your machine without needing a Kubernetes cluster. As part of this feature, the `kagent` CLI includes new commands to scaffold, build, run, and deploy agents. + +For more information, see the [local development](/docs/kagent/getting-started/local-development) guide. + +### Discovery label + +Now, you can add a discovery label to MCPServer kmcp resources. By default, discovery is enabled. + +If you plan to use your kmcp resources later with kagent and agentgateway, add the `kagent.dev/discovery=disabled` label to your MCPServer resource. Then, kagent does not automatically discover MCP servers. This way, you can have agentgateway in front of your kmcp servers so that the agent-tool traffic is routed correctly through agentgateway. + +### Installation profiles + +By default, kagent installs a `demo` profile with agents and MCP tools preloaded for you. If you don't want these default agents, you can disable them with the `minimal` profile. + +For the CLI: `kagent install --profile minimal` + +For Helm installations: Individually disable the default agents with Helm values or `--set` flags, such as `--set agents.argo-rollouts-agent.enabled=false`. You can also use Helm to update the resource limits and requests for each agent. + +## v0.6 + +Review the main changes from kagent version 0.5 to v0.6, then continue reading for more detailed information. + +* The `apiVersion` field in the kagent CRDs is now `kagent.dev/v1alpha2`. +* A new Helm chart for kmcp CRDs is available. +* API string references to resources in other namespaces in the format `namespace/name` now fail. Instead, the APIs have a separate field for you to specify the namespace of the resource. +* The Tools API moves or eliminates some APIs entirely in favor of new kmcp APIs. +* The Agents APIs now require a top-level `type` field to support the new BYO agent functionality. +* The ModelConfig APIs rename the secret name field from `apiKeySecretRef` to `apiKeySecret`. +* Memory APIs are not supported in ADK. + +### Upgraded API version + +The `apiVersion` field in the kagent CRDs is now `kagent.dev/v1alpha2`. + +### New! Helm chart for kmcp CRDs + +Previously, the kagent installation included only one CRD Helm chart. As of v0.6.3, the MCPServer CRD is part of a separate kmcp Helm subchart. This kmcp subchart is installed for you when you install the kagent CRD Helm chart. + +1. If you installed the separate kmcp CRD Helm in earlier versions of v0.6, uninstall the Helm chart. + + ```shell + helm uninstall kmcp-crds -n kagent + ``` + +2. Install the kagent CRD Helm chart that includes the kmcp subchart. + + ```shell + helm install kagent-crds oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds \ + --namespace kagent \ + --create-namespace + ``` + +### General changes + +**`namespace/name` references**: API string references to resources in other namespaces in the format `namespace/name` now fail. Instead, the APIs have a separate field for you to specify the namespace of the resource. + +**Local development `buildx` access**: The `make helm-install` command now creates a local Docker registry to push development images to. As part of the build process, you might need to allow the buildx builder to access your host network. For more information, see the [developer docs in the kagent repo](https://github.com/kagent-dev/kagent/blob/main/DEVELOPMENT.md#troubleshooting). + +### Tools APIs + +The Tools-related APIs are split up into several different APIs. Some functionality is moved to kmcp, such as the ToolServer API. + +#### ToolServer + +The ToolServer API is completely removed from kagent. Instead, use other resources including some [kmcp APIs](https://kagent.dev/docs/kmcp) to create and manage tools. + +##### Stdio ToolServer now in kmcp MCPServer + +Flip through the following tabs to understand the API differences between the old kagent ToolServer and the new method of using kmcp along with a kagent MCPServer and Kubernetes Service for the Stdio transport type. + +{{< tabs >}} +{{< tab name="kagent ToolServer" >}} +Old ToolServer example: + * The `stdio` config section includes the Grafana deployment details. + * The Grafana details, including the API key, are loaded as environment settings directly in the ToolServer. + ```yaml + apiVersion: kagent.dev/v1alpha2 + kind: ToolServer + metadata: + name: mcp-grafana + namespace: kagent + spec: + config: + stdio: + command: /app/python/bin/mcp-grafana + args: + - -t + - stdio + - debug + readTimeoutSeconds: 30 + envFrom: + - name: "GRAFANA_URL" + value: my-url.com + - name: "GRAFANA_API_KEY" + valueFrom: + type: Secret + key: "grafana" + valueRef: kagent-toolserver-secret + description: "" + ``` +{{< /tab >}} +{{< tab name="kmcp MCPServer" >}} +kmcp example: + * The kagent MCPServer includes the Grafana deployment details, with `stdio` as the transport type. + ```yaml + apiVersion: kagent.dev/v1alpha1 + kind: MCPServer + metadata: + name: grafana + spec: + deployment: + image: "mcp/grafana:latest" + port: 3000 + cmd: "/app/mcp-grafana" + args: + - "--transport" + - "stdio" + env: + GRAFANA_URL: my-url.com + secretRefs: + - name: grafana-api-key + transportType: "stdio" + ``` + * The Grafana API key is stored separately in a Secret, which is more secure. + ```yaml + apiVersion: v1 + kind: Secret + metadata: + name: grafana-api-key + type: Opaque + data: + GRAFANA_API_KEY: my-base-64-ikey + ``` +{{< /tab >}} +{{< /tabs >}} + +##### HTTP ToolServer moved to RemoteMCPServer + +ToolServer resources that used `type: streamableHttp` are now configured as RemoteMCPServer resources. For more detailed information, review the API definitions: +* ToolServer: [toolserver_types.go](https://github.com/kagent-dev/kagent/blob/main/go/controller/api/v1alpha1/toolserver_types.go) +* RemoteMCPServer: [remotemcpserver_types.go](https://github.com/kagent-dev/kagent/blob/main/go/controller/api/v1alpha2/remotemcpserver_types.go) +* MCPServer: [mcpserver_types.go](https://github.com/kagent-dev/kmcp/blob/main/api/v1alpha1/mcpserver_types.go) + +{{< tabs >}} +{{< tab name="Old ToolServer (v1alpha1)" >}} +Old ToolServer API: + ```yaml + apiVersion: kagent.dev/v1alpha2 + kind: ToolServer + metadata: + name: kagent-tool-server + spec: + config: + type: streamableHttp + streamableHttp: + url: "http://kagent-tools.kagent:8084/mcp" + timeout: 30s + sseReadTimeout: 5m0s + description: "Official kagent tool server" + ``` +{{< /tab >}} +{{< tab name="New RemoteMCPServer (v1alpha2)" >}} +New RemoteMCPServer API: + ```yaml + apiVersion: kagent.dev/v1alpha2 + kind: RemoteMCPServer + metadata: + name: kagent-tool-server + spec: + url: "http://kagent-tools.kagent:8084/mcp" + timeout: 30s + sseReadTimeout: 5m0s + description: "Official kagent tool server" + ``` +{{< /tab >}} +{{< /tabs >}} + +#### Kubernetes Services as HTTP MCP servers + +Now, you can use Kubernetes Services as MCP Servers. + +{{< tabs >}} +{{< tab name="Old Service" >}} +In the old configuration, you created a Service for your MCP Deployment, and then a ToolServer resource that referred to the Service. +```yaml +apiVersion: v1 +kind: Service +metadata: + name: kagent-querydoc + namespace: kagent +spec: + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: http +--- +apiVersion: kagent.dev/v1alpha2 +kind: ToolServer +metadata: + name: kagent-querydoc + namespace: kagent +spec: + description: Queries a documentation site + config: + sse: + url: http://kagent-querydoc.kagent.svc.cluster.local/sse +``` +{{< /tab >}} +{{< tab name="New Service for MCP" >}} +In v0.6, you add certain fields to designate the Service as an MCP server. + +In the following configuration file, notice the following settings: +* `kagent.dev/mcp-service: "true"`: Optional: Configure kagent to discover the tools for this Service. +* `appProtocol: mcp`: Required: Configure the port that the controller uses. If not set, and there is a single port, the controller uses that port for the MCP server. + +**Additional annotations**: You can use the following annotations to further configure the your MCP Service. + +* `kagent.dev:mcp-service-path`: Set the path on which the MCP server lives. The default value is `/mcp`. +* `kagent.dev/mcp-service-port`: Set the port number to be used. No port is set by default. +* `kagent.dev/mcp-service-port`: Set the protocol to use. Accepted values are `SSE` or `STREAMABLE_HTTP`. The default value is `STREAMABLE_HTTP`. + +```yaml +apiVersion: v1 +kind: Service +metadata: + labels: + kagent.dev/mcp-service: "true" + annotations: + kagent.dev/mcp-service-path: /sse + kagent.dev/mcp-service-port: 8080 + kagent.dev/mcp-service-protocol: SSE + name: kagent-querydoc + namespace: kagent +spec: + ports: + - appProtocol: mcp + name: http + port: 8080 + protocol: TCP + targetPort: http +``` +{{< /tab >}} +{{< /tabs >}} + +### Agent APIs + +#### API to specify the MCP server + +{{< tabs >}} +{{< tab name="Old API (v1alpha1)" >}} +**Old API Example:** + ```yaml + tools: + - type: McpServer + mcpServer: + toolServer: kagent-querydoc + toolNames: + - query_documentation + ``` +{{< /tab >}} +{{< tab name="New API (v1alpha2)" >}} +**New API Example:** + ```yaml + tools: + - type: McpServer + mcpServer: + name: kagent-querydoc + kind: Service + toolNames: + - query_documentation + ``` + + **Key Changes:** + * The `toolServer` field has been removed + * Replaced with: `name`, `kind`, and `apiGroup` fields + * This allows specifying 3 different types: `RemoteMCPServer`, `Service`, and `MCPServer` +{{< /tab >}} +{{< /tabs >}} + +The toolServer field has been removed, and has been replaced with the following: +name +kind +apiGroup +This allows for specifying the 3 different types which may be used. Those are: +RemoteMCPServer +Service +MCPServer +Here are the 2 api defs: +* [v1alpha1](https://github.com/kagent-dev/kagent/blob/069582fbd748cb66df31d620ceb2a7beae85caf0/go/controller/api/v1alpha1/agent_types.go#L106) +* [v1alpha2](https://github.com/kagent-dev/kagent/blob/069582fbd748cb66df31d620ceb2a7beae85caf0/go/controller/api/v1alpha2/agent_types.go#L93) + +#### Top-level field for Agent APIs + +A new top-level `type` field is added to the Agents API. For existing Agents, set the `type` to `Declarative`, and then nest the previous Agent configuration inline under the `declarative` setting. + +This change supports the new type for BYO agents. + +{{< tabs >}} +{{< tab name="Old Agent API" >}} +[v1alpha1 Example](https://github.com/kagent-dev/kagent/blob/main/helm/agents/k8s/templates/agent.yaml): + + ```yaml + apiVersion: kagent.dev/v1alpha2 + kind: Agent + metadata: + name: k8s-agent + namespace: {{ include "kagent.namespace" . }} + labels: + {{- include "kagent.labels" . | nindent 4 }} + spec: + description: An Kubernetes Expert AI Agent specializing in cluster operations, troubleshooting, and maintenance. + systemMessage: | + # Kubernetes AI Agent System Prompt + + You are KubeAssist, an advanced AI agent + # ... (truncated for brevity) + ``` +{{< /tab >}} +{{< tab name="New Agent API with inline type" >}} +[v1alpha2 Example](https://github.com/kagent-dev/kagent/blob/eitanya/byo/helm/agents/k8s/templates/agent.yaml): Note that the entire agent configuration is now nested under the `declarative` setting. + + ```yaml + apiVersion: kagent.dev/v1alpha2 + kind: Agent + metadata: + name: k8s-agent + namespace: kagent + spec: + description: An Kubernetes Expert AI Agent specializing in cluster operations, troubleshooting, and maintenance. + type: Declarative + declarative: + systemMessage: | + # Kubernetes AI Agent System Prompt + + You are KubeAssist, an advanced AI agent + # ... (truncated for brevity) + ``` + + **Key Changes:** + * Added `type: Declarative` field to specify agent type + * Agent configuration now under `declarative` section + * Supports new BYO deployment model +{{< /tab >}} +{{< /tabs >}} + +#### New! BYO agents + +A new agent type has been added to the Agents API so that you can bring your own (BYO) agent. The agent must be written in ADK, with other frameworks under development. + +BYO Agent example configuration. For more information, see the [BYO Agent](/docs/kagent/examples/a2a-byo) guide. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: Agent +metadata: + name: basic-agent + namespace: kagent +spec: + description: This agent can do anything. + type: BYO + byo: + deployment: + image: my-byo:latest + env: + - name: GOOGLE_API_KEY + valueFrom: + secretKeyRef: + name: kagent-google + key: GOOGLE_API_KEY +``` + +### ModelConfig API + +The secret name field is renamed from `apiKeySecretRef` to `apiKeySecret`. + +#### ModelInfo removed + +The `modelInfo` setting is removed from the ModelConfig API. + +Supported LLM providers are pre-configured by the [kagent-dev/autogen project fork](https://github.com/kagent-dev/autogen/tree/main/python/packages/autogen-ext/src/autogen_ext/models) for you by default. Trying to override these default settings, such as to enable vision for image recognition, could cause unexpected behavior in models that do not support these settings. Therefore, the `modelInfo` field is removed. + +### Memory API + +The Memory API is not supported in ADK. The [agent development kit](https://google.github.io/adk-docs/) is required to bring your own agents. As such, the Memory docs are removed. diff --git a/docs-site/content/kagent/resources/tools-ecosystem.md b/docs-site/content/kagent/resources/tools-ecosystem.md new file mode 100644 index 00000000..21b2751c --- /dev/null +++ b/docs-site/content/kagent/resources/tools-ecosystem.md @@ -0,0 +1,245 @@ +--- +title: Tools Ecosystem +description: Explore the built-in MCP tools for Kubernetes, Helm, Istio, Prometheus, Grafana, Cilium, and Argo Rollouts. +weight: 3 +author: kagent.dev +--- + +You can use a rich set of built-in tools through **Model Context Protocol (MCP)** servers, plus add your own custom tools. Two primary MCP servers serve the tools: `kagent-tool-server` (Kubernetes, Helm, Istio, Cilium, Argo) and `kagent-grafana-mcp` (Grafana, Prometheus, Loki, Incidents). + +## kagent-tool-server Tools + +### Kubernetes + +The following tools provide comprehensive cluster management. + +| Tool | Description | +|------|-------------| +| `k8s_get_resources` | Query resources, such as pods, deployments, and services. | +| `k8s_describe_resource` | Get detailed resource information. | +| `k8s_get_resource_yaml` | Get YAML representation of a resource. | +| `k8s_get_pod_logs` | Retrieve pod logs. | +| `k8s_get_events` | Get cluster events. | +| `k8s_get_available_api_resources` | List supported API resources. | +| `k8s_get_cluster_configuration` | Retrieve cluster configuration. | +| `k8s_check_service_connectivity` | Test service connectivity. | +| `k8s_execute_command` | Execute commands in pods. | +| `k8s_patch_resource` | Patch resources with strategic merge. | +| `k8s_label_resource` | Add labels to resources. | +| `k8s_remove_label` | Remove labels from resources. | +| `k8s_annotate_resource` | Add annotations to resources. | +| `k8s_remove_annotation` | Remove annotations from resources. | +| `k8s_delete_resource` | Delete resources. | +| `k8s_apply_manifest` | Apply YAML manifests. | +| `k8s_create_resource` | Create a resource from a local file. | +| `k8s_create_resource_from_url` | Create a resource from a URL. | +| `k8s_generate_resource` | Generate YAML for Istio, Gateway API, or Argo resources. | +| `k8s_rollout` | Manage rollouts (restart, status, history). | +| `k8s_scale` | Scale a resource (deployment, statefulset, etc.). | + +### Helm + +| Tool | Description | +|------|-------------| +| `helm_list_releases` | List installed releases. | +| `helm_get_release` | Get details of a specific release. | +| `helm_upgrade` | Upgrade a release. | +| `helm_uninstall` | Remove a release. | +| `helm_repo_add` | Add a chart repository. | +| `helm_repo_update` | Update chart repositories. | + +### Istio + +| Tool | Description | +|------|-------------| +| `istio_proxy_status` | Check proxy synchronization status. | +| `istio_proxy_config` | Inspect proxy configuration. | +| `istio_install_istio` | Install Istio. | +| `istio_generate_manifest` | Generate installation manifests. | +| `istio_analyze_cluster_configuration` | Analyze Istio configuration for issues. | +| `istio_version` | Get Istio version info. | +| `istio_remote_clusters` | Manage remote cluster configuration. | +| `istio_waypoint_status` | Get waypoint proxy status. | +| `istio_list_waypoints` | List waypoint proxies. | +| `istio_generate_waypoint` | Generate waypoint configuration. | +| `istio_apply_waypoint` | Apply waypoint configuration. | +| `istio_delete_waypoint` | Delete a waypoint proxy. | +| `istio_ztunnel_config` | Inspect ztunnel configuration. | + +### Argo Rollouts + +| Tool | Description | +|------|-------------| +| `argo_verify_argo_rollouts_controller_install` | Verify the Argo Rollouts controller is running. | +| `argo_rollouts_list` | List Argo Rollouts in a namespace. | +| `argo_promote_rollout` | Promote a paused rollout. | +| `argo_pause_rollout` | Pause a rollout. | +| `argo_set_rollout_image` | Set the image of a rollout. | +| `argo_check_plugin_logs` | Check Argo Rollouts plugin logs. | +| `argo_verify_kubectl_plugin_install` | Verify the kubectl Argo Rollouts plugin is installed. | +| `argo_verify_gateway_plugin` | Verify the Argo Rollouts gateway plugin. | + +### Cilium + +The following table shows a subset of Cilium tools. Cilium has 30+ tools available. + +| Tool | Description | +|------|-------------| +| `cilium_status_and_version` | Check Cilium status and version. | +| `cilium_install_cilium` | Install Cilium. | +| `cilium_upgrade_cilium` | Upgrade Cilium. | +| `cilium_toggle_cluster_mesh` | Enable or disable cluster mesh. | +| `cilium_show_cluster_mesh_status` | View cluster mesh status. | +| `cilium_list_bgp_peers` | View BGP peers. | +| `cilium_list_bgp_routes` | View BGP routes. | +| `cilium_get_endpoints_list` | List endpoints. | +| `cilium_get_endpoint_details` | Get endpoint details. | +| `cilium_validate_cilium_network_policies` | Validate network policies. | +| `cilium_toggle_hubble` | Enable or disable Hubble observability. | + +### Kubescape + +| Tool | Description | +|------|-------------| +| `kubescape_check_health` | Check Kubescape health status. | +| `kubescape_list_vulnerabilities` | List vulnerabilities. | +| `kubescape_get_vulnerability_details` | Get details of a specific vulnerability. | +| `kubescape_list_vulnerability_manifests` | List vulnerability manifests. | +| `kubescape_list_configuration_scans` | List configuration scans. | +| `kubescape_get_configuration_scan` | Get a specific configuration scan. | +| `kubescape_list_application_profiles` | List application profiles. | +| `kubescape_get_application_profile` | Get a specific application profile. | +| `kubescape_list_network_neighborhoods` | List network neighborhoods. | +| `kubescape_get_network_neighborhood` | Get a specific network neighborhood. | + +## kagent-grafana-mcp Tools + +A separate `kagent-grafana-mcp` MCP server (`RemoteMCPServer`) serves tools for Prometheus, Grafana, Loki, and incident management. + +### Prometheus + +| Tool | Description | +|------|-------------| +| `query_prometheus` | Execute PromQL queries. | +| `list_prometheus_metric_names` | List available metric names. | +| `list_prometheus_metric_metadata` | Get metric metadata. | +| `list_prometheus_label_names` | List available label names. | +| `list_prometheus_label_values` | List values for a specific label. | + +### Grafana + +| Tool | Description | +|------|-------------| +| `search_dashboards` | Search dashboards. | +| `update_dashboard` | Update a dashboard. | +| `get_dashboard_by_uid` | Get a dashboard by UID. | +| `get_dashboard_panel_queries` | Get panel queries from a dashboard. | +| `list_datasources` | List data sources. | +| `get_datasource` | Get a data source by name or UID. | +| `alerting_manage_rules` | Manage alert rules (list, create, update, delete). | +| `alerting_manage_routing` | Manage alerting routing, notification policies, and contact points. | + +### Loki + +| Tool | Description | +|------|-------------| +| `query_loki_logs` | Query logs via Loki. | +| `query_loki_stats` | Query Loki statistics. | +| `list_loki_label_names` | List Loki label names. | +| `list_loki_label_values` | List Loki label values. | + +### Incidents & On-Call + +| Tool | Description | +|------|-------------| +| `list_incidents` | List incidents. | +| `get_incident` | Get incident details. | +| `create_incident` | Create a new incident. | +| `add_activity_to_incident` | Add activity to an incident. | +| `list_oncall_users` | List on-call users. | +| `get_current_oncall_users` | Get current on-call users. | +| `list_oncall_schedules` | List on-call schedules. | + +## Agent Built-in Tools + +The following tools are automatically available to every agent without any configuration. + +| Tool | Description | +|------|-------------| +| `ask_user` | Pose questions to users with optional choices. | +| `SkillsTool` | Discover and load skills (Go ADK). | +| `bash` | Execute shell commands (Python ADK). | +| `read_file` | Read file contents with pagination (Python ADK). | +| `write_file` | Write file content (Python ADK). | +| `edit_file` | Edit files via string replacement (Python ADK). | + +## Configuring Tools on an Agent + +### Single MCP Server + +The following example shows how to configure an agent with a single MCP server. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: Agent +metadata: + name: k8s-agent + namespace: kagent +spec: + type: Declarative + declarative: + modelConfig: default-model-config + systemMessage: "You manage Kubernetes clusters." + tools: + - type: McpServer + mcpServer: + apiGroup: kagent.dev + name: kagent-tool-server + kind: RemoteMCPServer + toolNames: + - k8s_get_resources + - k8s_describe_resource + - k8s_get_pod_logs + - k8s_get_events +``` + +### With Tool Approval + +You can require user approval for sensitive tools by adding `requireApproval`. + +```yaml +tools: + - type: McpServer + mcpServer: + apiGroup: kagent.dev + name: kagent-tool-server + kind: RemoteMCPServer + toolNames: + - k8s_get_resources + - k8s_describe_resource + - k8s_delete_resource + - k8s_apply_manifest + requireApproval: # These tools pause for user approval + - k8s_delete_resource + - k8s_apply_manifest +``` + +### Agent as Tool (A2A) + +You can use another agent as a tool via the A2A protocol. + +```yaml +tools: + - type: Agent + agent: + name: specialist-agent +``` + +## Community / Contrib MCP Servers + +You can find additional MCP servers in `contrib/tools/`. + +| Server | Description | +|--------|-------------| +| **GitHub MCP Server** | GitHub Copilot MCP server with tools for issues, PRs, repos, actions, and more. | +| **k8sgpt MCP Server** | K8sGPT integration for AI-powered Kubernetes diagnostics. | diff --git a/docs-site/content/kagent/supported-providers/_index.md b/docs-site/content/kagent/supported-providers/_index.md new file mode 100644 index 00000000..994b1644 --- /dev/null +++ b/docs-site/content/kagent/supported-providers/_index.md @@ -0,0 +1,9 @@ +--- +title: Supported Providers +description: Learn how to configure various LLM providers like OpenAI, Azure OpenAI, Anthropic, and Ollama for kagent. +weight: 4 +author: kagent.dev +--- + +Learn how to configure various LLM providers for kagent + diff --git a/docs-site/content/kagent/supported-providers/amazon-bedrock.md b/docs-site/content/kagent/supported-providers/amazon-bedrock.md new file mode 100644 index 00000000..b71a986b --- /dev/null +++ b/docs-site/content/kagent/supported-providers/amazon-bedrock.md @@ -0,0 +1,155 @@ +--- +title: Amazon Bedrock +description: Use Amazon Bedrock models with kagent via the native Bedrock provider or the OpenAI Chat Completions API. +weight: 1 +author: kagent.dev +--- + +You can use Amazon Bedrock models with kagent in two ways: the native Bedrock provider (recommended) or the OpenAI-compatible API interface. + +## Option 1: Native Bedrock provider + +The native Bedrock provider uses the standard AWS credential chain and the Bedrock API directly. Use this option when you want the simplest configuration and full Bedrock feature support. + +On Kubernetes, the recommended setup is to use an IAM role attached to the agent's ServiceAccount, such as [EKS IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). Use static access keys only when workload identity is not available. + +### Step 1: Prepare AWS access + +1. Create an IAM user or role with permissions for Bedrock. You need at least `bedrock:InvokeModel` for the models you use. For more information, see the [AWS Bedrock model access docs](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html). + +2. Choose the AWS region and Bedrock model. Refer to the [AWS Bedrock supported models documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html). + - Example regions: `us-east-1` or `us-west-2` + - Example model IDs: `us.anthropic.claude-sonnet-4-20250514-v1:0` or `amazon.titan-text-express-v1` + +3. Choose how the agent will authenticate to AWS: + - Recommended: attach an IAM role to the agent ServiceAccount using workload identity, such as EKS IRSA. + - Alternative: create a Kubernetes secret with `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. + +If you are using access keys, create the secret in the same namespace as your agent, typically `kagent`: + +```bash +kubectl create secret generic bedrock-credentials -n kagent \ + --from-literal=AWS_ACCESS_KEY_ID= \ + --from-literal=AWS_SECRET_ACCESS_KEY= +``` + +### Step 2: Create the ModelConfig + +```yaml +kubectl apply -f - < + ``` + +4. Create a Kubernetes secret that stores your AWS API key in the same namespace as your agent, typically `kagent`. + + ```bash + kubectl create secret generic kagent-bedrock -n kagent --from-literal AWS_API_KEY=$AWS_API_KEY + ``` + +### Step 2: Create the ModelConfig + +```yaml +kubectl apply -f - <.amazonaws.com/openai/v1`. | + +## Next steps + +Now that you configured your Bedrock model, you can [create or update an agent](https://kagent.dev/docs/kagent/getting-started/first-agent) to use this model configuration. diff --git a/docs-site/content/kagent/supported-providers/anthropic.md b/docs-site/content/kagent/supported-providers/anthropic.md new file mode 100644 index 00000000..200929a9 --- /dev/null +++ b/docs-site/content/kagent/supported-providers/anthropic.md @@ -0,0 +1,40 @@ +--- +title: Anthropic +description: Learn how to configure Anthropic models for kagent. +weight: 2 +author: kagent.dev +--- + +## Configuring Anthropic + +1. Create a Kubernetes Secret that stores the API key, replace `` with an actual API key: + +```shell +export ANTHROPIC_API_KEY= +kubectl create secret generic kagent-anthropic -n kagent --from-literal ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY +``` + +2. Create a ModelConfig resource that references the secret and key name, and specify the Anthropic model you want to use: + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: claude-model-config + namespace: kagent +spec: + apiKeySecret: kagent-anthropic + apiKeySecretKey: ANTHROPIC_API_KEY + model: claude-3-sonnet-20240229 + provider: Anthropic + anthropic: {} +``` + +For Anthropic's Claude models, kagent automatically configures the appropriate model capabilities, including vision support for Claude-3 models. + +3. Apply the above resource to the cluster. + +Once the resource is applied, you can select the model from the Model dropdown in the UI when creating or updating agents. + +![Model selection](/images/modelselection.png "kagent model selection dropdown") + diff --git a/docs-site/content/kagent/supported-providers/azure-openai.md b/docs-site/content/kagent/supported-providers/azure-openai.md new file mode 100644 index 00000000..5317818e --- /dev/null +++ b/docs-site/content/kagent/supported-providers/azure-openai.md @@ -0,0 +1,41 @@ +--- +title: Azure OpenAI +description: Learn how to configure Azure OpenAI models in kagent. +weight: 3 +author: kagent.dev +--- + +## Configuring Azure OpenAI + +1. Create a Kubernetes Secret that stores the API key, replace `` with an actual API key: + +```shell +export AZURE_OPENAI_API_KEY= +kubectl create secret generic kagent-azureopenai -n kagent --from-literal AZURE_OPENAI_API_KEY=$AZURE_OPENAI_API_KEY +``` + +2. Create a ModelConfig resource that references the secret and key name, and specify the additional information that's required for the Azure OpenAI - that's the deployment name, version and the Azure AD token. You can get these values from Azure. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: azuredefault-model-config + namespace: kagent +spec: + apiKeySecret: kagent-azureopenai + apiKeySecretKey: AZURE_OPENAI_API_KEY + model: gpt-4o-mini + provider: AzureOpenAI + azureOpenAI: + azureEndpoint: "https://{yourendpointname}.openai.azure.com/" + apiVersion: "2025-03-01-preview" + azureDeployment: "gpt-4o-mini" + azureAdToken: +``` + +For Azure OpenAI's standard models, kagent automatically configures the appropriate model capabilities. + +3. Apply the above resource to the cluster. + +Once the resource is applied, you can select the model from the Model dropdown in the UI when creating or updating agents. diff --git a/docs-site/content/kagent/supported-providers/byo-openai.md b/docs-site/content/kagent/supported-providers/byo-openai.md new file mode 100644 index 00000000..52f52de4 --- /dev/null +++ b/docs-site/content/kagent/supported-providers/byo-openai.md @@ -0,0 +1,122 @@ +--- +title: BYO OpenAI-compatible model +description: Bring your own OpenAI-compatible model to kagent. +weight: 8 +author: kagent.dev +--- + +You can bring your own model from an [OpenAI API-compatible](https://platform.openai.com/docs/api-reference/introduction) LLM provider. The example integrates with [Cohere AI](https://cohere.com/). + +1. Save your API key from the OpenAI-compatible provider as an environment variable. For example, navigate to the [Cohere AI dashboard](https://dashboard.cohere.com/api-keys). + + ```bash + export PROVIDER_API_KEY=Dgs... + ``` + +2. Create a Kubernetes secret that stores your API key. Make sure to create the secret in the same namespace as you plan to create your agent, such as `kagent`. + + ```bash + kubectl create secret generic kagent-my-provider -n kagent --from-literal PROVIDER_API_KEY=$PROVIDER_API_KEY + ``` + +3. Create a ModelConfig resource. + + ```yaml + kubectl apply -f - < **Note:** TLS configuration only supports OpenAI-compatible providers. + +### Use Case: Custom CA Certificates + +Configure the CA certificate of your LLM server in the `ModelConfig` resource. + +1. Create a `Secret` with the relevant CA certificate in the same namespace as the `ModelConfig`. + + ```bash + kubectl -n kagent create secret generic llm-certs \ + --from-file=ca.crt=ca.crt + ``` + +2. Create a `ModelConfig` resource with TLS configuration that references the CA certificate `Secret`. + + ```yaml + apiVersion: kagent.dev/v1alpha2 + kind: ModelConfig + metadata: + name: internal-llm-model-config + namespace: kagent + spec: + apiKeySecret: kagent-my-provider + apiKeySecretKey: ${PROVIDER_API_KEY} + provider: OpenAI + model: ${MODEL_NAME} + openAI: + baseUrl: ${COMPATIBLE_PROVIDER_URL} + tls: + caCertSecretRef: llm-certs + caCertSecretKey: ca.crt + ``` + +### Use Case: Insecure Communication + +> **Warning:** Insecure communication is for **demo purposes only**. Do not use insecure communication in production environments. + +For development or testing scenarios where you need to disable TLS verification, configure the `ModelConfig` to skip certificate verification. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: internal-llm-model-config + namespace: kagent +spec: + apiKeySecret: kagent-my-provider + apiKeySecretKey: ${PROVIDER_API_KEY} + provider: OpenAI + model: ${MODEL_NAME} + openAI: + baseUrl: ${COMPATIBLE_PROVIDER_URL} + tls: + disableVerify: true +``` + +### TLS Configuration Settings + +Review the following table to understand the TLS configuration options. For more information, see the [API docs](https://kagent.dev/docs/kagent/resources/api-ref#modelconfigspec). + +| Setting | Description | +| --- | --- | +| `tls.caCertSecretRef` | The name of the Kubernetes secret that contains the CA certificate. The secret must be in the same namespace as the `ModelConfig`. | +| `tls.caCertSecretKey` | The key in the secret that stores the CA certificate file. | +| `tls.disableVerify` | When set to `true`, disables TLS certificate verification. **Warning:** Only use this for demo purposes, not in production. | diff --git a/docs-site/content/kagent/supported-providers/gemini.md b/docs-site/content/kagent/supported-providers/gemini.md new file mode 100644 index 00000000..7f0e93a3 --- /dev/null +++ b/docs-site/content/kagent/supported-providers/gemini.md @@ -0,0 +1,44 @@ +--- +title: Gemini +description: Learn how to configure Gemini models in kagent. +weight: 4 +author: kagent.dev +--- + +Gemini is Google's AI model family that can be accessed directly through the Google AI Studio API. + +## Before you begin + +Make sure that your Google Cloud account has a project with the Gemini API enabled. + +## Configuring Gemini + +1. Get your API key from [Google AI Studio](https://ai.google.dev/). + +2. Create a Kubernetes Secret that stores the API key. + + ```shell + kubectl create secret generic kagent-gemini -n kagent --from-literal GOOGLE_API_KEY= + ``` + +3. Create a ModelConfig resource using the `Gemini` provider. + +You can find out the latest model names and capabilities on the [Gemini API docs](https://ai.google.dev/gemini-api/docs/models). Once you have chosen a model, replace the `model` field with the name such as `gemini-2.5-pro`. + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: gemini-model-config + namespace: kagent +spec: + apiKeySecret: kagent-gemini + apiKeySecretKey: GOOGLE_API_KEY + model: gemini-2.5-flash + provider: Gemini + gemini: {} +``` + +4. Apply the above resource to the cluster. + +Once the resource is applied, you can select the model from the Model dropdown in the UI when creating or updating agents. diff --git a/docs-site/content/kagent/supported-providers/google-vertexai.md b/docs-site/content/kagent/supported-providers/google-vertexai.md new file mode 100644 index 00000000..b5b186c0 --- /dev/null +++ b/docs-site/content/kagent/supported-providers/google-vertexai.md @@ -0,0 +1,53 @@ +--- +title: Google Vertex AI +description: Learn how to configure Google Vertex AI models in kagent. +weight: 5 +author: kagent.dev +--- + +## Configuring Google Vertex AI + +Google Vertex AI is supported for Gemini and Anthropic models. + +1. Create the [Google Application Default Credentials file](https://cloud.google.com/docs/authentication/provide-credentials-adc) and store it in a Kubernetes Secret. If your credentials are in a different location, update the filepath. + +```shell +kubectl create secret generic kagent-google-creds -n kagent --from-file=~/.config/gcloud/application_default_credentials.json +``` + +2. For Gemini models: create a ModelConfig resource using the `GeminiVertexAI` provider that references the secret and key name, and specify the Gemini model you want to use. Note the `projectID` and `location` are required: + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: gemini-model-config-vertexai + namespace: kagent +spec: + apiKeySecret: kagent-google-creds + apiKeySecretKey: google_creds.json + model: gemini-2.0-flash-lite + provider: GeminiVertexAI + geminiVertexAI: + projectID: kagent-dev + location: us-west1 + maxOutputTokens: 1000 +``` + +3. For Anthropic models: create a ModelConfig resource using the `AnthropicVertexAI` provider that references the secret and key name, and specify the Anthropic model you want to use. Note the `projectID` and `location` are required: + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: anthropic-model-config-vertexai + namespace: kagent +spec: + apiKeySecret: kagent-google-creds + apiKeySecretKey: google_creds.json + model: claude-sonnet-4@20250514 + provider: AnthropicVertexAI + anthropicVertexAI: + projectID: kagent-dev + location: us-east5 +``` diff --git a/docs-site/content/kagent/supported-providers/ollama.md b/docs-site/content/kagent/supported-providers/ollama.md new file mode 100644 index 00000000..d59c98c7 --- /dev/null +++ b/docs-site/content/kagent/supported-providers/ollama.md @@ -0,0 +1,82 @@ +--- +title: Ollama +description: Learn how to configure Ollama models in kagent. +weight: 6 +author: kagent.dev +--- + +## Configuring Ollama + +[Ollama](https://ollama.com) allows you to run LLMs locally on your computer or in a Kubernetes cluster. Configuring Ollama in kagent follows the same pattern as for other providers. + +Let's give an example of how to run Ollama on a Kubernetes cluster: + +1. Create a namespace for Ollama deployment and service: + +```shell +kubectl create ns ollama +``` + +2. Create the deployment and service: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ollama + namespace: ollama +spec: + selector: + matchLabels: + name: ollama + template: + metadata: + labels: + name: ollama + spec: + containers: + - name: ollama + image: ollama/ollama:latest + ports: + - name: http + containerPort: 11434 + protocol: TCP +--- +apiVersion: v1 +kind: Service +metadata: + name: ollama + namespace: ollama +spec: + type: ClusterIP + selector: + name: ollama + ports: + - port: 80 + name: http + targetPort: http + protocol: TCP +``` + +You can run `kubectl get pod -n ollama` and wait until the pod has started. + +Once the pod has started, you can port-forward to the Ollama service and use `ollama run [model-name]` to download/run the model. You can download Ollama binary [here](https://ollama.com/download/). + +>As kagent relies on calling tools, make sure you're using a model that allows function calling. + +Let's assume we've downloaded the `llama3` model, you can then use the following ModelConfig to configure the model: + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: llama3-model-config + namespace: kagent +spec: + apiKeySecretKey: OPENAI_API_KEY + apiKeySecret: kagent-openai + model: llama3 + provider: Ollama + ollama: + host: http://ollama.ollama.svc.cluster.local +``` diff --git a/docs-site/content/kagent/supported-providers/openai.md b/docs-site/content/kagent/supported-providers/openai.md new file mode 100644 index 00000000..d695db4f --- /dev/null +++ b/docs-site/content/kagent/supported-providers/openai.md @@ -0,0 +1,37 @@ +--- +title: OpenAI +description: Learn how to configure OpenAI models in kagent. +weight: 7 +author: kagent.dev +--- + +## Configuring OpenAI + +1. Create a Kubernetes Secret that stores the API key, replace `` with an actual API key: + +```shell +export OPENAI_API_KEY= +kubectl create secret generic kagent-openai -n kagent --from-literal OPENAI_API_KEY=$OPENAI_API_KEY +``` + +2. Create a ModelConfig resource that references the secret and key name: + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: default-model-config + namespace: kagent +spec: + apiKeySecret: kagent-openai + apiKeySecretKey: OPENAI_API_KEY + model: gpt-4o-mini + provider: OpenAI + openAI: {} +``` + +For OpenAI's standard models like GPT-4 and GPT-3.5, kagent automatically configures the appropriate model capabilities. + +3. Apply the above resource to the cluster. + +Once the resource is applied, you can select the model from the Model dropdown in the UI when creating or updating agents. diff --git a/docs-site/content/kagent/supported-providers/sap-ai-core.md b/docs-site/content/kagent/supported-providers/sap-ai-core.md new file mode 100644 index 00000000..7e193097 --- /dev/null +++ b/docs-site/content/kagent/supported-providers/sap-ai-core.md @@ -0,0 +1,52 @@ +--- +title: SAP AI Core +description: Learn how to configure SAP AI Core models for kagent. +author: kagent.dev +--- + +## Configuring SAP AI Core + +kagent connects to SAP AI Core through its [Orchestration Service](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/orchestration), which provides a unified endpoint for models from multiple families, including Anthropic, OpenAI, Gemini, Amazon, Meta, and Mistral. Authentication uses OAuth2 client credentials from your SAP AI Core service key. + +1. Create a Kubernetes Secret that stores the OAuth2 client credentials. The Secret must contain two keys, `client_id` and `client_secret`. Replace the placeholder values with the credentials from your SAP AI Core service key. + + ```shell + export SAP_AI_CORE_CLIENT_ID= + export SAP_AI_CORE_CLIENT_SECRET= + kubectl create secret generic kagent-sapaicore -n kagent \ + --from-literal client_id=$SAP_AI_CORE_CLIENT_ID \ + --from-literal client_secret=$SAP_AI_CORE_CLIENT_SECRET + ``` + + Unlike other providers, the `apiKeySecretKey` field on the `ModelConfig` is not used for SAP AI Core. The keys `client_id` and `client_secret` are read directly from the Secret. + +2. Create a `ModelConfig` resource that references the Secret and specifies the SAP AI Core endpoint, resource group, and OAuth2 token endpoint. You can find these values in your SAP AI Core service key. + + ```yaml + kubectl apply -f - <.authentication.eu10.hana.ondemand.com" + resourceGroup: "default" + EOF + ``` + + | Field | Required | Description | + | --- | --- | --- | + | `apiKeySecret` | Yes | Name of the secret that contains the OAuth2 client credentials. | + | `model` | Yes | Model names follow the Orchestration Service naming convention, such as `anthropic--claude-4.6-sonnet`, `gpt-5-mini`, or `gemini-3-pro-preview`. For the full list of supported models, see the [SAP AI Core Orchestration Service documentation](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/models-and-scenarios-in-generative-ai-hub). | + | `provider` | Yes | Provider name. Must be `SAPAICore`. | + | `sapAICore.baseUrl` | Yes | Base URL for the SAP AI Core API. | + | `sapAICore.authUrl` | No | OAuth2 token endpoint URL. | + | `sapAICore.resourceGroup` | No | Resource group in SAP AI Core. Defaults to `default`. | + +After the resource is applied, you can select the model from the **Model** dropdown in the UI when creating or updating agents. diff --git a/docs-site/content/kagent/supported-providers/xai.md b/docs-site/content/kagent/supported-providers/xai.md new file mode 100644 index 00000000..cb65d504 --- /dev/null +++ b/docs-site/content/kagent/supported-providers/xai.md @@ -0,0 +1,40 @@ +--- +title: xAI (Grok) +description: Learn how to configure xAI Grok models for kagent. +weight: 9 +author: kagent.dev +--- + +## Configuring xAI (Grok) + +xAI's Grok models are OpenAI-compatible, so you can use the BYO OpenAI-compatible provider configuration. + +1. Create a Kubernetes Secret that stores the API key, replace `` with an actual xAI API key: + +```shell +export XAI_API_KEY= +kubectl create secret generic kagent-xai -n kagent --from-literal XAI_API_KEY=$XAI_API_KEY +``` + +2. Create a ModelConfig resource that references the secret and specifies the xAI base URL and Grok model: + +```yaml +apiVersion: kagent.dev/v1alpha2 +kind: ModelConfig +metadata: + name: grok-model-config + namespace: kagent +spec: + apiKeySecret: kagent-xai + apiKeySecretKey: XAI_API_KEY + model: grok-3 + provider: OpenAI + openAI: + baseURL: https://api.x.ai/v1 +``` + +3. Apply the above resource to the cluster. + +Once the resource is applied, you can select the model from the Model dropdown in the UI when creating or updating agents. + +![Model selection](/images/modelselection.png "kagent model selection dropdown") diff --git a/docs-site/content/kmcp/_index.md b/docs-site/content/kmcp/_index.md new file mode 100644 index 00000000..d371fed1 --- /dev/null +++ b/docs-site/content/kmcp/_index.md @@ -0,0 +1,10 @@ +--- +title: kmcp +weight: 1 +author: kagent.dev +--- + +Accelerate local development of Model Context Protocol (MCP) servers and manage their deployment to cloud-native environments. + +[Get Started](/docs/kmcp/quickstart) + diff --git a/docs-site/content/kmcp/deploy/_index.md b/docs-site/content/kmcp/deploy/_index.md new file mode 100644 index 00000000..84d92e3f --- /dev/null +++ b/docs-site/content/kmcp/deploy/_index.md @@ -0,0 +1,9 @@ +--- +title: Deploy to Kubernetes +description: Quickly develop and deploy Model Context Protocol (MCP) servers. +weight: 40 +author: kagent.dev +--- + +Use the kmcp controller to manage the lifecycle of your MCP servers in a Kubernetes environment. + diff --git a/docs-site/content/kmcp/deploy/install-controller.md b/docs-site/content/kmcp/deploy/install-controller.md new file mode 100644 index 00000000..5f32cc5c --- /dev/null +++ b/docs-site/content/kmcp/deploy/install-controller.md @@ -0,0 +1,76 @@ +--- +title: Install the kmcp controller +description: Deploy the kmcp controller in a Kubernetes cluster. +weight: 10 +author: kagent.dev +--- + +The kmcp controller manages the lifecycle of MCP servers that are defined in an MCPServer custom resource. + +## Prerequisites + +- [Kind](https://kind.sigs.k8s.io) for creating and running a local Kubernetes cluster +- [Docker](https://docs.docker.com/desktop/) for running local kind clusters +- [Helm](https://helm.sh/docs/intro/install/) for installing the kmcp controller chart + +## Install the controller + +1. Create a kind cluster. + + **Tip**: If you already have a Kubernetes cluster that you want to use, switch to the kubeconfig context for that cluster by using the `kubectl config use-context [CONTEXT-NAME]` command. + ```sh + kind create cluster + ``` + +2. Install the kmcp CRDs. + + ```sh + helm install kmcp-crds oci://ghcr.io/kagent-dev/kmcp/helm/kmcp-crds \ + --namespace kmcp-system \ + --create-namespace + ``` + +3. Install the following kmcp controller components in your cluster. + * The MCPServer Custom Resource Definition to define your MCP server. + * The ClusterRole and ClusterRoleBinding to control RBAC permissions for the kmcp controller. + * The kmcp controller deployment that automatically manages the lifecycle of MCPServer resources. + + ```sh + kmcp install + ``` + + Example output: + ```sh + 🚀 Deploying KMCP controller to cluster... + No version specified, using latest: v{{< reuse "versions/kmcp.md" >}} + Release "kmcp" does not exist. Installing it now. + NAME: kmcp + LAST DEPLOYED: Wed Jul 30 18:41:01 2025 + NAMESPACE: kmcp-system + STATUS: deployed + REVISION: 1 + TEST SUITE: None + ✅ KMCP controller deployed successfully + 💡 Check controller status with: kubectl get pods -n kmcp-system + 💡 View controller logs with: kubectl logs -l app.kubernetes.io/name=kmcp -n kmcp-system + ``` + +4. Verify that the kmcp controller manager is up and running. + ```sh + kubectl get pods -n kmcp-system + ``` + + Example output: + ```sh + NAME READY STATUS RESTARTS AGE + kmcp-controller-manager-66c8764c66-8h5sl 1/1 Running 0 27h + ``` + +5. Optional: Look at the logs of the kmcp controller manager. + ```sh + kubectl logs -l app.kubernetes.io/name=kmcp -n kmcp-system + ``` + +## Next + +[Deploy your MCP servers](/docs/kmcp/deploy/server) to your cluster and manage their lifecycle. \ No newline at end of file diff --git a/docs-site/content/kmcp/deploy/server.md b/docs-site/content/kmcp/deploy/server.md new file mode 100644 index 00000000..1f8c3f47 --- /dev/null +++ b/docs-site/content/kmcp/deploy/server.md @@ -0,0 +1,191 @@ +--- +title: Deploy MCP servers +description: Deploy MCP servers using kmcp +weight: 20 +author: kagent.dev +--- + +Use the kmcp controller to automatically spin up your MCP server in a Kubernetes environment. + +## Prerequisites + +- Create a [FastMCP](/docs/kmcp/develop/fastmcp-python) or [MCP Go](/docs/kmcp/develop/mcp-go) project with a sample MCP server and tool. +- [Install the KMCP controller](/docs/kmcp/deploy/install-controller) in a local kind cluster to manage the lifecycle of MCP servers in your cluster. + +## Deploy the MCP server + +Learn how you can deploy an MCP server in a Kubernetes cluster. Choose between the following options: + +* [Option 1: Deploy an MCP server with `npx` or `uvx`](#option-1-deploy-an-mcp-server-with-npx-or-uvx): Use an existing npm package to spin up an MCP server instance with `npx` or `uvx`. +* [Option 2: Build and deploy an MCP server](#option-2-build-and-deploy-an-mcp-server): Build a Docker image for your MCP server project. Then, load this image to your Kubernetes cluster and deploy an MCP server from it. + +### Option 1: Deploy an MCP server with `npx` or `uvx` + +Deploy an instance of the [`server-everything`](https://github.com/modelcontextprotocol/servers/tree/main/src/everything) MCP server by using the `npx` or `uvx` command. This server provides simple tools, such as an echo tool, that you can use for testing. +Choose between using the kmcp CLI or creating the MCPServer resource yourself. + +{{< tabs >}} +{{< tab name="kmcp CLI" >}} +1. Deploy the MCP server. + ```sh + kmcp deploy package --deployment-name my-mcp-server \ + --manager npx --args @modelcontextprotocol/server-everything + ``` + 2. Verify that the MCP server is up and running. + ```sh + kubectl get pods + ``` + + Example output: + ```sh + NAME READY STATUS RESTARTS AGE + my-mcp-server-669bcb5d6f-zv5dn 1/1 Running 0 27h + ``` +{{< /tab >}} +{{< tab name="MCPServer resource" >}} +1. Create the MCPServer resource. + ```yaml + kubectl apply -f- <}} +{{< /tabs >}} + + +### Option 2: Build and deploy an MCP server + +Learn how to use the kmcp CLI to build an image for your MCP server and to deploy the server to your Kubernetes cluster. +The following example assumes that you created a [FastMCP](/docs/kmcp/develop/fastmcp-python) or [MCP Go](/docs/kmcp/develop/mcp-go) project with a sample MCP server and tool, and that your kind cluster is named `kind`. + +1. Build a Docker image for your MCP server and load it to your kind cluster. + ```sh + kmcp build --project-dir my-mcp-server -t my-mcp-server:latest --kind-load-cluster kind + ``` + +2. Deploy your MCP server. Choose between the kmcp CLI or manually creating an MCPServer resource. + + > **Note**: Planning to use your kmcp resources later with kagent and agentgateway? Add the `kagent.dev/discovery=disabled` label to your MCPServer resource. Then, kagent does not automatically discover MCP servers. This way, you can have agentgateway in front of your kmcp servers so that the agent-tool traffic is routed correctly through agentgateway. + +{{< tabs >}} +{{< tab name="kmcp CLI" >}} +The `kmcp deploy` command automatically creates an MCPServer resource in your cluster that contains the MCP server configuration that is defined in the `kmcp.yaml` file in your MCP project. The kmcp controller then uses this resource to spin up and manage the lifecycle of your MCP server. After the MCP server is deployed, the command automatically starts the MCP inspector tool so that you can test your server. + + **Tip**: If you do not want to start the MCP inspector tool, add the `--no-inspector` flag to the command. + + ```sh + kmcp deploy --file my-mcp-server/kmcp.yaml --image my-mcp-server:latest + ``` +{{< /tab >}} +{{< tab name="MCPServer resource" >}} +You can manually create an MCPServer resource yourself as shown in the following examples. + + * FastMCP example + ```yaml + kubectl apply -f- <}} +{{< /tabs >}} + + +3. Verify that the MCP server is up and running. + ```sh + kubectl get pods + ``` + + Example output: + ```sh + NAME READY STATUS RESTARTS AGE + my-mcp-server-669bcb5d6f-zv5dn 1/1 Running 0 27h + ``` + +## Test access to the MCP server + +1. Run the MCP inspector tool. Note that if you used the `kmcp deploy` command to spin up your MCP server, the MCP inspector tool is already running. You can skip to the next step. + 1. Port-forward the MCP server that you deployed. + ```sh + kubectl port-forward deploy/my-mcp-server 3000 + ``` + + 2. Run the MCP inspector tool. In your CLI output, find the URL that the MCP inspector tool is exposed on. + ```sh + npx @modelcontextprotocol/inspector + ``` + + Example output: + ```sh + 🚀 MCP Inspector is up and running at: + http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=8aca1a7088efc984e433fd750ed042b1881fbda3734282e3f0e524b00fc3e69f + ``` + +2. In your MCP inspector tool, click **Connect** to connect to your MCP server. Note that it might take a few seconds for the MCP inspector tool to successfully connect to your MCP server. If the connection fails, make sure the following fields are set in the MCP inspector tool. + * Select **Streamable HTTP** from the **Transport Type** drop down. + * Enter `http://127.0.0.1:3000/mcp` in the **URL** field. + * Expand the **Configuration** section and make sure that the **Proxy Session Token** is set to the value of the `PROXY_AUTH_TOKEN` that was shown in the CLI output when you opened the MCP inspector tool. + + ![MCP inspector UI for FastMCP](/images/kmcp-inspector-ov.png "Connect to FastMCP server with MCP inspector tool") + +4. Try out the built-in `echo` MCP tool. + 1. Go to the **Tools** tab and click **List Tools**. + 2. Select the `echo` tool. + 3. Enter any string in the **message** field, such as `Hello world` and click **Run Tool**. + 4. Verify that you see your message echoed in the **Tool result** card. + + ![Run echo tool in MCP inspector UI](/images/kmcp-inspector-echo-success.png "Successful run of the echo tool") + +## Next + +Learn how to [manage secrets for your MCP servers](/docs/kmcp/secrets). + + diff --git a/docs-site/content/kmcp/develop/_index.md b/docs-site/content/kmcp/develop/_index.md new file mode 100644 index 00000000..4a754a6a --- /dev/null +++ b/docs-site/content/kmcp/develop/_index.md @@ -0,0 +1,9 @@ +--- +title: Develop MCP servers +description: Quickly develop and deploy Model Context Protocol (MCP) servers. +weight: 30 +author: kagent.dev +--- + +Use kmcp to quickly create and initialize an MCP project on your local machine. kmcp automatically generates all the necessary files and dependencies so that you can get started with developing your MCP server and tools. + diff --git a/docs-site/content/kmcp/develop/fastmcp-python.md b/docs-site/content/kmcp/develop/fastmcp-python.md new file mode 100644 index 00000000..7d7130e1 --- /dev/null +++ b/docs-site/content/kmcp/develop/fastmcp-python.md @@ -0,0 +1,98 @@ +--- +title: FastMCP Python +description: Create the MCP server with kmcp +weight: 10 +author: kagent.dev +--- + +[FastMCP Python](https://github.com/jlowin/fastmcp) is a lightweight, high-performance Python framework that implements the Model Context Protocol (MCP). With KMCP, you can quickly create an MCP project that uses the FastMCP framework with a sample MCP server and `echo` tool that you can use as a boilerplate to develop your own tools. + +## Prerequisites + +- Install [uv](https://docs.astral.sh/uv/getting-started/installation/) to build and run FastMCP servers. +- Install the MCP inspector tool to access and test your MCP server. + ```sh + npx @modelcontextprotocol/inspector + ``` + +## Create the MCP project + +1. Create a scaffold for your FastMCP server project. + + The following command creates an MCP server +in the `my-mcp-server` directory and a sample echo tool that you can later use to test your server. Follow the interactive CLI prompts to optionally add a description and author for your project. + + ```sh + kmcp init python my-mcp-server + ``` + +2. Review the project structure that was created for you. + ```sh + find my-mcp-server + ``` + + Example project structure: + ```sh + ├── src/ + | ├── core/ # MCP server code and utilities + │ ├── tools/ # Tool implementations + │ └── main.py # MCP server entry point + ├── tests/ # Built-in test suite + ├── Dockerfile # Dockerfile for spinning up your MCP server in a Kubernetes environment + ├── kmcp.yaml # MCP container definition for spinning up your MCP server + ├── pyproject.toml # Python dependencies + ├── .env.example # Sample environment variables file for your MCP server + └── README.md # MCP Project documentation + ``` + +## Add tools + +1. Create a boilerplate for an MCP tool in the `src/tools` directory of your MCP project. + + The boilerplate includes code for an echo tool that is similar to the `my-mcp-server/src/tools/echo.py` tool that is automatically created when you initialize the project. You can use the boilerplate as a base to create your own tools. + ```sh + kmcp add-tool mytool --project-dir my-mcp-server + ``` + +2. Review the code for the `mytool` tool. + ```sh + cat my-mcp-server/src/tools/mytool.py + ``` + +3. Make changes to the `mytool.py` tool to implement your own tool logic. + +## Run locally + +Use the `kmcp run` command to run your MCP server on your local machine so that you can test your MCP server and tools. + +1. Run your MCP server on your local machine. The command builds the Docker image for your MCP server and automatically opens the MCP inspector tool so that you can connect to your MCP server and test it. + + **Tip**: The following command automatically opens the MCP inspector tool so that you can test your MCP server. If you do not want to open the MCP inspector tool, add the `--no-inspector` option to your command. + ```sh + kmcp run --project-dir my-mcp-server + ``` + +2. In the MCP inspector tool, click **Connect** to connect to your MCP server. Note that it might take a few seconds for the MCP inspector tool to successfully connect to your MCP server. If the connection fails, make sure the following fields are set in the MCP inspector tool. + * Select **STDIO** from the **Transport Type** drop down. + * In the **Command** section, enter `uv`. + * In the **Arguments** section, enter `run python src/main.py`. + * In the **Configuration** section, enter the **Proxy Session Token** that was returned in the `kmcp run` command. + + ![Locally run the MCP server](/images/kmcp-local-inspector-ov.png "Locally run your MCP server with the MCP inspector tool") + +3. Try out the `mytool` MCP tool. + 1. Go to the **Tools** tab and click **List Tools**. + 2. Select the `mytool` tool. + 3. Enter any string in the **message** field, such as `Hello world` and click **Run Tool**. + 4. Verify that you see your message echoed in the **Tool result** card. + + ![Run mytool tool in MCP inspector UI](/images/kmcp-local-mytool-success.png "Successful run of the mytool tool") + + + +## Next + +* Explore other MCP frameworks, such as [MCP Go](/docs/kmcp/develop/mcp-go). +* [Deploy your MCP server to a Kubernetes cluster](/docs/kmcp/deploy). +* Learn how to [manage secrets for your MCP server](/docs/kmcp/secrets). + diff --git a/docs-site/content/kmcp/develop/mcp-go.md b/docs-site/content/kmcp/develop/mcp-go.md new file mode 100644 index 00000000..4ff2ad6a --- /dev/null +++ b/docs-site/content/kmcp/develop/mcp-go.md @@ -0,0 +1,98 @@ +--- +title: MCP Go +description: Create the Go MCP server with kmcp. +weight: 10 +author: kagent.dev +--- + +[MCP Go](https://github.com/modelcontextprotocol/go-sdk) uses the native Go SDK to implement the Model Context Protocol (MCP). The framework provides type-safe tool definitions and is best suited for high-throughput and high-performance services, system-level integrations, and performance-critical applications. + +## Prerequisites + +- Install [go](https://go.dev/doc/install) version 1.23 or later. +- Install the MCP inspector tool to access and test your MCP server. + ```sh + npx @modelcontextprotocol/inspector + ``` + +## Create the MCP project + +1. Create a scaffold for your MCP Go server project. + + The following command creates an MCP server +in the `my-mcp-server` directory and a sample echo tool that you can later use to test your server. Follow the interactive CLI prompts to optionaly add a description and author for your project. + + ```sh + kmcp init go my-mcp-server --go-module-name my-mcp-server + ``` + +2. Review the project structure that was created for you. + ```sh + find my-mcp-server + ``` + + Example project structure: + ```sh + my-mcp-server/ + ├── main.go # Server entry point + ├── go.mod # Go module definition + ├── go.sum # Dependency checksums + ├── tools/ # Tool implementations + │ ├── all_tools.go # Tool registration + │ ├── echo.go # Example tool + │ └── tool.go # Tool template + ├── Dockerfile # Container definition + ├── .gitignore # Git ignore rules + ├── kmcp.yaml # Project configuration + └── README.md # Project documentation + ``` + +## Add tools + +1. Create a boilerplate for an MCP tool that is named `mytool`. The following command creates the `mytool.go` tool in the `tools` directory of your MCP project. + + The boilerplate includes code for an echo tool that is similar to the `my-mcp-server/tools/echo.go` tool that is automatically created when you initialize the project. You can use the boilerplate as a base to create your own tools. + ```sh + kmcp add-tool mytool --project-dir my-mcp-server + ``` + +2. Review the code for the `mytool` tool. + ```sh + cat my-mcp-server/tools/mytool.go + ``` + +3. Make changes to the `mytool.go` tool to implement your own tool logic. + +## Run locally + +Use the `kmcp run` command to run your MCP server on your local machine so that you can test your MCP server and tools. + +1. Run your MCP server on your local machine. The command builds the Docker image for your MCP server and automatically opens the MCP inspector tool so that you can connect to your MCP server and test it. + + **Tip**: The following command automatically opens the MCP inspector tool so that you can test your MCP server. If you do not want to open the MCP inspector tool, add the `--no-inspector` option to your command. + ```sh + kmcp run --project-dir my-mcp-server + ``` + +2. In the MCP inspector tool, click **Connect** to connect to your MCP server. Note that it might take a few seconds for the MCP inspector tool to successfully connect to your MCP server. If the connection fails, make sure the following fields are set in the MCP inspector tool. + * Select **STDIO** from the **Transport Type** drop down. + * In the **Command** section, enter `go`. + * In the **Arguments** section, enter `run main.go`. + * In the **Configuration** section, enter the **Proxy Session Token** that was returned in the `kmcp run` command. + + ![Locally run the MCP server](/images/kmcp-local-inspector-go-ov.png "Locally run your MCP server with the MCP inspector tool") + +3. Try out the `mytool` MCP tool. + 1. Go to the **Tools** tab and click **List Tools**. + 2. Select the `mytool` tool. + 3. Enter any string in the **message** field, such as `Hello world` and click **Run Tool**. + 4. Verify that you see your message echoed in the **Tool result** card. + + ![Run mytool tool in MCP inspector UI](/images/kmcp-local-go-mytool-success.png "Successful run of the mytool tool") + + +## Next + +* Explore other MCP frameworks, such as [FastMCP Python](/docs/kmcp/develop/fastmcp-python). +* [Deploy your MCP server to a Kubernetes cluster](/docs/kmcp/deploy). +* Learn how to [manage secrets for your MCP server](/docs/kmcp/secrets). \ No newline at end of file diff --git a/docs-site/content/kmcp/introduction.md b/docs-site/content/kmcp/introduction.md new file mode 100644 index 00000000..ff21e5ab --- /dev/null +++ b/docs-site/content/kmcp/introduction.md @@ -0,0 +1,22 @@ +--- +title: Introduction +description: Quickly develop and deploy Model Context Protocol (MCP) servers. +weight: 10 +--- + +kmcp is a comprehensive platform to accelerate the local development of Model Context Protocol (MCP) servers and manage their lifecycle in cloud-native environments, such as Kubernetes. + +## About MCP + +[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol developed by Anthropic that standardizes how Large Language Model (LLM) applications connect to various external data sources and tools. Without MCP, you need to implement custom integrations for each tool that your LLM application needs to access. However, this approach is hard to maintain and can cause issues when you want to scale your environment. With MCP, you can significantly speed up, simplify, and standardize these types of integrations. An MCP server exposes external data sources and tools so that LLM applications can access them. + +## What is kmcp? + +kmcp provides a powerful CLI tool with built-in boilerplates to speed up the local development of MCP servers and MCP tools. Once developed, you can leverage the kmcp control plane to quickly spin up and deploy your MCP servers in your cloud-native environment, such as Kubernetes. + +With kmcp, you can: +* Quickly initialize an MCP project for various MCP frameworks that follows industry best practices for developing MCP servers and tools. +* Access built-in boilerplates to accelerate the development and deployment of MCP tools. +* Automatically manage the lifecycle of MCP servers in cloud-native environments, such as Kubernetes. +* Manage secrets for MCP servers in Kubernetes. + diff --git a/docs-site/content/kmcp/quickstart.md b/docs-site/content/kmcp/quickstart.md new file mode 100644 index 00000000..441f4b3e --- /dev/null +++ b/docs-site/content/kmcp/quickstart.md @@ -0,0 +1,169 @@ +--- +title: Quickstart +description: Get started with kmcp +weight: 20 +--- + +Install the kmcp CLI and quickly spin up your first FastMCP Python server in a Kubernetes cluster. + +## Prerequisites + +- [Docker](https://docs.docker.com/desktop/) for building your MCP server images locally +- [Kind](https://kind.sigs.k8s.io) for creating and running a local Kubernetes cluster +- [Helm](https://helm.sh/docs/intro/install/) for installing the kmcp chart +- [uv](https://docs.astral.sh/uv/getting-started/installation/) for running FastMCP servers +- MCP Inspector tool to test access to your MCP server + ```sh + npm install -g @modelcontextprotocol/inspector + ``` + +## Install the kmcp CLI + +1. Install the kmcp CLI on your local machine. + ```sh + curl -fsSL https://raw.githubusercontent.com/kagent-dev/kmcp/refs/heads/main/scripts/get-kmcp.sh | bash + ``` + +2. Verify that the kmcp CLI is installed. + ```sh + kmcp --help + ``` + +## Spin up your first MCP server + +1. Create a scaffold for your FastMCP Python server project in the `my-mcp-server` directory. The scaffold includes all the files and dependencies to spin up the MCP server with a sample `echo` tool. + + **Tip:** Want to use a different MCP framework instead? Try out [MCP Go](/docs/kmcp/develop/mcp-go). + + ```sh + kmcp init python my-mcp-server + ``` + +2. Run your MCP server on your local machine. The command builds the Docker image for your MCP server and automatically opens the MCP inspector tool so that you can connect to your MCP server and test it. + + ```sh + kmcp run --project-dir my-mcp-server + ``` + + Example output: + ```sh + Starting MCP inspector... + ⚙️ Proxy server listening on localhost:6277 + 🔑 Session token: 39359f4867a366abc8ecdf5daa243d547d4f61a43e207cc1adbdc23ae47550f8 + Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth + + 🚀 MCP Inspector is up and running at: + http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=39359f4867a366abc8ecdf5daa243d547d4f61a43e207cc1adbdc23ae47550f8 + ``` + +3. In the MCP inspector tool, click **Connect** to connect to your MCP server. Note that it might take a few seconds for the MCP inspector tool to successfully connect to your MCP server. If the connection fails, make sure the following fields are set in the MCP inspector tool. + * Select **STDIO** from the **Transport Type** drop down. + * In the **Command** field, enter `uv`. + * In the **Arguments** field, enter `run python src/main.py`. + * In the **Configuration** section, enter the session token from the previous command output in the **Proxy Session Token** field. + + ![Locally run the MCP server](/images/kmcp-local-inspector-ov.png "Locally run your MCP server with the MCP inspector tool") + +4. Try out the `echo` MCP tool. + 1. Go to the **Tools** tab and click **List Tools**. + 2. Select the `echo` tool. + 3. Enter any string in the **message** field, such as `Hello world` and click **Run Tool**. + 4. Verify that you see your message echoed in the **Tool result** card. + + ![Run echo tool in MCP inspector UI](/images/kmcp-local-echo-success.png "Successful run of the echo tool") + + +## Install the kmcp controller + +With your first FastMCP Python server up and running, you can now deploy it to a Kubernetes cluster. To simplify this process, you install the kmcp controller manager that manages the lifecycle of your MCP servers. + +1. Create a kind cluster. + + **Tip**: If you already have a Kubernetes cluster that you want to use, switch to the kubeconfig context for that cluster by using the `kubectl config use-context [CONTEXT-NAME]` command. + ```sh + kind create cluster + ``` + +2. Install the kmcp CRDs. + + ```sh + helm install kmcp-crds oci://ghcr.io/kagent-dev/kmcp/helm/kmcp-crds \ + --namespace kmcp-system \ + --create-namespace + ``` + +3. Install the following kmcp controller components in your cluster. + * The MCPServer Custom Resource Definition to define your MCP server. + * The ClusterRole and ClusterRoleBinding to control RBAC permissions for the kmcp controller. + * The kmcp controller deployment that automatically manages the lifecycle of MCPServer resources. + + ```sh + kmcp install + ``` + + Example output: + ```sh + 🚀 Deploying KMCP controller to cluster... + No version specified, using latest: v{{< reuse "versions/kmcp.md" >}} + Release "kmcp" does not exist. Installing it now. + NAME: kmcp + LAST DEPLOYED: Wed Jul 30 18:41:01 2025 + NAMESPACE: kmcp-system + STATUS: deployed + REVISION: 1 + TEST SUITE: None + ✅ KMCP controller deployed successfully + 💡 Check controller status with: kubectl get pods -n kmcp-system + 💡 View controller logs with: kubectl logs -l app.kubernetes.io/name=kmcp -n kmcp-system + ``` + +4. Verify that the kmcp controller manager is up and running. + ```sh + kubectl get pods -n kmcp-system + ``` + + Example output: + ```sh + NAME READY STATUS RESTARTS AGE + kmcp-controller-manager-66c8764c66-8h5sl 1/1 Running 0 27h + ``` + +## Deploy the MCP server + +1. Build a Docker image for your MCP server and load it to your kind cluster. + ```sh + kmcp build --project-dir my-mcp-server -t my-mcp-server:latest --kind-load-cluster kind + ``` + +2. Deploy the MCP server. + + The kmcp controller creates an MCPServer resource in your cluster that contains the MCP server configuration that is defined in the `kmcp.yaml` file in your MCP project. The controller then uses this resource to spin up and manage the lifecycle of your MCP server. + + **Note**: The following command automatically opens the MCP inspector tool so that you can test your MCP server. If you do not want to open the MCP inspector tool, add the `--no-inspector` option to your command. + ```sh + kmcp deploy --file my-mcp-server/kmcp.yaml --image my-mcp-server:latest + ``` + +3. In the MCP inspector tool, click **Connect** to connect to your MCP server. Note that it might take a few seconds for the MCP inspector tool to successfully connect to your MCP server. If the connection fails, make sure the following fields are set in the MCP inspector tool. + * Select **Streamable HTTP** from the **Transport Type** drop down. + * Enter `http://127.0.0.1:3000/mcp` in the **URL** field. + * Expand the **Configuration** section and make sure that the **Proxy Session Token** is set to the value of the `PROXY_AUTH_TOKEN` that was shown in the CLI output when you opened the MCP inspector tool. + + ![MCP inspector UI for FastMCP](/images/kmcp-inspector-ov.png "Connect to FastMCP server with MCP inspector tool") + +4. Try out the built-in `echo` MCP tool. + 1. Go to the **Tools** tab and click **List Tools**. + 2. Select the `echo` tool. + 3. Enter any string in the **message** field, such as `Hello world` and click **Run Tool**. + 4. Verify that you see your message echoed in the **Tool result** card. + + ![Run echo tool in MCP inspector UI](/images/kmcp-inspector-echo-success.png "Successful run of the echo tool") + + +Congratulations, you successfully developed an MCP server and deployed it to a Kubernetes cluster with kmcp! + +## Next + +* Explore other MCP frameworks, such as [MCP Go](/docs/kmcp/develop/mcp-go). +* Learn how to [manage secrets for your MCP server](/docs/kmcp/secrets) when deploying it in a Kubernetes cluster. + diff --git a/docs-site/content/kmcp/reference/_index.md b/docs-site/content/kmcp/reference/_index.md new file mode 100644 index 00000000..8e916d09 --- /dev/null +++ b/docs-site/content/kmcp/reference/_index.md @@ -0,0 +1,7 @@ +--- +title: Reference +weight: 100 +--- + +Review the KMCP commands and learn how to use them effectively. + diff --git a/docs-site/content/kmcp/reference/api-ref.md b/docs-site/content/kmcp/reference/api-ref.md new file mode 100644 index 00000000..f7cd8732 --- /dev/null +++ b/docs-site/content/kmcp/reference/api-ref.md @@ -0,0 +1,165 @@ +--- +title: API Reference +linkTitle: API docs +description: kmcp API reference documentation +weight: 5 +author: kagent.dev +--- + +## Packages +- [kagent.dev/v1alpha1](#kagentdevv1alpha1) + +## kagent.dev/v1alpha1 + +Package v1alpha1 contains API Schema definitions for the v1alpha1 API group. + +### Resource Types +- [MCPServer](#mcpserver) + +#### HTTPTransport + +HTTPTransport defines the configuration for a Streamable HTTP transport. + +_Appears in:_ +- [MCPServerSpec](#mcpserverspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `targetPort` _integer_ | target port is the HTTP port that serves the MCP server.over HTTP | | | +| `path` _string_ | the target path where MCP is served | | | +| `tls` _[HTTPTransportTLS](#httptransporttls)_ | TLS defines the TLS configuration for HTTPS access to the MCP server. | | | + +#### HTTPTransportTLS + +HTTPTransportTLS defines the TLS configuration for HTTP transport. + +_Appears in:_ +- [HTTPTransport](#httptransport) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `secretRef` _string_ | SecretRef is a reference to a Kubernetes Secret containing
    the client certificate (tls.crt), key (tls.key), and optionally
    the CA certificate (ca.crt) for mTLS authentication.
    The Secret must be in the same namespace as the MCPServer. | | | +| `insecureSkipVerify` _boolean_ | InsecureSkipVerify disables SSL certificate verification.
    WARNING: This should ONLY be used in development/testing environments.
    Production deployments MUST use proper certificates. | false | | + +#### InitContainerConfig + +InitContainerConfig defines the configuration for the init container. + +_Appears in:_ +- [MCPServerDeployment](#mcpserverdeployment) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `image` _string_ | Image defines the full image reference for the init container.
    If specified, this overrides the default transport adapter image.
    Example: "myregistry.com/agentgateway/agentgateway:0.9.0-musl" | | | +| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | ImagePullPolicy defines the pull policy for the init container image. | | Enum: [Always Never IfNotPresent]
    | +| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | Resources defines the compute resource requirements for the init container.
    Use this to specify CPU and memory requests and limits for the init container. | | | +| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | SecurityContext defines the security context for the init container.
    If not specified, the main container's security context will be used. | | | + +#### MCPServer + +MCPServer is the Schema for the mcpservers API. + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `kagent.dev/v1alpha1` | | | +| `kind` _string_ | `MCPServer` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
    Servers may infer this from the endpoint the client submits requests to.
    Cannot be updated.
    In CamelCase.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
    Servers should convert recognized schemas to the latest internal value, and
    may reject unrecognized values.
    More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[MCPServerSpec](#mcpserverspec)_ | | | | +| `status` _[MCPServerStatus](#mcpserverstatus)_ | | | | + +#### MCPServerDeployment + +MCPServerDeployment + +_Appears in:_ +- [MCPServerSpec](#mcpserverspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `image` _string_ | Image defines the container image to to deploy the MCP server. | | | +| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | ImagePullPolicy defines the pull policy for the container image. | | Enum: [Always Never IfNotPresent]
    | +| `port` _integer_ | Port defines the port on which the MCP server will listen. | 3000 | | +| `cmd` _string_ | Cmd defines the command to run in the container to start the mcp server. | | | +| `args` _string array_ | Args defines the arguments to pass to the command. | | | +| `env` _object (keys:string, values:string)_ | Env defines the environment variables to set in the container. | | | +| `secretRefs` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core) array_ | SecretRefs defines the list of Kubernetes secrets to reference.
    These secrets will be mounted as volumes to the MCP server container. | | | +| `configMapRefs` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core) array_ | ConfigMapRefs defines the list of Kubernetes configmaps to reference.
    These configmaps will be mounted as volumes to the MCP server container. | | | +| `volumeMounts` _[VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volumemount-v1-core) array_ | VolumeMounts defines the list of volume mounts for the MCP server container.
    This allows for more flexible volume mounting configurations. | | | +| `volumes` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volume-v1-core) array_ | Volumes defines the list of volumes that can be mounted by containers.
    This allows for custom volume configurations beyond just secrets and configmaps. | | | +| `initContainer` _[InitContainerConfig](#initcontainerconfig)_ | InitContainer defines the configuration for the init container that copies
    the transport adapter binary. This is used for stdio transport type. | | | +| `serviceAccount` _[ServiceAccountConfig](#serviceaccountconfig)_ | ServiceAccount defines the configuration for the ServiceAccount to be created. | | | +| `serviceAccountName` _string_ | ServiceAccountName is the name of an existing ServiceAccount to use. | | | +| `sidecars` _[Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#container-v1-core) array_ | Sidecars defines additional containers to run alongside the MCP server container.
    These containers will share the same pod and can share volumes with the main container. | | | +| `labels` _object (keys:string, values:string)_ | Labels defines additional labels to add to the pod template.
    These labels will be merged with the default labels. | | | +| `annotations` _object (keys:string, values:string)_ | Annotations defines additional annotations to add to the pod template.
    These annotations will be merged with the default annotations. | | | +| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | Resources defines the compute resource requirements for the main MCP server container.
    Use this to specify CPU and memory requests and limits.
    Example:
    resources:
    requests:
    cpu: "100m"
    memory: "128Mi"
    limits:
    cpu: "500m"
    memory: "512Mi" | | | +| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | SecurityContext defines the security context for the main MCP server container.
    Use this to configure container-level security settings such as:
    - runAsUser/runAsGroup: Run as specific user/group
    - runAsNonRoot: Ensure container doesn't run as root
    - readOnlyRootFilesystem: Make root filesystem read-only
    - allowPrivilegeEscalation: Prevent privilege escalation
    - capabilities: Add or drop Linux capabilities | | | +| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podsecuritycontext-v1-core)_ | PodSecurityContext defines the security context for the entire pod.
    Use this to configure pod-level security settings such as:
    - runAsUser/runAsGroup: Default user/group for all containers
    - fsGroup: Group ownership of mounted volumes
    - seccompProfile: Seccomp profile for the pod
    - sysctls: Kernel parameters to set | | | +| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core) array_ | Tolerations defines the tolerations for the pod.
    Use this to schedule pods on nodes with matching taints. | | | +| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | Affinity defines the affinity rules for the pod.
    Use this to control pod placement based on node labels, pod labels,
    or other scheduling constraints. | | | +| `nodeSelector` _object (keys:string, values:string)_ | NodeSelector defines the node selector for the pod.
    Use this to constrain pods to nodes with specific labels. | | | +| `replicas` _integer_ | Replicas defines the number of desired pod replicas.
    Defaults to 1 if not specified. | 1 | | +| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core) array_ | ImagePullSecrets defines the list of secrets to use for pulling container images. | | | + +#### MCPServerSpec + +MCPServerSpec defines the desired state of MCPServer. + +_Appears in:_ +- [MCPServer](#mcpserver) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `deployment` _[MCPServerDeployment](#mcpserverdeployment)_ | Configuration to Deploy the MCP Server using a docker container | | | +| `transportType` _[TransportType](#transporttype)_ | TransportType defines the type of mcp server being run | | Enum: [stdio http]
    | +| `stdioTransport` _[StdioTransport](#stdiotransport)_ | StdioTransport defines the configuration for a standard input/output transport. | | | +| `httpTransport` _[HTTPTransport](#httptransport)_ | HTTPTransport defines the configuration for a Streamable HTTP transport. | | | +| `timeout` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#duration-v1-meta)_ | Timeout defines the default connection timeout for clients connecting
    to this MCP server. MCP servers deployed via the MCPServer CRD use a
    sidecar gateway that spawns a new stdio process (e.g. via uvx/npx)
    for each session. Process startup can take 2-8 seconds depending on
    package cache state, which may exceed the default timeout used by some
    clients. This value is propagated to the generated RemoteMCPServer
    resources when they do not specify an explicit timeout. | 30s | | + +#### MCPServerStatus + +MCPServerStatus defines the observed state of MCPServer. + +_Appears in:_ +- [MCPServer](#mcpserver) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#condition-v1-meta) array_ | Conditions describe the current conditions of the MCPServer.
    Implementations should prefer to express MCPServer conditions
    using the `MCPServerConditionType` and `MCPServerConditionReason`
    constants so that operators and tools can converge on a common
    vocabulary to describe MCPServer state.

    Known condition types are:

    * "Accepted"
    * "ResolvedRefs"
    * "Programmed"
    * "Ready" | | MaxItems: 8
    | +| `observedGeneration` _integer_ | ObservedGeneration is the most recent generation observed for this MCPServer.
    It corresponds to the MCPServer's generation, which is updated on mutation by the API Server. | | | + +#### ServiceAccountConfig + +ServiceAccountConfig defines the configuration for the ServiceAccount. + +_Appears in:_ +- [MCPServerDeployment](#mcpserverdeployment) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `annotations` _object (keys:string, values:string)_ | Annotations to add to the ServiceAccount.
    This is useful for configuring AWS IRSA (IAM Roles for Service Accounts)
    or other cloud provider integrations.
    Example: \{"eks.amazonaws.com/role-arn": "arn:aws:iam::123456789012:role/my-role"\} | | | +| `labels` _object (keys:string, values:string)_ | Labels to add to the ServiceAccount. | | | + +#### StdioTransport + +StdioTransport defines the configuration for a standard input/output transport. + +_Appears in:_ +- [MCPServerSpec](#mcpserverspec) + +#### TransportType + +_Underlying type:_ _string_ + +MCPServerTransportType defines the type of transport for the MCP server. + +_Appears in:_ +- [MCPServerSpec](#mcpserverspec) + +| Field | Description | +| --- | --- | +| `stdio` | TransportTypeStdio indicates that the MCP server uses standard input/output for communication.
    | +| `http` | TransportTypeHTTP indicates that the MCP server uses Streamable HTTP for communication.
    | + diff --git a/docs-site/content/kmcp/reference/kmcp-add-tool.md b/docs-site/content/kmcp/reference/kmcp-add-tool.md new file mode 100644 index 00000000..8a1a78a5 --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-add-tool.md @@ -0,0 +1,30 @@ +--- +title: kmcp add-tool +description: kmcp add-tool command +weight: 10 +--- + +Create a boilerplate for a sample `echo` tool in the `tools` directory of your MCP project and update all the MCP server dependencies to import that tool. You can use this boilerplate as the base to build your own tool. + +```bash +kmcp add-tool [tool-name] [flags] +``` + +**Flags:** +- `--description, -d` - Tool description +- `--force, -f` - Overwrite existing tool file +- `-h, --help` - Help for the command +- `--interactive, -i` - Interactive tool creation +- `--project-dir` - Project directory (default: current directory) + +**Global Flags:** +- `--verbose, -v` - Show detailed output + +## Example + +The following command creates a `mytool` MCP tool in the `my-mcp-server` MCP project. You can edit the file and adjust the code as needed. + +```sh +kmcp add-tool mytool --project-dir my-mcp-server +``` + diff --git a/docs-site/content/kmcp/reference/kmcp-build.md b/docs-site/content/kmcp/reference/kmcp-build.md new file mode 100644 index 00000000..216c32bb --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-build.md @@ -0,0 +1,28 @@ +--- +title: kmcp build +description: kmcp build command +weight: 10 +--- + +Build a Docker image for your MCP server. You can later use this image to deploy your MCP server in a Kubernetes environment. + +```bash +kmcp build [flags] +``` + +**Flags:** +- `-h, --help` - Help for the command +- `--kind-load` - Load image onto a kind cluster (requires kind) +- `--kind-load-cluster` - Name of the kind cluster to load the image onto (default: current cluster context) +- `--platform` - Target platform (e.g., linux/amd64, linux/arm64) +- `--project-dir, -d` - Build directory (default: current directory) +- `--push` - Push the Docker image to a container registry +- `--tag, -t` - Docker image tag + +## Example + +The following command creates a Docker image for the `my-mcp-server` project on your local machine and tags the image as latest. The image is then loaded to a kind cluster named `kind`. + +```sh +kmcp build --project-dir my-mcp-server -t my-mcp-server:latest --kind-load-cluster kind +``` \ No newline at end of file diff --git a/docs-site/content/kmcp/reference/kmcp-completion.md b/docs-site/content/kmcp/reference/kmcp-completion.md new file mode 100644 index 00000000..ec13618e --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-completion.md @@ -0,0 +1,18 @@ +--- +title: kmcp completion +description: kmcp completion command +weight: 30 +--- + +Generate the autocompletion script for kmcp for the specified shell. See each sub-command's help for details on how to use the generated script. + +```bash +kmcp completion [flags] +``` + +**Subcommands:** +- `bash` - Generate the autocompletion script for bash +- `fish` - Generate the autocompletion script for fish +- `powershell` - Generate the autocompletion script for powershell +- `zsh` - Generate the autocompletion script for zsh + diff --git a/docs-site/content/kmcp/reference/kmcp-deploy.md b/docs-site/content/kmcp/reference/kmcp-deploy.md new file mode 100644 index 00000000..b1f378c2 --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-deploy.md @@ -0,0 +1,49 @@ +--- +title: kmcp deploy +description: kmcp deploy command +weight: 10 +--- + +Deploy an MCP server to Kubernetes by generating the MCPServer CRDs. The command uses the `kmcp.yaml` file in your MCP project to spin up and deploy the MCP server in the environment that you specified. + +```bash +kmcp deploy [name] [flags] +``` + +**Subcommands**: + +* `package [flags]` - Deploys an MCP server instance from an existing npm package. + +**Package flags**: +- `--args` - Arguments to pass to the package manager, such as package names (required) +- `--deployment-name` - Name of the MCP server deployment +- `--manager` - Package manager to use (`npx` or `uvx`) (required) + +**Flags:** +- `--args` - Command arguments +- `--command` - Command to run (overrides project config) +- `--dry-run` - Generate manifest without applying to cluster +- `--env` - Environment variables (KEY=VALUE) +- `--environment` - Target environment for deployment (e.g., staging, production) (default: "staging") +- `--file, -f` - Path to kmcp.yaml file (default: current directory) +- `--force` - Force deployment even if validation fails +- `-h, --help` - Help for the command +- `--image` - Docker image to deploy (overrides build image) +- `--namespace, -n` - Kubernetes namespace (default: "default") +- `--no-inspector` - Do not start the MCP inspector tool when deploying the MCP server +- `--output, -o` - Output file for the generated YAML +- `--port` - Container port (default: from project config) +- `--target-port` - Target port for HTTP transport +- `--transport` - Transport type (stdio, http) + +**Global Flags:** +- `--verbose, -v` - Show detailed output + +## Example + +The following example spins up an MCP server in the staging environment with the configuration that is defined in the `my-mcp-server/kmcp.yaml` file. To spin up the server, you use the `my-mcp-server:latest` image. The command automatically opens the MCP inspector tool so that you can test your MCP server. + +```sh +kmcp deploy --environment staging --file my-mcp-server/kmcp.yaml --image my-mcp-server:latest +``` + diff --git a/docs-site/content/kmcp/reference/kmcp-help.md b/docs-site/content/kmcp/reference/kmcp-help.md new file mode 100644 index 00000000..29695c2a --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-help.md @@ -0,0 +1,12 @@ +--- +title: kmcp help +description: kmcp help command +weight: 100 +--- + +Help provides help for any command in the `kmcp` CLI. + +```bash +kmcp help [command] [flags] +``` + diff --git a/docs-site/content/kmcp/reference/kmcp-init.md b/docs-site/content/kmcp/reference/kmcp-init.md new file mode 100644 index 00000000..b3e03579 --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-init.md @@ -0,0 +1,43 @@ +--- +title: kmcp init +description: kmcp init command +weight: 10 +--- + +Create a scaffold for a new [FastMCP](https://github.com/jlowin/fastmcp) or [MCP Go](https://github.com/mark3labs/mcp-go) server project. + +```bash +kmcp init [subcommand] [project-name] [flags] +``` + +**Subcommands:** +- `python [project-name]` - Initialize a Python MCP server project using fastmcp-python +- `go [project-name]` - Initialize a Go MCP server project using mcp-go + +**Flags:** +- `--author` - Set project author +- `--description` - Set project description +- `--email` - Set author email +- `--force` - Overwrite existing directory +- `-h, --help` - Help for the command +- `--namespace` - Default namespace for project resources (default: "default") +- `--no-git` - Skip git initialization +- `--non-interactive` - Use defaults without prompts + +**Go-specific Flags:** +- `--go-module-name` - The Go module name for the project (e.g., github.com/my-org/my-project) + +**Global Flags:** +- `--verbose, -v` - Show detailed output + +## Example + +FastMCP: +```sh +kmcp init python my-mcp-server +``` + +MCP Go: +```sh +kmcp init go my-mcp-server --go-module-name my-mcp-server +``` diff --git a/docs-site/content/kmcp/reference/kmcp-install.md b/docs-site/content/kmcp/reference/kmcp-install.md new file mode 100644 index 00000000..e19e8be4 --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-install.md @@ -0,0 +1,29 @@ +--- +title: kmcp install +description: kmcp install command +weight: 10 +--- + +Install the KMCP controller and its required Custom Resource Definitions (CRDs) +on a Kubernetes cluster. The KMCP contoller manages the lifecycle of MCPServer resources. + +The command installs the following resources: +* The MCPServer Custom Resource Definition to define your MCP server. +* The ClusterRole and ClusterRoleBinding to control RBAC permissions for the KMCP controller. +* The KMCP controller deployment that automatically manages the lifecycle of MCPServer resources. + +```bash +kmcp install [flags] +``` + +**Note**: Run this command once for each cluster to set up the necessary infrastructure +for deploying MCP servers. + +**Flags:** +- `-h, --help` - Help for the command +- `--namespace` - Namespace for the KMCP controller (defaults to kmcp-system) +- `--version` - Version of the controller to deploy (defaults to kmcp version) + +**Global Flags:** +- `--verbose, -v` - Show detailed output + diff --git a/docs-site/content/kmcp/reference/kmcp-run.md b/docs-site/content/kmcp/reference/kmcp-run.md new file mode 100644 index 00000000..26d08740 --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-run.md @@ -0,0 +1,32 @@ +--- +title: kmcp run +description: kmcp run command +weight: 10 +--- + +Run an MCP server on your local machine by using the Model Context Protocol inspector tool. + +**Note**: If you do not have the MCP inspector tool installed, run `npm install -g @modelcontextprotocol/inspector`. + +```bash +kmcp run [flags] +``` + +**Flags:** +- `-h, --help` - Help for the command +- `--no-inspector` - Run the server directly without launching the MCP inspector tool +- `--project-dir, -d` - Project directory to use (default: current directory) + +**Global Flags:** +- `--verbose, -v` - Show detailed output + +## Example + +The following command runs the MCP server that is defined in the `my-mcp-server` project on your local machine. +The command automatically builds the Docker image for your MCP server and opens the MCP inspector tool so that you can connect to your server. + +```sh +kmcp run --project-dir my-mcp-server +``` + +To learn how to use the MCP inspector tool to connect to an MCP server, check out the [FastMCP Python](/docs/kmcp/develop/fastmcp-python) or [MCP Go](/docs/kmcp/develop/mcp-go) guide. diff --git a/docs-site/content/kmcp/reference/kmcp-secrets.md b/docs-site/content/kmcp/reference/kmcp-secrets.md new file mode 100644 index 00000000..747579ac --- /dev/null +++ b/docs-site/content/kmcp/reference/kmcp-secrets.md @@ -0,0 +1,34 @@ +--- +title: kmcp secrets +description: kmcp secrets command +weight: 10 +--- + +Manage secrets for MCP server projects and apply them to a Kubernetes cluster. + +```bash +kmcp secrets [subcommand] [flags] +``` + +**Subcommands:** +- `sync [environment]` - Sync secrets to a Kubernetes environment from a local .env file. The environment is defined in the `kmcp.yaml` file. + +**Sync Flags:** +- `--dry-run` - Output the generated secret YAML instead of applying it +- `--from-file` - Source .env file to sync from (default: ".env") +- `-h, --help` - Help for the command +- `--project-dir, -d` - Project directory (default: current directory) + +**Global Flags:** +- `--verbose, -v` - Show detailed output + +## Example + +The following command reads the environment variables that are defined in the `.env.staging` file and puts them into a Kubernetes secret in your cluster. +The name and namespace for the secret are defined in the `staging` environment configuration of the `kmcp.yaml` file. + +```sh +kmcp secrets sync staging --from-file my-mcp-server/.env.staging --project-dir my-mcp-server +``` + +For more information, check out [Manage secrets for MCP servers](/docs/kmcp/secrets). \ No newline at end of file diff --git a/docs-site/content/kmcp/secrets.md b/docs-site/content/kmcp/secrets.md new file mode 100644 index 00000000..8716c55a --- /dev/null +++ b/docs-site/content/kmcp/secrets.md @@ -0,0 +1,143 @@ +--- +title: Manage secrets +description: Configure your MCP server to read additional environment variables from a Kubernetes secret. +weight: 50 +--- + +You can bootstrap your MCP server with additional environment variables that the MCP server needs to run properly. These environment variables are typically defined in an `.env` file. + +You can use the `kmcp secret` command to store these environment variables in a Kubernetes secret and to automatically configure the MCP server to mount that secret during the MCP server deployment. + +The name and namespace of the Kubernetes secret that you want to create is defined in the `kmcp.yaml` file of your project. + +## Prerequisites + +- Create a [FastMCP](/docs/kmcp/develop/fastmcp-python) or [MCP Go](/docs/kmcp/develop/mcp-go) project with a sample MCP server and tool. +- [Install the kmcp controller](/docs/kmcp/deploy/install-controller) in a local kind cluster to manage the lifecycle of MCP servers in your cluster. + +## Store environment variables in a Kubernetes secret + +1. Review the `kmcp.yaml` configuration of your MCP project. The default `kmcp.yaml` file includes a `secrets` section that defines multiple environments, such as `staging`, `production`, and `local`. Each environment defines the name and the namespace of the Kubernetes secret that you want to use. Note that all environments are currently disabled. + ```sh + cat my-mcp-server/kmcp.yaml + ``` + + Example output: + ```yaml + name: my-mcp-server + framework: fastmcp-python + version: 0.1.0 + description: MCP server built with fastmcp-python + secrets: + local: + enabled: false + provider: env + file: .env.local + production: + enabled: false + provider: kubernetes + secretName: my-mcp-server-secrets-production + namespace: default + staging: + enabled: false + provider: kubernetes + secretName: my-mcp-server-secrets-staging + namespace: default + ``` + +2. Enable the staging environment by setting the `secret.staging.enabled` field to `true`. You can optionally change the name and namespace of the Kubernetes secret that you want to use with your MCP server. However, keep in mind that the secret must be in the same namespace where the MCP server is deployed. + ```yaml + ... + secrets: + local: + enabled: false + provider: env + file: .env.local + production: + enabled: false + provider: kubernetes + secretName: my-mcp-server-secrets-production + namespace: default + staging: + enabled: true + provider: kubernetes + secretName: my-mcp-server-secrets-staging + namespace: default + ``` + +3. Create an `.env.staging` file in your MCP project that defines additional environment variables that you want to provide to your MCP server. + ```sh + cat << EOF > my-mcp-server/.env.staging + # .env.staging + API_KEY=your-api-key-here + DATABASE_URL=postgresql://user:pass@host:5432/db + EOF + ``` + +4. Create the Kubernetes secret in your kind cluster by using the secret defintion from the `kmcp.yaml` file and the environment variables from the `.env.staging` file. Note that this step is not required when you plan to run your MCP server locally only. + ```sh + kmcp secrets sync staging --from-file my-mcp-server/.env.staging --project-dir my-mcp-server + ``` + +5. Verify that the Kubernetes secret is created and that you can see the base64-encoded environment variables that you defined earlier. + ```sh + kubectl get secret my-mcp-server-secrets-staging -o yaml + ``` + + Example output: + ```yaml + apiVersion: v1 + data: + API_KEY: eW91ci1hcGkta2V5LWhlcmU= + DATABASE_URL: cG9zdGdyZXNxbDovL3VzZXI6cGFzc0Bob3N0OjU0MzIvZGI= + kind: Secret + metadata: + name: my-mcp-server-secrets-staging + namespace: default + resourceVersion: "10819" + uid: 85... + type: Opaque + ``` + +## Deploy the MCP server with your secret + +1. Build a Docker image for your MCP server and load it to your kind cluster. + ```sh + kmcp build --project-dir my-mcp-server -t my-mcp-server:latest --kind-load-cluster kind + ``` + +2. Deploy your MCP server and bootstrap it with the Kubernetes secret of the staging environment. + ```sh + kmcp deploy --environment staging --file my-mcp-server/kmcp.yaml --no-inspector --image my-mcp-server:latest + ``` + +3. Verify that your server is up and running. + ```sh + kubectl get pods + ``` + +4. Get the details of the `my-mcp-server` deployment. Verify that you see the reference to your Kubernetes secret in the `spec.containers.envFrom` section. + ```sh + kubectl get deployment my-mcp-server -o yaml + ``` + + Example output: + ```sh + ... + template: + metadata: + creationTimestamp: null + labels: + app.kubernetes.io/instance: my-mcp-server + app.kubernetes.io/managed-by: kmcp + app.kubernetes.io/name: my-mcp-server + spec: + containers: + ... + envFrom: + - secretRef: + name: my-mcp-server-secrets-staging + image: my-mcp-server:latest + ... + ``` + diff --git a/docs-site/go.mod b/docs-site/go.mod new file mode 100644 index 00000000..57b96605 --- /dev/null +++ b/docs-site/go.mod @@ -0,0 +1,5 @@ +module github.com/kagent-dev/website-docs + +go 1.21 + +require github.com/solo-io/docs-theme-extras v0.1.18-beta.7 // indirect diff --git a/docs-site/go.sum b/docs-site/go.sum new file mode 100644 index 00000000..9a4f577c --- /dev/null +++ b/docs-site/go.sum @@ -0,0 +1,6 @@ +github.com/solo-io/docs-theme-extras v0.1.18-beta.5 h1:gbCV0I0NB6z/k+qQTy0Dhl1XkswDwsxQPfZiM1Fniaw= +github.com/solo-io/docs-theme-extras v0.1.18-beta.5/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= +github.com/solo-io/docs-theme-extras v0.1.18-beta.6 h1:+E0ZW1rmf8rnL3TaFgaIwW72HtCdJzuw1UEIdY2RPTc= +github.com/solo-io/docs-theme-extras v0.1.18-beta.6/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= +github.com/solo-io/docs-theme-extras v0.1.18-beta.7 h1:Z1WWb9ZCoJymUkh3d1e9akfVX2aGOIUTdPoEH26XvcQ= +github.com/solo-io/docs-theme-extras v0.1.18-beta.7/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= diff --git a/docs-site/hugo.yaml b/docs-site/hugo.yaml new file mode 100644 index 00000000..db1b73f2 --- /dev/null +++ b/docs-site/hugo.yaml @@ -0,0 +1,151 @@ +# The docs are served as a static sub-site under /docs of the kagent.dev origin +# (the Next.js marketing worker owns everything else). A baseURL with the /docs +# path prefix namespaces every emitted URL (pages AND css/js/images/favicons) +# under /docs, so Hugo's output drops cleanly into the worker's public/docs/ +# static assets with no collisions against the marketing site's /images, etc. +# Content lives at content// (NOT content/docs/) so the /docs prefix +# comes only from baseURL and isn't doubled. +baseURL: "https://kagent.dev/docs/" +enableRobotsTXT: true +# canonifyURLs must stay off with a subpath baseURL: it would rewrite already +# root-relative links (/docs/…) and relURL-built asset paths against baseURL and +# double the /docs prefix. The theme uses relURL, which already honors the +# subpath, so canonify is unnecessary here. +canonifyURLs: false +title: "kagent docs" + +outputs: + home: [HTML, RSS, llms] + page: [HTML, markdown] + section: [HTML, RSS, markdown, llms] + +defaultContentLanguage: en + +module: + imports: + # docs-theme-extras declares the hextra import itself; consumers do not + # need to list hextra separately. Extras layouts win over the transitively + # imported hextra ones. + - path: github.com/solo-io/docs-theme-extras + mounts: + - source: "assets" + target: "assets" + - source: "hugo_stats.json" + target: "assets/watching/hugo_stats.json" + +build: + writeStats: true + cachebusters: + - source: "assets/watching/hugo_stats\\.json" + target: "styles\\.css" + - source: "(postcss|tailwind)\\.config\\.js" + target: "css" + - source: "assets/.*\\.(js|ts|jsx|tsx)" + target: "js" + - source: "assets/.*\\.(.*)$" + target: "$1" + +caches: + getresource: + dir: ":cacheDir/:project" + maxAge: 1h + +markup: + goldmark: + extensions: + extras: + superscript: + enable: true + renderer: + unsafe: true + highlight: + noClasses: false + +enableInlineShortcodes: true + +params: + # Load the docs-theme-extras OSS brand layer (brand-oss.css + Open Sans). + # This is what gives the navbar search its rounded/padded look and keeps + # styling consistent with the other Solo OSS docs sites (agw, kgw). + themeExtras: + brand: oss + prodHost: "https://kagent.dev" + navbar: + displayTitle: false + displayLogo: true + logo: + path: images/kagent-logo-light.svg + dark: images/kagent-logo-dark.svg + # The docs are served under /docs, so the Hugo home is the /docs landing. + # Point the logo at the site root (/) — the Next.js marketing home — instead. + # navbar-title.html emits this link raw (no relURL), so it stays "/" and + # isn't prefixed with /docs. + link: / + width: 126 + height: 28 + theme: + # Auto-render the light/dark toggle in the navbar + displayToggle: true + +# Top nav — mirrors kagent.dev. Docs is local; the marketing/blog sections stay +# on the Next.js site, so those link out to absolute kagent.dev URLs. +menu: + main: + - name: Docs + identifier: docs + # Menu urls are relative to baseURL, so Hugo prepends the /docs subpath + # automatically — use logical paths here (/, /kagent, /kmcp), NOT /docs/…, + # or the prefix doubles to /docs/docs/…. + url: / + weight: 1 + # Child entries turn "Docs" into a dropdown. Hextra's navbar-link.html + # renders any menu item with children as a dropdown toggle (matches agw's + # standalone/kubernetes split). kagent docs are unversioned, so these point + # straight at each product's section landing. + - name: kagent + parent: docs + url: /kagent + weight: 1 + params: + # Matches assets/icons/nav-.svg; rendered inline by navbar-link.html + # so the dropdown carries the same product marks as the JS marketing nav. + icon: kagent + - name: kmcp + parent: docs + url: /kmcp + weight: 2 + params: + icon: kmcp + # Marketing pages are served on the SAME origin (the Next.js worker), at the + # site root — not under the docs' /docs baseURL. Use params.localHref (emitted + # verbatim by navbar-link.html) so these stay root-relative and clicking stays + # on the current host instead of jumping to production kagent.dev. + - name: Blog + weight: 2 + params: + localHref: /blog + - name: Tools + weight: 3 + params: + localHref: /tools + - name: Agents + weight: 4 + params: + localHref: /agents + - name: Community + weight: 5 + params: + localHref: /community + - name: Enterprise + weight: 6 + params: + localHref: /enterprise + - name: Search + weight: 7 + params: + type: search + - name: GitHub + url: https://github.com/kagent-dev/kagent + weight: 8 + params: + icon: github diff --git a/docs-site/i18n/en.yaml b/docs-site/i18n/en.yaml new file mode 100644 index 00000000..1d18eb59 --- /dev/null +++ b/docs-site/i18n/en.yaml @@ -0,0 +1 @@ +copyright: "© 2026, kagent, a Series of LF Projects, LLC. All rights reserved." \ No newline at end of file diff --git a/docs-site/layouts/_partials/navbar-link.html b/docs-site/layouts/_partials/navbar-link.html new file mode 100644 index 00000000..e8515e5c --- /dev/null +++ b/docs-site/layouts/_partials/navbar-link.html @@ -0,0 +1,114 @@ +{{- /* + kagent project override of Hextra's navbar-link.html. + + Why this exists: Hextra highlights the active top-nav item with + `hx:font-medium` + a darker color. Because kagent's non-Docs nav links all + point off-site (kagent.dev/blog, /tools, …), they're never "active", so only + Docs ever gets the bold/dark treatment on docs pages — making it look bigger + than its neighbors. agw-oss and kgw-oss avoid this by rendering every top-nav + link with one uniform `.link` class (no active emphasis); this override mirrors + that result by forcing the non-active styling for all items. + + Only the `$activeClass` line differs from Hextra v0.12.x's stock partial; the + rest is copied verbatim so the dropdown markup keeps working. +*/ -}} +{{- $currentPage := .currentPage -}} +{{- $link := .link -}} +{{- $item := .item -}} +{{- $icon := .icon -}} +{{- $external := .external -}} + +{{- /* Uniform styling for every top-nav link (no active bold/dark state), so + Docs doesn't stand out from the off-site links. */ -}} +{{- $activeClass := "hx:text-gray-600 hx:hover:text-gray-800 hx:dark:text-gray-400 hx:dark:hover:text-gray-200" -}} + +{{- if $item.HasChildren -}} +{{- /* Dropdown menu for items with children */ -}} +
    + + +
    +{{- else -}} +{{- /* Regular menu item without children */ -}} +{{- /* Same-origin marketing links (Blog/Tools/Agents/…) live at the site ROOT, + not under the docs' /docs baseURL. A menu `url: /agents` would be prefixed + to /docs/agents, so those entries set `params.localHref` (used verbatim) + to keep them root-relative — clicking stays on the current host instead of + jumping to production. */ -}} +{{- $href := $link -}} +{{- with $item.Params.localHref -}}{{- $href = . -}}{{- end -}} + + {{- if $icon -}} + + {{- partial "utils/icon" (dict "name" $icon "attributes" `height="1em" class="hx:inline-block"`) -}} + + {{- end -}} + + {{- or (T $item.Identifier) $item.Name | safeHTML -}} + + +{{- end -}} diff --git a/docs-site/layouts/_partials/sidebar.html b/docs-site/layouts/_partials/sidebar.html new file mode 100644 index 00000000..fd2a0d40 --- /dev/null +++ b/docs-site/layouts/_partials/sidebar.html @@ -0,0 +1,88 @@ +{{- /* + kagent project sidebar override. + + Why this exists: Hextra v0.12 ships layouts/_partials/sidebar.html, which + (per the _partials-shadows-partials precedence rule) wins over docs-theme- + extras' layouts/partials/sidebar.html. Hextra's native sidebar roots the tree + at the current section, so kagent's nav "drills down" as you navigate deeper + instead of showing the whole product tree. + + kagent docs are flat + unversioned but split across two products (kagent + kmcp, + each a top-level content section). This override roots the tree at the product + section via .FirstSection — the current page's top-level section ancestor — so + every page in a product shows that product's full, expandable tree with the + active branch auto-expanded. Using .FirstSection (rather than parsing the URL + for a /docs/ prefix) keeps this correct regardless of the baseURL + subpath the site is served under. It reuses the same CSS classes / + data-attributes as extras' sidebar (sidebar-link, sidebar-toggle, + sidebar-children, data-sidebar-item, sidebar-mobile-panel) so the toggle JS and + mobile drawer in docs-theme-extras keep working. + + Called by extras' docs/single.html + docs/list.html as: + {{ partial "sidebar.html" (dict "context" .) }} +*/ -}} +{{- $context := .context -}} + +{{- /* The site home (_index.md) is the /docs landing itself — it has no single + product tree to show, so suppress the sidebar there. */ -}} +{{- if $context.IsHome -}} + +{{- else -}} + {{- $navRoot := $context.FirstSection -}} + + + +{{- end -}} + +{{- /* Recursive tree renderer — mirrors extras' render-sidebar-tree markup. */ -}} +{{- define "kagent-sidebar-tree" -}} + {{- $page := .page -}} + {{- $current := .current -}} + {{- $depth := .depth | default 0 -}} + {{- if gt $depth 4 -}}{{- return -}}{{- end -}} + + {{- $children := $page.Pages -}} + {{- if gt (len $children) 0 -}} + + {{- end -}} +{{- end -}} diff --git a/docs-site/layouts/_shortcodes/feature-card.html b/docs-site/layouts/_shortcodes/feature-card.html new file mode 100644 index 00000000..9786e4a6 --- /dev/null +++ b/docs-site/layouts/_shortcodes/feature-card.html @@ -0,0 +1,9 @@ +{{- /* A single non-link feature tile. Mirrors extras' .section-card markup but + as a
    (no anchor), because feature capabilities have no destination + URL. Cards that DO navigate use the `card` shortcode instead. */ -}} +
    + + {{ .Get "title" }} + {{- with .Get "desc" }}{{ . }}{{ end -}} + +
    diff --git a/docs-site/layouts/_shortcodes/feature-cards.html b/docs-site/layouts/_shortcodes/feature-cards.html new file mode 100644 index 00000000..65d09238 --- /dev/null +++ b/docs-site/layouts/_shortcodes/feature-cards.html @@ -0,0 +1,6 @@ +{{- /* Non-link feature tile grid (from ). Reuses the extras + .section-cards grid so the layout matches real card grids, but the tiles + are display-only (see feature-card.html) — no empty links. */ -}} +
    + {{ .Inner }} +
    diff --git a/docs-site/layouts/partials/custom/head-end.html b/docs-site/layouts/partials/custom/head-end.html new file mode 100644 index 00000000..603d7cc0 --- /dev/null +++ b/docs-site/layouts/partials/custom/head-end.html @@ -0,0 +1,25 @@ +{{- /* + Module bootstrap MUST be the first call here. docs-theme-extras ships its + head-end content (brand CSS, fonts, sidebar JS, TOC scroll-spy, Copy-as- + Markdown, version dropdown) inside themeExtras/head-end.html. Hugo's + project-over-imports precedence would let this file silently shadow the + module's bootstrap, so we invoke it explicitly. Everything below is the + consumer-local PostCSS pipeline that carries kagent-specific Tailwind usage. +*/ -}} +{{ partial "themeExtras/head-end.html" . }} + +{{/* Consumer-local PostCSS pipeline (Tailwind utilities on top of the module CSS) */}} +{{ $options := dict "inlineImports" true "config" "./assets/css/postcss.config.js" }} +{{ $styles := resources.Get "css/styles.css" }} +{{ $styles = $styles | css.PostCSS $options }} +{{- if hugo.IsProduction }} +{{ $styles = $styles | minify | fingerprint | resources.PostProcess }} + +{{- else }} + +{{ end }} + +{{/* Font preconnects — perf hints; the module emits the actual font links */}} + + + diff --git a/docs-site/package-lock.json b/docs-site/package-lock.json new file mode 100644 index 00000000..b76d8854 --- /dev/null +++ b/docs-site/package-lock.json @@ -0,0 +1,1921 @@ +{ + "name": "kagent-hugo-site", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@tailwindcss/typography": "^0.5.10", + "tailwindcss": "^3.3.5" + }, + "devDependencies": { + "autoprefixer": "^10.4.20", + "postcss": "^8.4.47", + "postcss-cli": "^11.0.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", + "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", + "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-cli": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.0.tgz", + "integrity": "sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.3.0", + "dependency-graph": "^0.11.0", + "fs-extra": "^11.0.0", + "get-stdin": "^9.0.0", + "globby": "^14.0.0", + "picocolors": "^1.0.0", + "postcss-load-config": "^5.0.0", + "postcss-reporter": "^7.0.0", + "pretty-hrtime": "^1.0.3", + "read-cache": "^1.0.0", + "slash": "^5.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "postcss": "index.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.0.3.tgz", + "integrity": "sha512-90pBBI5apUVruIEdCxZic93Wm+i9fTrp7TXbgdUCH+/L+2WnfpITSpq5dFU/IPvbv7aNiMlQISpUkAm3fEcvgQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-reporter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.1.0.tgz", + "integrity": "sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "picocolors": "^1.0.0", + "thenby": "^1.3.4" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thenby": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", + "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", + "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/docs-site/package.json b/docs-site/package.json new file mode 100644 index 00000000..bf712a9c --- /dev/null +++ b/docs-site/package.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "@tailwindcss/typography": "^0.5.10", + "tailwindcss": "^3.3.5" + }, + "devDependencies": { + "autoprefixer": "^10.4.20", + "postcss": "^8.4.47", + "postcss-cli": "^11.0.0" + } +} diff --git a/docs-site/static/images/add-tool-server.png b/docs-site/static/images/add-tool-server.png new file mode 100644 index 00000000..219066e8 Binary files /dev/null and b/docs-site/static/images/add-tool-server.png differ diff --git a/docs-site/static/images/adopters/amdocs.png b/docs-site/static/images/adopters/amdocs.png new file mode 100644 index 00000000..3858e4a2 Binary files /dev/null and b/docs-site/static/images/adopters/amdocs.png differ diff --git a/docs-site/static/images/adopters/au10tix.png b/docs-site/static/images/adopters/au10tix.png new file mode 100644 index 00000000..109632a7 Binary files /dev/null and b/docs-site/static/images/adopters/au10tix.png differ diff --git a/docs-site/static/images/adopters/cloudraft.svg b/docs-site/static/images/adopters/cloudraft.svg new file mode 100644 index 00000000..6657d15c --- /dev/null +++ b/docs-site/static/images/adopters/cloudraft.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs-site/static/images/adopters/codewizard.png b/docs-site/static/images/adopters/codewizard.png new file mode 100644 index 00000000..fbb4a797 Binary files /dev/null and b/docs-site/static/images/adopters/codewizard.png differ diff --git a/docs-site/static/images/adopters/krateo-dark.svg b/docs-site/static/images/adopters/krateo-dark.svg new file mode 100644 index 00000000..a93ae97f --- /dev/null +++ b/docs-site/static/images/adopters/krateo-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs-site/static/images/adopters/krateo-light.svg b/docs-site/static/images/adopters/krateo-light.svg new file mode 100644 index 00000000..2eb23c9c --- /dev/null +++ b/docs-site/static/images/adopters/krateo-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs-site/static/images/adopters/solo-io-dark.png b/docs-site/static/images/adopters/solo-io-dark.png new file mode 100644 index 00000000..e516ce8f Binary files /dev/null and b/docs-site/static/images/adopters/solo-io-dark.png differ diff --git a/docs-site/static/images/adopters/solo-io-light.png b/docs-site/static/images/adopters/solo-io-light.png new file mode 100644 index 00000000..30449335 Binary files /dev/null and b/docs-site/static/images/adopters/solo-io-light.png differ diff --git a/docs-site/static/images/adopters/solo-io.png b/docs-site/static/images/adopters/solo-io.png new file mode 100644 index 00000000..fda2902e Binary files /dev/null and b/docs-site/static/images/adopters/solo-io.png differ diff --git a/docs-site/static/images/agent-mcp-claude.png b/docs-site/static/images/agent-mcp-claude.png new file mode 100644 index 00000000..387e9112 Binary files /dev/null and b/docs-site/static/images/agent-mcp-claude.png differ diff --git a/docs-site/static/images/agent-mcp-tools.png b/docs-site/static/images/agent-mcp-tools.png new file mode 100644 index 00000000..34af50d2 Binary files /dev/null and b/docs-site/static/images/agent-mcp-tools.png differ diff --git a/docs-site/static/images/arch.png b/docs-site/static/images/arch.png new file mode 100644 index 00000000..0f8fb7bc Binary files /dev/null and b/docs-site/static/images/arch.png differ diff --git a/docs-site/static/images/authors/antweiss.png b/docs-site/static/images/authors/antweiss.png new file mode 100644 index 00000000..224f47e2 Binary files /dev/null and b/docs-site/static/images/authors/antweiss.png differ diff --git a/docs-site/static/images/authors/christian-posta.png b/docs-site/static/images/authors/christian-posta.png new file mode 100644 index 00000000..71538489 Binary files /dev/null and b/docs-site/static/images/authors/christian-posta.png differ diff --git a/docs-site/static/images/authors/eitan_yarmush.jpeg b/docs-site/static/images/authors/eitan_yarmush.jpeg new file mode 100644 index 00000000..cbebe9fd Binary files /dev/null and b/docs-site/static/images/authors/eitan_yarmush.jpeg differ diff --git a/docs-site/static/images/authors/jetchiang.jpg b/docs-site/static/images/authors/jetchiang.jpg new file mode 100644 index 00000000..c6034bf7 Binary files /dev/null and b/docs-site/static/images/authors/jetchiang.jpg differ diff --git a/docs-site/static/images/authors/linsun.jpg b/docs-site/static/images/authors/linsun.jpg new file mode 100644 index 00000000..b583ba10 Binary files /dev/null and b/docs-site/static/images/authors/linsun.jpg differ diff --git a/docs-site/static/images/authors/michaellevan.jpeg b/docs-site/static/images/authors/michaellevan.jpeg new file mode 100644 index 00000000..57e0d8c4 Binary files /dev/null and b/docs-site/static/images/authors/michaellevan.jpeg differ diff --git a/docs-site/static/images/authors/sebastianmaniak.png b/docs-site/static/images/authors/sebastianmaniak.png new file mode 100644 index 00000000..984d17bd Binary files /dev/null and b/docs-site/static/images/authors/sebastianmaniak.png differ diff --git a/docs-site/static/images/authors/yanivmn.jpg b/docs-site/static/images/authors/yanivmn.jpg new file mode 100644 index 00000000..39a4c5bc Binary files /dev/null and b/docs-site/static/images/authors/yanivmn.jpg differ diff --git a/docs-site/static/images/blog/100days/London-devops-meetup.png b/docs-site/static/images/blog/100days/London-devops-meetup.png new file mode 100644 index 00000000..35e05d40 Binary files /dev/null and b/docs-site/static/images/blog/100days/London-devops-meetup.png differ diff --git a/docs-site/static/images/blog/100days/Marcin-post.png b/docs-site/static/images/blog/100days/Marcin-post.png new file mode 100644 index 00000000..8104b43a Binary files /dev/null and b/docs-site/static/images/blog/100days/Marcin-post.png differ diff --git a/docs-site/static/images/blog/100days/aire-agent.png b/docs-site/static/images/blog/100days/aire-agent.png new file mode 100644 index 00000000..978ca459 Binary files /dev/null and b/docs-site/static/images/blog/100days/aire-agent.png differ diff --git a/docs-site/static/images/blog/100days/argo-mcp.png b/docs-site/static/images/blog/100days/argo-mcp.png new file mode 100644 index 00000000..ad1bf535 Binary files /dev/null and b/docs-site/static/images/blog/100days/argo-mcp.png differ diff --git a/docs-site/static/images/blog/100days/cncf-sandbox.png b/docs-site/static/images/blog/100days/cncf-sandbox.png new file mode 100644 index 00000000..4845e8d1 Binary files /dev/null and b/docs-site/static/images/blog/100days/cncf-sandbox.png differ diff --git a/docs-site/static/images/blog/100days/home-lab-mcp.png b/docs-site/static/images/blog/100days/home-lab-mcp.png new file mode 100644 index 00000000..38da9cdf Binary files /dev/null and b/docs-site/static/images/blog/100days/home-lab-mcp.png differ diff --git a/docs-site/static/images/blog/100days/kagent-a2a.png b/docs-site/static/images/blog/100days/kagent-a2a.png new file mode 100644 index 00000000..459d5ded Binary files /dev/null and b/docs-site/static/images/blog/100days/kagent-a2a.png differ diff --git a/docs-site/static/images/blog/100days/kcd-texas.png b/docs-site/static/images/blog/100days/kcd-texas.png new file mode 100644 index 00000000..13235777 Binary files /dev/null and b/docs-site/static/images/blog/100days/kcd-texas.png differ diff --git a/docs-site/static/images/blog/100days/kubecon-china.png b/docs-site/static/images/blog/100days/kubecon-china.png new file mode 100644 index 00000000..a6e03a93 Binary files /dev/null and b/docs-site/static/images/blog/100days/kubecon-china.png differ diff --git a/docs-site/static/images/blog/100days/terraform-agent.png b/docs-site/static/images/blog/100days/terraform-agent.png new file mode 100644 index 00000000..eb8916da Binary files /dev/null and b/docs-site/static/images/blog/100days/terraform-agent.png differ diff --git a/docs-site/static/images/blog/100days/top-contributors.png b/docs-site/static/images/blog/100days/top-contributors.png new file mode 100644 index 00000000..65477076 Binary files /dev/null and b/docs-site/static/images/blog/100days/top-contributors.png differ diff --git a/docs-site/static/images/blog/agent-substrate/architecture.png b/docs-site/static/images/blog/agent-substrate/architecture.png new file mode 100644 index 00000000..855723ee Binary files /dev/null and b/docs-site/static/images/blog/agent-substrate/architecture.png differ diff --git a/docs-site/static/images/blog/agent-substrate/hero.png b/docs-site/static/images/blog/agent-substrate/hero.png new file mode 100644 index 00000000..a05d5bc3 Binary files /dev/null and b/docs-site/static/images/blog/agent-substrate/hero.png differ diff --git a/docs-site/static/images/blog/aire/incident-msg.png b/docs-site/static/images/blog/aire/incident-msg.png new file mode 100644 index 00000000..52077838 Binary files /dev/null and b/docs-site/static/images/blog/aire/incident-msg.png differ diff --git a/docs-site/static/images/blog/aire/text-msg.png b/docs-site/static/images/blog/aire/text-msg.png new file mode 100644 index 00000000..04525a76 Binary files /dev/null and b/docs-site/static/images/blog/aire/text-msg.png differ diff --git a/docs-site/static/images/blog/community-nginx-khook-kagent/diagram.png b/docs-site/static/images/blog/community-nginx-khook-kagent/diagram.png new file mode 100644 index 00000000..03900227 Binary files /dev/null and b/docs-site/static/images/blog/community-nginx-khook-kagent/diagram.png differ diff --git a/docs-site/static/images/blog/crewai-byo/shakespeare-flow.png b/docs-site/static/images/blog/crewai-byo/shakespeare-flow.png new file mode 100644 index 00000000..bf006e76 Binary files /dev/null and b/docs-site/static/images/blog/crewai-byo/shakespeare-flow.png differ diff --git a/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo1.png b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo1.png new file mode 100644 index 00000000..3a2ed703 Binary files /dev/null and b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo1.png differ diff --git a/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo2.png b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo2.png new file mode 100644 index 00000000..1d3139d5 Binary files /dev/null and b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo2.png differ diff --git a/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo3.png b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo3.png new file mode 100644 index 00000000..376b44f0 Binary files /dev/null and b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo3.png differ diff --git a/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo4.png b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo4.png new file mode 100644 index 00000000..a0cfe6a8 Binary files /dev/null and b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo4.png differ diff --git a/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo5.png b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo5.png new file mode 100644 index 00000000..9878403f Binary files /dev/null and b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo5.png differ diff --git a/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo6.png b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo6.png new file mode 100644 index 00000000..28bc36c1 Binary files /dev/null and b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo6.png differ diff --git a/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo7.png b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo7.png new file mode 100644 index 00000000..b053a825 Binary files /dev/null and b/docs-site/static/images/blog/kagent-nemo-openshell-imp/nemo7.png differ diff --git a/docs-site/static/images/blog/kgateway/kagent-aigw.gif b/docs-site/static/images/blog/kgateway/kagent-aigw.gif new file mode 100644 index 00000000..bb8f33ad Binary files /dev/null and b/docs-site/static/images/blog/kgateway/kagent-aigw.gif differ diff --git a/docs-site/static/images/blog/kgateway/kagent-llm.gif b/docs-site/static/images/blog/kgateway/kagent-llm.gif new file mode 100644 index 00000000..47b0e4f9 Binary files /dev/null and b/docs-site/static/images/blog/kgateway/kagent-llm.gif differ diff --git a/docs-site/static/images/blog/reactive-agents-khook/kagent-logo.png b/docs-site/static/images/blog/reactive-agents-khook/kagent-logo.png new file mode 100644 index 00000000..8a066458 Binary files /dev/null and b/docs-site/static/images/blog/reactive-agents-khook/kagent-logo.png differ diff --git a/docs-site/static/images/blog/reactive-agents-khook/khook-diagram.png b/docs-site/static/images/blog/reactive-agents-khook/khook-diagram.png new file mode 100644 index 00000000..9e3c9b3d Binary files /dev/null and b/docs-site/static/images/blog/reactive-agents-khook/khook-diagram.png differ diff --git a/docs-site/static/images/blog/reactive-agents-khook/khook-logo.png b/docs-site/static/images/blog/reactive-agents-khook/khook-logo.png new file mode 100644 index 00000000..a828ec02 Binary files /dev/null and b/docs-site/static/images/blog/reactive-agents-khook/khook-logo.png differ diff --git a/docs-site/static/images/byo-basic.png b/docs-site/static/images/byo-basic.png new file mode 100644 index 00000000..2802eaa6 Binary files /dev/null and b/docs-site/static/images/byo-basic.png differ diff --git a/docs-site/static/images/byo-langgraph.png b/docs-site/static/images/byo-langgraph.png new file mode 100644 index 00000000..324514f2 Binary files /dev/null and b/docs-site/static/images/byo-langgraph.png differ diff --git a/docs-site/static/images/cncf-logo.png b/docs-site/static/images/cncf-logo.png new file mode 100644 index 00000000..e69de29b diff --git a/docs-site/static/images/contributors/adobe.svg b/docs-site/static/images/contributors/adobe.svg new file mode 100644 index 00000000..97418737 --- /dev/null +++ b/docs-site/static/images/contributors/adobe.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/contributors/cncf-dark.png b/docs-site/static/images/contributors/cncf-dark.png new file mode 100644 index 00000000..72092ef4 Binary files /dev/null and b/docs-site/static/images/contributors/cncf-dark.png differ diff --git a/docs-site/static/images/contributors/cncf-light.png b/docs-site/static/images/contributors/cncf-light.png new file mode 100644 index 00000000..7a389548 Binary files /dev/null and b/docs-site/static/images/contributors/cncf-light.png differ diff --git a/docs-site/static/images/contributors/confluent.svg b/docs-site/static/images/contributors/confluent.svg new file mode 100644 index 00000000..055f3584 --- /dev/null +++ b/docs-site/static/images/contributors/confluent.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/docs-site/static/images/contributors/google.svg b/docs-site/static/images/contributors/google.svg new file mode 100644 index 00000000..a60c9fa5 --- /dev/null +++ b/docs-site/static/images/contributors/google.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/contributors/ibm.svg b/docs-site/static/images/contributors/ibm.svg new file mode 100644 index 00000000..5d1ba699 --- /dev/null +++ b/docs-site/static/images/contributors/ibm.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/contributors/microsoft.svg b/docs-site/static/images/contributors/microsoft.svg new file mode 100644 index 00000000..1f5fcaaa --- /dev/null +++ b/docs-site/static/images/contributors/microsoft.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/contributors/redhat.svg b/docs-site/static/images/contributors/redhat.svg new file mode 100644 index 00000000..e74e08f0 --- /dev/null +++ b/docs-site/static/images/contributors/redhat.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/discord-a2a/discord-a2a-kagent.png b/docs-site/static/images/discord-a2a/discord-a2a-kagent.png new file mode 100644 index 00000000..9410e5bd Binary files /dev/null and b/docs-site/static/images/discord-a2a/discord-a2a-kagent.png differ diff --git a/docs-site/static/images/discord-a2a/discord-intents.png b/docs-site/static/images/discord-a2a/discord-intents.png new file mode 100644 index 00000000..7d6baf72 Binary files /dev/null and b/docs-site/static/images/discord-a2a/discord-intents.png differ diff --git a/docs-site/static/images/discord-a2a/discord-oauth2-1.png b/docs-site/static/images/discord-a2a/discord-oauth2-1.png new file mode 100644 index 00000000..c888e5d1 Binary files /dev/null and b/docs-site/static/images/discord-a2a/discord-oauth2-1.png differ diff --git a/docs-site/static/images/discord-a2a/discord-oauth2-2.png b/docs-site/static/images/discord-a2a/discord-oauth2-2.png new file mode 100644 index 00000000..9530b91e Binary files /dev/null and b/docs-site/static/images/discord-a2a/discord-oauth2-2.png differ diff --git a/docs-site/static/images/discord-a2a/discord-portal.png b/docs-site/static/images/discord-a2a/discord-portal.png new file mode 100644 index 00000000..fc45f670 Binary files /dev/null and b/docs-site/static/images/discord-a2a/discord-portal.png differ diff --git a/docs-site/static/images/discord-a2a/discord-token.png b/docs-site/static/images/discord-a2a/discord-token.png new file mode 100644 index 00000000..eede7cc4 Binary files /dev/null and b/docs-site/static/images/discord-a2a/discord-token.png differ diff --git a/docs-site/static/images/events/kagent-kubecon-atl-1.png b/docs-site/static/images/events/kagent-kubecon-atl-1.png new file mode 100644 index 00000000..ee637ee6 Binary files /dev/null and b/docs-site/static/images/events/kagent-kubecon-atl-1.png differ diff --git a/docs-site/static/images/first-agent-chat.png b/docs-site/static/images/first-agent-chat.png new file mode 100644 index 00000000..fb263dae Binary files /dev/null and b/docs-site/static/images/first-agent-chat.png differ diff --git a/docs-site/static/images/first-agent-discovery.png b/docs-site/static/images/first-agent-discovery.png new file mode 100644 index 00000000..79a88cb7 Binary files /dev/null and b/docs-site/static/images/first-agent-discovery.png differ diff --git a/docs-site/static/images/hero.png b/docs-site/static/images/hero.png new file mode 100644 index 00000000..86130f61 Binary files /dev/null and b/docs-site/static/images/hero.png differ diff --git a/docs-site/static/images/jaeger-landing.png b/docs-site/static/images/jaeger-landing.png new file mode 100644 index 00000000..b65b5102 Binary files /dev/null and b/docs-site/static/images/jaeger-landing.png differ diff --git a/docs-site/static/images/jaeger-trace.png b/docs-site/static/images/jaeger-trace.png new file mode 100644 index 00000000..f51db3b0 Binary files /dev/null and b/docs-site/static/images/jaeger-trace.png differ diff --git a/docs-site/static/images/k8s-agent-first-chat.png b/docs-site/static/images/k8s-agent-first-chat.png new file mode 100644 index 00000000..eed56e2d Binary files /dev/null and b/docs-site/static/images/k8s-agent-first-chat.png differ diff --git a/docs-site/static/images/k8s-agent-query-light.png b/docs-site/static/images/k8s-agent-query-light.png new file mode 100644 index 00000000..711724f9 Binary files /dev/null and b/docs-site/static/images/k8s-agent-query-light.png differ diff --git a/docs-site/static/images/k8s-agent-query.png b/docs-site/static/images/k8s-agent-query.png new file mode 100644 index 00000000..59530e53 Binary files /dev/null and b/docs-site/static/images/k8s-agent-query.png differ diff --git a/docs-site/static/images/k8s-agent-results.png b/docs-site/static/images/k8s-agent-results.png new file mode 100644 index 00000000..46c61133 Binary files /dev/null and b/docs-site/static/images/k8s-agent-results.png differ diff --git a/docs-site/static/images/kagent-agents-ui.gif b/docs-site/static/images/kagent-agents-ui.gif new file mode 100644 index 00000000..647059e5 Binary files /dev/null and b/docs-site/static/images/kagent-agents-ui.gif differ diff --git a/docs-site/static/images/kagent-chat-1.png b/docs-site/static/images/kagent-chat-1.png new file mode 100644 index 00000000..f1e87c39 Binary files /dev/null and b/docs-site/static/images/kagent-chat-1.png differ diff --git a/docs-site/static/images/kagent-config.png b/docs-site/static/images/kagent-config.png new file mode 100644 index 00000000..7a951e11 Binary files /dev/null and b/docs-site/static/images/kagent-config.png differ diff --git a/docs-site/static/images/kagent-default-k8s-agent.png b/docs-site/static/images/kagent-default-k8s-agent.png new file mode 100644 index 00000000..3cd51648 Binary files /dev/null and b/docs-site/static/images/kagent-default-k8s-agent.png differ diff --git a/docs-site/static/images/kagent-landing.png b/docs-site/static/images/kagent-landing.png new file mode 100644 index 00000000..cfce95b1 Binary files /dev/null and b/docs-site/static/images/kagent-landing.png differ diff --git a/docs-site/static/images/kagent-logo-dark.svg b/docs-site/static/images/kagent-logo-dark.svg new file mode 100644 index 00000000..e92925d4 --- /dev/null +++ b/docs-site/static/images/kagent-logo-dark.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs-site/static/images/kagent-logo-light.svg b/docs-site/static/images/kagent-logo-light.svg new file mode 100644 index 00000000..31bdc497 --- /dev/null +++ b/docs-site/static/images/kagent-logo-light.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs-site/static/images/kagent-logo-mark.png b/docs-site/static/images/kagent-logo-mark.png new file mode 100644 index 00000000..c1a5cc9c Binary files /dev/null and b/docs-site/static/images/kagent-logo-mark.png differ diff --git a/docs-site/static/images/kagent-memory.png b/docs-site/static/images/kagent-memory.png new file mode 100644 index 00000000..c9be94a3 Binary files /dev/null and b/docs-site/static/images/kagent-memory.png differ diff --git a/docs-site/static/images/kagent-new.png b/docs-site/static/images/kagent-new.png new file mode 100644 index 00000000..f31b47fb Binary files /dev/null and b/docs-site/static/images/kagent-new.png differ diff --git a/docs-site/static/images/kagent-rejected-content.png b/docs-site/static/images/kagent-rejected-content.png new file mode 100644 index 00000000..a08bff3d Binary files /dev/null and b/docs-site/static/images/kagent-rejected-content.png differ diff --git a/docs-site/static/images/kagent-tools-add.png b/docs-site/static/images/kagent-tools-add.png new file mode 100644 index 00000000..3d1c1734 Binary files /dev/null and b/docs-site/static/images/kagent-tools-add.png differ diff --git a/docs-site/static/images/kagent-wizard-finish.png b/docs-site/static/images/kagent-wizard-finish.png new file mode 100644 index 00000000..8edcd278 Binary files /dev/null and b/docs-site/static/images/kagent-wizard-finish.png differ diff --git a/docs-site/static/images/kagent-wizard-review.png b/docs-site/static/images/kagent-wizard-review.png new file mode 100644 index 00000000..7230db5e Binary files /dev/null and b/docs-site/static/images/kagent-wizard-review.png differ diff --git a/docs-site/static/images/kagent-wizard.png b/docs-site/static/images/kagent-wizard.png new file mode 100644 index 00000000..e00bcd51 Binary files /dev/null and b/docs-site/static/images/kagent-wizard.png differ diff --git a/docs-site/static/images/kmcp-inspector-echo-success.png b/docs-site/static/images/kmcp-inspector-echo-success.png new file mode 100644 index 00000000..513ac8a2 Binary files /dev/null and b/docs-site/static/images/kmcp-inspector-echo-success.png differ diff --git a/docs-site/static/images/kmcp-inspector-ov.png b/docs-site/static/images/kmcp-inspector-ov.png new file mode 100644 index 00000000..8814f61f Binary files /dev/null and b/docs-site/static/images/kmcp-inspector-ov.png differ diff --git a/docs-site/static/images/kmcp-local-echo-success.png b/docs-site/static/images/kmcp-local-echo-success.png new file mode 100644 index 00000000..4b66d438 Binary files /dev/null and b/docs-site/static/images/kmcp-local-echo-success.png differ diff --git a/docs-site/static/images/kmcp-local-go-echo-success.png b/docs-site/static/images/kmcp-local-go-echo-success.png new file mode 100644 index 00000000..023cc879 Binary files /dev/null and b/docs-site/static/images/kmcp-local-go-echo-success.png differ diff --git a/docs-site/static/images/kmcp-local-go-mytool-success.png b/docs-site/static/images/kmcp-local-go-mytool-success.png new file mode 100644 index 00000000..c2a3a1f3 Binary files /dev/null and b/docs-site/static/images/kmcp-local-go-mytool-success.png differ diff --git a/docs-site/static/images/kmcp-local-inspector-go-ov.png b/docs-site/static/images/kmcp-local-inspector-go-ov.png new file mode 100644 index 00000000..07764948 Binary files /dev/null and b/docs-site/static/images/kmcp-local-inspector-go-ov.png differ diff --git a/docs-site/static/images/kmcp-local-inspector-ov.png b/docs-site/static/images/kmcp-local-inspector-ov.png new file mode 100644 index 00000000..848e9ff0 Binary files /dev/null and b/docs-site/static/images/kmcp-local-inspector-ov.png differ diff --git a/docs-site/static/images/kmcp-local-mytool-success.png b/docs-site/static/images/kmcp-local-mytool-success.png new file mode 100644 index 00000000..f62b7f32 Binary files /dev/null and b/docs-site/static/images/kmcp-local-mytool-success.png differ diff --git a/docs-site/static/images/kubernetes-logo.png b/docs-site/static/images/kubernetes-logo.png new file mode 100644 index 00000000..a6062368 Binary files /dev/null and b/docs-site/static/images/kubernetes-logo.png differ diff --git a/docs-site/static/images/list-agents.png b/docs-site/static/images/list-agents.png new file mode 100644 index 00000000..af2688ad Binary files /dev/null and b/docs-site/static/images/list-agents.png differ diff --git a/docs-site/static/images/list-tool-servers.png b/docs-site/static/images/list-tool-servers.png new file mode 100644 index 00000000..b86b0282 Binary files /dev/null and b/docs-site/static/images/list-tool-servers.png differ diff --git a/docs-site/static/images/localdev-run-tui.png b/docs-site/static/images/localdev-run-tui.png new file mode 100644 index 00000000..d00f40a9 Binary files /dev/null and b/docs-site/static/images/localdev-run-tui.png differ diff --git a/docs-site/static/images/manage-tool-servers.png b/docs-site/static/images/manage-tool-servers.png new file mode 100644 index 00000000..8e737651 Binary files /dev/null and b/docs-site/static/images/manage-tool-servers.png differ diff --git a/docs-site/static/images/mcp-agent.png b/docs-site/static/images/mcp-agent.png new file mode 100644 index 00000000..730f96c2 Binary files /dev/null and b/docs-site/static/images/mcp-agent.png differ diff --git a/docs-site/static/images/mcp-tool-call.png b/docs-site/static/images/mcp-tool-call.png new file mode 100644 index 00000000..a18c58e5 Binary files /dev/null and b/docs-site/static/images/mcp-tool-call.png differ diff --git a/docs-site/static/images/modelselection.png b/docs-site/static/images/modelselection.png new file mode 100644 index 00000000..cd395df0 Binary files /dev/null and b/docs-site/static/images/modelselection.png differ diff --git a/docs-site/static/images/openclaw-icon.svg b/docs-site/static/images/openclaw-icon.svg new file mode 100644 index 00000000..bda5c35c --- /dev/null +++ b/docs-site/static/images/openclaw-icon.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/openclaw-logo.png b/docs-site/static/images/openclaw-logo.png new file mode 100644 index 00000000..1ef79fe0 Binary files /dev/null and b/docs-site/static/images/openclaw-logo.png differ diff --git a/docs-site/static/images/redesign/agentic-hero.png b/docs-site/static/images/redesign/agentic-hero.png new file mode 100644 index 00000000..3a6df2fa Binary files /dev/null and b/docs-site/static/images/redesign/agentic-hero.png differ diff --git a/docs-site/static/images/redesign/customer-logos/adk.svg b/docs-site/static/images/redesign/customer-logos/adk.svg new file mode 100644 index 00000000..d684b3f9 --- /dev/null +++ b/docs-site/static/images/redesign/customer-logos/adk.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/customer-logos/any-agent.svg b/docs-site/static/images/redesign/customer-logos/any-agent.svg new file mode 100644 index 00000000..db8cb52d --- /dev/null +++ b/docs-site/static/images/redesign/customer-logos/any-agent.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/customer-logos/any-mcp.svg b/docs-site/static/images/redesign/customer-logos/any-mcp.svg new file mode 100644 index 00000000..3d48a443 --- /dev/null +++ b/docs-site/static/images/redesign/customer-logos/any-mcp.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/customer-logos/any-skill.svg b/docs-site/static/images/redesign/customer-logos/any-skill.svg new file mode 100644 index 00000000..2a66ea6d --- /dev/null +++ b/docs-site/static/images/redesign/customer-logos/any-skill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/customer-logos/cncf.svg b/docs-site/static/images/redesign/customer-logos/cncf.svg new file mode 100644 index 00000000..14c69fe9 --- /dev/null +++ b/docs-site/static/images/redesign/customer-logos/cncf.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/customer-logos/crewai.svg b/docs-site/static/images/redesign/customer-logos/crewai.svg new file mode 100644 index 00000000..f48ac6d0 --- /dev/null +++ b/docs-site/static/images/redesign/customer-logos/crewai.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/customer-logos/langchain.svg b/docs-site/static/images/redesign/customer-logos/langchain.svg new file mode 100644 index 00000000..6ee86ccd --- /dev/null +++ b/docs-site/static/images/redesign/customer-logos/langchain.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/dashboard-1.png b/docs-site/static/images/redesign/dashboard-1.png new file mode 100644 index 00000000..db1f5070 Binary files /dev/null and b/docs-site/static/images/redesign/dashboard-1.png differ diff --git a/docs-site/static/images/redesign/dashboard-2.png b/docs-site/static/images/redesign/dashboard-2.png new file mode 100644 index 00000000..a249ad3e Binary files /dev/null and b/docs-site/static/images/redesign/dashboard-2.png differ diff --git a/docs-site/static/images/redesign/icons/discord.svg b/docs-site/static/images/redesign/icons/discord.svg new file mode 100644 index 00000000..3b96fd7d --- /dev/null +++ b/docs-site/static/images/redesign/icons/discord.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/icons/github.svg b/docs-site/static/images/redesign/icons/github.svg new file mode 100644 index 00000000..67d0aaad --- /dev/null +++ b/docs-site/static/images/redesign/icons/github.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/icons/slack.svg b/docs-site/static/images/redesign/icons/slack.svg new file mode 100644 index 00000000..ac8245b9 --- /dev/null +++ b/docs-site/static/images/redesign/icons/slack.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/kagent-agents.png b/docs-site/static/images/redesign/kagent-agents.png new file mode 100644 index 00000000..1a8c591e Binary files /dev/null and b/docs-site/static/images/redesign/kagent-agents.png differ diff --git a/docs-site/static/images/redesign/kagent-dashboard-hero.png b/docs-site/static/images/redesign/kagent-dashboard-hero.png new file mode 100644 index 00000000..074dca41 Binary files /dev/null and b/docs-site/static/images/redesign/kagent-dashboard-hero.png differ diff --git a/docs-site/static/images/redesign/kagent-hero.png b/docs-site/static/images/redesign/kagent-hero.png new file mode 100644 index 00000000..d771524e Binary files /dev/null and b/docs-site/static/images/redesign/kagent-hero.png differ diff --git a/docs-site/static/images/redesign/logos/kagent-logo.svg b/docs-site/static/images/redesign/logos/kagent-logo.svg new file mode 100644 index 00000000..8fc8d663 --- /dev/null +++ b/docs-site/static/images/redesign/logos/kagent-logo.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/docs-site/static/images/redesign/product-icons/kagent.svg b/docs-site/static/images/redesign/product-icons/kagent.svg new file mode 100644 index 00000000..c619d28f --- /dev/null +++ b/docs-site/static/images/redesign/product-icons/kagent.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/docs-site/static/images/slack-a2a/1-create-slack-app.png b/docs-site/static/images/slack-a2a/1-create-slack-app.png new file mode 100644 index 00000000..1ffddfdc Binary files /dev/null and b/docs-site/static/images/slack-a2a/1-create-slack-app.png differ diff --git a/docs-site/static/images/slack-a2a/2-name-workspace.png b/docs-site/static/images/slack-a2a/2-name-workspace.png new file mode 100644 index 00000000..97dd6a96 Binary files /dev/null and b/docs-site/static/images/slack-a2a/2-name-workspace.png differ diff --git a/docs-site/static/images/slack-a2a/app-in-slack.png b/docs-site/static/images/slack-a2a/app-in-slack.png new file mode 100644 index 00000000..371bddba Binary files /dev/null and b/docs-site/static/images/slack-a2a/app-in-slack.png differ diff --git a/docs-site/static/images/slack-a2a/app-level-token.png b/docs-site/static/images/slack-a2a/app-level-token.png new file mode 100644 index 00000000..3b9cff00 Binary files /dev/null and b/docs-site/static/images/slack-a2a/app-level-token.png differ diff --git a/docs-site/static/images/slack-a2a/bot-token-scopes.png b/docs-site/static/images/slack-a2a/bot-token-scopes.png new file mode 100644 index 00000000..5b974609 Binary files /dev/null and b/docs-site/static/images/slack-a2a/bot-token-scopes.png differ diff --git a/docs-site/static/images/slack-a2a/install-app.png b/docs-site/static/images/slack-a2a/install-app.png new file mode 100644 index 00000000..c68b5e8e Binary files /dev/null and b/docs-site/static/images/slack-a2a/install-app.png differ diff --git a/docs-site/static/images/slack-a2a/message-in-slack.png b/docs-site/static/images/slack-a2a/message-in-slack.png new file mode 100644 index 00000000..ceb37ed0 Binary files /dev/null and b/docs-site/static/images/slack-a2a/message-in-slack.png differ diff --git a/docs-site/static/images/slack-a2a/send-to-slack.png b/docs-site/static/images/slack-a2a/send-to-slack.png new file mode 100644 index 00000000..44b839d1 Binary files /dev/null and b/docs-site/static/images/slack-a2a/send-to-slack.png differ diff --git a/docs-site/static/images/slack-a2a/show-pods.png b/docs-site/static/images/slack-a2a/show-pods.png new file mode 100644 index 00000000..da0159c0 Binary files /dev/null and b/docs-site/static/images/slack-a2a/show-pods.png differ diff --git a/docs-site/static/images/slack-a2a/slack-a2a-kagent.png b/docs-site/static/images/slack-a2a/slack-a2a-kagent.png new file mode 100644 index 00000000..4d6035b8 Binary files /dev/null and b/docs-site/static/images/slack-a2a/slack-a2a-kagent.png differ diff --git a/docs-site/static/images/slack-a2a/slash-commands.png b/docs-site/static/images/slack-a2a/slash-commands.png new file mode 100644 index 00000000..150405aa Binary files /dev/null and b/docs-site/static/images/slack-a2a/slash-commands.png differ diff --git a/docs-site/static/images/telegram-bot/arch.png b/docs-site/static/images/telegram-bot/arch.png new file mode 100644 index 00000000..50538f86 Binary files /dev/null and b/docs-site/static/images/telegram-bot/arch.png differ diff --git a/docs-site/static/images/telegram-bot/telegram.gif b/docs-site/static/images/telegram-bot/telegram.gif new file mode 100644 index 00000000..5edad8b2 Binary files /dev/null and b/docs-site/static/images/telegram-bot/telegram.gif differ diff --git a/public/sitemap.xml b/public/sitemap.xml index dcd24913..6307579c 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -2,840 +2,840 @@ https://kagent.dev/agents - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/blog - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/community - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/concepts/agent-harness - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/concepts/agent-memory - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/concepts/agent-substrate - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/concepts/agents - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/concepts/architecture - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/concepts - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/concepts/tools - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/a2a-agents - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/a2a-byo - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/agent-harness - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/agent-substrate - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/agentgateway - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/agents-mcp - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/crewai-byo - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/discord-a2a - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/documentation - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/human-in-the-loop - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/langchain-byo - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/skills - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/slack-a2a - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/examples/telegram-bot - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/getting-started/first-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/getting-started/first-mcp-tool - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/getting-started/local-development - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/getting-started - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/getting-started/quickstart - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/getting-started/system-prompts - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/introduction/features - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/introduction/installation - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/introduction - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/introduction/what-is-kagent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/observability/audit-prompts - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/observability/launch-ui - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/observability - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/observability/tracing - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/operations/debug - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/operations/operational-considerations - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/operations - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/operations/uninstall - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/operations/upgrade - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/api-ref - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-add-mcp - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-bug-report - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-build - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-completion - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-dashboard - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-deploy - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-get - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-help - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-init - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-install - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-invoke - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-mcp - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-run - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-uninstall - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli/kagent-version - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/cli - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/faq - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/helm - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/release-notes - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/resources/tools-ecosystem - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/amazon-bedrock - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/anthropic - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/azure-openai - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/byo-openai - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/gemini - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/google-vertexai - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/ollama - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/openai - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/sap-ai-core - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kagent/supported-providers/xai - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/deploy/install-controller - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/deploy - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/deploy/server - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/develop/fastmcp-python - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/develop/mcp-go - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/develop - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/introduction - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/quickstart - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/api-ref - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-add-tool - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-build - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-completion - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-deploy - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-help - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-init - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-install - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-run - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference/kmcp-secrets - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/reference - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs/kmcp/secrets - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/docs - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/enterprise - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/page.tsx - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/agents/argo-rollouts-conversion-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/agents/cilium-crd-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/agents/helm-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/agents/istio-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/agents/k8s-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/agents/kgateway-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/agents/observability-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/agents/promql-agent - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/istio - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/kubernetes - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/prometheus - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/documentation - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/helm - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/argo - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/grafana - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/other - 2026-06-26 + 2026-07-10 weekly 0.8 https://kagent.dev/tools/cilium - 2026-06-26 + 2026-07-10 weekly 0.8 diff --git a/scripts/mdx-to-hugo.mjs b/scripts/mdx-to-hugo.mjs new file mode 100644 index 00000000..c609e554 Binary files /dev/null and b/scripts/mdx-to-hugo.mjs differ diff --git a/src/app/agents/layout.tsx b/src/app/agents/layout.tsx deleted file mode 100644 index 92eab50b..00000000 --- a/src/app/agents/layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from "react"; -import DocsLayoutClient from "../docs/DocsLayoutClient"; -import navigationData from "@/config/navigation.json"; - -interface NavItem { - title: string; - href: string; - items?: NavItem[]; - external?: boolean; -} - -export default function AgentsLayout({ children }: { children: React.ReactNode }) { - const navigation: NavItem[] = navigationData as NavItem[]; - - return ( - - {children} - - ); -} diff --git a/src/app/docs/kagent/resources/release-notes/page.mdx b/src/app/docs/kagent/resources/release-notes/page.mdx index 3d42b59f..45e0084a 100644 --- a/src/app/docs/kagent/resources/release-notes/page.mdx +++ b/src/app/docs/kagent/resources/release-notes/page.mdx @@ -535,7 +535,7 @@ spec: ```
    -
    +
    In v0.6, you add certain fields to designate the Service as an MCP server. In the following configuration file, notice the following settings: diff --git a/src/app/tools/layout.tsx b/src/app/tools/layout.tsx deleted file mode 100644 index 9d55450d..00000000 --- a/src/app/tools/layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from "react"; -import DocsLayoutClient from "../docs/DocsLayoutClient"; -import navigationData from "@/config/navigation.json"; - -interface NavItem { - title: string; - href: string; - items?: NavItem[]; - external?: boolean; -} - -export default function ToolsLayout({ children }: { children: React.ReactNode }) { - const navigation: NavItem[] = navigationData as NavItem[]; - - return ( - - {children} - - ); -} diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx index 2e1e01c3..5114ac0f 100644 --- a/src/components/navbar.tsx +++ b/src/components/navbar.tsx @@ -2,13 +2,11 @@ import Link from "next/link"; import { GITHUB_LINK } from "@/data/links"; import { useState } from "react"; -import { usePathname } from "next/navigation"; import KagentLogoWithText from "./icons/kagent-logo-text"; import KagentLogo from "./icons/kagent-logo"; import KMCPIcon from "./icons/kmcpicon"; import { ThemeToggle } from "./theme-toggle"; -import { Button } from "./ui/button"; -import { Menu, X, ChevronDown } from "lucide-react"; +import { Menu, X, ChevronDown, Github } from "lucide-react"; import { DocSearch } from "@docsearch/react"; import { DropdownMenu, @@ -17,296 +15,153 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +/* + * Marketing navbar — styled to match the Hugo/Hextra docs top nav so switching + * between the marketing pages and /docs isn't jarring. Mirrors the docs nav's + * layout (logo left; Docs dropdown + marketing links + search + GitHub icon + + * theme toggle on the right), uniform gray link styling (no active bold/underline), + * height, and light/dark colors. The docs nav is rendered by Hugo + * (docs-site/layouts/_partials/navbar-link.html); keep the two visually in sync. + */ + +// Uniform link styling — matches the docs nav (no active-state emphasis, since +// most links are cross-section and would rarely be "active" anyway). +const linkCls = + "text-sm whitespace-nowrap text-gray-600 transition-colors hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200"; + +const marketingLinks = [ + { href: "/blog", label: "Blog" }, + { href: "/tools", label: "Tools" }, + { href: "/agents", label: "Agents" }, + { href: "/community", label: "Community" }, + { href: "/enterprise", label: "Enterprise" }, +]; + +// Docs products for the dropdown (mirrors the docs nav's kagent/kmcp menu). +const docsProducts = [ + { href: "/docs/kagent", label: "kagent", Icon: KagentLogo }, + { href: "/docs/kmcp", label: "kmcp", Icon: KMCPIcon }, +]; + export default function Navbar() { const [isMenuOpen, setIsMenuOpen] = useState(false); - const pathname = usePathname(); - - const isActive = (href: string) => { - if (href === "/") return pathname === "/"; - return pathname.startsWith(href); - }; return ( -
    +
    + )} ); } diff --git a/src/components/theme-toggle.tsx b/src/components/theme-toggle.tsx index 11bd7d5e..bb20379f 100644 --- a/src/components/theme-toggle.tsx +++ b/src/components/theme-toggle.tsx @@ -13,7 +13,7 @@ export function ThemeToggle() { return ( -