Files
c-relay/AGENTS.md
2025-09-30 05:32:23 -04:00

5.2 KiB

AGENTS.md - AI Agent Integration Guide

Project-Specific Information for AI Agents Working with C-Relay

Critical Build Commands

Primary Build Command

./make_and_restart_relay.sh

Never use make directly. The project requires the custom restart script which:

  • Handles database preservation/cleanup based on flags
  • Manages architecture-specific binary detection (x86/ARM64)
  • Performs automatic process cleanup and port management
  • Starts relay in background with proper logging

Architecture-Specific Binary Outputs

  • x86_64: ./build/c_relay_x86
  • ARM64: ./build/c_relay_arm64
  • Other: ./build/c_relay_$(ARCH)

Database File Naming Convention

  • Format: <relay_pubkey>.db (NOT .nrdb as shown in docs)
  • Location: Created in build/ directory during execution
  • Cleanup: Use --preserve-database flag to retain between builds

Critical Integration Issues

Event-Based Configuration System

  • No traditional config files - all configuration stored in config table
  • Admin private key shown only once on first startup
  • Configuration changes require cryptographically signed events
  • Database path determined by generated relay pubkey

First-Time Startup Sequence

  1. Relay generates admin keypair and relay keypair
  2. Creates database file with relay pubkey as filename
  3. Stores default configuration in config table
  4. CRITICAL: Admin private key displayed once and never stored on disk

Port Management

  • Default port 8888 with automatic fallback (8889, 8890, etc.)
  • Script performs port availability checking before libwebsockets binding
  • Process cleanup includes force-killing processes on port 8888

Database Schema Dependencies

  • Uses embedded SQL schema (sql_schema.h)
  • Schema version 4 with JSON tag storage
  • Critical: Event expiration filtering done at application level, not SQL level

Admin API Event Structure

{
  "kind": 23456,
  "content": "base64_nip44_encrypted_command_array",
  "tags": [
    ["p", "<relay_pubkey>"]
  ]
}

Configuration Commands (encrypted in content):

  • ["relay_description", "My Relay"]
  • ["max_subscriptions_per_client", "25"]
  • ["pow_min_difficulty", "16"]

Auth Rule Commands (encrypted in content):

  • ["blacklist", "pubkey", "hex_pubkey_value"]
  • ["whitelist", "pubkey", "hex_pubkey_value"]

Query Commands (encrypted in content):

  • ["auth_query", "all"]
  • ["system_command", "system_status"]

Process Management

# Kill existing relay processes
pkill -f "c_relay_"

# Check running processes
ps aux | grep c_relay_

# Force kill port binding
fuser -k 8888/tcp

Cross-Compilation Specifics

  • ARM64 requires explicit dependency installation: make install-arm64-deps
  • Uses aarch64-linux-gnu-gcc with specific library paths
  • PKG_CONFIG_PATH must be set for ARM64: /usr/lib/aarch64-linux-gnu/pkgconfig

Testing Integration

  • Tests expect relay running on default port
  • Use tests/quick_error_tests.sh for validation
  • Event configuration tests: tests/event_config_tests.sh

SystemD Integration Considerations

  • Service runs as c-relay user in /opt/c-relay
  • Database files created in WorkingDirectory automatically
  • No environment variables needed (event-based config)
  • Resource limits: 65536 file descriptors, 4096 processes

Development vs Production Differences

  • Development: make_and_restart_relay.sh (default database cleanup)
  • Production: make_and_restart_relay.sh --preserve-database
  • Debug build requires manual gdb attachment to architecture-specific binary

Critical File Dependencies

  • nostr_core_lib/ submodule must be initialized and built first
  • Version header auto-generated from git tags: src/version.h
  • Schema embedded in binary from src/sql_schema.h

WebSocket Protocol Specifics

  • Supports both WebSocket (Nostr protocol) and HTTP (NIP-11)
  • NIP-11 requires Accept: application/nostr+json header
  • CORS headers automatically added for NIP-11 compliance

Memory Management Notes

  • Persistent subscription system with thread-safe global manager
  • Per-session subscription limits enforced
  • Event filtering done at C level, not SQL level for NIP-40 expiration

Configuration Override Behavior

  • CLI port override only affects first-time startup
  • After database creation, all config comes from events
  • Database path cannot be changed after initialization

Non-Obvious Pitfalls

  1. Database Lock Issues: Script handles SQLite locking by killing existing processes first
  2. Port Race Conditions: Pre-check + libwebsockets binding can still fail due to timing
  3. Key Loss: Admin private key loss requires complete database deletion and restart
  4. Architecture Detection: Build system auto-detects but cross-compilation requires manual setup
  5. Event Storage: Ephemeral events (kind 20000-29999) accepted but not stored
  6. Signature Validation: All events validated with nostr_verify_event_signature() from nostr_core_lib

Quick Debugging Commands

# Check relay status
ps aux | grep c_relay_ && netstat -tln | grep 8888

# View logs
tail -f relay.log

# Test WebSocket connection
wscat -c ws://localhost:8888

# Test NIP-11 endpoint
curl -H "Accept: application/nostr+json" http://localhost:8888

# Find database files
find . -name "*.db" -type f