All skills
Skillintermediate

Kubernetes support — implementation plan

- **Feature:** kubernetes-support - **Design:** [design.md](design.md) - **Tasks:** [tasks.md](tasks.md) - **Status:** implementation-plan - **Branch:** `k8s_support`

Claude Code Knowledge Pack7/10/2026

Overview

Kubernetes support — implementation plan

  • Feature: kubernetes-support
  • Design: design.md
  • Tasks: tasks.md
  • Status: implementation-plan
  • Branch: k8s_support

This document is a step-by-step guide for implementing the design. Each step is paired with an explicit verification. Tasks in tasks.md reference the corresponding steps here.

Conventions

  • All file paths in this document are relative to the repository root unless noted otherwise.
  • Each step's verify clause specifies how the implementer confirms the step succeeded. Steps without a verification are not considered complete.
  • Commits are atomic per task in tasks.md; a task may span multiple steps here, but the steps collectively map to one self-contained commit.
  • The order of steps within a phase is significant; dependencies are stated explicitly where a later step requires the output of an earlier one.

Prerequisites

Before starting P0:

  1. The three ADRs (0001, 0002, 0003) have been authored in docs/adr/.
  2. docs/wip/kubernetes-support/ exists with this file, design.md, and tasks.md.
  3. The branch k8s_support is checked out (confirm with git branch --show-current).
  4. The plugin-structure test currently passes on the branch (confirm with bash test/test-plugin-structure.sh — captures the pre-P0 baseline).

Phase 0 — Profile-first refactor

Goal. Introduce klaude-plugin/profiles/ as a top-level directory; migrate programming-language checklist content from klaude-plugin/skills/review-code/reference/<lang>/ to klaude-plugin/profiles/<lang>/review-code/; author the shared detection procedure and the six consumer symlinks; restructure the review-code workflow to be index-driven; update the plugin-structure test, CLAUDE.md, and README.md. Behavior must remain equivalent to pre-P0 when review-code is invoked on diffs affecting the existing programming-language profiles.

Step 0.1 — Create the profiles/ top level and migrate programming-language checklists

For each language in (go, python, java, js_ts, kotlin):

  1. Create directory klaude-plugin/profiles/<lang>/review-code/.
  2. Move the existing files from klaude-plugin/skills/review-code/reference/<lang>/ to klaude-plugin/profiles/<lang>/review-code/ using git mv (preserves history).
  3. Author klaude-plugin/profiles/<lang>/DETECTION.md using the mandatory three-section schema (see design.md §Detection mechanics): ## Path signals (empty for programming-language profiles; file-extension detection does not involve path heuristics), ## Filename signals (empty — language detection is extension-based, not filename-based), ## Content signals (the file-extension rule: "any file whose extension matches .go / .py / etc."). The three sections must be present even when empty, so the shared procedure iterates predictably.
  4. Author klaude-plugin/profiles/<lang>/overview.md — a one-page summary: what the profile covers (the programming language), when it activates, and "Looking up dependencies" targets (context7, language-specific references).
  5. Author klaude-plugin/profiles/<lang>/review-code/index.md — lists the four migrated files (security-checklist.md, solid-checklist.md, code-quality-checklist.md, removal-plan.md) in the "Always load" section with one-line descriptions. No conditional entries for programming-language profiles.
  6. Remove the now-empty klaude-plugin/skills/review-code/reference/<lang>/ directory.

After iterating through all five languages, remove klaude-plugin/skills/review-code/reference/ itself (now empty).

Audit downstream migration impact. Check .github/scripts/template-sync.sh for a run_plugin_migration function with a dirs_to_remove array (or equivalent mechanism). Determine whether the removal of klaude-plugin/skills/review-code/reference/ requires an entry there to clean up downstream projects that have migrated from an older template version. Document the decision (add an entry OR document that no entry is needed — CLAUDE.md's "don't touch historical entries" directive covers pre-v0.5.0 historical paths, not new migrations introduced by this feature). If an entry is added, follow the existing entry format and date the addition.

Verify.

  • ls klaude-plugin/profiles/ shows exactly go, java, js_ts, kotlin, python (plus, after P1, k8s).
  • ls klaude-plugin/skills/review-code/reference/ returns "No such file or directory".
  • For each language: test -f klaude-plugin/profiles/<lang>/{DETECTION.md,overview.md,review-code/index.md} succeeds.
  • For each language: the profile's DETECTION.md contains the three required sections (## Path signals, ## Filename signals, ## Content signals) — any may be empty but all three headings must be present.
  • git log --follow klaude-plugin/profiles/go/review-code/security-checklist.md shows history continuous with the old path.
  • Template-sync audit decision documented in the PR description or as a comment in template-sync.sh.

Step 0.2 — Author the shared profile-detection procedure

Create klaude-plugin/skills/_shared/profile-detection.md with the following mandatory sections:

  1. Purpose. Single source of truth for "compute the set of active profiles for the current context." Used by six consuming skills; the shared file exists to prevent interpretation drift.
  2. Per-consumer input model. Enumerate what each consuming skill passes as detection input:
    • review-code → git diff (staged or explicit range, scoped to the diff's touched files).
    • review-spec → git diff when invoked standalone; the feature directory's full file list when invoked by implement.
    • test → git diff (mid-feature) or full feature-directory file list (post-implementation).
    • implement → the current sub-task's target file list, optionally augmented by the diff accumulated so far.
    • design → user-declared signal OR keyword inference from the idea prose. Detection in the design phase is not file-based. The file must spell out the interaction: "check idea prose against the high-precision auto-trigger set (Kubernetes, K8s, Helm chart, kubectl, kustomize, manifest.yaml, Deployment resource, StatefulSet, DaemonSet, CronJob); if any match, ask the user to confirm activation. If no auto-trigger matches but the idea is ambiguous — names infrastructure, deployment, runtime, or platform concerns without naming a specific technology, or includes tokens like cluster/namespace/pod that collide with non-K8s meanings — ask explicitly." Rationale: the narrow auto-trigger set avoids noisy false positives from overloaded tokens.
    • document → the feature directory's current file list; diff is optional.
  3. Detection algorithm. Iterate klaude-plugin/profiles/*/DETECTION.md. For each profile, evaluate signals in cost order (path → filename → content). Apply authority rule: filename or content signal matches activate the profile; path signal alone does not activate. Bounded content inspection: ~16 KB per file; multi-document YAML inspected per ----separated block. Every profile's DETECTION.md uses the three-section schema (## Path signals / ## Filename signals / ## Content signals); the shared procedure applies the same algorithm against each profile's declared values.
  4. Unset-variable check. Before returning results, verify ${CLAUDE_PLUGIN_ROOT} is set. If unset: emit a loud error message naming the variable and pointing at CLAUDE.md's Profile Conventions section; return the empty-set result so consumers fall back to generic guidance rather than panicking. (Per ADR 0003 §Decision, the brace form is mandatory — $CLAUDE_PLUGIN_ROOT without braces is NOT substituted by the Claude Code harness and will never be used here.)

Authoring caveat for the shared file itself. klaude-plugin/skills/_shared/profile-detection.md lives INSIDE the plugin tree and is therefore subject to ${CLAUDE_PLUGIN_ROOT} substitution when an agent reads it. When the file needs to describe the variable BY NAME (e.g., "check that $CLAUDE_PLUGIN_ROOT is set"), use the bare form $CLAUDE_PLUGIN_ROOT (without braces) — the bare form is not substituted (verified 2026-04-18, ADR 0003 §Verification). When the file uses the variable as a PATH that must resolve at runtime (e.g., ${CLAUDE_PLUGIN_ROOT}/profiles/*/DETECTION.md), use the brace form — that is the intended substitution. Mixing the two conventions in the same file is normal and correct. 5. Output shape. A list of records, one per matched profile: {profile: <name>, triggered_by: [<signal descriptions>], files: [<paths>]}. triggered_by names the signal type that fired (e.g., "filename: Chart.yaml", "content: apiVersion+kind in block 2").

Verify. test -f klaude-plugin/skills/_shared/profile-detection.md. The file contains all five sections by heading. File size is ~120–200 lines (a few pages; not a brief summary). Content is readable by a skilled contributor unfamiliar with the plugin — pass it to a colleague for a sanity read.

Step 0.3 — Create the six consumer symlinks

Create the following symlinks (each is shared-profile-detection.md pointing at ../_shared/profile-detection.md):

  • klaude-plugin/skills/review-code/shared-profile-detection.md
  • klaude-plugin/skills/review-spec/shared-profile-detection.md
  • klaude-plugin/skills/design/shared-profile-detection.md
  • klaude-plugin/skills/implement/shared-profile-detection.md
  • klaude-plugin/skills/test/shared-profile-detection.md
  • klaude-plugin/skills/document/shared-profile-detection.md

Verify.

  • For each symlink path P: test -L P succeeds; readlink P returns ../_shared/profile-detection.md; realpath P resolves to the shared file.

Step 0.4 — Restructure the review-code workflow

Update the following files to consume shared-profile-detection.md and the index-driven loading pattern. Each file needs specific literal-string replacements, not just behavioral intent — the old prose hardcodes reference/<lang>/ paths in multiple places, and the grep verification below catches missed replacements.

  • klaude-plugin/skills/review-code/SKILL.md — prose gains a sentence linking [shared-profile-detection.md](shared-profile-detection.md) (per CLAUDE.md convention: consumers reference the per-skill symlink, not the shared source). No change to the description frontmatter.
  • klaude-plugin/skills/review-code/review-process.md:
    • "Step 2: Detect primary language" renames to "Step 2: Detect active profiles" and delegates to the shared procedure.
    • Former Steps 3–6 (SOLID / Removal / Security / Quality) collapse into:
      • "Step 3: Load profile review indexes." For each active profile, resolve ${CLAUDE_PLUGIN_ROOT}/profiles/<name>/review-code/index.md; collect always-load entries and conditional entries whose stated triggers match the diff.
      • "Step 4: Apply checklists." Iterate the resolved checklists; each checklist's findings are emitted with (profile, checklist) as the grouping key.
    • Subsequent steps (self-check, indexing, output formatting) are renumbered but otherwise unchanged.
    • Replace every literal occurrence of reference/<lang>/ and reference/{lang}/ (any variant) with the ${CLAUDE_PLUGIN_ROOT}/profiles/... equivalent or a description of the index-driven loading step.
  • klaude-plugin/skills/review-code/review-isolated.md — the same restructure pattern, adapted for the isolated sub-agent variant.
    • Literal path string to replace: the sub-agent prompt template in Step 2 currently injects klaude-plugin/skills/review-code/reference/{language_key}/ into the spawned agent's prompt. This literal string must be replaced with the list of resolved checklists (produced in Step 1 when preparing the scope block). The sub-agent receives the list, not a path.
    • Replace every other literal occurrence of reference/<lang>/ in the file.
  • klaude-plugin/agents/code-reviewer.md — the prompt updates to iterate the (profile, checklist) list it is given, rather than iterating fixed category names.
    • Literal path string to replace: the agent's current Step 2 says "Load the corresponding reference checklists from klaude-plugin/skills/review-code/reference/{lang}/" with the full extension table duplicated. Rewrite to: "Apply the checklists provided in the input payload; for each (profile, checklist) record, read the checklist content from ${CLAUDE_PLUGIN_ROOT}/profiles/<profile>/review-code/<checklist> and apply it to the diff." Remove the extension table (detection is no longer the agent's responsibility; the calling skill has already produced the list).

Verify.

  • Grep check (expanded scope to include agents/): grep -rn 'reference/' klaude-plugin/skills/review-code/ klaude-plugin/agents/code-reviewer.md returns no lines. If any remain, replacement was incomplete.
  • Grep check: grep -rn '${CLAUDE_PLUGIN_ROOT}/profiles/' klaude-plugin/skills/review-code/ returns matches at the relevant points (Step 3 of review-process.md, equivalent in review-isolated.md).
  • Manual dry-run: invoke /kk:review-code on a Go-only diff (e.g., a recent commit touching only .go files). The output identifies the go profile as active and loads the four checklists now at profiles/go/review-code/. Findings coverage and categories match pre-P0 output qualitatively.
  • klaude-plugin/agents/code-reviewer.md parses cleanly (front-matter valid, instructions coherent on a manual read).

Step 0.5 — Update the plugin-structure test

Modify test/test-plugin-structure.sh:

  • Add EXPECTED_PROFILES=("go" "java" "js_ts" "kotlin" "python") (k8s will be added in alphabetical position in Step 1.3 of P1, after k8s content files exist; the array is alphabetised and the structure test treats it as a set).
  • Per-profile assertions (presence-conditional). Assertions are predicated on what the profile declares; they do NOT require every profile to populate every phase subdirectory:
    • Directory klaude-plugin/profiles/<name>/ exists (required for every profile in EXPECTED_PROFILES).
    • File klaude-plugin/profiles/<name>/DETECTION.md exists (required).
    • DETECTION.md contains the three required section headings (## Path signals, ## Filename signals, ## Content signals). Any may be empty; all must be present. Use grep -c '^## Path signals' ... and similar to verify each header appears exactly once.
    • File klaude-plugin/profiles/<name>/overview.md exists (required).
    • For each phase subdirectory name in (review-code, design, test, implement, document, review-spec): IF `klaude-plugin/profiles/<