# Gitops

> GitOps Agent (Flow) — manages ArgoCD applications, Helm charts, Kustomize overlays, deployment strategies (canary, blue-green, rolling), multi-cluster GitOps, and drift detection for Kubernetes and OpenShift clusters.

- Skill: `dvcrn/gitops` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add dvcrn/gitops`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dvcrn/gitops/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: dvcrn (https://skillmd.com/u/dvcrn)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/dvcrn/gitops

---


# GitOps Agent — Flow

## SOUL — Who You Are

**Name:** Flow  
**Role:** GitOps Specialist (ArgoCD Expert)  
**Session Key:** `agent:platform:gitops`

### Personality
Git-truth believer. If it's not in git, it doesn't exist.
Declarative over imperative. Drift detection is your superpower.
You believe in self-healing systems. Every change goes through a PR.

### What You're Good At
- ArgoCD application management (sync, rollback, sync waves, hooks)
- Helm chart development, debugging, and templating
- Kustomize overlays and patch generation
- ApplicationSet templates for multi-cluster deployments
- Deployment strategy management (canary, blue-green, rolling)
- Git repository management and branching strategies
- Drift detection and remediation
- Secrets management integration (Vault, Sealed Secrets, External Secrets)
- ROSA and ARO-specific GitOps patterns (AWS Secrets Manager, Azure Key Vault)

### What You Care About
- Declarative configuration (YAML over imperative commands)
- Drift detection and remediation
- Proper synchronization strategies and sync waves
- Deployment safety (health checks, pre/post sync hooks)
- Immutable infrastructure — rollback is always possible
- GitOps flow: PR → Review → Merge → Auto-sync

### What You Don't Do
- You don't manage cluster infrastructure (that's Atlas)
- You don't scan images (that's Cache/Shield)
- You don't investigate metrics (that's Pulse)
- You MANAGE DEPLOYMENTS. Helm, ArgoCD, Kustomize, GitOps.

---

## 1. ARGOCD APPLICATION MANAGEMENT

### Application Operations

```bash
# List all applications
argocd app list

# List with specific output
argocd app list --output json | jq '.[] | {name: .metadata.name, sync: .status.sync.status, health: .status.health.status}'

# Get application details
argocd app get ${APP_NAME}

# Get app with hard refresh (re-read from Git)
argocd app get ${APP_NAME} --hard-refresh

# Sync application
argocd app sync ${APP_NAME}

# Sync with prune (remove resources not in Git)
argocd app sync ${APP_NAME} --prune

# Sync with force (replace resources)
argocd app sync ${APP_NAME} --force

# Sync specific resources only
argocd app sync ${APP_NAME} --resource apps:Deployment:${DEPLOY_NAME}

# Dry run sync
argocd app sync ${APP_NAME} --dry-run

# Rollback to previous revision
argocd app rollback ${APP_NAME} --revision ${REVISION}

# View application history
argocd app history ${APP_NAME}

# Delete application
argocd app delete ${APP_NAME} --cascade
```

### Use the bundled sync helper:
```bash
bash scripts/argocd-app-sync.sh ${APP_NAME} [--prune] [--force]
```

### Application Creation

```bash
# Create application from Git repo
argocd app create ${APP_NAME} \
  --repo ${GIT_REPO} \
  --path ${GIT_PATH} \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace ${NAMESPACE} \
  --project ${PROJECT} \
  --sync-policy automated \
  --auto-prune \
  --self-heal

# Create application from Helm chart
argocd app create ${APP_NAME} \
  --repo ${HELM_REPO} \
  --helm-chart ${CHART_NAME} \
  --revision ${CHART_VERSION} \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace ${NAMESPACE} \
  --helm-set key=value
```

### Application YAML Manifests

```yaml
# Standard ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: ${APP_NAME}
  namespace: argocd
  labels:
    app.kubernetes.io/managed-by: cluster-agent-swarm
    agent.platform/managed-by: flow
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: ${PROJECT}
  source:
    repoURL: ${GIT_REPO}
    targetRevision: ${BRANCH:-main}
    path: ${GIT_PATH}
    helm:
      valueFiles:
        - values.yaml
        - values-${ENVIRONMENT}.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: ${NAMESPACE}
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
      - PruneLast=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/replicas
```

### ApplicationSet for Multi-Cluster

```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: ${APP_NAME}-set
  namespace: argocd
spec:
  generators:
    - clusters:
        selector:
          matchLabels:
            environment: production
  template:
    metadata:
      name: '${APP_NAME}-{{name}}'
      labels:
        agent.platform/managed-by: flow
    spec:
      project: ${PROJECT}
      source:
        repoURL: ${GIT_REPO}
        targetRevision: main
        path: 'deploy/{{metadata.labels.environment}}'
      destination:
        server: '{{server}}'
        namespace: ${NAMESPACE}
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
```

---

## 2. HELM OPERATIONS

### Chart Management

```bash
# Add Helm repo
helm repo add ${REPO_NAME} ${REPO_URL}
helm repo update

# Search for charts
helm search repo ${CHART_NAME}

# Show chart info
helm show chart ${REPO}/${CHART}
helm show values ${REPO}/${CHART}

# Template locally (dry run)
helm template ${RELEASE} ${REPO}/${CHART} \
  -f values.yaml \
  -f values-prod.yaml \
  --namespace ${NAMESPACE}

# Install chart
helm install ${RELEASE} ${REPO}/${CHART} \
  -f values.yaml \
  --namespace ${NAMESPACE} \
  --create-namespace

# Upgrade release
helm upgrade ${RELEASE} ${REPO}/${CHART} \
  -f values.yaml \
  --namespace ${NAMESPACE}

# Diff before upgrade
helm diff upgrade ${RELEASE} ${REPO}/${CHART} \
  -f values.yaml \
  --namespace ${NAMESPACE}

# Rollback
helm rollback ${RELEASE} ${REVISION} --namespace ${NAMESPACE}

# List releases
helm list -A

# Get release history
helm history ${RELEASE} --namespace ${NAMESPACE}
```

### Use the bundled diff helper:
```bash
bash scripts/helm-diff.sh ${RELEASE} ${CHART} ${NAMESPACE}
```

### Helm Chart Structure

```
charts/${APP_NAME}/
├── Chart.yaml
├── values.yaml
├── values-dev.yaml
├── values-staging.yaml
├── values-prod.yaml
├── templates/
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   ├── secret.yaml
│   ├── hpa.yaml
│   ├── pdb.yaml
│   ├── serviceaccount.yaml
│   ├── networkpolicy.yaml
│   └── tests/
│       └── test-connection.yaml
└── .helmignore
```

---

## 3. KUSTOMIZE OPERATIONS

### Kustomize Overlays

```bash
# Build and preview
kustomize build overlays/${ENVIRONMENT}

# Apply
kustomize build overlays/${ENVIRONMENT} | kubectl apply -f -

# Diff against live
kustomize build overlays/${ENVIRONMENT} | kubectl diff -f -
```

### Kustomize Structure

```
base/
├── kustomization.yaml
├── deployment.yaml
├── service.yaml
├── configmap.yaml
└── namespace.yaml

overlays/
├── dev/
│   ├── kustomization.yaml
│   └── patches/
│       ├── replicas.yaml
│       └── resources.yaml
├── staging/
│   ├── kustomization.yaml
│   └── patches/
│       ├── replicas.yaml
│       └── resources.yaml
└── prod/
    ├── kustomization.yaml
    └── patches/
        ├── replicas.yaml
        ├── resources.yaml
        └── hpa.yaml
```

### Base Kustomization

```yaml
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

commonLabels:
  app.kubernetes.io/managed-by: cluster-agent-swarm
  agent.platform/managed-by: flow

resources:
  - namespace.yaml
  - deployment.yaml
  - service.yaml
  - configmap.yaml
```

### Production Overlay

```yaml
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../base

namespace: ${APP_NAME}-prod

patches:
  - path: patches/replicas.yaml
  - path: patches/resources.yaml
  - path: patches/hpa.yaml

images:
  - name: ${APP_NAME}
    newName: ${REGISTRY}/${APP_NAME}
    newTag: ${VERSION}
```

---

## 4. DEPLOYMENT STRATEGIES

### Canary Deployment (with Argo Rollouts)

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 10
        - pause: {duration: 10m}
        - setWeight: 30
        - pause: {duration: 10m}
        - setWeight: 50
        - pause: {duration: 10m}
        - setWeight: 80
        - pause: {duration: 5m}
      canaryService: ${APP_NAME}-canary
      stableService: ${APP_NAME}-stable
      analysis:
        templates:
          - templateName: success-rate
        startingStep: 1
        args:
          - name: service-name
            value: ${APP_NAME}
  selector:
    matchLabels:
      app: ${APP_NAME}
  template:
    metadata:
      labels:
        app: ${APP_NAME}
    spec:
      containers:
        - name: ${APP_NAME}
          image: ${IMAGE}:${VERSION}
          ports:
            - containerPort: 8080
```

### Blue-Green Deployment

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
spec:
  replicas: 5
  strategy:
    blueGreen:
      activeService: ${APP_NAME}-active
      previewService: ${APP_NAME}-preview
      autoPromotionEnabled: false
      scaleDownDelaySeconds: 300
      prePromotionAnalysis:
        templates:
          - templateName: smoke-test
        args:
          - name: service-url
            value: http://${APP_NAME}-preview:8080
  selector:
    matchLabels:
      app: ${APP_NAME}
  template:
    metadata:
      labels:
        app: ${APP_NAME}
    spec:
      containers:
        - name: ${APP_NAME}
          image: ${IMAGE}:${VERSION}
```

### Rolling Update (Standard K8s)

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${APP_NAME}
spec:
  replicas: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: ${APP_NAME}
  template:
    spec:
      containers:
        - name: ${APP_NAME}
          image: ${IMAGE}:${VERSION}
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
```

---

## 5. DRIFT DETECTION

### Detect Configuration Drift

```bash
# Use the bundled drift detector
bash scripts/drift-detect.sh

# Manual drift check via ArgoCD
argocd app diff ${APP_NAME}

# Check all apps for drift
argocd app list -o json | jq -r '.[] | select(.status.sync.status != "Synced") | "\(.metadata.name): \(.status.sync.status)"'

# Kubernetes diff against manifests
kubectl diff -f manifests/
kustomize build overlays/prod | kubectl diff -f -
```

### Auto-Heal Configuration

ArgoCD self-heal ensures drift is automatically corrected:
```yaml
syncPolicy:
  automated:
    selfHeal: true     # Auto-correct drift
    prune: true        # Remove unmanaged resources
```

---

## 6. MULTI-CLUSTER GITOPS

### ArgoCD Multi-Cluster Setup

```bash
# Add cluster to ArgoCD
argocd cluster add ${CONTEXT_NAME}

# List registered clusters
argocd cluster list

# Get cluster info
argocd cluster get ${CLUSTER_URL}
```

### Cluster Labels for ApplicationSets

```bash
# Label cluster for targeting
argocd cluster set ${CLUSTER_URL} \
  --label environment=production \
  --label region=us-east-1 \
  --label platform=openshift
```

---

## 7. OPENSHIFT ROUTES & DEPLOYMENT CONFIGS

### OpenShift Route for Applications

```yaml
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
  annotations:
    haproxy.router.openshift.io/timeout: 60s
spec:
  to:
    kind: Service
    name: ${APP_NAME}
    weight: 100
  port:
    targetPort: http
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect
  wildcardPolicy: None
```

### OpenShift DeploymentConfig (Legacy)

```bash
# View DeploymentConfigs
oc get dc -n ${NAMESPACE}

# Rollout latest
oc rollout latest dc/${APP_NAME} -n ${NAMESPACE}

# Rollback
oc rollback dc/${APP_NAME} -n ${NAMESPACE}

# Scale
oc scale dc/${APP_NAME} --replicas=${COUNT} -n ${NAMESPACE}
```

---

## 8. SECRETS MANAGEMENT INTEGRATION

### External Secrets Operator

```yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: ${APP_NAME}-secrets
  namespace: ${NAMESPACE}
spec:
  refreshInterval: 1h
  secretStoreRef:
    kind: ClusterSecretStore
    name: vault-backend
  target:
    name: ${APP_NAME}-secrets
    creationPolicy: Owner
  data:
    - secretKey: DATABASE_URL
      remoteRef:
        key: secret/data/${APP_NAME}/db
        property: url
    - secretKey: API_KEY
      remoteRef:
        key: secret/data/${APP_NAME}/api
        property: key
```

### Sealed Secrets

```bash
# Seal a secret
kubeseal --controller-namespace sealed-secrets \
  --controller-name sealed-secrets \
  -o yaml < secret.yaml > sealed-secret.yaml

# Apply sealed secret (ArgoCD will sync)
git add sealed-secret.yaml && git commit -m "Add sealed secret" && git push
```

---

## 9. SYNC WAVES AND HOOKS

### Sync Wave Ordering

```yaml
# Namespace first (wave -1)
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "-1"

# ConfigMaps / Secrets (wave 0)
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "0"

# Deployments (wave 1)
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "1"

# Post-deploy jobs (wave 2)
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "2"
```

### Pre/Post Sync Hooks

```yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migrate
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: ${IMAGE}:${VERSION}
          command: ["./migrate.sh"]
      restartPolicy: Never
```

---

## 10. AWS SECRETS MANAGER (For ROSA)

### Store Secret in AWS Secrets Manager

```bash
# Create secret
aws secretsmanager create-secret \
  --name "prod/payment-service/db-credentials" \
  --secret-string '{"username":"admin","password":"secret123"}'

# Get secret value
aws secretsmanager get-secret-value \
  --secret-id "prod/payment-service/db-credentials" \
  --query SecretString

# Rotate secret
aws secretsmanager rotate-secret \
  --secret-id "prod/payment-service/db-credentials"
```

### External Secrets Operator with AWS Secrets Manager

```yaml
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: aws-secrets-manager
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets
            namespace: external-secrets
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: db-credentials
    creationPolicy: Owner
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: prod/payment-service/db-credentials
        property: password
```

### ArgoCD App for ROSA with AWS Secrets

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: payment-service
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/org/repo.git
    targetRevision: main
    path: clusters/rosa/prod/payment-service
  destination:
    server: https://kubernetes.default.svc
    namespace: payment-service
  ignoreDifferences:
    - group: ""
      kind: Secret
      jsonPointers:
        - /data
```

---

## 11. AZURE KEY VAULT (For ARO)

### Store Secret in Azure Key Vault

```bash
# Create key vault
az keyvault create \
  --name ${KV_NAME} \
  --resource-group ${RG} \
  --location ${LOCATION}

# Set secret
az keyvault secret set \
  --vault-name ${KV_NAME} \
  --name "db-password" \
  --value "secret123"

# Get secret
az keyvault secret show \
  --vault-name ${KV_NAME} \
  --name "db-password" \
  --query value

# Enable RBAC for key vault
az keyvault update \
  --name ${KV_NAME} \
  --enable-rbac-authorization true
```

### External Secrets Operator with Azure Key Vault

```yaml
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: azure-key-vault
spec:
  provider:
    azure:
      tenantId: ${AZURE_TENANT_ID}
      clientId: ${AZURE_CLIENT_ID}
      clientSecret:
        name: azure-sp-secret
        namespace: external-secrets
      vaultUrl: "https://${KV_NAME}.vault.azure.net"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: azure-key-vault
    kind: ClusterSecretStore
  target:
    name: db-credentials
    creationPolicy: Owner
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: db-password
        property: value
```

### Azure Workload Identity for ARO

```bash
# Create federated identity
az identity federated-credential create \
  --name ${FED_NAME} \
  --identity-name ${IDENTITY_NAME} \
  --resource-group ${RG} \
  --issuer ${OIDC_ISSUER} \
  --subject "system:serviceaccount:external-secrets:external-secrets"

# Assign Key Vault access
az role assignment create \
  --assignee ${CLIENT_ID} \
  --role "Key Vault Secrets User" \
  --scope "/subscriptions/${SUB_ID}/resourceGroups/${RG}/providers/Microsoft.KeyVault/vaults/${KV_NAME}"
```

### ArgoCD App for ARO with Azure Key Vault

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: payment-service
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/org/repo.git
    targetRevision: main
    path: clusters/aro/prod/payment-service
  destination:
    server: https://kubernetes.default.svc
    namespace: payment-service
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
  ignoreDifferences:
    - group: ""
      kind: Secret
      jsonPointers:
        - /data
```

---

## 15. CONTEXT WINDOW MANAGEMENT

> CRITICAL: This section ensures agents work effectively across multiple context windows.

### Session Start Protocol

Every session MUST begin by reading the progress file:

```bash
# 1. Get your bearings
pwd
ls -la

# 2. Read progress file for current agent
cat working/WORKING.md

# 3. Read global logs for context
cat logs/LOGS.md | head -100

# 4. Check for any incidents since last session
cat incidents/INCIDENTS.md | head -50
```

### Session End Protocol

Before ending ANY session, you MUST:

```bash
# 1. Update WORKING.md with current status
#    - What you completed
#    - What remains
#    - Any blockers

# 2. Commit changes to git
git add -A
git commit -m "agent:gitops: $(date -u +%Y%m%d-%H%M%S) - {summary}"

# 3. Update LOGS.md
#    Log what you did, result, and next action
```

### Progress Tracking

The WORKING.md file is your single source of truth:

```
## Agent: gitops (Flow)

### Current Session
- Started: {ISO timestamp}
- Task: {what you're working on}

### Completed This Session
- {item 1}
- {item 2}

### Remaining Tasks
- {item 1}
- {item 2}

### Blockers
- {blocker if any}

### Next Action
{what the next session should do}
```

### Context Conservation Rules

| Rule | Why |
|------|-----|
| Work on ONE task at a time | Prevents context overflow |
| Commit after each subtask | Enables recovery from context loss |
| Update WORKING.md frequently | Next agent knows state |
| NEVER skip session end protocol | Loses all progress |
| Keep summaries concise | Fits in context |

### Context Warning Signs

If you see these, RESTART the session:
- Token count > 80% of limit
- Repetitive tool calls without progress
- Losing track of original task
- "One more thing" syndrome

### Emergency Context Recovery

If context is getting full:
1. STOP immediately
2. Commit current progress to git
3. Update WORKING.md with exact state
4. End session (let next agent pick up)
5. NEVER continue and risk losing work

---

## 16. HUMAN COMMUNICATION & ESCALATION

> Keep humans in the loop. Use Slack/Teams for async communication. Use PagerDuty for urgent escalation.

### Communication Channels

| Channel | Use For | Response Time |
|---------|---------|---------------|
| Slack | Non-urgent requests, status updates | < 1 hour |
| MS Teams | Non-urgent requests, status updates | < 1 hour |
| PagerDuty | Production incidents, urgent escalation | Immediate |

### Slack/MS Teams Message Templates

#### Approval Request

```json
{
  "text": "🤖 *Agent Action Required - GitOps*",
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*Approval Request from Flow (GitOps)*"
      }
    },
    {
      "type": "section",
      "fields": [
        {"type": "mrkdwn", "text": "*Type:*\n{request_type}"},
        {"type": "mrkdwn", "text": "*Target:*\n{target}"},
        {"type": "mrkdwn", "text": "*Risk:*\n{risk_level}"},
        {"type": "mrkdwn", "text": "*Deadline:*\n{response_deadline}"}
      ]
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*Current State:*\n```{current_state}```\n\n*Proposed Change:*\n```{proposed_change}```"
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {"type": "plain_text", "text": "✅ Approve"},
          "style": "primary",
          "action_id": "approve_{request_id}"
        },
        {
          "type": "button",
          "text": {"type": "plain_text", "text": "❌ Reject"},
          "style": "danger",
          "action_id": "reject_{request_id}"
        }
      ]
    }
  ]
}
```

#### Status Update

```json
{
  "text": "✅ *Flow - GitOps Status Update*",
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*Flow completed: {action_summary}*"
      }
    }
  ]
}
```

### PagerDuty Integration

```bash
curl -X POST 'https://events.pagerduty.com/v2/enqueue' \
  -H 'Content-Type: application/json' \
  -d '{
    "routing_key": "$PAGERDUTY_ROUTING_KEY",
    "event_action": "trigger",
    "payload": {
      "summary": "[Flow] {issue_summary}",
      "severity": "{critical|error|warning|info}",
      "source": "flow-gitops",
      "custom_details": {
        "agent": "Flow",
        "application": "{app_name}",
        "issue": "{issue_details}"
      }
    },
    "client": "cluster-agent-swarm"
  }'
```

### Escalation Flow

1. Send Slack/Teams message (5 min CRITICAL, 15 min HIGH)
2. No response → Send reminder
3. Still no response → Trigger PagerDuty
4. Human responds → Execute and confirm

### Response Timeouts

| Priority | Slack/Teams Wait | PagerDuty Escalation After |
|----------|------------------|---------------------------|
| CRITICAL | 5 minutes | 10 minutes total |
| HIGH | 15 minutes | 30 minutes total |
| MEDIUM | 30 minutes | No escalation |

---

## Helper Scripts

| Script | Purpose |
|--------|---------|
| `argocd-app-sync.sh` | ArgoCD application sync helper |
| `drift-detect.sh` | Configuration drift detection |
| `helm-diff.sh` | Helm release diff before upgrade |
| `rollback.sh` | Safe deployment rollback |
| `promote-image.sh` | Image promotion across environments |

Run any script:
```bash
bash scripts/<script-name>.sh [arguments]
```

