Nostr Identity + Trust Engine — cryptographic memory for every user #64

Closed
opened 2026-03-21 00:46:47 +00:00 by replit · 1 comment
Owner

What & Why

Give Timmy a cryptographic memory. Users identify themselves with a Nostr keypair (secp256k1, same curve as Lightning). Timmy stores a trust score per identity that grows from reliable interactions. Trust scores become the input to the cost-routing gate — this is the foundational identity layer.

Done looks like

  • A nostr_identities table tracks pubkey, trust score, interaction count, free-tier budget consumed, last seen, and tier label (anonymous / new / established / trusted / elite)
  • A challenge/verify API endpoint lets the browser prove Nostr identity without revealing the private key (server issues a nonce, client signs it, server verifies)
  • Sessions and jobs optionally bind to a Nostr identity at creation time; the identity is recorded in the audit tables
  • After each job or session request completes, the trust score updates: paid reliably → score rises; poor patterns → score falls; long absence → soft decay
  • Trust tier is returned on GET /sessions/:id and GET /jobs/:id so the frontend can display it

Out of scope

  • Nostr Web of Trust graph traversal (can be added later as a trust bootstrap signal)
  • Timmy's own Nostr identity (separate task)
  • Any pricing or free-tier logic (separate task)

Tasks

  1. DB schema — Add nostr_identities table (pubkey PK, trust_score, tier, interaction_count, sats_absorbed_today, last_seen, created_at) and nullable nostr_pubkey FK columns on sessions and jobs tables. Run db:push.
  2. Challenge/verify endpointsPOST /api/identity/challenge returns a time-limited nonce; POST /api/identity/verify accepts pubkey + Nostr-signed event, verifies signature via nostr-tools, upserts identity row, returns a signed session token.
  3. Session + job binding — Modify POST /api/sessions and POST /api/jobs to accept optional nostr_token in request body. Validate token, resolve pubkey, record it on the row. Anonymous requests get nostr_pubkey = null.
  4. Trust scoringTrustService with getTier(pubkey), recordSuccess(pubkey, satsCost), recordFailure(pubkey, reason). Tier boundaries and decay rate env-var configurable. Call from job/session completion paths.
  5. Tier on poll responses — Include trust_tier in JSON from GET /sessions/:id and GET /jobs/:id.

Relevant files

  • lib/db/src/schema/sessions.ts
  • lib/db/src/schema/jobs.ts
  • lib/db/src/schema/index.ts
  • artifacts/api-server/src/routes/sessions.ts
  • artifacts/api-server/src/routes/jobs.ts
  • artifacts/api-server/src/lib/trust.ts
## What & Why Give Timmy a cryptographic memory. Users identify themselves with a Nostr keypair (secp256k1, same curve as Lightning). Timmy stores a trust score per identity that grows from reliable interactions. Trust scores become the input to the cost-routing gate — this is the foundational identity layer. ## Done looks like - A `nostr_identities` table tracks pubkey, trust score, interaction count, free-tier budget consumed, last seen, and tier label (anonymous / new / established / trusted / elite) - A challenge/verify API endpoint lets the browser prove Nostr identity without revealing the private key (server issues a nonce, client signs it, server verifies) - Sessions and jobs optionally bind to a Nostr identity at creation time; the identity is recorded in the audit tables - After each job or session request completes, the trust score updates: paid reliably → score rises; poor patterns → score falls; long absence → soft decay - Trust tier is returned on `GET /sessions/:id` and `GET /jobs/:id` so the frontend can display it ## Out of scope - Nostr Web of Trust graph traversal (can be added later as a trust bootstrap signal) - Timmy's own Nostr identity (separate task) - Any pricing or free-tier logic (separate task) ## Tasks 1. **DB schema** — Add `nostr_identities` table (pubkey PK, trust_score, tier, interaction_count, sats_absorbed_today, last_seen, created_at) and nullable `nostr_pubkey` FK columns on `sessions` and `jobs` tables. Run `db:push`. 2. **Challenge/verify endpoints** — `POST /api/identity/challenge` returns a time-limited nonce; `POST /api/identity/verify` accepts pubkey + Nostr-signed event, verifies signature via `nostr-tools`, upserts identity row, returns a signed session token. 3. **Session + job binding** — Modify `POST /api/sessions` and `POST /api/jobs` to accept optional `nostr_token` in request body. Validate token, resolve pubkey, record it on the row. Anonymous requests get `nostr_pubkey = null`. 4. **Trust scoring** — `TrustService` with `getTier(pubkey)`, `recordSuccess(pubkey, satsCost)`, `recordFailure(pubkey, reason)`. Tier boundaries and decay rate env-var configurable. Call from job/session completion paths. 5. **Tier on poll responses** — Include `trust_tier` in JSON from `GET /sessions/:id` and `GET /jobs/:id`. ## Relevant files - `lib/db/src/schema/sessions.ts` - `lib/db/src/schema/jobs.ts` - `lib/db/src/schema/index.ts` - `artifacts/api-server/src/routes/sessions.ts` - `artifacts/api-server/src/routes/jobs.ts` - `artifacts/api-server/src/lib/trust.ts`
replit added the nostrbackend labels 2026-03-21 00:46:47 +00:00
gemini was assigned by Rockachopa 2026-03-22 23:37:10 +00:00
Collaborator

PR created. All tasks for this issue were found to be already implemented in the codebase. PR #95 has been created to reflect this.

PR created. All tasks for this issue were found to be already implemented in the codebase. PR #95 has been created to reflect this.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: replit/timmy-tower#64