Files
archy/aiui/.claude/plans/content-detection-overhaul.md
T

6.7 KiB

Plan: Overhaul Content Detection + Add Apps Tab

Context

The content surfacing system misses many common AI response patterns. Example: AI responds about Nostr (mentioning damus.io, primal.net, snort.social) but the Nostr tab never surfaces. Query/response classifiers use narrow regexes that miss natural language variations. There's no "topic detection" layer, no app detection, and bare domains in AI text aren't extracted as websites.

Goals:

  1. Fix content detection to handle how AIs actually respond
  2. Add Nostr tab surfacing (currently only via /nostr command)
  3. Add Apps tab with curated Nostr + Bitcoin ecosystem apps (local DB + AI extraction fallback)
  4. Extract bare domains from AI text (e.g. "check out damus.io")

Part 1: Expand Query & Response Classifiers

File: packages/app/src/composables/contentFiltering.ts

1A. Add Nostr classifiers (new functions)

  • isNostrQuery(q) — matches: nostr, npub, nip-\d, damus, primal, snort, amethyst, coracle, zap, relay, note1, nevent, nprofile, fiatjaf, nostrich, "decentralized social"
  • isNostrLikeResponse(text) — requires literal "nostr" OR 2+ Nostr-specific signals (npub, nip-, client names, relay+wss, zap+lightning)

1B. Add App classifiers (new functions)

  • isAppQuery(q) — matches: app, client, wallet, tool, software, download, install, "what app", "best app for", "recommend.*app"
  • isAppLikeResponse(text) — matches: "you can use", "popular clients include", "I'd recommend", "available on", "download from"

1C. Expand existing classifiers with broader patterns

Classifier Add these patterns
isNewsQuery "what happened today", "any updates on", "trending", "catch me up", "brief me", "current events"
isMusicQuery "genre", "spotify", "bandcamp", "grammys", "billboard", "mixtape", "discography", "banger", "favorite jam"
isBookQuery "what should I read", "favorite reads", "reading list", "book club", "memoir", "audiobook", "goodreads", "worth reading"
isTVQuery "what's good on netflix", "anything to binge", "hbo", "disney+", "apple tv", "amazon prime", "docuseries", "limited series"
isPlaceQuery "hungry", "food near me", "best brunch spot", "happy hour", "speakeasy", "rooftop bar", "food truck"
isWebsitesQuery "point me to", "link me", "any good sites", "tools for", "platforms for"
isWebsitesLikeResponse "here are some resources", "I'd recommend checking", "you can visit", "useful resources"
isNewsLikeResponse "I can't access the web but", "having trouble reaching", "unable to browse but"

1D. Update preferredFirstTab() — add nostr + app checks

1E. Update filterTabsByContext() — add hasNostr and hasApps params, integrate into tab ordering


Part 2: Bare Domain Extraction

File: packages/app/src/composables/contentExtraction.ts

Add extractBareDomainLinks(text):

  • Detect plain-text domains like "damus.io", "primal.net" not inside markdown links or bold patterns
  • Skip positions covered by existing extractors (markdown links, bold-domain, full URLs)
  • Require known TLDs (.com, .org, .io, .net, .social, .app, etc.)
  • Block file extensions (.js, .ts, .vue, .json, .css)
  • Use existing normUrl() for dedup

Part 3: Apps Tab — Curated Database + AI Extraction

3A. Create app database

New file: packages/app/src/data/apps.ts

interface AppEntry {
  id: string
  name: string
  description: string          // One-liner
  longDescription: string      // Why use this, how it works
  category: 'nostr-client' | 'lightning-wallet' | 'bitcoin-wallet' | 'privacy' | 'node' | 'dev-tool' | 'relay'
  platforms: ('ios' | 'android' | 'web' | 'desktop' | 'cli' | 'nodeos')[]
  url: string
  icon?: string
  keywords: string[]           // For matching AI responses
  howTo?: string[]             // Getting started steps
  relatedApps?: string[]       // IDs of related apps
}

Initial curated apps (~25-30):

  • Nostr clients: Damus, Primal, Snort, Amethyst, Coracle, Iris, Nostrudel, nos.social
  • Lightning wallets: Phoenix, Mutiny, Breez, Zeus, Alby, Wallet of Satoshi
  • Bitcoin wallets: Sparrow, Blue Wallet, Nunchuk, Coldcard, Green
  • Privacy tools: Tor, SimpleX Chat, Signal, Mullvad VPN
  • Node software: Start9, Umbrel, RaspiBlitz, myNode
  • Dev tools: NDK, nostr-tools, Nak

3B. Add app extraction

File: packages/app/src/composables/contentExtraction.ts

Add extractApps(text, userQuery):

  1. Match AI text against known app names/keywords from database
  2. If app query detected OR 2+ known apps mentioned → return matched apps
  3. For unknown apps, create basic entries from context (name + URL if bare domain found)

3C. Create UI components

New files:

  • packages/app/src/components/content/AppsGrid.vue — Grid of app cards (icon, name, category badge, one-liner)
  • packages/app/src/components/content/AppDetail.vue — Detail: icon, name, platforms, long description, how-to steps, link, related apps

Follow existing grid/detail patterns (e.g. BookGrid.vue/BookDetail.vue).

3D. Register in ContentPanel.vue

Add rendering for activeTab === 'app', add 'app' to ContentTab type.


Part 4: Wire Everything Together

File: packages/app/src/composables/useContentPanel.ts

In updatePanelFromText():

  • Call extractBareDomainLinks(text), merge with website sources
  • Call extractApps(text, userQuery)
  • Compute hasNostr = isNostrQuery(userQuery) || isNostrLikeResponse(text)
  • Compute hasApps = apps.length > 0
  • Pass hasNostr and hasApps to filterTabsByContext()
  • Add panelApps ref, title logic for apps/nostr tabs

Same changes in getContextualInlineContent().

Broaden magazine detection: add tech/protocol keywords, surface magazine for 3+ sections with no other structured content.


Part 5: PromptIndex badges

File: packages/app/src/components/chat/PromptIndex.vue

Add 'Nostr' and 'Apps' badge detection.


Implementation Order

  1. contentFiltering.ts — classifiers + filterTabsByContext signature
  2. contentExtraction.tsextractBareDomainLinks() + extractApps()
  3. data/apps.ts — curated app database
  4. useContentPanel.ts — wire everything
  5. AppsGrid.vue + AppDetail.vue — UI components
  6. ContentPanel.vue — register tab + components
  7. PromptIndex.vue — badges
  8. Typecheck + manual test

Verification

  1. pnpm typecheck passes
  2. "tell me about Nostr" → Nostr + magazine tabs surface
  3. "best Nostr clients?" → Apps tab with Damus, Primal, Snort
  4. "recommend a bitcoin wallet" → Apps tab with Phoenix, Sparrow
  5. "what happened with BIP 110?" → Magazine tab (regression)
  6. "best movies of 2024" → Films tab (regression)
  7. Bare domains in AI text extracted as websites
  8. PromptIndex badges show Nostr/Apps