Add a detailed guide for AI assistants working with the bitvid codebase. The document covers: - Project overview and technology stack - Codebase structure and essential files - Development workflow and setup instructions - CI/CD pipeline overview with job timeouts - Code conventions (logging, styling, Nostr events, magnets) - Architecture patterns (bitvidApp vs controllers) - Feature flags and runtime configuration - Nostr integration details and NIP usage - Testing guidelines and common troubleshooting - Quick reference for imports and content schema This complements AGENTS.md (mission/architecture) and CONTRIBUTING.md (setup/PR process) by providing AI-specific context and patterns. https://claude.ai/code/session_014BfcJJAuzSHDwdoyYKoHZG
14 KiB
CLAUDE.md — AI Assistant Guide for bitvid
This document provides context and guidance for AI assistants working with the bitvid codebase. It explains the project structure, development workflows, conventions, and key architectural decisions.
Project Overview
bitvid is a decentralized video sharing platform built on the Nostr protocol. It operates as a static client — no backend server, no custody of user keys, no server-side signing. All authentication and state management happens client-side or via connected Nostr signers.
Key Technologies
- Nostr: Decentralized identity and event protocol (NIP-07, NIP-33, NIP-44, NIP-46, NIP-51, NIP-71, etc.)
- WebTorrent: P2P video streaming fallback
- Tailwind CSS: Utility-first styling with custom design tokens
- Playwright: E2E and visual regression testing
- Node.js 20+: Development environment
License
GPL-3.0-or-later (see LICENSE)
Codebase Structure
bitvid/
├── js/ # Main application JavaScript
│ ├── app.js # Main orchestrator (bitvidApp)
│ ├── nostr/ # Nostr protocol implementation
│ │ ├── client.js # Core Nostr client with signer adapters
│ │ ├── nip71.js # NIP-71 video note parsing
│ │ ├── sessionActor.js # Anonymous session actors for telemetry
│ │ └── adapters/ # NIP-07, NIP-46, nsec signer adapters
│ ├── services/ # Business logic services
│ │ └── playbackService.js # Video playback orchestration
│ ├── ui/ # UI components and controllers
│ ├── state/ # State management (cache.js)
│ ├── utils/ # Utility functions
│ ├── constants.js # Feature flags and WSS trackers
│ ├── config.js # Re-exports from instance config
│ ├── magnetUtils.js # Magnet URI helpers
│ ├── nostrEventSchemas.js # Event schema definitions (source of truth)
│ └── nostrClientFacade.js # Main Nostr client entry point
├── config/
│ └── instance-config.js # Deployment configuration
├── css/
│ ├── tokens.css # Design token definitions
│ ├── tailwind.source.css # Tailwind input file
│ └── tailwind.generated.css # Generated (gitignored)
├── tests/ # Test suites
│ ├── unit/ # Unit tests
│ ├── e2e/ # End-to-end tests
│ ├── visual/ # Visual regression tests
│ ├── nostr/ # Nostr-specific tests
│ └── moderation/ # Moderation feature tests
├── docs/ # Documentation
│ ├── nostr-event-schemas.md # Event schema reference
│ ├── playback-fallback.md # Playback architecture
│ ├── moderation/ # Moderation system docs
│ └── nips/ # NIP reference documentation
├── views/ # HTML view templates
├── components/ # HTML component templates
├── content/ # Markdown content (docs, roadmap)
├── torrent/ # WebTorrent integration
├── scripts/ # Build and utility scripts
└── .github/workflows/ # CI/CD configuration
Essential Files to Know
| File | Purpose |
|---|---|
AGENTS.md |
AI agent guide with architectural rules and mission |
KNOWN_ISSUES.md |
Pre-existing test failures and environmental quirks |
CONTRIBUTING.md |
Developer setup and contribution guidelines |
js/app.js |
Main application orchestrator (bitvidApp) |
js/nostr/client.js |
Core Nostr client with signer registry |
js/nostrEventSchemas.js |
Source of truth for all Nostr event schemas |
js/constants.js |
Feature flags and runtime configuration |
config/instance-config.js |
Deployment-specific settings |
docs/nostr-event-schemas.md |
Event schema documentation |
Development Workflow
Initial Setup
# Clone and install
git clone https://github.com/PR0M3TH3AN/bitvid.git
cd bitvid
npm ci # Use ci for exact lockfile deps
# Build (generates Tailwind CSS)
npm run build
# Start local server
python -m http.server 8000
# or
npx serve
Before Every PR
# Required checks
npm run format # Format CSS/HTML/MD
npm run lint # All lint checks
npm run test:unit # Or use shards for faster feedback
# Recommended for UI changes
npm run test:visual
Available Scripts
| Script | Purpose |
|---|---|
npm run build |
Full build (Tailwind + dist) |
npm run build:css |
Regenerate Tailwind only |
npm run format |
Format with Prettier |
npm run lint |
Run all linting checks |
npm run lint:css |
CSS token validation |
npm run lint:inline-styles |
Block inline styles |
npm run lint:tokens |
Design token enforcement |
npm run test:unit |
Full unit test suite |
npm run test:unit:shard1 |
Shard 1/3 (faster local dev) |
npm run test:unit:shard2 |
Shard 2/3 |
npm run test:unit:shard3 |
Shard 3/3 |
npm run test:dm:unit |
Direct message unit tests |
npm run test:dm:integration |
DM integration tests |
npm run test:e2e |
Headless E2E tests |
npm run test:visual |
Visual regression tests |
CI/CD Pipeline
The CI workflow (.github/workflows/ci.yml) runs on every push to main and all PRs:
| Job | Timeout | Description |
|---|---|---|
build |
45 min | Lint, build, visual regression |
unit-tests |
30 min | Sharded unit tests (3 shards) |
dm-unit-tests |
20 min | Direct message unit tests |
dm-integration-tests |
30 min | DM integration tests |
e2e-headless |
45 min | Playwright E2E tests |
Concurrency: cancel-in-progress: true — new commits cancel running jobs.
Code Conventions
Logging
Always use the logger utility, never call console.* directly:
import { logger } from './utils/logger.js';
logger.user.error('User-facing error'); // Production visible
logger.dev.log('Debug info'); // Dev mode only (IS_DEV_MODE)
Styling Rules
- Token-first: Use design tokens from
css/tokens.css, never raw hex colors - No inline styles:
style=attributes andelement.styleare blocked by lint - Semantic tokens: Use
bg,text,accent,border,danger, etc. - Theme scopes: Toggle themes via
data-themeattribute, not code
Nostr Event Schemas
All Nostr events must be defined in js/nostrEventSchemas.js:
import { buildVideoPostEvent, NOTE_TYPES } from './nostrEventSchemas.js';
const event = buildVideoPostEvent({
pubkey: hexPubkey,
created_at: Math.floor(Date.now() / 1000),
dTagValue: 'video-id',
content: {
version: 3,
title: 'My Video',
videoRootId: 'video-id',
url: 'https://example.com/video.mp4'
}
});
Magnet Handling
Critical rules — magnets are fragile:
import { safeDecodeMagnet, normalizeAndAugmentMagnet } from './magnetUtils.js';
// Always decode first
const raw = safeDecodeMagnet(userInput);
// Then normalize with hints
const enriched = normalizeAndAugmentMagnet(raw, { wsHint, xsHint });
// NEVER use new URL() on magnets — it corrupts hashes!
- WSS trackers only (from
js/constants.js) - Persist raw magnet strings, decode only at playback
- Include HTTPS
ws=/xs=hints when available
Architecture Pattern
Separation of concerns:
bitvidApp(js/app.js) — Orchestrator, manages app-wide state- UI Controllers — Handle specific UI components (e.g.,
ProfileModalController) - Services — Business logic (e.g.,
playbackService.js) - State — Central truth in
js/state/cache.js
Data flow:
- User action triggers controller event handler
- Controller invokes callback provided by
bitvidApp bitvidAppexecutes logic, updates central statebitvidAppnotifies controller to re-render
Feature Flags
Feature flags in js/constants.js gate experimental behavior:
| Flag | Default | Purpose |
|---|---|---|
URL_FIRST_ENABLED |
Depends on config | Try URL before magnet |
FEATURE_WATCH_HISTORY_V2 |
true | Watch history system |
FEATURE_PUBLISH_NIP71 |
false | NIP-71 video publishing |
FEATURE_SEARCH_FILTERS |
Dev mode only | Advanced search |
FEATURE_TRUST_SEEDS |
true | Baseline trust seeds |
Toggle at runtime:
import { setUrlFirstEnabled } from './constants.js';
setUrlFirstEnabled(false); // Disable URL-first playback
Nostr Integration
Key NIPs Used
| NIP | Purpose |
|---|---|
| NIP-07 | Browser extension signing |
| NIP-33 | Parameterized replaceable events (videos) |
| NIP-04 | Legacy DM encryption |
| NIP-44 | Modern encryption |
| NIP-46 | Remote signing |
| NIP-51 | Lists (mute, admin) |
| NIP-56 | Moderation reports |
| NIP-71 | Video events |
Signer Adapters
import { nostrClient } from './nostrClientFacade.js';
import { setActiveSigner } from './nostr/client.js';
// Register a signer
setActiveSigner({
pubkey,
signEvent: (event) => signer.sign(event),
nip04Encrypt: (target, text) => signer.nip04.encrypt(target, text),
nip04Decrypt: (actor, cipher) => signer.nip04.decrypt(actor, cipher),
// Optional: nip44Encrypt, nip44Decrypt
});
NIP-33 Addressing (Important!)
Video events are addressed by kind + pubkey + d-tag:
// CORRECT: Use the d-tag for addressing
const dTag = event.tags.find(t => t[0] === 'd')?.[1];
// WRONG: Don't use logical IDs like videoRootId for relay lookups
Testing Guidelines
Before Starting Work
- Read
KNOWN_ISSUES.mdfor pre-existing failures - Run relevant test shard to verify baseline
Running Tests
# Fast feedback during development
npm run test:unit:shard1
# Full suite before PR
npm run test:unit
# Visual changes
npm run test:visual
# DM features
npm run test:dm:unit && npm run test:dm:integration
# E2E journeys
npm run test:e2e
Test Artifacts
Failed visual tests store artifacts in artifacts/test-results/:
- Screenshots
- Videos
- Traces
View with: ./scripts/show-artifacts.sh
Common Tasks
Adding a New Nostr Event Type
- Define schema in
js/nostrEventSchemas.js - Add builder function
- Document in
docs/nostr-event-schemas.md - Add tests
Creating UI Components
- Create controller in
js/ui/ - Wire callbacks through
bitvidApp - Read state via provided getters, never directly
- Use design tokens for styling
Modifying Playback Behavior
- Check
js/services/playbackService.jsfor stream handling - Update
js/constants.jsfeature flags if needed - Test with both URL and magnet sources
- Document rollback steps in PR
Troubleshooting
Build Issues
# Browserslist warning
npx update-browserslist-db@latest
# Tailwind not regenerating
rm css/tailwind.generated.css && npm run build:css
Test Hangs
- Unit tests may hang after completion — use
Ctrl+C - Use shards for faster local runs
- Set
UNIT_TEST_TIMEOUT_MS=120000for slow tests
Lint Failures
- Inline styles: Move to CSS classes or tokens
- Hex colors: Use design tokens
- Design tokens: Use
theme()or existing utilities
Release Channels
- Main: Production track — preserve UX, atomic commits, feature flags default off
- Unstable: Experimentation — gate risky features behind flags
Emergency Response
If a change breaks playback or magnet handling:
- Revert immediately
- Note rollback in PR
- Document in AGENTS.md
Key Documentation
| Document | What It Covers |
|---|---|
AGENTS.md |
AI agent rules, mission, architectural decisions |
CONTRIBUTING.md |
Setup, PR process, DCO |
KNOWN_ISSUES.md |
Pre-existing test failures |
docs/nostr-event-schemas.md |
Event definitions |
docs/playback-fallback.md |
URL-first strategy |
docs/moderation/README.md |
Moderation system |
docs/logging.md |
Logger usage |
Quick Reference
Import Patterns
// Nostr client
import { nostrClient } from './nostrClientFacade.js';
// View events (analytics)
import { recordVideoView } from './nostrViewEventsFacade.js';
// Watch history
import { updateWatchHistoryListWithDefaultClient } from './nostrWatchHistoryFacade.js';
// Event building
import { buildVideoPostEvent } from './nostrEventSchemas.js';
// Feature flags
import { URL_FIRST_ENABLED, setUrlFirstEnabled } from './constants.js';
// Logger
import { logger } from './utils/logger.js';
Content Schema v3
{
version: 3,
title: string, // Required
url?: string, // HTTPS video URL
magnet?: string, // WebTorrent magnet
thumbnail?: string,
description?: string,
mode: 'live' | 'dev',
isPrivate: boolean,
deleted: boolean,
videoRootId: string // Stable identifier
}
Validation: Must have title + at least one of url or magnet.
Final Notes
- Read AGENTS.md first — it contains mission-critical architectural decisions
- Check KNOWN_ISSUES.md — avoid investigating pre-existing failures
- Use sharded tests — faster feedback during development
- Never commit generated CSS —
css/tailwind.generated.cssis gitignored - Token-first styling — no raw colors, no inline styles
- Keep magnets raw — decode only at playback time
- Document rollback steps — especially for playback changes