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#
# 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#
# 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:
[
{
"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#
- Rotation Key Priority: Keys are ordered by array index (0 = highest priority)
- Recovery Window: 72 hours from the first operation's timestamp
- First-Received Default: The operation received first wins unless invalidated
- 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#
$ 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#
$ 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#
cargo build --bins --features cli --release
Install to ~/.cargo/bin#
cargo install --path . --features cli
Then use directly:
plc-audit did:plc:ewvi7nxzyoun6zhxrhs64oiz
plc-fork-viz did:plc:ewvi7nxzyoun6zhxrhs64oiz
Common Workflows#
Workflow 1: Validate and Check for Forks#
# 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#
# 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#
#!/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#
-
"Invalidated by higher-priority key[N] within recovery window"
- A higher-priority rotation key signed a competing operation within 72 hours
-
"Higher-priority key[N] but outside 72-hour recovery window (X hours late)"
- A higher-priority key tried to invalidate but arrived too late
-
"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-urlfor 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:
- DID format (prefix, length, base32 encoding)
- Chain linkage (prev references)
- Cryptographic signatures (ECDSA with P-256/secp256k1)
- State consistency
plc-fork-viz implements:
- Fork detection (multiple operations with same prev CID)
- Rotation key index resolution
- Priority-based fork resolution
- 72-hour recovery window enforcement
Both tools use:
reqwestfor HTTP requestsatproto-plclibrary for cryptographic operationsclapfor command-line parsing
See Also#
- AT Protocol PLC Specification
- Fork Resolution Implementation Report
- Implementation Summary
- Library Documentation
License#
Dual-licensed under MIT or Apache-2.0, same as the parent library.