Skip to content

Commit e7ca4fd

Browse files
chore: bump v0.7.0, update changelog and README
Add memory_edit docs, stats/export CLI commands, relay config examples, Phase 7 roadmap entry. Closes #12, #13, #14. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d7a18d8 commit e7ca4fd

5 files changed

Lines changed: 204 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
# Changelog
22

3+
## [0.7.0] - 2026-03-24
4+
5+
### Added
6+
- `memory_edit` MCP tool for correcting stored memories with edit tracking (21 → 22 tools)
7+
- Optional semantic search via ONNX embeddings (all-MiniLM-L6-v2, 384-dim)
8+
- Install with `pip install lightning-memory[semantic]`
9+
- Hybrid FTS5 + cosine similarity with reciprocal rank fusion
10+
- Hash-based fallback when onnxruntime not installed
11+
- Memory deduplication using Jaccard word-set similarity (per-type thresholds)
12+
- `lightning-memory stats` CLI command — memory statistics dashboard
13+
- `lightning-memory export [json|csv]` CLI command
14+
- Schema migration system using PRAGMA user_version
15+
- Per-relay circuit breaker (auto-skip down relays, exponential backoff)
16+
- L402 payment idempotency (duplicate tokens detected, payment logged once)
17+
- Relay configuration examples in README
18+
19+
### Fixed
20+
- Vendor name normalization across all subsystems — `bitrefill.com`, `www.bitrefill.com`, `BITREFILL.COM` now match consistently in reputation, budget, trust, and anomaly detection
21+
- Intelligence engine double-scan — `vendor_report()` now counts failures in a single pass instead of scanning all memories twice
22+
- Relay sync batching — `push_memories()` uses single event loop instead of per-memory `asyncio.run()`
23+
- `pull_trust_assertions()` now fetches all vendors concurrently instead of sequentially
24+
25+
### Changed
26+
- `GatewayClient` reuses persistent `httpx.Client` with connection pooling
27+
- `PhoenixdClient` reuses persistent `httpx.AsyncClient` with connection pooling
28+
329
## [0.6.0] - 2026-03-14
430

531
### Added

README.md

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,19 @@ ln_remote_query(
279279
# → {status: "success", data: {count: 3, memories: [...]}}
280280
```
281281

282+
### `memory_edit`
283+
284+
Edit an existing memory's content or metadata. Tracks edit history.
285+
286+
```
287+
memory_edit(
288+
id="7222215a5eba8547",
289+
content="Bitrefill now charges 300 sats (was 500)",
290+
metadata='{"note": "price updated March 2026"}'
291+
)
292+
# → {id: "7222...", content: "...", old_content_preview: "...", edit_count: 1}
293+
```
294+
282295
### `memory_sync`
283296

284297
Sync memories with Nostr relays (push and/or pull). Also pulls NIP-85 trust assertions and gateway announcements.
@@ -429,11 +442,84 @@ Generate a `.well-known/lightning-memory.json` manifest for DNS-based gateway di
429442
lightning-memory-manifest > .well-known/lightning-memory.json
430443
```
431444

445+
### `lightning-memory stats`
446+
447+
Show a memory statistics dashboard:
448+
449+
```bash
450+
lightning-memory stats
451+
# Lightning Memory — Statistics Dashboard
452+
# ==========================================
453+
# Agent: 7222215a5eba8547...
454+
# Total memories: 147
455+
#
456+
# By type:
457+
# transaction 89
458+
# vendor 23
459+
# decision 18
460+
# error 12
461+
# attestation 5
462+
#
463+
# Spending (30d): 42,500 sats across 89 txns
464+
# Top vendors:
465+
# bitrefill.com 15,200 sats
466+
# openai.l402.io 8,300 sats
467+
#
468+
# Semantic search: active
469+
```
470+
471+
### `lightning-memory export [json|csv]`
472+
473+
Export memories to JSON or CSV:
474+
475+
```bash
476+
lightning-memory export json > backup.json
477+
lightning-memory export csv > backup.csv
478+
```
479+
480+
## Relay Configuration
481+
482+
Memories sync to Nostr relays via NIP-78 events. Default relays:
483+
484+
```json
485+
["wss://relay.damus.io", "wss://nos.lol", "wss://relay.nostr.band"]
486+
```
487+
488+
To customize, create `~/.lightning-memory/config.json`:
489+
490+
```json
491+
{
492+
"relays": [
493+
"wss://relay.damus.io",
494+
"wss://nos.lol",
495+
"wss://relay.nostr.band",
496+
"wss://relay.primal.net"
497+
],
498+
"sync_timeout_seconds": 30,
499+
"max_events_per_sync": 500
500+
}
501+
```
502+
503+
**Choosing relays:**
504+
505+
| Relay | Speed | Reliability | Notes |
506+
|-------|-------|-------------|-------|
507+
| `wss://relay.damus.io` | Fast | High | Most popular, good uptime |
508+
| `wss://nos.lol` | Fast | High | Reliable, good NIP-78 support |
509+
| `wss://relay.nostr.band` | Medium | Medium | Search-focused, may be slow |
510+
| `wss://relay.primal.net` | Fast | High | Primal's relay, well-maintained |
511+
| `wss://nostr.wine` | Fast | High | Paid relay, less spam |
512+
513+
**Tips:**
514+
- Use 2-3 relays for redundancy — Lightning Memory deduplicates across relays
515+
- Check relay health: `lightning-memory relay-status`
516+
- Relays with a circuit breaker tripped are automatically skipped until they recover
517+
432518
## How It Works
433519

434520
1. **First run**: A Nostr keypair is generated and stored at `~/.lightning-memory/keys/`
435521
2. **Storing**: Memories go to local SQLite with FTS5 indexing. Each memory is tagged with your agent's public key.
436-
3. **Querying**: Full-text search with BM25 ranking returns the most relevant memories.
522+
3. **Querying**: Full-text search with BM25 ranking returns the most relevant memories. With `pip install lightning-memory[semantic]`, queries also use ONNX-based semantic similarity for concept matching.
437523
4. **Identity**: Your agent's public key is a globally unique, cryptographically verifiable identifier. No accounts needed.
438524

439525
## Data Storage
@@ -458,6 +544,7 @@ All data is stored locally:
458544
- [x] Phase 5.1: Community reputation — live NIP-85 trust attestation sync
459545
- [x] Phase 5.2: Compliance integration — KYA attestations, LNURL-auth sessions, compliance reports
460546
- [x] Phase 6: Memory marketplace — gateway discovery (Nostr + DNS), remote L402 queries, gateway client
547+
- [x] Phase 7: Agent reliability — vendor normalization, deduplication, memory edit, semantic search, circuit breakers, L402 idempotency
461548

462549
## Star History
463550

lightning_memory/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Lightning Memory: Decentralized agent memory for the Lightning economy."""
22

3-
__version__ = "0.6.0"
3+
__version__ = "0.7.0"

lightning_memory/server.py

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -908,13 +908,98 @@ def gateway_manifest_main() -> None:
908908
print(json.dumps(manifest, indent=2))
909909

910910

911+
def _cmd_stats() -> None:
912+
"""Show memory statistics dashboard."""
913+
engine = _get_engine()
914+
stats = engine.stats()
915+
intel = _get_intelligence()
916+
917+
print("Lightning Memory — Statistics Dashboard")
918+
print("=" * 42)
919+
print(f" Agent: {stats['agent_pubkey'][:16]}...")
920+
print(f" Total memories: {stats['total']}")
921+
print()
922+
923+
if stats["by_type"]:
924+
print(" By type:")
925+
for t, count in sorted(stats["by_type"].items(), key=lambda x: x[1], reverse=True):
926+
print(f" {t:20s} {count:>5}")
927+
else:
928+
print(" No memories stored yet.")
929+
print()
930+
931+
# Spending summary
932+
summary = intel.spending_summary("30d")
933+
if summary.txn_count > 0:
934+
print(f" Spending (30d): {summary.total_sats:,} sats across {summary.txn_count} txns")
935+
if summary.by_vendor:
936+
print(" Top vendors:")
937+
for vendor, sats in sorted(summary.by_vendor.items(), key=lambda x: x[1], reverse=True)[:5]:
938+
print(f" {vendor:30s} {sats:>8,} sats")
939+
print()
940+
941+
# Budget rules
942+
budget = _get_budget()
943+
rules = budget.list_rules()
944+
if rules:
945+
print(f" Budget rules: {len(rules)}")
946+
for r in rules:
947+
limits = []
948+
if r.max_sats_per_txn:
949+
limits.append(f"{r.max_sats_per_txn}/txn")
950+
if r.max_sats_per_day:
951+
limits.append(f"{r.max_sats_per_day}/day")
952+
if r.max_sats_per_month:
953+
limits.append(f"{r.max_sats_per_month}/mo")
954+
print(f" {r.vendor:30s} {', '.join(limits)}")
955+
956+
# Embedding status
957+
try:
958+
from .embedding import has_embeddings, get_embedding_info
959+
info = get_embedding_info()
960+
status = "active" if info["model_loaded"] else ("available" if info["available"] else "not installed")
961+
print(f"\n Semantic search: {status}")
962+
except Exception:
963+
print("\n Semantic search: not installed")
964+
965+
966+
def _cmd_export(fmt: str = "json") -> None:
967+
"""Export memories to JSON or CSV."""
968+
import csv
969+
import io
970+
971+
engine = _get_engine()
972+
memories = engine.list(limit=10000)
973+
974+
if fmt == "csv":
975+
output = io.StringIO()
976+
if memories:
977+
fields = ["id", "content", "type", "created_at"]
978+
writer = csv.DictWriter(output, fieldnames=fields, extrasaction="ignore")
979+
writer.writeheader()
980+
for m in memories:
981+
writer.writerow(m)
982+
print(output.getvalue(), end="")
983+
else:
984+
print(json.dumps(memories, indent=2, default=str))
985+
986+
911987
def main():
912988
"""Run the MCP server, or a CLI subcommand."""
913989
import sys
914990

915-
if len(sys.argv) > 1 and sys.argv[1] == "relay-status":
916-
_cmd_relay_status()
917-
return
991+
if len(sys.argv) > 1:
992+
cmd = sys.argv[1]
993+
if cmd == "relay-status":
994+
_cmd_relay_status()
995+
return
996+
elif cmd == "stats":
997+
_cmd_stats()
998+
return
999+
elif cmd == "export":
1000+
fmt = sys.argv[2] if len(sys.argv) > 2 else "json"
1001+
_cmd_export(fmt)
1002+
return
9181003

9191004
mcp.run()
9201005

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "lightning-memory"
7-
version = "0.6.0"
7+
version = "0.7.0"
88
description = "Decentralized agent memory for the Lightning economy. Nostr identity, L402 payments, semantic search."
99
readme = "README.md"
1010
license = "MIT"

0 commit comments

Comments
 (0)