# AT Protocol PLC Command-Line Tools Command-line tools for working with AT Protocol PLC (Public Ledger of Credentials) DIDs. ## Tools ### plc-audit: DID Audit Log Validator Validates the cryptographic integrity of a DID's audit log from plc.directory. #### Features - 🔍 **Fetch Audit Logs**: Retrieves complete operation history from plc.directory - 🔐 **Cryptographic Validation**: Verifies all signatures using rotation keys - 🔗 **Chain Verification**: Validates operation chain linkage (prev references) - 📊 **Detailed Output**: Shows operation history and final DID state - ⚡ **Fast & Reliable**: Built with Rust for performance and safety #### Usage ```bash # Basic validation cargo run --bin plc-audit --features cli -- did:plc:z72i7hdynmk6r22z27h6tvur # Verbose mode (show all operations) cargo run --bin plc-audit --features cli -- did:plc:z72i7hdynmk6r22z27h6tvur --verbose # Quiet mode (VALID/INVALID only) cargo run --bin plc-audit --features cli -- did:plc:z72i7hdynmk6r22z27h6tvur --quiet # Custom PLC directory cargo run --bin plc-audit --features cli -- did:plc:example --plc-url https://custom.plc.directory ``` --- ### plc-fork-viz: Fork Visualizer Visualizes forks in a DID's operation chain, showing which operations won/lost based on rotation key priority and the 72-hour recovery window. #### Features - 🔀 **Fork Detection**: Identifies competing operations in the chain - 🔐 **Priority Analysis**: Determines which rotation key signed each operation - ⏱️ **Recovery Window**: Applies 72-hour recovery window rules - 📊 **Multiple Formats**: Tree, JSON, and Markdown visualization - 🎨 **Color Coding**: Green for canonical operations, red for rejected #### Usage ```bash # Basic fork visualization cargo run --bin plc-fork-viz --features cli -- did:plc:ewvi7nxzyoun6zhxrhs64oiz # Verbose mode (detailed operation info) cargo run --bin plc-fork-viz --features cli -- did:plc:ewvi7nxzyoun6zhxrhs64oiz --verbose # Show timestamps and recovery window calculations cargo run --bin plc-fork-viz --features cli -- did:plc:ewvi7nxzyoun6zhxrhs64oiz --timing # Show full DIDs/CIDs cargo run --bin plc-fork-viz --features cli -- did:plc:ewvi7nxzyoun6zhxrhs64oiz --full-ids # Output as JSON cargo run --bin plc-fork-viz --features cli -- did:plc:ewvi7nxzyoun6zhxrhs64oiz --format json # Output as Markdown cargo run --bin plc-fork-viz --features cli -- did:plc:ewvi7nxzyoun6zhxrhs64oiz --format markdown ``` #### Output Formats **Tree Format** (default): ``` Fork at operation referencing bafyre...abc123 ├─ 🔴 ✗ CID: bafyre...def456 │ Signed by: rotation_key[1] │ Reason: Invalidated by higher-priority key[0] within recovery window └─ 🟢 ✓ CID: bafyre...ghi789 Signed by: rotation_key[0] Status: CANONICAL (winner) ``` **JSON Format**: ```json [ { "prev_cid": "bafyre...", "winner_cid": "bafyre...", "operations": [...] } ] ``` **Markdown Format**: | Status | CID | Key Index | Timestamp | Reason | |--------|-----|-----------|-----------|--------| | ✅ Winner | bafyre...ghi789 | 0 | 2025-01-15 14:30:00 | Canonical operation | | ❌ Rejected | bafyre...def456 | 1 | 2025-01-15 10:00:00 | Invalidated by higher-priority key[0] | #### Fork Resolution Rules 1. **Rotation Key Priority**: Keys are ordered by array index (0 = highest priority) 2. **Recovery Window**: 72 hours from the first operation's timestamp 3. **First-Received Default**: The operation received first wins unless invalidated 4. **Higher Priority Override**: A higher-priority key can invalidate if: - It arrives within 72 hours - Its key index is lower (e.g., key[0] beats key[1]) #### Example: No Forks ```bash $ cargo run --bin plc-fork-viz --features cli -- did:plc:ewvi7nxzyoun6zhxrhs64oiz 🔍 Analyzing forks in: did:plc:ewvi7nxzyoun6zhxrhs64oiz Source: https://plc.directory 📊 Audit log contains 5 operations ✅ No forks detected - this is a linear operation chain All operations form a single canonical path from genesis to tip. ``` #### Example: Fork Detected ```bash $ cargo run --bin plc-fork-viz --features cli -- did:plc:z7x2k3j4m5n6 --timing 🔍 Analyzing forks in: did:plc:z7x2k3j4m5n6 Source: https://plc.directory 📊 Audit log contains 8 operations ⚠️ Detected 1 fork point(s) 📊 Fork Visualization (Tree Format) ═══════════════════════════════════════════════════════════════ Fork at operation referencing bafyre...abc123 ├─ 🔴 ✗ CID: bafyre...def456 │ Signed by: rotation_key[1] │ Timestamp: 2025-01-15 10:00:00 UTC │ Reason: Invalidated by higher-priority key[0] within recovery window │ └─ 🟢 ✓ CID: bafyre...ghi789 │ Signed by: rotation_key[0] │ Timestamp: 2025-01-15 14:00:00 UTC │ Status: CANONICAL (winner) ═══════════════════════════════════════════════════════════════ 📈 Summary: Total operations: 8 Fork points: 1 Rejected operations: 1 🔐 Fork Resolution Details: Fork 1: Winner is bafyre...ghi789 (signed by key[0]) ``` --- ## Building & Installation ### Build Both Tools ```bash cargo build --bins --features cli --release ``` ### Install to ~/.cargo/bin ```bash cargo install --path . --features cli ``` Then use directly: ```bash plc-audit did:plc:ewvi7nxzyoun6zhxrhs64oiz plc-fork-viz did:plc:ewvi7nxzyoun6zhxrhs64oiz ``` --- ## Common Workflows ### Workflow 1: Validate and Check for Forks ```bash # First validate the audit log $ plc-audit did:plc:ewvi7nxzyoun6zhxrhs64oiz ✅ Validation successful! # Then check for forks $ plc-fork-viz did:plc:ewvi7nxzyoun6zhxrhs64oiz ``` ### Workflow 2: Export Fork Data ```bash # Export as JSON for analysis $ plc-fork-viz did:plc:ewvi7nxzyoun6zhxrhs64oiz --format json > forks.json # Generate Markdown report $ plc-fork-viz did:plc:ewvi7nxzyoun6zhxrhs64oiz --format markdown > FORK_REPORT.md ``` ### Workflow 3: Monitor DIDs ```bash #!/bin/bash # Monitor a DID for changes and forks DID="did:plc:ewvi7nxzyoun6zhxrhs64oiz" # Validate if plc-audit $DID --quiet; then echo "✅ DID is valid" # Check for forks plc-fork-viz $DID --format json > /tmp/forks.json if [ -s /tmp/forks.json ]; then echo "⚠️ Forks detected!" plc-fork-viz $DID fi else echo "❌ DID validation failed!" exit 1 fi ``` --- ## Understanding Fork Visualization ### Symbols - 🌱 Genesis operation (creates the DID) - 🟢 ✓ Canonical operation (winner) - 🔴 ✗ Rejected operation (lost the fork) - ├─ Fork branch (more operations follow) - └─ Final fork branch ### Rejection Reasons 1. **"Invalidated by higher-priority key[N] within recovery window"** - A higher-priority rotation key signed a competing operation within 72 hours 2. **"Higher-priority key[N] but outside 72-hour recovery window (X hours late)"** - A higher-priority key tried to invalidate but arrived too late 3. **"Lower-priority key[N] (current winner has key[M])"** - This operation was signed by a lower-priority key and can't override --- ## Troubleshooting ### Error: "Invalid DID format" DID must follow format: `did:plc:<24 lowercase base32 characters>` ### Error: "Failed to fetch audit log" - Check internet connection - Verify DID exists on plc.directory - Try `--plc-url` for custom PLC directories ### No forks detected but expected - The DID may have a linear operation chain - All operations were submitted sequentially without conflicts --- ## Technical Details **plc-audit** validates: 1. DID format (prefix, length, base32 encoding) 2. Chain linkage (prev references) 3. Cryptographic signatures (ECDSA with P-256/secp256k1) 4. State consistency **plc-fork-viz** implements: 1. Fork detection (multiple operations with same prev CID) 2. Rotation key index resolution 3. Priority-based fork resolution 4. 72-hour recovery window enforcement Both tools use: - `reqwest` for HTTP requests - `atproto-plc` library for cryptographic operations - `clap` for command-line parsing --- ## See Also - [AT Protocol PLC Specification](https://atproto.com/specs/did-plc) - [Fork Resolution Implementation Report](../../FORK_RESOLUTION_REPORT.md) - [Implementation Summary](../../IMPLEMENTATION_SUMMARY.md) - [Library Documentation](../../README.md) --- ## License Dual-licensed under MIT or Apache-2.0, same as the parent library.