Agent Skills Framework Extension
Cloud-Native Patterns Skill
When to Use This Skill
Use this skill when implementing cloud native patterns patterns in your codebase.
How to Use This Skill
- Review the patterns and examples below
- Apply the relevant patterns to your implementation
- Follow the best practices outlined in this skill
12-factor app, serverless, auto-scaling, and cloud-native design patterns.
Core Capabilities
- 12-Factor App - Cloud-native application design
- Container Patterns - Sidecar, ambassador, adapter
- Auto-Scaling - HPA, VPA, custom metrics
- Health Management - Liveness, readiness, startup probes
- Graceful Operations - Shutdown, drainage, zero-downtime
12-Factor Application
// 1. Codebase - One codebase tracked in version control
// ✅ Single git repository per service
// 2. Dependencies - Explicitly declare and isolate dependencies
// package.json or requirements.txt
// 3. Config - Store config in the environment
// src/config/index.ts
export const config = {
port: parseInt(process.env.PORT || '3000'),
databaseUrl: process.env.DATABASE_URL!,
redisUrl: process.env.REDIS_URL!,
logLevel: process.env.LOG_LEVEL || 'info',
// Validate required config
validate() {
const required = ['DATABASE_URL', 'REDIS_URL'];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}
},
};
// 4. Backing Services - Treat backing services as attached resources
// src/services/database.ts
import { Pool } from 'pg';
export function createPool(connectionString: string): Pool {
return new Pool({
connectionString,
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
}
// Connection URL can be swapped without code changes:
// DATABASE_URL=postgres://user:pass@localhost:5432/mydb (dev)
// DATABASE_URL=postgres://user:pass@prod-db:5432/mydb (prod)
// 5. Build, Release, Run - Strictly separate build and run stages
// Dockerfile
/*
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
*/
// 6. Processes - Execute the app as stateless processes
// ❌ Don't store session state in memory
// ✅ Use Redis for sessions
import session from 'express-session';
import RedisStore from 'connect-redis';
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET!,
resave: false,
saveUninitialized: false,
}));
// 7. Port Binding - Export services via port binding
// src/index.ts
const server = app.listen(config.port, () => {
console.log(`Server running on port ${config.port}`);
});
// 8. Concurrency - Scale out via the process model
// Kubernetes Deployment
/*
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3 # Horizontal scaling
selector:
matchLabels:
app: api
template:
spec:
containers:
- name: api
image: api:latest
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
*/
// 9. Disposability - Fast startup and graceful shutdown
// src/graceful-shutdown.ts
export function setupGracefulShutdown(server: Server, pool: Pool): void {
let isShuttingDown = false;
const shutdown = async (signal: string) => {
if (isShuttingDown) return;
isShuttingDown = true;
console.log(`Received ${signal}, starting graceful shutdown...`);
// Stop accepting new connections
server.close(() => {
console.log('HTTP server closed');
});
// Allow in-flight requests to complete (30s timeout)
await new Promise(resolve => setTimeout(resolve, 30000));
// Close database connections
await pool.end();
console.log('Database pool closed');
process.exit(0);
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
}
// 10. Dev/Prod Parity - Keep development, staging, and production similar
// docker-compose.yml for local development mirrors production
// 11. Logs - Treat logs as event streams
// src/logging/logger.ts
import pino from 'pino';
export const logger = pino({
level: config.logLevel,
formatters: {
level: (label) => ({ level: label }),
},
timestamp: pino.stdTimeFunctions.isoTime,
});
// Don't manage log files - write to stdout, let platform handle
// 12. Admin Processes - Run admin tasks as one-off processes
// package.json scripts
/*
{
"scripts": {
"migrate": "node dist/scripts/migrate.js",
"seed": "node dist/scripts/seed.js",
"console": "node --experimental-repl-await dist/scripts/console.js"
}
}
*/
Container Patterns
Sidecar Pattern
# Logging sidecar
apiVersion: v1
kind: Pod
metadata:
name: app-with-logging-sidecar
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: logs
mountPath: /var/log/app
- name: log-shipper
image: fluent-bit:latest
volumeMounts:
- name: logs
mountPath: /var/log/app
- name: fluent-bit-config
mountPath: /fluent-bit/etc/
volumes:
- name: logs
emptyDir: {}
- name: fluent-bit-config
configMap:
name: fluent-bit-config
Ambassador Pattern
# API gateway ambassador
apiVersion: v1
kind: Pod
metadata:
name: app-with-ambassador
spec:
containers:
- name: app
image: myapp:latest
ports:
- containerPort: 8080
- name: ambassador
image: envoyproxy/envoy:v1.25
ports:
- containerPort: 8443
volumeMounts:
- name: envoy-config
mountPath: /etc/envoy
volumes:
- name: envoy-config
configMap:
name: envoy-config
Health Checks
// src/health/checks.ts
import { Pool } from 'pg';
import Redis from 'ioredis';
interface HealthCheck {
name: string;
check: () => Promise<{ healthy: boolean; details?: unknown }>;
}
export class HealthChecker {
private checks: HealthCheck[] = [];
addCheck(check: HealthCheck): void {
this.checks.push(check);
}
async runAll(): Promise<{
status: 'healthy' | 'unhealthy';
checks: Record<string, { healthy: boolean; details?: unknown }>;
}> {
const results: Record<string, { healthy: boolean; details?: unknown }> = {};
let allHealthy = true;
for (const check of this.checks) {
try {
const result = await check.check();
results[check.name] = result;
if (!result.healthy) allHealthy = false;
} catch (error) {
results[check.name] = {
healthy: false,
details: error instanceof Error ? error.message : 'Unknown error',
};
allHealthy = false;
}
}
return {
status: allHealthy ? 'healthy' : 'unhealthy',
checks: results,
};
}
}
// Database health check
export function databaseCheck(pool: Pool): HealthCheck {
return {
name: 'database',
check: async () => {
const start = Date.now();
await pool.query('SELECT 1');
const latency = Date.now() - start;
return {
healthy: latency < 1000,
details: { latency_ms: latency },
};
},
};
}
// Redis health check
export function redisCheck(redis: Redis): HealthCheck {
return {
name: 'redis',
check: async () => {
const start = Date.now();
await redis.ping();
const latency = Date.now() - start;
return {
healthy: latency < 100,
details: { latency_ms: latency },
};
},
};
}
// Memory health check
export function memoryCheck(maxHeapMB: number): HealthCheck {
return {
name: 'memory',
check: async () => {
const used = process.memoryUsage().heapUsed / 1024 / 1024;
return {
healthy: used < maxHeapMB,
details: { heap_used_mb: Math.round(used), max_mb: maxHeapMB },
};
},
};
}
// Express routes
import { Router } from 'express';
export function healthRoutes(checker: HealthChecker): Router {
const router = Router();
// Liveness - is the app running?
router.get('/health/live', (req, res) => {
res.status(200).json({ status: 'alive' });
});
// Readiness - is the app ready to serve traffic?
router.get('/health/ready', async (req, res) => {
const result = await checker.runAll();
const status = result.status === 'healthy' ? 200 : 503;
res.status(status).json(result);
});
// Startup - has the app completed initialization?
router.get('/health/startup', async (req, res) => {
const result = await checker.runAll();
const status = result.status === 'healthy' ? 200 : 503;
res.status(status).json(result);
});
return router;
}
Kubernetes Probes
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
template:
spec:
containers:
- name: api
image: api:latest
ports:
- containerPort: 3000
# Startup probe - wait for app initialization
startupProbe:
httpGet:
path: /health/startup
port: 3000
failureThreshold: 30
periodSeconds: 10
# Liveness probe - restart if unhealthy
livenessProbe:
httpGet:
path: /health/live
port: 3000
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Readiness probe - remove from load balancer if not ready
readinessProbe:
httpGet:
path: /health/ready
port: 3000
initialDelaySeconds: 0
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Lifecycle hooks
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10"]
Auto-Scaling
# Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
# Custom metrics (requests per second)
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 1000
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
Usage Examples
Implement 12-Factor App
Apply cloud-native-patterns skill to refactor application to follow 12-factor methodology
Add Health Checks
Apply cloud-native-patterns skill to implement liveness, readiness, and startup probes
Configure Auto-Scaling
Apply cloud-native-patterns skill to set up HPA with CPU, memory, and custom metrics
Integration Points
- container-orchestration - Kubernetes deployment patterns
- infrastructure-as-code - Terraform/Helm configuration
- monitoring-observability - Metrics for auto-scaling
Success Output
When successful, this skill MUST output:
✅ SKILL COMPLETE: cloud-native-patterns
Completed:
- [x] 12-factor app principles applied (config in env, stateless processes)
- [x] Health checks implemented (liveness, readiness, startup probes)
- [x] Graceful shutdown configured (SIGTERM handling, connection drainage)
- [x] Auto-scaling configured (HPA with CPU/memory/custom metrics)
- [x] Container patterns implemented (sidecar/ambassador/adapter if applicable)
- [x] Kubernetes manifests validated and deployed
Outputs:
- config/index.ts (environment-based configuration)
- health/checks.ts (health check implementation)
- graceful-shutdown.ts (shutdown handler)
- k8s/deployment.yaml (Kubernetes deployment with probes)
- k8s/hpa.yaml (Horizontal Pod Autoscaler configuration)
Cloud-Native Compliance:
- 12-Factor Score: XX/12 factors implemented
- Health Checks: ✓ Liveness, ✓ Readiness, ✓ Startup
- Auto-Scaling: Min X replicas, Max X replicas
- Graceful Shutdown: XX second timeout
Completion Checklist
Before marking this skill as complete, verify:
- Configuration stored in environment variables (not hardcoded)
- All backing services treated as attached resources (swappable URLs)
- Build/release/run stages strictly separated (Docker multi-stage build)
- Application runs as stateless processes (no in-memory sessions)
- Services exported via port binding (not relying on runtime injection)
- Logs written to stdout (not managing log files)
- Health check endpoints implemented (/health/live, /health/ready, /health/startup)
- Graceful shutdown handler added (SIGTERM, SIGINT handling)
- Kubernetes probes configured (liveness, readiness, startup)
- Horizontal Pod Autoscaler configured with appropriate metrics
- Resource requests/limits defined (CPU, memory)
- Zero-downtime deployment tested (rolling updates without errors)
Failure Indicators
This skill has FAILED if:
- ❌ Configuration hardcoded in code (not environment variables)
- ❌ Application stores state in memory (sessions not externalized)
- ❌ No health check endpoints (Kubernetes cannot determine pod health)
- ❌ Graceful shutdown missing (connections dropped on SIGTERM)
- ❌ Pods crash on startup (startup probe not configured)
- ❌ Auto-scaling not working (HPA cannot read metrics)
- ❌ Zero-downtime deployment fails (service interruption during rollout)
- ❌ Resource limits not set (pod consumes all node resources)
When NOT to Use
Do NOT use this skill when:
- Building monolithic applications not intended for cloud deployment
- Legacy applications with hard dependencies on local filesystem/state
- Applications requiring persistent local storage (not backing services)
- Single-instance applications (no scaling requirements)
- Use monolith-architecture-patterns for traditional deployments
- Use serverless-patterns for event-driven, fully managed compute
Alternative skills for different deployment models:
- serverless-patterns - AWS Lambda, Cloud Functions, Azure Functions
- container-patterns - Docker without Kubernetes orchestration
- vm-deployment-patterns - Traditional VM-based deployments
Anti-Patterns (Avoid)
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Hardcoded configuration | Cannot deploy across environments | Use environment variables, ConfigMaps, Secrets |
| Storing state in memory | Horizontal scaling impossible | Externalize state to Redis, database, or cache |
| Managing log files | Container disk fills, logs lost | Write to stdout, let platform handle aggregation |
| No health checks | Kubernetes cannot detect failures | Implement /health/live and /health/ready endpoints |
| Abrupt shutdown | Connections dropped, data loss | Handle SIGTERM, drain connections gracefully |
| Fixed replica count | Cannot handle traffic spikes | Configure HPA with CPU/memory/custom metrics |
| No resource limits | Noisy neighbor, node exhaustion | Set CPU/memory requests and limits |
| Tight coupling to backing services | Cannot swap database/cache providers | Use connection strings from environment |
| Build artifacts in container | Large image size, slow deployments | Multi-stage Docker builds, separate build/run stages |
Principles
This skill embodies CODITECT foundational principles:
#2 First Principles Thinking
- 12-factor methodology based on cloud-native fundamentals
- Stateless processes enable horizontal scaling
- Treating logs as event streams (not files) aligns with distributed systems
#4 Separation of Concerns
- Build stage separate from run stage (Docker multi-stage builds)
- Configuration separate from code (environment variables)
- Admin tasks as one-off processes (migrations, seeds separate from app)
#5 Eliminate Ambiguity
- Clear health check semantics (liveness vs. readiness vs. startup)
- Explicit resource requests/limits (not relying on defaults)
- Documented graceful shutdown timeout (30s standard)
#7 Measurable Outcomes
- Auto-scaling metrics (CPU %, memory %, requests/second)
- Health check success rates (uptime monitoring)
- Zero-downtime deployment verification (no 5xx errors during rollout)
#10 Automation First
- Auto-scaling removes manual intervention (HPA)
- Kubernetes self-healing (liveness probe restarts unhealthy pods)
- Graceful shutdown automated (no manual connection drainage)
Full Principles: CODITECT-STANDARD-AUTOMATION.md
Version: 1.1.0 | Updated: 2026-01-04 | Author: CODITECT Team