Files
Timmy-time-dashboard/docs/adr/024-nostr-identity-canonical-location.md
Claude (Opus 4.6) a0c35202f3
Some checks failed
Tests / lint (push) Has been cancelled
Tests / test (push) Has been cancelled
[claude] ADR-024: canonical Nostr identity in timmy-nostr (#1223) (#1230)
2026-03-23 22:47:25 +00:00

4.9 KiB

ADR-024: Canonical Nostr Identity Location

Status: Accepted Date: 2026-03-23 Issue: #1223 Refs: #1210 (duplicate-work audit), ROADMAP.md Phase 2


Context

Nostr identity logic has been independently implemented in at least three repos (replit/timmy-tower, replit/token-gated-economy, rockachopa/Timmy-time-dashboard), each building keypair generation, event publishing, and NIP-07 browser-extension auth in isolation.

This duplication causes:

  • Bug fixes applied in one repo but silently missed in others.
  • Diverging implementations of the same NIPs (NIP-01, NIP-07, NIP-44).
  • Agent time wasted re-implementing logic that already exists.

ROADMAP.md Phase 2 already names timmy-nostr as the planned home for Nostr infrastructure. This ADR makes that decision explicit and prescribes how other repos consume it.


Decision

The canonical home for all Nostr identity logic is rockachopa/timmy-nostr.

All other repos (Timmy-time-dashboard, timmy-tower, token-gated-economy) become consumers, not implementers, of Nostr identity primitives.

What lives in timmy-nostr

Module Responsibility
nostr_id/keypair.py Keypair generation, nsec/npub encoding, encrypted storage
nostr_id/identity.py Agent identity lifecycle (NIP-01 kind:0 profile events)
nostr_id/auth.py NIP-07 browser-extension signer; NIP-42 relay auth
nostr_id/event.py Event construction, signing, serialisation (NIP-01)
nostr_id/crypto.py NIP-44 encryption (XChaCha20-Poly1305 v2)
nostr_id/nip05.py DNS-based identifier verification
nostr_id/relay.py WebSocket relay client (publish / subscribe)

What does NOT live in timmy-nostr

  • Business logic that combines Nostr with application-specific concepts (e.g. "publish a task-completion event" lives in the application layer that calls timmy-nostr).
  • Reputation scoring algorithms (depends on application policy).
  • Dashboard UI components.

How Other Repos Reference timmy-nostr

Python repos (Timmy-time-dashboard, timmy-tower)

Add to pyproject.toml dependencies:

[tool.poetry.dependencies]
timmy-nostr = {git = "https://gitea.hermes.local/rockachopa/timmy-nostr.git", tag = "v0.1.0"}

Import pattern:

from nostr_id.keypair import generate_keypair, load_keypair
from nostr_id.event import build_event, sign_event
from nostr_id.relay import NostrRelayClient

JavaScript/TypeScript repos (token-gated-economy frontend)

Add to package.json (once published or via local path):

"dependencies": {
  "timmy-nostr": "rockachopa/timmy-nostr#v0.1.0"
}

Import pattern:

import { generateKeypair, signEvent } from 'timmy-nostr';

Until timmy-nostr publishes a JS package, use NIP-07 browser extension directly and delegate all key-management to the browser signer — never re-implement crypto in JS without the shared library.


Migration Plan

Existing duplicated code should be migrated in this order:

  1. Keypair generation — highest duplication, clearest interface.
  2. NIP-01 event construction/signing — used by all three repos.
  3. NIP-07 browser auth — currently in timmy-tower and token-gated-economy.
  4. NIP-44 encryption — lowest priority, least duplicated.

Each step: implement in timmy-nostr → cut over one repo → delete the duplicate → repeat.


Interface Contract

timmy-nostr must expose a stable public API:

# Keypair
keypair = generate_keypair()           # -> NostrKeypair(nsec, npub, privkey_bytes, pubkey_bytes)
keypair = load_keypair(encrypted_nsec, secret_key)

# Events
event = build_event(kind=0, content=profile_json, keypair=keypair)
event = sign_event(event, keypair)     # attaches .id and .sig

# Relay
async with NostrRelayClient(url) as relay:
    await relay.publish(event)
    async for msg in relay.subscribe(filters):
        ...

Breaking changes to this interface require a semver major bump and a migration note in timmy-nostr's CHANGELOG.


Consequences

  • Positive: Bug fixes in cryptographic or protocol code propagate to all repos via a version bump.
  • Positive: New NIPs are implemented once and adopted everywhere.
  • Negative: Adds a cross-repo dependency; version pinning discipline required.
  • Negative: timmy-nostr must be stood up and tagged before any migration can begin.

Action Items

  • Create rockachopa/timmy-nostr repo with the module structure above.
  • Implement keypair generation + NIP-01 signing as v0.1.0.
  • Replace Timmy-time-dashboard inline Nostr code (if any) with timmy-nostr import once v0.1.0 is tagged.
  • Add src/infrastructure/clients/nostr_client.py as the thin application-layer wrapper (see ROADMAP.md §2.6).
  • File issues in timmy-tower and token-gated-economy to migrate their duplicate implementations.