@intentius/chant-lexicon-k8s 0.0.22 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/integrity.json +9 -4
  2. package/dist/manifest.json +1 -1
  3. package/dist/skills/chant-k8s-aks.md +146 -0
  4. package/{src/skills/kubernetes-patterns.md → dist/skills/chant-k8s-deployment-strategies.md} +1 -1
  5. package/dist/skills/chant-k8s-eks.md +156 -0
  6. package/dist/skills/chant-k8s-gke.md +246 -0
  7. package/{src/skills/kubernetes-security.md → dist/skills/chant-k8s-security.md} +1 -1
  8. package/dist/skills/chant-k8s.md +65 -2
  9. package/package.json +1 -1
  10. package/src/composites/adot-collector.ts +34 -22
  11. package/src/composites/agic-ingress.ts +14 -6
  12. package/src/composites/aks-external-dns-agent.ts +29 -18
  13. package/src/composites/alb-ingress.ts +14 -6
  14. package/src/composites/autoscaled-service.ts +25 -20
  15. package/src/composites/azure-disk-storage-class.ts +14 -6
  16. package/src/composites/azure-file-storage-class.ts +14 -6
  17. package/src/composites/azure-monitor-collector.ts +34 -22
  18. package/src/composites/batch-job.ts +25 -17
  19. package/src/composites/cockroachdb-cluster.ts +148 -58
  20. package/src/composites/composites.test.ts +369 -363
  21. package/src/composites/config-connector-context.ts +15 -8
  22. package/src/composites/configured-app.ts +21 -15
  23. package/src/composites/cron-workload.ts +25 -20
  24. package/src/composites/ebs-storage-class.ts +14 -6
  25. package/src/composites/efs-storage-class.ts +14 -6
  26. package/src/composites/external-dns-agent.ts +26 -20
  27. package/src/composites/filestore-storage-class.ts +14 -6
  28. package/src/composites/fluent-bit-agent.ts +30 -24
  29. package/src/composites/gce-ingress.ts +14 -6
  30. package/src/composites/gce-pd-storage-class.ts +14 -6
  31. package/src/composites/gke-external-dns-agent.ts +34 -21
  32. package/src/composites/gke-fluent-bit-agent.ts +34 -22
  33. package/src/composites/gke-gateway.ts +19 -12
  34. package/src/composites/gke-otel-collector.ts +34 -22
  35. package/src/composites/irsa-service-account.ts +22 -14
  36. package/src/composites/metrics-server.ts +41 -26
  37. package/src/composites/monitored-service.ts +26 -19
  38. package/src/composites/namespace-env.ts +26 -17
  39. package/src/composites/network-isolated-app.ts +21 -16
  40. package/src/composites/node-agent.ts +33 -22
  41. package/src/composites/secure-ingress.ts +19 -11
  42. package/src/composites/sidecar-app.ts +17 -12
  43. package/src/composites/stateful-app.ts +21 -12
  44. package/src/composites/web-app.ts +25 -21
  45. package/src/composites/worker-pool.ts +40 -26
  46. package/src/composites/workload-identity-sa.ts +22 -14
  47. package/src/composites/workload-identity-service-account.ts +22 -16
  48. package/src/plugin.ts +40 -614
  49. package/src/serializer.ts +3 -0
  50. package/src/skills/chant-k8s-deployment-strategies.md +183 -0
  51. package/src/skills/chant-k8s-gke.md +55 -0
  52. package/src/skills/chant-k8s-patterns.md +245 -0
  53. package/src/skills/chant-k8s-security.md +237 -0
  54. package/src/skills/chant-k8s.md +305 -0
package/src/plugin.ts CHANGED
@@ -6,10 +6,13 @@
6
6
  */
7
7
 
8
8
  import { createRequire } from "module";
9
- import type { LexiconPlugin, SkillDefinition, InitTemplateSet, ResourceMetadata } from "@intentius/chant/lexicon";
9
+ import type { LexiconPlugin, InitTemplateSet, ResourceMetadata } from "@intentius/chant/lexicon";
10
10
  const require = createRequire(import.meta.url);
11
11
  import type { LintRule } from "@intentius/chant/lint/rule";
12
- import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
12
+ import { discoverPostSynthChecks } from "@intentius/chant/lint/discover";
13
+ import { createSkillsLoader, createDiffTool, createCatalogResource } from "@intentius/chant/lexicon-plugin-helpers";
14
+ import { join, dirname } from "path";
15
+ import { fileURLToPath } from "url";
13
16
  import { k8sSerializer } from "./serializer";
14
17
 
15
18
  export const k8sPlugin: LexiconPlugin = {
@@ -23,36 +26,9 @@ export const k8sPlugin: LexiconPlugin = {
23
26
  return [hardcodedNamespaceRule, latestImageTagRule, missingResourceLimitsRule];
24
27
  },
25
28
 
26
- postSynthChecks(): PostSynthCheck[] {
27
- const { wk8005 } = require("./lint/post-synth/wk8005");
28
- const { wk8006 } = require("./lint/post-synth/wk8006");
29
- const { wk8041 } = require("./lint/post-synth/wk8041");
30
- const { wk8042 } = require("./lint/post-synth/wk8042");
31
- const { wk8101 } = require("./lint/post-synth/wk8101");
32
- const { wk8102 } = require("./lint/post-synth/wk8102");
33
- const { wk8103 } = require("./lint/post-synth/wk8103");
34
- const { wk8104 } = require("./lint/post-synth/wk8104");
35
- const { wk8105 } = require("./lint/post-synth/wk8105");
36
- const { wk8201 } = require("./lint/post-synth/wk8201");
37
- const { wk8202 } = require("./lint/post-synth/wk8202");
38
- const { wk8203 } = require("./lint/post-synth/wk8203");
39
- const { wk8204 } = require("./lint/post-synth/wk8204");
40
- const { wk8205 } = require("./lint/post-synth/wk8205");
41
- const { wk8207 } = require("./lint/post-synth/wk8207");
42
- const { wk8208 } = require("./lint/post-synth/wk8208");
43
- const { wk8209 } = require("./lint/post-synth/wk8209");
44
- const { wk8301 } = require("./lint/post-synth/wk8301");
45
- const { wk8302 } = require("./lint/post-synth/wk8302");
46
- const { wk8303 } = require("./lint/post-synth/wk8303");
47
- const { wk8304 } = require("./lint/post-synth/wk8304");
48
- const { wk8305 } = require("./lint/post-synth/wk8305");
49
- const { wk8306 } = require("./lint/post-synth/wk8306");
50
- return [
51
- wk8005, wk8006, wk8041, wk8042,
52
- wk8101, wk8102, wk8103, wk8104, wk8105,
53
- wk8201, wk8202, wk8203, wk8204, wk8205, wk8207, wk8208, wk8209,
54
- wk8301, wk8302, wk8303, wk8304, wk8305, wk8306,
55
- ];
29
+ postSynthChecks() {
30
+ const postSynthDir = join(dirname(fileURLToPath(import.meta.url)), "lint", "post-synth");
31
+ return discoverPostSynthChecks(postSynthDir, import.meta.url);
56
32
  },
57
33
 
58
34
  // K8s YAML has no template interpolation functions like CloudFormation's
@@ -390,48 +366,12 @@ export const service = new Service({
390
366
  },
391
367
 
392
368
  mcpTools() {
393
- return [
394
- {
395
- name: "diff",
396
- description: "Compare current build output against previous output for Kubernetes manifests",
397
- inputSchema: {
398
- type: "object" as const,
399
- properties: {
400
- path: {
401
- type: "string",
402
- description: "Path to the infrastructure project directory",
403
- },
404
- },
405
- },
406
- async handler(params: Record<string, unknown>): Promise<unknown> {
407
- const { diffCommand } = await import("@intentius/chant/cli/commands/diff");
408
- const result = await diffCommand({
409
- path: (params.path as string) ?? ".",
410
- serializers: [k8sSerializer],
411
- });
412
- return result;
413
- },
414
- },
415
- ];
369
+ return [createDiffTool(k8sSerializer, "Compare current build output against previous output for Kubernetes manifests")];
416
370
  },
417
371
 
418
372
  mcpResources() {
419
373
  return [
420
- {
421
- uri: "resource-catalog",
422
- name: "Kubernetes Resource Catalog",
423
- description: "JSON list of all supported Kubernetes resource types",
424
- mimeType: "application/json",
425
- async handler(): Promise<string> {
426
- const lexicon = require("./generated/lexicon-k8s.json") as Record<string, { resourceType: string; kind: string }>;
427
- const entries = Object.entries(lexicon).map(([className, entry]) => ({
428
- className,
429
- resourceType: entry.resourceType,
430
- kind: entry.kind,
431
- }));
432
- return JSON.stringify(entries);
433
- },
434
- },
374
+ createCatalogResource(import.meta.url, "Kubernetes Resource Catalog", "JSON list of all supported Kubernetes resource types", "lexicon-k8s.json"),
435
375
  {
436
376
  uri: "examples/basic-deployment",
437
377
  name: "Basic Deployment Example",
@@ -475,254 +415,11 @@ export const service = new Service({
475
415
  ];
476
416
  },
477
417
 
478
- skills(): SkillDefinition[] {
479
- return [
418
+ skills: createSkillsLoader(import.meta.url, [
480
419
  {
420
+ file: "chant-k8s.md",
481
421
  name: "chant-k8s",
482
422
  description: "Kubernetes manifest lifecycle — scaffold, generate, lint, build, apply, troubleshoot, rollback",
483
- content: `---
484
- skill: chant-k8s
485
- description: Build, validate, and deploy Kubernetes manifests from a chant project
486
- user-invocable: true
487
- ---
488
-
489
- # Kubernetes Operational Playbook
490
-
491
- ## How chant and Kubernetes relate
492
-
493
- chant is a **synthesis compiler** — it compiles TypeScript source files into Kubernetes YAML manifests. \`chant build\` does not call the Kubernetes API; synthesis is pure and deterministic. The optional \`chant state snapshot\` command queries the Kubernetes API to capture deployment metadata (pod names, status, UIDs) for observability. Your job as an agent is to bridge synthesis and deployment:
494
-
495
- - Use **chant** for: build, lint, diff (local YAML comparison)
496
- - Use **kubectl / k8s API** for: apply, rollback, monitoring, troubleshooting
497
-
498
- The source of truth for infrastructure is the TypeScript in \`src/\`. The generated YAML manifests are intermediate artifacts — never edit them by hand.
499
-
500
- ## Scaffolding a new project
501
-
502
- ### Initialize with a template
503
-
504
- \`\`\`bash
505
- chant init --lexicon k8s # default: Deployment + Service
506
- chant init --lexicon k8s --template microservice # Deployment + Service + HPA + PDB
507
- chant init --lexicon k8s --template stateful # StatefulSet + PVC + Service
508
- \`\`\`
509
-
510
- ### Available templates
511
-
512
- | Template | What it generates | Best for |
513
- |----------|-------------------|----------|
514
- | *(default)* | Deployment + Service | Simple stateless apps |
515
- | \`microservice\` | Deployment + Service + HPA + PDB | Production microservices |
516
- | \`stateful\` | StatefulSet + PVC + headless Service | Databases, caches |
517
-
518
- ## Build and validate
519
-
520
- ### Build manifests
521
-
522
- \`\`\`bash
523
- chant build src/ --output manifests.yaml
524
- \`\`\`
525
-
526
- Options:
527
- - \`--format yaml\` — emit YAML (default for K8s)
528
- - \`--watch\` — rebuild on source changes
529
- - \`--output <path>\` — write to a specific file
530
-
531
- ### Lint the source
532
-
533
- \`\`\`bash
534
- chant lint src/
535
- \`\`\`
536
-
537
- ### What each step catches
538
-
539
- | Step | Catches | When to run |
540
- |------|---------|-------------|
541
- | \`chant lint\` | Hardcoded namespaces (WK8001) | Every edit |
542
- | \`chant build\` | Post-synth: secrets in env (WK8005), latest tags (WK8006), API keys (WK8041), missing probes (WK8301), no resource limits (WK8201), privileged containers (WK8202), and more | Before apply |
543
- | \`kubectl --dry-run=server\` | K8s API validation: schema errors, admission webhooks | Before production apply |
544
-
545
- ## Deploying to Kubernetes
546
-
547
- ### Apply manifests
548
-
549
- \`\`\`bash
550
- # Build
551
- chant build src/ --output manifests.yaml
552
-
553
- # Dry run first
554
- kubectl apply -f manifests.yaml --dry-run=server
555
-
556
- # Apply
557
- kubectl apply -f manifests.yaml
558
- \`\`\`
559
-
560
- ### Check rollout status
561
-
562
- \`\`\`bash
563
- kubectl rollout status deployment/my-app
564
- \`\`\`
565
-
566
- ### Rollback
567
-
568
- \`\`\`bash
569
- kubectl rollout undo deployment/my-app
570
- kubectl rollout undo deployment/my-app --to-revision=2
571
- \`\`\`
572
-
573
- ## Debugging strategies
574
-
575
- ### Check pod status and events
576
-
577
- \`\`\`bash
578
- # Overview
579
- kubectl get pods -l app.kubernetes.io/name=my-app
580
- kubectl get events --sort-by=.lastTimestamp -n <namespace>
581
-
582
- # Deep dive into a specific pod
583
- kubectl describe pod <pod-name>
584
-
585
- # Logs (current and previous crash)
586
- kubectl logs <pod-name>
587
- kubectl logs <pod-name> --previous
588
- kubectl logs <pod-name> -c <container-name> # specific container
589
- kubectl logs deployment/my-app --all-containers
590
-
591
- # Debug containers (K8s 1.25+)
592
- kubectl debug <pod-name> -it --image=busybox --target=<container>
593
-
594
- # Port-forwarding for local testing
595
- kubectl port-forward svc/my-app 8080:80
596
- kubectl port-forward pod/<pod-name> 8080:8080
597
- \`\`\`
598
-
599
- ### Common error patterns
600
-
601
- | Status | Meaning | Diagnostic command | Typical fix |
602
- |--------|---------|-------------------|-------------|
603
- | Pending | Not scheduled | \`kubectl describe pod\` → Events | Check resource requests, node selectors, taints, PVC binding |
604
- | CrashLoopBackOff | App crashing on start | \`kubectl logs --previous\` | Fix app startup, check probe config, increase initialDelaySeconds |
605
- | ImagePullBackOff | Image not found | \`kubectl describe pod\` → Events | Verify image name/tag, check imagePullSecrets, registry auth |
606
- | OOMKilled | Out of memory | \`kubectl describe pod\` → Last State | Increase memory limit, profile app memory usage |
607
- | Evicted | Node disk/memory pressure | \`kubectl describe node\` | Increase limits, add node capacity, check for log/tmp bloat |
608
- | CreateContainerError | Container config issue | \`kubectl describe pod\` → Events | Check volume mounts, configmap/secret refs, security context |
609
- | Init:CrashLoopBackOff | Init container failing | \`kubectl logs -c <init-container>\` | Fix init container command, check dependencies |
610
-
611
- ## Production safety
612
-
613
- ### Pre-apply validation
614
-
615
- \`\`\`bash
616
- # Always diff before applying
617
- kubectl diff -f manifests.yaml
618
-
619
- # Server-side dry run (validates with admission webhooks)
620
- kubectl apply -f manifests.yaml --dry-run=server
621
-
622
- # Client-side dry run (fast, but no webhook validation)
623
- kubectl apply -f manifests.yaml --dry-run=client
624
- \`\`\`
625
-
626
- ### Deployment strategies
627
-
628
- - **RollingUpdate** (default): Gradually replaces pods. Set \`maxSurge\` and \`maxUnavailable\`.
629
- - **Recreate**: All pods terminated before new ones created. Use for stateful apps that cannot run multiple versions.
630
- - **Canary**: Deploy a second Deployment with 1 replica + same selector labels. Route percentage via Ingress annotations or service mesh.
631
- - **Blue/Green**: Two full Deployments (blue/green), switch Service selector between them.
632
-
633
- ## Choosing the Right Composite
634
-
635
- Composites are higher-level functions that produce multiple coordinated K8s resources from a single call. They return plain prop objects — not class instances.
636
-
637
- ### Decision Tree
638
-
639
- | Need | Composite | Resources |
640
- |------|-----------|-----------|
641
- | Stateless web app | **WebApp** | Deployment + Service + optional Ingress + optional PDB |
642
- | Stateful database/cache | **StatefulApp** | StatefulSet + headless Service + PVC + optional PDB |
643
- | Production HTTP service with autoscaling | **AutoscaledService** | Deployment + Service + HPA + PDB |
644
- | Background queue workers | **WorkerPool** | Deployment + RBAC + optional ConfigMap + optional HPA + optional PDB |
645
- | Scheduled jobs | **CronWorkload** | CronJob + RBAC |
646
- | One-shot batch jobs | **BatchJob** | Job + optional RBAC |
647
- | App with ConfigMap/Secret mounts | **ConfiguredApp** | Deployment + Service + optional ConfigMap |
648
- | Multi-container sidecar patterns | **SidecarApp** | Deployment + Service |
649
- | App with Prometheus monitoring | **MonitoredService** | Deployment + Service + ServiceMonitor + optional PrometheusRule |
650
- | App with fine-grained network policies | **NetworkIsolatedApp** | Deployment + Service + NetworkPolicy |
651
- | Namespace with quotas and isolation | **NamespaceEnv** | Namespace + ResourceQuota + LimitRange + NetworkPolicy |
652
- | Per-node agent (custom) | **NodeAgent** | DaemonSet + RBAC + optional ConfigMap |
653
- | Multi-host TLS Ingress (cert-manager) | **SecureIngress** | Ingress + optional Certificate |
654
- | EKS IRSA ServiceAccount | **IrsaServiceAccount** | ServiceAccount + optional RBAC |
655
- | AWS ALB Ingress | **AlbIngress** | Ingress with ALB annotations |
656
- | EBS StorageClass | **EbsStorageClass** | StorageClass (ebs.csi.aws.com) |
657
- | EFS StorageClass | **EfsStorageClass** | StorageClass (efs.csi.aws.com) |
658
- | Fluent Bit for CloudWatch | **FluentBitAgent** | DaemonSet + RBAC + ConfigMap |
659
- | ExternalDNS for Route53 | **ExternalDnsAgent** | Deployment + IRSA SA + ClusterRole |
660
- | ADOT for CloudWatch/X-Ray | **AdotCollector** | DaemonSet + RBAC + ConfigMap |
661
-
662
- ### Hardening options (available on Deployment-based composites)
663
-
664
- - \`minAvailable\` — creates a PodDisruptionBudget (WebApp, StatefulApp, WorkerPool; AutoscaledService always has one)
665
- - \`initContainers\` — run before main containers (WebApp, StatefulApp, AutoscaledService, ConfiguredApp, SidecarApp)
666
- - \`securityContext\` — container security settings (WebApp, StatefulApp, AutoscaledService, WorkerPool)
667
- - \`terminationGracePeriodSeconds\` — graceful shutdown (WebApp, StatefulApp, AutoscaledService, WorkerPool)
668
- - \`priorityClassName\` — pod scheduling priority (WebApp, StatefulApp, AutoscaledService, WorkerPool)
669
-
670
- ### Common patterns across all composites
671
-
672
- - All resources carry \`app.kubernetes.io/name\`, \`app.kubernetes.io/managed-by: chant\`, and \`app.kubernetes.io/component\` labels
673
- - Pass \`labels: { team: "platform" }\` to add extra labels to all resources
674
- - Pass \`namespace: "prod"\` to set namespace on all namespaced resources
675
- - Pass \`env: [{ name: "KEY", value: "val" }]\` for container environment variables
676
-
677
- ## Troubleshooting reference table
678
-
679
- | Symptom | Likely cause | Resolution |
680
- |---------|-------------|------------|
681
- | Pod stuck in Pending | Insufficient CPU/memory on nodes | Scale up cluster or reduce resource requests |
682
- | Pod stuck in Pending | PVC not bound | Check StorageClass exists, PV available |
683
- | Pod stuck in Pending | Node selector/affinity mismatch | Verify node labels match selectors |
684
- | Pod stuck in ContainerCreating | ConfigMap/Secret not found | Ensure referenced ConfigMaps/Secrets exist |
685
- | Service returns 503 | No ready endpoints | Check pod readiness probes, selector match |
686
- | Ingress returns 404 | Backend service not found | Check Ingress rules, service name/port |
687
- | HPA not scaling | Metrics server not installed | Install metrics-server |
688
- | HPA not scaling | Resource requests not set | Add CPU/memory requests to containers |
689
- | CronJob not running | Invalid cron expression | Validate cron syntax (5-field format) |
690
- | NetworkPolicy blocking | Default deny applied | Add explicit allow rules for required traffic |
691
- | RBAC permission denied | Missing Role/RoleBinding | Check ServiceAccount bindings and verb permissions |
692
-
693
- ## Quick reference
694
-
695
- \`\`\`bash
696
- # Build
697
- chant build src/ --output manifests.yaml
698
-
699
- # Lint
700
- chant lint src/
701
-
702
- # Validate
703
- kubectl apply -f manifests.yaml --dry-run=server
704
-
705
- # Diff
706
- kubectl diff -f manifests.yaml
707
-
708
- # Apply
709
- kubectl apply -f manifests.yaml
710
-
711
- # Status
712
- kubectl get pods,svc,deploy
713
-
714
- # Logs
715
- kubectl logs deployment/my-app
716
-
717
- # Rollback
718
- kubectl rollout undo deployment/my-app
719
-
720
- # Debug
721
- kubectl describe pod <name>
722
- kubectl logs <name> --previous
723
- kubectl get events --sort-by=.lastTimestamp
724
- \`\`\`
725
- `,
726
423
  triggers: [
727
424
  { type: "file-pattern", value: "**/*.k8s.ts" },
728
425
  { type: "file-pattern", value: "**/k8s/**/*.ts" },
@@ -812,254 +509,9 @@ const { job, serviceAccount, role, roleBinding } = BatchJob({
812
509
  ],
813
510
  },
814
511
  {
512
+ file: "chant-k8s-patterns.md",
815
513
  name: "chant-k8s-patterns",
816
514
  description: "Advanced K8s patterns — sidecars, observability, TLS, network isolation, config/secret mounting",
817
- content: `---
818
- skill: chant-k8s-patterns
819
- description: Advanced Kubernetes deployment patterns and composites
820
- user-invocable: true
821
- ---
822
-
823
- # Advanced Kubernetes Patterns
824
-
825
- ## Sidecar Patterns
826
-
827
- ### SidecarApp — multi-container Deployment
828
-
829
- \`\`\`typescript
830
- import { SidecarApp } from "@intentius/chant-lexicon-k8s";
831
-
832
- // Envoy sidecar proxy
833
- const { deployment, service } = SidecarApp({
834
- name: "api",
835
- image: "api:1.0",
836
- port: 8080,
837
- sidecars: [
838
- {
839
- name: "envoy",
840
- image: "envoyproxy/envoy:v1.28",
841
- ports: [{ containerPort: 9901, name: "admin" }],
842
- resources: { requests: { cpu: "100m", memory: "128Mi" }, limits: { cpu: "200m", memory: "256Mi" } },
843
- },
844
- ],
845
- initContainers: [
846
- { name: "migrate", image: "api:1.0", command: ["python", "manage.py", "migrate"] },
847
- ],
848
- sharedVolumes: [{ name: "tmp", emptyDir: {} }],
849
- });
850
- \`\`\`
851
-
852
- Common sidecar use cases:
853
- - **Envoy proxy** — service mesh, mTLS, traffic management
854
- - **Log forwarder** — Fluent Bit sidecar for app-specific log routing
855
- - **Auth proxy** — OAuth2 Proxy for authentication
856
- - **Config watcher** — reload config on ConfigMap changes
857
-
858
- ## Config and Secret Mounting
859
-
860
- ### ConfiguredApp — automatic volume wiring
861
-
862
- \`\`\`typescript
863
- import { ConfiguredApp } from "@intentius/chant-lexicon-k8s";
864
-
865
- const { deployment, service, configMap } = ConfiguredApp({
866
- name: "api",
867
- image: "api:1.0",
868
- port: 8080,
869
- // Mount ConfigMap as volume
870
- configData: { "app.conf": "key=value\\nother=setting" },
871
- configMountPath: "/etc/api",
872
- // Mount existing Secret as volume
873
- secretName: "api-creds",
874
- secretMountPath: "/secrets",
875
- // Inject as environment variables
876
- envFrom: { secretRef: "api-env-secret", configMapRef: "api-env-config" },
877
- // Run migrations before the app starts
878
- initContainers: [
879
- { name: "migrate", image: "api:1.0", command: ["./migrate.sh"] },
880
- ],
881
- });
882
- \`\`\`
883
-
884
- ### Volume patterns
885
-
886
- | Pattern | Use Case | ConfiguredApp Props |
887
- |---------|----------|---------------------|
888
- | ConfigMap as file | Config files, templates | \`configData\` + \`configMountPath\` |
889
- | Secret as file | TLS certs, credentials | \`secretName\` + \`secretMountPath\` |
890
- | ConfigMap as env | Simple key-value config | \`envFrom.configMapRef\` |
891
- | Secret as env | Database URLs, API keys | \`envFrom.secretRef\` |
892
-
893
- ## TLS / cert-manager
894
-
895
- ### SecureIngress — multi-host TLS with cert-manager
896
-
897
- \`\`\`typescript
898
- import { SecureIngress } from "@intentius/chant-lexicon-k8s";
899
-
900
- const { ingress, certificate } = SecureIngress({
901
- name: "app-ingress",
902
- hosts: [
903
- {
904
- hostname: "api.example.com",
905
- paths: [
906
- { path: "/v1", serviceName: "api-v1", servicePort: 80 },
907
- { path: "/v2", serviceName: "api-v2", servicePort: 80 },
908
- ],
909
- },
910
- {
911
- hostname: "admin.example.com",
912
- paths: [{ path: "/", serviceName: "admin", servicePort: 80 }],
913
- },
914
- ],
915
- clusterIssuer: "letsencrypt-prod",
916
- ingressClassName: "nginx",
917
- });
918
- \`\`\`
919
-
920
- Features:
921
- - Multiple hosts and paths per Ingress
922
- - Automatic cert-manager Certificate when \`clusterIssuer\` set
923
- - TLS secret auto-provisioned by cert-manager
924
-
925
- ### cert-manager setup (prerequisite)
926
-
927
- \`\`\`bash
928
- # Install cert-manager
929
- kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
930
-
931
- # Create ClusterIssuer for Let's Encrypt
932
- kubectl apply -f - <<EOF
933
- apiVersion: cert-manager.io/v1
934
- kind: ClusterIssuer
935
- metadata:
936
- name: letsencrypt-prod
937
- spec:
938
- acme:
939
- server: https://acme-v02.api.letsencrypt.org/directory
940
- email: admin@example.com
941
- privateKeySecretRef:
942
- name: letsencrypt-prod-key
943
- solvers:
944
- - http01:
945
- ingress:
946
- class: nginx
947
- EOF
948
- \`\`\`
949
-
950
- ## Observability
951
-
952
- ### MonitoredService — Prometheus monitoring
953
-
954
- \`\`\`typescript
955
- import { MonitoredService } from "@intentius/chant-lexicon-k8s";
956
-
957
- const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService({
958
- name: "api",
959
- image: "api:1.0",
960
- port: 8080,
961
- metricsPort: 9090,
962
- metricsPath: "/metrics",
963
- scrapeInterval: "15s",
964
- alertRules: [
965
- {
966
- name: "HighErrorRate",
967
- expr: 'rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05',
968
- for: "5m",
969
- severity: "critical",
970
- annotations: { summary: "High error rate on {{ $labels.instance }}" },
971
- },
972
- {
973
- name: "HighLatency",
974
- expr: 'histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 1',
975
- for: "10m",
976
- severity: "warning",
977
- },
978
- ],
979
- });
980
- \`\`\`
981
-
982
- ### Prerequisites
983
-
984
- - Prometheus Operator installed (for ServiceMonitor/PrometheusRule CRDs)
985
- - Prometheus configured to discover ServiceMonitors
986
-
987
- ## Network Isolation
988
-
989
- ### NetworkIsolatedApp — per-app firewall rules
990
-
991
- \`\`\`typescript
992
- import { NetworkIsolatedApp } from "@intentius/chant-lexicon-k8s";
993
-
994
- const { deployment, service, networkPolicy } = NetworkIsolatedApp({
995
- name: "api",
996
- image: "api:1.0",
997
- port: 8080,
998
- allowIngressFrom: [
999
- { podSelector: { "app.kubernetes.io/name": "frontend" } },
1000
- { namespaceSelector: { "kubernetes.io/metadata.name": "monitoring" } },
1001
- ],
1002
- allowEgressTo: [
1003
- { podSelector: { "app.kubernetes.io/name": "postgres" }, ports: [{ port: 5432 }] },
1004
- { podSelector: { "app.kubernetes.io/name": "redis" }, ports: [{ port: 6379 }] },
1005
- ],
1006
- });
1007
- \`\`\`
1008
-
1009
- ### Combining with NamespaceEnv
1010
-
1011
- Use NamespaceEnv for namespace-level default-deny, then NetworkIsolatedApp for per-app allow rules:
1012
-
1013
- \`\`\`typescript
1014
- // Namespace: deny all by default
1015
- const ns = NamespaceEnv({ name: "prod", defaultDenyIngress: true, defaultDenyEgress: true });
1016
-
1017
- // App: allow specific traffic
1018
- const app = NetworkIsolatedApp({
1019
- name: "api",
1020
- image: "api:1.0",
1021
- namespace: "prod",
1022
- allowIngressFrom: [{ podSelector: { "app.kubernetes.io/name": "gateway" } }],
1023
- allowEgressTo: [{ podSelector: { "app.kubernetes.io/name": "db" }, ports: [{ port: 5432 }] }],
1024
- });
1025
- \`\`\`
1026
-
1027
- ## Blue/Green and Canary
1028
-
1029
- These patterns use standard K8s resources — no special composite needed.
1030
-
1031
- ### Blue/Green
1032
-
1033
- \`\`\`typescript
1034
- // Two Deployments with different versions
1035
- const blue = WebApp({ name: "app-blue", image: "app:1.0", labels: { version: "blue" } });
1036
- const green = WebApp({ name: "app-green", image: "app:2.0", labels: { version: "green" } });
1037
-
1038
- // Service points to active version — switch by changing selector
1039
- // Active: blue → green (update the Service selector)
1040
- \`\`\`
1041
-
1042
- ### Canary
1043
-
1044
- \`\`\`typescript
1045
- // Main deployment (90% traffic)
1046
- const main = AutoscaledService({ name: "app", image: "app:1.0", minReplicas: 9, maxReplicas: 20, ... });
1047
-
1048
- // Canary deployment (10% traffic) — same app label, fewer replicas
1049
- const canary = WebApp({ name: "app-canary", image: "app:2.0", replicas: 1, labels: { track: "canary" } });
1050
- // Both share the same Service selector ("app.kubernetes.io/name": "app") for traffic splitting
1051
- \`\`\`
1052
-
1053
- ## Gateway API (future direction)
1054
-
1055
- Gateway API is the successor to Ingress. Key differences:
1056
- - **HTTPRoute** replaces Ingress rules
1057
- - **Gateway** replaces IngressClass
1058
- - Built-in traffic splitting, header matching, URL rewriting
1059
- - Currently in beta — use Ingress/SecureIngress/AlbIngress for production today
1060
-
1061
- When Gateway API reaches GA, new composites will be added. For now, use CRD import if you need Gateway API resources.
1062
- `,
1063
515
  triggers: [
1064
516
  { type: "context", value: "sidecar" },
1065
517
  { type: "context", value: "init-container" },
@@ -1109,26 +561,17 @@ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService
1109
561
  },
1110
562
  ],
1111
563
  },
1112
- ];
1113
-
1114
- // Load file-based skills from src/skills/
1115
- const { readFileSync } = require("fs");
1116
- const { join, dirname } = require("path");
1117
- const { fileURLToPath } = require("url");
1118
- const dir = dirname(fileURLToPath(import.meta.url));
1119
-
1120
- const skillFiles = [
1121
564
  {
1122
- file: "kubernetes-patterns.md",
1123
- name: "kubernetes-patterns",
565
+ file: "chant-k8s-deployment-strategies.md",
566
+ name: "chant-k8s-deployment-strategies",
1124
567
  description: "Kubernetes deployment strategies, stateful workloads, RBAC, and networking patterns",
1125
568
  triggers: [
1126
- { type: "context" as const, value: "deployment strategy" },
1127
- { type: "context" as const, value: "statefulset" },
1128
- { type: "context" as const, value: "rbac" },
1129
- { type: "context" as const, value: "network policy" },
1130
- { type: "context" as const, value: "rolling update" },
1131
- { type: "context" as const, value: "blue green" },
569
+ { type: "context", value: "deployment strategy" },
570
+ { type: "context", value: "statefulset" },
571
+ { type: "context", value: "rbac" },
572
+ { type: "context", value: "network policy" },
573
+ { type: "context", value: "rolling update" },
574
+ { type: "context", value: "blue green" },
1132
575
  ],
1133
576
  parameters: [],
1134
577
  examples: [
@@ -1140,15 +583,15 @@ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService
1140
583
  ],
1141
584
  },
1142
585
  {
1143
- file: "kubernetes-security.md",
1144
- name: "kubernetes-security",
586
+ file: "chant-k8s-security.md",
587
+ name: "chant-k8s-security",
1145
588
  description: "Kubernetes pod security, image scanning, network policies, and secrets management",
1146
589
  triggers: [
1147
- { type: "context" as const, value: "k8s security" },
1148
- { type: "context" as const, value: "pod security" },
1149
- { type: "context" as const, value: "image security" },
1150
- { type: "context" as const, value: "k8s secrets" },
1151
- { type: "context" as const, value: "security context" },
590
+ { type: "context", value: "k8s security" },
591
+ { type: "context", value: "pod security" },
592
+ { type: "context", value: "image security" },
593
+ { type: "context", value: "k8s secrets" },
594
+ { type: "context", value: "security context" },
1152
595
  ],
1153
596
  parameters: [],
1154
597
  examples: [
@@ -1164,11 +607,11 @@ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService
1164
607
  name: "chant-k8s-eks",
1165
608
  description: "EKS-specific Kubernetes composites — IRSA, ALB, EBS/EFS, Fluent Bit, ExternalDNS, ADOT",
1166
609
  triggers: [
1167
- { type: "context" as const, value: "eks composites" },
1168
- { type: "context" as const, value: "irsa" },
1169
- { type: "context" as const, value: "alb ingress" },
1170
- { type: "context" as const, value: "ebs storage" },
1171
- { type: "context" as const, value: "karpenter" },
610
+ { type: "context", value: "eks composites" },
611
+ { type: "context", value: "irsa" },
612
+ { type: "context", value: "alb ingress" },
613
+ { type: "context", value: "ebs storage" },
614
+ { type: "context", value: "karpenter" },
1172
615
  ],
1173
616
  parameters: [],
1174
617
  examples: [
@@ -1184,9 +627,9 @@ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService
1184
627
  name: "chant-k8s-gke",
1185
628
  description: "GKE-specific Kubernetes composites — Workload Identity, GCE PD, Filestore, FluentBit, OTel, ExternalDNS, Gateway",
1186
629
  triggers: [
1187
- { type: "context" as const, value: "gke composites" },
1188
- { type: "context" as const, value: "workload identity gke" },
1189
- { type: "context" as const, value: "config connector k8s" },
630
+ { type: "context", value: "gke composites" },
631
+ { type: "context", value: "workload identity gke" },
632
+ { type: "context", value: "config connector k8s" },
1190
633
  ],
1191
634
  parameters: [],
1192
635
  examples: [
@@ -1202,9 +645,9 @@ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService
1202
645
  name: "chant-k8s-aks",
1203
646
  description: "AKS-specific Kubernetes composites — Workload Identity, AGIC, Azure Disk/File, ExternalDNS, Azure Monitor",
1204
647
  triggers: [
1205
- { type: "context" as const, value: "aks composites" },
1206
- { type: "context" as const, value: "workload identity aks" },
1207
- { type: "context" as const, value: "agic ingress" },
648
+ { type: "context", value: "aks composites" },
649
+ { type: "context", value: "workload identity aks" },
650
+ { type: "context", value: "agic ingress" },
1208
651
  ],
1209
652
  parameters: [],
1210
653
  examples: [
@@ -1215,22 +658,5 @@ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService
1215
658
  },
1216
659
  ],
1217
660
  },
1218
- ];
1219
-
1220
- for (const skill of skillFiles) {
1221
- try {
1222
- const content = readFileSync(join(dir, "skills", skill.file), "utf-8");
1223
- skills.push({
1224
- name: skill.name,
1225
- description: skill.description,
1226
- content,
1227
- triggers: skill.triggers,
1228
- parameters: skill.parameters,
1229
- examples: skill.examples,
1230
- });
1231
- } catch { /* skip missing skills */ }
1232
- }
1233
-
1234
- return skills;
1235
- },
661
+ ]),
1236
662
  };