# AGENTS.md - AI Agent Integration Guide

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

## Critical Build Commands

### Primary Build Command
```bash
./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
```json
{
  "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
```bash
# 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
```bash
# 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