Files
TORCH/CLAUDE.md
T
2026-02-13 22:31:26 -05:00

20 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.


<<<<<<< Updated upstream Applies to all tasks unless direct session instructions override it.

Operating principles

  • Be repository-agnostic by default.
  • Make deterministic, auditable decisions.
  • Prefer minimal, reversible changes.
  • Leave clearer context for the next agent.

Standard execution workflow

  1. Load baseline context:
    • AGENTS.md
    • CONTRIBUTING.md
    • KNOWN_ISSUES.md
    • docs/agent-handoffs/README.md
    • recent notes in docs/agent-handoffs/learnings/ and docs/agent-handoffs/incidents/
  2. Translate the request into concrete outcomes.
  3. Implement the smallest safe change.
  4. Run relevant validation.
  5. Summarize evidence clearly (commands, outputs, and changed files).
  6. Record durable learnings/incidents when new reusable knowledge appears.

Quality checklist before finishing

  • Scope matches the user request.
  • Language and guidance remain generic unless project-specific detail is required.
  • Existing workflows were not unintentionally broken.
  • Validation coverage is appropriate for risk/impact.

Knowledge-sharing and handoff protocol

1) Search first

Before writing a new note, check for an existing related note and update it if applicable.

2) Write in the right place

  • docs/agent-handoffs/learnings/ for successful patterns.
  • docs/agent-handoffs/incidents/ for failures and mitigations.

3) Use generic, consistent names

  • Format: YYYY-MM-DD-short-topic.md
  • Keep names descriptive and repository-agnostic.

4) Use the required structure

Each note should include:

  • Context
  • Observation
  • Action taken
  • Validation performed
  • Recommendation for next agents

5) Promote active problems to KNOWN_ISSUES.md

If the problem is still reproducible or unresolved, add/update a KNOWN_ISSUES.md entry with status, impact, workaround, and last verified date.

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 22+: 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
js/testHarness.js Playwright test harness (window.__bitvidTest__)
tests/e2e/helpers/bitvidTestFixture.ts Reusable Playwright fixture for agent testing
scripts/agent/simple-relay.mjs Mock Nostr relay with HTTP seeding API
docs/nostr-event-schemas.md Event schema documentation
context/ Agent working state: current goal, scope, assumptions (see AGENTS.md §15)
todo/ Agent task checklist with done/blocked sections (see AGENTS.md §15)
decisions/ Agent decision log: choices, alternatives, rationale (see AGENTS.md §15)
test_logs/ Agent verification log: commands run and results (see AGENTS.md §15)

Development Workflow

Stashed changes

Initial Setup

<<<<<<< Updated upstream

  • KNOWN_ISSUES.md: currently active issues and workarounds.
  • docs/agent-handoffs/learnings/: reusable successes.
  • docs/agent-handoffs/incidents/: reusable failure analysis.
  • CONTRIBUTING.md: expectations for commits, PRs, and validation.

Writing style for agent notes

  • Prefer concise bullets over long prose.
  • Include exact commands when they improve reproducibility.
  • Clearly separate facts from assumptions.
  • End with a practical recommendation for the next agent.

Anti-patterns

  • Project/brand-specific assumptions in reusable docs.
  • Unnecessary broad refactors.
  • Claims of validation without executed checks.
  • Duplicate notes that fragment context across many files. =======
# 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 + verify)
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 lint:file-size Enforce file size limits
npm run lint:innerhtml Enforce innerHTML baseline
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:smoke Run critical path smoke tests
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
node scripts/agent/validate-events.mjs Validate Nostr event schemas

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

  1. Token-first: Use design tokens from css/tokens.css, never raw hex colors
  2. No inline styles: style= attributes and element.style are blocked by lint
  3. Semantic tokens: Use bg, text, accent, border, danger, etc.
  4. Theme scopes: Toggle themes via data-theme attribute, 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:

  1. User action triggers controller event handler
  2. Controller invokes callback provided by bitvidApp
  3. bitvidApp executes logic, updates central state
  4. bitvidApp notifies 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
FEATURE_TRUSTED_HIDE_CONTROLS true Trusted mute/spam hide controls
FEATURE_IMPROVED_COMMENT_FETCHING true Improved comment fetching logic

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

  1. Read KNOWN_ISSUES.md for pre-existing failures
  2. 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

Agent E2E Testing (Playwright)

bitvid includes a test harness for programmatic Playwright testing without browser extensions or real relays. See AGENTS.md Section 14 for the full reference. Quick start:

import { test, expect } from "./helpers/bitvidTestFixture";

test("my test", async ({ page, gotoApp, loginAs, seedEvent }) => {
  await seedEvent({ title: "Test Video", url: "https://example.com/v.mp4" });
  await gotoApp();
  await loginAs(page);
  // interact with the app using data-testid selectors
  await expect(page.locator('[data-testid="upload-button"]')).toBeVisible();
});

Key capabilities:

  • Programmatic login: loginAs(page) uses window.__bitvidTest__.loginWithNsec() — no modal interaction needed
  • Mock relay: Each test gets an isolated in-memory relay with HTTP seeding
  • Relay override: ?__test__=1&__testRelays__=ws://localhost:8877 redirects all connections
  • State inspection: window.__bitvidTest__.getAppState() returns login status, relays, etc.
  • Stable selectors: All key elements have data-testid attributes (see AGENTS.md Section 14)

Common Tasks

Adding a New Nostr Event Type

  1. Define schema in js/nostrEventSchemas.js
  2. Add builder function
  3. Document in docs/nostr-event-schemas.md
  4. Add tests

Creating UI Components

  1. Create controller in js/ui/
  2. Wire callbacks through bitvidApp
  3. Read state via provided getters, never directly
  4. Use design tokens for styling

Modifying Playback Behavior

  1. Check js/services/playbackService.js for stream handling
  2. Update js/constants.js feature flags if needed
  3. Test with both URL and magnet sources
  4. 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=120000 for 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 & Promotion Pipeline

Code flows through three branches with increasing stability:

unstable  →  beta  →  main
 (dev)      (soak)   (prod)
Branch Purpose CI Required Manual QA
unstable Active development, AI agent PRs land here Yes No
beta Stabilization soak (hosted for testing) Yes Yes — hosted domain
main Production Yes Verified via beta

Promotion rules:

  • unstable → beta: After a batch of improvements passes CI and local testing
  • beta → main: After weeks of soak time on the beta hosted domain with no regressions
  • Never push directly to main or beta — always promote from the previous stage

Emergency Response

If a change breaks playback or magnet handling:

  1. Revert immediately
  2. Note rollback in PR
  3. Document in AGENTS.md

Multi-Agent Development Workflow

This project uses multiple AI coding agents working in parallel:

  • Claude Code — Refactoring, convention enforcement, codebase-wide changes
  • OpenAI Codex — Isolated feature implementation with clear specs
  • Google Jules — Issue triage and straightforward bug fixes

Coordination Rules

All agents must follow the subsystem boundaries and PR discipline rules in AGENTS.md Section 12. The key principles:

  1. Check before you start. Look at open PRs before beginning work by running:
    curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
    
    If another agent has an open PR touching the same files, stop and flag the conflict.
  2. One subsystem per PR. Don't mix unrelated changes. A lint fix and a feature addition are two separate PRs.
  3. js/app.js is single-writer. Only one PR at a time should modify the main orchestrator.
  4. Merge fast, branch short. Long-lived branches cause exponential merge pain with multiple agents. Keep PRs small and mergeable in one sitting.

For Human Maintainers

When assigning work to agents:

  • Update the "Currently In-Flight Work" section in AGENTS.md to reserve subsystems
  • Avoid sending two agents at the same subsystem simultaneously
  • Review and merge agent PRs promptly to keep the queue short — stale PRs compound conflicts
  • Use PR title prefixes ([nostr-core], [ui], [playback], etc.) to make scope visible

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
docs/agents/TORCH.md TORCH distributed task locking protocol
context/ / todo/ / decisions/ / test_logs/ Agent persistent state files (see AGENTS.md §15)

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

  1. Read AGENTS.md first — it contains mission-critical architectural decisions and the Agent Execution Protocol (§15)
  2. Check KNOWN_ISSUES.md — avoid investigating pre-existing failures
  3. Use sharded tests — faster feedback during development
  4. Never commit generated CSS — css/tailwind.generated.css is gitignored
  5. Token-first styling — no raw colors, no inline styles
  6. Keep magnets raw — decode only at playback time
  7. Document rollback steps — especially for playback changes

Stashed changes