# Project export: CarbonShift

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2026
- Tagline: CarbonShift: Grid-aware AI training that dynamically adjusts GPU power based on real-time electricity prices and carbon intensity. 37% cost savings, 43% emission reduction, zero accuracy loss.
- Devpost: https://devpost.com/software/carbonshift
- GitHub: https://github.com/ayushgawai/carbonshift
- Team: 2 GitHub contributor(s) — ayushgawai (4 commits), frejya123 (1 commits)

## Devpost submission (written by the team)

### Overview

💡

### Inspiration

The idea for CarbonShift hit us when we looked at two simple charts side-by-side. On the left: AI compute demand, which is growing exponentially and running 24/7. On the right: The energy grid, which fluctuates wildly in price and cleanliness throughout the day. We realized that training a model at 4 PM (when the grid is dirty and expensive) versus 3 AM (when wind energy is abundant and free) yields the exact same model—but with vastly different environmental and financial costs. A single training run can emit hundreds of tons of CO₂, yet our GPU clusters are completely blind to the world outside the data center. We asked ourselves: What if our AI models knew when the sun was shining? 💻

### What it does

CarbonShift is an intelligent orchestration layer that sits between your AI training workload and the power grid. It monitors real-time electricity prices and carbon intensity, then dynamically adjusts GPU power consumption to train during optimal conditions. Green State (Clean/Cheap): The system boosts GPU power to maximum (250W) to speed up training. Red State (Dirty/Expensive): The system pauses training or throttles power down (100W) to wait for better conditions. It turns AI training from a dumb, constant load into an intelligent, grid-responsive asset. ⚙️

### How we built it

1. The Architecture We built CarbonShift as a modular system with a "Brain" (the decision engine) and a "Body" (the training agents). The Stack: Hardware: NVIDIA A100 GPUs (via Brev.dev) Backend: Python, FastAPI AI Agents: Fetch.ai uAgents Intelligence: OpenAI GPT-4 & Anthropic Claude 3.5 Sonnet Grid Data: CAISO API (Prices) & WattTime (Carbon) 2. The "Eco-Pulse" Algorithm The core logic runs every 60 seconds. We developed a state-machine algorithm that balances training velocity against environmental impact. Mathematical logic for the decision thresholds: $$Score_{grid} = \alpha \cdot P_{norm} + \beta \cdot C_{norm}$$ Where $P$ is price and $C$ is carbon intensity. When the score exceeds our critical threshold, the system triggers a Hardware Interrupt. We interact directly with the GPU hardware using nvidia-ml-py to physically cap the wattage: 3. Autonomous Agents (Fetch.ai) Instead of a central server telling every GPU what to do, we wrapped our training jobs in Fetch.ai Agents. This allows for decentralized coordination. Each GPU acts as an independent agent that can "negotiate" with the grid, ensuring we don't accidentally spike demand when resuming. 4. LLM Prediction Layer We didn't just want to react to the present; we wanted to predict the future. GPT-4 analyzes the last 24 hours of grid data to forecast price spikes over the next 4 hours. Claude 3.5 Sonnet acts as the "Explainability Engine," generating human-readable summaries of why the training was paused (e.g., "Training paused due to a sudden spike in coal generation in the CAISO region."). 🚧

### Challenges we ran into

The "Zombie" GPU Process: Pausing a training loop without killing the process is incredibly difficult. We had to engineer a custom PyTorch wrapper that could "sleep" the training loop while keeping the model loaded in VRAM, allowing for instant resumption without reloading 80GB of parameters. Grid Data is Messy: Real-time energy data is noisy. The CAISO API would frequently return null values or XML errors. We had to build a robust data cleaning pipeline with exponential backoff and linear interpolation to fill in the gaps. Hardware Limits: We discovered that not all GPUs allow dynamic power limiting via software. We had to add hardware capability detection to prevent the system from crashing on unsupported cards. 🏅

### Accomplishments we're proud of

Real Impact: In our test run training ResNet-18, we achieved a 37% cost reduction and a 43% reduction in carbon footprint compared to a standard continuous run. Hardware Control: Successfully controlling the physical power draw of an NVIDIA A100 via code felt like magic. Watching the wattage drop on our dashboard in real-time as prices spiked was a huge win. Seamlessness: The user doesn't need to change their PyTorch code significantly. Our wrapper handles the complexity. 🧠

### What we learned

Energy is Volatile: We assumed electricity prices were somewhat stable. We were wrong. They can jump from $20/MWh to $150/MWh in minutes. Latency Matters: The grid changes fast. A 5-minute delay in data processing can mean the difference between training on wind vs. coal. AI for AI: Using LLMs to optimize the training of other AI models creates a fascinating feedback loop. 🔮

### What's next

Multi-Region Hopping: Allowing agents to move training jobs geographically (e.g., move the job from Virginia to Oregon if the wind is blowing in the West). Spot Instance Integration: Automatically bidding on spot instances when prices drop. LLM Fine-tuning: Scaling up from ResNet to Llama-3 training runs where the energy savings would be in the thousands of dollars. Built With: python pytorch fastapi fetch.ai openai anthropic react vite nvidia-ml-py

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 78 recognized source files, 373 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- Hugging Face (technology) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- PyTorch (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (87 of 87)

```
.gitignore
backend/.env.template
backend/agentverse_agent.py
backend/api/main.py
backend/backfill_history.py
backend/BREV_DEPLOYMENT.md
backend/config.py
backend/core/caiso_api.py
backend/core/decision_engine.py
backend/core/energy_monitor.py
backend/core/fetchai_agent.py
backend/core/gpu_controller.py
backend/core/llm_intelligence.py
backend/core/metrics_history.py
backend/demo_workload/training_engine.py
backend/deploy_to_brev.sh
backend/final_test.sh
backend/PROJECT_STATUS.md
backend/quick_train.py
backend/README.md
backend/requirements.txt
backend/setup_brev_env.sh
backend/start.sh
backend/test_agent_communication.py
backend/test_anthropic.py
backend/test_endpoints.sh
backend/test_fetchai_real.py
backend/test_integration.sh
backend/test_openai.py
backend/TEST_RESULTS.md
BUILD_COMPLETE.md
carbonshift-gpu-details.txt
check_history.sh
DEPLOY_STEPS.md
deploy_to_brev_full.sh
DEPLOY_TO_BREV.md
deploy-to-brev.sh
DEPLOYMENT_READY.md
FEATURES_COMPLETE.md
FRONTEND_INTEGRATION.md
frontend/.gitignore
frontend/eslint.config.js
frontend/index.html
frontend/package.json
frontend/postcss.config.js
frontend/README.md
frontend/src/App.tsx
frontend/src/components/AnimatedValue.tsx
frontend/src/components/AuraOverlay.tsx
frontend/src/components/DomainFilter.tsx
frontend/src/components/EnergyPriceChart.tsx
frontend/src/components/EnergySourceMix.tsx
frontend/src/components/ESGTargets.tsx
frontend/src/components/GlitchOverlay.tsx
frontend/src/components/GpuHeatBar.tsx
frontend/src/components/GPUPowerChart.tsx
frontend/src/components/GridBackground.tsx
frontend/src/components/Header.tsx
frontend/src/components/HeroIntro.tsx
frontend/src/components/HudRing.tsx
frontend/src/components/ImpactMetrics.tsx
frontend/src/components/MarketInsights.tsx
frontend/src/components/MetricCard.tsx
frontend/src/components/PeaksTimeline.tsx
frontend/src/components/ProfitChart.tsx
frontend/src/components/SystemLogs.tsx
frontend/src/components/TrainingControl.tsx
frontend/src/components/VictoryOverlay.tsx
frontend/src/hooks/useTrainingAPI.ts
frontend/src/hooks/useWebSocket.ts
frontend/src/index.css
frontend/src/main.tsx
frontend/src/types/index.ts
frontend/src/utils/formatters.ts
frontend/src/utils/prediction.ts
frontend/tailwind.config.js
frontend/tsconfig.app.json
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/vite.config.ts
GPU_DEPLOYMENT.md
QUICKSTART.md
restart_backend.sh
restart_with_history.sh
start_complete.sh
test_connection.sh
verify_running.sh
```

### Dependencies

- backend/requirements.txt: accelerate@==0.25.0, anthropic@>=0.18.0, asyncio@==3.4.3, datasets@==2.16.0, fastapi@>=0.109.0, httpx@>=0.26.0, loguru@==0.7.2, nvidia-ml-py@>=11.5.0, openai@>=1.10.0, Pillow@==10.2.0, pydantic@>=2.5.0, python-dateutil@==2.8.2, python-dotenv@==1.0.0, python-multipart@>=0.0.9, reportlab@==4.0.8, torch@>=2.1.0, torchvision@>=0.16.0, transformers@==4.36.0, uagents@>=0.20.0, uvicorn[standard]@>=0.27.0, websockets@>=12.0
- frontend/package.json: @eslint/js@^9.39.1, @types/canvas-confetti@^1.9.0, @types/node@^24.10.1, @types/react@^19.2.7, @types/react-dom@^19.2.3, @vitejs/plugin-react@^5.1.1, autoprefixer@^10.4.24, axios@^1.13.5, canvas-confetti@^1.9.4, eslint@^9.39.1, eslint-plugin-react-hooks@^7.0.1, eslint-plugin-react-refresh@^0.4.24, framer-motion@^12.34.0, globals@^16.5.0, lucide-react@^0.564.0, postcss@^8.5.6, react@^19.2.0, react-dom@^19.2.0, recharts@^3.7.0, tailwindcss@^3.4.19, typescript@~5.9.3, typescript-eslint@^8.48.0, vite@^7.3.1

### Recent commits (newest first)

- added architecture diagram
- fixes
- integration done
- front end fınal changes
- Final Backend Changes

## Key source files (fetched from GitHub, selected and truncated for size)

### FRONTEND_INTEGRATION.md

```markdown
# Frontend Integration - Complete ✅

## API Format Alignment

Updated backend `collect_metrics()` to match frontend expectations exactly:

### Frontend Expected Fields (TypeScript)
```typescript
interface DashboardData {
  timestamp: string;
  electricity_price: number;           // $/MWh
  carbon_intensity: number;            // gCO2/kWh
  gpu_power_watts: number;             // W
  gpu_power_limit: number;             // W
  training_status: 'running' | 'paused' | 'idle' | 'completed';
  total_cost_saved: number;            // $
  total_carbon_saved: number;          // kg CO2
  training_progress: number;           // 0-100%
  current_epoch: number;
  total_epochs: number;
  peaks_avoided: number;
}
```

### Backend Response (Python)
```python
{
    "timestamp": "2026-02-15T05:10:41.468485",
    "electricity_price": 45.0,
    "carbon_intensity": 350.0,
    "gpu_power_watts": 50.0,
    "gpu_power_limit": 200,
    "training_status": "idle",
    "training_progress": 0.0,
    "current_epoch": 0,
    "total_epochs": 10,
    "total_cost_saved": 0.0,
    "total_carbon_saved": 0.0,
    "peaks_avoided": 0,
    # Additional backend fields
    "orchestrator_state": "NORMAL",
    "orchestrator_action": "CONTINUE",
    "orchestrator_reason": "▶️ NORMAL: Price $45.0/MWh...",
    "gpu_temperature_c": 0,
    "gpu_utilization_percent": 0,
    "training_loss": 0.0
}
```

## Integration Test Results

✅ **All Required Fields Present**
- timestamp ✅
- electricity_price ✅
- carbon_intensity ✅
- gpu_power_watts ✅
- gpu_power_limit ✅
- training_status ✅
- training_progress ✅
- current_epoch ✅
- total_epochs ✅
- total_cost_saved ✅
- total_carbon_saved ✅
- peaks_avoided ✅

## API Endpoints

### WebSocket (Real-time)
```
ws://localhost:8000/ws
```
Broadcasts updates every 2 seconds

### REST Endpoints
```
GET /api/status - Current system status
GET /api/history - Historical metrics (24h)
GET /api/gpu - GPU details
GET /api/predict - GPT-4o price prediction
GET /api/report - Claude sustainability report
GET /api/fetchai/status - Agent status
POST /api/fetchai/coordinate - Coordination request
POST /api/start-training - Start training
POST /api/stop-training - Stop training
```

## Frontend Configuration

Update `/Users/spartan/Documents/GitHub/carbonshift/frontend/src/types/index.ts`:
```typescript
export const API_BASE_URL = 'http://localhost:8000';
export const WS_URL = 'ws://localhost:8000/ws';
```

## Running

1. **Backend:**
```bash
cd backend
source venv/bin/activate
python3 api/main.py
```

2. **Frontend:**
```bash
cd frontend
npm install
npm run dev
```

3. **Access Dashboard:**
```
http://localhost:3000
```

## Features Confirmed

✅ Real-time CAISO grid data
✅ WebSocket streaming (2s intervals)
✅ GPU power monitoring
✅ Training progress tracking
✅ Cost/carbon savings calculation
✅ Peak avoidance tracking
✅ GPT-4o predictions
✅ Claude reports
✅ AgentVerse integration

**Status:** Production Ready 🚀

```

### DEPLOY_STEPS.md

```markdown
# 🚀 Step-by-Step Deployment to Brev

## Current Situation
You're on your **local Mac** right now. You need to switch to your **Brev terminal** to run the training.

---

## ✅ Step 1: Verify You're on Brev

In your **other terminal** (the one SSH'd to Brev), run:

```bash
nvidia-smi
```

**Expected output:** Should show your GPU (e.g., "NVIDIA A100")

**If you see an error:** You're not connected to Brev yet.

---

## ✅ Step 2: Get Your Code on Brev

### Option A: If repo is already on Brev
```bash
cd carbonshift/backend
git pull origin main
```

### Option B: Clone fresh
```bash
git clone https://github.com/YOUR_USERNAME/carbonshift.git
cd carbonshift/backend
```

### Option C: Copy files from local machine
From your **local machine** (this terminal):
```bash
# First, get your Brev instance IP/hostname
# Then copy the files
cd /Users/spartan/Documents/GitHub/carbonshift/backend
scp quick_train.py setup_brev_env.sh ubuntu@YOUR_BREV_IP:~/
```

---

## ✅ Step 3: Setup Environment (First Time Only)

On your **Brev terminal**:

```bash
cd carbonshift/backend  # or wherever you copied the files

# Make scripts executable
chmod +x setup_brev_env.sh quick_train.py

# Run setup (this installs PyTorch with GPU support)
bash setup_brev_env.sh
```

This will:
- Create a Python virtual environment
- Install PyTorch with CUDA
- Verify GPU is working

---

## ✅ Step 4: Run Training

On your **Brev terminal**:

```bash
# Activate the environment
source venv_train/bin/activate

# Start 10-minute training
python3 quick_train.py --duration 10
```

---

## 🎯 Quick Method (If PyTorch is Already Installed)

If PyTorch is already on your Brev instance:

```bash
# On Brev terminal
cd carbonshift/backend
python3 quick_train.py --duration 10
```

---

## 🔍 How to Connect to Brev (If Not Connected)

```bash
# Get your Brev instance info
brev ls

# SSH into your instance
brev shell YOUR_INSTANCE_NAME

# Or use direct SSH
ssh ubuntu@YOUR_BREV_IP
```

---

## 📊 Expected Training Output

```
======================================================================
🚀 Quick Training Session Starting
Device: cuda
GPU: NVIDIA A100-SXM4-80GB
GPU Memory: 80.00 GB
Duration: 10 minutes
======================================================================
Initializing ResNet-18 model...
Creating synthetic dataset: 10000 samples
🔥 Training started!
----------------------------------------------------------------------
Epoch   1 | Step    20 | Loss: 2.3142 | Elapsed: 12s | Remaining: 588s
Epoch   2 | Step    40 | Loss: 2.1891 | Elapsed: 24s | Remaining: 576s
...
----------------------------------------------------------------------
✅ Training Complete!
Total Epochs: 47
Total Steps: 7344
Training Time: 600.0s (10.0 minutes)
Final Loss: 0.4523
💾 Checkpoint saved: model_checkpoint_20260215_123045.pth
======================================================================
```

---

## 🐛 Troubleshooting

### "nvidia-smi not found"
❌ You're on your local Mac, not Brev
✅ Switch to the Brev
[truncated — 799 more characters]
```

### frontend/package.json

```
{
  "name": "frontend",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "axios": "^1.13.5",
    "canvas-confetti": "^1.9.4",
    "framer-motion": "^12.34.0",
    "lucide-react": "^0.564.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "recharts": "^3.7.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.39.1",
    "@types/canvas-confetti": "^1.9.0",
    "@types/node": "^24.10.1",
    "@types/react": "^19.2.7",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^5.1.1",
    "autoprefixer": "^10.4.24",
    "eslint": "^9.39.1",
    "eslint-plugin-react-hooks": "^7.0.1",
    "eslint-plugin-react-refresh": "^0.4.24",
    "globals": "^16.5.0",
    "postcss": "^8.5.6",
    "tailwindcss": "^3.4.19",
    "typescript": "~5.9.3",
    "typescript-eslint": "^8.48.0",
    "vite": "^7.3.1"
  }
}

```

### backend/requirements.txt

```
# CarbonShift Backend Requirements
# Python 3.9+

# ============================================================================
# CORE DEPENDENCIES
# ============================================================================

# Web Framework & API
fastapi>=0.109.0
uvicorn[standard]>=0.27.0
websockets>=12.0
python-multipart>=0.0.9

# HTTP Client
httpx>=0.26.0

# Environment Variables
python-dotenv==1.0.0

# ============================================================================
# GPU & HARDWARE CONTROL
# ============================================================================

# NVIDIA GPU Management
nvidia-ml-py>=11.5.0

# ============================================================================
# MACHINE LEARNING & AI
# ============================================================================

# PyTorch (CPU/CUDA compatible)
torch>=2.1.0
torchvision>=0.16.0

# Hugging Face Transformers
transformers==4.36.0
datasets==2.16.0
accelerate==0.25.0

# ============================================================================
# PDF GENERATION
# ============================================================================

reportlab==4.0.8
Pillow==10.2.0

# ============================================================================
# LLM INTEGRATIONS (Optional)
# ============================================================================

# OpenAI
openai>=1.10.0

# Anthropic Claude
anthropic>=0.18.0

# ============================================================================
# DATA & UTILITIES
# ============================================================================

# Date/Time handling
python-dateutil==2.8.2

# Async support
asyncio==3.4.3

# Logging
loguru==0.7.2

# JSON handling
pydantic>=2.5.0

# ============================================================================
# FETCH.AI (Autonomous Agents)
# ============================================================================

# Fetch.ai uAgents SDK - Now integrated and active!
uagents>=0.20.0

# ============================================================================
# DEVELOPMENT & TESTING (Optional)
# ============================================================================

# pytest==7.4.3
# pytest-asyncio==0.21.1
# black==23.12.1
# flake8==7.0.0

```

### frontend/src/main.tsx

```typescript
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import { App } from './App';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

```

### backend/api/main.py

```python
"""
CarbonShift - Main FastAPI Server
Grid-Aware AI Training Orchestrator
"""

import logging
import asyncio
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from contextlib import asynccontextmanager
from typing import List
import sys
import os

# Add parent directory to path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from config import config
from core.gpu_controller import gpu_controller
from core.energy_monitor import energy_monitor
from core.decision_engine import decision_engine
from demo_workload.training_engine import training_engine
from core.metrics_history import metrics_history
from core.llm_intelligence import llm_intelligence
from core.fetchai_agent import fetchai_real_agent as fetchai_agent

# Setup logging
logging.basicConfig(
    level=getattr(logging, config.LOG_LEVEL),
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Global state
class SystemState:
    """Shared system state"""
    def __init__(self):
        self.current_grid_data = {}
        self.current_decision = None
        self.websocket_clients: List[WebSocket] = []
        self.energy_monitor_task = None
        self.metrics_broadcast_task = None
        self.is_running = False

system_state = SystemState()


# ============================================================================
# BACKGROUND TASKS
# ============================================================================

async def energy_monitor_loop():
    """
    Background task: Monitor grid energy every 60 seconds
    Makes orchestrator decisions based on real-time data
    """
    logger.info("🔋 Energy monitor loop started")

    while system_state.is_running:
        try:
            # Fetch grid data
            grid_data = await energy_monitor.fetch_grid_data()
            system_state.current_grid_data = grid_data

            logger.info(
                f"Grid Update - Price: ${grid_data['electricity_price']}/MWh, "
                f"Carbon: {grid_data['carbon_intensity']} gCO2/kWh"
            )

            # Make orchestrator decision
            decision = decision_engine.make_decision(
                grid_data['electricity_price'],
                grid_data['carbon_intensity']
            )
            system_state.current_decision = decision

            logger.info(
                f"Decision: {decision.state} | {decision.action} | "
                f"{decision.power_limit_watts}W | Pause: {decision.should_pause}"
            )
            logger.info(f"Reason: {decision.reason}")

            # Apply decision to hardware
            gpu_controller.set_power_limit(decision.power_limit_watts)

            # Apply decision to training
            if decision.should_pause and training_engine.is_training:
                training_engine.pause_training()
            elif not decision.should_pause and training_engine.is_paused:
                training_engine.resume_training()

            # Store historical data for charts
            gpu_stats = gpu_controller.get_gpu_stats()
            metrics_history.add_datapoint({
                "timestamp": grid_data["timestamp"],
                "electricity_price": grid_data["electricity_price"],
                "carbon_intensity": grid_data["carbon_intensity"],
                "gpu_power_watts": gpu_stats["power_usage_watts"],
                "gpu_power_limit_watts": gpu_stats["power_limit_watts"],
                "orchestrator_state": decision.state,
                "training_status": "paused" if decision.should_pause else "running",
                "cost_per_second": decision.cost_per_second,
                "carbon_per_second": decision.carbon_per_second
            })

            # Broadcast to Fetch.ai network (if active)
            await fetchai_agent.broadcast_grid_conditions(grid_data)

            # Wait before next poll
            await asyncio.sleep(config.ENERGY_POLL_INTERVAL)

        except Exception as e:
            logger.error(f"Energy monitor error: {e}")
            await asyncio.sleep(10)  # Shorter retry on error


async def metrics_broadcast_loop():
    """
    Background task: Broadcast metrics to WebSocket clients every 2 seconds
    """
    logger.info("📡 Metrics broadcast loop started")

    while system_state.is_running:
        try:
            # Collect all metrics
            metrics = await collect_metrics()

            # Broadcast to all connected WebSocket clients
            dead_clients = []
            for client in system_state.websocket_clients:
                try:
                    await client.send_json(metrics)
                except Exception:
                    dead_clients.append(client)

            # Remove disconnected clients
            for client in dead_clients:
                system_state.websocket_clients.remove(client)

            # Wait before next broadcast
            await asyncio.sleep(config.METRICS_BROADCAST_INTERVAL)

        except Exception as e:
            logger.error(f"Metrics broadcast error: {e}")
            await asyncio.sleep(2)


async def collect_metrics() -> dict:
    """Collect all system metrics for frontend"""
    grid_data = system_state.current_grid_data
    decision = system_state.current_decision
    gpu_stats = gpu_controller.get_gpu_stats()
    training_progress = training_engine.get_progress()
    savings = decision_engine.get_savings_summary()

    # Determine training status
    if training_progress["is_paused"]:
        training_status = "paused"
    elif training_progress["is_training"]:
        training_status = "running"
    elif training_progress["progress_percent"] >= 99.9:
        training_status = "completed"
    else:
        training_status = "idle"

    return {
        # Timestamp
        "timestamp": grid_data.get("timestamp", ""),

        # Grid data (frontend format)
        "el
[truncated — 10179 more characters]
```

### frontend/src/App.tsx

```typescript
import { useState, useCallback, useMemo } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { DollarSign, Leaf, Cpu, Activity, Loader2 } from 'lucide-react';
import { Header } from './components/Header';
import { MetricCard } from './components/MetricCard';
import { AnimatedValue } from './components/AnimatedValue';
import { EnergyPriceChart } from './components/EnergyPriceChart';
import { GPUPowerChart } from './components/GPUPowerChart';
import { ImpactMetrics } from './components/ImpactMetrics';
import { EnergySourceMix } from './components/EnergySourceMix';
import { SystemLogs } from './components/SystemLogs';
import { GridBackground } from './components/GridBackground';
import { GlitchOverlay } from './components/GlitchOverlay';
import { GpuHeatBar } from './components/GpuHeatBar';
import { HudRing } from './components/HudRing';
import { AuraOverlay } from './components/AuraOverlay';
import { MarketInsights } from './components/MarketInsights';
import { ESGTargets } from './components/ESGTargets';
import { DomainFilter } from './components/DomainFilter';
import { ProfitChart } from './components/ProfitChart';
import { PeaksTimeline } from './components/PeaksTimeline';
import { HeroIntro } from './components/HeroIntro';
import { useWebSocket } from './hooks/useWebSocket';
import { getCarbonColor, getStatusColor, formatStatus } from './utils/formatters';
import { predictPrices, deriveMarketInsights } from './utils/prediction';
import type { DomainFocus } from './types';

// ── Stagger "unbox" variants ─────────────────────────────────────────

const staggerContainer = {
  hidden: {},
  show: {
    transition: { staggerChildren: 0.08, delayChildren: 0.05 },
  },
};

const staggerItem = {
  hidden: { opacity: 0, y: 16 },
  show: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number] },
  },
};

// ── Map training status → CSS glow class ─────────────────────────────

function getGlowClass(status: string | null): string {
  switch (status) {
    case 'running':   return 'glow-running';
    case 'paused':    return 'glow-paused';
    case 'completed': return 'glow-completed';
    default:          return 'glow-idle';
  }
}

// ── Formatters for AnimatedValue (stable references) ─────────────────

const fmtPrice  = (v: number) => v.toFixed(2);
const fmtCarbon = (v: number) => Math.round(v).toString();
const fmtWatts  = (v: number) => Math.round(v).toString();

// ── Loading skeleton ─────────────────────────────────────────────────

function LoadingSkeleton() {
  return (
    <div className="min-h-screen" style={{ background: 'linear-gradient(160deg, #f0fdf4 0%, #ffffff 30%, #ecfdf5 60%, #f0fdf4 100%)' }}>
      <div className="sticky top-0 z-50 border-b border-gray-200/60" style={{ background: 'rgba(255,255,255,0.72)', backdropFilter: 'blur(24px)' }}>
        <div className="w-full px-4 sm:px-6 lg:px-8">
          <div className="flex items-center justify-between h-16">
            <div className="flex items-center gap-2.5">
              <div className="w-10 h-10 rounded-xl bg-gray-100 animate-pulse" />
              <div>
                <div className="h-5 w-28 bg-gray-100 rounded-lg animate-pulse" />
                <div className="h-2.5 w-36 bg-gray-50 rounded animate-pulse mt-1.5" />
              </div>
            </div>
            <div className="flex items-center gap-3">
              <div className="h-6 w-20 bg-gray-100 rounded-full animate-pulse" />
            </div>
          </div>
        </div>
      </div>

      <main className="w-full px-4 sm:px-6 lg:px-8 py-8 space-y-6">
        <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
          {[...Array(4)].map((_, i) => (
            <div key={i} className="card">
              <div className="flex items-start justify-between mb-4">
                <div className="h-3 w-20 bg-gray-100 rounded animate-pulse" />
              </div>
              <div className="h-10 w-28 bg-gray-100 rounded-lg animate-pulse" />
            </div>
          ))}
        </div>
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
          {[...Array(2)].map((_, i) => (
            <div key={i} className="card">
              <div className="h-4 w-32 bg-gray-100 rounded animate-pulse mb-4" />
              <div className="h-56 bg-gray-50 rounded-2xl animate-pulse flex items-center justify-center">
                <Loader2 className="w-5 h-5 text-gray-300 animate-spin" />
              </div>
            </div>
          ))}
        </div>
      </main>
    </div>
  );
}

// ── App ──────────────────────────────────────────────────────────────

export function App() {
  const { isConnected, isSimulating, currentData, history, error } = useWebSocket();
  // Cinematic intro state
  const [showIntro, setShowIntro] = useState(true);
  const dismissIntro = useCallback(() => setShowIntro(false), []);

  // Domain focus mode
  const [focusMode, setFocusMode] = useState<DomainFocus>('all');

  // GPU icon spin speed
  const gpuSpinDuration = useMemo(() => {
    if (!currentData) return 4;
    return Math.max(4 - (currentData.gpu_power_watts / 100), 0.5);
  }, [currentData?.gpu_power_watts]);

  const isPriceDanger = (currentData?.electricity_price ?? 0) > 50;

  // ── AI Prediction + Market Insights ─────────────────────────────
  const marketInsight = useMemo(() => {
    if (!currentData || history.length < 5) return null;
    const prices = history.map((d) => d.electricity_price);
    const lastTime = history[history.length - 1].time;
    const prediction = predictPrices(prices, lastTime, 15);
    return deriveMarketInsights(
      prices,
      currentData.carbon_intensity,
      currentData.total_cost_saved,
      prediction,
    );
  }, [currentData, history]);

  const focusClass = useCallback(
    (...modes: DomainFocus[]): string => {
      if (focusMode === 'all') return 'focus-section focus-highlighted';
      return modes.i
[truncated — 14249 more characters]
```

### frontend/src/types/index.ts

```typescript
export interface DashboardData {
  timestamp: string;
  electricity_price: number;
  carbon_intensity: number;
  gpu_power_watts: number;
  gpu_power_limit: number;
  training_status: TrainingStatus;
  total_cost_saved: number;
  total_carbon_saved: number;
  training_progress: number;
  current_epoch: number;
  total_epochs: number;
  peaks_avoided: number;
}

export type TrainingStatus = 'running' | 'paused' | 'idle' | 'completed';

export interface ChartDataPoint {
  time: string;
  timestamp: string;
  electricity_price: number;
  gpu_power_watts: number;
  gpu_power_limit: number;
  carbon_intensity: number;
}

export interface MetricCardProps {
  title: string;
  value: string | number;
  unit: string;
  icon: React.ReactNode;
  color: 'blue' | 'green' | 'orange' | 'red' | 'yellow';
  trend?: 'up' | 'down' | 'stable';
  pulse?: boolean;
}

export interface WebSocketState {
  isConnected: boolean;
  isSimulating: boolean;
  currentData: DashboardData | null;
  history: ChartDataPoint[];
  error: string | null;
}

export interface TrainingAPIState {
  isStarting: boolean;
  isStopping: boolean;
  isDownloading: boolean;
  error: string | null;
}

export type DomainFocus = 'all' | 'sustainability' | 'finance' | 'grid';

export const API_BASE_URL = 'http://localhost:8000';
export const WS_URL = 'ws://localhost:8000/ws';

```

### check_history.sh

```shell
#!/bin/bash

sleep 3

echo "Checking historical data..."
curl -s http://localhost:8000/api/history | python3 -c "
import json, sys
d = json.load(sys.stdin)
total = d['summary']['total_datapoints']
print(f'✅ Historical datapoints: {total}')
print(f'✅ Price range: \${d[\"summary\"][\"min_price\"]:.2f} - \${d[\"summary\"][\"max_price\"]:.2f}/MWh')
print(f'✅ Avg carbon: {d[\"summary\"][\"avg_carbon\"]:.1f} gCO2/kWh')

if total > 100:
    print(f'\n🎉 Dashboard has full 24h data for charts!')
else:
    print(f'\n⏳ Still collecting... ({total}/288)')
"

```

### restart_with_history.sh

```shell
#!/bin/bash

echo "Stopping backend..."
lsof -ti:8000 | xargs kill -9 2>/dev/null
lsof -ti:8001 | xargs kill -9 2>/dev/null
sleep 3

cd /Users/spartan/Documents/GitHub/carbonshift/backend
source venv/bin/activate

echo "Backfilling 24h historical data..."
python3 backfill_history.py

echo "Starting backend..."
python3 api/main.py > backend_with_history.log 2>&1 &

sleep 12

echo ""
echo "Checking history..."
curl -s http://localhost:8000/api/history | python3 -c "
import json, sys
d = json.load(sys.stdin)
print(f'✅ Historical datapoints: {d[\"summary\"][\"total_datapoints\"]}')
print(f'✅ Avg price: \${d[\"summary\"][\"avg_price\"]:.2f}/MWh')
print(f'✅ Price range: \${d[\"summary\"][\"min_price\"]:.2f} - \${d[\"summary\"][\"max_price\"]:.2f}')
print(f'\n✅ Dashboard now has full 24h of data for charts!')
"

```

[68 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]