added AGENTS.md

This commit is contained in:
Johan Lundberg 2026-01-22 10:25:07 +01:00
parent 0b91798c96
commit 21042ec133
No known key found for this signature in database
GPG key ID: A6C152738D03C7D1

187
AGENTS.md Normal file
View file

@ -0,0 +1,187 @@
# AGENTS.md
This file provides guidance for AI coding agents working in this repository.
## Project Overview
Top 500 Albums analysis with data from Rolling Stone (2020) and Wikipedia (2023). Includes Python data processing scripts, an interactive web interface (vanilla HTML/CSS/JS), and album cover artwork from the iTunes API.
## Build/Lint/Test Commands
**No formal build system.** All Python scripts use only the standard library.
```bash
# Run Python scripts directly
python scripts/download_all_covers.py
python scripts/compare_top500_albums.py
# Local dev server (required for CORS)
python -m http.server 8000
```
**No tests or linting configured.** Manual testing only - run scripts and verify output, open website and check functionality.
## Code Style Guidelines
### Python
```python
#!/usr/bin/env python3
"""Module docstring explaining the script's purpose."""
import csv
import json
import os
import re
from typing import Dict, List, Optional, Tuple
# Constants: UPPER_SNAKE_CASE
MAX_RETRIES = 3
# Functions/variables: snake_case
def normalize_text(text: str) -> str:
"""Normalize text for comparison."""
pass
albums_2020 = {}
```
**Key patterns:**
- Always use shebang: `#!/usr/bin/env python3`
- Include module-level docstring
- Standard library only - no external dependencies
- Type hints for function signatures
- Use `encoding='utf-8'` and `newline=''` for CSV operations
**Error handling:**
```python
try:
with urllib.request.urlopen(url, timeout=15) as response:
data = json.loads(response.read().decode())
except Exception as e:
print(f"Error: {e}")
return None
```
### JavaScript
```javascript
// Global variables at top
let albumsData = [];
const itemsPerPage = 50;
// DOM refs cached on load
const albumsGrid = document.getElementById('albumsGrid');
// Initialize on DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() {
loadData();
});
// Async/await for fetch
async function loadAlbumsData() {
try {
const response = await fetch('data.csv');
if (!response.ok) throw new Error('Failed');
// ...
} catch (err) {
console.error('Error:', err);
}
}
```
**Key patterns:**
- Variables/functions: camelCase
- Use `console.warn()` for non-critical failures
- Vanilla JS only - no frameworks
### HTML/CSS
- Semantic HTML5 elements
- CSS custom properties for theming
- Responsive design with Grid/Flexbox
## Accessibility Requirements
All UI changes must follow WCAG 2.1 AA guidelines:
**Keyboard Navigation:**
- All interactive elements must be keyboard accessible
- Use `tabindex` appropriately (0 for focusable, -1 for programmatic focus)
- Implement visible focus indicators (`:focus-visible` with `outline`)
- Support skip links for main content
**Screen Readers:**
- Use semantic HTML (`<button>`, `<nav>`, `<main>`, `<article>`)
- Add ARIA labels for icon-only buttons: `aria-label="Share album"`
- Use `.sr-only` class for screen-reader-only text
- Ensure proper heading hierarchy (`h1` > `h2` > `h3`)
**Color & Contrast:**
- Minimum 4.5:1 contrast ratio for normal text
- Minimum 3:1 for large text and UI components
- Never use color alone to convey information
**Motion & Animations:**
- Respect `prefers-reduced-motion` media query
- Avoid layout shifts on hover (no `transform: translateY()` on cards)
**Focus Management:**
- Trap focus in modals/dialogs
- Return focus to trigger element when closing overlays
**Existing Patterns:**
```css
/* Screen reader only */
.sr-only { position: absolute; width: 1px; height: 1px; ... }
/* Focus indicators */
button:focus-visible { outline: 2px solid var(--primary-color); outline-offset: 2px; }
/* Reduced motion */
@media (prefers-reduced-motion: reduce) { ... }
```
## Project Structure
```
top500albums/
├── index.html, script.js, styles.css # Website
├── *.csv, *.json # Data files
├── covers/ # Album artwork (500 images)
└── scripts/ # Python utilities (36 scripts)
```
## Data Files
| File | Notes |
|------|-------|
| `rolling_stone_top_500_albums_2020.csv` | Title case columns, ranks in reverse order |
| `wikipedia_top_500_albums.csv` | Lowercase columns (`rank`, `artist`, `album`) |
| `top_500_albums_2023.csv` | Combined comparison file |
## Key Patterns
**CSV column naming:**
- Rolling Stone/Combined: Title case (`Rank`, `Artist`, `Album`)
- Wikipedia: lowercase (`rank`, `artist`, `album`)
**Album matching:** Uses `difflib` for fuzzy matching variations like "The Beatles" vs "Beatles"
**API rate limiting:** `time.sleep(1.2)` between requests
## Common Tasks
**New Python script:**
1. Create in `scripts/`, add shebang + docstring
2. Standard library only
3. Include `if __name__ == "__main__":` block
**Working with album data:**
```python
import csv
with open('top_500_albums_2023.csv', 'r', encoding='utf-8') as f:
for row in csv.DictReader(f):
rank, artist, album = int(row['Rank']), row['Artist'], row['Album']
status = row['Status'] # "New in 2023", "+10", "-5", "No change"
```