agentleFS
SWEStashSWEStash/swe-workflow-skills/skills/gitops-delivery/SKILL.md

gitops-delivery

Skill1 starsChanged 4 days agoMITView on GitHub

Design GitOps continuous delivery with ArgoCD or Flux — declarative reconciliation, cross-repo CI/CD triggers, drift detection, progressive delivery. Triggers: ArgoCD, Flux, FluxCD, GitOps, git-based deployment, declarative delivery, auto-sync, drift detection, cross-repo trigger, reconciliation loop, pull-based deployment, canary GitOps.

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 3 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Test the full GitOps pipeline:

    line 301
  2. Very specific:

    Git is the source of truth: If it's not in Git, it doesn't exist.

    line 319
  3. Distinctive:

    KISS: Start with a single ArgoCD Application per environment.

    line 321
  4. Distinctive:

    YAGNI: Don't set up Argo Rollouts for a service with 10 requests per minute.

    line 322

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

GitOps Delivery

GitOps makes Git the single source of truth for deployment state. An operator watches a Git repository and continuously reconciles the cluster to match what's declared in Git. The deployment repo defines the desired state — the GitOps operator enforces it.

Step 1: Choose the GitOps Model

Pull-based (recommended): An operator running in the cluster watches the deployment repo and applies changes. No CI system needs cluster credentials.

  • ArgoCD: Application-centric, strong UI, sync waves for ordering, multi-cluster support
  • Flux: Toolkit-based, composable, native Kustomize/Helm support, image automation

Push-based (simpler but less robust): CI pipeline runs kubectl apply or helm upgrade after building. Simpler to set up but has drawbacks: CI needs cluster credentials, no drift detection, no self-healing.

Decision guide:

FactorPush-basedPull-based (GitOps)
Setup complexityLowerHigher initial setup
Cluster credentialsCI needs themOnly operator needs them
Drift detectionNoneAutomatic
Self-healingNoneOperator reverts manual changes
Audit trailCI logsGit history (stronger)
Multi-clusterDuplicated CI jobsNative support

When push-based is fine: Single cluster, single environment, small team, no compliance requirements. See cicd-pipeline for push-based patterns.

When GitOps is worth it: Multiple environments, compliance/audit needs, multi-cluster, or you want drift detection and self-healing.

Either way, say this: version pinning and a declarative record of what is deployed are worth adopting regardless of which side of this decision you land on — they are what make a deploy reproducible and a rollback a known-good revert, and none of that requires an operator. Point at deployment-repo even when you are recommending against ArgoCD; a team that keeps pinned manifests in Git gets most of the auditability benefit now, and has already done the setup work if they adopt GitOps later. Recommending push-based is not a reason to leave the handoff out.

Step 2: Design Cross-Repo Triggers

The critical bridge: when an app repo builds a new image, the deployment repo must be updated. This is the most common source of friction in GitOps setups.

Pattern A: Automated PR via GitHub Actions repository_dispatch

App repo CI triggers a workflow in the deployment repo:

# In app repo: .github/workflows/release.yml
- name: Mint a short-lived token for the deployment repo
  id: app-token
  uses: actions/create-github-app-token@v1
  with:
    app-id: ${{ vars.DEPLOY_APP_ID }}
    private-key: ${{ secrets.DEPLOY_APP_PRIVATE_KEY }}
    repositories: deployment-repo
- name: Trigger deployment repo update
  uses: peter-evans/repository-dispatch@v3
  with:
    token: ${{ steps.app-token.outputs.token }}
    repository: org/deployment-repo
    event-type: version-bump
    client-payload: |
      {
        "service": "user-service",
        "version": "v1.8.0",
        "image": "ghcr.io/org/user-service:v1.8.0"
      }
# In deployment repo: .github/workflows/version-bump.yml
on:
  repository_dispatch:
    types: [version-bump]

jobs:
  update-version:
    steps:
      - uses: actions/checkout@v4
      - name: Update versions.yaml
        run: |
          yq e ".services.${{ github.event.client_payload.service }}.version = \"${{ github.event.client_payload.version }}\"" \
            -i environments/dev/versions.yaml
      - name: Create PR
        uses: peter-evans/create-pull-request@v6
        with:
          title: "bump ${{ github.event.client_payload.service }} to ${{ github.event.client_payload.version }}"
          branch: "bump/${{ github.event.client_payload.service }}-${{ github.event.client_payload.version }}"

Pattern B: Renovate / Dependabot for image tags

Configure Renovate to watch container registries and create PRs when new tags appear:

{
  "packageRules": [
    {
      "matchDatasources": ["docker"],
      "matchPackagePatterns": ["ghcr.io/org/*"],
      "automerge": false,
      "labels": ["version-bump"]
    }
  ]
}

Pattern C: GitLab CI downstream pipeline

# In app repo: .gitlab-ci.yml
trigger-deployment:
  stage: deploy
  trigger:
    project: org/deployment-repo
    branch: main
    strategy: depend
  variables:
    SERVICE_NAME: user-service
    SERVICE_VERSION: $CI_COMMIT_TAG

Recommendation: Pattern A (repository_dispatch + PR) for most teams. It creates an auditable PR, allows contract tests to run before merge, and doesn't require additional tooling. Use Pattern B (Renovate) if you want fully automated version tracking without custom workflows.

Step 3: Configure the GitOps Operator

ArgoCD Setup

Application per service per environment:

# argocd/staging/user-service.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: user-service-staging
  namespace: argocd
  labels:
    environment: staging
    service: user-service
spec:
  project: default
  source:
    repoURL: https://github.com/org/deployment-repo
    targetRevision: main
    path: helm/user-service
    helm:
      valueFiles:
        - ../../environments/staging/user-service-values.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: staging
  syncPolicy:
    automated:              # Auto-sync for staging
      prune: true           # Remove resources not in Git
      selfHeal: true        # Revert manual changes
    syncOptions:
      - CreateNamespace=true
    retry:
      limit: 3
      backoff:
        duration: 5s
        factor: 2

Production — manual sync with approval:

# argocd/production/user-service.yaml
spec:
  syncPolicy: {}            # No automated sync — requires manual sync or CI trigger
  # Add sync windows to restrict when syncs can happen:
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
    # Sync windows defined in the ArgoCD project

App of Apps pattern (manage all Applications as a single unit):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: platform-staging
spec:
  source:
    repoURL: https://github.com/org/deployment-repo
    path: argocd/staging       # Directory containing all Application YAMLs
  destination:
    server: https://kubernetes.default.svc

Sync waves (control deployment order):

# Database migration job runs first (wave 0), then services (wave 1), then ingress (wave 2)
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "0"   # Lower runs first

Flux Setup

# flux/staging/kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: staging-apps
  namespace: flux-system
spec:
  interval: 5m
  sourceRef:
    kind: GitRepository
    name: deployment-repo
  path: ./overlays/staging
  prune: true
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: user-service
      namespace: staging
  timeout: 3m

Flux image automation (auto-update image tags):

apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: user-service
spec:
  imageRepositoryRef:
    name: user-service
  policy:
    semver:
      range: ">=1.0.0"

See references/gitops-patterns.md for complete manifests and templates/gitops-config.md for ready-to-use templates.

Step 4: Implement Progressive Delivery

Layer progressive delivery on top of GitOps for safer production rollouts. This step is optional for lightweight setups but critical at scale.

Argo Rollouts (works with ArgoCD):

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: user-service
spec:
  strategy:
    canary:
      steps:
        - setWeight: 10       # Send 10% of traffic to new version
        - pause: { duration: 5m }
        - analysis:
            templates:
              - templateName: success-rate
        - setWeight: 50
        - pause: { duration: 10m }
        - analysis:
            templates:
              - templateName: success-rate
      # Auto-rollback if analysis fails

Analysis template (gate on metrics):

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  metrics:
    - name: success-rate
      interval: 1m
      successCondition: result[0] >= 0.99
      provider:
        prometheus:
          address: http://prometheus:9090
          query: |
            sum(rate(http_requests_total{service="user-service",status=~"2.."}[5m]))
            /
            sum(rate(http_requests_total{service="user-service"}[5m]))

Flagger (works with Flux): Similar concept — canary analysis using Prometheus, Datadog, or other metrics providers. Flagger automatically manages the canary/primary services and traffic splitting.

When to skip progressive delivery: Dev and staging environments (just deploy directly). Small teams with low traffic. Services with comprehensive E2E tests that catch issues before deploy.

Step 5: Validate End-to-End

Test the full GitOps pipeline:

  • Trigger flow: Merge a change in an app repo -> verify a PR appears in the deployment repo
  • Contract validation: The deployment repo PR CI runs contract tests against the new version combination
  • GitOps sync: After merging the deployment repo PR, the operator detects the change and syncs
  • Health checks: The operator reports healthy status after sync
  • Drift detection: Manually modify a resource in the cluster -> verify the operator reverts it
  • Rollback: Revert a commit in the deployment repo -> verify the operator rolls back the cluster
  • Sync windows (if configured): Verify syncs are blocked outside allowed windows
  • Progressive delivery (if configured): Verify canary analysis runs and gates promotion

Monitoring the GitOps pipeline:

  • ArgoCD: Built-in UI shows sync status, health, and history per Application
  • Flux: flux get kustomizations shows reconciliation status
  • Both: Export metrics to Prometheus for alerting on sync failures

Principles Applied

  • Git is the source of truth: If it's not in Git, it doesn't exist. No kubectl edit in production, no manual Helm upgrades.
  • Pull over push: The cluster pulls desired state from Git rather than CI pushing to the cluster. This inverts the security model — the cluster needs Git read access, not the other way around.
  • KISS: Start with a single ArgoCD Application per environment. Add App of Apps, sync waves, and progressive delivery as complexity demands.
  • YAGNI: Don't set up Argo Rollouts for a service with 10 requests per minute. Don't configure multi-cluster GitOps for a single cluster.
  • Declarative over imperative: Define the desired state, let the operator figure out how to get there. Avoid custom sync scripts.

Cross-Skill References

  • deployment-repo — pinned versions and declarative manifests in Git, valuable with or without an operator: it is what ArgoCD/Flux watch if you adopt GitOps, and the reproducibility/rollback substrate if you stay push-based. Design the repo structure first either way.
  • cicd-pipeline — cross-repo trigger pipelines that update the deployment repo on new builds
  • rollback-strategy — in GitOps, rollback = revert a Git commit; the operator handles the rest
  • observability-design — metrics and dashboards for monitoring sync status, drift, and progressive delivery analysis
  • containerization — Helm chart structure and Kustomize overlay patterns used by the operator
  • infrastructure-as-code — Terraform for cluster and infrastructure provisioning (separate from app deployment)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.