feat: Claude Code Monitor — lanes, pipelines and a merged workspace

Internal SmartGift build of a Claude Code monitoring dashboard.

Lanes: a durable unit of parallel agent work, one per working directory,
tracked across session restarts. Managed lanes are git worktrees the
dashboard provisions and can reset or remove behind a three-check destroy
guard and a counted preflight; adopted lanes are directories you already
own and are never destroyable.

Pipelines: a lane moves through pipeline stages. A stage the agent declares
with evidence renders green; a stage inferred from the tool-event stream
renders dashed amber and never counts as done. Detection is forward-only
within a 30-minute window, and never writes the declared stage.

Workspace: one page at /run with a lane grid, the selected lane's pipeline,
and a full Claude console behind a disclosure.
This commit is contained in:
2026-07-29 17:07:45 +07:00
commit 57dc91585d
783 changed files with 221743 additions and 0 deletions
@@ -0,0 +1,18 @@
# Patterns to ignore when building packages.
.DS_Store
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
*.swp
*.bak
*.tmp
*.orig
*~
.project
.idea/
*.tmproj
.vscode/
+28
View File
@@ -0,0 +1,28 @@
apiVersion: v2
name: agent-monitor
description: Claude Code Agent Monitor - Real-time dashboard for tracking Claude Code agent activity
type: application
version: 1.0.0
appVersion: "1.0.0"
home: https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor
sources:
- https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor
keywords:
- claude
- agent
- monitor
- dashboard
- ai
- devtools
- observability
maintainers:
- name: David Nguyen
url: https://git.smartgift.io.vn/Smartgift-AI
icon: https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor/raw/branch/master/favicon.svg
annotations:
artifacthub.io/category: monitoring-logging
@@ -0,0 +1,79 @@
╔══════════════════════════════════════════════════════════════════════╗
║ Claude Code Agent Monitor - Deployment Notes ║
╚══════════════════════════════════════════════════════════════════════╝
{{- $fullName := include "agent-monitor.fullname" . -}}
🎉 {{ $fullName }} has been deployed to namespace "{{ .Release.Namespace }}"!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📡 Accessing the Dashboard:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
URL: http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get -n {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ $fullName }})
export NODE_IP=$(kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}")
echo "Dashboard URL: http://$NODE_IP:$NODE_PORT"
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
Watch status with:
kubectl get -n {{ .Release.Namespace }} svc {{ $fullName }} -w
export SERVICE_IP=$(kubectl get svc -n {{ .Release.Namespace }} {{ $fullName }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Dashboard URL: http://$SERVICE_IP:{{ .Values.service.port }}"
{{- else }}
Port-forward to access locally:
kubectl port-forward -n {{ .Release.Namespace }} svc/{{ $fullName }} 4820:{{ .Values.service.port }}
Then open: http://localhost:4820
{{- end }}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔍 Health Check:
kubectl exec -n {{ .Release.Namespace }} deploy/{{ $fullName }} -- wget -qO- http://localhost:{{ .Values.service.targetPort }}/api/health
🧪 Run Tests:
helm test {{ .Release.Name }} -n {{ .Release.Namespace }}
📊 View Logs:
kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "agent-monitor.name" . }} -f
📈 Check Pods:
kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "agent-monitor.name" . }}
{{- if .Values.persistence.enabled }}
💾 Persistent Storage:
SQLite data is stored on PVC: {{ $fullName }}-data ({{ .Values.persistence.size }})
{{- end }}
{{- if .Values.mcp.enabled }}
🔌 MCP Sidecar:
MCP server is running on port {{ .Values.mcp.port }}
Access via: kubectl port-forward -n {{ .Release.Namespace }} svc/{{ $fullName }} {{ .Values.mcp.port }}:{{ .Values.mcp.port }}
{{- end }}
{{- if .Values.autoscaling.enabled }}
📐 Autoscaling:
Min replicas: {{ .Values.autoscaling.minReplicas }}
Max replicas: {{ .Values.autoscaling.maxReplicas }}
CPU target: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}%
Memory target: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}%
{{- end }}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -0,0 +1,88 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "agent-monitor.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this
(by the DNS naming spec). If release name contains the chart name it will be used
as a full name.
*/}}
{{- define "agent-monitor.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "agent-monitor.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "agent-monitor.labels" -}}
helm.sh/chart: {{ include "agent-monitor.chart" . }}
{{ include "agent-monitor.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: claude-code-agent-monitor
{{- end }}
{{/*
Selector labels
*/}}
{{- define "agent-monitor.selectorLabels" -}}
app.kubernetes.io/name: {{ include "agent-monitor.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "agent-monitor.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "agent-monitor.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Return the container image string
*/}}
{{- define "agent-monitor.image" -}}
{{- $tag := default .Chart.AppVersion .Values.image.tag -}}
{{- if .Values.image.registry -}}
{{- printf "%s/%s:%s" .Values.image.registry .Values.image.repository $tag -}}
{{- else -}}
{{- printf "%s:%s" .Values.image.repository $tag -}}
{{- end -}}
{{- end }}
{{/*
Return the MCP sidecar container image string
*/}}
{{- define "agent-monitor.mcpImage" -}}
{{- $tag := default .Chart.AppVersion .Values.mcp.image.tag -}}
{{- if .Values.mcp.image.registry -}}
{{- printf "%s/%s:%s" .Values.mcp.image.registry .Values.mcp.image.repository $tag -}}
{{- else -}}
{{- printf "%s:%s" .Values.mcp.image.repository $tag -}}
{{- end -}}
{{- end }}
@@ -0,0 +1,13 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "agent-monitor.fullname" . }}-config
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
data:
{{- range $key, $value := .Values.env }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- range $key, $value := .Values.extraEnv }}
{{ $key }}: {{ $value | quote }}
{{- end }}
@@ -0,0 +1,159 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "agent-monitor.fullname" . }}
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
revisionHistoryLimit: {{ .Values.deployment.revisionHistoryLimit | default 5 }}
{{- with .Values.deployment.strategy }}
strategy:
{{- toYaml . | nindent 4 }}
{{- end }}
selector:
matchLabels:
{{- include "agent-monitor.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "agent-monitor.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "agent-monitor.serviceAccountName" . }}
automountServiceAccountToken: false
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
# ── Main application container ────────────────────────────────────
- name: {{ .Chart.Name }}
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
image: {{ include "agent-monitor.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
{{- with .Values.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.startupProbe }}
startupProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
envFrom:
- configMapRef:
name: {{ include "agent-monitor.fullname" . }}-config
{{- with .Values.extraEnvFrom }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
lifecycle:
preStop:
exec:
# Allow in-flight requests (including WebSockets) to drain before SIGTERM
command: ["sh", "-c", "sleep 5"]
volumeMounts:
- name: data
mountPath: /app/data
- name: tmp
mountPath: /tmp
{{- if .Values.mcp.enabled }}
# ── MCP sidecar container ─────────────────────────────────────────
- name: mcp
{{- with .Values.mcp.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
image: {{ include "agent-monitor.mcpImage" . }}
imagePullPolicy: {{ .Values.mcp.image.pullPolicy }}
ports:
- name: mcp
containerPort: {{ .Values.mcp.port }}
protocol: TCP
env:
{{- range $key, $value := .Values.mcp.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
startupProbe:
tcpSocket:
port: mcp
failureThreshold: 30
periodSeconds: 2
livenessProbe:
tcpSocket:
port: mcp
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
tcpSocket:
port: mcp
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
{{- with .Values.mcp.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- name: tmp
mountPath: /tmp
{{- end }}
volumes:
- name: data
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim | default (printf "%s-data" (include "agent-monitor.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
- name: tmp
emptyDir:
sizeLimit: 100Mi
terminationGracePeriodSeconds: 30
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
@@ -0,0 +1,53 @@
{{- if .Values.autoscaling.enabled -}}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "agent-monitor.fullname" . }}
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "agent-monitor.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
behavior:
scaleDown:
stabilizationWindowSeconds: {{ .Values.autoscaling.scaleDownStabilizationWindowSeconds | default 300 }}
policies:
- type: Pods
value: 1
periodSeconds: 60
- type: Percent
value: 10
periodSeconds: 60
selectPolicy: Min
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Pods
value: 2
periodSeconds: 60
- type: Percent
value: 50
periodSeconds: 60
selectPolicy: Max
{{- end }}
@@ -0,0 +1,41 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "agent-monitor.fullname" . }}
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "agent-monitor.fullname" $ }}
port:
name: http
{{- end }}
{{- end }}
{{- end }}
@@ -0,0 +1,46 @@
{{- if .Values.networkPolicy.enabled -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "agent-monitor.fullname" . }}
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "agent-monitor.selectorLabels" . | nindent 6 }}
policyTypes:
- Ingress
- Egress
ingress:
# Allow HTTP traffic to the application port from any pod (ingress controllers, etc.)
- ports:
- port: {{ .Values.service.targetPort }}
protocol: TCP
{{- if .Values.mcp.enabled }}
# Allow MCP traffic when sidecar is enabled
- ports:
- port: {{ .Values.mcp.port }}
protocol: TCP
{{- end }}
{{- with .Values.networkPolicy.additionalIngressRules }}
{{- toYaml . | nindent 4 }}
{{- end }}
egress:
# Allow DNS resolution
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
# Allow outbound HTTPS (for external API calls)
- ports:
- port: 443
protocol: TCP
# Allow internal communication within the cluster
- to:
- podSelector: {}
{{- with .Values.networkPolicy.additionalEgressRules }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
@@ -0,0 +1,18 @@
{{- if .Values.podDisruptionBudget.enabled -}}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "agent-monitor.fullname" . }}
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
spec:
{{- if .Values.podDisruptionBudget.minAvailable }}
minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
{{- end }}
{{- if .Values.podDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
{{- end }}
selector:
matchLabels:
{{- include "agent-monitor.selectorLabels" . | nindent 6 }}
{{- end }}
@@ -0,0 +1,23 @@
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) -}}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "agent-monitor.fullname" . }}-data
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
{{- with .Values.persistence.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
accessModes:
{{- range .Values.persistence.accessModes }}
- {{ . }}
{{- end }}
{{- if .Values.persistence.storageClass }}
storageClassName: {{ .Values.persistence.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size }}
{{- end }}
@@ -0,0 +1,33 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "agent-monitor.fullname" . }}
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
# Sticky sessions for WebSocket connections
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
{{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }}
nodePort: {{ .Values.service.nodePort }}
{{- end }}
{{- if .Values.mcp.enabled }}
- name: mcp
port: {{ .Values.mcp.port }}
targetPort: mcp
protocol: TCP
{{- end }}
selector:
{{- include "agent-monitor.selectorLabels" . | nindent 4 }}
@@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "agent-monitor.serviceAccountName" . }}
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken | default false }}
{{- end }}
@@ -0,0 +1,29 @@
{{- if and .Values.monitoring.enabled .Values.monitoring.serviceMonitor.enabled -}}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "agent-monitor.fullname" . }}
{{- if .Values.monitoring.serviceMonitor.namespace }}
namespace: {{ .Values.monitoring.serviceMonitor.namespace }}
{{- end }}
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
{{- with .Values.monitoring.serviceMonitor.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
{{- include "agent-monitor.selectorLabels" . | nindent 6 }}
{{- if .Values.monitoring.serviceMonitor.namespace }}
namespaceSelector:
matchNames:
- {{ .Release.Namespace }}
{{- end }}
endpoints:
- port: http
path: {{ .Values.monitoring.serviceMonitor.path | default "/api/metrics" }}
interval: {{ .Values.monitoring.serviceMonitor.interval | default "30s" }}
scrapeTimeout: {{ .Values.monitoring.serviceMonitor.scrapeTimeout | default "10s" }}
honorLabels: {{ .Values.monitoring.serviceMonitor.honorLabels | default false }}
{{- end }}
@@ -0,0 +1,34 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "agent-monitor.fullname" . }}-test-connection"
labels:
{{- include "agent-monitor.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
seccompProfile:
type: RuntimeDefault
containers:
- name: wget
image: busybox:1.36
command: ['wget']
args:
- '--timeout=10'
- '--tries=3'
- '-qO-'
- 'http://{{ include "agent-monitor.fullname" . }}:{{ .Values.service.port }}/api/health'
securityContext:
runAsNonRoot: true
runAsUser: 65534
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
@@ -0,0 +1,50 @@
# =============================================================================
# Development Environment Overrides
# =============================================================================
# Usage: helm install agent-monitor ./agent-monitor -f values-dev.yaml
replicaCount: 1
image:
pullPolicy: Always
env:
NODE_ENV: development
DASHBOARD_PORT: "4820"
LOG_LEVEL: debug
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: false
persistence:
enabled: true
size: 1Gi
podDisruptionBudget:
enabled: false
networkPolicy:
enabled: false
monitoring:
enabled: false
ingress:
enabled: false
# Relax security for dev debugging
securityContext:
readOnlyRootFilesystem: false
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
@@ -0,0 +1,117 @@
# =============================================================================
# Production Environment Overrides
# =============================================================================
# Usage: helm install agent-monitor ./agent-monitor -f values-production.yaml
replicaCount: 3
env:
NODE_ENV: production
DASHBOARD_PORT: "4820"
LOG_LEVEL: warn
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: "1Gi"
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
scaleDownStabilizationWindowSeconds: 600
deployment:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
persistence:
enabled: true
size: 20Gi
storageClass: gp3
podDisruptionBudget:
enabled: true
minAvailable: 2
networkPolicy:
enabled: true
# -- Spread pods across nodes (required) and zones (preferred) for high availability
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- agent-monitor
topologyKey: kubernetes.io/hostname
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- agent-monitor
topologyKey: topology.kubernetes.io/zone
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: agent-monitor
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: agent-monitor.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: agent-monitor-production-tls
hosts:
- agent-monitor.example.com
monitoring:
enabled: true
serviceMonitor:
enabled: true
interval: 15s
scrapeTimeout: 10s
mcp:
enabled: true
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
@@ -0,0 +1,65 @@
# =============================================================================
# Staging Environment Overrides
# =============================================================================
# Usage: helm install agent-monitor ./agent-monitor -f values-staging.yaml
replicaCount: 2
env:
NODE_ENV: production
DASHBOARD_PORT: "4820"
LOG_LEVEL: info
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 5
targetCPUUtilizationPercentage: 75
targetMemoryUtilizationPercentage: 80
scaleDownStabilizationWindowSeconds: 180
persistence:
enabled: true
size: 5Gi
podDisruptionBudget:
enabled: true
minAvailable: 1
networkPolicy:
enabled: true
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
hosts:
- host: agent-monitor.staging.internal
paths:
- path: /
pathType: Prefix
tls:
- secretName: agent-monitor-staging-tls
hosts:
- agent-monitor.staging.internal
monitoring:
enabled: true
serviceMonitor:
enabled: true
interval: 30s
+312
View File
@@ -0,0 +1,312 @@
# =============================================================================
# Claude Code Agent Monitor - Default Helm Values
# =============================================================================
# Override these values per environment using values-dev.yaml, values-staging.yaml,
# or values-production.yaml.
# -- Number of pod replicas
replicaCount: 2
# -- Container image configuration
image:
registry: ghcr.io
repository: smartgift/claude-code-monitor
tag: "" # Defaults to .Chart.AppVersion if empty
pullPolicy: IfNotPresent
# -- Image pull secrets for private registries
imagePullSecrets: []
# -- Override the release name
nameOverride: ""
# -- Override the full release name
fullnameOverride: ""
# =============================================================================
# Service Account
# =============================================================================
serviceAccount:
# -- Whether to create a ServiceAccount
create: true
# -- Annotations to add to the ServiceAccount
annotations: {}
# -- The name of the ServiceAccount (auto-generated if empty)
name: ""
# -- Automount API credentials
automountServiceAccountToken: false
# =============================================================================
# Pod Configuration
# =============================================================================
# -- Annotations to add to pods
podAnnotations: {}
# -- Labels to add to pods
podLabels: {}
# -- Pod-level security context
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
seccompProfile:
type: RuntimeDefault
# -- Container-level security context
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
# =============================================================================
# Deployment Strategy
# =============================================================================
deployment:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
# =============================================================================
# Service
# =============================================================================
service:
# -- Service type (ClusterIP, NodePort, LoadBalancer)
type: ClusterIP
# -- Service port (external)
port: 80
# -- Container port the application listens on
targetPort: 4820
# -- Node port (only used when type is NodePort)
nodePort: ""
# -- Additional service annotations
annotations: {}
# =============================================================================
# Ingress
# =============================================================================
ingress:
# -- Enable ingress resource
enabled: false
# -- Ingress class name (e.g. nginx, traefik, alb)
className: ""
# -- Ingress annotations
annotations: {}
# nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
# nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
# nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
# nginx.ingress.kubernetes.io/proxy-set-headers: "Upgrade=$http_upgrade,Connection=upgrade"
# -- Ingress host definitions
hosts:
- host: agent-monitor.local
paths:
- path: /
pathType: Prefix
# -- TLS configuration
tls: []
# - secretName: agent-monitor-tls
# hosts:
# - agent-monitor.local
# =============================================================================
# Resource Limits
# =============================================================================
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
# =============================================================================
# Autoscaling (HPA)
# =============================================================================
autoscaling:
# -- Enable Horizontal Pod Autoscaler
enabled: true
# -- Minimum number of replicas
minReplicas: 2
# -- Maximum number of replicas
maxReplicas: 10
# -- Target CPU utilization percentage
targetCPUUtilizationPercentage: 70
# -- Target memory utilization percentage
targetMemoryUtilizationPercentage: 80
# -- Scale-down stabilization window (seconds)
scaleDownStabilizationWindowSeconds: 300
# =============================================================================
# Persistence (SQLite database)
# =============================================================================
persistence:
# -- Enable persistent storage for SQLite data
enabled: true
# -- Storage class name (empty string uses default)
storageClass: ""
# -- Access modes for the PVC
accessModes:
- ReadWriteOnce
# -- Size of the persistent volume
size: 10Gi
# -- Annotations for the PVC
annotations: {}
# -- Use an existing PVC instead of creating one
existingClaim: ""
# =============================================================================
# Scheduling
# =============================================================================
# -- Node selector for pod placement
nodeSelector: {}
# -- Tolerations for pod placement
tolerations: []
# -- Affinity rules for pod placement
affinity: {}
# -- Topology spread constraints
topologySpreadConstraints: []
# =============================================================================
# Environment Variables
# =============================================================================
env:
# -- Node.js environment
NODE_ENV: production
# -- Port the dashboard server listens on (must match service.targetPort)
DASHBOARD_PORT: "4820"
# -- Log level (debug, info, warn, error)
LOG_LEVEL: info
# -- Additional environment variables as key-value pairs
extraEnv: {}
# MY_CUSTOM_VAR: my-value
# -- Extra environment variables from secrets or configmaps
extraEnvFrom: []
# - secretRef:
# name: my-secret
# - configMapRef:
# name: my-configmap
# =============================================================================
# Health Probes
# =============================================================================
livenessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
readinessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
startupProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
successThreshold: 1
# =============================================================================
# Pod Disruption Budget
# =============================================================================
podDisruptionBudget:
# -- Enable PodDisruptionBudget
enabled: true
# -- Minimum available pods during voluntary disruptions
minAvailable: 1
# -- Maximum unavailable pods (alternative to minAvailable)
# maxUnavailable: 1
# =============================================================================
# Network Policy
# =============================================================================
networkPolicy:
# -- Enable NetworkPolicy
enabled: true
# -- Additional ingress rules
additionalIngressRules: []
# -- Additional egress rules
additionalEgressRules: []
# =============================================================================
# MCP Sidecar (Model Context Protocol server)
# =============================================================================
mcp:
# -- Enable MCP sidecar container
enabled: false
image:
registry: ghcr.io
repository: smartgift/claude-code-monitor-mcp
tag: "" # Defaults to .Chart.AppVersion if empty
pullPolicy: IfNotPresent
# -- MCP HTTP transport port
port: 8819
# -- Resource limits for MCP sidecar
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
# -- MCP environment variables
env:
MCP_TRANSPORT: http
MCP_PORT: "8819"
DASHBOARD_URL: "http://localhost:4820"
# -- Container security context for MCP
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
# =============================================================================
# Monitoring
# =============================================================================
monitoring:
# -- Enable Prometheus monitoring
enabled: false
serviceMonitor:
# -- Enable ServiceMonitor resource (requires Prometheus Operator)
enabled: false
# -- Namespace for the ServiceMonitor (defaults to release namespace)
namespace: ""
# -- Additional labels for the ServiceMonitor
labels: {}
# -- Scrape interval
interval: 30s
# -- Scrape timeout
scrapeTimeout: 10s
# -- Metric path
path: /api/metrics
# -- Honor labels from the target
honorLabels: false