Commit 2c6d94568a91

Vincent Demeester <vincent@sbr.pm>
2025-12-04 12:31:59
feat: Add comprehensive Tekton skill for Kubernetes-native CI/CD
- Enable Tekton pipeline development with tasks, triggers, and GitOps - Provide production best practices and integration with ArgoCD/Flux - Support container builds with Kaniko/Buildah and event-driven automation Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent f67d529
dots/.config/claude/skills/Tekton/workflows/BestPractices.md
@@ -0,0 +1,590 @@
+# Best Practices Workflow
+
+Tekton best practices for security, performance, reliability, and maintainability.
+
+## When to Use
+
+- Optimizing Tekton pipelines
+- Implementing security best practices
+- Improving performance
+- Operating Tekton at scale
+- Troubleshooting common issues
+
+## Security Best Practices
+
+### Workspace-Based Authentication (2024 Recommendation)
+
+**DO: Use workspace-based authentication**
+```yaml
+workspaces:
+  - name: git-credentials
+    secret:
+      secretName: git-ssh-key
+```
+
+**DON'T: Rely only on built-in credential initialization**
+- Being phased out
+- All steps get access to all credentials
+- Credentials copied to disk
+- Security issues with different UIDs
+
+### ServiceAccount and RBAC
+
+**Create dedicated ServiceAccounts:**
+```yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: pipeline-sa
+secrets:
+  - name: docker-credentials
+  - name: git-credentials
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: pipeline-role
+rules:
+  - apiGroups: [""]
+    resources: ["pods", "services"]
+    verbs: ["get", "list"]
+  - apiGroups: ["apps"]
+    resources: ["deployments"]
+    verbs: ["get", "list", "update", "patch"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: pipeline-binding
+subjects:
+  - kind: ServiceAccount
+    name: pipeline-sa
+roleRef:
+  kind: Role
+  name: pipeline-role
+  apiGroup: rbac.authorization.k8s.io
+```
+
+**Principle of least privilege:**
+- Create separate ServiceAccounts for CI and CD
+- Grant only necessary permissions
+- Use Role instead of ClusterRole when possible
+- Regularly audit permissions
+
+### Pod Security
+
+```yaml
+spec:
+  steps:
+    - name: secure-step
+      image: alpine
+      securityContext:
+        runAsNonRoot: true
+        runAsUser: 1000
+        allowPrivilegeEscalation: false
+        readOnlyRootFilesystem: true
+        capabilities:
+          drop:
+            - ALL
+```
+
+### Secrets Management
+
+**DO:**
+- Use Kubernetes Secrets or external secret managers (Vault, AWS Secrets Manager)
+- Mount secrets as volumes, not environment variables
+- Use short-lived tokens (OAuth, OIDC)
+- Rotate secrets regularly
+- Scan secrets with tools like gitleaks, trufflehog
+
+**DON'T:**
+- Commit secrets to Git
+- Print secrets in logs
+- Use long-lived credentials
+- Share secrets across environments
+
+## Performance Best Practices
+
+### Resource Management
+
+**Always set resource requests and limits:**
+```yaml
+steps:
+  - name: build
+    image: maven:3.8
+    resources:
+      requests:
+        cpu: 1000m
+        memory: 2Gi
+      limits:
+        cpu: 2000m
+        memory: 4Gi
+```
+
+**Guidelines:**
+- Set requests based on average usage
+- Set limits 1.5-2x higher than requests
+- Monitor actual usage: `kubectl top pods`
+- Use task-level resources for simplicity
+
+### Configure Pipeline Pruner
+
+**Automatic cleanup of old resources:**
+```yaml
+apiVersion: operator.tekton.dev/v1alpha1
+kind: TektonConfig
+metadata:
+  name: config
+spec:
+  pruner:
+    disabled: false
+    schedule: "0 8 * * *"  # Daily at 8 AM
+    keep: 3  # Keep last 3 runs
+    resources:
+      - pipelinerun
+      - taskrun
+```
+
+**Manual cleanup:**
+```bash
+# Keep last 5 runs
+tkn pipelinerun delete --keep 5 -f
+
+# Delete runs older than 60 minutes
+tkn pipelinerun delete --keep-since 60 -f
+
+# Delete all failed runs
+tkn pipelinerun delete --all --failed -f
+```
+
+### Workspace Optimization
+
+**Use volumeClaimTemplate for isolation:**
+```yaml
+workspaces:
+  - name: workspace
+    volumeClaimTemplate:
+      spec:
+        accessModes:
+          - ReadWriteOnce
+        resources:
+          requests:
+            storage: 1Gi
+```
+
+**Avoid PVC sharing conflicts:**
+- ReadWriteOnce: Limited to single node
+- ReadWriteMany: Best for Tekton but less common
+- Use emptyDir for temporary data
+- Use subPaths for organization
+
+### Caching Strategies
+
+**Maven cache:**
+```yaml
+workspaces:
+  - name: maven-cache
+    persistentVolumeClaim:
+      claimName: maven-cache-pvc
+
+steps:
+  - name: build
+    image: maven:3.8
+    env:
+      - name: MAVEN_OPTS
+        value: "-Dmaven.repo.local=$(workspaces.maven-cache.path)"
+```
+
+**Kaniko cache:**
+```yaml
+args:
+  - --cache=true
+  - --cache-repo=myregistry.com/cache
+  - --cache-ttl=24h
+```
+
+**npm cache:**
+```yaml
+workspaces:
+  - name: npm-cache
+
+steps:
+  - name: install
+    image: node:18
+    script: |
+      npm config set cache $(workspaces.npm-cache.path)
+      npm install
+```
+
+## Reliability Best Practices
+
+### Error Handling
+
+**Use retries for flaky operations:**
+```yaml
+tasks:
+  - name: flaky-network-test
+    retries: 3
+    taskRef:
+      name: integration-test
+```
+
+**Use onError for optional tasks:**
+```yaml
+tasks:
+  - name: optional-scan
+    onError: continue
+    taskRef:
+      name: security-scan
+```
+
+**Implement timeout:**
+```yaml
+spec:
+  timeouts:
+    pipeline: 2h
+    tasks: 1h
+    finally: 30m
+
+tasks:
+  - name: long-running
+    timeout: 45m
+```
+
+### Finally Tasks for Cleanup
+
+```yaml
+finally:
+  - name: cleanup-workspace
+    taskRef:
+      name: cleanup
+    workspaces:
+      - name: workspace
+        workspace: shared-data
+
+  - name: send-notification
+    taskRef:
+      name: notify
+    params:
+      - name: status
+        value: $(tasks.status)
+      - name: message
+        value: "Pipeline $(context.pipelineRun.name) $(tasks.status)"
+```
+
+### Idempotent Tasks
+
+```yaml
+# BAD: Not idempotent
+script: |
+  echo "data" >> file.txt  # Appends on retry
+
+# GOOD: Idempotent
+script: |
+  echo "data" > file.txt   # Overwrites on retry
+```
+
+## Maintainability Best Practices
+
+### Task Reusability
+
+**DO: Parameterize everything**
+```yaml
+params:
+  - name: image
+  - name: dockerfile
+    default: ./Dockerfile
+  - name: context
+    default: .
+```
+
+**DON'T: Hardcode values**
+```yaml
+# Anti-pattern
+args:
+  - --destination=myregistry.com/myimage:latest
+```
+
+### Use Tekton Hub
+
+**Check Hub before creating custom tasks:**
+```bash
+tkn hub search git
+tkn hub info task git-clone
+tkn hub install task git-clone
+```
+
+**Reference Hub tasks:**
+```yaml
+taskRef:
+  resolver: hub
+  params:
+    - name: name
+      value: git-clone
+    - name: version
+      value: "0.10.0"
+```
+
+### Migration from Deprecated Features
+
+**AVOID: ClusterTasks (deprecated)**
+```yaml
+# Old
+taskRef:
+  name: git-clone
+  kind: ClusterTask
+```
+
+**USE: Resolvers**
+```yaml
+# New - Cluster resolver
+taskRef:
+  resolver: cluster
+  params:
+    - name: name
+      value: git-clone
+    - name: namespace
+      value: tekton-tasks
+
+# New - Hub resolver (preferred)
+taskRef:
+  resolver: hub
+  params:
+    - name: name
+      value: git-clone
+```
+
+**AVOID: PipelineResources (deprecated)**
+- Use Tasks with Results and Workspaces instead
+
+### Documentation
+
+**Document tasks comprehensively:**
+```yaml
+metadata:
+  name: build-app
+  labels:
+    app.kubernetes.io/version: "1.0"
+  annotations:
+    tekton.dev/pipelines.minVersion: "0.50.0"
+    tekton.dev/categories: Build Tools
+    tekton.dev/tags: build, maven
+spec:
+  description: |
+    Builds Java application using Maven.
+
+    This task compiles source code, runs tests,
+    and packages the application as a JAR file.
+
+    ## Parameters
+    - maven-goals: Maven goals to execute (default: clean package)
+    - settings-path: Path to custom settings.xml
+
+    ## Workspaces
+    - source: Source code directory
+    - maven-cache: Maven local repository cache (optional)
+
+    ## Results
+    - artifact-name: Name of the generated JAR file
+```
+
+### Versioning
+
+```yaml
+metadata:
+  labels:
+    app.kubernetes.io/version: "2.1.0"
+    version: "2.1.0"
+```
+
+## Anti-Patterns to Avoid
+
+### 1. Not Setting Resource Limits
+
+**Impact:** Poor scheduling, resource contention, cluster instability
+
+**Solution:**
+```yaml
+resources:
+  requests:
+    cpu: 500m
+    memory: 1Gi
+  limits:
+    cpu: 1000m
+    memory: 2Gi
+```
+
+### 2. Using :latest Image Tag
+
+**Impact:** Non-deterministic builds, cache issues
+
+**Solution:**
+```yaml
+image: maven:3.8.6-openjdk-17  # Specific version
+```
+
+### 3. Monolithic Tasks
+
+**Impact:** Poor reusability, difficult debugging
+
+**Solution:** Break into focused, single-responsibility tasks
+
+### 4. Ignoring Pipeline Pruner
+
+**Impact:** etcd bloat, performance degradation
+
+**Solution:** Configure automatic pruning (see above)
+
+### 5. Sharing ReadWriteOnce PVC in Parallel
+
+**Impact:** Pod scheduling failures
+
+**Solution:**
+- Use ReadWriteMany
+- Use volumeClaimTemplate
+- Avoid parallel tasks with shared workspace
+
+### 6. Results Over 4KB
+
+**Impact:** Task failures
+
+**Solution:** Use workspaces for large data
+
+### 7. Not Using Tekton Hub
+
+**Impact:** Reinventing the wheel, maintenance burden
+
+**Solution:** Check Hub first, contribute improvements
+
+### 8. Overly Permissive RBAC
+
+**Impact:** Security risks
+
+**Solution:** Least privilege principle
+
+### 9. Secrets in Logs
+
+**Impact:** Credential exposure
+
+**Solution:** Never print sensitive data
+
+### 10. Not Testing Tasks Isolation
+
+**Impact:** Pipeline failures
+
+**Solution:** Test TaskRuns independently before using in pipelines
+
+## Operating at Scale (Red Hat Lessons)
+
+### 1. Configure Pipeline Pruner
+Delete completed pods to free volumes and improve performance
+
+### 2. Set Resource Requests/Limits
+Scheduler performs poorly without them
+
+### 3. Understand Workload Bottlenecks
+Profile and optimize based on actual constraints
+
+### 4. Avoid PVC Sharing Conflicts
+Use volumeClaimTemplate or manage access modes carefully
+
+### 5. Monitor etcd Performance
+Prune old resources, use Tekton Results for long-term storage
+
+### 6. Plan for Multi-AZ Clusters
+PVCs are tied to specific availability zones
+
+### 7. Use Tekton Resolvers
+Replace ClusterTasks with cluster/hub/git resolvers
+
+### 8. Implement Retry Strategies
+Set retries for flaky network operations
+
+### 9. Version Control Everything
+Pin task/pipeline versions for stability
+
+### 10. Test at Scale
+Load test pipelines before production deployment
+
+## Monitoring and Observability
+
+### Tekton Dashboard
+
+```bash
+# Install Tekton Dashboard
+kubectl apply -f https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml
+
+# Access dashboard
+kubectl port-forward -n tekton-pipelines svc/tekton-dashboard 9097:9097
+```
+
+### Prometheus Metrics
+
+**Tekton exports metrics:**
+- `tekton_pipelinerun_duration_seconds`
+- `tekton_pipelinerun_count`
+- `tekton_taskrun_duration_seconds`
+- `tekton_taskrun_count`
+
+### Logging Best Practices
+
+**Structured logging in tasks:**
+```yaml
+script: |
+  echo "[INFO] Starting build"
+  echo "[ERROR] Build failed: $ERROR_MSG"
+  echo "[SUCCESS] Build completed"
+```
+
+**Aggregate logs:**
+- Use Fluentd/Fluent Bit to collect logs
+- Send to Elasticsearch, Loki, or CloudWatch
+- Create dashboards in Grafana, Kibana
+
+### Alerting
+
+**Alert on:**
+- Pipeline failure rate exceeding threshold
+- Long-running pipelines
+- Resource quota exhaustion
+- PVC capacity
+- Failed webhook deliveries
+
+## Checklist
+
+### Security Checklist
+- [ ] Use workspace-based authentication
+- [ ] Create dedicated ServiceAccounts
+- [ ] Follow least privilege RBAC
+- [ ] Run containers as non-root
+- [ ] Scan images for vulnerabilities
+- [ ] Rotate credentials regularly
+- [ ] Don't commit secrets to Git
+- [ ] Use signed commits
+
+### Performance Checklist
+- [ ] Set resource requests/limits on all steps
+- [ ] Configure pipeline pruner
+- [ ] Use caching (Kaniko, Maven, npm)
+- [ ] Use volumeClaimTemplate for isolation
+- [ ] Monitor resource usage
+- [ ] Optimize Dockerfile layer caching
+- [ ] Use specific image tags
+
+### Reliability Checklist
+- [ ] Set retries for flaky operations
+- [ ] Use onError for optional tasks
+- [ ] Implement timeouts
+- [ ] Use finally tasks for cleanup
+- [ ] Write idempotent tasks
+- [ ] Test tasks in isolation
+- [ ] Monitor pipeline success rate
+
+### Maintainability Checklist
+- [ ] Check Tekton Hub before custom tasks
+- [ ] Parameterize all tasks
+- [ ] Document parameters and workspaces
+- [ ] Use resolvers (not ClusterTasks)
+- [ ] Version tasks and pipelines
+- [ ] Use consistent naming conventions
+- [ ] Organize tasks by function
dots/.config/claude/skills/Tekton/workflows/Build.md
@@ -0,0 +1,445 @@
+# Build Workflow
+
+Building container images with Tekton using Kaniko and Buildah.
+
+## When to Use
+
+- Building Docker/OCI container images
+- Pushing images to registries
+- Implementing caching strategies
+- Building without Docker daemon
+
+## Kaniko
+
+**Builds Docker images inside Kubernetes without Docker daemon**
+
+### Kaniko Task from Tekton Hub
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: TaskRun
+metadata:
+  name: kaniko-build
+spec:
+  taskRef:
+    resolver: hub
+    params:
+      - name: name
+        value: kaniko
+      - name: version
+        value: "0.6.0"
+  params:
+    - name: IMAGE
+      value: myregistry.com/myapp:latest
+    - name: DOCKERFILE
+      value: ./Dockerfile
+    - name: CONTEXT
+      value: .
+    - name: EXTRA_ARGS
+      value:
+        - --cache=true
+        - --cache-ttl=24h
+  workspaces:
+    - name: source
+      persistentVolumeClaim:
+        claimName: source-pvc
+    - name: dockerconfig
+      secret:
+        secretName: docker-config
+```
+
+### Custom Kaniko Task
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: kaniko-build-push
+spec:
+  params:
+    - name: IMAGE
+      description: Image name with tag
+    - name: DOCKERFILE
+      description: Path to Dockerfile
+      default: ./Dockerfile
+    - name: CONTEXT
+      description: Build context
+      default: .
+    - name: BUILD_ARGS
+      type: array
+      description: Build arguments
+      default: []
+  workspaces:
+    - name: source
+      description: Source code
+    - name: dockerconfig
+      description: Docker credentials
+  results:
+    - name: IMAGE_DIGEST
+      description: Image digest
+  steps:
+    - name: build-and-push
+      image: gcr.io/kaniko-project/executor:latest
+      args:
+        - --dockerfile=$(params.DOCKERFILE)
+        - --context=$(workspaces.source.path)/$(params.CONTEXT)
+        - --destination=$(params.IMAGE)
+        - --digest-file=$(results.IMAGE_DIGEST.path)
+        - $(params.BUILD_ARGS[*])
+      env:
+        - name: DOCKER_CONFIG
+          value: $(workspaces.dockerconfig.path)
+      resources:
+        requests:
+          cpu: 1000m
+          memory: 1Gi
+        limits:
+          cpu: 2000m
+          memory: 4Gi
+```
+
+### Kaniko with Caching
+
+```yaml
+args:
+  - --dockerfile=./Dockerfile
+  - --context=.
+  - --destination=myregistry.com/myapp:latest
+  - --cache=true
+  - --cache-repo=myregistry.com/cache
+  - --cache-ttl=24h
+  - --compressed-caching=false
+```
+
+### Multi-Stage Dockerfile with Kaniko
+
+```dockerfile
+# Dockerfile
+FROM maven:3.8-openjdk-17 AS build
+WORKDIR /app
+COPY pom.xml .
+RUN mvn dependency:go-offline
+COPY src ./src
+RUN mvn package -DskipTests
+
+FROM eclipse-temurin:17-jre-alpine
+COPY --from=build /app/target/*.jar /app/app.jar
+ENTRYPOINT ["java", "-jar", "/app/app.jar"]
+```
+
+## Buildah
+
+**Builds OCI images with or without Dockerfiles**
+
+### Buildah Task
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: buildah-build
+spec:
+  params:
+    - name: IMAGE
+      description: Image name with tag
+    - name: DOCKERFILE
+      description: Path to Dockerfile
+      default: ./Dockerfile
+    - name: CONTEXT
+      description: Build context
+      default: .
+    - name: FORMAT
+      description: Image format (oci or docker)
+      default: oci
+    - name: TLS_VERIFY
+      description: Verify TLS certificates
+      default: "true"
+  workspaces:
+    - name: source
+    - name: dockerconfig
+  results:
+    - name: IMAGE_DIGEST
+  steps:
+    - name: build
+      image: quay.io/buildah/stable:latest
+      workingDir: $(workspaces.source.path)
+      script: |
+        #!/bin/bash
+        buildah --storage-driver=vfs bud \
+          --format=$(params.FORMAT) \
+          --tls-verify=$(params.TLS_VERIFY) \
+          --no-cache \
+          -f $(params.DOCKERFILE) \
+          -t $(params.IMAGE) \
+          $(params.CONTEXT)
+
+        buildah --storage-driver=vfs push \
+          --tls-verify=$(params.TLS_VERIFY) \
+          --digestfile=$(results.IMAGE_DIGEST.path) \
+          $(params.IMAGE) \
+          docker://$(params.IMAGE)
+      env:
+        - name: REGISTRY_AUTH_FILE
+          value: $(workspaces.dockerconfig.path)/config.json
+      securityContext:
+        privileged: true
+      resources:
+        requests:
+          cpu: 1000m
+          memory: 1Gi
+        limits:
+          cpu: 2000m
+          memory: 4Gi
+```
+
+### Buildah without Dockerfile
+
+```yaml
+steps:
+  - name: build-from-scratch
+    image: quay.io/buildah/stable
+    script: |
+      #!/bin/bash
+      # Create container from base image
+      container=$(buildah from alpine:latest)
+
+      # Install packages
+      buildah run $container -- apk add --no-cache python3
+
+      # Copy application
+      buildah copy $container app.py /app/
+
+      # Configure
+      buildah config --entrypoint '["python3", "/app/app.py"]' $container
+      buildah config --port 8080 $container
+
+      # Commit and push
+      buildah commit $container $(params.IMAGE)
+      buildah push $(params.IMAGE)
+```
+
+## Container Registry Authentication
+
+### Docker Config Secret
+
+```bash
+# Create docker config secret
+kubectl create secret docker-registry docker-config \
+  --docker-server=myregistry.com \
+  --docker-username=myuser \
+  --docker-password=mypassword \
+  --docker-email=myemail@example.com
+```
+
+**Or from existing config:**
+```bash
+kubectl create secret generic docker-config \
+  --from-file=config.json=$HOME/.docker/config.json
+```
+
+### Using in Workspace
+
+```yaml
+workspaces:
+  - name: dockerconfig
+    secret:
+      secretName: docker-config
+```
+
+### Harbor Integration
+
+```bash
+# Create secret for Harbor
+kubectl create secret docker-registry harbor-config \
+  --docker-server=harbor.example.com \
+  --docker-username=admin \
+  --docker-password=Harbor12345
+```
+
+### AWS ECR Authentication
+
+```yaml
+# Create ECR credentials task
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: ecr-login
+spec:
+  results:
+    - name: docker-config
+  steps:
+    - name: get-credentials
+      image: amazon/aws-cli
+      script: |
+        aws ecr get-login-password --region us-east-1 > $(results.docker-config.path)
+```
+
+## Complete Build Pipeline
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Pipeline
+metadata:
+  name: build-push-pipeline
+spec:
+  params:
+    - name: git-url
+    - name: git-revision
+      default: main
+    - name: image-name
+    - name: dockerfile
+      default: ./Dockerfile
+  workspaces:
+    - name: source-code
+    - name: docker-credentials
+  tasks:
+    # Clone repository
+    - name: clone
+      taskRef:
+        resolver: hub
+        params:
+          - name: name
+            value: git-clone
+          - name: version
+            value: "0.10.0"
+      workspaces:
+        - name: output
+          workspace: source-code
+      params:
+        - name: url
+          value: $(params.git-url)
+        - name: revision
+          value: $(params.git-revision)
+
+    # Extract version from git
+    - name: get-version
+      runAfter:
+        - clone
+      taskRef:
+        name: git-version
+      workspaces:
+        - name: source
+          workspace: source-code
+
+    # Build and push with Kaniko
+    - name: build-push
+      runAfter:
+        - get-version
+      taskRef:
+        resolver: hub
+        params:
+          - name: name
+            value: kaniko
+      workspaces:
+        - name: source
+          workspace: source-code
+        - name: dockerconfig
+          workspace: docker-credentials
+      params:
+        - name: IMAGE
+          value: $(params.image-name):$(tasks.get-version.results.version)
+        - name: DOCKERFILE
+          value: $(params.dockerfile)
+        - name: EXTRA_ARGS
+          value:
+            - --cache=true
+            - --compressed-caching=false
+
+    # Scan image for vulnerabilities
+    - name: scan
+      runAfter:
+        - build-push
+      taskRef:
+        name: trivy-scanner
+      params:
+        - name: IMAGE
+          value: $(params.image-name):$(tasks.get-version.results.version)
+        - name: DIGEST
+          value: $(tasks.build-push.results.IMAGE_DIGEST)
+```
+
+## Best Practices
+
+### Image Tagging
+- Use semantic versioning: `v1.2.3`
+- Include git commit SHA: `abc123`
+- Tag with branch name for development: `main`, `develop`
+- Always tag `latest` for main branch
+- Use immutable tags in production
+
+### Build Optimization
+- Use multi-stage Dockerfiles
+- Leverage build cache (Kaniko `--cache`)
+- Order Dockerfile commands from least to most frequently changed
+- Use `.dockerignore` to exclude unnecessary files
+- Minimize layer count
+
+### Security
+- Scan images for vulnerabilities (Trivy, Grype)
+- Use minimal base images (alpine, distroless)
+- Run as non-root user
+- Don't include secrets in images
+- Sign images (Cosign)
+
+### Resource Management
+- Set appropriate CPU/memory limits
+- Use caching to reduce build time
+- Clean up intermediate images
+- Limit concurrent builds
+
+## Troubleshooting
+
+### Kaniko Build Fails
+
+```bash
+# Check workspace is populated
+kubectl exec <pod-name> -c step-build-and-push -- ls /workspace/source
+
+# Check Dockerfile path
+kubectl exec <pod-name> -c step-build-and-push -- cat /workspace/source/Dockerfile
+
+# Check registry credentials
+kubectl get secret docker-config -o yaml
+
+# View detailed logs
+tkn taskrun logs <taskrun-name> -f
+```
+
+### Authentication Errors
+
+```bash
+# Verify secret format
+kubectl get secret docker-config -o jsonpath='{.data.config\.json}' | base64 -d | jq
+
+# Test registry access
+kubectl run test-registry --rm -i --tty --image=alpine -- sh
+apk add --no-cache docker
+docker login myregistry.com
+```
+
+### Image Push Fails
+
+```bash
+# Check network connectivity
+kubectl exec <pod-name> -- ping myregistry.com
+
+# Verify registry URL
+kubectl exec <pod-name> -- nslookup myregistry.com
+
+# Check TLS verification
+# Add --insecure flag for testing (not production!)
+```
+
+### Out of Memory
+
+```bash
+# Increase memory limits
+resources:
+  limits:
+    memory: 8Gi
+
+# Use Kaniko compressed caching
+- --compressed-caching=true
+
+# Reduce concurrent builds
+```
dots/.config/claude/skills/Tekton/workflows/GitOps.md
@@ -0,0 +1,612 @@
+# GitOps Workflow
+
+Integrating Tekton with GitOps tools (ArgoCD, Flux CD) for complete CI/CD automation.
+
+## When to Use
+
+- Implementing GitOps workflows
+- Integrating Tekton with ArgoCD or Flux
+- Automating deployments via Git
+- Separating CI and CD concerns
+- Managing multi-environment deployments
+
+## GitOps Architecture
+
+### Tekton + ArgoCD Pattern
+
+```
+┌──────────┐    ┌────────────┐    ┌──────────────┐    ┌─────────────┐
+│  GitHub  │───▶│   Tekton   │───▶│  GitOps Repo │───▶│   ArgoCD    │
+│  (Code)  │    │    (CI)    │    │  (Manifests) │    │    (CD)     │
+└──────────┘    └────────────┘    └──────────────┘    └─────────────┘
+                     │                                        │
+                     │ Build & Push                           │ Sync
+                     ▼                                        ▼
+               ┌────────────┐                          ┌─────────────┐
+               │  Registry  │                          │  Kubernetes │
+               └────────────┘                          └─────────────┘
+```
+
+**Responsibilities:**
+- **Tekton (CI)**: Build, test, create container images
+- **ArgoCD (CD)**: Deploy manifests to Kubernetes
+
+**Benefits:**
+- Separation of concerns
+- Git as single source of truth
+- Declarative deployments
+- Automated rollback capabilities
+- Audit trail via Git history
+
+## Tekton CI Pipeline for GitOps
+
+### Complete CI Pipeline
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Pipeline
+metadata:
+  name: gitops-ci-pipeline
+spec:
+  params:
+    - name: git-url
+      description: Application source repository
+    - name: git-revision
+      description: Git commit/branch
+      default: main
+    - name: image-name
+      description: Container image name
+    - name: gitops-repo-url
+      description: GitOps repository URL
+    - name: gitops-branch
+      description: GitOps repository branch
+      default: main
+    - name: deployment-file
+      description: Path to deployment file
+      default: k8s/deployment.yaml
+
+  workspaces:
+    - name: source-code
+    - name: gitops-repo
+    - name: docker-credentials
+    - name: git-credentials
+
+  tasks:
+    # 1. Clone application source
+    - name: clone-source
+      taskRef:
+        resolver: hub
+        params:
+          - name: name
+            value: git-clone
+      workspaces:
+        - name: output
+          workspace: source-code
+        - name: ssh-directory
+          workspace: git-credentials
+      params:
+        - name: url
+          value: $(params.git-url)
+        - name: revision
+          value: $(params.git-revision)
+
+    # 2. Extract version from commit
+    - name: get-version
+      runAfter: [clone-source]
+      taskRef:
+        name: git-version
+      workspaces:
+        - name: source
+          workspace: source-code
+
+    # 3. Run tests
+    - name: test
+      runAfter: [clone-source]
+      taskRef:
+        name: run-tests
+      workspaces:
+        - name: source
+          workspace: source-code
+
+    # 4. Build and push image
+    - name: build-push
+      runAfter: [test, get-version]
+      taskRef:
+        resolver: hub
+        params:
+          - name: name
+            value: kaniko
+      workspaces:
+        - name: source
+          workspace: source-code
+        - name: dockerconfig
+          workspace: docker-credentials
+      params:
+        - name: IMAGE
+          value: $(params.image-name):$(tasks.get-version.results.version)
+        - name: EXTRA_ARGS
+          value:
+            - --cache=true
+
+    # 5. Clone GitOps repository
+    - name: clone-gitops
+      runAfter: [build-push]
+      taskRef:
+        resolver: hub
+        params:
+          - name: name
+            value: git-clone
+      workspaces:
+        - name: output
+          workspace: gitops-repo
+        - name: ssh-directory
+          workspace: git-credentials
+      params:
+        - name: url
+          value: $(params.gitops-repo-url)
+        - name: revision
+          value: $(params.gitops-branch)
+
+    # 6. Update image tag in GitOps repo
+    - name: update-manifest
+      runAfter: [clone-gitops]
+      taskRef:
+        name: yq-update
+      workspaces:
+        - name: source
+          workspace: gitops-repo
+      params:
+        - name: file
+          value: $(params.deployment-file)
+        - name: expression
+          value: .spec.template.spec.containers[0].image = "$(params.image-name):$(tasks.get-version.results.version)"
+
+    # 7. Commit and push changes
+    - name: commit-push
+      runAfter: [update-manifest]
+      taskRef:
+        name: git-cli
+      workspaces:
+        - name: source
+          workspace: gitops-repo
+        - name: ssh-directory
+          workspace: git-credentials
+      params:
+        - name: GIT_USER_NAME
+          value: "Tekton Pipeline"
+        - name: GIT_USER_EMAIL
+          value: "tekton@example.com"
+        - name: GIT_SCRIPT
+          value: |
+            git add $(params.deployment-file)
+            git commit -m "Update image to $(params.image-name):$(tasks.get-version.results.version)"
+            git push origin $(params.gitops-branch)
+```
+
+### Update Manifest Task
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: yq-update
+spec:
+  params:
+    - name: file
+      description: YAML file to update
+    - name: expression
+      description: yq expression
+  workspaces:
+    - name: source
+  steps:
+    - name: update
+      image: mikefarah/yq:latest
+      workingDir: $(workspaces.source.path)
+      script: |
+        #!/bin/sh
+        yq eval -i '$(params.expression)' $(params.file)
+```
+
+### Git Commit Task
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: git-commit-push
+spec:
+  params:
+    - name: commit-message
+    - name: file-path
+  workspaces:
+    - name: source
+    - name: ssh-directory
+  steps:
+    - name: commit-push
+      image: alpine/git:latest
+      workingDir: $(workspaces.source.path)
+      env:
+        - name: GIT_SSH_COMMAND
+          value: ssh -i $(workspaces.ssh-directory.path)/id_rsa -o StrictHostKeyChecking=no
+      script: |
+        #!/bin/sh
+        set -e
+
+        git config user.name "Tekton Pipeline"
+        git config user.email "tekton@example.com"
+
+        git add $(params.file-path)
+        git commit -m "$(params.commit-message)"
+        git push origin HEAD
+```
+
+## ArgoCD Integration
+
+### ArgoCD Application
+
+```yaml
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+  name: myapp
+  namespace: argocd
+spec:
+  project: default
+  source:
+    repoURL: https://github.com/org/gitops-repo
+    targetRevision: main
+    path: k8s
+  destination:
+    server: https://kubernetes.default.svc
+    namespace: production
+  syncPolicy:
+    automated:
+      prune: true
+      selfHeal: true
+    syncOptions:
+      - CreateNamespace=true
+```
+
+### Trigger ArgoCD Sync from Tekton
+
+```yaml
+# Task to trigger ArgoCD sync
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: argocd-sync
+spec:
+  params:
+    - name: app-name
+      description: ArgoCD application name
+    - name: argocd-server
+      description: ArgoCD server URL
+      default: argocd-server.argocd.svc:443
+  steps:
+    - name: sync
+      image: argoproj/argocd:latest
+      script: |
+        #!/bin/sh
+        argocd app sync $(params.app-name) \
+          --server $(params.argocd-server) \
+          --auth-token $ARGOCD_TOKEN
+      env:
+        - name: ARGOCD_TOKEN
+          valueFrom:
+            secretKeyRef:
+              name: argocd-token
+              key: token
+```
+
+## Flux CD Integration
+
+### Flux ImageUpdateAutomation
+
+**Flux automatically updates images:**
+
+```yaml
+apiVersion: image.toolkit.fluxcd.io/v1beta1
+kind: ImageRepository
+metadata:
+  name: myapp
+  namespace: flux-system
+spec:
+  image: myregistry.com/myapp
+  interval: 1m
+---
+apiVersion: image.toolkit.fluxcd.io/v1beta1
+kind: ImagePolicy
+metadata:
+  name: myapp
+  namespace: flux-system
+spec:
+  imageRepositoryRef:
+    name: myapp
+  policy:
+    semver:
+      range: 1.x.x
+---
+apiVersion: image.toolkit.fluxcd.io/v1beta1
+kind: ImageUpdateAutomation
+metadata:
+  name: myapp
+  namespace: flux-system
+spec:
+  interval: 1m
+  sourceRef:
+    kind: GitRepository
+    name: gitops-repo
+  git:
+    checkout:
+      ref:
+        branch: main
+    commit:
+      author:
+        email: flux@example.com
+        name: Flux
+      messageTemplate: "Update image to {{range .Updated.Images}}{{println .}}{{end}}"
+    push:
+      branch: main
+  update:
+    path: ./k8s
+    strategy: Setters
+```
+
+### Tekton with Flux
+
+**Simpler Tekton pipeline:**
+```yaml
+# Tekton only builds and pushes
+# Flux automatically detects new image and updates manifests
+spec:
+  tasks:
+    - name: clone
+    - name: test
+    - name: build-push
+  # No manifest update needed - Flux handles it
+```
+
+## Multi-Environment GitOps
+
+### Directory Structure
+
+```
+gitops-repo/
+├── base/
+│   ├── deployment.yaml
+│   ├── service.yaml
+│   └── kustomization.yaml
+├── overlays/
+│   ├── dev/
+│   │   ├── kustomization.yaml
+│   │   └── patches/
+│   ├── staging/
+│   │   ├── kustomization.yaml
+│   │   └── patches/
+│   └── production/
+│       ├── kustomization.yaml
+│       └── patches/
+```
+
+### Kustomize Update Task
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: kustomize-set-image
+spec:
+  params:
+    - name: image
+    - name: overlay
+      default: dev
+  workspaces:
+    - name: source
+  steps:
+    - name: set-image
+      image: k8s.gcr.io/kustomize/kustomize:v5.0.0
+      workingDir: $(workspaces.source.path)/overlays/$(params.overlay)
+      script: |
+        kustomize edit set image app=$(params.image)
+```
+
+### Environment-Specific Pipelines
+
+```yaml
+# Dev pipeline - auto-deploy
+- name: update-dev
+  when:
+    - input: $(params.git-branch)
+      operator: in
+      values: [develop]
+  taskRef:
+    name: update-gitops
+  params:
+    - name: overlay
+      value: dev
+
+# Staging pipeline - auto-deploy
+- name: update-staging
+  when:
+    - input: $(params.git-branch)
+      operator: in
+      values: [main]
+  taskRef:
+    name: update-gitops
+  params:
+    - name: overlay
+      value: staging
+
+# Production - manual approval required
+- name: update-production
+  when:
+    - input: $(params.deploy-to-prod)
+      operator: in
+      values: ["true"]
+  taskRef:
+    name: update-gitops
+  params:
+    - name: overlay
+      value: production
+```
+
+## Git Credentials Management
+
+### SSH Key Secret
+
+```bash
+# Generate SSH key
+ssh-keygen -t ed25519 -C "tekton@example.com" -f tekton_key -N ""
+
+# Create secret
+kubectl create secret generic git-ssh-credentials \
+  --from-file=id_rsa=tekton_key \
+  --from-file=id_rsa.pub=tekton_key.pub \
+  --from-file=known_hosts=~/.ssh/known_hosts
+
+# Add public key to GitHub/GitLab as deploy key with write access
+```
+
+### Using SSH Credentials
+
+```yaml
+workspaces:
+  - name: ssh-directory
+    secret:
+      secretName: git-ssh-credentials
+      items:
+        - key: id_rsa
+          path: id_rsa
+          mode: 0600
+        - key: known_hosts
+          path: known_hosts
+```
+
+## Best Practices
+
+### Repository Structure
+- Separate application and GitOps repositories
+- Use Kustomize or Helm for multi-environment management
+- Version GitOps manifests
+- Protect main branch with pull requests
+
+### CI Pipeline
+- Build and test in Tekton
+- Push images with semantic versioning
+- Update GitOps repo via automation
+- Sign commits for traceability
+
+### CD with ArgoCD/Flux
+- Enable auto-sync for development
+- Require manual approval for production
+- Configure sync windows for production
+- Set up health checks and rollback
+
+### Security
+- Use SSH keys with write-only access to GitOps repo
+- Rotate credentials regularly
+- Scan container images before pushing
+- Use signed commits
+
+### Monitoring
+- Monitor ArgoCD sync status
+- Alert on sync failures
+- Track deployment frequency
+- Measure lead time for changes
+
+## Complete GitOps Example
+
+```yaml
+# PipelineRun with all parameters
+apiVersion: tekton.dev/v1
+kind: PipelineRun
+metadata:
+  generateName: gitops-ci-run-
+spec:
+  pipelineRef:
+    name: gitops-ci-pipeline
+  params:
+    - name: git-url
+      value: https://github.com/org/myapp
+    - name: git-revision
+      value: main
+    - name: image-name
+      value: myregistry.com/myapp
+    - name: gitops-repo-url
+      value: git@github.com:org/gitops-repo.git
+    - name: gitops-branch
+      value: main
+    - name: deployment-file
+      value: overlays/production/kustomization.yaml
+  workspaces:
+    - name: source-code
+      volumeClaimTemplate:
+        spec:
+          accessModes:
+            - ReadWriteOnce
+          resources:
+            requests:
+              storage: 1Gi
+    - name: gitops-repo
+      volumeClaimTemplate:
+        spec:
+          accessModes:
+            - ReadWriteOnce
+          resources:
+            requests:
+              storage: 500Mi
+    - name: docker-credentials
+      secret:
+        secretName: docker-config
+    - name: git-credentials
+      secret:
+        secretName: git-ssh-credentials
+  serviceAccountName: gitops-pipeline-sa
+```
+
+## Troubleshooting
+
+### Manifest Update Fails
+
+```bash
+# Check workspace contents
+kubectl exec <pod-name> -- ls /workspace/gitops-repo
+
+# Verify yq/kustomize syntax
+kubectl logs <pod-name> -c step-update
+```
+
+### Git Push Fails
+
+```bash
+# Check SSH credentials
+kubectl get secret git-ssh-credentials -o yaml
+
+# Test SSH connection
+kubectl run test-git --rm -i --tty --image=alpine/git -- sh
+apk add openssh-client
+ssh -T git@github.com
+```
+
+### ArgoCD Not Syncing
+
+```bash
+# Check ArgoCD application
+kubectl get application myapp -n argocd
+
+# View sync status
+argocd app get myapp
+
+# Manual sync
+argocd app sync myapp
+```
+
+### Wrong Image Tag
+
+```bash
+# Check task results
+kubectl get pipelinerun <name> -o jsonpath='{.status.taskRuns}'
+
+# Verify manifest update
+kubectl logs <pod-name> -c step-update
+```
dots/.config/claude/skills/Tekton/workflows/Pipelines.md
@@ -0,0 +1,621 @@
+# Pipelines Workflow
+
+Creating and managing Tekton Pipelines to orchestrate multiple Tasks into complete CI/CD workflows.
+
+## When to Use
+
+- Orchestrating multiple tasks
+- Defining task dependencies and execution order
+- Creating complete CI/CD workflows
+- Managing data flow between tasks
+- Building complex pipelines
+
+## Pipeline Structure
+
+### Basic Pipeline
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Pipeline
+metadata:
+  name: build-and-deploy
+spec:
+  params:
+    - name: git-url
+      type: string
+    - name: image-name
+      type: string
+  workspaces:
+    - name: shared-data
+  tasks:
+    - name: fetch-source
+      taskRef:
+        name: git-clone
+      workspaces:
+        - name: output
+          workspace: shared-data
+      params:
+        - name: url
+          value: $(params.git-url)
+
+    - name: build-image
+      taskRef:
+        name: kaniko
+      runAfter:
+        - fetch-source
+      workspaces:
+        - name: source
+          workspace: shared-data
+      params:
+        - name: IMAGE
+          value: $(params.image-name)
+```
+
+## Task Execution Control
+
+### Sequential Execution
+
+```yaml
+tasks:
+  - name: test
+    taskRef:
+      name: run-tests
+
+  - name: build
+    taskRef:
+      name: build-image
+    runAfter:
+      - test  # Waits for test to complete
+```
+
+### Parallel Execution
+
+```yaml
+tasks:
+  - name: lint
+    taskRef:
+      name: lint-code
+    # No runAfter - starts immediately
+
+  - name: test
+    taskRef:
+      name: run-tests
+    # No runAfter - starts in parallel with lint
+
+  - name: security-scan
+    taskRef:
+      name: trivy-scan
+    # No runAfter - starts in parallel
+
+  - name: build
+    taskRef:
+      name: build-image
+    runAfter:
+      - lint
+      - test
+      - security-scan  # Waits for all three
+```
+
+### Conditional Execution
+
+```yaml
+tasks:
+  - name: deploy-staging
+    when:
+      - input: "$(params.environment)"
+        operator: in
+        values: ["staging", "production"]
+    taskRef:
+      name: deploy
+
+  - name: deploy-prod
+    when:
+      - input: "$(params.environment)"
+        operator: in
+        values: ["production"]
+      - input: "$(tasks.test.results.status)"
+        operator: in
+        values: ["passed"]
+    runAfter:
+      - deploy-staging
+    taskRef:
+      name: deploy-production
+```
+
+**When Expression Operators:**
+- `in`: Value is in list
+- `notin`: Value is not in list
+
+## Passing Data Between Tasks
+
+### Using Results
+
+```yaml
+tasks:
+  - name: get-version
+    taskRef:
+      name: calculate-version
+    # Task emits result: version
+
+  - name: build-image
+    taskRef:
+      name: kaniko
+    runAfter:
+      - get-version
+    params:
+      - name: IMAGE
+        value: $(params.image-name):$(tasks.get-version.results.version)
+```
+
+### Using Workspaces
+
+```yaml
+workspaces:
+  - name: source-code
+
+tasks:
+  - name: clone
+    taskRef:
+      name: git-clone
+    workspaces:
+      - name: output
+        workspace: source-code
+
+  - name: test
+    taskRef:
+      name: run-tests
+    runAfter:
+      - clone
+    workspaces:
+      - name: source
+        workspace: source-code  # Shares data with clone task
+```
+
+## Finally Tasks
+
+**Finally tasks run after all pipeline tasks complete, regardless of success or failure.**
+
+```yaml
+finally:
+  - name: cleanup-workspace
+    taskRef:
+      name: cleanup
+    workspaces:
+      - name: workspace
+        workspace: shared-data
+
+  - name: send-notification
+    taskRef:
+      name: send-slack-message
+    params:
+      - name: status
+        value: $(tasks.status)  # SUCCESS or FAILURE
+      - name: message
+        value: "Pipeline $(context.pipelineRun.name) completed"
+```
+
+## Complete Pipeline Example
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Pipeline
+metadata:
+  name: nodejs-ci-cd
+spec:
+  params:
+    - name: git-url
+      description: Git repository URL
+    - name: git-revision
+      description: Git revision
+      default: main
+    - name: image-name
+      description: Container image name
+    - name: deploy-namespace
+      description: Kubernetes namespace
+      default: default
+
+  workspaces:
+    - name: source-code
+    - name: docker-credentials
+
+  tasks:
+    # Fetch source code
+    - name: clone
+      taskRef:
+        resolver: hub
+        params:
+          - name: name
+            value: git-clone
+          - name: version
+            value: "0.10.0"
+      workspaces:
+        - name: output
+          workspace: source-code
+      params:
+        - name: url
+          value: $(params.git-url)
+        - name: revision
+          value: $(params.git-revision)
+
+    # Parallel: Lint and test
+    - name: lint
+      taskRef:
+        name: npm-lint
+      runAfter:
+        - clone
+      workspaces:
+        - name: source
+          workspace: source-code
+
+    - name: test
+      taskRef:
+        name: npm-test
+      runAfter:
+        - clone
+      workspaces:
+        - name: source
+          workspace: source-code
+
+    # Security scan
+    - name: security-scan
+      taskRef:
+        name: trivy-scan
+      runAfter:
+        - clone
+      workspaces:
+        - name: source
+          workspace: source-code
+
+    # Build and push image
+    - name: build-push
+      taskRef:
+        resolver: hub
+        params:
+          - name: name
+            value: kaniko
+          - name: version
+            value: "0.6.0"
+      runAfter:
+        - lint
+        - test
+        - security-scan
+      workspaces:
+        - name: source
+          workspace: source-code
+        - name: dockerconfig
+          workspace: docker-credentials
+      params:
+        - name: IMAGE
+          value: $(params.image-name):$(tasks.clone.results.commit)
+
+    # Deploy to Kubernetes
+    - name: deploy
+      taskRef:
+        name: kubernetes-deploy
+      runAfter:
+        - build-push
+      params:
+        - name: image
+          value: $(params.image-name):$(tasks.clone.results.commit)
+        - name: namespace
+          value: $(params.deploy-namespace)
+
+  finally:
+    - name: cleanup
+      taskRef:
+        name: cleanup-workspace
+      workspaces:
+        - name: workspace
+          workspace: source-code
+
+    - name: notify
+      taskRef:
+        name: send-notification
+      params:
+        - name: pipeline-status
+          value: $(tasks.status)
+```
+
+## PipelineRun
+
+### Creating PipelineRun
+
+**Using tkn CLI:**
+```bash
+tkn pipeline start nodejs-ci-cd \
+  -p git-url=https://github.com/myorg/myapp \
+  -p git-revision=main \
+  -p image-name=myregistry.com/myapp \
+  -p deploy-namespace=production \
+  -w name=source-code,volumeClaimTemplateFile=pvc-template.yaml \
+  -w name=docker-credentials,secret=docker-config \
+  --serviceaccount=pipeline-sa \
+  --showlog
+```
+
+**Declarative YAML:**
+```yaml
+apiVersion: tekton.dev/v1
+kind: PipelineRun
+metadata:
+  generateName: nodejs-ci-cd-run-
+spec:
+  pipelineRef:
+    name: nodejs-ci-cd
+  params:
+    - name: git-url
+      value: https://github.com/myorg/myapp
+    - name: git-revision
+      value: main
+    - name: image-name
+      value: myregistry.com/myapp
+    - name: deploy-namespace
+      value: production
+  workspaces:
+    - name: source-code
+      volumeClaimTemplate:
+        spec:
+          accessModes:
+            - ReadWriteOnce
+          resources:
+            requests:
+              storage: 1Gi
+    - name: docker-credentials
+      secret:
+        secretName: docker-config
+  serviceAccountName: pipeline-sa
+  timeout: 1h
+```
+
+## Advanced Patterns
+
+### Matrix Execution (Beta)
+
+**Run task with multiple parameter combinations:**
+```yaml
+tasks:
+  - name: test-platforms
+    taskRef:
+      name: run-tests
+    matrix:
+      params:
+        - name: platform
+          value:
+            - linux/amd64
+            - linux/arm64
+        - name: version
+          value:
+            - "18"
+            - "20"
+    # Creates 4 TaskRuns: all combinations of platform x version
+```
+
+### Custom Task References
+
+```yaml
+tasks:
+  - name: custom-action
+    taskRef:
+      apiVersion: custom.dev/v1
+      kind: CustomTask
+      name: my-custom-task
+```
+
+### Retries
+
+```yaml
+tasks:
+  - name: flaky-test
+    retries: 3
+    taskRef:
+      name: integration-tests
+```
+
+### Timeouts
+
+```yaml
+# Pipeline-level timeout
+spec:
+  timeouts:
+    pipeline: 2h
+    tasks: 1h
+    finally: 30m
+
+# Task-level timeout
+tasks:
+  - name: long-running
+    timeout: 45m
+    taskRef:
+      name: build-task
+```
+
+### OnError Behavior
+
+```yaml
+tasks:
+  - name: optional-scan
+    onError: continue  # Continue even if this task fails
+    taskRef:
+      name: security-scan
+```
+
+## Common Pipeline Patterns
+
+### Build-Test-Deploy
+
+```yaml
+spec:
+  tasks:
+    - name: fetch-repo
+    - name: run-tests
+      runAfter: [fetch-repo]
+    - name: build-image
+      runAfter: [run-tests]
+    - name: deploy
+      runAfter: [build-image]
+```
+
+### Fan-Out, Fan-In
+
+```yaml
+spec:
+  tasks:
+    - name: clone
+
+    # Fan out (parallel)
+    - name: unit-test
+      runAfter: [clone]
+    - name: integration-test
+      runAfter: [clone]
+    - name: e2e-test
+      runAfter: [clone]
+
+    # Fan in (wait for all)
+    - name: build
+      runAfter: [unit-test, integration-test, e2e-test]
+```
+
+### Multi-Environment Deploy
+
+```yaml
+spec:
+  params:
+    - name: environment
+  tasks:
+    - name: build
+
+    - name: deploy-dev
+      when:
+        - input: $(params.environment)
+          operator: in
+          values: [dev, staging, production]
+      runAfter: [build]
+
+    - name: deploy-staging
+      when:
+        - input: $(params.environment)
+          operator: in
+          values: [staging, production]
+      runAfter: [deploy-dev]
+
+    - name: deploy-production
+      when:
+        - input: $(params.environment)
+          operator: in
+          values: [production]
+      runAfter: [deploy-staging]
+```
+
+## Monitoring and Debugging
+
+### View Pipeline Status
+
+```bash
+# List pipelineruns
+tkn pipelinerun list
+
+# Describe pipelinerun
+tkn pipelinerun describe my-run
+
+# View logs
+tkn pipelinerun logs my-run -f
+
+# Check task status
+kubectl get pipelinerun my-run -o jsonpath='{.status.taskRuns}'
+```
+
+### Pipeline Metrics
+
+```bash
+# Get pipeline duration
+kubectl get pipelinerun my-run -o jsonpath='{.status.startTime}'
+kubectl get pipelinerun my-run -o jsonpath='{.status.completionTime}'
+
+# Get task durations
+kubectl get pipelinerun my-run -o json | \
+  jq '.status.taskRuns[] | {name: .pipelineTaskName, duration: (.status.completionTime - .status.startTime)}'
+```
+
+## Best Practices
+
+### Pipeline Design
+- Keep pipelines focused on single workflow (CI or CD, not both)
+- Use descriptive task names
+- Group related tasks with proper dependencies
+- Use finally tasks for cleanup and notifications
+- Set appropriate timeouts
+
+### Data Flow
+- Use Results for small data (<4KB): commits, versions, flags
+- Use Workspaces for larger data: source code, build artifacts
+- Use PVC with volumeClaimTemplate for isolation
+- Be aware of PVC access mode limitations for parallel tasks
+
+### Error Handling
+- Set retries for flaky network operations
+- Use onError: continue for optional tasks
+- Use finally tasks for cleanup
+- Implement proper logging in tasks
+
+### Performance
+- Run independent tasks in parallel
+- Use caching workspaces (Maven, npm, Go modules)
+- Set resource limits to prevent resource contention
+- Use pipeline pruner to clean old runs
+
+### Security
+- Use dedicated ServiceAccounts
+- Follow least privilege for RBAC
+- Use Secrets for credentials
+- Never hardcode sensitive data in pipelines
+
+## Troubleshooting
+
+### Pipeline Won't Start
+
+```bash
+# Check pipeline exists
+kubectl get pipeline my-pipeline
+
+# Check pipelinerun
+kubectl describe pipelinerun my-run
+
+# Check service account
+kubectl get serviceaccount pipeline-sa
+
+# Check RBAC
+kubectl auth can-i create pipelineruns
+```
+
+### Task Dependencies Not Working
+
+```bash
+# Check runAfter is correct
+kubectl get pipeline my-pipeline -o yaml | grep -A 5 runAfter
+
+# Check when expressions
+kubectl get pipelinerun my-run -o jsonpath='{.status.skippedTasks}'
+```
+
+### Workspace Issues
+
+```bash
+# Check workspace bindings
+kubectl get pipelinerun my-run -o jsonpath='{.spec.workspaces}'
+
+# Check PVC exists
+kubectl get pvc
+
+# Check PVC is bound
+kubectl get pvc my-pvc -o jsonpath='{.status.phase}'
+```
+
+### Finally Tasks Not Running
+
+```bash
+# Check pipeline status
+kubectl get pipelinerun my-run -o jsonpath='{.status.conditions}'
+
+# View finally task status
+kubectl get pipelinerun my-run -o jsonpath='{.status.finallyStatus}'
+```
dots/.config/claude/skills/Tekton/workflows/Tasks.md
@@ -0,0 +1,778 @@
+# Tasks Workflow
+
+Creating and managing Tekton Tasks - the fundamental building blocks of Tekton Pipelines.
+
+## When to Use
+
+- Creating new Tasks
+- Defining Steps and workspaces
+- Parameterizing tasks for reusability
+- Emitting Results
+- Understanding TaskRuns
+
+## Task Anatomy
+
+### Basic Task Structure
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: my-task
+  namespace: default
+spec:
+  description: |
+    A brief description of what this task does
+  params:
+    - name: param-name
+      type: string
+      description: Description of the parameter
+      default: "default-value"
+  workspaces:
+    - name: workspace-name
+      description: Workspace for source code
+      mountPath: /workspace/source
+  results:
+    - name: result-name
+      description: Description of the result
+  steps:
+    - name: step-name
+      image: alpine:latest
+      script: |
+        #!/bin/sh
+        echo "Hello from step"
+```
+
+### Complete Task Example
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: build-app
+  labels:
+    app.kubernetes.io/version: "1.0"
+spec:
+  description: Build application using Maven
+  params:
+    - name: maven-image
+      type: string
+      description: Maven image to use
+      default: maven:3.8-openjdk-17
+    - name: goals
+      type: array
+      description: Maven goals to execute
+      default:
+        - clean
+        - package
+    - name: settings-path
+      type: string
+      description: Path to Maven settings.xml
+      default: ""
+  workspaces:
+    - name: source
+      description: Source code workspace
+    - name: maven-cache
+      description: Maven local repository cache
+      optional: true
+  results:
+    - name: artifact-name
+      description: Name of the built artifact
+    - name: build-timestamp
+      description: When the build completed
+  steps:
+    - name: build
+      image: $(params.maven-image)
+      workingDir: $(workspaces.source.path)
+      script: |
+        #!/bin/bash
+        set -e
+
+        # Use cache if available
+        if [ "$(workspaces.maven-cache.bound)" == "true" ]; then
+          export MAVEN_OPTS="-Dmaven.repo.local=$(workspaces.maven-cache.path)"
+        fi
+
+        # Add settings if provided
+        SETTINGS_ARG=""
+        if [ -n "$(params.settings-path)" ]; then
+          SETTINGS_ARG="-s $(params.settings-path)"
+        fi
+
+        # Run Maven build
+        mvn $SETTINGS_ARG $(params.goals[*])
+
+        # Output results
+        ARTIFACT=$(ls target/*.jar | head -n 1 | xargs basename)
+        echo -n "$ARTIFACT" > $(results.artifact-name.path)
+        echo -n "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > $(results.build-timestamp.path)
+      resources:
+        requests:
+          cpu: 500m
+          memory: 1Gi
+        limits:
+          cpu: 2000m
+          memory: 4Gi
+```
+
+## Parameters
+
+### Parameter Types
+
+**String parameter:**
+```yaml
+params:
+  - name: git-url
+    type: string
+    description: Git repository URL
+    default: ""
+```
+
+**Array parameter:**
+```yaml
+params:
+  - name: build-args
+    type: array
+    description: Build arguments
+    default: []
+```
+
+**Object parameter (Beta):**
+```yaml
+params:
+  - name: gitconfig
+    type: object
+    description: Git configuration
+    properties:
+      username:
+        type: string
+      email:
+        type: string
+    default:
+      username: ""
+      email: ""
+```
+
+### Using Parameters in Steps
+
+```yaml
+steps:
+  - name: use-params
+    image: alpine
+    script: |
+      echo "String param: $(params.git-url)"
+      echo "Array param: $(params.build-args[*])"
+      echo "Array first element: $(params.build-args[0])"
+      echo "Object param: $(params.gitconfig.username)"
+```
+
+### Parameter Validation
+
+```yaml
+params:
+  - name: environment
+    type: string
+    description: Deployment environment
+    default: "dev"
+    # Validation happens at runtime via when expressions or script logic
+```
+
+## Workspaces
+
+### Declaring Workspaces
+
+```yaml
+workspaces:
+  - name: source
+    description: Source code directory
+    mountPath: /workspace/source  # Optional custom mount path
+  - name: cache
+    description: Build cache
+    optional: true  # Task can run without this workspace
+  - name: config
+    description: Configuration files
+    readOnly: true  # Workspace is read-only
+```
+
+### Workspace Variables
+
+```yaml
+script: |
+  # Path to workspace
+  echo "Workspace path: $(workspaces.source.path)"
+
+  # PVC name (if using PVC)
+  echo "PVC name: $(workspaces.source.claim)"
+
+  # Check if workspace is bound
+  if [ "$(workspaces.source.bound)" == "true" ]; then
+    echo "Workspace is available"
+  fi
+```
+
+### Workspace Use Cases
+
+**PVC workspace (shared data):**
+```yaml
+# In TaskRun
+workspaces:
+  - name: source
+    persistentVolumeClaim:
+      claimName: shared-workspace
+```
+
+**emptyDir workspace (temporary):**
+```yaml
+# In TaskRun
+workspaces:
+  - name: temp
+    emptyDir: {}
+```
+
+**ConfigMap workspace (configuration):**
+```yaml
+# In TaskRun
+workspaces:
+  - name: config
+    configMap:
+      name: app-config
+```
+
+**Secret workspace (credentials):**
+```yaml
+# In TaskRun
+workspaces:
+  - name: credentials
+    secret:
+      secretName: git-credentials
+```
+
+## Steps
+
+### Step Structure
+
+```yaml
+steps:
+  - name: step-name
+    image: container-image
+    command:
+      - /bin/sh
+    args:
+      - -c
+      - echo "Hello"
+    env:
+      - name: ENV_VAR
+        value: "value"
+    workingDir: /workspace
+    script: |
+      #!/bin/sh
+      echo "Multi-line script"
+    resources:
+      requests:
+        cpu: 100m
+        memory: 128Mi
+      limits:
+        cpu: 500m
+        memory: 512Mi
+    securityContext:
+      runAsNonRoot: true
+      runAsUser: 1000
+```
+
+### Multiple Steps (Sequential)
+
+```yaml
+steps:
+  - name: fetch-dependencies
+    image: node:18
+    script: |
+      npm install
+
+  - name: run-tests
+    image: node:18
+    script: |
+      npm test
+
+  - name: build
+    image: node:18
+    script: |
+      npm run build
+```
+
+### Step Script vs Command
+
+**Using script (recommended):**
+```yaml
+steps:
+  - name: build
+    image: maven:3.8
+    script: |
+      #!/bin/bash
+      set -e
+      mvn clean package
+```
+
+**Using command/args:**
+```yaml
+steps:
+  - name: build
+    image: maven:3.8
+    command:
+      - mvn
+    args:
+      - clean
+      - package
+```
+
+### Environment Variables
+
+```yaml
+steps:
+  - name: build
+    image: alpine
+    env:
+      # From parameter
+      - name: GIT_URL
+        value: $(params.git-url)
+
+      # From secret
+      - name: API_KEY
+        valueFrom:
+          secretKeyRef:
+            name: api-credentials
+            key: api_key
+
+      # From configMap
+      - name: CONFIG_PATH
+        valueFrom:
+          configMapKeyRef:
+            name: app-config
+            key: config_path
+
+      # Built-in Tekton variables
+      - name: TASK_NAME
+        value: $(context.task.name)
+      - name: TASKRUN_NAME
+        value: $(context.taskRun.name)
+      - name: TASKRUN_NAMESPACE
+        value: $(context.taskRun.namespace)
+```
+
+## Results
+
+### Emitting Results
+
+**IMPORTANT:** Results are limited to 4KB. Use workspaces for larger data.
+
+```yaml
+results:
+  - name: commit-sha
+    description: Git commit SHA
+  - name: image-digest
+    description: Container image digest
+  - name: test-status
+    description: Test pass/fail status
+
+steps:
+  - name: get-commit
+    image: alpine/git
+    script: |
+      git rev-parse HEAD > $(results.commit-sha.path)
+
+  - name: build-image
+    image: gcr.io/kaniko-project/executor
+    script: |
+      # Kaniko outputs digest to /kaniko/digest
+      cp /kaniko/digest $(results.image-digest.path)
+
+  - name: run-tests
+    image: node:18
+    script: |
+      if npm test; then
+        echo -n "passed" > $(results.test-status.path)
+      else
+        echo -n "failed" > $(results.test-status.path)
+      fi
+```
+
+### Result Size Considerations
+
+**Good (small data):**
+- Commit SHAs
+- Image digests
+- Version numbers
+- Status flags
+- Ephemeral namespace names
+
+**Bad (use workspaces instead):**
+- Full build logs
+- Large JSON payloads
+- File contents
+- Binary data
+
+## Resource Management
+
+### Step Resources
+
+```yaml
+steps:
+  - name: build
+    image: maven:3.8
+    resources:
+      requests:
+        cpu: 500m
+        memory: 1Gi
+      limits:
+        cpu: 2000m
+        memory: 4Gi
+```
+
+### Task-Level Resources (Alpha)
+
+```yaml
+# In TaskRun, not Task definition
+apiVersion: tekton.dev/v1beta1
+kind: TaskRun
+spec:
+  taskRef:
+    name: build-task
+  computeResources:
+    requests:
+      cpu: "1"
+      memory: "2Gi"
+    limits:
+      cpu: "2"
+      memory: "4Gi"
+```
+
+**Best Practices:**
+- Always set resource requests for scheduler
+- Set limits 1.5-2x higher than requests
+- Monitor actual usage with `kubectl top pods`
+- Use task-level resources for simplicity when all steps have similar requirements
+
+## Security Context
+
+### Task Security
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: secure-task
+spec:
+  steps:
+    - name: build
+      image: alpine
+      securityContext:
+        runAsNonRoot: true
+        runAsUser: 1000
+        runAsGroup: 1000
+        allowPrivilegeEscalation: false
+        readOnlyRootFilesystem: true
+        capabilities:
+          drop:
+            - ALL
+      volumeMounts:
+        - name: tmp
+          mountPath: /tmp
+  volumes:
+    - name: tmp
+      emptyDir: {}
+```
+
+## TaskRun
+
+### Creating TaskRun
+
+**Imperative (tkn):**
+```bash
+tkn task start my-task \
+  -p param1=value1 \
+  -p param2=value2 \
+  -w name=source,claimName=my-pvc \
+  --showlog
+```
+
+**Declarative (YAML):**
+```yaml
+apiVersion: tekton.dev/v1
+kind: TaskRun
+metadata:
+  name: my-taskrun
+spec:
+  taskRef:
+    name: my-task
+  params:
+    - name: param1
+      value: "value1"
+    - name: param2
+      value: "value2"
+  workspaces:
+    - name: source
+      persistentVolumeClaim:
+        claimName: my-pvc
+  serviceAccountName: pipeline-sa
+  timeout: 1h
+```
+
+### TaskRun with Resolvers
+
+**Hub resolver:**
+```yaml
+apiVersion: tekton.dev/v1
+kind: TaskRun
+metadata:
+  name: git-clone-run
+spec:
+  taskRef:
+    resolver: hub
+    params:
+      - name: name
+        value: git-clone
+      - name: version
+        value: "0.10.0"
+  params:
+    - name: url
+      value: https://github.com/myorg/myrepo
+  workspaces:
+    - name: output
+      emptyDir: {}
+```
+
+**Cluster resolver:**
+```yaml
+apiVersion: tekton.dev/v1
+kind: TaskRun
+metadata:
+  name: shared-task-run
+spec:
+  taskRef:
+    resolver: cluster
+    params:
+      - name: name
+        value: shared-task
+      - name: namespace
+        value: tekton-tasks
+```
+
+### TaskRun Status
+
+```bash
+# View taskrun status
+kubectl get taskrun my-taskrun
+
+# Describe for details
+kubectl describe taskrun my-taskrun
+
+# Get status conditions
+kubectl get taskrun my-taskrun -o jsonpath='{.status.conditions}'
+
+# Get results
+kubectl get taskrun my-taskrun -o jsonpath='{.status.taskResults}'
+```
+
+## Reusable Task Patterns
+
+### Git Clone Task
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: git-clone-custom
+spec:
+  params:
+    - name: url
+      description: Git repository URL
+    - name: revision
+      description: Branch, tag, or commit
+      default: "main"
+    - name: depth
+      description: Shallow clone depth
+      default: "1"
+  workspaces:
+    - name: output
+      description: Clone destination
+  steps:
+    - name: clone
+      image: alpine/git:latest
+      script: |
+        git clone --depth=$(params.depth) \
+          --branch=$(params.revision) \
+          $(params.url) \
+          $(workspaces.output.path)
+```
+
+### Test Runner Task
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: run-tests
+spec:
+  params:
+    - name: test-command
+      description: Command to run tests
+      default: "npm test"
+  workspaces:
+    - name: source
+      description: Source code
+  results:
+    - name: test-result
+      description: Test pass/fail
+  steps:
+    - name: test
+      image: node:18
+      workingDir: $(workspaces.source.path)
+      script: |
+        if $(params.test-command); then
+          echo -n "passed" > $(results.test-result.path)
+        else
+          echo -n "failed" > $(results.test-result.path)
+          exit 1
+        fi
+```
+
+## Best Practices
+
+### Task Design
+- Keep tasks focused on single responsibility
+- Use parameters for configurability (no hardcoded values)
+- Document all parameters, workspaces, and results
+- Emit results for small data (<4KB)
+- Use workspaces for sharing larger data
+- Set resource requests/limits for all steps
+- Use non-root containers when possible
+
+### Reusability
+- Check Tekton Hub before creating custom tasks
+- Make tasks generic and parameterized
+- Use descriptive names and labels
+- Version your tasks (labels/annotations)
+- Write comprehensive descriptions
+
+### Security
+- Run as non-root user
+- Use read-only root filesystem when possible
+- Drop unnecessary capabilities
+- Use workspace-based authentication
+- Avoid embedding secrets in task definitions
+
+### Performance
+- Use caching workspaces (Maven, npm, Go)
+- Set appropriate resource limits
+- Use specific image tags (not :latest)
+- Minimize image sizes (alpine, distroless)
+- Use build caches (Kaniko, Buildah)
+
+## Common Patterns
+
+### Conditional Execution
+
+```yaml
+steps:
+  - name: deploy-to-prod
+    image: kubectl
+    script: |
+      if [ "$(params.environment)" = "production" ]; then
+        kubectl apply -f production.yaml
+      else
+        echo "Skipping production deployment"
+      fi
+```
+
+### Error Handling
+
+```yaml
+steps:
+  - name: build-with-retry
+    image: maven:3.8
+    script: |
+      #!/bin/bash
+      set -e
+
+      MAX_RETRIES=3
+      RETRY_COUNT=0
+
+      until mvn clean package; do
+        RETRY_COUNT=$((RETRY_COUNT+1))
+        if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
+          echo "Build failed after $MAX_RETRIES attempts"
+          exit 1
+        fi
+        echo "Build failed, retrying ($RETRY_COUNT/$MAX_RETRIES)..."
+        sleep 5
+      done
+```
+
+### Using Previous Step Results
+
+```yaml
+steps:
+  - name: get-version
+    image: alpine
+    script: |
+      echo -n "1.2.3" > /tmp/version
+
+  - name: use-version
+    image: alpine
+    script: |
+      VERSION=$(cat /tmp/version)
+      echo "Building version: $VERSION"
+```
+
+## Troubleshooting
+
+### Task Won't Start
+
+```bash
+# Check task exists
+kubectl get task my-task
+
+# Check taskrun status
+kubectl describe taskrun my-taskrun
+
+# Check events
+kubectl get events --sort-by=.metadata.creationTimestamp
+```
+
+### Step Failing
+
+```bash
+# View logs
+tkn taskrun logs my-taskrun -f
+
+# Check specific step
+kubectl logs <pod-name> -c step-<step-name>
+
+# Check previous container logs if crashed
+kubectl logs <pod-name> -c step-<step-name> --previous
+```
+
+### Workspace Issues
+
+```bash
+# Check PVC exists and is bound
+kubectl get pvc
+
+# Check workspace binding in taskrun
+kubectl get taskrun my-taskrun -o jsonpath='{.spec.workspaces}'
+
+# Check pod volumes
+kubectl get pod <pod-name> -o jsonpath='{.spec.volumes}'
+```
+
+### Results Not Available
+
+```bash
+# Check result was written
+kubectl get taskrun my-taskrun -o jsonpath='{.status.taskResults}'
+
+# Check step completed successfully
+kubectl get taskrun my-taskrun -o jsonpath='{.status.steps}'
+
+# Verify result size (<4KB)
+kubectl logs <pod-name> -c step-<step-name> | wc -c
+```
dots/.config/claude/skills/Tekton/workflows/TknCli.md
@@ -0,0 +1,690 @@
+# TknCli Workflow
+
+Tekton CLI (tkn) command reference and usage patterns for managing pipelines, tasks, and debugging.
+
+## When to Use
+
+- Running tkn commands
+- Viewing pipeline/task logs
+- Managing pipeline runs
+- Debugging Tekton workflows
+- Monitoring execution status
+
+## Installation
+
+### Package Managers
+
+```bash
+# macOS
+brew install tektoncd-cli
+
+# Windows
+choco install tektoncd-cli
+
+# Linux (deb-based)
+curl -LO https://github.com/tektoncd/cli/releases/download/v0.35.0/tektoncd-cli-0.35.0_Linux-64bit.deb
+sudo dpkg -i tektoncd-cli-0.35.0_Linux-64bit.deb
+
+# Linux (rpm-based)
+curl -LO https://github.com/tektoncd/cli/releases/download/v0.35.0/tektoncd-cli-0.35.0_Linux-64bit.rpm
+sudo rpm -Uvh tektoncd-cli-0.35.0_Linux-64bit.rpm
+
+# Linux (tarball)
+curl -LO https://github.com/tektoncd/cli/releases/download/v0.35.0/tkn_0.35.0_Linux_x86_64.tar.gz
+sudo tar xvzf tkn_0.35.0_Linux_x86_64.tar.gz -C /usr/local/bin/ tkn
+```
+
+### As kubectl Plugin
+
+```bash
+# Create symlink
+ln -s /usr/local/bin/tkn /usr/local/bin/kubectl-tkn
+
+# Use as kubectl plugin
+kubectl tkn version
+```
+
+### Shell Completion
+
+```bash
+# Bash
+source <(tkn completion bash)
+echo "source <(tkn completion bash)" >> ~/.bashrc
+
+# Zsh
+source <(tkn completion zsh)
+echo "source <(tkn completion zsh)" >> ~/.zshrc
+
+# Fish
+tkn completion fish | source
+echo "tkn completion fish | source" >> ~/.config/fish/config.fish
+```
+
+### Verify Installation
+
+```bash
+tkn version
+
+# Expected output:
+# Client version: 0.35.0
+# Pipeline version: v0.53.0
+# Triggers version: v0.25.0
+```
+
+## Pipeline Commands
+
+### List Pipelines
+
+```bash
+# List all pipelines
+tkn pipeline list
+
+# List with namespace
+tkn pipeline list -n <namespace>
+
+# List all namespaces
+tkn pipeline list --all-namespaces
+```
+
+### Describe Pipeline
+
+```bash
+# Show pipeline details
+tkn pipeline describe <pipeline-name>
+
+# Show with full YAML
+tkn pipeline describe <pipeline-name> -o yaml
+
+# Show with JSON
+tkn pipeline describe <pipeline-name> -o json
+```
+
+### Start Pipeline
+
+```bash
+# Start pipeline interactively
+tkn pipeline start <pipeline-name>
+
+# Start with parameters
+tkn pipeline start <pipeline-name> \
+  -p git-url=https://github.com/org/repo \
+  -p image-name=myregistry.com/myimage:latest
+
+# Start with workspace
+tkn pipeline start <pipeline-name> \
+  -w name=shared-data,claimName=my-pvc
+
+# Start with ServiceAccount
+tkn pipeline start <pipeline-name> \
+  --serviceaccount=pipeline-sa
+
+# Start and follow logs
+tkn pipeline start <pipeline-name> --showlog
+
+# Use last pipelinerun's parameters
+tkn pipeline start <pipeline-name> --last
+
+# Dry run (generate YAML without creating)
+tkn pipeline start <pipeline-name> \
+  -p git-url=https://github.com/org/repo \
+  --dry-run > pipelinerun.yaml
+```
+
+### Delete Pipeline
+
+```bash
+# Delete pipeline
+tkn pipeline delete <pipeline-name>
+
+# Delete without confirmation
+tkn pipeline delete <pipeline-name> -f
+
+# Delete all pipelines
+tkn pipeline delete --all
+
+# Delete with associated runs
+tkn pipeline delete <pipeline-name> --delete-prs
+```
+
+## PipelineRun Commands
+
+### List PipelineRuns
+
+```bash
+# List all pipelineruns
+tkn pipelinerun list
+
+# List for specific pipeline
+tkn pipelinerun list -p <pipeline-name>
+
+# List with timestamps
+tkn pipelinerun list -o wide
+
+# Limit results
+tkn pipelinerun list --limit 10
+```
+
+### Describe PipelineRun
+
+```bash
+# Describe last pipelinerun
+tkn pipelinerun describe --last
+
+# Describe specific pipelinerun
+tkn pipelinerun describe <pipelinerun-name>
+
+# Show full YAML
+tkn pipelinerun describe <pipelinerun-name> -o yaml
+
+# Show results
+tkn pipelinerun describe <pipelinerun-name> | grep -A 10 Results
+```
+
+### View Logs
+
+```bash
+# View logs from last pipelinerun
+tkn pipelinerun logs --last
+
+# Follow logs from last run
+tkn pipelinerun logs --last -f
+
+# View specific pipelinerun logs
+tkn pipelinerun logs <pipelinerun-name>
+
+# Follow specific pipelinerun
+tkn pipelinerun logs <pipelinerun-name> -f
+
+# View logs for specific task
+tkn pipelinerun logs <pipelinerun-name> -t <task-name>
+
+# View all task logs
+tkn pipelinerun logs <pipelinerun-name> --all
+
+# Stream logs with timestamps
+tkn pipelinerun logs --last -f --timestamps
+```
+
+### Cancel PipelineRun
+
+```bash
+# Cancel last pipelinerun
+tkn pipelinerun cancel --last
+
+# Cancel specific pipelinerun
+tkn pipelinerun cancel <pipelinerun-name>
+
+# Cancel without confirmation
+tkn pipelinerun cancel <pipelinerun-name> -f
+```
+
+### Delete PipelineRun
+
+```bash
+# Delete specific pipelinerun
+tkn pipelinerun delete <pipelinerun-name>
+
+# Delete last pipelinerun
+tkn pipelinerun delete --last
+
+# Delete all failed pipelineruns
+tkn pipelinerun delete --all -f --failed
+
+# Delete all pipelineruns for pipeline
+tkn pipelinerun delete --pipeline <pipeline-name>
+
+# Keep last N runs
+tkn pipelinerun delete --keep 5
+
+# Delete runs older than N minutes
+tkn pipelinerun delete --keep-since 60
+```
+
+## Task Commands
+
+### List Tasks
+
+```bash
+# List all tasks
+tkn task list
+
+# List in namespace
+tkn task list -n <namespace>
+
+# List all namespaces
+tkn task list --all-namespaces
+```
+
+### Describe Task
+
+```bash
+# Describe task
+tkn task describe <task-name>
+
+# Show YAML
+tkn task describe <task-name> -o yaml
+
+# Show parameters and workspaces
+tkn task describe <task-name> | grep -E "(Parameters|Workspaces)" -A 10
+```
+
+### Start Task
+
+```bash
+# Start task interactively
+tkn task start <task-name>
+
+# Start with parameters
+tkn task start <task-name> \
+  -p greeting=Hello \
+  -p name=World
+
+# Start with workspace
+tkn task start <task-name> \
+  -w name=source,claimName=my-pvc
+
+# Start and show logs
+tkn task start <task-name> --showlog
+
+# Use last taskrun's parameters
+tkn task start <task-name> --last
+```
+
+### Delete Task
+
+```bash
+# Delete task
+tkn task delete <task-name>
+
+# Delete without confirmation
+tkn task delete <task-name> -f
+
+# Delete with associated taskruns
+tkn task delete <task-name> --delete-trs
+```
+
+## TaskRun Commands
+
+### List TaskRuns
+
+```bash
+# List all taskruns
+tkn taskrun list
+
+# List for specific task
+tkn taskrun list -t <task-name>
+
+# List with details
+tkn taskrun list -o wide
+
+# Limit results
+tkn taskrun list --limit 10
+```
+
+### Describe TaskRun
+
+```bash
+# Describe last taskrun
+tkn taskrun describe --last
+
+# Describe specific taskrun
+tkn taskrun describe <taskrun-name>
+
+# Show YAML
+tkn taskrun describe <taskrun-name> -o yaml
+```
+
+### View TaskRun Logs
+
+```bash
+# View last taskrun logs
+tkn taskrun logs --last
+
+# Follow last taskrun
+tkn taskrun logs --last -f
+
+# View specific taskrun
+tkn taskrun logs <taskrun-name>
+
+# Follow specific taskrun
+tkn taskrun logs <taskrun-name> -f
+```
+
+### Delete TaskRun
+
+```bash
+# Delete taskrun
+tkn taskrun delete <taskrun-name>
+
+# Delete last taskrun
+tkn taskrun delete --last
+
+# Delete all taskruns
+tkn taskrun delete --all
+```
+
+## ClusterTask Commands (Deprecated)
+
+**IMPORTANT:** ClusterTasks are deprecated. Use resolvers instead.
+
+```bash
+# List clustertasks (still works but deprecated)
+tkn clustertask list
+
+# Describe clustertask
+tkn clustertask describe <clustertask-name>
+
+# Start clustertask
+tkn clustertask start <clustertask-name>
+```
+
+**Migration to resolvers:**
+```yaml
+# Old (ClusterTask)
+taskRef:
+  name: git-clone
+  kind: ClusterTask
+
+# New (Cluster resolver)
+taskRef:
+  resolver: cluster
+  params:
+    - name: name
+      value: git-clone
+    - name: namespace
+      value: tekton-tasks
+
+# Or use Hub resolver
+taskRef:
+  resolver: hub
+  params:
+    - name: name
+      value: git-clone
+    - name: version
+      value: "0.10.0"
+```
+
+## Hub Commands
+
+### Search Hub
+
+```bash
+# Search for tasks
+tkn hub search git
+
+# Search with tags
+tkn hub search --tags git
+
+# Search with limit
+tkn hub search --limit 10
+```
+
+### Get Hub Task Info
+
+```bash
+# Get task info
+tkn hub info task git-clone
+
+# Get specific version
+tkn hub info task git-clone --version 0.10.0
+```
+
+### Install from Hub
+
+```bash
+# Install task from hub
+tkn hub install task git-clone
+
+# Install specific version
+tkn hub install task git-clone --version 0.10.0
+
+# Install to specific namespace
+tkn hub install task git-clone -n tekton-tasks
+```
+
+## Debugging Workflows
+
+### Check Pipeline Status
+
+```bash
+# Get overview
+tkn pipelinerun describe --last
+
+# Check task statuses
+tkn pipelinerun describe --last | grep "TASKRUNS"
+
+# View conditions
+kubectl get pipelinerun <name> -o jsonpath='{.status.conditions}'
+```
+
+### View Detailed Logs
+
+```bash
+# All task logs with timestamps
+tkn pipelinerun logs --last -f --all --timestamps
+
+# Specific task logs
+tkn pipelinerun logs --last -t <task-name> -f
+
+# Specific step logs (use kubectl)
+kubectl logs <pod-name> -c step-<step-name>
+```
+
+### Check Events
+
+```bash
+# View events for namespace
+kubectl get events --sort-by=.metadata.creationTimestamp
+
+# Filter for Tekton events
+kubectl get events | grep -E "(Task|Pipeline)"
+
+# Watch events
+kubectl get events -w
+```
+
+### Inspect Pods
+
+```bash
+# Find taskrun pods
+kubectl get pods | grep <pipelinerun-name>
+
+# Describe pod
+kubectl describe pod <pod-name>
+
+# Check init containers
+kubectl get pod <pod-name> -o jsonpath='{.spec.initContainers[*].name}'
+
+# Check step containers
+kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].name}'
+```
+
+### Debug Failed Tasks
+
+```bash
+# Describe failed taskrun
+tkn taskrun describe <taskrun-name>
+
+# View pod conditions
+kubectl get pod <pod-name> -o jsonpath='{.status.conditions}' | jq
+
+# Check step status
+kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses}' | jq
+
+# View terminated container info
+kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[?(@.name=="step-build")].state}' | jq
+```
+
+### Access Step Results
+
+```bash
+# View task results
+tkn taskrun describe <taskrun-name> | grep -A 10 "Results"
+
+# Get specific result
+kubectl get taskrun <name> -o jsonpath='{.status.taskResults[?(@.name=="commit-sha")].value}'
+```
+
+## Useful Aliases and Functions
+
+### Bash Aliases
+
+```bash
+# Add to ~/.bashrc
+
+alias tkn-logs='tkn pipelinerun logs --last -f'
+alias tkn-list='tkn pipelinerun list'
+alias tkn-desc='tkn pipelinerun describe --last'
+alias tkn-start='tkn pipeline start'
+alias tkn-cancel='tkn pipelinerun cancel --last'
+alias tkn-tasks='tkn taskrun list'
+alias tkn-clean='tkn pipelinerun delete --all -f'
+```
+
+### Bash Functions
+
+```bash
+# Add to ~/.bashrc
+
+# Follow logs for specific pipeline
+tkn-watch() {
+  tkn pipeline start "$1" --showlog
+}
+
+# Delete old pipelineruns
+tkn-prune() {
+  local keep=${1:-5}
+  tkn pipelinerun delete --keep $keep -f
+}
+
+# Get pipeline status
+tkn-status() {
+  tkn pipelinerun list | head -n 10
+}
+
+# Restart last failed pipeline
+tkn-retry() {
+  local last_pr=$(tkn pipelinerun list -o name | head -n 1 | cut -d'/' -f2)
+  tkn pipelinerun delete $last_pr -f
+  tkn pipeline start $(tkn pipelinerun describe $last_pr -o jsonpath='{.spec.pipelineRef.name}') --last
+}
+```
+
+## Common Workflows
+
+### Start Pipeline with Full Options
+
+```bash
+tkn pipeline start build-deploy \
+  -p git-url=https://github.com/myorg/myrepo \
+  -p git-revision=main \
+  -p image-name=myregistry.com/myapp:latest \
+  -w name=shared-data,volumeClaimTemplateFile=pvc-template.yaml \
+  --serviceaccount=pipeline-sa \
+  --showlog
+```
+
+### Monitor Pipeline Execution
+
+```bash
+# Start and follow logs
+tkn pipeline start my-pipeline --showlog
+
+# Or in separate commands
+tkn pipeline start my-pipeline
+tkn pipelinerun logs --last -f
+```
+
+### Cleanup Old Runs
+
+```bash
+# Keep last 5 runs
+tkn pipelinerun delete --keep 5 -f
+
+# Delete runs older than 60 minutes
+tkn pipelinerun delete --keep-since 60 -f
+
+# Delete all failed runs
+tkn pipelinerun delete --all --failed -f
+```
+
+### Export PipelineRun for Rerun
+
+```bash
+# Export last run as YAML
+tkn pipelinerun describe --last -o yaml > rerun.yaml
+
+# Edit if needed
+vim rerun.yaml
+
+# Remove status and metadata.name
+yq eval 'del(.status) | del(.metadata.name) | del(.metadata.namespace) | del(.metadata.uid)' rerun.yaml > clean-rerun.yaml
+
+# Apply
+kubectl apply -f clean-rerun.yaml
+```
+
+## Troubleshooting
+
+### tkn Command Not Found
+
+```bash
+# Check installation
+which tkn
+
+# Add to PATH if needed
+export PATH=$PATH:/usr/local/bin
+
+# Reinstall
+brew reinstall tektoncd-cli  # macOS
+```
+
+### Cannot Connect to Cluster
+
+```bash
+# Check kubectl context
+kubectl config current-context
+
+# Check Tekton installation
+kubectl get pods -n tekton-pipelines
+
+# Check API access
+kubectl api-resources | grep tekton
+```
+
+### Logs Not Showing
+
+```bash
+# Check pod exists
+kubectl get pods | grep <pipelinerun-name>
+
+# Check pod status
+kubectl describe pod <pod-name>
+
+# Try kubectl logs directly
+kubectl logs <pod-name> -c step-<step-name>
+```
+
+### Permission Denied
+
+```bash
+# Check RBAC
+kubectl auth can-i create pipelineruns
+
+# Check ServiceAccount
+kubectl get serviceaccount
+
+# Check RoleBinding
+kubectl get rolebinding | grep tekton
+```
+
+## Best Practices
+
+- Always use `--showlog` or `-f` to follow pipeline execution
+- Set up shell completion for faster command entry
+- Use aliases for frequently used commands
+- Clean up old pipelineruns regularly to free resources
+- Use `--last` flag to avoid typing pipelinerun names
+- Export successful runs as templates for reuse
+- Monitor events during debugging (`kubectl get events -w`)
+- Use `tkn hub` to discover and install community tasks
dots/.config/claude/skills/Tekton/workflows/Triggers.md
@@ -0,0 +1,577 @@
+# Triggers Workflow
+
+Tekton Triggers for event-driven pipeline execution via webhooks and automated CI/CD.
+
+## When to Use
+
+- Setting up GitHub/GitLab webhooks
+- Automating pipeline execution from events
+- Creating event listeners
+- Configuring trigger bindings and templates
+- Integrating with version control systems
+
+## Trigger Components
+
+### EventListener
+
+**Listens for incoming HTTP events (webhooks)**
+
+```yaml
+apiVersion: triggers.tekton.dev/v1beta1
+kind: EventListener
+metadata:
+  name: github-listener
+spec:
+  serviceAccountName: tekton-triggers-sa
+  triggers:
+    - name: github-push
+      interceptors:
+        - ref:
+            name: "github"
+          params:
+            - name: "secretRef"
+              value:
+                secretName: github-secret
+                secretKey: secretToken
+            - name: "eventTypes"
+              value: ["push"]
+      bindings:
+        - ref: github-push-binding
+      template:
+        ref: pipeline-template
+```
+
+### TriggerBinding
+
+**Extracts data from event payload**
+
+```yaml
+apiVersion: triggers.tekton.dev/v1beta1
+kind: TriggerBinding
+metadata:
+  name: github-push-binding
+spec:
+  params:
+    - name: gitrevision
+      value: $(body.head_commit.id)
+    - name: gitrepositoryurl
+      value: $(body.repository.clone_url)
+    - name: gitbranch
+      value: $(body.ref)
+    - name: gitauthor
+      value: $(body.head_commit.author.username)
+    - name: gitmessage
+      value: $(body.head_commit.message)
+```
+
+### TriggerTemplate
+
+**Creates PipelineRun or TaskRun from event**
+
+```yaml
+apiVersion: triggers.tekton.dev/v1beta1
+kind: TriggerTemplate
+metadata:
+  name: pipeline-template
+spec:
+  params:
+    - name: gitrevision
+      description: Git commit SHA
+    - name: gitrepositoryurl
+      description: Repository URL
+    - name: gitbranch
+      description: Git branch ref
+  resourcetemplates:
+    - apiVersion: tekton.dev/v1
+      kind: PipelineRun
+      metadata:
+        generateName: ci-pipeline-run-
+      spec:
+        pipelineRef:
+          name: ci-pipeline
+        params:
+          - name: git-url
+            value: $(tt.params.gitrepositoryurl)
+          - name: git-revision
+            value: $(tt.params.gitrevision)
+        workspaces:
+          - name: source-code
+            volumeClaimTemplate:
+              spec:
+                accessModes:
+                  - ReadWriteOnce
+                resources:
+                  requests:
+                    storage: 1Gi
+```
+
+## GitHub Integration
+
+### Complete GitHub Webhook Setup
+
+**1. Create Secret for Webhook Validation**
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+  name: github-secret
+type: Opaque
+stringData:
+  secretToken: "your-webhook-secret-here"
+```
+
+**2. Create ServiceAccount with RBAC**
+
+```yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: tekton-triggers-sa
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: tekton-triggers-role
+rules:
+  - apiGroups: ["triggers.tekton.dev"]
+    resources: ["eventlisteners", "triggerbindings", "triggertemplates"]
+    verbs: ["get"]
+  - apiGroups: ["tekton.dev"]
+    resources: ["pipelineruns", "pipelineresources", "taskruns"]
+    verbs: ["create"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: tekton-triggers-binding
+subjects:
+  - kind: ServiceAccount
+    name: tekton-triggers-sa
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: tekton-triggers-role
+```
+
+**3. Create EventListener**
+
+```yaml
+apiVersion: triggers.tekton.dev/v1beta1
+kind: EventListener
+metadata:
+  name: github-listener
+spec:
+  serviceAccountName: tekton-triggers-sa
+  triggers:
+    - name: github-push
+      interceptors:
+        - ref:
+            name: "github"
+          params:
+            - name: "secretRef"
+              value:
+                secretName: github-secret
+                secretKey: secretToken
+            - name: "eventTypes"
+              value: ["push", "pull_request"]
+      bindings:
+        - ref: github-binding
+      template:
+        ref: pipeline-template
+```
+
+**4. Expose EventListener**
+
+```bash
+# Get event listener service
+kubectl get svc el-github-listener
+
+# Expose via Ingress
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: github-webhook
+  annotations:
+    cert-manager.io/cluster-issuer: letsencrypt-prod
+spec:
+  ingressClassName: nginx
+  tls:
+    - hosts:
+        - webhooks.example.com
+      secretName: webhook-tls
+  rules:
+    - host: webhooks.example.com
+      http:
+        paths:
+          - path: /
+            pathType: Prefix
+            backend:
+              service:
+                name: el-github-listener
+                port:
+                  number: 8080
+```
+
+**5. Configure GitHub Webhook**
+
+- Go to GitHub repository Settings → Webhooks
+- Payload URL: `https://webhooks.example.com`
+- Content type: `application/json`
+- Secret: Same value as in `github-secret`
+- Events: Push, Pull Request
+- Active: ✓
+
+### GitHub TriggerBinding Examples
+
+**Push event:**
+```yaml
+spec:
+  params:
+    - name: gitrevision
+      value: $(body.head_commit.id)
+    - name: gitrepositoryurl
+      value: $(body.repository.clone_url)
+    - name: gitbranch
+      value: $(extensions.branch_name)
+```
+
+**Pull Request event:**
+```yaml
+spec:
+  params:
+    - name: pr-number
+      value: $(body.pull_request.number)
+    - name: pr-title
+      value: $(body.pull_request.title)
+    - name: pr-head-sha
+      value: $(body.pull_request.head.sha)
+    - name: pr-base-branch
+      value: $(body.pull_request.base.ref)
+```
+
+## GitLab Integration
+
+### GitLab EventListener
+
+```yaml
+apiVersion: triggers.tekton.dev/v1beta1
+kind: EventListener
+metadata:
+  name: gitlab-listener
+spec:
+  serviceAccountName: tekton-triggers-sa
+  triggers:
+    - name: gitlab-push
+      interceptors:
+        - ref:
+            name: "gitlab"
+          params:
+            - name: "secretRef"
+              value:
+                secretName: gitlab-secret
+                secretKey: secretToken
+            - name: "eventTypes"
+              value: ["Push Hook", "Merge Request Hook"]
+      bindings:
+        - ref: gitlab-binding
+      template:
+        ref: pipeline-template
+```
+
+### GitLab TriggerBinding
+
+```yaml
+apiVersion: triggers.tekton.dev/v1beta1
+kind: TriggerBinding
+metadata:
+  name: gitlab-binding
+spec:
+  params:
+    - name: gitrevision
+      value: $(body.checkout_sha)
+    - name: gitrepositoryurl
+      value: $(body.project.git_http_url)
+    - name: gitbranch
+      value: $(body.ref)
+    - name: project-name
+      value: $(body.project.name)
+```
+
+## Interceptors
+
+### CEL Interceptor (Custom Logic)
+
+```yaml
+interceptors:
+  - name: "filter-branch"
+    ref:
+      name: "cel"
+    params:
+      - name: "filter"
+        value: "body.ref.startsWith('refs/heads/main')"
+      - name: "overlays"
+        value:
+          - key: branch_name
+            expression: "body.ref.split('/')[2]"
+```
+
+### Webhook Interceptor (Custom Service)
+
+```yaml
+interceptors:
+  - name: "custom-logic"
+    webhook:
+      objectRef:
+        apiVersion: v1
+        kind: Service
+        name: custom-interceptor
+        namespace: default
+      header:
+        - name: X-Custom-Header
+          value: "custom-value"
+```
+
+## Advanced Patterns
+
+### Multiple Triggers in One EventListener
+
+```yaml
+spec:
+  triggers:
+    - name: main-branch
+      interceptors:
+        - ref:
+            name: "cel"
+          params:
+            - name: "filter"
+              value: "body.ref == 'refs/heads/main'"
+      bindings:
+        - ref: prod-binding
+      template:
+        ref: prod-template
+
+    - name: feature-branch
+      interceptors:
+        - ref:
+            name: "cel"
+          params:
+            - name: "filter"
+              value: "body.ref.startsWith('refs/heads/feature/')"
+      bindings:
+        - ref: dev-binding
+      template:
+        ref: dev-template
+```
+
+### Conditional Pipeline Execution
+
+```yaml
+# In TriggerTemplate
+spec:
+  resourcetemplates:
+    - apiVersion: tekton.dev/v1
+      kind: PipelineRun
+      metadata:
+        generateName: conditional-run-
+      spec:
+        pipelineRef:
+          name: my-pipeline
+        params:
+          - name: deploy-to-prod
+            value: $(tt.params.gitbranch == "refs/heads/main")
+```
+
+### ClusterTriggerBinding (Cluster-Wide Reuse)
+
+```yaml
+apiVersion: triggers.tekton.dev/v1beta1
+kind: ClusterTriggerBinding
+metadata:
+  name: common-git-binding
+spec:
+  params:
+    - name: gitrevision
+      value: $(body.head_commit.id)
+    - name: gitrepositoryurl
+      value: $(body.repository.clone_url)
+```
+
+## Testing Triggers
+
+### Test with curl
+
+```bash
+# Get EventListener URL
+EL_URL=$(kubectl get eventlistener github-listener -o jsonpath='{.status.address.url}')
+
+# Send test payload
+curl -X POST $EL_URL \
+  -H "Content-Type: application/json" \
+  -H "X-GitHub-Event: push" \
+  -H "X-Hub-Signature: sha1=..." \
+  -d @test-payload.json
+
+# Watch for pipelinerun creation
+kubectl get pipelineruns -w
+```
+
+### Test Payload Examples
+
+**GitHub push:**
+```json
+{
+  "ref": "refs/heads/main",
+  "head_commit": {
+    "id": "abc123...",
+    "message": "Test commit",
+    "author": {
+      "username": "testuser"
+    }
+  },
+  "repository": {
+    "clone_url": "https://github.com/org/repo.git",
+    "name": "repo"
+  }
+}
+```
+
+## Troubleshooting
+
+### EventListener Not Receiving Events
+
+```bash
+# Check EventListener pod
+kubectl get pods -l eventlistener=github-listener
+
+# Check logs
+kubectl logs -l eventlistener=github-listener
+
+# Check service
+kubectl get svc el-github-listener
+
+# Test connectivity
+kubectl port-forward svc/el-github-listener 8080:8080
+curl -X POST http://localhost:8080 -d '{}'
+```
+
+### Webhook Validation Failing
+
+```bash
+# Check secret exists
+kubectl get secret github-secret
+
+# Verify secret value matches GitHub
+kubectl get secret github-secret -o jsonpath='{.data.secretToken}' | base64 -d
+
+# Check interceptor logs
+kubectl logs -l eventlistener=github-listener | grep "validation failed"
+```
+
+### PipelineRun Not Created
+
+```bash
+# Check EventListener logs
+kubectl logs -l eventlistener=github-listener
+
+# Check RBAC permissions
+kubectl auth can-i create pipelineruns --as=system:serviceaccount:default:tekton-triggers-sa
+
+# Check TriggerTemplate
+kubectl get triggertemplate pipeline-template -o yaml
+```
+
+### Wrong Parameters Extracted
+
+```bash
+# View received payload
+kubectl logs -l eventlistener=github-listener | grep "event body"
+
+# Test TriggerBinding
+# Create test EventListener with logging
+# Examine extracted parameters in logs
+```
+
+## Best Practices
+
+### Security
+- Always validate webhooks with secrets
+- Use HTTPS for webhook endpoints
+- Limit webhook events to necessary types
+- Use dedicated ServiceAccount with minimal permissions
+- Never expose raw event data in logs
+
+### Reliability
+- Set resource limits on EventListener pods
+- Use horizontal pod autoscaling for high traffic
+- Implement retry logic in pipelines
+- Monitor EventListener availability
+- Use Ingress with TLS termination
+
+### Maintainability
+- Use ClusterTriggerBinding for common parameters
+- Keep TriggerBindings focused and reusable
+- Document expected event payload structure
+- Version your TriggerTemplates
+- Use CEL interceptors for complex filtering
+
+### Performance
+- Filter events early with interceptors
+- Avoid creating unnecessary PipelineRuns
+- Use volumeClaimTemplate for workspace isolation
+- Set appropriate timeouts
+- Clean up old PipelineRuns with pruner
+
+## Common Patterns
+
+### Multi-Repository Trigger
+
+```yaml
+spec:
+  triggers:
+    - name: repo-a
+      interceptors:
+        - ref:
+            name: "cel"
+          params:
+            - name: "filter"
+              value: "body.repository.name == 'repo-a'"
+      template:
+        ref: repo-a-template
+
+    - name: repo-b
+      interceptors:
+        - ref:
+            name: "cel"
+          params:
+            - name: "filter"
+              value: "body.repository.name == 'repo-b'"
+      template:
+        ref: repo-b-template
+```
+
+### Branch-Based Pipeline Selection
+
+```yaml
+spec:
+  triggers:
+    - name: main-branch
+      interceptors:
+        - ref:
+            name: "cel"
+          params:
+            - name: "filter"
+              value: "body.ref == 'refs/heads/main'"
+      template:
+        ref: production-pipeline-template
+
+    - name: develop-branch
+      interceptors:
+        - ref:
+            name: "cel"
+          params:
+            - name: "filter"
+              value: "body.ref == 'refs/heads/develop'"
+      template:
+        ref: staging-pipeline-template
+```
dots/.config/claude/skills/Tekton/SKILL.md
@@ -0,0 +1,347 @@
+---
+name: Tekton
+description: Tekton Pipelines CI/CD best practices for Kubernetes-native workflows. USE WHEN working with Tekton tasks, pipelines, triggers, building container images, GitOps integration, or cloud-native CI/CD.
+---
+
+# Tekton
+
+Expert guidance on Tekton Pipelines, a Kubernetes-native CI/CD framework for building, testing, and deploying applications with declarative, reusable workflows.
+
+## Workflow Routing
+
+**When executing a workflow, output this notification directly:**
+
+```
+Running the **WorkflowName** workflow from the **Tekton** skill...
+```
+
+| Workflow | Trigger | File |
+|----------|---------|------|
+| **TknCli** | "tkn command", "view logs", "pipeline run", "task run" | `workflows/TknCli.md` |
+| **Tasks** | "create task", "task definition", "step", "taskrun" | `workflows/Tasks.md` |
+| **Pipelines** | "create pipeline", "pipeline workflow", "pipelinerun" | `workflows/Pipelines.md` |
+| **Triggers** | "webhook", "eventlistener", "trigger", "github integration" | `workflows/Triggers.md` |
+| **Build** | "build image", "kaniko", "buildah", "container build" | `workflows/Build.md` |
+| **GitOps** | "argocd", "flux", "gitops integration", "deployment automation" | `workflows/GitOps.md` |
+| **BestPractices** | "tekton best practices", "optimization", "security" | `workflows/BestPractices.md` |
+
+## Quick Reference
+
+### Essential tkn Commands
+
+```bash
+# Pipeline operations
+tkn pipeline list
+tkn pipeline describe <pipeline-name>
+tkn pipeline start <pipeline-name>
+tkn pipeline delete <pipeline-name>
+
+# PipelineRun operations
+tkn pipelinerun list
+tkn pipelinerun describe <pipelinerun-name>
+tkn pipelinerun logs <pipelinerun-name> -f
+tkn pipelinerun cancel <pipelinerun-name>
+tkn pipelinerun delete <pipelinerun-name>
+
+# Task operations
+tkn task list
+tkn task start <task-name>
+tkn taskrun logs <taskrun-name> -f
+
+# ClusterTask operations (deprecated - use resolvers)
+tkn clustertask list
+```
+
+### Common Aliases
+
+```bash
+alias tkn-logs='tkn pipelinerun logs --last -f'
+alias tkn-list='tkn pipelinerun list'
+alias tkn-desc='tkn pipelinerun describe --last'
+alias tkn-cancel='tkn pipelinerun cancel --last'
+```
+
+## Core Concepts
+
+### Tekton Building Blocks
+
+**Task**: Single unit of work with one or more Steps
+- Reusable, parameterized
+- Executes in containers
+- Can emit Results (<4KB)
+- Declares Workspace requirements
+
+**Pipeline**: Orchestrates multiple Tasks
+- Defines task execution order (sequential/parallel)
+- Manages data flow between tasks
+- DAG (Directed Acyclic Graph) execution
+
+**Trigger**: Event-driven pipeline execution
+- EventListener: Listens for webhooks
+- TriggerBinding: Extracts event data
+- TriggerTemplate: Creates PipelineRun/TaskRun
+
+**Workspace**: Shared filesystem storage
+- PersistentVolumeClaim (best for sharing)
+- emptyDir (temporary)
+- ConfigMap/Secret (configuration)
+
+### Task Example
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+  name: hello-world
+spec:
+  params:
+    - name: greeting
+      description: The greeting message
+      default: "Hello"
+  steps:
+    - name: echo
+      image: alpine
+      script: |
+        echo "$(params.greeting), World!"
+```
+
+### Pipeline Example
+
+```yaml
+apiVersion: tekton.dev/v1
+kind: Pipeline
+metadata:
+  name: build-deploy
+spec:
+  params:
+    - name: git-url
+    - name: image-name
+  workspaces:
+    - name: shared-data
+  tasks:
+    - name: clone
+      taskRef:
+        name: git-clone
+      workspaces:
+        - name: output
+          workspace: shared-data
+      params:
+        - name: url
+          value: $(params.git-url)
+
+    - name: build
+      taskRef:
+        name: kaniko
+      runAfter:
+        - clone
+      workspaces:
+        - name: source
+          workspace: shared-data
+      params:
+        - name: IMAGE
+          value: $(params.image-name)
+```
+
+## Common Workflow Patterns
+
+### CI/CD Pipeline Pattern
+
+```
+1. Git Clone    → Fetch source code
+2. Test         → Run unit/integration tests
+3. Build        → Build container image (Kaniko/Buildah)
+4. Scan         → Security scan (Trivy)
+5. Push         → Push to container registry
+6. Deploy       → Update GitOps repo or deploy directly
+```
+
+### Task Execution Control
+
+**Sequential execution:**
+```yaml
+- name: build
+  runAfter:
+    - test
+```
+
+**Parallel execution:**
+```yaml
+- name: lint
+  # No runAfter - runs in parallel
+- name: test
+  # No runAfter - runs in parallel
+```
+
+**Conditional execution:**
+```yaml
+- name: deploy-prod
+  when:
+    - input: "$(params.environment)"
+      operator: in
+      values: ["production"]
+```
+
+**Cleanup (always runs):**
+```yaml
+finally:
+  - name: cleanup
+    taskRef:
+      name: cleanup-workspace
+```
+
+## Tekton Hub Integration
+
+**Reference tasks from Tekton Hub:**
+```yaml
+taskRef:
+  resolver: hub
+  params:
+    - name: name
+      value: git-clone
+    - name: version
+      value: "0.10.0"
+```
+
+**Popular Hub Tasks:**
+- `git-clone`: Clone Git repositories
+- `kaniko`: Build and push container images
+- `kubernetes-actions`: Run kubectl commands
+- `helm-upgrade`: Deploy Helm charts
+- `trivy-scanner`: Security scanning
+
+**Browse tasks:** https://hub.tekton.dev
+
+## Integration with Kubernetes Skill
+
+This Tekton skill builds on the Kubernetes skill:
+
+- **Kubernetes/Debug**: Debug pods created by Tekton TaskRuns
+- **Kubernetes/Deploy**: Understanding where Tekton deploys workloads
+- **Kubernetes/Resources**: Tekton creates Kubernetes CRDs (Tasks, Pipelines)
+- **Kubernetes/Security**: RBAC for Tekton ServiceAccounts
+- **Kubernetes/Context**: Managing Tekton across multiple clusters
+
+**Before using Tekton, ensure you're familiar with:**
+- Kubernetes pods and containers
+- PersistentVolumeClaims (PVCs)
+- ServiceAccounts and RBAC
+- Secrets and ConfigMaps
+- kubectl basics
+
+## Key Best Practices
+
+### Security
+- Use workspace-based authentication (not built-in credential init)
+- Create dedicated ServiceAccounts per pipeline
+- Follow least privilege principle for RBAC
+- Use personal access tokens, not passwords
+- Never commit secrets to Git
+
+### Performance
+- Always set resource requests/limits
+- Configure pipeline pruner for automatic cleanup
+- Use volumeClaimTemplate for isolation
+- Leverage caching (Kaniko layers, Maven deps)
+- Be aware of PVC access mode limitations
+
+### Reusability
+- Parameterize everything (no hardcoded values)
+- Use Tekton Hub tasks when available
+- Emit Results for small data (<4KB)
+- Use Workspaces for larger data
+- Keep tasks focused (single responsibility)
+
+### Anti-Patterns to Avoid
+1. **Don't use ClusterTasks** - Deprecated, use resolvers instead
+2. **Don't use PipelineResources** - Deprecated, use Tasks with Results
+3. **Don't skip resource limits** - Causes scheduling issues
+4. **Don't share ReadWriteOnce PVCs in parallel** - Will fail
+5. **Don't use built-in credential init only** - Moving to workspace-based auth
+6. **Don't create monolithic tasks** - Break into focused tasks
+7. **Don't ignore pipeline pruner** - Old resources fill etcd
+
+## Troubleshooting Quick Reference
+
+```bash
+# View pipeline run status
+tkn pipelinerun describe <name>
+
+# Stream logs
+tkn pipelinerun logs <name> -f
+
+# Check why task failed
+kubectl describe taskrun <taskrun-name>
+
+# View events
+kubectl get events --sort-by=.metadata.creationTimestamp
+
+# Check pod logs directly
+kubectl logs <pod-name> -c step-<step-name>
+
+# Debug container
+kubectl debug -it <pod-name> --image=alpine --target=<container>
+```
+
+## Examples
+
+**Example 1: Create CI pipeline**
+```
+User: "Create a Tekton pipeline that clones a repo, runs tests, and builds a container image"
+→ Invokes Pipelines workflow
+→ Creates pipeline with git-clone, test, and kaniko tasks
+→ Configures workspaces for source sharing
+→ Sets up proper task dependencies
+```
+
+**Example 2: Set up GitHub webhook**
+```
+User: "Set up GitHub webhook to trigger my pipeline on push"
+→ Invokes Triggers workflow
+→ Creates EventListener with GitHub interceptor
+→ Configures TriggerBinding to extract commit info
+→ Sets up TriggerTemplate to start PipelineRun
+```
+
+**Example 3: Integrate with ArgoCD**
+```
+User: "How do I integrate Tekton with ArgoCD for GitOps?"
+→ Invokes GitOps workflow
+→ Explains CI (Tekton) vs CD (ArgoCD) separation
+→ Shows how Tekton updates GitOps repo
+→ ArgoCD syncs changes to cluster
+```
+
+## Installation
+
+**Install Tekton Pipelines:**
+```bash
+kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
+```
+
+**Install Tekton Triggers:**
+```bash
+kubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
+```
+
+**Install tkn CLI:**
+```bash
+# macOS
+brew install tektoncd-cli
+
+# Linux
+curl -LO https://github.com/tektoncd/cli/releases/latest/download/tkn_<version>_Linux_x86_64.tar.gz
+sudo tar xvzf tkn_<version>_Linux_x86_64.tar.gz -C /usr/local/bin/ tkn
+```
+
+**Verify installation:**
+```bash
+kubectl get pods -n tekton-pipelines
+tkn version
+```
+
+## Related Skills
+
+- **Kubernetes**: Foundation for Tekton (pods, PVCs, RBAC)
+- **Git**: Source control integration and GitOps workflows
+- **Golang**: Writing custom Tekton tasks and controllers
+- **Nix/Homelab**: Managing Tekton in NixOS/K3s environments