diff options
| -rw-r--r-- | AGENTS.md | 560 | ||||
| -rw-r--r-- | CLEANUP_SUMMARY.md | 448 | ||||
| -rw-r--r-- | CURRENT_STATUS.md | 464 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-architecture-investigation.md (renamed from INVESTIGATION_COMPLETE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-compliance-test-proposal.md (renamed from COMPLIANCE_TEST_PROPOSAL.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-compliance-testing-report.md (renamed from REPORT_COMPLIANCE_TESTING.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-documentation-index.md (renamed from DOCUMENTATION_INDEX.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-files-created.md (renamed from FILES_CREATED.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-final-audit-report.md (renamed from FINAL_AUDIT_REPORT.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-final-summary.md (renamed from FINAL_SUMMARY.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-grasp-audit-implementation.md (renamed from GRASP_AUDIT_IMPLEMENTATION_SUMMARY.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-grasp-audit-plan.md (renamed from GRASP_AUDIT_PLAN.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-implementation-complete.md (renamed from IMPLEMENTATION_COMPLETE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-quick-reference.md (renamed from QUICK_REFERENCE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-review-summary.md (renamed from REVIEW_SUMMARY.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-smoke-test-report.md (renamed from SMOKE_TEST_REPORT.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-start-here.md (renamed from START_HERE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-test-breakdown.md (renamed from TEST_BREAKDOWN.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-03-verification-complete.md (renamed from VERIFICATION_COMPLETE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-audit-status-report.md (renamed from AUDIT_SYSTEM_STATUS_REPORT.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-audit-system-fixed.md (renamed from AUDIT_SYSTEM_FIXED.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-compilation-fixes.md (renamed from COMPILATION_FIXES.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-flake-migration.md (renamed from FLAKE_MIGRATION_COMPLETE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-next-prompt.md (renamed from next_prompt.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-next-session-quickstart.md (renamed from NEXT_SESSION_QUICKSTART.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-nostr-sdk-upgrade.md (renamed from NOSTR_SDK_0.43_UPGRADE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-ready-for-next-phase.md (renamed from READY_FOR_NEXT_PHASE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-session-complete-1.md (renamed from SESSION_COMPLETE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-session-complete-2.md (renamed from SESSION_COMPLETE_2025_11_04.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-session-continuation.md (renamed from SESSION_CONTINUATION_COMPLETE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-session-summary.md (renamed from SESSION_2025_11_04_SUMMARY.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-tag-migration-summary.md (renamed from TAG_MIGRATION_SUMMARY.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-tag-migration.md (renamed from TAG_MIGRATION_COMPLETE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/2025-11-04-upgrade-complete.md (renamed from UPGRADE_COMPLETE.md) | 0 | ||||
| -rw-r--r-- | docs/archive/README.md | 158 | ||||
| -rw-r--r-- | docs/learnings/grasp-audit.md | 498 | ||||
| -rw-r--r-- | docs/learnings/nix-flakes.md | 423 | ||||
| -rw-r--r-- | docs/learnings/nostr-sdk.md | 577 |
38 files changed, 3128 insertions, 0 deletions
diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..c063f68 --- /dev/null +++ b/AGENTS.md | |||
| @@ -0,0 +1,560 @@ | |||
| 1 | # AI Agent Guidelines for ngit-grasp | ||
| 2 | |||
| 3 | **Purpose:** Ensure AI agents (and humans) maintain consistent documentation practices and avoid common pitfalls. | ||
| 4 | |||
| 5 | **Last Updated:** November 4, 2025 | ||
| 6 | |||
| 7 | --- | ||
| 8 | |||
| 9 | ## 📁 Documentation Structure | ||
| 10 | |||
| 11 | ### Overview | ||
| 12 | |||
| 13 | We maintain a **clean, hierarchical documentation structure** to avoid documentation sprawl. All working documents have a defined lifecycle and location. | ||
| 14 | |||
| 15 | ``` | ||
| 16 | ngit-grasp/ | ||
| 17 | ├── README.md # Project overview (keep updated) | ||
| 18 | ├── AGENTS.md # This file - agent guidelines | ||
| 19 | ├── CHANGELOG.md # User-facing changes (semver) | ||
| 20 | │ | ||
| 21 | ├── docs/ # Permanent technical documentation | ||
| 22 | │ ├── README.md # Docs navigation guide | ||
| 23 | │ ├── ARCHITECTURE.md # System architecture | ||
| 24 | │ ├── TEST_STRATEGY.md # Testing approach | ||
| 25 | │ ├── GIT_PROTOCOL.md # Git protocol reference | ||
| 26 | │ ├── COMPARISON.md # vs other implementations | ||
| 27 | │ ├── GETTING_STARTED.md # Setup guide | ||
| 28 | │ └── DECISION_SUMMARY.md # Key architectural decisions | ||
| 29 | │ | ||
| 30 | ├── docs/archive/ # Completed session/phase docs | ||
| 31 | │ ├── 2025-11-04-tag-migration.md | ||
| 32 | │ ├── 2025-11-04-flake-migration.md | ||
| 33 | │ └── 2025-11-03-architecture-investigation.md | ||
| 34 | │ | ||
| 35 | ├── docs/learnings/ # Extracted knowledge (permanent) | ||
| 36 | │ ├── nix-flakes.md # Flake gotchas and patterns | ||
| 37 | │ ├── nostr-sdk.md # nostr-sdk patterns and upgrades | ||
| 38 | │ └── git-http-backend.md # Git protocol learnings | ||
| 39 | │ | ||
| 40 | ├── grasp-audit/ # Audit tool subproject | ||
| 41 | │ ├── README.md # Main audit docs | ||
| 42 | │ ├── QUICK_START.md # Getting started | ||
| 43 | │ └── docs/ | ||
| 44 | │ └── archive/ # Audit-specific archives | ||
| 45 | │ | ||
| 46 | └── .ai/ # AI assistant context (ignored in git) | ||
| 47 | └── history/ # Conversation history | ||
| 48 | ``` | ||
| 49 | |||
| 50 | --- | ||
| 51 | |||
| 52 | ## 📋 Document Lifecycle | ||
| 53 | |||
| 54 | ### 1. Working Documents (Root Level) | ||
| 55 | |||
| 56 | **Purpose:** Active development, session notes, status reports | ||
| 57 | **Location:** Project root | ||
| 58 | **Lifecycle:** Created → Updated → Archived | ||
| 59 | **Retention:** Archive after completion, delete if obsolete | ||
| 60 | |||
| 61 | **Examples:** | ||
| 62 | - `TAG_MIGRATION_COMPLETE.md` → Archive when next phase starts | ||
| 63 | - `SESSION_2025_11_04_SUMMARY.md` → Archive at session end | ||
| 64 | - `NEXT_STEPS.md` → Update continuously, archive when complete | ||
| 65 | |||
| 66 | **Rules:** | ||
| 67 | - ✅ Use descriptive names with dates: `YYYY-MM-DD-description.md` | ||
| 68 | - ✅ Mark status clearly: `[WIP]`, `[COMPLETE]`, `[ARCHIVED]` | ||
| 69 | - ✅ Include date and context at top | ||
| 70 | - ❌ Don't let root accumulate more than 5-10 working docs | ||
| 71 | - ❌ Don't create duplicates (merge or link instead) | ||
| 72 | |||
| 73 | ### 2. Permanent Documentation (docs/) | ||
| 74 | |||
| 75 | **Purpose:** Long-term reference, architecture, guides | ||
| 76 | **Location:** `docs/` | ||
| 77 | **Lifecycle:** Created → Maintained → Updated | ||
| 78 | **Retention:** Permanent (version controlled) | ||
| 79 | |||
| 80 | **Examples:** | ||
| 81 | - `docs/ARCHITECTURE.md` - System design | ||
| 82 | - `docs/TEST_STRATEGY.md` - Testing approach | ||
| 83 | - `docs/learnings/nix-flakes.md` - Extracted knowledge | ||
| 84 | |||
| 85 | **Rules:** | ||
| 86 | - ✅ Keep updated as project evolves | ||
| 87 | - ✅ Use clear structure and headings | ||
| 88 | - ✅ Link between related docs | ||
| 89 | - ❌ Don't duplicate information (use links) | ||
| 90 | - ❌ Don't include session-specific details | ||
| 91 | |||
| 92 | ### 3. Archive (docs/archive/) | ||
| 93 | |||
| 94 | **Purpose:** Historical record, completed phases | ||
| 95 | **Location:** `docs/archive/` | ||
| 96 | **Lifecycle:** Moved from root → Archived | ||
| 97 | **Retention:** Permanent (for reference) | ||
| 98 | |||
| 99 | **Examples:** | ||
| 100 | - `docs/archive/2025-11-04-tag-migration.md` | ||
| 101 | - `docs/archive/2025-11-03-architecture-investigation.md` | ||
| 102 | |||
| 103 | **Rules:** | ||
| 104 | - ✅ Rename with date prefix when archiving | ||
| 105 | - ✅ Add "ARCHIVED" marker at top | ||
| 106 | - ✅ Extract learnings to docs/learnings/ first | ||
| 107 | - ❌ Don't modify after archiving | ||
| 108 | - ❌ Don't reference in active documentation | ||
| 109 | |||
| 110 | ### 4. Learnings (docs/learnings/) | ||
| 111 | |||
| 112 | **Purpose:** Reusable knowledge, gotchas, patterns | ||
| 113 | **Location:** `docs/learnings/` | ||
| 114 | **Lifecycle:** Extracted → Maintained → Updated | ||
| 115 | **Retention:** Permanent (living documents) | ||
| 116 | |||
| 117 | **Examples:** | ||
| 118 | - `docs/learnings/nix-flakes.md` - Flake patterns and gotchas | ||
| 119 | - `docs/learnings/nostr-sdk.md` - SDK upgrade notes | ||
| 120 | - `docs/learnings/git-http-backend.md` - Git protocol tips | ||
| 121 | |||
| 122 | **Rules:** | ||
| 123 | - ✅ Extract from session docs before archiving | ||
| 124 | - ✅ Organize by topic, not by session | ||
| 125 | - ✅ Include code examples | ||
| 126 | - ✅ Update as we learn more | ||
| 127 | - ❌ Don't duplicate official docs (link instead) | ||
| 128 | |||
| 129 | --- | ||
| 130 | |||
| 131 | ## 🔄 Cleanup Process | ||
| 132 | |||
| 133 | ### When to Clean Up | ||
| 134 | |||
| 135 | **Trigger:** Root directory has >10 markdown files | ||
| 136 | **Frequency:** End of each major phase or weekly | ||
| 137 | **Responsibility:** AI agents should proactively suggest cleanup | ||
| 138 | |||
| 139 | ### Cleanup Steps | ||
| 140 | |||
| 141 | 1. **Identify Completed Documents** | ||
| 142 | ```bash | ||
| 143 | # Find old working docs | ||
| 144 | ls -lt *.md | head -20 | ||
| 145 | ``` | ||
| 146 | |||
| 147 | 2. **Extract Learnings** | ||
| 148 | - Review each completed doc | ||
| 149 | - Extract gotchas, patterns, solutions | ||
| 150 | - Add to appropriate `docs/learnings/*.md` | ||
| 151 | |||
| 152 | 3. **Archive Completed Work** | ||
| 153 | ```bash | ||
| 154 | # Move to archive with date prefix | ||
| 155 | mv TAG_MIGRATION_COMPLETE.md docs/archive/2025-11-04-tag-migration.md | ||
| 156 | ``` | ||
| 157 | |||
| 158 | 4. **Delete Obsolete Documents** | ||
| 159 | - Duplicates (keep most recent/complete) | ||
| 160 | - Superseded documents | ||
| 161 | - Pure status reports (no learnings) | ||
| 162 | |||
| 163 | 5. **Update References** | ||
| 164 | - Update links in active docs | ||
| 165 | - Update README.md if needed | ||
| 166 | - Commit changes | ||
| 167 | |||
| 168 | ### Example Cleanup | ||
| 169 | |||
| 170 | ```bash | ||
| 171 | # Before cleanup (36 files in root!) | ||
| 172 | ls *.md | wc -l | ||
| 173 | # 36 | ||
| 174 | |||
| 175 | # After cleanup (5-8 files in root) | ||
| 176 | ls *.md | ||
| 177 | # README.md | ||
| 178 | # AGENTS.md | ||
| 179 | # CHANGELOG.md | ||
| 180 | # CURRENT_STATUS.md | ||
| 181 | # NEXT_STEPS.md | ||
| 182 | |||
| 183 | # Archived | ||
| 184 | ls docs/archive/ | ||
| 185 | # 2025-11-04-tag-migration.md | ||
| 186 | # 2025-11-04-flake-migration.md | ||
| 187 | # 2025-11-03-architecture-investigation.md | ||
| 188 | # ... | ||
| 189 | |||
| 190 | # Learnings extracted | ||
| 191 | ls docs/learnings/ | ||
| 192 | # nix-flakes.md | ||
| 193 | # nostr-sdk.md | ||
| 194 | # git-http-backend.md | ||
| 195 | ``` | ||
| 196 | |||
| 197 | --- | ||
| 198 | |||
| 199 | ## 🚨 Common Gotchas | ||
| 200 | |||
| 201 | ### Nix Flakes | ||
| 202 | |||
| 203 | **Always use `nix develop`, not `nix-shell`** | ||
| 204 | |||
| 205 | ```bash | ||
| 206 | # ✅ Correct | ||
| 207 | cd grasp-audit | ||
| 208 | nix develop | ||
| 209 | nix develop -c cargo build | ||
| 210 | |||
| 211 | # ❌ Wrong | ||
| 212 | nix-shell | ||
| 213 | nix-shell --run "cargo build" | ||
| 214 | ``` | ||
| 215 | |||
| 216 | **Why:** We use `flake.nix`, not `shell.nix`. See `docs/learnings/nix-flakes.md`. | ||
| 217 | |||
| 218 | **Flake Commands:** | ||
| 219 | ```bash | ||
| 220 | # Show flake outputs | ||
| 221 | nix flake show | ||
| 222 | |||
| 223 | # Update flake inputs | ||
| 224 | nix flake update | ||
| 225 | |||
| 226 | # Build package | ||
| 227 | nix build | ||
| 228 | |||
| 229 | # Run package | ||
| 230 | nix run | ||
| 231 | ``` | ||
| 232 | |||
| 233 | ### Git Subprojects | ||
| 234 | |||
| 235 | **grasp-audit is a subproject with its own flake** | ||
| 236 | |||
| 237 | ```bash | ||
| 238 | # ✅ Correct - enter grasp-audit environment | ||
| 239 | cd grasp-audit | ||
| 240 | nix develop | ||
| 241 | cargo build | ||
| 242 | |||
| 243 | # ❌ Wrong - can't build from root | ||
| 244 | cd ngit-grasp | ||
| 245 | cargo build # This won't find grasp-audit | ||
| 246 | ``` | ||
| 247 | |||
| 248 | **Why:** `grasp-audit/` has its own `Cargo.toml` and `flake.nix`. | ||
| 249 | |||
| 250 | ### nostr-sdk Versions | ||
| 251 | |||
| 252 | **We use nostr-sdk 0.43.x (latest stable)** | ||
| 253 | |||
| 254 | ```toml | ||
| 255 | # ✅ Correct | ||
| 256 | [dependencies] | ||
| 257 | nostr-sdk = "0.43" | ||
| 258 | |||
| 259 | # ❌ Wrong | ||
| 260 | nostr-sdk = "0.35" # Old version, breaking changes | ||
| 261 | ``` | ||
| 262 | |||
| 263 | **Why:** We upgraded from 0.35 to 0.43. See `docs/learnings/nostr-sdk.md` for migration notes. | ||
| 264 | |||
| 265 | **Common Breaking Changes:** | ||
| 266 | - `EventBuilder::new()` signature changed | ||
| 267 | - Tag API changed to `Tag::custom()` | ||
| 268 | - Filter API changed | ||
| 269 | - See archived upgrade docs for details | ||
| 270 | |||
| 271 | ### Testing Patterns | ||
| 272 | |||
| 273 | **Integration tests require relay** | ||
| 274 | |||
| 275 | ```bash | ||
| 276 | # ✅ Correct - start relay first | ||
| 277 | docker run --rm -p 7000:7000 scsibug/nostr-rs-relay | ||
| 278 | |||
| 279 | # Then run tests | ||
| 280 | cd grasp-audit | ||
| 281 | nix develop -c cargo test --ignored | ||
| 282 | |||
| 283 | # ❌ Wrong - integration tests will fail | ||
| 284 | cargo test --ignored # No relay running | ||
| 285 | ``` | ||
| 286 | |||
| 287 | **Test Organization:** | ||
| 288 | ```rust | ||
| 289 | // Unit tests (no relay needed) | ||
| 290 | #[cfg(test)] | ||
| 291 | mod tests { | ||
| 292 | #[test] | ||
| 293 | fn test_something() { } | ||
| 294 | } | ||
| 295 | |||
| 296 | // Integration tests (relay required) | ||
| 297 | #[cfg(test)] | ||
| 298 | mod tests { | ||
| 299 | #[test] | ||
| 300 | #[ignore] // Requires relay | ||
| 301 | fn test_against_relay() { } | ||
| 302 | } | ||
| 303 | ``` | ||
| 304 | |||
| 305 | ### Documentation Updates | ||
| 306 | |||
| 307 | **Keep README.md synchronized** | ||
| 308 | |||
| 309 | When you: | ||
| 310 | - Complete a major feature → Update README.md status | ||
| 311 | - Change architecture → Update docs/ARCHITECTURE.md | ||
| 312 | - Add dependencies → Update README.md tech stack | ||
| 313 | - Change workflow → Update docs/GETTING_STARTED.md | ||
| 314 | |||
| 315 | **Don't:** | ||
| 316 | - Create duplicate documentation | ||
| 317 | - Leave stale status markers | ||
| 318 | - Forget to update CHANGELOG.md for user-facing changes | ||
| 319 | |||
| 320 | --- | ||
| 321 | |||
| 322 | ## 📝 Writing Guidelines | ||
| 323 | |||
| 324 | ### Markdown Style | ||
| 325 | |||
| 326 | ```markdown | ||
| 327 | # Title (H1 - only one per file) | ||
| 328 | |||
| 329 | **Date:** YYYY-MM-DD | ||
| 330 | **Status:** [WIP|COMPLETE|ARCHIVED] | ||
| 331 | |||
| 332 | ## Section (H2) | ||
| 333 | |||
| 334 | ### Subsection (H3) | ||
| 335 | |||
| 336 | **Bold** for emphasis, `code` for commands/code. | ||
| 337 | |||
| 338 | - Bullet lists for items | ||
| 339 | - Keep consistent style | ||
| 340 | |||
| 341 | 1. Numbered lists for sequences | ||
| 342 | 2. Use when order matters | ||
| 343 | |||
| 344 | ✅ Use emoji for status (sparingly) | ||
| 345 | ❌ Don't overuse emoji | ||
| 346 | |||
| 347 | \`\`\`bash | ||
| 348 | # Code blocks with language | ||
| 349 | cargo build | ||
| 350 | \`\`\` | ||
| 351 | ``` | ||
| 352 | |||
| 353 | ### Status Markers | ||
| 354 | |||
| 355 | - `[WIP]` - Work in progress | ||
| 356 | - `[COMPLETE]` - Finished, may be archived | ||
| 357 | - `[ARCHIVED]` - Moved to archive, historical only | ||
| 358 | - `✅` - Success/complete | ||
| 359 | - `❌` - Failure/incorrect | ||
| 360 | - `⏳` - In progress | ||
| 361 | - `🔜` - Planned/next | ||
| 362 | |||
| 363 | ### Document Headers | ||
| 364 | |||
| 365 | ```markdown | ||
| 366 | # Document Title | ||
| 367 | |||
| 368 | **Purpose:** One-line purpose | ||
| 369 | **Date:** YYYY-MM-DD | ||
| 370 | **Status:** [WIP|COMPLETE|ARCHIVED] | ||
| 371 | **Related:** Links to related docs | ||
| 372 | |||
| 373 | --- | ||
| 374 | |||
| 375 | ## Content starts here | ||
| 376 | ``` | ||
| 377 | |||
| 378 | --- | ||
| 379 | |||
| 380 | ## 🤖 AI Agent Responsibilities | ||
| 381 | |||
| 382 | ### Before Creating New Documents | ||
| 383 | |||
| 384 | 1. **Check if document already exists** | ||
| 385 | ```bash | ||
| 386 | find . -name "*keyword*.md" | ||
| 387 | ``` | ||
| 388 | |||
| 389 | 2. **Check if information can be added to existing doc** | ||
| 390 | - Prefer updating over creating | ||
| 391 | - Use sections/subsections | ||
| 392 | |||
| 393 | 3. **Determine correct location** | ||
| 394 | - Working doc → Root | ||
| 395 | - Permanent → docs/ | ||
| 396 | - Learning → docs/learnings/ | ||
| 397 | - Historical → docs/archive/ | ||
| 398 | |||
| 399 | 4. **Use descriptive names with dates** | ||
| 400 | - `YYYY-MM-DD-description.md` for working docs | ||
| 401 | - `topic-name.md` for permanent docs | ||
| 402 | |||
| 403 | ### During Development | ||
| 404 | |||
| 405 | 1. **Update status markers** | ||
| 406 | - Mark WIP → COMPLETE when done | ||
| 407 | - Update README.md status section | ||
| 408 | |||
| 409 | 2. **Extract learnings as you go** | ||
| 410 | - Add gotchas to docs/learnings/ | ||
| 411 | - Don't wait until cleanup | ||
| 412 | |||
| 413 | 3. **Keep documentation DRY** | ||
| 414 | - Link to existing docs | ||
| 415 | - Don't duplicate information | ||
| 416 | |||
| 417 | ### End of Session | ||
| 418 | |||
| 419 | 1. **Suggest cleanup if needed** | ||
| 420 | - Count root .md files | ||
| 421 | - Suggest archiving completed docs | ||
| 422 | |||
| 423 | 2. **Create session summary** | ||
| 424 | - What was accomplished | ||
| 425 | - What's next | ||
| 426 | - Any blockers | ||
| 427 | |||
| 428 | 3. **Update permanent docs** | ||
| 429 | - Sync README.md with reality | ||
| 430 | - Update relevant docs/ files | ||
| 431 | |||
| 432 | ### Cleanup Time | ||
| 433 | |||
| 434 | 1. **Review all root .md files** | ||
| 435 | 2. **Extract learnings to docs/learnings/** | ||
| 436 | 3. **Archive completed work to docs/archive/** | ||
| 437 | 4. **Delete obsolete duplicates** | ||
| 438 | 5. **Update links in active docs** | ||
| 439 | 6. **Commit with clear message** | ||
| 440 | |||
| 441 | --- | ||
| 442 | |||
| 443 | ## 🎯 Quality Checklist | ||
| 444 | |||
| 445 | ### For Every Document | ||
| 446 | |||
| 447 | - [ ] Clear purpose stated at top | ||
| 448 | - [ ] Date included | ||
| 449 | - [ ] Status marker present | ||
| 450 | - [ ] Proper heading hierarchy (H1 → H2 → H3) | ||
| 451 | - [ ] Code blocks have language specified | ||
| 452 | - [ ] Links are valid and relative | ||
| 453 | - [ ] No duplicate information | ||
| 454 | - [ ] Spell-checked and readable | ||
| 455 | |||
| 456 | ### For Working Documents | ||
| 457 | |||
| 458 | - [ ] Descriptive filename with date | ||
| 459 | - [ ] Will be archived or deleted when done | ||
| 460 | - [ ] Not duplicating permanent docs | ||
| 461 | - [ ] Learnings extracted to docs/learnings/ | ||
| 462 | |||
| 463 | ### For Permanent Documents | ||
| 464 | |||
| 465 | - [ ] In correct docs/ subdirectory | ||
| 466 | - [ ] Linked from docs/README.md | ||
| 467 | - [ ] Updated as project evolves | ||
| 468 | - [ ] No session-specific details | ||
| 469 | - [ ] Serves long-term purpose | ||
| 470 | |||
| 471 | ### For Archived Documents | ||
| 472 | |||
| 473 | - [ ] Moved to docs/archive/ | ||
| 474 | - [ ] Renamed with date prefix | ||
| 475 | - [ ] ARCHIVED marker at top | ||
| 476 | - [ ] Learnings extracted first | ||
| 477 | - [ ] Not referenced in active docs | ||
| 478 | |||
| 479 | --- | ||
| 480 | |||
| 481 | ## 📚 Reference Documents | ||
| 482 | |||
| 483 | ### Must Read | ||
| 484 | - **This file (AGENTS.md)** - Guidelines for documentation | ||
| 485 | - **README.md** - Project overview | ||
| 486 | - **docs/README.md** - Documentation navigation | ||
| 487 | |||
| 488 | ### Key Technical Docs | ||
| 489 | - **docs/ARCHITECTURE.md** - System design | ||
| 490 | - **docs/TEST_STRATEGY.md** - Testing approach | ||
| 491 | - **docs/GETTING_STARTED.md** - Setup guide | ||
| 492 | |||
| 493 | ### Learnings (Gotchas) | ||
| 494 | - **docs/learnings/nix-flakes.md** - Nix flake patterns | ||
| 495 | - **docs/learnings/nostr-sdk.md** - nostr-sdk notes | ||
| 496 | - **docs/learnings/git-http-backend.md** - Git protocol tips | ||
| 497 | |||
| 498 | --- | ||
| 499 | |||
| 500 | ## 🔗 Quick Links | ||
| 501 | |||
| 502 | - [Project README](README.md) | ||
| 503 | - [Documentation Index](docs/README.md) | ||
| 504 | - [Architecture](docs/ARCHITECTURE.md) | ||
| 505 | - [Learnings](docs/learnings/) | ||
| 506 | - [Archive](docs/archive/) | ||
| 507 | |||
| 508 | --- | ||
| 509 | |||
| 510 | ## 💡 Tips for Success | ||
| 511 | |||
| 512 | 1. **Less is more** - Prefer updating over creating | ||
| 513 | 2. **Archive often** - Keep root clean | ||
| 514 | 3. **Extract learnings** - Make knowledge reusable | ||
| 515 | 4. **Link, don't duplicate** - DRY applies to docs too | ||
| 516 | 5. **Date everything** - Context is important | ||
| 517 | 6. **Use descriptive names** - Future you will thank you | ||
| 518 | 7. **Check before creating** - Document might already exist | ||
| 519 | 8. **Update as you go** - Don't wait for cleanup time | ||
| 520 | |||
| 521 | --- | ||
| 522 | |||
| 523 | ## 🚀 Next Steps | ||
| 524 | |||
| 525 | After reading this: | ||
| 526 | |||
| 527 | 1. **Review current documentation structure** | ||
| 528 | ```bash | ||
| 529 | ls -la *.md | ||
| 530 | ls -la docs/ | ||
| 531 | ``` | ||
| 532 | |||
| 533 | 2. **Identify cleanup candidates** | ||
| 534 | - Completed working docs | ||
| 535 | - Obsolete duplicates | ||
| 536 | - Session summaries | ||
| 537 | |||
| 538 | 3. **Extract learnings** | ||
| 539 | - Review completed docs | ||
| 540 | - Add to docs/learnings/ | ||
| 541 | |||
| 542 | 4. **Archive and clean** | ||
| 543 | - Move to docs/archive/ | ||
| 544 | - Delete obsolete files | ||
| 545 | - Update links | ||
| 546 | |||
| 547 | 5. **Commit changes** | ||
| 548 | ```bash | ||
| 549 | git add . | ||
| 550 | git commit -m "docs: cleanup and reorganization" | ||
| 551 | ``` | ||
| 552 | |||
| 553 | --- | ||
| 554 | |||
| 555 | **Remember:** Good documentation structure is like good code structure - it makes everything easier. | ||
| 556 | |||
| 557 | --- | ||
| 558 | |||
| 559 | *Last updated: November 4, 2025* | ||
| 560 | *Status: ✅ Active guidelines* | ||
diff --git a/CLEANUP_SUMMARY.md b/CLEANUP_SUMMARY.md new file mode 100644 index 0000000..8ffce92 --- /dev/null +++ b/CLEANUP_SUMMARY.md | |||
| @@ -0,0 +1,448 @@ | |||
| 1 | # Documentation Cleanup - November 4, 2025 | ||
| 2 | |||
| 3 | **Purpose:** Summary of documentation reorganization | ||
| 4 | **Status:** ✅ Complete | ||
| 5 | |||
| 6 | --- | ||
| 7 | |||
| 8 | ## Summary | ||
| 9 | |||
| 10 | Cleaned up **32 markdown files** from project root, organizing them into a clear, maintainable structure. | ||
| 11 | |||
| 12 | **Before:** 32 files in root (documentation sprawl) | ||
| 13 | **After:** 3 files in root (clean structure) | ||
| 14 | |||
| 15 | --- | ||
| 16 | |||
| 17 | ## What Changed | ||
| 18 | |||
| 19 | ### Root Directory | ||
| 20 | |||
| 21 | **Before:** | ||
| 22 | ``` | ||
| 23 | 32 markdown files including: | ||
| 24 | - Session summaries | ||
| 25 | - Status reports | ||
| 26 | - Migration docs | ||
| 27 | - Implementation reports | ||
| 28 | - Quick references | ||
| 29 | - Planning documents | ||
| 30 | ``` | ||
| 31 | |||
| 32 | **After:** | ||
| 33 | ``` | ||
| 34 | 3 essential files: | ||
| 35 | - README.md # Project overview | ||
| 36 | - AGENTS.md # AI agent guidelines | ||
| 37 | - CURRENT_STATUS.md # Current project state | ||
| 38 | ``` | ||
| 39 | |||
| 40 | --- | ||
| 41 | |||
| 42 | ### New Structure | ||
| 43 | |||
| 44 | ``` | ||
| 45 | docs/ | ||
| 46 | ├── README.md # Docs navigation | ||
| 47 | ├── ARCHITECTURE.md # System design | ||
| 48 | ├── TEST_STRATEGY.md # Testing approach | ||
| 49 | ├── GETTING_STARTED.md # Setup guide | ||
| 50 | ├── GIT_PROTOCOL.md # Git protocol reference | ||
| 51 | ├── COMPARISON.md # vs other implementations | ||
| 52 | ├── DECISION_SUMMARY.md # Key decisions | ||
| 53 | │ | ||
| 54 | ├── learnings/ # Reusable knowledge | ||
| 55 | │ ├── nix-flakes.md # Nix patterns & gotchas ✨ NEW | ||
| 56 | │ ├── nostr-sdk.md # nostr-sdk 0.43 notes ✨ NEW | ||
| 57 | │ └── grasp-audit.md # Audit tool patterns ✨ NEW | ||
| 58 | │ | ||
| 59 | └── archive/ # Historical documents | ||
| 60 | ├── README.md # Archive index ✨ NEW | ||
| 61 | ├── 2025-11-03-*.md # Nov 3 session docs (16 files) | ||
| 62 | └── 2025-11-04-*.md # Nov 4 session docs (14 files) | ||
| 63 | ``` | ||
| 64 | |||
| 65 | --- | ||
| 66 | |||
| 67 | ## Documents Archived | ||
| 68 | |||
| 69 | ### November 3, 2025 (16 files) | ||
| 70 | |||
| 71 | **Investigation & Planning:** | ||
| 72 | - architecture-investigation.md | ||
| 73 | - review-summary.md | ||
| 74 | - documentation-index.md | ||
| 75 | - grasp-audit-plan.md | ||
| 76 | |||
| 77 | **Implementation:** | ||
| 78 | - grasp-audit-implementation.md | ||
| 79 | - implementation-complete.md | ||
| 80 | - verification-complete.md | ||
| 81 | |||
| 82 | **Testing:** | ||
| 83 | - compliance-test-proposal.md | ||
| 84 | - compliance-testing-report.md | ||
| 85 | - test-breakdown.md | ||
| 86 | - smoke-test-report.md | ||
| 87 | - final-audit-report.md | ||
| 88 | - final-summary.md | ||
| 89 | |||
| 90 | **Reference:** | ||
| 91 | - files-created.md | ||
| 92 | - quick-reference.md | ||
| 93 | - start-here.md | ||
| 94 | |||
| 95 | --- | ||
| 96 | |||
| 97 | ### November 4, 2025 (14 files) | ||
| 98 | |||
| 99 | **Migrations:** | ||
| 100 | - tag-migration.md | ||
| 101 | - tag-migration-summary.md | ||
| 102 | - flake-migration.md | ||
| 103 | |||
| 104 | **Upgrades:** | ||
| 105 | - nostr-sdk-upgrade.md | ||
| 106 | - upgrade-complete.md | ||
| 107 | |||
| 108 | **Fixes:** | ||
| 109 | - compilation-fixes.md | ||
| 110 | - audit-system-fixed.md | ||
| 111 | - audit-status-report.md | ||
| 112 | |||
| 113 | **Sessions:** | ||
| 114 | - session-summary.md | ||
| 115 | - session-complete-1.md | ||
| 116 | - session-complete-2.md | ||
| 117 | - session-continuation.md | ||
| 118 | |||
| 119 | **Planning:** | ||
| 120 | - next-session-quickstart.md | ||
| 121 | - next-prompt.md | ||
| 122 | - ready-for-next-phase.md | ||
| 123 | |||
| 124 | --- | ||
| 125 | |||
| 126 | ## Learnings Extracted | ||
| 127 | |||
| 128 | Created 3 new learning documents with reusable knowledge: | ||
| 129 | |||
| 130 | ### 1. docs/learnings/nix-flakes.md | ||
| 131 | |||
| 132 | **Content:** | ||
| 133 | - Critical gotcha: Use `nix develop`, not `nix-shell` | ||
| 134 | - Flake structure and patterns | ||
| 135 | - Common commands | ||
| 136 | - Subproject flakes | ||
| 137 | - Migration from shell.nix | ||
| 138 | - Benefits and best practices | ||
| 139 | - Common issues and solutions | ||
| 140 | |||
| 141 | **Extracted from:** | ||
| 142 | - FLAKE_MIGRATION_COMPLETE.md | ||
| 143 | - Various session documents | ||
| 144 | - Real experience during development | ||
| 145 | |||
| 146 | --- | ||
| 147 | |||
| 148 | ### 2. docs/learnings/nostr-sdk.md | ||
| 149 | |||
| 150 | **Content:** | ||
| 151 | - Current version: 0.43.x | ||
| 152 | - Breaking changes from 0.35 → 0.43 | ||
| 153 | - Common patterns (events, tags, queries) | ||
| 154 | - Testing patterns (unit vs integration) | ||
| 155 | - Common gotchas and solutions | ||
| 156 | - Performance tips | ||
| 157 | - Migration checklist | ||
| 158 | |||
| 159 | **Extracted from:** | ||
| 160 | - NOSTR_SDK_0.43_UPGRADE.md | ||
| 161 | - Implementation experience | ||
| 162 | - Test code examples | ||
| 163 | |||
| 164 | --- | ||
| 165 | |||
| 166 | ### 3. docs/learnings/grasp-audit.md | ||
| 167 | |||
| 168 | **Content:** | ||
| 169 | - Architecture decisions | ||
| 170 | - Audit event tagging strategy | ||
| 171 | - Code patterns | ||
| 172 | - Test isolation | ||
| 173 | - Cleanup strategy | ||
| 174 | - Testing organization | ||
| 175 | - Lessons learned | ||
| 176 | - Common issues | ||
| 177 | |||
| 178 | **Extracted from:** | ||
| 179 | - TAG_MIGRATION_COMPLETE.md | ||
| 180 | - GRASP_AUDIT_PLAN.md | ||
| 181 | - Implementation summaries | ||
| 182 | - Testing experience | ||
| 183 | |||
| 184 | --- | ||
| 185 | |||
| 186 | ## New Documents Created | ||
| 187 | |||
| 188 | ### CURRENT_STATUS.md | ||
| 189 | |||
| 190 | **Purpose:** Single source of truth for project state | ||
| 191 | |||
| 192 | **Content:** | ||
| 193 | - Quick summary | ||
| 194 | - Project structure | ||
| 195 | - What works | ||
| 196 | - What's next | ||
| 197 | - Development workflow | ||
| 198 | - Key technologies | ||
| 199 | - Important gotchas | ||
| 200 | - Recent milestones | ||
| 201 | - Success metrics | ||
| 202 | - Resources | ||
| 203 | |||
| 204 | **Replaces:** Multiple status reports and session summaries | ||
| 205 | |||
| 206 | --- | ||
| 207 | |||
| 208 | ### AGENTS.md (Updated) | ||
| 209 | |||
| 210 | **Purpose:** AI agent documentation guidelines | ||
| 211 | |||
| 212 | **Already existed but now enforced:** | ||
| 213 | - Documentation structure | ||
| 214 | - Document lifecycle | ||
| 215 | - Cleanup process | ||
| 216 | - Common gotchas | ||
| 217 | - Writing guidelines | ||
| 218 | - AI agent responsibilities | ||
| 219 | - Quality checklist | ||
| 220 | |||
| 221 | --- | ||
| 222 | |||
| 223 | ### docs/archive/README.md | ||
| 224 | |||
| 225 | **Purpose:** Archive organization and usage guide | ||
| 226 | |||
| 227 | **Content:** | ||
| 228 | - Archive organization | ||
| 229 | - Document index by date/topic | ||
| 230 | - When to reference archives | ||
| 231 | - Extracting learnings | ||
| 232 | - Archive principles | ||
| 233 | - Quick find by topic/date | ||
| 234 | |||
| 235 | --- | ||
| 236 | |||
| 237 | ## Benefits Achieved | ||
| 238 | |||
| 239 | ### 1. Clarity | ||
| 240 | |||
| 241 | ✅ **Easy to find current information** | ||
| 242 | - `CURRENT_STATUS.md` - where we are | ||
| 243 | - `README.md` - what the project is | ||
| 244 | - `AGENTS.md` - how to document | ||
| 245 | |||
| 246 | ✅ **Easy to find historical information** | ||
| 247 | - `docs/archive/` - organized by date | ||
| 248 | - `docs/archive/README.md` - searchable index | ||
| 249 | |||
| 250 | --- | ||
| 251 | |||
| 252 | ### 2. Maintainability | ||
| 253 | |||
| 254 | ✅ **Clear document lifecycle** | ||
| 255 | - Working docs in root | ||
| 256 | - Permanent docs in docs/ | ||
| 257 | - Learnings extracted | ||
| 258 | - Completed work archived | ||
| 259 | |||
| 260 | ✅ **No more sprawl** | ||
| 261 | - Root directory stays clean | ||
| 262 | - Archive grows but stays organized | ||
| 263 | - Learnings get updated, not duplicated | ||
| 264 | |||
| 265 | --- | ||
| 266 | |||
| 267 | ### 3. Reusability | ||
| 268 | |||
| 269 | ✅ **Learnings are accessible** | ||
| 270 | - Organized by topic, not session | ||
| 271 | - Include code examples | ||
| 272 | - Link to historical context | ||
| 273 | - Living documents that evolve | ||
| 274 | |||
| 275 | ✅ **Patterns are documented** | ||
| 276 | - Nix flake patterns | ||
| 277 | - nostr-sdk patterns | ||
| 278 | - grasp-audit patterns | ||
| 279 | - Testing patterns | ||
| 280 | |||
| 281 | --- | ||
| 282 | |||
| 283 | ### 4. Onboarding | ||
| 284 | |||
| 285 | ✅ **New developers (human or AI) can:** | ||
| 286 | 1. Read `README.md` - understand project | ||
| 287 | 2. Read `CURRENT_STATUS.md` - know where we are | ||
| 288 | 3. Read `AGENTS.md` - learn documentation practices | ||
| 289 | 4. Read `docs/learnings/` - avoid known pitfalls | ||
| 290 | 5. Reference `docs/archive/` - understand history | ||
| 291 | |||
| 292 | --- | ||
| 293 | |||
| 294 | ## Cleanup Statistics | ||
| 295 | |||
| 296 | ### Before | ||
| 297 | |||
| 298 | ``` | ||
| 299 | Root directory: | ||
| 300 | - 32 markdown files | ||
| 301 | - Mix of status, reports, plans, summaries | ||
| 302 | - Hard to find current information | ||
| 303 | - Duplicate information | ||
| 304 | - No clear organization | ||
| 305 | |||
| 306 | docs/ directory: | ||
| 307 | - 7 permanent docs | ||
| 308 | - 0 learnings | ||
| 309 | - 0 archived docs | ||
| 310 | ``` | ||
| 311 | |||
| 312 | ### After | ||
| 313 | |||
| 314 | ``` | ||
| 315 | Root directory: | ||
| 316 | - 3 markdown files (README, AGENTS, CURRENT_STATUS) | ||
| 317 | - Clean and focused | ||
| 318 | - Clear purpose for each file | ||
| 319 | |||
| 320 | docs/ directory: | ||
| 321 | - 7 permanent docs (unchanged) | ||
| 322 | - 3 learnings (NEW) | ||
| 323 | - 30 archived docs (NEW) | ||
| 324 | - 1 archive index (NEW) | ||
| 325 | ``` | ||
| 326 | |||
| 327 | --- | ||
| 328 | |||
| 329 | ## Document Count | ||
| 330 | |||
| 331 | | Location | Count | Purpose | | ||
| 332 | |----------|-------|---------| | ||
| 333 | | Root | 3 | Essential project files | | ||
| 334 | | docs/ | 7 | Permanent documentation | | ||
| 335 | | docs/learnings/ | 3 | Reusable knowledge | | ||
| 336 | | docs/archive/ | 30 | Historical records | | ||
| 337 | | **Total** | **43** | **Well-organized docs** | | ||
| 338 | |||
| 339 | --- | ||
| 340 | |||
| 341 | ## Maintenance Going Forward | ||
| 342 | |||
| 343 | ### Daily Development | ||
| 344 | |||
| 345 | **Create working docs in root:** | ||
| 346 | - Session notes | ||
| 347 | - Status updates | ||
| 348 | - Temporary planning | ||
| 349 | |||
| 350 | **Keep root clean:** | ||
| 351 | - Max 5-10 working docs | ||
| 352 | - Archive when complete | ||
| 353 | - Extract learnings first | ||
| 354 | |||
| 355 | --- | ||
| 356 | |||
| 357 | ### Weekly Cleanup | ||
| 358 | |||
| 359 | **Trigger:** Root has >10 markdown files | ||
| 360 | |||
| 361 | **Process:** | ||
| 362 | 1. Review completed working docs | ||
| 363 | 2. Extract learnings to `docs/learnings/` | ||
| 364 | 3. Archive to `docs/archive/YYYY-MM-DD-topic.md` | ||
| 365 | 4. Delete obsolete duplicates | ||
| 366 | 5. Update `CURRENT_STATUS.md` | ||
| 367 | 6. Commit changes | ||
| 368 | |||
| 369 | --- | ||
| 370 | |||
| 371 | ### Guidelines | ||
| 372 | |||
| 373 | **Follow `AGENTS.md` for:** | ||
| 374 | - When to create new documents | ||
| 375 | - Where to put documents | ||
| 376 | - How to name documents | ||
| 377 | - When to archive | ||
| 378 | - How to extract learnings | ||
| 379 | |||
| 380 | --- | ||
| 381 | |||
| 382 | ## Commit Message | ||
| 383 | |||
| 384 | ``` | ||
| 385 | docs: major cleanup and reorganization | ||
| 386 | |||
| 387 | - Archive 30 completed session documents to docs/archive/ | ||
| 388 | - Extract learnings to docs/learnings/ (nix-flakes, nostr-sdk, grasp-audit) | ||
| 389 | - Create CURRENT_STATUS.md as single source of truth | ||
| 390 | - Create docs/archive/README.md for archive organization | ||
| 391 | - Clean root directory: 32 files → 3 files | ||
| 392 | - Enforce AGENTS.md documentation guidelines | ||
| 393 | |||
| 394 | Root directory now contains only: | ||
| 395 | - README.md (project overview) | ||
| 396 | - AGENTS.md (documentation guidelines) | ||
| 397 | - CURRENT_STATUS.md (current state) | ||
| 398 | |||
| 399 | All historical documents preserved in docs/archive/ with proper dating. | ||
| 400 | All reusable knowledge extracted to docs/learnings/. | ||
| 401 | |||
| 402 | Benefits: | ||
| 403 | - Easy to find current information | ||
| 404 | - Clear document lifecycle | ||
| 405 | - No more documentation sprawl | ||
| 406 | - Learnings are accessible and reusable | ||
| 407 | - Better onboarding for new developers/agents | ||
| 408 | ``` | ||
| 409 | |||
| 410 | --- | ||
| 411 | |||
| 412 | ## Verification | ||
| 413 | |||
| 414 | ```bash | ||
| 415 | # Verify structure | ||
| 416 | ls -la *.md | ||
| 417 | # Should show: README.md, AGENTS.md, CURRENT_STATUS.md | ||
| 418 | |||
| 419 | ls -la docs/learnings/ | ||
| 420 | # Should show: nix-flakes.md, nostr-sdk.md, grasp-audit.md | ||
| 421 | |||
| 422 | ls -la docs/archive/ | wc -l | ||
| 423 | # Should show: 31 (30 files + README.md) | ||
| 424 | |||
| 425 | # Verify no broken links (manual check) | ||
| 426 | grep -r "\.md" docs/ | grep -v ".git" | ||
| 427 | ``` | ||
| 428 | |||
| 429 | --- | ||
| 430 | |||
| 431 | ## Next Steps | ||
| 432 | |||
| 433 | 1. ✅ Cleanup complete | ||
| 434 | 2. ✅ Learnings extracted | ||
| 435 | 3. ✅ Archive organized | ||
| 436 | 4. 🔜 Commit changes | ||
| 437 | 5. 🔜 Start NIP-01 relay implementation | ||
| 438 | |||
| 439 | --- | ||
| 440 | |||
| 441 | **Cleanup completed:** November 4, 2025 | ||
| 442 | **Files organized:** 43 total | ||
| 443 | **Root cleaned:** 32 → 3 files | ||
| 444 | **Status:** ✅ Ready for next phase | ||
| 445 | |||
| 446 | --- | ||
| 447 | |||
| 448 | *This document will be archived after commit* | ||
diff --git a/CURRENT_STATUS.md b/CURRENT_STATUS.md new file mode 100644 index 0000000..417691a --- /dev/null +++ b/CURRENT_STATUS.md | |||
| @@ -0,0 +1,464 @@ | |||
| 1 | # ngit-grasp - Current Status | ||
| 2 | |||
| 3 | **Date:** November 4, 2025 | ||
| 4 | **Phase:** Audit Tool Complete - Ready for NIP-01 Implementation | ||
| 5 | **Status:** 🟢 All Systems Green | ||
| 6 | |||
| 7 | --- | ||
| 8 | |||
| 9 | ## Quick Summary | ||
| 10 | |||
| 11 | ✅ **grasp-audit tool complete** - NIP-01 smoke tests passing | ||
| 12 | ✅ **Tag migration complete** - Using standard NIP-01 "t" tags | ||
| 13 | ✅ **nostr-sdk upgraded** - Version 0.43.x (latest stable) | ||
| 14 | ✅ **Nix flakes migrated** - Modern reproducible builds | ||
| 15 | ✅ **Documentation cleaned** - Clear structure established | ||
| 16 | |||
| 17 | **Next:** Build NIP-01 relay implementation, test with grasp-audit | ||
| 18 | |||
| 19 | --- | ||
| 20 | |||
| 21 | ## Project Structure | ||
| 22 | |||
| 23 | ``` | ||
| 24 | ngit-grasp/ | ||
| 25 | ├── README.md # Project overview | ||
| 26 | ├── AGENTS.md # AI agent guidelines | ||
| 27 | ├── CURRENT_STATUS.md # This file | ||
| 28 | │ | ||
| 29 | ├── docs/ # Permanent documentation | ||
| 30 | │ ├── ARCHITECTURE.md # System design | ||
| 31 | │ ├── TEST_STRATEGY.md # Testing approach | ||
| 32 | │ ├── GETTING_STARTED.md # Setup guide | ||
| 33 | │ ├── GIT_PROTOCOL.md # Git protocol reference | ||
| 34 | │ ├── COMPARISON.md # vs ngit-relay | ||
| 35 | │ ├── DECISION_SUMMARY.md # Key decisions | ||
| 36 | │ │ | ||
| 37 | │ ├── learnings/ # Reusable knowledge | ||
| 38 | │ │ ├── nix-flakes.md # Nix flake patterns | ||
| 39 | │ │ ├── nostr-sdk.md # nostr-sdk 0.43 notes | ||
| 40 | │ │ └── grasp-audit.md # Audit tool patterns | ||
| 41 | │ │ | ||
| 42 | │ └── archive/ # Historical documents | ||
| 43 | │ ├── 2025-11-04-tag-migration.md | ||
| 44 | │ ├── 2025-11-04-flake-migration.md | ||
| 45 | │ ├── 2025-11-04-nostr-sdk-upgrade.md | ||
| 46 | │ └── ... | ||
| 47 | │ | ||
| 48 | └── grasp-audit/ # Audit tool (separate crate) | ||
| 49 | ├── README.md # Audit tool docs | ||
| 50 | ├── QUICK_START.md # Getting started | ||
| 51 | ├── flake.nix # Nix dev environment | ||
| 52 | ├── Cargo.toml # Rust dependencies | ||
| 53 | └── src/ | ||
| 54 | ├── specs/ # Test specifications | ||
| 55 | │ └── nip01_smoke.rs # NIP-01 basic tests ✅ | ||
| 56 | ├── audit.rs # Audit config & event builder | ||
| 57 | ├── client.rs # Audit client wrapper | ||
| 58 | └── ... | ||
| 59 | ``` | ||
| 60 | |||
| 61 | --- | ||
| 62 | |||
| 63 | ## What Works | ||
| 64 | |||
| 65 | ### grasp-audit Tool ✅ | ||
| 66 | |||
| 67 | **Status:** Fully functional, all tests passing | ||
| 68 | |||
| 69 | ```bash | ||
| 70 | cd grasp-audit | ||
| 71 | nix develop | ||
| 72 | cargo test --lib # 12/12 unit tests ✅ | ||
| 73 | cargo test -- --ignored # 1/1 integration test ✅ | ||
| 74 | cargo run -- audit --relay ws://localhost:7000 --spec nip01-smoke | ||
| 75 | # Results: 6/6 passed (100.0%) ✅ | ||
| 76 | ``` | ||
| 77 | |||
| 78 | **Features:** | ||
| 79 | - ✅ NIP-01 smoke tests (websocket, events, subscriptions) | ||
| 80 | - ✅ CI and production modes | ||
| 81 | - ✅ Test isolation via unique run IDs | ||
| 82 | - ✅ Standard "t" tag usage | ||
| 83 | - ✅ Audit event cleanup strategy | ||
| 84 | - ✅ CLI interface | ||
| 85 | |||
| 86 | **Test Coverage:** | ||
| 87 | - websocket_connection | ||
| 88 | - send_receive_event | ||
| 89 | - create_subscription | ||
| 90 | - close_subscription | ||
| 91 | - reject_invalid_signature | ||
| 92 | - reject_invalid_event_id | ||
| 93 | |||
| 94 | --- | ||
| 95 | |||
| 96 | ### Development Environment ✅ | ||
| 97 | |||
| 98 | **Nix Flakes:** | ||
| 99 | - ✅ `grasp-audit/flake.nix` - Reproducible builds | ||
| 100 | - ✅ Rust toolchain via rust-overlay | ||
| 101 | - ✅ All dependencies managed | ||
| 102 | - ✅ Cross-platform support | ||
| 103 | |||
| 104 | **Usage:** | ||
| 105 | ```bash | ||
| 106 | cd grasp-audit | ||
| 107 | nix develop # Enter dev shell | ||
| 108 | nix develop -c cargo build # One-off command | ||
| 109 | nix build # Build package | ||
| 110 | ``` | ||
| 111 | |||
| 112 | --- | ||
| 113 | |||
| 114 | ### Documentation ✅ | ||
| 115 | |||
| 116 | **Permanent Docs:** | ||
| 117 | - ✅ `docs/ARCHITECTURE.md` - Detailed system design | ||
| 118 | - ✅ `docs/TEST_STRATEGY.md` - Testing approach | ||
| 119 | - ✅ `docs/GETTING_STARTED.md` - Setup guide | ||
| 120 | - ✅ `docs/README.md` - Documentation index | ||
| 121 | |||
| 122 | **Learnings:** | ||
| 123 | - ✅ `docs/learnings/nix-flakes.md` - Nix patterns and gotchas | ||
| 124 | - ✅ `docs/learnings/nostr-sdk.md` - nostr-sdk 0.43 migration | ||
| 125 | - ✅ `docs/learnings/grasp-audit.md` - Audit tool patterns | ||
| 126 | |||
| 127 | **Guidelines:** | ||
| 128 | - ✅ `AGENTS.md` - AI agent documentation practices | ||
| 129 | |||
| 130 | --- | ||
| 131 | |||
| 132 | ## What's Next | ||
| 133 | |||
| 134 | ### Immediate: NIP-01 Relay Implementation | ||
| 135 | |||
| 136 | **Goal:** Build basic Nostr relay that passes grasp-audit tests | ||
| 137 | |||
| 138 | **Approach:** | ||
| 139 | 1. Create `src/` directory structure | ||
| 140 | 2. Implement basic NIP-01 relay using nostr-relay-builder | ||
| 141 | 3. Run grasp-audit tests against it | ||
| 142 | 4. Iterate until all tests pass | ||
| 143 | |||
| 144 | **Files to Create:** | ||
| 145 | ``` | ||
| 146 | src/ | ||
| 147 | ├── main.rs # Entry point | ||
| 148 | ├── config.rs # Configuration | ||
| 149 | ├── nostr/ | ||
| 150 | │ ├── mod.rs | ||
| 151 | │ ├── relay.rs # NIP-01 relay setup | ||
| 152 | │ └── events.rs # Event handling | ||
| 153 | └── storage/ | ||
| 154 | ├── mod.rs | ||
| 155 | └── repository.rs # Event storage | ||
| 156 | ``` | ||
| 157 | |||
| 158 | **Success Criteria:** | ||
| 159 | ```bash | ||
| 160 | # Start ngit-grasp relay | ||
| 161 | cargo run | ||
| 162 | |||
| 163 | # In another terminal | ||
| 164 | cd grasp-audit | ||
| 165 | cargo run -- audit --relay ws://localhost:8080 --spec nip01-smoke | ||
| 166 | # Results: 6/6 passed (100.0%) ✅ | ||
| 167 | ``` | ||
| 168 | |||
| 169 | --- | ||
| 170 | |||
| 171 | ### Phase 2: GRASP-01 Compliance | ||
| 172 | |||
| 173 | **After NIP-01 works:** | ||
| 174 | |||
| 175 | 1. **Extend grasp-audit** | ||
| 176 | - Create `src/specs/grasp_01_relay.rs` | ||
| 177 | - Test repository announcements (NIP-34) | ||
| 178 | - Test state events | ||
| 179 | - Test maintainer validation | ||
| 180 | |||
| 181 | 2. **Implement in ngit-grasp** | ||
| 182 | - NIP-34 event validation | ||
| 183 | - Repository state management | ||
| 184 | - Maintainer authorization | ||
| 185 | |||
| 186 | 3. **Iterate** | ||
| 187 | - Run GRASP-01 audit tests | ||
| 188 | - Fix failures | ||
| 189 | - Repeat until passing | ||
| 190 | |||
| 191 | --- | ||
| 192 | |||
| 193 | ### Phase 3: Git Integration | ||
| 194 | |||
| 195 | **After GRASP-01 compliance:** | ||
| 196 | |||
| 197 | 1. **Git HTTP Backend** | ||
| 198 | - Implement git-smart-http handlers | ||
| 199 | - Integrate with authorization | ||
| 200 | |||
| 201 | 2. **Push Validation** | ||
| 202 | - Query Nostr state events | ||
| 203 | - Validate push permissions | ||
| 204 | - Inline authorization (no hooks) | ||
| 205 | |||
| 206 | 3. **Full GRASP-01** | ||
| 207 | - Complete service requirements | ||
| 208 | - End-to-end testing | ||
| 209 | |||
| 210 | --- | ||
| 211 | |||
| 212 | ## Development Workflow | ||
| 213 | |||
| 214 | ### Daily Development | ||
| 215 | |||
| 216 | ```bash | ||
| 217 | # For ngit-grasp (when we create it) | ||
| 218 | cd ngit-grasp | ||
| 219 | nix develop | ||
| 220 | cargo build | ||
| 221 | cargo test | ||
| 222 | cargo run | ||
| 223 | |||
| 224 | # For grasp-audit | ||
| 225 | cd grasp-audit | ||
| 226 | nix develop | ||
| 227 | cargo build | ||
| 228 | cargo test --lib | ||
| 229 | cargo test -- --ignored # Requires relay | ||
| 230 | cargo run -- audit --relay ws://localhost:8080 | ||
| 231 | ``` | ||
| 232 | |||
| 233 | --- | ||
| 234 | |||
| 235 | ### Running Tests | ||
| 236 | |||
| 237 | **Unit Tests (Fast):** | ||
| 238 | ```bash | ||
| 239 | # grasp-audit | ||
| 240 | cd grasp-audit | ||
| 241 | cargo test --lib | ||
| 242 | |||
| 243 | # ngit-grasp (when created) | ||
| 244 | cargo test --lib | ||
| 245 | ``` | ||
| 246 | |||
| 247 | **Integration Tests (Requires Relay):** | ||
| 248 | ```bash | ||
| 249 | # Start test relay | ||
| 250 | docker run --rm -p 7000:7000 scsibug/nostr-rs-relay | ||
| 251 | |||
| 252 | # Run integration tests | ||
| 253 | cd grasp-audit | ||
| 254 | cargo test -- --ignored | ||
| 255 | ``` | ||
| 256 | |||
| 257 | **Audit Tests:** | ||
| 258 | ```bash | ||
| 259 | # Start your relay | ||
| 260 | cd ngit-grasp | ||
| 261 | cargo run | ||
| 262 | |||
| 263 | # Run audit in another terminal | ||
| 264 | cd grasp-audit | ||
| 265 | cargo run -- audit --relay ws://localhost:8080 | ||
| 266 | ``` | ||
| 267 | |||
| 268 | --- | ||
| 269 | |||
| 270 | ## Key Technologies | ||
| 271 | |||
| 272 | ### Current Stack | ||
| 273 | |||
| 274 | - **Rust**: Core language | ||
| 275 | - **nostr-sdk 0.43**: Nostr event handling | ||
| 276 | - **Nix Flakes**: Reproducible dev environment | ||
| 277 | - **Cargo**: Build system | ||
| 278 | - **Docker**: Test relay (nostr-rs-relay) | ||
| 279 | |||
| 280 | ### Planned Stack (ngit-grasp) | ||
| 281 | |||
| 282 | - **actix-web**: HTTP server | ||
| 283 | - **nostr-relay-builder**: Relay infrastructure | ||
| 284 | - **git-http-backend**: Git protocol handling | ||
| 285 | - **tokio**: Async runtime | ||
| 286 | |||
| 287 | --- | ||
| 288 | |||
| 289 | ## Important Gotchas | ||
| 290 | |||
| 291 | ### 1. Use Nix Flakes, Not nix-shell | ||
| 292 | |||
| 293 | ```bash | ||
| 294 | # ✅ Correct | ||
| 295 | nix develop | ||
| 296 | |||
| 297 | # ❌ Wrong | ||
| 298 | nix-shell | ||
| 299 | ``` | ||
| 300 | |||
| 301 | **Why:** We use `flake.nix`, not `shell.nix` | ||
| 302 | |||
| 303 | --- | ||
| 304 | |||
| 305 | ### 2. grasp-audit is Separate | ||
| 306 | |||
| 307 | ```bash | ||
| 308 | # ✅ Correct | ||
| 309 | cd grasp-audit | ||
| 310 | nix develop | ||
| 311 | cargo build | ||
| 312 | |||
| 313 | # ❌ Wrong | ||
| 314 | cd ngit-grasp | ||
| 315 | cargo build # Won't find grasp-audit | ||
| 316 | ``` | ||
| 317 | |||
| 318 | **Why:** Separate crate with own flake and Cargo.toml | ||
| 319 | |||
| 320 | --- | ||
| 321 | |||
| 322 | ### 3. Integration Tests Need Relay | ||
| 323 | |||
| 324 | ```bash | ||
| 325 | # ✅ Correct | ||
| 326 | docker run --rm -p 7000:7000 scsibug/nostr-rs-relay | ||
| 327 | cargo test -- --ignored | ||
| 328 | |||
| 329 | # ❌ Wrong | ||
| 330 | cargo test -- --ignored # Will fail without relay | ||
| 331 | ``` | ||
| 332 | |||
| 333 | --- | ||
| 334 | |||
| 335 | ### 4. nostr-sdk 0.43 API Changes | ||
| 336 | |||
| 337 | **Event Building:** | ||
| 338 | ```rust | ||
| 339 | // ✅ Correct (0.43) | ||
| 340 | EventBuilder::new(kind, content) | ||
| 341 | .tags(tags) | ||
| 342 | .sign_with_keys(&keys)? | ||
| 343 | |||
| 344 | // ❌ Wrong (0.35) | ||
| 345 | EventBuilder::new(kind, content, tags) | ||
| 346 | .to_event(&keys)? | ||
| 347 | ``` | ||
| 348 | |||
| 349 | **See:** `docs/learnings/nostr-sdk.md` for full migration guide | ||
| 350 | |||
| 351 | --- | ||
| 352 | |||
| 353 | ## Documentation Practices | ||
| 354 | |||
| 355 | ### When to Create Documents | ||
| 356 | |||
| 357 | **Working Docs (Root):** | ||
| 358 | - Session summaries | ||
| 359 | - Status reports | ||
| 360 | - Next steps | ||
| 361 | - Temporary notes | ||
| 362 | |||
| 363 | **Permanent Docs (docs/):** | ||
| 364 | - Architecture | ||
| 365 | - Design decisions | ||
| 366 | - API documentation | ||
| 367 | - User guides | ||
| 368 | |||
| 369 | **Learnings (docs/learnings/):** | ||
| 370 | - Gotchas and patterns | ||
| 371 | - Migration notes | ||
| 372 | - Best practices | ||
| 373 | - Reusable knowledge | ||
| 374 | |||
| 375 | **Archive (docs/archive/):** | ||
| 376 | - Completed session docs | ||
| 377 | - Historical records | ||
| 378 | - Superseded documents | ||
| 379 | |||
| 380 | **See:** `AGENTS.md` for full guidelines | ||
| 381 | |||
| 382 | --- | ||
| 383 | |||
| 384 | ## Recent Milestones | ||
| 385 | |||
| 386 | - ✅ **Nov 4, 2025** - Tag migration to standard "t" tags | ||
| 387 | - ✅ **Nov 4, 2025** - Flake migration (shell.nix → flake.nix) | ||
| 388 | - ✅ **Nov 4, 2025** - nostr-sdk upgrade (0.35 → 0.43) | ||
| 389 | - ✅ **Nov 4, 2025** - Documentation cleanup | ||
| 390 | - ✅ **Nov 3, 2025** - Architecture investigation complete | ||
| 391 | - ✅ **Nov 3, 2025** - grasp-audit tool implemented | ||
| 392 | - ✅ **Nov 3, 2025** - NIP-01 smoke tests passing | ||
| 393 | |||
| 394 | --- | ||
| 395 | |||
| 396 | ## Success Metrics | ||
| 397 | |||
| 398 | ### Current Status | ||
| 399 | |||
| 400 | | Metric | Status | Details | | ||
| 401 | |--------|--------|---------| | ||
| 402 | | grasp-audit builds | ✅ | Clean build, no warnings | | ||
| 403 | | Unit tests | ✅ | 12/12 passing | | ||
| 404 | | Integration tests | ✅ | 1/1 passing | | ||
| 405 | | CLI works | ✅ | All commands functional | | ||
| 406 | | Smoke tests | ✅ | 6/6 passing | | ||
| 407 | | Documentation | ✅ | Complete and organized | | ||
| 408 | | Nix flakes | ✅ | Reproducible builds | | ||
| 409 | |||
| 410 | ### Next Milestone: NIP-01 Relay | ||
| 411 | |||
| 412 | | Metric | Status | Target | | ||
| 413 | |--------|--------|--------| | ||
| 414 | | ngit-grasp builds | 🔜 | Clean build | | ||
| 415 | | NIP-01 relay running | 🔜 | Accepts connections | | ||
| 416 | | Smoke tests pass | 🔜 | 6/6 against ngit-grasp | | ||
| 417 | | Basic event storage | 🔜 | Events persist | | ||
| 418 | | Subscriptions work | 🔜 | Real-time updates | | ||
| 419 | |||
| 420 | --- | ||
| 421 | |||
| 422 | ## Resources | ||
| 423 | |||
| 424 | ### Documentation | ||
| 425 | - [Project README](README.md) | ||
| 426 | - [Architecture](docs/ARCHITECTURE.md) | ||
| 427 | - [Test Strategy](docs/TEST_STRATEGY.md) | ||
| 428 | - [Getting Started](docs/GETTING_STARTED.md) | ||
| 429 | - [Agent Guidelines](AGENTS.md) | ||
| 430 | |||
| 431 | ### Learnings | ||
| 432 | - [Nix Flakes](docs/learnings/nix-flakes.md) | ||
| 433 | - [nostr-sdk](docs/learnings/nostr-sdk.md) | ||
| 434 | - [grasp-audit](docs/learnings/grasp-audit.md) | ||
| 435 | |||
| 436 | ### External | ||
| 437 | - [GRASP Protocol](https://gitworkshop.dev/danconwaydev.com/grasp) | ||
| 438 | - [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md) | ||
| 439 | - [NIP-34](https://github.com/nostr-protocol/nips/blob/master/34.md) | ||
| 440 | - [nostr-sdk docs](https://docs.rs/nostr-sdk/0.43.0) | ||
| 441 | |||
| 442 | --- | ||
| 443 | |||
| 444 | ## Contact & Contribution | ||
| 445 | |||
| 446 | **Status:** Alpha - Active Development | ||
| 447 | **License:** MIT | ||
| 448 | **Repository:** ngit-grasp (local development) | ||
| 449 | |||
| 450 | **Contributing:** | ||
| 451 | 1. Read `AGENTS.md` for documentation practices | ||
| 452 | 2. Review `docs/ARCHITECTURE.md` for design | ||
| 453 | 3. Check `CURRENT_STATUS.md` (this file) for current state | ||
| 454 | 4. Follow Rust conventions (`cargo fmt`, `cargo clippy`) | ||
| 455 | 5. Add tests for new functionality | ||
| 456 | |||
| 457 | --- | ||
| 458 | |||
| 459 | **Last Updated:** November 4, 2025 | ||
| 460 | **Next Review:** When NIP-01 relay is implemented | ||
| 461 | |||
| 462 | --- | ||
| 463 | |||
| 464 | *Status: 🟢 Ready to build NIP-01 relay implementation* | ||
diff --git a/INVESTIGATION_COMPLETE.md b/docs/archive/2025-11-03-architecture-investigation.md index 190a010..190a010 100644 --- a/INVESTIGATION_COMPLETE.md +++ b/docs/archive/2025-11-03-architecture-investigation.md | |||
diff --git a/COMPLIANCE_TEST_PROPOSAL.md b/docs/archive/2025-11-03-compliance-test-proposal.md index 792f375..792f375 100644 --- a/COMPLIANCE_TEST_PROPOSAL.md +++ b/docs/archive/2025-11-03-compliance-test-proposal.md | |||
diff --git a/REPORT_COMPLIANCE_TESTING.md b/docs/archive/2025-11-03-compliance-testing-report.md index d850f73..d850f73 100644 --- a/REPORT_COMPLIANCE_TESTING.md +++ b/docs/archive/2025-11-03-compliance-testing-report.md | |||
diff --git a/DOCUMENTATION_INDEX.md b/docs/archive/2025-11-03-documentation-index.md index 17ba744..17ba744 100644 --- a/DOCUMENTATION_INDEX.md +++ b/docs/archive/2025-11-03-documentation-index.md | |||
diff --git a/FILES_CREATED.md b/docs/archive/2025-11-03-files-created.md index 2bdb0f4..2bdb0f4 100644 --- a/FILES_CREATED.md +++ b/docs/archive/2025-11-03-files-created.md | |||
diff --git a/FINAL_AUDIT_REPORT.md b/docs/archive/2025-11-03-final-audit-report.md index 83419d9..83419d9 100644 --- a/FINAL_AUDIT_REPORT.md +++ b/docs/archive/2025-11-03-final-audit-report.md | |||
diff --git a/FINAL_SUMMARY.md b/docs/archive/2025-11-03-final-summary.md index 19e7a06..19e7a06 100644 --- a/FINAL_SUMMARY.md +++ b/docs/archive/2025-11-03-final-summary.md | |||
diff --git a/GRASP_AUDIT_IMPLEMENTATION_SUMMARY.md b/docs/archive/2025-11-03-grasp-audit-implementation.md index 827db24..827db24 100644 --- a/GRASP_AUDIT_IMPLEMENTATION_SUMMARY.md +++ b/docs/archive/2025-11-03-grasp-audit-implementation.md | |||
diff --git a/GRASP_AUDIT_PLAN.md b/docs/archive/2025-11-03-grasp-audit-plan.md index 96097a3..96097a3 100644 --- a/GRASP_AUDIT_PLAN.md +++ b/docs/archive/2025-11-03-grasp-audit-plan.md | |||
diff --git a/IMPLEMENTATION_COMPLETE.md b/docs/archive/2025-11-03-implementation-complete.md index 1938595..1938595 100644 --- a/IMPLEMENTATION_COMPLETE.md +++ b/docs/archive/2025-11-03-implementation-complete.md | |||
diff --git a/QUICK_REFERENCE.md b/docs/archive/2025-11-03-quick-reference.md index b9b9943..b9b9943 100644 --- a/QUICK_REFERENCE.md +++ b/docs/archive/2025-11-03-quick-reference.md | |||
diff --git a/REVIEW_SUMMARY.md b/docs/archive/2025-11-03-review-summary.md index f66a371..f66a371 100644 --- a/REVIEW_SUMMARY.md +++ b/docs/archive/2025-11-03-review-summary.md | |||
diff --git a/SMOKE_TEST_REPORT.md b/docs/archive/2025-11-03-smoke-test-report.md index ccb3916..ccb3916 100644 --- a/SMOKE_TEST_REPORT.md +++ b/docs/archive/2025-11-03-smoke-test-report.md | |||
diff --git a/START_HERE.md b/docs/archive/2025-11-03-start-here.md index eaa125c..eaa125c 100644 --- a/START_HERE.md +++ b/docs/archive/2025-11-03-start-here.md | |||
diff --git a/TEST_BREAKDOWN.md b/docs/archive/2025-11-03-test-breakdown.md index c054cd3..c054cd3 100644 --- a/TEST_BREAKDOWN.md +++ b/docs/archive/2025-11-03-test-breakdown.md | |||
diff --git a/VERIFICATION_COMPLETE.md b/docs/archive/2025-11-03-verification-complete.md index e1efa65..e1efa65 100644 --- a/VERIFICATION_COMPLETE.md +++ b/docs/archive/2025-11-03-verification-complete.md | |||
diff --git a/AUDIT_SYSTEM_STATUS_REPORT.md b/docs/archive/2025-11-04-audit-status-report.md index 3e1c3e7..3e1c3e7 100644 --- a/AUDIT_SYSTEM_STATUS_REPORT.md +++ b/docs/archive/2025-11-04-audit-status-report.md | |||
diff --git a/AUDIT_SYSTEM_FIXED.md b/docs/archive/2025-11-04-audit-system-fixed.md index e47ac44..e47ac44 100644 --- a/AUDIT_SYSTEM_FIXED.md +++ b/docs/archive/2025-11-04-audit-system-fixed.md | |||
diff --git a/COMPILATION_FIXES.md b/docs/archive/2025-11-04-compilation-fixes.md index 18584eb..18584eb 100644 --- a/COMPILATION_FIXES.md +++ b/docs/archive/2025-11-04-compilation-fixes.md | |||
diff --git a/FLAKE_MIGRATION_COMPLETE.md b/docs/archive/2025-11-04-flake-migration.md index 2d2514d..2d2514d 100644 --- a/FLAKE_MIGRATION_COMPLETE.md +++ b/docs/archive/2025-11-04-flake-migration.md | |||
diff --git a/next_prompt.md b/docs/archive/2025-11-04-next-prompt.md index 7cfdd32..7cfdd32 100644 --- a/next_prompt.md +++ b/docs/archive/2025-11-04-next-prompt.md | |||
diff --git a/NEXT_SESSION_QUICKSTART.md b/docs/archive/2025-11-04-next-session-quickstart.md index a198bf9..a198bf9 100644 --- a/NEXT_SESSION_QUICKSTART.md +++ b/docs/archive/2025-11-04-next-session-quickstart.md | |||
diff --git a/NOSTR_SDK_0.43_UPGRADE.md b/docs/archive/2025-11-04-nostr-sdk-upgrade.md index 052b851..052b851 100644 --- a/NOSTR_SDK_0.43_UPGRADE.md +++ b/docs/archive/2025-11-04-nostr-sdk-upgrade.md | |||
diff --git a/READY_FOR_NEXT_PHASE.md b/docs/archive/2025-11-04-ready-for-next-phase.md index 10ad84a..10ad84a 100644 --- a/READY_FOR_NEXT_PHASE.md +++ b/docs/archive/2025-11-04-ready-for-next-phase.md | |||
diff --git a/SESSION_COMPLETE.md b/docs/archive/2025-11-04-session-complete-1.md index 3f07161..3f07161 100644 --- a/SESSION_COMPLETE.md +++ b/docs/archive/2025-11-04-session-complete-1.md | |||
diff --git a/SESSION_COMPLETE_2025_11_04.md b/docs/archive/2025-11-04-session-complete-2.md index 5de92f6..5de92f6 100644 --- a/SESSION_COMPLETE_2025_11_04.md +++ b/docs/archive/2025-11-04-session-complete-2.md | |||
diff --git a/SESSION_CONTINUATION_COMPLETE.md b/docs/archive/2025-11-04-session-continuation.md index 6838115..6838115 100644 --- a/SESSION_CONTINUATION_COMPLETE.md +++ b/docs/archive/2025-11-04-session-continuation.md | |||
diff --git a/SESSION_2025_11_04_SUMMARY.md b/docs/archive/2025-11-04-session-summary.md index 4cc53b0..4cc53b0 100644 --- a/SESSION_2025_11_04_SUMMARY.md +++ b/docs/archive/2025-11-04-session-summary.md | |||
diff --git a/TAG_MIGRATION_SUMMARY.md b/docs/archive/2025-11-04-tag-migration-summary.md index 34d4ff0..34d4ff0 100644 --- a/TAG_MIGRATION_SUMMARY.md +++ b/docs/archive/2025-11-04-tag-migration-summary.md | |||
diff --git a/TAG_MIGRATION_COMPLETE.md b/docs/archive/2025-11-04-tag-migration.md index c2fdbfc..c2fdbfc 100644 --- a/TAG_MIGRATION_COMPLETE.md +++ b/docs/archive/2025-11-04-tag-migration.md | |||
diff --git a/UPGRADE_COMPLETE.md b/docs/archive/2025-11-04-upgrade-complete.md index 8fe3ebc..8fe3ebc 100644 --- a/UPGRADE_COMPLETE.md +++ b/docs/archive/2025-11-04-upgrade-complete.md | |||
diff --git a/docs/archive/README.md b/docs/archive/README.md new file mode 100644 index 0000000..9ff9e3e --- /dev/null +++ b/docs/archive/README.md | |||
| @@ -0,0 +1,158 @@ | |||
| 1 | # Archive - Historical Documentation | ||
| 2 | |||
| 3 | **Purpose:** Completed session documents, phase reports, and historical records | ||
| 4 | **Status:** Read-only - documents are not modified after archiving | ||
| 5 | |||
| 6 | --- | ||
| 7 | |||
| 8 | ## Archive Organization | ||
| 9 | |||
| 10 | Documents are organized by date (YYYY-MM-DD) and topic. | ||
| 11 | |||
| 12 | ### November 3, 2025 - Architecture Investigation & Initial Implementation | ||
| 13 | |||
| 14 | **Architecture Investigation:** | ||
| 15 | - `2025-11-03-architecture-investigation.md` - GRASP protocol investigation complete | ||
| 16 | - `2025-11-03-review-summary.md` - Executive summary of investigation | ||
| 17 | - `2025-11-03-documentation-index.md` - Initial docs structure | ||
| 18 | |||
| 19 | **grasp-audit Implementation:** | ||
| 20 | - `2025-11-03-grasp-audit-plan.md` - Audit tool design decisions | ||
| 21 | - `2025-11-03-grasp-audit-implementation.md` - Implementation summary | ||
| 22 | - `2025-11-03-implementation-complete.md` - Initial implementation complete | ||
| 23 | - `2025-11-03-verification-complete.md` - Verification results | ||
| 24 | |||
| 25 | **Testing:** | ||
| 26 | - `2025-11-03-compliance-test-proposal.md` - Test strategy proposal | ||
| 27 | - `2025-11-03-compliance-testing-report.md` - Compliance testing report | ||
| 28 | - `2025-11-03-test-breakdown.md` - Detailed test breakdown | ||
| 29 | - `2025-11-03-smoke-test-report.md` - Smoke test results | ||
| 30 | - `2025-11-03-final-audit-report.md` - Final audit report | ||
| 31 | - `2025-11-03-final-summary.md` - Final summary | ||
| 32 | |||
| 33 | **Reference:** | ||
| 34 | - `2025-11-03-files-created.md` - Files created during investigation | ||
| 35 | - `2025-11-03-quick-reference.md` - Quick reference guide | ||
| 36 | - `2025-11-03-start-here.md` - Getting started guide | ||
| 37 | |||
| 38 | --- | ||
| 39 | |||
| 40 | ### November 4, 2025 - Upgrades & Migrations | ||
| 41 | |||
| 42 | **Tag Migration:** | ||
| 43 | - `2025-11-04-tag-migration.md` - Migration to standard "t" tags (detailed) | ||
| 44 | - `2025-11-04-tag-migration-summary.md` - Migration summary | ||
| 45 | |||
| 46 | **Flake Migration:** | ||
| 47 | - `2025-11-04-flake-migration.md` - shell.nix → flake.nix migration | ||
| 48 | |||
| 49 | **nostr-sdk Upgrade:** | ||
| 50 | - `2025-11-04-nostr-sdk-upgrade.md` - 0.35 → 0.43 upgrade guide | ||
| 51 | - `2025-11-04-upgrade-complete.md` - Upgrade completion report | ||
| 52 | |||
| 53 | **Fixes & Improvements:** | ||
| 54 | - `2025-11-04-compilation-fixes.md` - Compilation fixes | ||
| 55 | - `2025-11-04-audit-system-fixed.md` - Audit system fixes | ||
| 56 | - `2025-11-04-audit-status-report.md` - Audit status report | ||
| 57 | |||
| 58 | **Session Summaries:** | ||
| 59 | - `2025-11-04-session-summary.md` - Main session summary | ||
| 60 | - `2025-11-04-session-complete-1.md` - Session completion 1 | ||
| 61 | - `2025-11-04-session-complete-2.md` - Session completion 2 | ||
| 62 | - `2025-11-04-session-continuation.md` - Session continuation | ||
| 63 | |||
| 64 | **Planning:** | ||
| 65 | - `2025-11-04-next-session-quickstart.md` - Next session quickstart | ||
| 66 | - `2025-11-04-next-prompt.md` - Next prompt planning | ||
| 67 | - `2025-11-04-ready-for-next-phase.md` - Phase readiness report | ||
| 68 | |||
| 69 | --- | ||
| 70 | |||
| 71 | ## Using Archived Documents | ||
| 72 | |||
| 73 | ### When to Reference | ||
| 74 | |||
| 75 | ✅ **Good reasons to reference:** | ||
| 76 | - Understanding historical context | ||
| 77 | - Learning from past decisions | ||
| 78 | - Reviewing what was tried before | ||
| 79 | - Tracking project evolution | ||
| 80 | |||
| 81 | ❌ **Don't reference for:** | ||
| 82 | - Current implementation details (use `docs/` instead) | ||
| 83 | - Active development (use `CURRENT_STATUS.md`) | ||
| 84 | - Reusable patterns (use `docs/learnings/`) | ||
| 85 | |||
| 86 | ### Extracting Learnings | ||
| 87 | |||
| 88 | If you find useful patterns or gotchas in archived documents: | ||
| 89 | |||
| 90 | 1. Extract to appropriate `docs/learnings/*.md` file | ||
| 91 | 2. Update with current context | ||
| 92 | 3. Link to archive for historical context | ||
| 93 | |||
| 94 | **Example:** | ||
| 95 | ```markdown | ||
| 96 | <!-- In docs/learnings/nostr-sdk.md --> | ||
| 97 | |||
| 98 | ## Tag Migration Pattern | ||
| 99 | |||
| 100 | When changing tag structure... | ||
| 101 | |||
| 102 | **Reference:** See `docs/archive/2025-11-04-tag-migration.md` for detailed migration story. | ||
| 103 | ``` | ||
| 104 | |||
| 105 | --- | ||
| 106 | |||
| 107 | ## Archive Principles | ||
| 108 | |||
| 109 | 1. **Immutable**: Documents are not modified after archiving | ||
| 110 | 2. **Dated**: All filenames include YYYY-MM-DD prefix | ||
| 111 | 3. **Organized**: Grouped by date and topic | ||
| 112 | 4. **Referenced**: Can be linked from active docs for context | ||
| 113 | 5. **Searchable**: Full-text search helps find historical info | ||
| 114 | |||
| 115 | --- | ||
| 116 | |||
| 117 | ## Document Lifecycle | ||
| 118 | |||
| 119 | ``` | ||
| 120 | Working Doc (root) | ||
| 121 | ↓ | ||
| 122 | Extract Learnings → docs/learnings/ | ||
| 123 | ↓ | ||
| 124 | Archive → docs/archive/ | ||
| 125 | ↓ | ||
| 126 | Reference (read-only) | ||
| 127 | ``` | ||
| 128 | |||
| 129 | --- | ||
| 130 | |||
| 131 | ## Quick Find | ||
| 132 | |||
| 133 | ### By Topic | ||
| 134 | |||
| 135 | - **Architecture**: `2025-11-03-architecture-investigation.md` | ||
| 136 | - **Testing**: `2025-11-03-*-test-*.md` | ||
| 137 | - **Migrations**: `2025-11-04-*-migration.md` | ||
| 138 | - **Upgrades**: `2025-11-04-*-upgrade.md` | ||
| 139 | - **Sessions**: `2025-11-04-session-*.md` | ||
| 140 | |||
| 141 | ### By Date | ||
| 142 | |||
| 143 | - **Nov 3**: Initial investigation and implementation | ||
| 144 | - **Nov 4**: Upgrades, migrations, and refinements | ||
| 145 | |||
| 146 | --- | ||
| 147 | |||
| 148 | ## Related Documentation | ||
| 149 | |||
| 150 | - **Active Status**: `../CURRENT_STATUS.md` | ||
| 151 | - **Learnings**: `../learnings/` | ||
| 152 | - **Architecture**: `../ARCHITECTURE.md` | ||
| 153 | - **Guidelines**: `../../AGENTS.md` | ||
| 154 | |||
| 155 | --- | ||
| 156 | |||
| 157 | *Archive established: November 4, 2025* | ||
| 158 | *Total documents: 30* | ||
diff --git a/docs/learnings/grasp-audit.md b/docs/learnings/grasp-audit.md new file mode 100644 index 0000000..531ebda --- /dev/null +++ b/docs/learnings/grasp-audit.md | |||
| @@ -0,0 +1,498 @@ | |||
| 1 | # GRASP Audit Tool - Patterns and Learnings | ||
| 2 | |||
| 3 | **Purpose:** Document grasp-audit architecture, patterns, and lessons learned | ||
| 4 | **Last Updated:** November 4, 2025 | ||
| 5 | |||
| 6 | --- | ||
| 7 | |||
| 8 | ## Overview | ||
| 9 | |||
| 10 | `grasp-audit` is a compliance testing tool for GRASP (Git Relays Authorized via Signed-Nostr Proofs) protocol implementations. It tests both Nostr relay compliance (NIP-01) and GRASP-specific functionality. | ||
| 11 | |||
| 12 | --- | ||
| 13 | |||
| 14 | ## Architecture Decisions | ||
| 15 | |||
| 16 | ### Separate Crate Strategy | ||
| 17 | |||
| 18 | **Decision:** Build `grasp-audit` as a separate crate from `ngit-grasp` | ||
| 19 | |||
| 20 | **Why:** | ||
| 21 | 1. **Parallel Development**: Can build tests before implementation | ||
| 22 | 2. **Isolated Testing**: Tests run in isolation (CI/CD safe) | ||
| 23 | 3. **Production Auditing**: Can audit live production services | ||
| 24 | 4. **Reusability**: Other GRASP implementations can use it | ||
| 25 | |||
| 26 | **Location:** `grasp-audit/` subdirectory with own `Cargo.toml` and `flake.nix` | ||
| 27 | |||
| 28 | --- | ||
| 29 | |||
| 30 | ### Audit Event Tagging Strategy | ||
| 31 | |||
| 32 | **Problem:** Test events pollute the relay and need cleanup without deletion events. | ||
| 33 | |||
| 34 | **Solution:** Use special tags to mark audit events: | ||
| 35 | |||
| 36 | ```rust | ||
| 37 | // Every audit event includes these tags | ||
| 38 | [ | ||
| 39 | ["t", "grasp-audit-test-event"], // Marker | ||
| 40 | ["t", "audit-{run-id}"], // Run isolation | ||
| 41 | ["t", "audit-cleanup-after-{timestamp}"] // Cleanup time | ||
| 42 | ] | ||
| 43 | ``` | ||
| 44 | |||
| 45 | **Benefits:** | ||
| 46 | - ✅ **Queryable**: Can find all audit events via tag filter | ||
| 47 | - ✅ **Isolated**: Each test run has unique run ID | ||
| 48 | - ✅ **Self-cleaning**: Cleanup timestamp indicates when to delete | ||
| 49 | - ✅ **No deletion events**: Direct database cleanup, no KIND 5 events | ||
| 50 | - ✅ **Production safe**: Won't interfere with real events | ||
| 51 | |||
| 52 | **Reference:** See `docs/archive/2025-11-04-tag-migration.md` | ||
| 53 | |||
| 54 | --- | ||
| 55 | |||
| 56 | ### Standard "t" Tags vs Custom Tags | ||
| 57 | |||
| 58 | **Evolution:** | ||
| 59 | 1. **Original**: Custom single-letter tags (`g`, `r`, `c`) | ||
| 60 | 2. **Current**: Standard NIP-01 "t" tags with prefixed values | ||
| 61 | |||
| 62 | **Why we changed:** | ||
| 63 | - ❌ Custom tags could conflict with other systems | ||
| 64 | - ✅ "t" tag is standard for categorization/topics | ||
| 65 | - ✅ Multiple "t" tags are expected and supported | ||
| 66 | - ✅ Self-documenting values (`audit-{run-id}` vs just `{run-id}`) | ||
| 67 | - ✅ Better namespacing with prefixes | ||
| 68 | |||
| 69 | **Migration:** Completed November 4, 2025 | ||
| 70 | |||
| 71 | --- | ||
| 72 | |||
| 73 | ## Code Patterns | ||
| 74 | |||
| 75 | ### Audit Configuration | ||
| 76 | |||
| 77 | ```rust | ||
| 78 | use grasp_audit::audit::AuditConfig; | ||
| 79 | |||
| 80 | // CI mode - isolated test runs | ||
| 81 | let config = AuditConfig::ci(); | ||
| 82 | // Generates UUID run ID: "ci-{uuid}" | ||
| 83 | // Cleanup after 1 hour | ||
| 84 | |||
| 85 | // Production mode - persistent run ID | ||
| 86 | let config = AuditConfig::production("prod-server-1"); | ||
| 87 | // Uses provided run ID | ||
| 88 | // Cleanup after 24 hours | ||
| 89 | ``` | ||
| 90 | |||
| 91 | **When to use:** | ||
| 92 | - **CI mode**: Automated testing, parallel runs, temporary | ||
| 93 | - **Production mode**: Manual audits, monitoring, persistent | ||
| 94 | |||
| 95 | --- | ||
| 96 | |||
| 97 | ### Creating Audit Events | ||
| 98 | |||
| 99 | ```rust | ||
| 100 | use grasp_audit::audit::{AuditConfig, AuditEventBuilder}; | ||
| 101 | use nostr_sdk::prelude::*; | ||
| 102 | |||
| 103 | let config = AuditConfig::ci(); | ||
| 104 | let keys = Keys::generate(); | ||
| 105 | |||
| 106 | // Create audit event | ||
| 107 | let event = AuditEventBuilder::new(&config, Kind::TextNote, "test content") | ||
| 108 | .build(&keys)?; | ||
| 109 | |||
| 110 | // Event automatically includes: | ||
| 111 | // - Audit marker tag | ||
| 112 | // - Run ID tag | ||
| 113 | // - Cleanup timestamp tag | ||
| 114 | ``` | ||
| 115 | |||
| 116 | --- | ||
| 117 | |||
| 118 | ### Querying Audit Events | ||
| 119 | |||
| 120 | ```rust | ||
| 121 | use grasp_audit::client::AuditClient; | ||
| 122 | use grasp_audit::audit::AuditConfig; | ||
| 123 | |||
| 124 | let config = AuditConfig::ci(); | ||
| 125 | let client = AuditClient::new(config, keys); | ||
| 126 | |||
| 127 | // Connect to relay | ||
| 128 | client.add_relay("ws://localhost:7000").await?; | ||
| 129 | client.connect().await; | ||
| 130 | |||
| 131 | // Query audit events for this run | ||
| 132 | let events = client.query().await?; | ||
| 133 | |||
| 134 | // Events are filtered by: | ||
| 135 | // - "grasp-audit-test-event" marker | ||
| 136 | // - Current run ID | ||
| 137 | ``` | ||
| 138 | |||
| 139 | --- | ||
| 140 | |||
| 141 | ### Test Isolation | ||
| 142 | |||
| 143 | **Each test run is isolated by unique run ID:** | ||
| 144 | |||
| 145 | ```rust | ||
| 146 | // CI mode generates unique UUID per run | ||
| 147 | let config1 = AuditConfig::ci(); | ||
| 148 | let config2 = AuditConfig::ci(); | ||
| 149 | |||
| 150 | // config1.run_id != config2.run_id | ||
| 151 | // Tests won't interfere with each other | ||
| 152 | ``` | ||
| 153 | |||
| 154 | **Benefits:** | ||
| 155 | - ✅ Parallel CI/CD runs don't conflict | ||
| 156 | - ✅ Can run multiple test suites simultaneously | ||
| 157 | - ✅ Easy to identify which run created which events | ||
| 158 | - ✅ Cleanup can target specific runs | ||
| 159 | |||
| 160 | --- | ||
| 161 | |||
| 162 | ### Cleanup Strategy | ||
| 163 | |||
| 164 | **Two-phase cleanup:** | ||
| 165 | |||
| 166 | 1. **Automatic expiry** via cleanup timestamp tag | ||
| 167 | 2. **Manual cleanup** by querying and deleting | ||
| 168 | |||
| 169 | ```rust | ||
| 170 | // Events include cleanup timestamp | ||
| 171 | ["t", "audit-cleanup-after-1730707200"] | ||
| 172 | |||
| 173 | // Cleanup process: | ||
| 174 | // 1. Query events with expired cleanup timestamp | ||
| 175 | // 2. Delete from database directly (no KIND 5) | ||
| 176 | // 3. Avoid deletion event pollution | ||
| 177 | ``` | ||
| 178 | |||
| 179 | **Implementation:** To be built in relay (not in audit tool) | ||
| 180 | |||
| 181 | --- | ||
| 182 | |||
| 183 | ## Testing Strategy | ||
| 184 | |||
| 185 | ### Test Organization | ||
| 186 | |||
| 187 | ``` | ||
| 188 | grasp-audit/src/specs/ | ||
| 189 | ├── nip01_smoke.rs # NIP-01 basic functionality | ||
| 190 | ├── grasp_01_relay.rs # GRASP-01 relay requirements (planned) | ||
| 191 | └── mod.rs # Test suite registry | ||
| 192 | ``` | ||
| 193 | |||
| 194 | ### Unit vs Integration Tests | ||
| 195 | |||
| 196 | **Unit Tests** (no relay required): | ||
| 197 | ```rust | ||
| 198 | #[cfg(test)] | ||
| 199 | mod tests { | ||
| 200 | #[test] | ||
| 201 | fn test_audit_config() { | ||
| 202 | let config = AuditConfig::ci(); | ||
| 203 | assert!(config.run_id.starts_with("ci-")); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | ``` | ||
| 207 | |||
| 208 | **Integration Tests** (relay required): | ||
| 209 | ```rust | ||
| 210 | #[cfg(test)] | ||
| 211 | mod tests { | ||
| 212 | #[tokio::test] | ||
| 213 | #[ignore] // Requires relay | ||
| 214 | async fn test_smoke_tests_against_relay() { | ||
| 215 | // Test against real relay | ||
| 216 | } | ||
| 217 | } | ||
| 218 | ``` | ||
| 219 | |||
| 220 | **Running tests:** | ||
| 221 | ```bash | ||
| 222 | # Unit tests (fast, no dependencies) | ||
| 223 | cargo test --lib | ||
| 224 | |||
| 225 | # Integration tests (requires relay) | ||
| 226 | docker run --rm -p 7000:7000 scsibug/nostr-rs-relay | ||
| 227 | cargo test -- --ignored | ||
| 228 | ``` | ||
| 229 | |||
| 230 | --- | ||
| 231 | |||
| 232 | ### Test Result Reporting | ||
| 233 | |||
| 234 | ```rust | ||
| 235 | use grasp_audit::result::AuditResult; | ||
| 236 | |||
| 237 | // Run tests | ||
| 238 | let results = vec![ | ||
| 239 | AuditResult::pass("websocket_connection", "Connected successfully"), | ||
| 240 | AuditResult::fail("invalid_event", "Expected rejection, got acceptance"), | ||
| 241 | ]; | ||
| 242 | |||
| 243 | // Report | ||
| 244 | for result in &results { | ||
| 245 | println!("{}", result); | ||
| 246 | } | ||
| 247 | |||
| 248 | // Summary | ||
| 249 | let passed = results.iter().filter(|r| r.is_pass()).count(); | ||
| 250 | let total = results.len(); | ||
| 251 | println!("Results: {}/{} passed ({:.1}%)", | ||
| 252 | passed, total, (passed as f64 / total as f64) * 100.0); | ||
| 253 | ``` | ||
| 254 | |||
| 255 | --- | ||
| 256 | |||
| 257 | ## CLI Design | ||
| 258 | |||
| 259 | ### Command Structure | ||
| 260 | |||
| 261 | ```bash | ||
| 262 | grasp-audit audit [OPTIONS] | ||
| 263 | |||
| 264 | Options: | ||
| 265 | --relay <URL> Relay to test (required) | ||
| 266 | --mode <MODE> ci or production (default: ci) | ||
| 267 | --run-id <ID> Custom run ID (production mode only) | ||
| 268 | --spec <SPEC> Test spec to run (default: all) | ||
| 269 | --verbose Detailed output | ||
| 270 | ``` | ||
| 271 | |||
| 272 | ### Usage Examples | ||
| 273 | |||
| 274 | ```bash | ||
| 275 | # CI mode - quick smoke test | ||
| 276 | grasp-audit audit \ | ||
| 277 | --relay ws://localhost:7000 \ | ||
| 278 | --mode ci \ | ||
| 279 | --spec nip01-smoke | ||
| 280 | |||
| 281 | # Production mode - full compliance audit | ||
| 282 | grasp-audit audit \ | ||
| 283 | --relay wss://relay.example.com \ | ||
| 284 | --mode production \ | ||
| 285 | --run-id "audit-2025-11-04" \ | ||
| 286 | --verbose | ||
| 287 | |||
| 288 | # Test all specs | ||
| 289 | grasp-audit audit --relay ws://localhost:7000 | ||
| 290 | ``` | ||
| 291 | |||
| 292 | --- | ||
| 293 | |||
| 294 | ## Lessons Learned | ||
| 295 | |||
| 296 | ### 1. Tag Migration is Breaking | ||
| 297 | |||
| 298 | **Lesson:** Changing tag structure breaks event queries. | ||
| 299 | |||
| 300 | **Impact:** Events created with old tags won't be found by new queries. | ||
| 301 | |||
| 302 | **Mitigation:** | ||
| 303 | - ✅ Accept breaking changes in alpha stage | ||
| 304 | - ✅ Document migration clearly | ||
| 305 | - ✅ Old events auto-expire via cleanup | ||
| 306 | - ✅ No production deployments affected | ||
| 307 | |||
| 308 | **Reference:** `docs/archive/2025-11-04-tag-migration.md` | ||
| 309 | |||
| 310 | --- | ||
| 311 | |||
| 312 | ### 2. Test Data Lifecycle Matters | ||
| 313 | |||
| 314 | **Lesson:** Test events accumulate and pollute relay. | ||
| 315 | |||
| 316 | **Solution:** Built-in cleanup strategy from day one. | ||
| 317 | |||
| 318 | **Implementation:** | ||
| 319 | - Every event has cleanup timestamp | ||
| 320 | - Relay can cleanup expired events | ||
| 321 | - No deletion event pollution (direct DB cleanup) | ||
| 322 | |||
| 323 | --- | ||
| 324 | |||
| 325 | ### 3. Isolation Enables Parallel Testing | ||
| 326 | |||
| 327 | **Lesson:** Unique run IDs enable parallel test execution. | ||
| 328 | |||
| 329 | **Benefit:** CI/CD can run multiple test suites simultaneously. | ||
| 330 | |||
| 331 | **Pattern:** | ||
| 332 | ```rust | ||
| 333 | // Each CI run gets unique ID | ||
| 334 | let config = AuditConfig::ci(); | ||
| 335 | // run_id = "ci-{uuid}" | ||
| 336 | |||
| 337 | // Tests isolated by run ID | ||
| 338 | let events = client.query().await?; | ||
| 339 | // Only returns events for this run | ||
| 340 | ``` | ||
| 341 | |||
| 342 | --- | ||
| 343 | |||
| 344 | ### 4. Standards Compliance Reduces Friction | ||
| 345 | |||
| 346 | **Lesson:** Using standard NIP-01 "t" tags instead of custom tags. | ||
| 347 | |||
| 348 | **Benefits:** | ||
| 349 | - ✅ No conflicts with other systems | ||
| 350 | - ✅ Standard relay filtering works | ||
| 351 | - ✅ Better interoperability | ||
| 352 | - ✅ Self-documenting | ||
| 353 | |||
| 354 | --- | ||
| 355 | |||
| 356 | ## Future Enhancements | ||
| 357 | |||
| 358 | ### Planned Features | ||
| 359 | |||
| 360 | - [ ] **GRASP-01 Test Suite**: Repository announcement and state event tests | ||
| 361 | - [ ] **Test Report Generation**: JSON/HTML output for CI/CD | ||
| 362 | - [ ] **Performance Benchmarks**: Measure relay performance | ||
| 363 | - [ ] **Relay Comparison**: Side-by-side compliance comparison | ||
| 364 | - [ ] **Continuous Monitoring**: Periodic production audits | ||
| 365 | |||
| 366 | --- | ||
| 367 | |||
| 368 | ### Possible Improvements | ||
| 369 | |||
| 370 | - [ ] **Parallel Test Execution**: Run specs in parallel | ||
| 371 | - [ ] **Retry Logic**: Handle transient failures | ||
| 372 | - [ ] **Custom Assertions**: Domain-specific test helpers | ||
| 373 | - [ ] **Event Diff Tool**: Compare expected vs actual events | ||
| 374 | - [ ] **Cleanup Automation**: Auto-cleanup after tests | ||
| 375 | |||
| 376 | --- | ||
| 377 | |||
| 378 | ## Common Issues | ||
| 379 | |||
| 380 | ### Issue: Integration Tests Fail | ||
| 381 | |||
| 382 | **Symptoms:** Tests timeout or fail to connect | ||
| 383 | |||
| 384 | **Causes:** | ||
| 385 | 1. No relay running | ||
| 386 | 2. Wrong relay URL | ||
| 387 | 3. Firewall blocking connection | ||
| 388 | |||
| 389 | **Solution:** | ||
| 390 | ```bash | ||
| 391 | # Start relay | ||
| 392 | docker run --rm -p 7000:7000 scsibug/nostr-rs-relay | ||
| 393 | |||
| 394 | # Verify relay is running | ||
| 395 | curl http://localhost:7000 | ||
| 396 | |||
| 397 | # Run tests | ||
| 398 | cargo test -- --ignored | ||
| 399 | ``` | ||
| 400 | |||
| 401 | --- | ||
| 402 | |||
| 403 | ### Issue: Events Not Found in Query | ||
| 404 | |||
| 405 | **Symptoms:** Query returns empty even though events were sent | ||
| 406 | |||
| 407 | **Causes:** | ||
| 408 | 1. Wrong run ID (querying different run) | ||
| 409 | 2. Connection timing (query before event propagated) | ||
| 410 | 3. Tag mismatch (uppercase vs lowercase) | ||
| 411 | |||
| 412 | **Solution:** | ||
| 413 | ```rust | ||
| 414 | // Use same config for send and query | ||
| 415 | let config = AuditConfig::ci(); | ||
| 416 | |||
| 417 | // Wait for event to propagate | ||
| 418 | tokio::time::sleep(Duration::from_millis(500)).await; | ||
| 419 | |||
| 420 | // Verify tags match exactly | ||
| 421 | let t_tag = SingleLetterTag::lowercase(Alphabet::T); // Lowercase! | ||
| 422 | ``` | ||
| 423 | |||
| 424 | --- | ||
| 425 | |||
| 426 | ### Issue: Build Fails in CI | ||
| 427 | |||
| 428 | **Symptoms:** `cargo build` fails with dependency errors | ||
| 429 | |||
| 430 | **Cause:** Not in Nix dev environment | ||
| 431 | |||
| 432 | **Solution:** | ||
| 433 | ```bash | ||
| 434 | # Enter Nix environment first | ||
| 435 | cd grasp-audit | ||
| 436 | nix develop | ||
| 437 | |||
| 438 | # Then build | ||
| 439 | cargo build | ||
| 440 | ``` | ||
| 441 | |||
| 442 | --- | ||
| 443 | |||
| 444 | ## Quick Reference | ||
| 445 | |||
| 446 | ### Configuration | ||
| 447 | |||
| 448 | ```rust | ||
| 449 | // CI mode | ||
| 450 | let config = AuditConfig::ci(); | ||
| 451 | |||
| 452 | // Production mode | ||
| 453 | let config = AuditConfig::production("run-id"); | ||
| 454 | ``` | ||
| 455 | |||
| 456 | ### Event Creation | ||
| 457 | |||
| 458 | ```rust | ||
| 459 | let event = AuditEventBuilder::new(&config, kind, content) | ||
| 460 | .build(&keys)?; | ||
| 461 | ``` | ||
| 462 | |||
| 463 | ### Client Usage | ||
| 464 | |||
| 465 | ```rust | ||
| 466 | let client = AuditClient::new(config, keys); | ||
| 467 | client.add_relay("ws://localhost:7000").await?; | ||
| 468 | client.connect().await; | ||
| 469 | let events = client.query().await?; | ||
| 470 | ``` | ||
| 471 | |||
| 472 | ### Running Tests | ||
| 473 | |||
| 474 | ```bash | ||
| 475 | # Unit tests | ||
| 476 | cargo test --lib | ||
| 477 | |||
| 478 | # Integration tests | ||
| 479 | cargo test -- --ignored | ||
| 480 | |||
| 481 | # CLI | ||
| 482 | cargo run -- audit --relay ws://localhost:7000 | ||
| 483 | ``` | ||
| 484 | |||
| 485 | --- | ||
| 486 | |||
| 487 | ## References | ||
| 488 | |||
| 489 | - **GRASP Protocol**: https://gitworkshop.dev/danconwaydev.com/grasp | ||
| 490 | - **NIP-01**: https://github.com/nostr-protocol/nips/blob/master/01.md | ||
| 491 | - **NIP-34**: https://github.com/nostr-protocol/nips/blob/master/34.md | ||
| 492 | - **grasp-audit README**: `grasp-audit/README.md` | ||
| 493 | - **Tag Migration**: `docs/archive/2025-11-04-tag-migration.md` | ||
| 494 | |||
| 495 | --- | ||
| 496 | |||
| 497 | *Last updated: November 4, 2025* | ||
| 498 | *Status: Living document - update as grasp-audit evolves* | ||
diff --git a/docs/learnings/nix-flakes.md b/docs/learnings/nix-flakes.md new file mode 100644 index 0000000..6876647 --- /dev/null +++ b/docs/learnings/nix-flakes.md | |||
| @@ -0,0 +1,423 @@ | |||
| 1 | # Nix Flakes - Learnings and Gotchas | ||
| 2 | |||
| 3 | **Purpose:** Document Nix flake patterns, gotchas, and best practices learned during ngit-grasp development | ||
| 4 | **Last Updated:** November 4, 2025 | ||
| 5 | |||
| 6 | --- | ||
| 7 | |||
| 8 | ## Critical Gotchas | ||
| 9 | |||
| 10 | ### Always Use `nix develop`, Not `nix-shell` | ||
| 11 | |||
| 12 | **Problem:** We use `flake.nix`, not `shell.nix`. Using `nix-shell` will fail or use the wrong environment. | ||
| 13 | |||
| 14 | ```bash | ||
| 15 | # ✅ Correct - for flake.nix | ||
| 16 | cd grasp-audit | ||
| 17 | nix develop | ||
| 18 | nix develop -c cargo build | ||
| 19 | |||
| 20 | # ❌ Wrong - for shell.nix (we don't use this) | ||
| 21 | nix-shell | ||
| 22 | nix-shell --run "cargo build" | ||
| 23 | ``` | ||
| 24 | |||
| 25 | **Why:** | ||
| 26 | - `nix-shell` looks for `shell.nix` or `default.nix` | ||
| 27 | - `nix develop` looks for `flake.nix` | ||
| 28 | - We migrated from `shell.nix` to `flake.nix` on November 4, 2025 | ||
| 29 | |||
| 30 | **Related:** See `docs/archive/2025-11-04-flake-migration.md` | ||
| 31 | |||
| 32 | --- | ||
| 33 | |||
| 34 | ## Flake Structure | ||
| 35 | |||
| 36 | ### Our Standard Flake Pattern | ||
| 37 | |||
| 38 | ```nix | ||
| 39 | { | ||
| 40 | inputs = { | ||
| 41 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; | ||
| 42 | rust-overlay.url = "github:oxalica/rust-overlay"; | ||
| 43 | flake-utils.url = "github:numtide/flake-utils"; | ||
| 44 | }; | ||
| 45 | |||
| 46 | outputs = { nixpkgs, rust-overlay, flake-utils, ... }: | ||
| 47 | flake-utils.lib.eachDefaultSystem (system: | ||
| 48 | let | ||
| 49 | overlays = [ (import rust-overlay) ]; | ||
| 50 | pkgs = import nixpkgs { inherit system overlays; }; | ||
| 51 | manifest = pkgs.lib.importTOML ./Cargo.toml; | ||
| 52 | in with pkgs; { | ||
| 53 | # Development shell | ||
| 54 | devShells.default = mkShell { | ||
| 55 | nativeBuildInputs = [ | ||
| 56 | rust-bin.stable.latest.default | ||
| 57 | pkg-config | ||
| 58 | gitlint | ||
| 59 | ]; | ||
| 60 | buildInputs = [ | ||
| 61 | openssl | ||
| 62 | ]; | ||
| 63 | shellHook = '' | ||
| 64 | echo "🦀 Development environment loaded" | ||
| 65 | export RUST_SRC_PATH=${pkgs.rustPlatform.rustLibSrc} | ||
| 66 | ''; | ||
| 67 | }; | ||
| 68 | |||
| 69 | # Package output | ||
| 70 | packages.default = pkgs.rustPlatform.buildRustPackage { | ||
| 71 | pname = manifest.package.name; | ||
| 72 | version = manifest.package.version; | ||
| 73 | src = ./.; | ||
| 74 | cargoLock = { lockFile = ./Cargo.lock; }; | ||
| 75 | buildInputs = [ openssl ]; | ||
| 76 | nativeBuildInputs = [ pkg-config ]; | ||
| 77 | doCheck = false; # Run tests separately | ||
| 78 | }; | ||
| 79 | }); | ||
| 80 | } | ||
| 81 | ``` | ||
| 82 | |||
| 83 | ### Key Components | ||
| 84 | |||
| 85 | 1. **rust-overlay**: Provides latest stable Rust toolchain | ||
| 86 | 2. **flake-utils**: Cross-platform support helper | ||
| 87 | 3. **manifest**: Auto-read version from Cargo.toml | ||
| 88 | 4. **devShells.default**: Development environment | ||
| 89 | 5. **packages.default**: Buildable package | ||
| 90 | |||
| 91 | --- | ||
| 92 | |||
| 93 | ## Common Flake Commands | ||
| 94 | |||
| 95 | ### Essential Commands | ||
| 96 | |||
| 97 | ```bash | ||
| 98 | # Enter development shell | ||
| 99 | nix develop | ||
| 100 | |||
| 101 | # Run command in dev shell (one-off) | ||
| 102 | nix develop -c cargo build | ||
| 103 | |||
| 104 | # Show flake outputs | ||
| 105 | nix flake show | ||
| 106 | |||
| 107 | # Check flake validity | ||
| 108 | nix flake check | ||
| 109 | |||
| 110 | # Update flake inputs (like updating dependencies) | ||
| 111 | nix flake update | ||
| 112 | |||
| 113 | # Build the package directly | ||
| 114 | nix build | ||
| 115 | |||
| 116 | # Run without installing | ||
| 117 | nix run | ||
| 118 | |||
| 119 | # Show flake metadata | ||
| 120 | nix flake metadata | ||
| 121 | ``` | ||
| 122 | |||
| 123 | ### Debugging Commands | ||
| 124 | |||
| 125 | ```bash | ||
| 126 | # Show detailed evaluation trace | ||
| 127 | nix develop --show-trace | ||
| 128 | |||
| 129 | # Print flake evaluation | ||
| 130 | nix eval .#devShells.x86_64-linux.default | ||
| 131 | |||
| 132 | # Check what's in the store | ||
| 133 | nix path-info .#packages.x86_64-linux.default | ||
| 134 | ``` | ||
| 135 | |||
| 136 | --- | ||
| 137 | |||
| 138 | ## Subproject Flakes | ||
| 139 | |||
| 140 | ### grasp-audit Has Its Own Flake | ||
| 141 | |||
| 142 | **Important:** `grasp-audit/` is a subproject with its own `flake.nix` and `Cargo.toml`. | ||
| 143 | |||
| 144 | ```bash | ||
| 145 | # ✅ Correct - enter grasp-audit environment | ||
| 146 | cd grasp-audit | ||
| 147 | nix develop | ||
| 148 | cargo build | ||
| 149 | |||
| 150 | # ❌ Wrong - can't build from root | ||
| 151 | cd ngit-grasp | ||
| 152 | cargo build # This won't find grasp-audit dependencies | ||
| 153 | ``` | ||
| 154 | |||
| 155 | **Why:** | ||
| 156 | - Each Rust workspace needs its own Nix environment | ||
| 157 | - Dependencies are project-specific | ||
| 158 | - Flake inputs are locked per-project | ||
| 159 | |||
| 160 | --- | ||
| 161 | |||
| 162 | ## Migration from shell.nix to flake.nix | ||
| 163 | |||
| 164 | ### What Changed | ||
| 165 | |||
| 166 | **Before (shell.nix):** | ||
| 167 | ```nix | ||
| 168 | { pkgs ? import <nixpkgs> {} }: | ||
| 169 | |||
| 170 | pkgs.mkShell { | ||
| 171 | buildInputs = with pkgs; [ | ||
| 172 | rustc | ||
| 173 | cargo | ||
| 174 | openssl | ||
| 175 | pkg-config | ||
| 176 | ]; | ||
| 177 | } | ||
| 178 | ``` | ||
| 179 | |||
| 180 | **After (flake.nix):** | ||
| 181 | - Locked inputs (reproducible) | ||
| 182 | - Multi-output (dev shell + package) | ||
| 183 | - Cross-platform by default | ||
| 184 | - Better tooling integration | ||
| 185 | |||
| 186 | ### Migration Steps | ||
| 187 | |||
| 188 | 1. Create `flake.nix` with standard structure | ||
| 189 | 2. Run `nix flake check` to validate | ||
| 190 | 3. Update all documentation: `nix-shell` → `nix develop` | ||
| 191 | 4. Test that build works: `nix develop -c cargo build` | ||
| 192 | 5. Remove `shell.nix` | ||
| 193 | 6. Commit changes | ||
| 194 | |||
| 195 | **Reference:** See `docs/archive/2025-11-04-flake-migration.md` | ||
| 196 | |||
| 197 | --- | ||
| 198 | |||
| 199 | ## Benefits of Flakes | ||
| 200 | |||
| 201 | ### Reproducibility | ||
| 202 | |||
| 203 | **Locked inputs** ensure everyone gets the same environment: | ||
| 204 | |||
| 205 | ```bash | ||
| 206 | # flake.lock contains exact commits | ||
| 207 | $ cat flake.lock | ||
| 208 | { | ||
| 209 | "nodes": { | ||
| 210 | "nixpkgs": { | ||
| 211 | "locked": { | ||
| 212 | "lastModified": 1698611440, | ||
| 213 | "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", | ||
| 214 | "rev": "23e89e0c8c5e2d9cf5b5e7c3e8e8e8e8e8e8e8e8" | ||
| 215 | } | ||
| 216 | } | ||
| 217 | } | ||
| 218 | } | ||
| 219 | ``` | ||
| 220 | |||
| 221 | Everyone running `nix develop` gets **exactly** this version of nixpkgs. | ||
| 222 | |||
| 223 | ### Multi-Output | ||
| 224 | |||
| 225 | Single flake provides: | ||
| 226 | - **devShells.default**: Development environment | ||
| 227 | - **packages.default**: Buildable package | ||
| 228 | - **apps.default**: Runnable application (optional) | ||
| 229 | |||
| 230 | ### Composability | ||
| 231 | |||
| 232 | Flakes can use other flakes as inputs: | ||
| 233 | |||
| 234 | ```nix | ||
| 235 | { | ||
| 236 | inputs = { | ||
| 237 | grasp-audit.url = "path:./grasp-audit"; | ||
| 238 | }; | ||
| 239 | } | ||
| 240 | ``` | ||
| 241 | |||
| 242 | --- | ||
| 243 | |||
| 244 | ## Common Issues | ||
| 245 | |||
| 246 | ### Issue: "error: getting status of '/nix/store/...': No such file or directory" | ||
| 247 | |||
| 248 | **Cause:** Flake inputs need to be updated or fetched | ||
| 249 | |||
| 250 | **Solution:** | ||
| 251 | ```bash | ||
| 252 | nix flake update | ||
| 253 | nix develop | ||
| 254 | ``` | ||
| 255 | |||
| 256 | ### Issue: "error: experimental feature 'nix-command' is not enabled" | ||
| 257 | |||
| 258 | **Cause:** Nix flakes are experimental and need to be enabled | ||
| 259 | |||
| 260 | **Solution:** | ||
| 261 | Add to `~/.config/nix/nix.conf`: | ||
| 262 | ``` | ||
| 263 | experimental-features = nix-command flakes | ||
| 264 | ``` | ||
| 265 | |||
| 266 | ### Issue: Changes to flake.nix not taking effect | ||
| 267 | |||
| 268 | **Cause:** Flake evaluation is cached | ||
| 269 | |||
| 270 | **Solution:** | ||
| 271 | ```bash | ||
| 272 | # Clear evaluation cache | ||
| 273 | nix flake update | ||
| 274 | # Or force re-evaluation | ||
| 275 | nix develop --refresh | ||
| 276 | ``` | ||
| 277 | |||
| 278 | ### Issue: "error: cannot find flake 'flake:self' in the flake registries" | ||
| 279 | |||
| 280 | **Cause:** Not in a git repository or flake.nix not committed | ||
| 281 | |||
| 282 | **Solution:** | ||
| 283 | ```bash | ||
| 284 | git add flake.nix flake.lock | ||
| 285 | git commit -m "Add flake" | ||
| 286 | ``` | ||
| 287 | |||
| 288 | **Note:** Flakes require git. Uncommitted files are ignored by default. | ||
| 289 | |||
| 290 | --- | ||
| 291 | |||
| 292 | ## Best Practices | ||
| 293 | |||
| 294 | ### 1. Always Commit flake.lock | ||
| 295 | |||
| 296 | ```bash | ||
| 297 | git add flake.lock | ||
| 298 | git commit -m "Update flake inputs" | ||
| 299 | ``` | ||
| 300 | |||
| 301 | **Why:** Ensures reproducibility across machines and CI/CD | ||
| 302 | |||
| 303 | ### 2. Use Specific Rust Versions When Needed | ||
| 304 | |||
| 305 | ```nix | ||
| 306 | # Latest stable (default) | ||
| 307 | rust-bin.stable.latest.default | ||
| 308 | |||
| 309 | # Specific version | ||
| 310 | rust-bin.stable."1.75.0".default | ||
| 311 | |||
| 312 | # Nightly | ||
| 313 | rust-bin.nightly."2024-01-01".default | ||
| 314 | ``` | ||
| 315 | |||
| 316 | ### 3. Include Helpful Shell Hooks | ||
| 317 | |||
| 318 | ```nix | ||
| 319 | shellHook = '' | ||
| 320 | echo "🦀 GRASP Audit development environment" | ||
| 321 | echo "" | ||
| 322 | echo "Common commands:" | ||
| 323 | echo " cargo build - Build project" | ||
| 324 | echo " cargo test - Run tests" | ||
| 325 | echo " cargo run - Run binary" | ||
| 326 | echo "" | ||
| 327 | export RUST_SRC_PATH=${pkgs.rustPlatform.rustLibSrc} | ||
| 328 | ''; | ||
| 329 | ``` | ||
| 330 | |||
| 331 | ### 4. Separate Build and Runtime Dependencies | ||
| 332 | |||
| 333 | ```nix | ||
| 334 | # Build-time only | ||
| 335 | nativeBuildInputs = [ | ||
| 336 | pkg-config | ||
| 337 | rustc | ||
| 338 | cargo | ||
| 339 | ]; | ||
| 340 | |||
| 341 | # Runtime needed | ||
| 342 | buildInputs = [ | ||
| 343 | openssl | ||
| 344 | ]; | ||
| 345 | ``` | ||
| 346 | |||
| 347 | ### 5. Disable Tests in Package Build | ||
| 348 | |||
| 349 | ```nix | ||
| 350 | packages.default = pkgs.rustPlatform.buildRustPackage { | ||
| 351 | # ... | ||
| 352 | doCheck = false; # Run tests separately with cargo test | ||
| 353 | }; | ||
| 354 | ``` | ||
| 355 | |||
| 356 | **Why:** Faster builds, tests run via `cargo test` in dev shell | ||
| 357 | |||
| 358 | --- | ||
| 359 | |||
| 360 | ## Workflow Examples | ||
| 361 | |||
| 362 | ### Daily Development | ||
| 363 | |||
| 364 | ```bash | ||
| 365 | # Start work | ||
| 366 | cd grasp-audit | ||
| 367 | nix develop | ||
| 368 | |||
| 369 | # Inside nix shell | ||
| 370 | cargo build | ||
| 371 | cargo test | ||
| 372 | cargo run -- --help | ||
| 373 | |||
| 374 | # Exit shell | ||
| 375 | exit | ||
| 376 | ``` | ||
| 377 | |||
| 378 | ### CI/CD | ||
| 379 | |||
| 380 | ```bash | ||
| 381 | # One-off commands (no interactive shell) | ||
| 382 | nix develop -c cargo build | ||
| 383 | nix develop -c cargo test --lib | ||
| 384 | nix develop -c cargo test -- --ignored | ||
| 385 | ``` | ||
| 386 | |||
| 387 | ### Building Release | ||
| 388 | |||
| 389 | ```bash | ||
| 390 | # Build package directly | ||
| 391 | nix build | ||
| 392 | |||
| 393 | # Result is in ./result/bin/ | ||
| 394 | ./result/bin/grasp-audit --version | ||
| 395 | ``` | ||
| 396 | |||
| 397 | --- | ||
| 398 | |||
| 399 | ## References | ||
| 400 | |||
| 401 | - **Nix Flakes Manual**: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html | ||
| 402 | - **rust-overlay**: https://github.com/oxalica/rust-overlay | ||
| 403 | - **flake-utils**: https://github.com/numtide/flake-utils | ||
| 404 | - **Our Migration**: `docs/archive/2025-11-04-flake-migration.md` | ||
| 405 | |||
| 406 | --- | ||
| 407 | |||
| 408 | ## Quick Reference | ||
| 409 | |||
| 410 | | Task | Command | | ||
| 411 | |------|---------| | ||
| 412 | | Enter dev shell | `nix develop` | | ||
| 413 | | Run one command | `nix develop -c <command>` | | ||
| 414 | | Show outputs | `nix flake show` | | ||
| 415 | | Validate flake | `nix flake check` | | ||
| 416 | | Update inputs | `nix flake update` | | ||
| 417 | | Build package | `nix build` | | ||
| 418 | | Run package | `nix run` | | ||
| 419 | |||
| 420 | --- | ||
| 421 | |||
| 422 | *Last updated: November 4, 2025* | ||
| 423 | *Status: Living document - update as we learn more* | ||
diff --git a/docs/learnings/nostr-sdk.md b/docs/learnings/nostr-sdk.md new file mode 100644 index 0000000..57f451a --- /dev/null +++ b/docs/learnings/nostr-sdk.md | |||
| @@ -0,0 +1,577 @@ | |||
| 1 | # nostr-sdk - Learnings and Patterns | ||
| 2 | |||
| 3 | **Purpose:** Document nostr-sdk usage patterns, upgrade notes, and gotchas | ||
| 4 | **Last Updated:** November 4, 2025 | ||
| 5 | |||
| 6 | --- | ||
| 7 | |||
| 8 | ## Current Version | ||
| 9 | |||
| 10 | **We use nostr-sdk 0.43.x (latest stable)** | ||
| 11 | |||
| 12 | ```toml | ||
| 13 | [dependencies] | ||
| 14 | nostr-sdk = "0.43" | ||
| 15 | ``` | ||
| 16 | |||
| 17 | **Upgraded from:** 0.35.0 on November 4, 2025 | ||
| 18 | |||
| 19 | --- | ||
| 20 | |||
| 21 | ## Critical Breaking Changes (0.35 → 0.43) | ||
| 22 | |||
| 23 | ### 1. EventBuilder API Changed | ||
| 24 | |||
| 25 | **Before (0.35):** | ||
| 26 | ```rust | ||
| 27 | let event = EventBuilder::new(kind, content, tags) | ||
| 28 | .to_event(keys)?; | ||
| 29 | ``` | ||
| 30 | |||
| 31 | **After (0.43):** | ||
| 32 | ```rust | ||
| 33 | let event = EventBuilder::new(kind, content) | ||
| 34 | .tags(tags) | ||
| 35 | .sign_with_keys(keys)?; | ||
| 36 | ``` | ||
| 37 | |||
| 38 | **Changes:** | ||
| 39 | - ❌ Removed `tags` parameter from constructor | ||
| 40 | - ✅ Use `.tags()` builder method instead | ||
| 41 | - ❌ Removed `.to_event()` method | ||
| 42 | - ✅ Use `.sign_with_keys()` instead (more descriptive) | ||
| 43 | |||
| 44 | --- | ||
| 45 | |||
| 46 | ### 2. Client Ownership of Keys | ||
| 47 | |||
| 48 | **Before (0.35):** | ||
| 49 | ```rust | ||
| 50 | let keys = Keys::generate(); | ||
| 51 | let client = Client::new(&keys); // Reference | ||
| 52 | // keys still available | ||
| 53 | ``` | ||
| 54 | |||
| 55 | **After (0.43):** | ||
| 56 | ```rust | ||
| 57 | let keys = Keys::generate(); | ||
| 58 | let client = Client::new(keys.clone()); // Ownership | ||
| 59 | // Need to clone if we want to keep keys | ||
| 60 | ``` | ||
| 61 | |||
| 62 | **Why:** Allows Client to own the signer, enabling more flexible signer types. | ||
| 63 | |||
| 64 | --- | ||
| 65 | |||
| 66 | ### 3. Relay Status Check No Longer Async | ||
| 67 | |||
| 68 | **Before (0.35):** | ||
| 69 | ```rust | ||
| 70 | if relay.is_connected().await { | ||
| 71 | // ... | ||
| 72 | } | ||
| 73 | ``` | ||
| 74 | |||
| 75 | **After (0.43):** | ||
| 76 | ```rust | ||
| 77 | if relay.is_connected() { // No await! | ||
| 78 | // ... | ||
| 79 | } | ||
| 80 | ``` | ||
| 81 | |||
| 82 | **Why:** Status check doesn't require async operation. | ||
| 83 | |||
| 84 | --- | ||
| 85 | |||
| 86 | ### 4. Query API Redesigned | ||
| 87 | |||
| 88 | **Before (0.35):** | ||
| 89 | ```rust | ||
| 90 | let events = client | ||
| 91 | .get_events_of(vec![filter], EventSource::relays(Some(timeout))) | ||
| 92 | .await?; | ||
| 93 | // Returns Vec<Event> | ||
| 94 | ``` | ||
| 95 | |||
| 96 | **After (0.43):** | ||
| 97 | ```rust | ||
| 98 | let events = client | ||
| 99 | .fetch_events(filter, timeout) | ||
| 100 | .await?; | ||
| 101 | // Returns Events (iterable collection) | ||
| 102 | |||
| 103 | // Convert to Vec if needed | ||
| 104 | let vec: Vec<Event> = events.into_iter().collect(); | ||
| 105 | ``` | ||
| 106 | |||
| 107 | **Changes:** | ||
| 108 | - ❌ Removed `get_events_of()` method | ||
| 109 | - ✅ Use `fetch_events()` instead | ||
| 110 | - ❌ Removed `EventSource` parameter (confusing) | ||
| 111 | - ✅ Direct timeout parameter | ||
| 112 | - ❌ Single filter instead of `Vec<Filter>` | ||
| 113 | - ✅ Returns `Events` type instead of `Vec<Event>` | ||
| 114 | |||
| 115 | --- | ||
| 116 | |||
| 117 | ### 5. Filter Custom Tags Simplified | ||
| 118 | |||
| 119 | **Before (0.35):** | ||
| 120 | ```rust | ||
| 121 | filter.custom_tag(tag, ["value"]) | ||
| 122 | filter.custom_tag(tag, [&string_ref]) | ||
| 123 | ``` | ||
| 124 | |||
| 125 | **After (0.43):** | ||
| 126 | ```rust | ||
| 127 | filter.custom_tag(tag, "value") | ||
| 128 | filter.custom_tag(tag, &string_ref) | ||
| 129 | ``` | ||
| 130 | |||
| 131 | **Why:** Simplified API for the common case of single tag value. | ||
| 132 | |||
| 133 | --- | ||
| 134 | |||
| 135 | ### 6. Send Event Takes Reference | ||
| 136 | |||
| 137 | **Before (0.35):** | ||
| 138 | ```rust | ||
| 139 | let event_id = client.send_event(event).await?; | ||
| 140 | ``` | ||
| 141 | |||
| 142 | **After (0.43):** | ||
| 143 | ```rust | ||
| 144 | let output = client.send_event(&event).await?; | ||
| 145 | let event_id = *output.id(); | ||
| 146 | ``` | ||
| 147 | |||
| 148 | **Changes:** | ||
| 149 | - Takes `&Event` instead of `Event` (can reuse events) | ||
| 150 | - Returns `SendEventOutput` instead of `EventId` | ||
| 151 | - Need to call `.id()` to get the event ID | ||
| 152 | |||
| 153 | --- | ||
| 154 | |||
| 155 | ## Common Patterns | ||
| 156 | |||
| 157 | ### Creating and Signing Events | ||
| 158 | |||
| 159 | ```rust | ||
| 160 | use nostr_sdk::prelude::*; | ||
| 161 | |||
| 162 | // Generate keys | ||
| 163 | let keys = Keys::generate(); | ||
| 164 | |||
| 165 | // Create event | ||
| 166 | let event = EventBuilder::new(Kind::TextNote, "Hello Nostr!") | ||
| 167 | .tags(vec![ | ||
| 168 | Tag::custom(TagKind::SingleLetter(SingleLetterTag::lowercase(Alphabet::T)), | ||
| 169 | vec!["nostr"]), | ||
| 170 | ]) | ||
| 171 | .sign_with_keys(&keys)?; | ||
| 172 | |||
| 173 | // Send event | ||
| 174 | let output = client.send_event(&event).await?; | ||
| 175 | println!("Event ID: {}", output.id()); | ||
| 176 | ``` | ||
| 177 | |||
| 178 | --- | ||
| 179 | |||
| 180 | ### Creating Custom Tags | ||
| 181 | |||
| 182 | ```rust | ||
| 183 | use nostr_sdk::prelude::*; | ||
| 184 | |||
| 185 | // Single letter tag (like "t" for topics) | ||
| 186 | let t_tag = SingleLetterTag::lowercase(Alphabet::T); | ||
| 187 | let tag = Tag::custom( | ||
| 188 | TagKind::SingleLetter(t_tag), | ||
| 189 | vec!["my-topic"] | ||
| 190 | ); | ||
| 191 | |||
| 192 | // Custom multi-letter tag | ||
| 193 | let tag = Tag::custom( | ||
| 194 | TagKind::Custom("custom-tag".to_string()), | ||
| 195 | vec!["value1", "value2"] | ||
| 196 | ); | ||
| 197 | |||
| 198 | // Hashtag (convenience method) | ||
| 199 | let tag = Tag::hashtag("nostr"); // Creates ["t", "nostr"] | ||
| 200 | ``` | ||
| 201 | |||
| 202 | --- | ||
| 203 | |||
| 204 | ### Querying Events | ||
| 205 | |||
| 206 | ```rust | ||
| 207 | use nostr_sdk::prelude::*; | ||
| 208 | |||
| 209 | // Build filter | ||
| 210 | let filter = Filter::new() | ||
| 211 | .kind(Kind::TextNote) | ||
| 212 | .custom_tag( | ||
| 213 | SingleLetterTag::lowercase(Alphabet::T), | ||
| 214 | "my-topic" | ||
| 215 | ) | ||
| 216 | .since(Timestamp::now() - Duration::from_secs(3600)); // Last hour | ||
| 217 | |||
| 218 | // Query events | ||
| 219 | let timeout = Duration::from_secs(10); | ||
| 220 | let events = client.fetch_events(filter, timeout).await?; | ||
| 221 | |||
| 222 | // Process events | ||
| 223 | for event in events.into_iter() { | ||
| 224 | println!("Event: {}", event.id()); | ||
| 225 | } | ||
| 226 | ``` | ||
| 227 | |||
| 228 | --- | ||
| 229 | |||
| 230 | ### Multiple Filters | ||
| 231 | |||
| 232 | Since `fetch_events()` takes a single filter, combine multiple queries: | ||
| 233 | |||
| 234 | ```rust | ||
| 235 | // Option 1: Fetch separately and combine | ||
| 236 | let mut all_events = Vec::new(); | ||
| 237 | for filter in filters { | ||
| 238 | let events = client.fetch_events(filter, timeout).await?; | ||
| 239 | all_events.extend(events.into_iter()); | ||
| 240 | } | ||
| 241 | |||
| 242 | // Option 2: Use subscription (more efficient) | ||
| 243 | let subscription_id = SubscriptionId::new("my-sub"); | ||
| 244 | client.subscribe(filters, None).await?; | ||
| 245 | |||
| 246 | // Handle events via notification handler | ||
| 247 | let mut notifications = client.notifications(); | ||
| 248 | while let Ok(notification) = notifications.recv().await { | ||
| 249 | if let RelayPoolNotification::Event { event, .. } = notification { | ||
| 250 | println!("Event: {}", event.id()); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | ``` | ||
| 254 | |||
| 255 | --- | ||
| 256 | |||
| 257 | ### Client Setup with Relay | ||
| 258 | |||
| 259 | ```rust | ||
| 260 | use nostr_sdk::prelude::*; | ||
| 261 | |||
| 262 | // Create keys | ||
| 263 | let keys = Keys::generate(); | ||
| 264 | |||
| 265 | // Create client | ||
| 266 | let client = Client::new(keys.clone()); | ||
| 267 | |||
| 268 | // Add relay | ||
| 269 | client.add_relay("wss://relay.example.com").await?; | ||
| 270 | |||
| 271 | // Connect | ||
| 272 | client.connect().await; | ||
| 273 | |||
| 274 | // Wait for connection | ||
| 275 | tokio::time::sleep(Duration::from_secs(2)).await; | ||
| 276 | |||
| 277 | // Check connection | ||
| 278 | if client.relay("wss://relay.example.com") | ||
| 279 | .await? | ||
| 280 | .is_connected() | ||
| 281 | { | ||
| 282 | println!("Connected!"); | ||
| 283 | } | ||
| 284 | ``` | ||
| 285 | |||
| 286 | --- | ||
| 287 | |||
| 288 | ## Testing Patterns | ||
| 289 | |||
| 290 | ### Unit Tests (No Relay Required) | ||
| 291 | |||
| 292 | ```rust | ||
| 293 | #[cfg(test)] | ||
| 294 | mod tests { | ||
| 295 | use super::*; | ||
| 296 | use nostr_sdk::prelude::*; | ||
| 297 | |||
| 298 | #[test] | ||
| 299 | fn test_event_creation() { | ||
| 300 | let keys = Keys::generate(); | ||
| 301 | let event = EventBuilder::new(Kind::TextNote, "test") | ||
| 302 | .sign_with_keys(&keys) | ||
| 303 | .unwrap(); | ||
| 304 | |||
| 305 | assert_eq!(event.kind(), Kind::TextNote); | ||
| 306 | assert_eq!(event.content(), "test"); | ||
| 307 | } | ||
| 308 | |||
| 309 | #[test] | ||
| 310 | fn test_tag_creation() { | ||
| 311 | let t_tag = SingleLetterTag::lowercase(Alphabet::T); | ||
| 312 | let tag = Tag::custom( | ||
| 313 | TagKind::SingleLetter(t_tag), | ||
| 314 | vec!["test-topic"] | ||
| 315 | ); | ||
| 316 | |||
| 317 | // Verify tag structure | ||
| 318 | assert_eq!(tag.as_vec()[0], "t"); | ||
| 319 | assert_eq!(tag.as_vec()[1], "test-topic"); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | ``` | ||
| 323 | |||
| 324 | --- | ||
| 325 | |||
| 326 | ### Integration Tests (Relay Required) | ||
| 327 | |||
| 328 | ```rust | ||
| 329 | #[cfg(test)] | ||
| 330 | mod tests { | ||
| 331 | use super::*; | ||
| 332 | use nostr_sdk::prelude::*; | ||
| 333 | |||
| 334 | #[tokio::test] | ||
| 335 | #[ignore] // Requires running relay | ||
| 336 | async fn test_send_and_receive() -> Result<()> { | ||
| 337 | // Setup | ||
| 338 | let keys = Keys::generate(); | ||
| 339 | let client = Client::new(keys.clone()); | ||
| 340 | client.add_relay("ws://localhost:7000").await?; | ||
| 341 | client.connect().await; | ||
| 342 | tokio::time::sleep(Duration::from_secs(2)).await; | ||
| 343 | |||
| 344 | // Send event | ||
| 345 | let event = EventBuilder::new(Kind::TextNote, "test") | ||
| 346 | .sign_with_keys(&keys)?; | ||
| 347 | let output = client.send_event(&event).await?; | ||
| 348 | |||
| 349 | // Query it back | ||
| 350 | let filter = Filter::new() | ||
| 351 | .id(*output.id()); | ||
| 352 | let events = client.fetch_events(filter, Duration::from_secs(5)).await?; | ||
| 353 | |||
| 354 | assert_eq!(events.len(), 1); | ||
| 355 | Ok(()) | ||
| 356 | } | ||
| 357 | } | ||
| 358 | ``` | ||
| 359 | |||
| 360 | **Running integration tests:** | ||
| 361 | ```bash | ||
| 362 | # Start relay first | ||
| 363 | docker run --rm -p 7000:7000 scsibug/nostr-rs-relay | ||
| 364 | |||
| 365 | # Run tests | ||
| 366 | cargo test -- --ignored | ||
| 367 | ``` | ||
| 368 | |||
| 369 | --- | ||
| 370 | |||
| 371 | ## Common Gotchas | ||
| 372 | |||
| 373 | ### 1. Event Validation Failures | ||
| 374 | |||
| 375 | **Problem:** Events fail validation with cryptic errors | ||
| 376 | |||
| 377 | **Common Causes:** | ||
| 378 | - Invalid signature (wrong keys used) | ||
| 379 | - Invalid event ID (content/tags changed after signing) | ||
| 380 | - Invalid timestamp (too far in future/past) | ||
| 381 | |||
| 382 | **Solution:** | ||
| 383 | ```rust | ||
| 384 | // Always sign AFTER setting all fields | ||
| 385 | let event = EventBuilder::new(kind, content) | ||
| 386 | .tags(tags) // Set tags first | ||
| 387 | .sign_with_keys(&keys)?; // Sign last | ||
| 388 | |||
| 389 | // Don't modify event after signing! | ||
| 390 | ``` | ||
| 391 | |||
| 392 | --- | ||
| 393 | |||
| 394 | ### 2. Filter Not Matching Events | ||
| 395 | |||
| 396 | **Problem:** Query returns no events even though they exist | ||
| 397 | |||
| 398 | **Common Causes:** | ||
| 399 | - Tag kind mismatch (uppercase vs lowercase) | ||
| 400 | - Wrong filter field (using `.author()` when you need `.authors()`) | ||
| 401 | - Timeout too short | ||
| 402 | |||
| 403 | **Solution:** | ||
| 404 | ```rust | ||
| 405 | // Be explicit about tag kinds | ||
| 406 | let t_tag = SingleLetterTag::lowercase(Alphabet::T); // Lowercase! | ||
| 407 | |||
| 408 | // Use correct filter methods | ||
| 409 | let filter = Filter::new() | ||
| 410 | .authors(vec![keys.public_key()]) // Note: plural | ||
| 411 | .kinds(vec![Kind::TextNote]); // Note: plural | ||
| 412 | |||
| 413 | // Increase timeout for slow relays | ||
| 414 | let timeout = Duration::from_secs(10); | ||
| 415 | ``` | ||
| 416 | |||
| 417 | --- | ||
| 418 | |||
| 419 | ### 3. Connection Timing Issues | ||
| 420 | |||
| 421 | **Problem:** Events fail to send or queries return empty | ||
| 422 | |||
| 423 | **Cause:** Client not fully connected to relay | ||
| 424 | |||
| 425 | **Solution:** | ||
| 426 | ```rust | ||
| 427 | // Connect | ||
| 428 | client.connect().await; | ||
| 429 | |||
| 430 | // Wait for connection to establish | ||
| 431 | tokio::time::sleep(Duration::from_secs(2)).await; | ||
| 432 | |||
| 433 | // Verify connection | ||
| 434 | let relay = client.relay("wss://relay.example.com").await?; | ||
| 435 | if !relay.is_connected() { | ||
| 436 | return Err("Not connected".into()); | ||
| 437 | } | ||
| 438 | |||
| 439 | // Now safe to send/query | ||
| 440 | ``` | ||
| 441 | |||
| 442 | --- | ||
| 443 | |||
| 444 | ### 4. Clone Keys When Creating Client | ||
| 445 | |||
| 446 | **Problem:** Can't use keys after creating client | ||
| 447 | |||
| 448 | **Cause:** Client takes ownership in 0.43+ | ||
| 449 | |||
| 450 | **Solution:** | ||
| 451 | ```rust | ||
| 452 | // Clone keys if you need them later | ||
| 453 | let keys = Keys::generate(); | ||
| 454 | let client = Client::new(keys.clone()); // Clone! | ||
| 455 | |||
| 456 | // Now can still use keys | ||
| 457 | let pubkey = keys.public_key(); | ||
| 458 | ``` | ||
| 459 | |||
| 460 | --- | ||
| 461 | |||
| 462 | ## Performance Tips | ||
| 463 | |||
| 464 | ### 1. Reuse Clients | ||
| 465 | |||
| 466 | ```rust | ||
| 467 | // ✅ Good - single client | ||
| 468 | let client = Client::new(keys); | ||
| 469 | client.add_relay("wss://relay1.com").await?; | ||
| 470 | client.add_relay("wss://relay2.com").await?; | ||
| 471 | client.connect().await; | ||
| 472 | |||
| 473 | // ❌ Bad - multiple clients | ||
| 474 | for relay in relays { | ||
| 475 | let client = Client::new(keys.clone()); // Wasteful! | ||
| 476 | client.add_relay(relay).await?; | ||
| 477 | } | ||
| 478 | ``` | ||
| 479 | |||
| 480 | --- | ||
| 481 | |||
| 482 | ### 2. Use Subscriptions for Live Updates | ||
| 483 | |||
| 484 | ```rust | ||
| 485 | // ✅ Good for live updates - subscription | ||
| 486 | let filters = vec![Filter::new().kind(Kind::TextNote)]; | ||
| 487 | client.subscribe(filters, None).await?; | ||
| 488 | |||
| 489 | let mut notifications = client.notifications(); | ||
| 490 | while let Ok(notification) = notifications.recv().await { | ||
| 491 | // Handle events as they arrive | ||
| 492 | } | ||
| 493 | |||
| 494 | // ❌ Bad for live updates - polling | ||
| 495 | loop { | ||
| 496 | let events = client.fetch_events(filter, timeout).await?; | ||
| 497 | tokio::time::sleep(Duration::from_secs(1)).await; | ||
| 498 | } | ||
| 499 | ``` | ||
| 500 | |||
| 501 | --- | ||
| 502 | |||
| 503 | ### 3. Batch Event Creation | ||
| 504 | |||
| 505 | ```rust | ||
| 506 | // ✅ Good - reuse keys | ||
| 507 | let keys = Keys::generate(); | ||
| 508 | let events: Vec<Event> = (0..100) | ||
| 509 | .map(|i| { | ||
| 510 | EventBuilder::new(Kind::TextNote, format!("Message {}", i)) | ||
| 511 | .sign_with_keys(&keys) | ||
| 512 | .unwrap() | ||
| 513 | }) | ||
| 514 | .collect(); | ||
| 515 | |||
| 516 | // ❌ Bad - regenerate keys | ||
| 517 | let events: Vec<Event> = (0..100) | ||
| 518 | .map(|i| { | ||
| 519 | let keys = Keys::generate(); // Wasteful! | ||
| 520 | EventBuilder::new(Kind::TextNote, format!("Message {}", i)) | ||
| 521 | .sign_with_keys(&keys) | ||
| 522 | .unwrap() | ||
| 523 | }) | ||
| 524 | .collect(); | ||
| 525 | ``` | ||
| 526 | |||
| 527 | --- | ||
| 528 | |||
| 529 | ## Migration Checklist (0.35 → 0.43) | ||
| 530 | |||
| 531 | When upgrading from 0.35 to 0.43: | ||
| 532 | |||
| 533 | - [ ] Update `Cargo.toml`: `nostr-sdk = "0.43"` | ||
| 534 | - [ ] Fix `EventBuilder::new()` - remove tags parameter | ||
| 535 | - [ ] Fix `EventBuilder::to_event()` → `sign_with_keys()` | ||
| 536 | - [ ] Fix `Client::new()` - clone keys instead of reference | ||
| 537 | - [ ] Fix `Relay::is_connected()` - remove `.await` | ||
| 538 | - [ ] Fix `Client::get_events_of()` → `fetch_events()` | ||
| 539 | - [ ] Remove `EventSource::relays()` usage | ||
| 540 | - [ ] Fix `Filter::custom_tag()` - single value instead of array | ||
| 541 | - [ ] Fix `Client::send_event()` - pass reference, handle `SendEventOutput` | ||
| 542 | - [ ] Update tests | ||
| 543 | - [ ] Verify all builds pass | ||
| 544 | - [ ] Run integration tests | ||
| 545 | |||
| 546 | **Reference:** See `docs/archive/2025-11-04-nostr-sdk-upgrade.md` | ||
| 547 | |||
| 548 | --- | ||
| 549 | |||
| 550 | ## Useful Resources | ||
| 551 | |||
| 552 | - **nostr-sdk docs**: https://docs.rs/nostr-sdk/0.43.0 | ||
| 553 | - **rust-nostr GitHub**: https://github.com/rust-nostr/nostr | ||
| 554 | - **NIPs**: https://github.com/nostr-protocol/nips | ||
| 555 | - **NIP-01 (Events)**: https://github.com/nostr-protocol/nips/blob/master/01.md | ||
| 556 | - **NIP-34 (Git)**: https://github.com/nostr-protocol/nips/blob/master/34.md | ||
| 557 | |||
| 558 | --- | ||
| 559 | |||
| 560 | ## Quick Reference | ||
| 561 | |||
| 562 | | Task | Code | | ||
| 563 | |------|------| | ||
| 564 | | Create event | `EventBuilder::new(kind, content).sign_with_keys(&keys)?` | | ||
| 565 | | Add tags | `.tags(vec![tag1, tag2])` | | ||
| 566 | | Custom tag | `Tag::custom(TagKind::SingleLetter(t), vec!["value"])` | | ||
| 567 | | Create client | `Client::new(keys.clone())` | | ||
| 568 | | Add relay | `client.add_relay("wss://...").await?` | | ||
| 569 | | Connect | `client.connect().await` | | ||
| 570 | | Send event | `client.send_event(&event).await?` | | ||
| 571 | | Query events | `client.fetch_events(filter, timeout).await?` | | ||
| 572 | | Subscribe | `client.subscribe(filters, None).await?` | | ||
| 573 | |||
| 574 | --- | ||
| 575 | |||
| 576 | *Last updated: November 4, 2025* | ||
| 577 | *Status: Living document - update as nostr-sdk evolves* | ||