plugins/bash-master/skills/modern-automation-patterns/SKILL.md
Modern DevOps and CI/CD bash automation patterns with containers and cloud (2025). PROACTIVELY activate for: (1) writing CI/CD scripts (GitHub Actions, GitLab CI, Azure DevOps), (2) container-aware shell scripting (detecting containers, Kubernetes pods), (3) cloud provider helpers (AWS CLI, Azure CLI, gcloud), (4) blue-green and canary deployments via bash, (5) writing idempotent rollback scripts, (6) integrating with Docker/Compose from bash, (7) cross-environment variable management, (8) build matrix orchestration. Provides: copy-pasteable CI snippets, container detection helpers, cloud CLI wrappers, deployment orchestration patterns, and idempotent rollback templates.
npx skillsauth add JosiahSiegel/claude-plugin-marketplace modern-automation-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
MANDATORY: Always Use Backslashes on Windows for File Paths
When using Edit or Write tools on Windows, you MUST use backslashes (\) in file paths, NOT forward slashes (/).
Examples:
D:/repos/project/file.tsxD:\repos\project\file.tsxThis applies to:
NEVER create new documentation files unless explicitly requested by the user.
Production-ready patterns for DevOps automation, CI/CD pipelines, and cloud-native operations following 2025 industry standards.
#!/usr/bin/env bash
set -euo pipefail
# Detect container environment
detect_container() {
if [[ -f /.dockerenv ]]; then
echo "docker"
elif grep -q docker /proc/1/cgroup 2>/dev/null; then
echo "docker"
elif [[ -n "${KUBERNETES_SERVICE_HOST:-}" ]]; then
echo "kubernetes"
else
echo "host"
fi
}
# Container-aware configuration
readonly CONTAINER_ENV=$(detect_container)
case "$CONTAINER_ENV" in
docker|kubernetes)
# Container-specific paths
DATA_DIR="/data"
CONFIG_DIR="/config"
;;
host)
# Host-specific paths
DATA_DIR="/var/lib/app"
CONFIG_DIR="/etc/app"
;;
esac
#!/bin/sh
# Use /bin/sh for Alpine-based containers (no bash)
set -eu # Note: No pipefail in POSIX sh
# Check if running as PID 1
if [ $$ -eq 1 ]; then
# PID 1 must handle signals properly
trap 'kill -TERM $child 2>/dev/null' TERM INT
# Start main process in background
/app/main &
child=$!
# Wait for child
wait "$child"
else
# Not PID 1, run directly
exec /app/main
fi
#!/usr/bin/env bash
# healthcheck.sh - Container health probe
set -euo pipefail
# Quick health check (< 1 second)
check_health() {
local timeout=1
# Check process is running
if ! pgrep -f "myapp" > /dev/null; then
echo "Process not running" >&2
return 1
fi
# Check HTTP endpoint
if ! timeout "$timeout" curl -sf http://localhost:8080/health > /dev/null; then
echo "Health endpoint failed" >&2
return 1
fi
# Check critical files
if [[ ! -f /app/ready ]]; then
echo "Not ready" >&2
return 1
fi
return 0
}
check_health
#!/usr/bin/env bash
# ci-helper.sh - GitHub Actions utilities
set -euo pipefail
# Detect GitHub Actions
is_github_actions() {
[[ "${GITHUB_ACTIONS:-false}" == "true" ]]
}
# GitHub Actions output
gh_output() {
local name="$1"
local value="$2"
if is_github_actions; then
echo "${name}=${value}" >> "$GITHUB_OUTPUT"
fi
}
# GitHub Actions annotations
gh_error() {
if is_github_actions; then
echo "::error::$*"
else
echo "ERROR: $*" >&2
fi
}
gh_warning() {
if is_github_actions; then
echo "::warning::$*"
else
echo "WARN: $*" >&2
fi
}
gh_notice() {
if is_github_actions; then
echo "::notice::$*"
else
echo "INFO: $*"
fi
}
# Set job summary
gh_summary() {
if is_github_actions; then
echo "$*" >> "$GITHUB_STEP_SUMMARY"
fi
}
# Usage example
gh_notice "Starting build"
build_result=$(make build 2>&1)
gh_output "build_result" "$build_result"
gh_summary "## Build Complete\n\nStatus: Success"
#!/usr/bin/env bash
# azdo-helper.sh - Azure DevOps utilities
set -euo pipefail
# Detect Azure DevOps
is_azure_devops() {
[[ -n "${TF_BUILD:-}" ]]
}
# Azure DevOps output variable
azdo_output() {
local name="$1"
local value="$2"
if is_azure_devops; then
echo "##vso[task.setvariable variable=$name]$value"
fi
}
# Azure DevOps logging
azdo_error() {
if is_azure_devops; then
echo "##vso[task.logissue type=error]$*"
else
echo "ERROR: $*" >&2
fi
}
azdo_warning() {
if is_azure_devops; then
echo "##vso[task.logissue type=warning]$*"
else
echo "WARN: $*" >&2
fi
}
# Section grouping
azdo_section_start() {
is_azure_devops && echo "##[section]$*"
}
azdo_section_end() {
is_azure_devops && echo "##[endsection]"
}
# Usage
azdo_section_start "Running Tests"
test_result=$(npm test)
azdo_output "test_result" "$test_result"
azdo_section_end
#!/usr/bin/env bash
set -euo pipefail
# Detect CI environment
detect_ci() {
if [[ "${GITHUB_ACTIONS:-false}" == "true" ]]; then
echo "github"
elif [[ -n "${TF_BUILD:-}" ]]; then
echo "azuredevops"
elif [[ -n "${GITLAB_CI:-}" ]]; then
echo "gitlab"
elif [[ -n "${CIRCLECI:-}" ]]; then
echo "circleci"
elif [[ -n "${JENKINS_URL:-}" ]]; then
echo "jenkins"
else
echo "local"
fi
}
# Universal output
ci_output() {
local name="$1"
local value="$2"
local ci_env
ci_env=$(detect_ci)
case "$ci_env" in
github)
echo "${name}=${value}" >> "$GITHUB_OUTPUT"
;;
azuredevops)
echo "##vso[task.setvariable variable=$name]$value"
;;
gitlab)
echo "${name}=${value}" >> ci_output.env
;;
*)
echo "export ${name}=\"${value}\""
;;
esac
}
# Universal error
ci_error() {
local ci_env
ci_env=$(detect_ci)
case "$ci_env" in
github)
echo "::error::$*"
;;
azuredevops)
echo "##vso[task.logissue type=error]$*"
;;
*)
echo "ERROR: $*" >&2
;;
esac
}
#!/usr/bin/env bash
set -euo pipefail
# Check AWS CLI availability
require_aws() {
if ! command -v aws &> /dev/null; then
echo "Error: AWS CLI not installed" >&2
exit 1
fi
}
# Get AWS account ID
get_aws_account_id() {
aws sts get-caller-identity --query Account --output text
}
# Get secret from AWS Secrets Manager
get_aws_secret() {
local secret_name="$1"
aws secretsmanager get-secret-value \
--secret-id "$secret_name" \
--query SecretString \
--output text
}
# Upload to S3 with retry
s3_upload_retry() {
local file="$1"
local s3_path="$2"
local max_attempts=3
local attempt=1
while ((attempt <= max_attempts)); do
if aws s3 cp "$file" "$s3_path"; then
return 0
fi
echo "Upload failed (attempt $attempt/$max_attempts)" >&2
((attempt++))
sleep $((attempt * 2))
done
return 1
}
# Assume IAM role
assume_role() {
local role_arn="$1"
local session_name="${2:-bash-script}"
local credentials
credentials=$(aws sts assume-role \
--role-arn "$role_arn" \
--role-session-name "$session_name" \
--query Credentials \
--output json)
export AWS_ACCESS_KEY_ID=$(echo "$credentials" | jq -r .AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo "$credentials" | jq -r .SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo "$credentials" | jq -r .SessionToken)
}
#!/usr/bin/env bash
set -euo pipefail
# Check Azure CLI
require_az() {
if ! command -v az &> /dev/null; then
echo "Error: Azure CLI not installed" >&2
exit 1
fi
}
# Get Azure subscription ID
get_az_subscription_id() {
az account show --query id --output tsv
}
# Get secret from Azure Key Vault
get_keyvault_secret() {
local vault_name="$1"
local secret_name="$2"
az keyvault secret show \
--vault-name "$vault_name" \
--name "$secret_name" \
--query value \
--output tsv
}
# Upload to Azure Blob Storage
az_blob_upload() {
local file="$1"
local container="$2"
local blob_name="${3:-$(basename "$file")}"
az storage blob upload \
--file "$file" \
--container-name "$container" \
--name "$blob_name" \
--overwrite
}
# Get managed identity token
get_managed_identity_token() {
local resource="${1:-https://management.azure.com/}"
curl -sf -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$resource" \
| jq -r .access_token
}
#!/usr/bin/env bash
set -euo pipefail
# Check for GNU parallel
if command -v parallel &> /dev/null; then
# Process files in parallel
export -f process_file
find data/ -name "*.json" | parallel -j 4 process_file {}
else
# Fallback to bash background jobs
max_jobs=4
job_count=0
for file in data/*.json; do
process_file "$file" &
((job_count++))
if ((job_count >= max_jobs)); then
wait -n
((job_count--))
fi
done
wait # Wait for remaining jobs
fi
#!/usr/bin/env bash
set -euo pipefail
# Job pool implementation
job_pool_init() {
readonly MAX_JOBS="${1:-4}"
JOB_POOL_PIDS=()
}
job_pool_run() {
# Wait if pool is full
while ((${#JOB_POOL_PIDS[@]} >= MAX_JOBS)); do
job_pool_wait_any
done
# Start new job
"$@" &
JOB_POOL_PIDS+=($!)
}
job_pool_wait_any() {
# Wait for any job to finish
if ((${#JOB_POOL_PIDS[@]} > 0)); then
local pid
wait -n
# Remove finished PIDs
for i in "${!JOB_POOL_PIDS[@]}"; do
if ! kill -0 "${JOB_POOL_PIDS[$i]}" 2>/dev/null; then
unset 'JOB_POOL_PIDS[$i]'
fi
done
JOB_POOL_PIDS=("${JOB_POOL_PIDS[@]}") # Reindex
fi
}
job_pool_wait_all() {
wait
JOB_POOL_PIDS=()
}
# Usage
job_pool_init 4
for file in data/*.txt; do
job_pool_run process_file "$file"
done
job_pool_wait_all
#!/usr/bin/env bash
set -euo pipefail
# Blue-green deployment helper
deploy_blue_green() {
local new_version="$1"
local health_check_url="$2"
echo "Starting blue-green deployment: $new_version"
# Deploy to green (inactive) environment
echo "Deploying to green environment..."
deploy_to_environment "green" "$new_version"
# Health check
echo "Running health checks..."
if ! check_health "$health_check_url"; then
echo "Health check failed, rolling back" >&2
return 1
fi
# Switch traffic to green
echo "Switching traffic to green..."
switch_traffic "green"
# Keep blue as backup for rollback
echo "Deployment complete. Blue environment kept for rollback."
}
check_health() {
local url="$1"
local max_attempts=30
local attempt=1
while ((attempt <= max_attempts)); do
if curl -sf "$url" > /dev/null; then
return 0
fi
echo "Health check attempt $attempt/$max_attempts failed"
sleep 2
((attempt++))
done
return 1
}
#!/usr/bin/env bash
set -euo pipefail
# Canary deployment with gradual rollout
deploy_canary() {
local new_version="$1"
local stages=(5 10 25 50 100) # Percentage stages
echo "Starting canary deployment: $new_version"
for percentage in "${stages[@]}"; do
echo "Rolling out to $percentage% of traffic..."
# Update traffic split
update_traffic_split "$percentage" "$new_version"
# Monitor for issues
echo "Monitoring for 5 minutes..."
if ! monitor_metrics 300; then
echo "Issues detected, rolling back" >&2
update_traffic_split 0 "$new_version"
return 1
fi
echo "Stage $percentage% successful"
done
echo "Canary deployment complete"
}
monitor_metrics() {
local duration="$1"
local end_time=$((SECONDS + duration))
while ((SECONDS < end_time)); do
# Check error rate
local error_rate
error_rate=$(get_error_rate)
if ((error_rate > 5)); then
echo "Error rate too high: $error_rate%" >&2
return 1
fi
sleep 10
done
return 0
}
#!/usr/bin/env bash
set -euo pipefail
# JSON structured logging
log_json() {
local level="$1"
local message="$2"
shift 2
local timestamp
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Build JSON
local json
json=$(jq -n \
--arg timestamp "$timestamp" \
--arg level "$level" \
--arg message "$message" \
--arg script "$SCRIPT_NAME" \
--argjson context "$(echo "$@" | jq -Rs .)" \
'{
timestamp: $timestamp,
level: $level,
message: $message,
script: $script,
context: $context
}')
echo "$json" >&2
}
log_info() { log_json "INFO" "$@"; }
log_error() { log_json "ERROR" "$@"; }
log_warn() { log_json "WARN" "$@"; }
# Usage
log_info "Processing file" "file=/data/input.txt" "size=1024"
Modern automation requires cloud-native patterns, container awareness, and robust CI/CD integration. These patterns ensure production-ready deployments in 2025.
development
This skill should be used when the user asks to train, debug, scale, or improve ML models. PROACTIVELY activate for: (1) PyTorch, TensorFlow/Keras, JAX, Flax, Hugging Face Trainer/Accelerate training loops, (2) distributed training, DDP/FSDP/DeepSpeed, TPU/GPU setup, (3) mixed precision AMP/bf16, gradient accumulation, checkpointing, seeding, (4) overfitting, imbalance, loss functions, regularization, LR schedules, warmup, (5) memory optimization, gradient checkpointing, offloading, quantization-aware training. Provides: reproducible training best practices across deep learning and classical ML.
development
This skill should be used when the user asks to productionize, track, version, govern, monitor, or automate ML systems. PROACTIVELY activate for: (1) MLflow, Weights & Biases, Neptune, Comet, ClearML experiment tracking, (2) model registry, model versioning, artifact lineage, reproducibility, (3) Kubeflow, SageMaker Pipelines, Vertex AI Pipelines, Azure ML pipelines, Databricks workflows, (4) CI/CD, continuous training/evaluation, A/B tests, canary/shadow deployments, (5) drift detection, model monitoring, data validation, responsible AI governance. Provides: end-to-end MLOps architecture and operational safeguards.
development
This skill should be used when the user asks to optimize, export, serve, compress, or accelerate ML inference. PROACTIVELY activate for: (1) latency, throughput, p95/p99, batching, concurrency, KV cache, memory, or cost issues, (2) quantization INT8/INT4, GPTQ, AWQ, bitsandbytes, pruning, sparsity, distillation, (3) ONNX export, ONNX Runtime, TensorRT, TorchScript, torch.compile, XLA, OpenVINO, Core ML, TFLite, (4) Triton, TorchServe, TF Serving, BentoML, Seldon, KServe configuration, (5) edge deployment, CPU/GPU/TPU/Inferentia serving. Provides: hardware-aware inference optimization and safe benchmarking.
testing
This skill should be used when the user asks to tune hyperparameters, run sweeps, optimize search spaces, or use AutoML. PROACTIVELY activate for: (1) Optuna, Ray Tune, FLAML, AutoGluon, Hyperopt, Nevergrad, KerasTuner, W&B sweeps, (2) grid search, random search, Bayesian optimization, TPE, Gaussian processes, evolutionary search, (3) ASHA, Hyperband, successive halving, multi-fidelity optimization, population-based training, (4) learning-rate finder, batch-size search, early stopping, pruning, (5) reproducible sweep design and experiment analysis. Provides: budget-aware hyperparameter search strategy.