A zero-shot time series forecaster built on Google's TimesFM foundation model. Feed it any univariate series (sales, sensor data, stock prices) and get point forecasts plus calibrated prediction intervals without training anything. The 200M parameter model needs about 4GB RAM and includes a mandatory preflight checker to verify your machine can handle it before loading. Supports basic forecasting and covariate-based forecasting (XReg) with exogenous variables. The honest take: this is genuinely useful if you need quick forecasts across many different series without tuning ARIMA parameters for each one, but you're still loading an 800MB model into memory. Works with context lengths up to 16,384 points and handles batch forecasting efficiently.
npx -y skills add google-research/timesfm --skill timesfm-forecasting --agent claude-codeInstalls into .claude/skills of the current project.
TimesFM (Time Series Foundation Model) is a pretrained decoder-only foundation model developed by Google Research for time-series forecasting. It works zero-shot — feed it any univariate time series and it returns point forecasts with calibrated quantile prediction intervals, no training required.
This skill includes a mandatory preflight system checker that verifies RAM, GPU memory, and disk space before the model is ever loaded so the agent never crashes the user's machine.
Key numbers: TimesFM 2.5 uses 200M parameters (~800 MB on disk, ~1.5 GB in RAM on CPU, ~1 GB VRAM on GPU). The archived v1/v2 500M-parameter model needs ~32 GB RAM. Always run the system checker first.
Use this skill when:
forecast_with_covariates() (TimesFM 2.5 + pip install timesfm[xreg])Do not use this skill when:
statsmodelsaeonstatsmodelsscikit-learnNote on Anomaly Detection: TimesFM does not have built-in anomaly detection, but you can use the quantile forecasts as prediction intervals — values outside the 90% CI (q10–q90) are statistically unusual. See
examples/anomaly-detection/for a full example.
CRITICAL — ALWAYS run the system checker before loading the model for the first time.
python scripts/check_system.py
This script checks:
timesfm and torch are installedNote: Model weights are NOT stored in this repository. TimesFM weights (~800 MB) download on-demand from HuggingFace on first use and cache in
~/.cache/huggingface/.
flowchart TD
start["🚀 Run check_system.py"] --> ram{"RAM ≥ 4 GB?"}
ram -->|"Yes"| gpu{"GPU available?"}
ram -->|"No (2-4 GB)"| warn_ram["⚠️ Warning: tight RAM<br/>CPU-only, small batches"]
ram -->|"No (< 2 GB)"| block["🛑 BLOCKED<br/>Insufficient memory"]
warn_ram --> disk
gpu -->|"CUDA / MPS"| vram{"VRAM ≥ 2 GB?"}
gpu -->|"CPU only"| cpu_ok["✅ CPU mode<br/>Slower but works"]
vram -->|"Yes"| gpu_ok["✅ GPU mode<br/>Fast inference"]
vram -->|"No"| cpu_ok
gpu_ok --> disk{"Disk ≥ 2 GB free?"}
cpu_ok --> disk
disk -->|"Yes"| ready["✅ READY<br/>Safe to load model"]
disk -->|"No"| block_disk["🛑 BLOCKED<br/>Need space for weights"]
Before loading your actual data, verify it will fit in memory:
# Quick estimate for your dataset
python scripts/check_system.py \
--num-series 1000 \
--context-length 1024 \
--horizon 24 \
--batch-size 32 \
--estimate-only
This will show you the estimated memory requirements and warn if your dataset is too large.
Memory Estimation Formula:
RAM ≈ 0.8 GB (model) + 0.5 GB (overhead) + (0.2 MB × num_series × context_length / 1000)
Example Outputs:
✅ Dataset Fits:
Total CPU memory: 2.34 GB
Total GPU memory: 2.15 GB
⚠️ Dataset Too Large:
Dataset requires ~12.5 GB RAM but system has 8.0 GB.
Try: context_length=512 or process in chunks of 50 series.
| Model | Parameters | RAM (CPU) | VRAM (GPU) | Disk | Context |
|---|---|---|---|---|---|
| TimesFM 2.5 (recommended) | 200M | ≥ 4 GB | ≥ 2 GB | ~800 MB | up to 16,384 |
| TimesFM 2.0 (archived) | 500M | ≥ 16 GB | ≥ 8 GB | ~2 GB | up to 2,048 |
| TimesFM 1.0 (archived) | 200M | ≥ 8 GB | ≥ 4 GB | ~800 MB | up to 2,048 |
Recommendation: Always use TimesFM 2.5 unless you have a specific reason to use an older checkpoint. It is smaller, faster, and supports 8× longer context.
python scripts/check_system.py
# Using uv (fast)
uv pip install timesfm[torch]
# Or using pip
pip install timesfm[torch]
# For JAX/Flax backend (faster on TPU/GPU)
uv pip install timesfm[flax]
# CUDA 12.1 (NVIDIA GPU)
pip install torch>=2.0.0 --index-url https://download.pytorch.org/whl/cu121
# CPU only
pip install torch>=2.0.0 --index-url https://download.pytorch.org/whl/cpu
# Apple Silicon (MPS)
pip install torch>=2.0.0 # MPS support is built-in
import torch, numpy as np, timesfm
torch.set_float32_matmul_precision("high")
model = timesfm.TimesFM_2p5_200M_torch.from_pretrained(
"google/timesfm-2.5-200m-pytorch"
)
model.compile(timesfm.ForecastConfig(
max_context=1024, max_horizon=256, normalize_inputs=True,
use_continuous_quantile_head=True, force_flip_invariance=True,
infer_is_positive=True, fix_quantile_crossing=True,
))
point, quantiles = model.forecast(horizon=24, inputs=[
np.sin(np.linspace(0, 20, 200)), # any 1-D array
])
# point.shape == (1, 24) — median forecast
# quantiles.shape == (1, 24, 10) — 10th–90th percentile bands
TimesFM 2.5+ supports exogenous variables through forecast_with_covariates().
Requires pip install timesfm[xreg].
point, quantiles = model.forecast_with_covariates(
inputs=inputs,
dynamic_numerical_covariates={"price": price_arrays},
dynamic_categorical_covariates={"holiday": holiday_arrays},
static_categorical_covariates={"region": region_labels},
xreg_mode="xreg + timesfm", # or "timesfm + xreg"
)
point, q = model.forecast(horizon=H, inputs=[values])
lower_90 = q[0, :, 1] # 10th percentile
upper_90 = q[0, :, 9] # 90th percentile
actual = test_values
anomalies = (actual < lower_90) | (actual > upper_90)
| Severity | Condition | Interpretation |
|---|---|---|
| Normal | Inside 80% CI | Expected behavior |
| Warning | Outside 80% CI | Unusual but possible |
| Critical | Outside 90% CI | Statistically rare (< 10% probability) |
See
examples/anomaly-detection/for a complete worked example with visualization.
TimesFM returns (point_forecast, quantile_forecast):
point_forecast: shape (batch, horizon) — the median (0.5 quantile)quantile_forecast: shape (batch, horizon, 10) — ten quantile slices:| Index | Quantile | Use |
|---|---|---|
| 0 | Mean | Average prediction |
| 1 | 0.1 | Lower bound of 80% PI |
| 2 | 0.2 | Lower bound of 60% PI |
| 5 | 0.5 | Median (= point_forecast) |
| 8 | 0.8 | Upper bound of 60% PI |
| 9 | 0.9 | Upper bound of 80% PI |
point, q = model.forecast(horizon=H, inputs=data)
lower_80 = q[:, :, 1] # 10th percentile
upper_80 = q[:, :, 9] # 90th percentile
median = q[:, :, 5]
All forecasting behavior is controlled by timesfm.ForecastConfig:
timesfm.ForecastConfig(
max_context=1024, # Max context window
max_horizon=256, # Max forecast horizon
normalize_inputs=True, # RECOMMENDED — prevents scale instability
per_core_batch_size=32, # Tune for memory
use_continuous_quantile_head=True, # Better quantile accuracy for long horizons
force_flip_invariance=True, # Ensures f(-x) = -f(x)
infer_is_positive=True, # Clamp forecasts ≥ 0 when all inputs > 0
fix_quantile_crossing=True, # Ensure q10 ≤ q20 ≤ ... ≤ q90
return_backcast=False, # Return backcast (for covariate workflows)
)
| Parameter | Default | When to Change |
|---|---|---|
max_context | 0 | Set to match your longest historical window |
normalize_inputs | False | Always set True |
use_continuous_quantile_head | False | Set True for calibrated PIs |
infer_is_positive | True | Set False for series that can be negative |
fix_quantile_crossing | False | Set True for monotonic quantiles |
See references/api_reference.md for the complete parameter reference.
import torch, numpy as np, pandas as pd, timesfm, matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
torch.set_float32_matmul_precision("high")
model = timesfm.TimesFM_2p5_200M_torch.from_pretrained(
"google/timesfm-2.5-200m-pytorch"
)
model.compile(timesfm.ForecastConfig(
max_context=512, max_horizon=52, normalize_inputs=True,
use_continuous_quantile_head=True, fix_quantile_crossing=True,
))
df = pd.read_csv("weekly_demand.csv", parse_dates=["week"])
values = df["demand"].values.astype(np.float32)
point, quantiles = model.forecast(horizon=52, inputs=[values])
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(values[-104:], label="Historical")
x_fc = range(len(values[-104:]), len(values[-104:]) + 52)
ax.plot(x_fc, point[0], label="Forecast", color="tab:orange")
ax.fill_between(x_fc, quantiles[0, :, 1], quantiles[0, :, 9],
alpha=0.2, color="tab:orange", label="80% PI")
ax.legend(); ax.set_title("52-Week Demand Forecast")
plt.tight_layout(); plt.savefig("forecast.png", dpi=150)
df = pd.read_csv("all_stores.csv", parse_dates=["date"], index_col="date")
inputs = [df[col].dropna().values.astype(np.float32) for col in df.columns]
point, quantiles = model.forecast(horizon=30, inputs=inputs)
import json
results = {col: {"forecast": point[i].tolist(),
"lower_80": quantiles[i, :, 1].tolist(),
"upper_80": quantiles[i, :, 9].tolist()}
for i, col in enumerate(df.columns)}
with open("batch_forecasts.json", "w") as f:
json.dump(results, f, indent=2)
H = 24
train, actual = values[:-H], values[-H:]
point, quantiles = model.forecast(horizon=H, inputs=[train])
pred = point[0]
mae = np.mean(np.abs(actual - pred))
rmse = np.sqrt(np.mean((actual - pred) ** 2))
mape = np.mean(np.abs((actual - pred) / actual)) * 100
coverage = np.mean((actual >= quantiles[0, :, 1]) & (actual <= quantiles[0, :, 9])) * 100
print(f"MAE: {mae:.2f} | RMSE: {rmse:.2f} | MAPE: {mape:.1f}% | 80% PI Coverage: {coverage:.1f}%")
# Always set on Ampere+ GPUs (A100, RTX 3090+)
torch.set_float32_matmul_precision("high")
# Batch size guidelines:
# GPU 8 GB VRAM: per_core_batch_size=64
# GPU 16 GB VRAM: per_core_batch_size=128
# CPU 8 GB RAM: per_core_batch_size=8
# CPU 16 GB RAM: per_core_batch_size=32
# Memory-constrained: process in chunks
CHUNK = 50
results = []
for i in range(0, len(inputs), CHUNK):
p, q = model.forecast(horizon=H, inputs=inputs[i:i+CHUNK])
results.append((p, q))
scripts/check_system.pyMandatory preflight checker — run before first model load. Now includes dataset-aware memory estimation to prevent OOM errors before loading your data.
# Basic system check
python scripts/check_system.py
# Check if your specific dataset will fit
python scripts/check_system.py \
--num-series 1000 \
--context-length 1024 \
--horizon 24 \
--batch-size 32
# Quick memory estimate without system checks
python scripts/check_system.py \
--num-series 5000 \
--context-length 2048 \
--estimate-only
What it checks:
timesfm and torch are installedscripts/forecast_csv.pyEnd-to-end CSV forecasting CLI.
python scripts/forecast_csv.py input.csv \
--horizon 24 \
--date-col date \
--value-cols sales,revenue \
--output forecasts.csv
| File | Contents |
|---|---|
references/system_requirements.md | Hardware tiers, GPU/CPU selection, memory estimation |
references/api_reference.md | Full ForecastConfig docs, output shapes, model options |
references/data_preparation.md | Input formats, NaN handling, CSV loading, covariate setup |
| Example | Directory | What It Demonstrates |
|---|---|---|
| Global Temperature Forecast | examples/global-temperature/ | Basic model.forecast(), CSV → PNG → GIF pipeline |
| Anomaly Detection | examples/anomaly-detection/ | Two-phase detrend + Z-score + quantile PI, 2-panel viz |
| Covariates (XReg) | examples/covariates-forecasting/ | forecast_with_covariates(), 2×2 shared-axis viz |
# Run all three examples:
cd examples/global-temperature && python run_forecast.py && python visualize_forecast.py
cd examples/anomaly-detection && python detect_anomalies.py
cd examples/covariates-forecasting && python demo_covariates.py
| Example | Key output files | Acceptance criteria |
|---|---|---|
| global-temperature | output/forecast_output.json, output/forecast_visualization.png | point_forecast has 12 values; PNG shows context + forecast + PI bands |
| anomaly-detection | output/anomaly_detection.json, output/anomaly_detection.png | Sep 2023 flagged CRITICAL (z ≥ 3.0) |
| covariates-forecasting | output/sales_with_covariates.csv, output/covariates_data.png | 108 rows (3 stores × 36 weeks); distinct price arrays per store |
| Version | Params | Context | Status | HuggingFace checkpoint |
|---|---|---|---|---|
| 2.5 | 200M | 16,384 | Latest | google/timesfm-2.5-200m-pytorch |
| 2.0 | 500M | 2,048 | Archived | google/timesfm-2.0-500m-pytorch |
| 1.0 | 200M | 2,048 | Archived | google/timesfm-1.0-200m-pytorch |
freq=[0] for monthly dataRun after every TimesFM task before declaring success:
point_fc is (n_series, horizon), quant_fc is (n_series, horizon, 10)freq=[0] for monthly. TimesFM 2.5: omit.np.isnan(point_fc).any() must be False.sharex=True.matplotlib.use('Agg') — before any pyplot import when running headless.infer_is_positive — set False for temperature, financial returns, negatives.Quantile index off-by-one — quant_fc[..., 0] is the mean, not q0. q10 = index 1, q90 = index 9. Define: IDX_Q10, IDX_Q90 = 1, 9.
Variable shadowing in covariate loops — don't use the outer loop variable as a comprehension variable when building per-series covariate dicts.
Wrong CSV column name — global-temperature CSV uses anomaly_c, not anomaly. Print df.columns first.
TimesFM 2.5 required for forecast_with_covariates() — TimesFM 1.0 does NOT have this method.
Future covariates must span the full horizon — dynamic covariates need values for BOTH context AND forecast windows.
Context anomaly detection uses residuals — detrend first, then Z-score. Raw Z-scores mislead on trending data.
# Anomaly detection regression:
python -c "
import json
d = json.load(open('examples/anomaly-detection/output/anomaly_detection.json'))
assert d['context_summary']['critical'] >= 1, 'Sep 2023 must be CRITICAL'
print('Anomaly detection: PASS')"
# Covariates regression:
python -c "
import pandas as pd
df = pd.read_csv('examples/covariates-forecasting/output/sales_with_covariates.csv')
assert len(df) == 108, f'Expected 108 rows, got {len(df)}'
print('Covariates: PASS')"
sickn33/antigravity-awesome-skills