added AGENTS.md
This commit is contained in:
parent
0b91798c96
commit
21042ec133
1 changed files with 187 additions and 0 deletions
187
AGENTS.md
Normal file
187
AGENTS.md
Normal 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"
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue