Skip to content

feat: ship kagent 1.x skills bundle in the tools OCI image - #91

Merged
danielle-mustillo merged 4 commits into
mainfrom
feat/kagent-skills-bundle
Oct 29, 2026
Merged

danielle-mustillo merged 4 commits into
mainfrom
feat/kagent-skills-bundle

Conversation

@dimetron

@dimetron dimetron commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Makes the kagent-tools image usable as a kagent 1.x Agent Plugin (OCI image source), bundling every CLI tool plus skills.

Image layout

  • /opt/kagent-tools — full bundle: stdio MCP server (plugin.json + mcp.json), kubectl, helm, istioctl, kubectl-argo-rollouts, cilium, plugin kubeconfig, skills
  • /opt/kagent-tools-skills — skills-only root, for use alongside the Helm-deployed server
  • Legacy /tool-server and /bin/* preserved as symlinks (Helm chart unchanged)

Changes

  • 7 skills in plugin/skills/ (k8s, helm, istio, argo rollouts, cilium, kubescape, prometheus)
  • Env fallbacks: KAGENT_TOOLS_TOOLS, KAGENT_TOOLS_READ_ONLY, KAGENT_TOOLS_DEFAULT_KUBECONFIG; resolved kubeconfig exported to all CLIs
  • Fix: stdio mode no longer writes trace output to stdout (would corrupt the MCP stream)
  • Tests: cmd/plugin_bundle_test.go (manifests, frontmatter, every skill-referenced tool is registered), cmd/plugin_image_test.go (mirrors kagent validatePackage)
  • make plugin-verify + plugin-verify CI job
  • Docs: docs/kagent-skills.md, README, AGENTS.md; design + plan under docs/superpowers/

Known limitation

kagent's current 100 MiB per-package limit rejects the full root (~546 MiB). The skills-only root works on current kagent. The full root needs an upstream kagent change exempting platform-mounted OCI packages (Task 0 in the plan). The bundled MCP server is only started by the Go ADK harness.

Testing

  • make test-only ✅, go vet ✅, golangci-lint v2.15.0 ✅ (pinned v2.13.2 can't load Go 1.27 export data — pre-existing)
  • make plugin-verify ✅ (layout check + stdio tools/list smoke test)
  • Validated against kagent's real materializer: skills-only root loads all 7 skills; full root resolves the stdio server correctly once the size limit is lifted
  • Not yet tested on a live kagent cluster (exec / streaming logs via egress gateway)

Toolchain

  • Go bumped to 1.27.3 (latest); golangci-lint pin v2.13.2 → v2.15.0 (v2.13.2 cannot load Go 1.27 export data)

Make the kagent-tools image usable as a kagent 1.x Agent Plugin source:

- /opt/kagent-tools: full bundle (stdio MCP server, kubectl, helm,
  istioctl, kubectl-argo-rollouts, cilium, kubeconfig, skills)
- /opt/kagent-tools-skills: skills-only root for use with the
  Helm-deployed server
- seven SKILL.md skills, one per tool provider
- legacy /tool-server and /bin/* paths preserved as symlinks
- env fallbacks (KAGENT_TOOLS_TOOLS, KAGENT_TOOLS_READ_ONLY,
  KAGENT_TOOLS_DEFAULT_KUBECONFIG); kubeconfig exported to all CLIs
- stdio mode keeps stdout clean (trace exporter writes to stderr)
- plugin bundle/image tests, make plugin-verify, CI job, docs

Co-authored-by: Copilot App <[email protected]>
Signed-off-by: Dmytro Rashko <[email protected]>
@dimetron
dimetron requested a review from EItanya as a code owner October 24, 2026 23:46
dimetron and others added 2 commits October 25, 2026 02:19
golangci-lint v2.13.2 cannot load Go 1.27 export data, so the lint pin
moves with the toolchain.

Co-authored-by: Copilot App <[email protected]>
Signed-off-by: Dmytro Rashko <[email protected]>
- track plugin/mcp.json (a global **/mcp.json ignore had dropped it)
- docs: omit apiGroup on RemoteMCPServer refs (kagent CEL rejects it)
- share logger.UseStderrEnv/UseStderr instead of repeated literals
- move env export out of run() into tested applyServerEnvironment,
  propagating Setenv errors
- generic decodeStrict without any; KUBECONFIG constant
- image test: resolve root symlinks, assert /usr/bin legacy links
- verify script runs /tool-server, /bin/kubectl and /bin/helm

Co-authored-by: Copilot App <[email protected]>
Signed-off-by: Dmytro Rashko <[email protected]>

@danielle-mustillo danielle-mustillo left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 written by AI, but I extensively reviewed and vetted every suggestion/comment. 🤖

Thanks for putting this together. Shipping the skills inside the tools image is a nice way to keep skills and tool names in step. I checked it against current kagent and left some comments. Each one has a suggested change, and I applied all of them together on top of this branch to check them: go test -tags=test ./pkg/... ./internal/... ./cmd/..., make lint and make plugin-verify all pass.

The main point: kagent's plugin loader applies its 100 MiB package limit to mounted OCI images too (maxPackageBytes in go/core/pkg/agentplugins/materialize.go in kagent-dev/kagent). I ran that loader (agentplugins.Materialize, kagent main at d9cc3a82) against this branch's image, unpacked:

opt/kagent-tools:        REJECTED: validate mounted artifact: artifact exceeds 104857600 bytes
opt/kagent-tools-skills: ACCEPTED (k8s-troubleshooting/SKILL.md copied)

So the skills-only root, plus the tool server deployed by the Helm chart, is the path that works today. Most of the comments follow from that.

Also, could you drop docs/superpowers/? Those plan and spec files don't belong in the repo, and docs/kagent-skills.md already covers the user-facing content.

Comment thread README.md Outdated
Comment thread docs/kagent-skills.md Outdated
Comment thread docs/kagent-skills.md
Comment thread docs/kagent-skills.md Outdated
Comment thread docs/kagent-skills.md Outdated
Comment thread Dockerfile
Comment thread Dockerfile Outdated
Comment thread plugin/skills/istio-traffic-debugging/SKILL.md Outdated
Comment thread plugin/skills/istio-traffic-debugging/SKILL.md
Comment thread plugin/skills/cilium-network-debugging/SKILL.md Outdated
- prometheus: read PROMETHEUS_URL as the default endpoint for all tools
- skills: align arguments with real tool schemas (cilium node_name and
  ids, istio pod discovery and istio-proxy access log, argo
  container=image, kubescape manifest_name, k8s previous logs) and drop
  the LLM-backed prometheus_promql_tool reference
- docs/README: lead with the skills-only root that works on kagent 1.x
  today, add modelConfig and an explicit tools list to AgentTemplates,
  mark the full root as needing a future kagent release
- Dockerfile: plugin stage only assembles small files on wolfi-base; the
  final image has three content layers ordered by change frequency
  (CLIs, plugin files, Go server) so a code or skill change does not
  re-ship the CLI layer
- tests: validate skill `arg: value` references against tool input
  schemas, deny LLM-backed tools in skills, lint the guide's
  AgentTemplates (modelConfig, binding kind, <=50 tools, pinned digest,
  tool coverage)
- remove docs/superpowers design notes

Co-authored-by: Copilot App <[email protected]>
Signed-off-by: Dmytro Rashko <[email protected]>
@dimetron

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough review, @danielle-mustillo. Every item is addressed in cc1e04e, and all threads are resolved.

Review items

# Item Fix
1 README wording Uses your text: skills-only first, full root needs a future kagent release
2 Docs heading Guide leads with skills-only; full root moved to its own section, with the 100 MiB limit
3–4 modelConfig Both AgentTemplates set modelConfig
5 Tools list Skills-only binding lists the 11 tools it needs (≤50 per binding, ≤128 per model request)
6 PROMETHEUS_URL not read Now the default endpoint for all prometheus tools (+ test)
7 prometheus_promql_tool Removed from the skill
8–9 Dockerfile layers Plugin stage on wolfi-base; final stage has 3 layers ordered by change frequency: CLIs 504 MB, plugin 98 kB, server 69 MB
10–11 istio Pod discovery step; response flag read from the istio-proxy access log
12 cilium node Find the node first, then pass node_name; ids come from the list output
— docs/superpowers Removed

Same-class fixes found by sweeping the other skills

  • argo: container_image: <container>=<image>, and the tool description is clarified
  • kubescape: list manifests, then pass manifest_name (the tools have no severity filter)
  • k8s: previous: true for logs from crashed containers

New guards, so these classes fail CI

  • Each `arg: value` in a skill must be an input property of the tool named on that line.
  • Skills may not reference LLM-backed tools.
  • cmd/plugin_docs_test.go lints the guide's AgentTemplates: modelConfig, RemoteMCPServer with no apiGroup, ≤50 registered tools, a digest-pinned OCI ref, and the tools list covers what the skills use.

Follow-ups (pre-existing issues, out of scope here): #92 chart env vars nothing reads · #93 LLM-backed tools registered without an LLM · #94 LOG_LEVEL · #95 CLI checksum verification · #96 Grafana provider via gcx

@danielle-mustillo

Copy link
Copy Markdown

Thanks, every review item is fixed. I filed #97 as a follow-up, not a blocker: publish the skills-only root as its own small image, so an Agent that mounts it doesn't pull the whole tools image.

@danielle-mustillo
danielle-mustillo merged commit a6597e2 into main Oct 29, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants