writing-skills
writing-skills
Use when creating new skills, editing existing skills, or verifying skills work before deployment
enterprise-capacity-planningUse this skill when forecasting infrastructure capacity needs, calculating headroom, sizing for growth, modeling peak vs sustained load, planning procurement lead times for bare-metal/colo, computing cost-per-unit-of-work, and planning multi-quarter capacity roadmap. This skill enforces: usage baseline + p99 + peak measurement, growth modeling (linear/expon…
Independent GitHub snapshot · Automated classification · Original documentation governs
name: enterprise-capacity-planning description: > Use this skill when forecasting infrastructure capacity needs, calculating headroom, sizing for growth, modeling peak vs sustained load, planning procurement lead times for bare-metal/colo, computing cost-per-unit-of-work, and planning multi-quarter capacity roadmap. This skill enforces: usage baseline
Forecast capacity demand 1-4 quarters ahead, size infrastructure with the right headroom for each service tier, and trigger procurement with enough lead time for bare-metal/colo. Translate business growth assumptions into compute/storage/network units and money.
A five-phase framework for systematic capacity planning:
Phase 1 - Profile: Establish baseline usage for every resource across all services. Collect median, p95, p99, and peak values over a rolling 90-day window. Segment by service tier, region, and deployment environment.
Phase 2 - Review: Analyze historical trends and identify growth patterns. Correlate usage spikes with business events (product launches, marketing campaigns, seasonal peaks). Document assumptions about future growth drivers.
Phase 3 - Estimate: Apply growth models to each resource. Run linear, exponential, seasonal, and event-driven projections. Assign confidence intervals based on historical accuracy and business certainty.
Phase 4 - Determine: Calculate required capacity including headroom by tier. Account for failure tolerance, maintenance windows, and deployment overhead. Generate procurement schedule aligned with lead times.
Phase 5 - Iterate: Establish quarterly review cadence. Compare forecast vs actual monthly. Adjust models based on accuracy. Re-forecast immediately after any business inflection.
Top-Down: Start with business growth assumptions (revenue targets, user growth, transaction volume). Apply historical ratios (requests per user, storage per user, compute per transaction). Best for new products without usage history. Risk: may over-provision if ratios shift.
Bottom-Up: Start with per-service usage metrics. Aggregate to total capacity. Best for mature services with stable growth patterns. Risk: may miss business-driven inflection points.
Recommended: Use both, reconcile differences. Top-down sets the ceiling, bottom-up validates the floor.
Compute: Measure in vCPU-hours or pod-seconds. Track utilization at node and container level. Plan for bin-packing overhead (Kubernetes scheduler efficiency). Account for cluster headroom (node failure buffer).
Memory: Measure RSS vs limit. Track page cache and buffer cache. Plan for GC overhead in managed runtimes. Account for OOM-killer safety margin (10-15%).
Storage: Measure logical usage, replication factor, backup copies, retention growth. Plan for compaction/defragmentation overhead. Account for snapshot and restore scratch space.
Network: Measure ingress/egress, p95 bandwidth, connection count, packet rate. Plan for spike buffers and CDN cache-miss scenarios. Account for cross-region replication traffic.
Is historical data available for 12+ months?
├── Yes → Can you identify a seasonal pattern?
│ ├── Yes → Use SEASONAL model
│ │ Example: ecommerce, tax season, sports
│ └── No → Is growth rate accelerating?
│ ├── Yes → Is there a known ceiling?
│ │ ├── Yes → Use LOGISTIC (S-curve)
│ │ └── No → Use EXPONENTIAL (viral, high-growth)
│ └── No → Use LINEAR (mature, B2B SaaS)
└── No → Do you have business targets?
├── Yes → Use TOP-DOWN from business targets
└── No → Use EVENT-DRIVEN (launch-based)
| Signal | Score | Action |
|---|---|---|
| R-squared > 0.95, MAPE < 5% | High | Use as primary |
| R-squared > 0.85, MAPE < 15% | Medium | Use with buffer |
| R-squared < 0.85, MAPE > 15% | Low | Investigate drivers |
| No fit | None | Use worst-case only |
| Resource | Base Factor | Replication | Backup | Total Multiplier |
|---|---|---|---|---|
| Database storage | 1x (data) | 2x (RF=3) | 1x (snapshot) | 4x |
| Object storage | 1x (data) | 2x (replication) | 1x (backup) | 4x |
| Compute (K8s) | 1x (requests) | 1.3x (scheduler overhead) | 0 | 1.3x |
| Network egress | 1x (user traffic) | 0.3x (CDN miss) | 0 | 1.3x |
Exact user phrases: "capacity planning", "headroom", "forecast", "demand model", "growth model", "sizing", "right-sizing", "autoscale limits", "procurement lead time", "compute budget", "storage projection", "peak-to-average ratio", "burst capacity", "quarterly capacity review".
Capacity plan with baseline, forecast, headroom, procurement schedule, autoscale boundaries.
Service Current Q+1 Q+2 Q+3 Q+4 Action
api-rps 12k 18k 27k 35k 45k scale autoscale max to 60k by Q+1
db-storage-TB 4.2 6.0 8.5 12.0 17.0 order 20TB tier by Q+1 (lead 8w)
egress-Gbps 1.5 2.2 3.0 4.5 6.5 upgrade transit contract Q+2
No preamble. No postamble. No explanations.
300 lines.
For each resource per service:
median 50th percentile of 30-day rolling window
p95 95th percentile (alert threshold sizing)
p99 99th percentile (peak handling)
peak max observed in 90-day window
peak/avg peak-to-average ratio (how spiky)
Collect per deployment group (region, AZ, cluster). Aggregate correctly: p95 of total is not sum of per-node p95. Use additive percentiles via HDR Histogram or DDSketch for accurate aggregation.
Measure request latency impact on resource usage. A latency spike can masquerade as a capacity shortage (queuing builds, utilization rises, but work done per second drops).
Linear predictable B2B SaaS, mature product
Exponential high-growth startup, viral product
Seasonal ecommerce (Q4 spike 3-5x), tax season, sport events
Event-driven product launch, marketing campaign, acquired customer
Step contract-bound enterprise customer (known onboarding date)
Formulas:
Linear: f(t) = a + b*t
Exponential: f(t) = a * (1+r)^t
Seasonal: f(t) = base(t) * season_factor(month)
Validate model fit using:
When models disagree, use the more conservative projection for Tier-1 services and the more optimistic for Tier-4.
Tier-1 (99.99%) 100% headroom over forecast peak (2x peak capacity)
Tier-2 (99.95%) 50% headroom over forecast peak (1.5x)
Tier-3 (99.9%) 25% headroom (1.25x)
Tier-4 (99%) 10% headroom (1.1x)
Reason: spike + node failure + maintenance window must all fit within remaining capacity.
Required capacity = forecast_peak x (1 + headroom%) x (N / (N - failures_tolerated))
where N = total nodes, failures_tolerated = nodes that can fail in window
Headroom decomposition:
30% traffic spike buffer
30% node failure tolerance (N+1 for 3+ nodes)
20% deployment surge (rolling update doubles resource need)
20% measurement error margin
Resource Lead time Order trigger
Cloud autoscale seconds-minutes raise max limit when current/limit > 60%
Cloud reserved cap 1-2 weeks order 1mo ahead for steep ramps
Colo rack + power 4-8 weeks order when 6mo forecast crosses limit
Bare-metal server 8-16 weeks order when 9mo forecast crosses limit
Transit / cross-connect 6-12 weeks order when bandwidth p95 > 50% of contract
Submarine fiber (rare) 12+ months strategic, not capacity-planning
For hardware procurement: factor in burn-in time (2 weeks for servers), staging/configuration (1 week), deployment window scheduling (1-2 weeks). Add these to lead time before computing order trigger.
# HorizontalPodAutoscaler - min/max set above forecast headroom
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
minReplicas: 6 # = base load / per-pod capacity
maxReplicas: 60 # = forecast peak x headroom / per-pod
metrics:
- type: Resource
resource:
name: cpu
target: {type: Utilization, averageUtilization: 60} # leave 40% for spike
behavior:
scaleUp: {stabilizationWindowSeconds: 0, policies: [{type: Percent, value: 100, periodSeconds: 60}]}
scaleDown: {stabilizationWindowSeconds: 300, policies: [{type: Percent, value: 25, periodSeconds: 60}]}
For stateful workloads: use maxReplicas as a hard safety limit. Set cluster-autoscaler limits separately. For serverless: configure provisioned concurrency and account for cold-start overhead in peak capacity.
Document the bottleneck resource for each scenario. Run chaos engineering experiments to validate.
$ / 1k requests
$ / GB stored
$ / GB egress
$ / active user / month
$ / transaction
Track these per quarter. If they trend up, find inefficiency. If down, reinvest in features.
Normalize cost-per-unit across deployment environments. Account for reserved instance discounts, committed use discounts, and spot pricing. Publish unit costs per service tier.
Q-end -2w: pull metrics, draft forecast
Q-end -1w: service owners review numbers
Q-end: finalize plan, file procurement orders
Q+1 -2w: place orders for Q+1 capacity
Q+1 day 1: autoscale max raised
Monthly pulse check: compare actual vs forecast for each resource. If variance exceeds 20%, trigger ad-hoc review. Document model accuracy in a running scorecard.
Pitfall 1: Measuring peak from average-only metrics. Average hides spikes. A service running at 40% average CPU but spiking to 95% every 5 minutes needs more headroom than one running at 60% flat.
Pitfall 2: Ignoring the noise floor. Low-utilization services show high variability in percentage terms. Don't over-provision for statistical noise. Set a minimum floor capacity.
Pitfall 3: Procurement for peak without considering elasticity. If your cloud autoscale can handle the spike in seconds, you don't need to provision for peak 100% of the time. Use burst capacity for spikes, base capacity for steady state.
Pitfall 4: Uniform headroom across all tiers. Tier-1 deserves 100% headroom. Tier-4 can run at 80% utilization. Treating them the same wastes budget or introduces risk.
Pitfall 5: Forecast without confidence intervals. A single number forecast is always wrong. Provide best-case, expected-case, worst-case. Use the worst case for procurement decisions.
Pitfall 6: Static models that don't adapt. A linear model fitted to last year's data will miss this year's hockey-stick growth. Re-fit models each quarter. Use ensemble methods for non-obvious patterns.
Pitfall 7: Storage growth modeled as linear when it compounds. Storage often exhibits exponential growth (user uploads, logs, event streams). Model it as compound growth with a retention-based decay.
Pitfall 8: Ignoring dependency cascades. Doubling API traffic may increase DB connections 10x due to N+1 queries. Model capacity at dependency boundaries, not just entry points.
Practice 1: Instrument everything in standard units. Use milli-cores for CPU, bytes for memory, IOPS for storage. Avoid percentage utilization as the primary metric - it varies by instance type.
Practice 2: Maintain a capacity budget API. Each team submits their forecast quarterly. The API aggregates, validates, and flags outliers. Automate the data collection, not the analysis.
Practice 3: Right-size autoscale policies before adding hardware. The cheapest capacity improvement is tuning scale-up thresholds, stabilization windows, and pod resource requests.
Practice 4: Over-provision cluster headroom, not instance size. A cluster with N+2 buffer can absorb a node failure gracefully. A single giant instance failure takes out 25% of capacity.
Practice 5: Benchmark perf-per-cost curves. A 32-vCPU instance may cost 2x a 16-vCPU but deliver 2.5x throughput for parallel workloads. Benchmark your workload, don't trust published specs.
Practice 6: Build a capacity dashboard with three views. Executive: total cost and headroom by tier. Engineering: per-service forecast vs actual. Procurement: order pipeline and lead times.
Practice 7: Integrate capacity data with financial planning. Cost-per-unit trends feed the budget process. Capacity investment requests must show ROI in terms of revenue support or cost avoidance.
# Capacity Plan: {Service} - {Quarter} {Year}
## Baseline (Last 90 Days)
- Average RPS: {value}
- P99 RPS: {value}
- Peak RPS: {value}
- Peak-to-Average Ratio: {value}
## Growth Model
- Selected Model: {linear/exponential/seasonal}
- Model Fit (R-squared): {value}
- Quarterly Growth Rate: {value}%
## Forecast
| Period | Expected | Pessimistic | Optimistic |
|--------|----------|-------------|------------|
| Q+1 | {value} | {value} | {value} |
| Q+2 | {value} | {value} | {value} |
| Q+3 | {value} | {value} | {value} |
| Q+4 | {value} | {value} | {value} |
## Headroom Calculation
- Service Tier: {Tier}
- Headroom Required: {value}%
- Required Capacity: {value}
## Procurement Plan
| Resource | Lead Time | Order Date | Delivery Date |
|----------|-----------|------------|---------------|
| {item} | {weeks} | {date} | {date} |
## Autoscale Configuration
- Min Replicas: {value}
- Max Replicas: {value}
- Target Utilization: {value}%
- Scale-Up Policy: {policy}
- Scale-Down Policy: {policy}
A major e-commerce platform with steady 20% QoQ growth faced Q4 spikes of 5x baseline. Using seasonal growth models, they established dynamic autoscale limits that expanded 2 hours before known flash sales. Pre-warmed 30% of peak capacity using spot instances. Result: zero scale-related incidents during Black Friday, 40% cost savings vs always-provisioned peak capacity.
A fintech startup modeled storage growth linearly while actual usage compounded at 15% month-over-month due to transaction history retention. At month 18, storage costs exceeded revenue. Applying exponential growth models with retention-based decay curves, they projected the crisis 6 months in advance. Implemented tiered storage (hot/warm/cold) with automated lifecycle policies. Result: storage cost growth reduced from +15% to +3% monthly.
An enterprise migrating from colo to cloud discovered that their 16-week bare-metal lead time was longer than their forecast horizon for a fast-growing service. They implemented a hybrid approach: cloud autoscale absorbed growth bursts while bare-metal orders were placed using 12-month forecasts with 50% headroom. Established a quarterly review cadence. Result: zero capacity-related outages during migration, 30% reduction in total infrastructure cost.
import numpy as np
from datetime import datetime, timedelta
class CapacityForecast:
def __init__(self, historical: list[float], timestamps: list[datetime]):
self.historical = np.array(historical)
self.timestamps = timestamps
def linear_model(self, quarters_ahead: int) -> float:
x = np.arange(len(self.historical))
coeffs = np.polyfit(x, self.historical, 1)
last_x = len(self.historical) - 1
return np.polyval(coeffs, last_x + quarters_ahead * 90)
def seasonal_multiplier(self, month: int) -> float:
# Compute seasonal factor from historical data
monthly_avgs = {}
for val, ts in zip(self.historical, self.timestamps):
monthly_avgs.setdefault(ts.month, []).append(val)
avg_all = np.mean(self.historical)
month_avg = np.mean(monthly_avgs.get(month, [avg_all]))
return month_avg / avg_all
def forecast_with_headroom(self, quarters_ahead: int, tier: str) -> dict:
base = self.linear_model(quarters_ahead)
seasonal = base * self.seasonal_multiplier((datetime.now().month + quarters_ahead * 3) % 12 or 12)
headroom = {"tier1": 1.0, "tier2": 0.5, "tier3": 0.25, "tier4": 0.1}
required = seasonal * (1 + headroom.get(tier, 0.25))
return {"forecast": round(seasonal), "required": round(required), "headroom_pct": headroom.get(tier, 0.25) * 100}
// terraform/hpa_template.tf
resource "kubernetes_horizontal_pod_autoscaler_v2" "service_hpa" {
metadata { name = "${var.service_name}-hpa" }
spec {
min_replicas = var.min_replicas
max_replicas = var.max_replicas
metric {
type = "Resource"
resource {
name = "cpu"
target { type = "Utilization" average_utilization = var.target_cpu }
}
}
behavior {
scale_down {
stabilization_window_seconds = 300
policy { type = "Percent" value = 25 period_seconds = 60 }
}
scale_up {
stabilization_window_seconds = 0
policy { type = "Percent" value = 100 period_seconds = 60 }
}
}
}
}
| Anti-Pattern | Why It Hurts | Fix |
|---|---|---|
| Forecasting from average only | Spike hidden. 40% avg CPU + 95% spikes = overloaded. | Track p95 and peak alongside average. |
| Uniform headroom across tiers | Tier-4 over-provisioned. Tier-1 under-provisioned. | 100% headroom for Tier-1, 10% for Tier-4. |
| Static model never re-fit | Linear model misses hockey-stick growth. | Re-fit quarterly. Immediate re-forecast on inflection. |
| Storage modeled as linear | Compounds at 15% mo/mo but model assumes 5%. | Exponential or logistic model. Retention-based decay. |
| Ignoring dependency cascade | 2x API traffic = 10x DB connections (N+1). | Model capacity at dependency boundaries, not entry. |
| No what-if scenarios | 2x traffic surprises. First clue is outage. | Document bottleneck for 2x, 0.5x, region-loss scenarios. |