| name | acx.code.assistant |
| description | Generate code scaffolds following Carbon ACX conventions for React components, TypeScript APIs, Cloudflare Workers, Python scripts, and tests. |
acx.code.assistant
Purpose
This skill enables Claude to generate production-ready code for Carbon ACX that adheres to repository conventions, architectural patterns, and quality standards defined in AGENTS.md, CLAUDE.md, and CONTRIBUTING.md.
Capabilities:
- Generate React components with proper TypeScript typing
- Create Cloudflare Worker endpoints with runtime constraints
- Scaffold Python data pipeline scripts
- Generate test files (Vitest, pytest)
- Create typed API client code
- Follow monorepo structure (pnpm workspaces)
- NEW: Generate 3D visualization components with Three.js/React Three Fiber
- NEW: Create 2D overlay components (modals, panels) for transparency
- NEW: Build Apache ECharts visualizations with design tokens
Quality Enforcement:
- All code passes linters (eslint, prettier, ruff, black)
- Includes proper error handling
- TypeScript strict mode compliance
- Includes basic tests
- Follows AGENTS.md review gates
- NEW: Uses design tokens (CSS custom properties)
- NEW: Follows 3D+2D hybrid architecture (viz in canvas, transparency in overlays)
When to Use
Trigger Patterns:
- "Create a React component for displaying emission trends"
- "Generate a Cloudflare Worker endpoint for /api/emissions"
- "Scaffold a Python script to process activity data"
- "Write a test for the EmissionCalculator class"
- "Create a typed API client for the carbon data service"
- "Generate boilerplate for a new layer in the Dash app"
- NEW: "Create a 3D sphere visualization component for..."
- NEW: "Build a citation panel modal for emission factor sources"
- NEW: "Generate an ECharts visualization for timeline data"
- NEW: "Create a Zustand store slice for..."
Do NOT Use When:
- User asks analytical questions (use
carbon.data.qa) - User wants reports (use
carbon.report.gen) - User wants to validate schemas (use
schema.linter) - Modifying core architecture (requires human design review first)
Allowed Tools
read_file- Read existing code for context and patternswrite_file- Create new code filesedit_file- Modify existing files (with caution)bash- Run linters, formatters, tests to verify code quality
Access Level: 2 (File Modification - can create/edit code files with human review)
Tool Rationale:
read_file: Required to understand existing patterns and conventionswrite_file: Required to generate new code filesedit_file: Allowed for targeted edits (must preserve existing logic)bash: Needed to run quality checks (eslint, pytest, etc.)
Explicitly Denied:
- No direct deployment or production changes
- No modifications to
wrangler.toml,.github/workflows/,Makefilewithout explicit user approval (high-risk per AGENTS.md) - No committing or pushing code (human must review first)
Expected I/O
Input:
- Type: Code generation request
- Format: Natural language description of desired code
- Required Context:
- What to build (component, endpoint, script, test)
- Where it fits (file path or module)
- Key functionality
- Optional Context:
- Specific technologies/libraries
- Integration points
- Edge cases to handle
Example:
"Create a React component that displays a bar chart of emissions by layer using our existing chart library"
Output:
- Type: Code file(s) with proper structure
- Format: TypeScript (.tsx, .ts), Python (.py), or JavaScript (.js)
- Location: Appropriate directory per repo structure
- Includes:
- Proper imports
- TypeScript types/interfaces
- Error handling
- JSDoc/docstring comments
- Basic test file (separate)
- Validation:
- Runs through linter without errors
- Follows naming conventions
- Includes type safety
- No TODOs without tracking
Dependencies
Required:
- Access to Carbon ACX repository structure
- Understanding of AGENTS.md conventions
- Knowledge of tech stack:
- TypeScript 5.5+
- React 18
- Vite 5
- Python 3.11+
- Cloudflare Workers runtime
- Reference files:
reference/conventions.md- Coding standardsAGENTS.md- AI development guidelinesCLAUDE.md- Repository-specific rules
Code Quality Tools:
- ESLint + Prettier (TypeScript/JavaScript)
- Ruff + Black (Python)
- Vitest (JavaScript tests)
- pytest (Python tests)
Examples
Example 1: React Component Generation
User: "Create a React component for displaying a list of activities with their emission factors"
Claude Process:
- Read existing component patterns (e.g., from
apps/carbon-acx-web/src/components/) - Check conventions in
reference/conventions.md - Generate component with:
- Proper TypeScript types
- Props interface
- Error handling
- Accessibility attributes
- Generate companion test file
- Run prettier/eslint to verify
- Save to appropriate directory
Output File: apps/carbon-acx-web/src/components/ActivityList.tsx
import React from 'react';
interface Activity {
activity_id: string;
name: string;
emission_factor?: number;
unit?: string;
}
interface ActivityListProps {
activities: Activity[];
onActivitySelect?: (activity: Activity) => void;
}
/**
* Displays a list of activities with their emission factors
* @param activities - Array of activity objects
* @param onActivitySelect - Optional callback when activity is clicked
*/
export const ActivityList: React.FC<ActivityListProps> = ({
activities,
onActivitySelect,
}) => {
if (!activities || activities.length === 0) {
return <p className="text-gray-500">No activities available</p>;
}
return (
<ul className="space-y-2" role="list">
{activities.map((activity) => (
<li
key={activity.activity_id}
className="p-4 border rounded hover:bg-gray-50 cursor-pointer"
onClick={() => onActivitySelect?.(activity)}
role="listitem"
>
<div className="font-semibold">{activity.name}</div>
{activity.emission_factor && (
<div className="text-sm text-gray-600">
{activity.emission_factor} kgCO2e/{activity.unit || 'unit'}
</div>
)}
</li>
))}
</ul>
);
};
Test File: apps/carbon-acx-web/src/components/ActivityList.test.tsx
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { ActivityList } from './ActivityList';
describe('ActivityList', () => {
const mockActivities = [
{ activity_id: 'TEST.1', name: 'Test Activity', emission_factor: 1.5, unit: 'hour' },
];
it('renders activities correctly', () => {
render(<ActivityList activities={mockActivities} />);
expect(screen.getByText('Test Activity')).toBeInTheDocument();
expect(screen.getByText(/1.5 kgCO2e/)).toBeInTheDocument();
});
it('shows message when no activities', () => {
render(<ActivityList activities={[]} />);
expect(screen.getByText(/No activities available/)).toBeInTheDocument();
});
});
Example 2: Cloudflare Worker Endpoint
User: "Create a Cloudflare Worker endpoint at /api/layers that returns all layer data"
Claude Process:
- Read existing Worker code in
workers/compute/index.ts - Understand Cloudflare runtime constraints (no Node.js APIs)
- Generate endpoint with:
- Proper error handling
- CORS headers
- Input validation
- Response typing
- Note binding requirements in comments
Output File: workers/compute/routes/layers.ts
/**
* GET /api/layers
* Returns all carbon accounting layers
*
* Runtime: Cloudflare Workers (no Node.js APIs)
* Bindings: None required
*/
interface Layer {
layer_id: string;
layer_name: string;
layer_type: string;
description: string;
}
export async function handleLayersRequest(request: Request): Promise<Response> {
// Validate request method
if (request.method !== 'GET') {
return new Response(
JSON.stringify({ error: 'Method not allowed' }),
{ status: 405, headers: { 'Content-Type': 'application/json' } }
);
}
try {
// In production, this would load from KV or R2
// For now, return static demo data
const layers: Layer[] = [
{
layer_id: 'professional',
layer_name: 'Professional Services',
layer_type: 'civilian',
description: 'Professional and consumer activities',
},
{
layer_id: 'online',
layer_name: 'Digital Infrastructure',
layer_type: 'civilian',
description: 'Online services and digital operations',
},
// Add more layers...
];
return new Response(JSON.stringify({ layers, count: layers.length }), {
status: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*', // Adjust for production
'Cache-Control': 'public, max-age=3600',
},
});
} catch (error) {
console.error('Error fetching layers:', error);
return new Response(
JSON.stringify({ error: 'Internal server error' }),
{ status: 500, headers: { 'Content-Type': 'application/json' } }
);
}
}
Integration Note: Add route to main Worker in workers/compute/index.ts:
import { handleLayersRequest } from './routes/layers';
// In fetch handler:
if (url.pathname === '/api/layers') {
return handleLayersRequest(request);
}
Example 3: Python Data Processing Script
User: "Create a Python script to aggregate emission factors by layer"
Output: scripts/aggregate_by_layer.py
"""
Aggregate emission factors by layer.
Reads activities.csv and emission_factors.csv, then produces a summary
of total emission factors grouped by layer_id.
"""
import pandas as pd
from pathlib import Path
def aggregate_by_layer(data_dir: Path = Path("data")) -> pd.DataFrame:
"""
Aggregate emission factors by layer.
Args:
data_dir: Path to data directory containing CSV files
Returns:
DataFrame with columns: layer_id, layer_name, total_ef, activity_count
Raises:
FileNotFoundError: If required CSV files are missing
ValueError: If data validation fails
"""
# Load data
activities_path = data_dir / "activities.csv"
emission_factors_path = data_dir / "emission_factors.csv"
layers_path = data_dir / "layers.csv"
if not activities_path.exists():
raise FileNotFoundError(f"Activities file not found: {activities_path}")
activities = pd.read_csv(activities_path)
emission_factors = pd.read_csv(emission_factors_path)
layers = pd.read_csv(layers_path)
# Merge activities with emission factors
merged = activities.merge(
emission_factors, on="activity_id", how="inner"
)
# Aggregate by layer
aggregated = (
merged.groupby("layer_id")
.agg(
total_ef=("emission_factor_kg", "sum"),
activity_count=("activity_id", "count"),
)
.reset_index()
)
# Add layer names
aggregated = aggregated.merge(
layers[["layer_id", "layer_name"]], on="layer_id", how="left"
)
# Sort by total emission factor descending
aggregated = aggregated.sort_values("total_ef", ascending=False)
return aggregated[["layer_id", "layer_name", "total_ef", "activity_count"]]
def main():
"""CLI entry point."""
result = aggregate_by_layer()
print("\n=== Emission Factors by Layer ===\n")
print(result.to_string(index=False))
print(f"\nTotal activities: {result['activity_count'].sum()}")
print(f"Total emission factors: {result['total_ef'].sum():.2f} kgCO2e\n")
if __name__ == "__main__":
main()
Test File: tests/test_aggregate_by_layer.py
import pytest
import pandas as pd
from pathlib import Path
from scripts.aggregate_by_layer import aggregate_by_layer
def test_aggregate_by_layer(tmp_path):
"""Test layer aggregation with mock data."""
# Create mock CSV files
activities_data = pd.DataFrame({
"activity_id": ["A1", "A2", "A3"],
"layer_id": ["professional", "professional", "online"],
"name": ["Activity 1", "Activity 2", "Activity 3"],
})
ef_data = pd.DataFrame({
"activity_id": ["A1", "A2", "A3"],
"emission_factor_kg": [10.5, 20.3, 15.7],
})
layers_data = pd.DataFrame({
"layer_id": ["professional", "online"],
"layer_name": ["Professional Services", "Digital Infrastructure"],
})
# Save to temp directory
activities_data.to_csv(tmp_path / "activities.csv", index=False)
ef_data.to_csv(tmp_path / "emission_factors.csv", index=False)
layers_data.to_csv(tmp_path / "layers.csv", index=False)
# Run aggregation
result = aggregate_by_layer(data_dir=tmp_path)
# Assertions
assert len(result) == 2
assert "professional" in result["layer_id"].values
assert "online" in result["layer_id"].values
prof_row = result[result["layer_id"] == "professional"].iloc[0]
assert prof_row["total_ef"] == pytest.approx(30.8) # 10.5 + 20.3
assert prof_row["activity_count"] == 2
Limitations
Scope Limitations:
- Cannot make architectural decisions (requires human design)
- Cannot modify deployment configs without approval (per AGENTS.md)
- Cannot bypass review gates for security-sensitive code
- Cannot write code using technologies not in the stack
Code Quality Constraints:
- Must pass linters (may need manual fixes for edge cases)
- TypeScript strict mode compliance (may require additional type definitions)
- Test coverage expectations (basic tests provided, comprehensive coverage requires expansion)
Knowledge Boundaries:
- Code generated based on existing patterns - novel patterns may need review
- Cloudflare Workers runtime constraints must be respected
- Brand/style guidelines from
reference/conventions.mdmust be followed
Validation Criteria
Success Metrics:
- ✅ Code compiles/runs without errors
- ✅ Passes linter (eslint, ruff, prettier, black)
- ✅ TypeScript strict mode compliance
- ✅ Includes proper error handling
- ✅ Has basic test coverage
- ✅ Follows naming conventions from
reference/conventions.md - ✅ Includes JSDoc/docstrings for complex functions
- ✅ No hardcoded secrets or credentials
Quality Checks:
# TypeScript/JavaScript
pnpm run lint # ESLint
pnpm run format # Prettier
pnpm run type-check # TypeScript compiler
# Python
ruff check . # Linting
black --check . # Formatting
pytest tests/ # Tests
Failure Modes:
- ❌ Linter errors → Fix before completing
- ❌ Type errors → Add proper types
- ❌ No tests → Generate basic test file
- ❌ TODOs without issue links → Remove or link
- ❌ Hardcoded values (should be config) → Parameterize
Recovery:
- If linter fails: Run formatter and fix issues
- If types incomplete: Infer from usage or use strict types
- If patterns unclear: Read similar existing code
- If tests fail: Debug and fix before delivery
Related Skills
Composes With:
schema.linter- Validate generated config filescarbon.data.qa- Use to understand data structure before generating data code
Not a Replacement For:
- Human code review (per AGENTS.md)
- Architecture decisions
- Deployment operations
3D Universe Patterns (NEW)
Architecture Overview
3D+2D Hybrid Approach:
- 3D Canvas: Interactive data visualization with Three.js/React Three Fiber
- 2D Overlays: Modals, panels, and forms for transparency and data entry
- Design Tokens: CSS custom properties for consistent styling
- State Management: Single Zustand store (simplified from dual-store pattern)
Component Organization
Component Types:
- System Primitives: Button, Input, Dialog, Transition (Tier 1)
- 3D Visualizations: DataUniverse, CentralSphere, OrbitingActivity (Tier 3)
- 2D Overlays: CitationPanel, MethodologyModal, ActivityManagement (Tier 4)
- Domain Pages: CalculatorPage, InsightsPage, ExplorePage (Tier 4)
Example 4: 3D Visualization Component
User: "Create a component for visualizing activity emissions as orbiting spheres"
Output: apps/carbon-acx-web/src/components/viz/ActivitySphere.tsx
/**
* ActivitySphere - 3D Visualization Component
*
* Renders an individual activity as an orbiting sphere in the DataUniverse.
* Size based on emissions (logarithmic scale), color based on intensity.
*/
import * as React from 'react';
import { useFrame } from '@react-three/fiber';
import { Html } from '@react-three/drei';
import * as THREE from 'three';
interface ActivitySphereProps {
activity: {
id: string;
name: string;
annualEmissions: number; // kg CO₂
category?: string;
};
orbitRadius: number;
orbitSpeed: number;
phaseOffset: number;
onClick?: () => void;
}
export function ActivitySphere({
activity,
orbitRadius,
orbitSpeed,
phaseOffset,
onClick,
}: ActivitySphereProps) {
const meshRef = React.useRef<THREE.Mesh>(null);
const groupRef = React.useRef<THREE.Group>(null);
const [hovered, setHovered] = React.useState(false);
// Calculate size (logarithmic scale)
const size = 0.5 + Math.log10(Math.max(activity.annualEmissions, 1)) * 0.3;
// Calculate color based on intensity
const color = React.useMemo(() => {
const tonnes = activity.annualEmissions / 1000;
if (tonnes < 1) return '#10b981'; // green (low)
if (tonnes < 5) return '#f59e0b'; // amber (moderate)
return '#ef4444'; // red (high)
}, [activity.annualEmissions]);
// Orbital motion animation
useFrame(() => {
if (!groupRef.current) return;
const time = Date.now() * orbitSpeed;
const angle = time + phaseOffset;
const x = Math.cos(angle) * orbitRadius;
const z = Math.sin(angle) * orbitRadius;
const y = Math.sin(time * 2) * 2; // vertical wobble
groupRef.current.position.set(x, y, z);
});
return (
<group ref={groupRef}>
<mesh
ref={meshRef}
onClick={onClick}
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
>
<sphereGeometry args={[size, 16, 16]} />
<meshStandardMaterial
color={color}
emissive={color}
emissiveIntensity={hovered ? 0.8 : 0.2}
metalness={0.6}
roughness={0.3}
/>
</mesh>
{/* Hover label */}
{hovered && (
<Html position={[0, size + 0.8, 0]} center>
<div
className="px-3 py-2 rounded-lg pointer-events-none"
style={{
backgroundColor: 'rgba(10, 14, 39, 0.95)',
border: `1px solid ${color}`,
color: 'white',
fontSize: 'var(--font-size-xs)',
whiteSpace: 'nowrap',
}}
>
<div style={{ fontWeight: 600, marginBottom: '4px' }}>
{activity.name}
</div>
<div style={{ opacity: 0.8 }}>
{(activity.annualEmissions / 1000).toFixed(2)}t CO₂/yr
</div>
</div>
</Html>
)}
</group>
);
}
Example 5: 2D Overlay Component
User: "Create a modal for displaying emission factor citations"
Output: apps/carbon-acx-web/src/components/domain/CitationModal.tsx
/**
* CitationModal - 2D Overlay Component
*
* Displays emission factor source information with transparency.
* Uses Radix Dialog for accessibility.
*/
import * as React from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { X, ExternalLink } from 'lucide-react';
import { Button } from '../system/Button';
interface Citation {
activityId: string;
activityName: string;
emissionFactor: number;
unit: string;
source: string;
sourceUrl?: string;
methodology?: string;
lastUpdated?: string;
}
interface CitationModalProps {
citation: Citation | null;
open: boolean;
onClose: () => void;
}
export function CitationModal({ citation, open, onClose }: CitationModalProps) {
if (!citation) return null;
return (
<Dialog.Root open={open} onOpenChange={onClose}>
<Dialog.Portal>
<Dialog.Overlay
className="fixed inset-0 z-50"
style={{
backgroundColor: 'rgba(0, 0, 0, 0.6)',
backdropFilter: 'blur(4px)',
}}
/>
<Dialog.Content
className="fixed top-[50%] left-[50%] z-50 max-h-[85vh] w-[90vw] max-w-[600px] translate-x-[-50%] translate-y-[-50%] rounded-[var(--radius-xl)] p-[var(--space-6)] shadow-xl overflow-y-auto"
style={{
backgroundColor: 'var(--surface-elevated)',
border: '1px solid var(--border-default)',
}}
>
{/* Header */}
<div className="flex items-start justify-between mb-[var(--space-6)]">
<Dialog.Title
className="font-bold"
style={{
fontSize: 'var(--font-size-2xl)',
color: 'var(--text-primary)',
}}
>
Emission Factor Source
</Dialog.Title>
<Dialog.Close asChild>
<button
className="p-[var(--space-2)] rounded-[var(--radius-md)]"
style={{ color: 'var(--text-tertiary)' }}
>
<X className="w-5 h-5" />
</button>
</Dialog.Close>
</div>
{/* Activity Info */}
<div className="space-y-[var(--space-4)]">
<div>
<div
className="font-semibold mb-[var(--space-1)]"
style={{
fontSize: 'var(--font-size-sm)',
color: 'var(--text-tertiary)',
}}
>
Activity
</div>
<div style={{ color: 'var(--text-primary)' }}>
{citation.activityName}
</div>
</div>
<div>
<div
className="font-semibold mb-[var(--space-1)]"
style={{
fontSize: 'var(--font-size-sm)',
color: 'var(--text-tertiary)',
}}
>
Emission Factor
</div>
<div
className="font-mono"
style={{
fontSize: 'var(--font-size-lg)',
color: 'var(--text-primary)',
}}
>
{citation.emissionFactor} kg CO₂e/{citation.unit}
</div>
</div>
<div>
<div
className="font-semibold mb-[var(--space-1)]"
style={{
fontSize: 'var(--font-size-sm)',
color: 'var(--text-tertiary)',
}}
>
Source
</div>
<div style={{ color: 'var(--text-primary)' }}>
{citation.source}
</div>
{citation.sourceUrl && (
<a
href={citation.sourceUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-[var(--space-1)] mt-[var(--space-2)] text-[var(--font-size-sm)]"
style={{ color: 'var(--interactive-primary)' }}
>
View source <ExternalLink className="w-4 h-4" />
</a>
)}
</div>
{citation.methodology && (
<div>
<div
className="font-semibold mb-[var(--space-1)]"
style={{
fontSize: 'var(--font-size-sm)',
color: 'var(--text-tertiary)',
}}
>
Methodology
</div>
<div
style={{
fontSize: 'var(--font-size-sm)',
color: 'var(--text-secondary)',
}}
>
{citation.methodology}
</div>
</div>
)}
</div>
{/* Actions */}
<div className="flex justify-end mt-[var(--space-6)] pt-[var(--space-4)] border-t" style={{ borderColor: 'var(--border-subtle)' }}>
<Button variant="primary" onClick={onClose}>
Close
</Button>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}
Design Token Usage
Always use design tokens for styling:
// ✅ Correct - Using design tokens
<div className="text-[var(--font-size-lg)] text-[var(--text-primary)]">
// ❌ Wrong - Hardcoded values
<div className="text-lg text-gray-900">
// ✅ Correct - Using token-based spacing
<div className="space-y-[var(--space-4)]">
// ❌ Wrong - Hardcoded spacing
<div className="space-y-4">
Available Design Tokens:
- Typography:
--font-size-xsthrough--font-size-5xl(Major Third scale 1.250) - Colors:
--carbon-low,--carbon-moderate,--carbon-high,--carbon-neutral - Story colors:
--color-goal,--color-baseline,--color-improvement,--color-insight - Spacing:
--space-1through--space-16(4px base) - Shadows:
--shadow-sm,--shadow-md,--shadow-lg - Radii:
--radius-sm,--radius-md,--radius-lg,--radius-xl - Motion:
--motion-story-duration(600ms),--motion-story-ease
State Management Pattern
Zustand for all app state:
import { useAppStore } from '../../hooks/useAppStore';
// Get state
const activities = useAppStore((state) => state.activities);
const totalEmissions = useAppStore((state) => state.getTotalEmissions());
// Update state
const { addActivity, removeActivity } = useAppStore();
// Store example structure:
interface AppState {
// Profile data
profile: {
activities: Activity[];
goals: Goal[];
};
// UI state
selectedActivityId: string | null;
// Actions
addActivity: (activity: Activity) => void;
removeActivity: (id: string) => void;
getTotalEmissions: () => number;
}
Maintenance
Owner: ACX Team Review Cycle: Weekly (high-activity skill) Last Updated: 2025-10-27 Version: 2.1.0 (3D Universe architecture update)
Maintenance Notes:
- Update
reference/conventions.mdwhen coding standards change - Review generated code quality monthly
- Keep examples synchronized with actual codebase patterns
- Update when tech stack versions change (React, TypeScript, Python, Three.js)
- NEW: Keep 3D Universe patterns current (Three.js, React Three Fiber, Drei helpers)
- NEW: Update component examples as hybrid 2D+3D architecture evolves