npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nodebb-plugin-search-agent

v0.0.943

Published

NodeBB plugin that adds a floating chat assistant to help users find relevant forum topics using TF-IDF text similarity

Readme

nodebb-plugin-search-agent

A NodeBB plugin that adds a floating chat assistant in the bottom-left corner of every forum page.
Users can type a natural-language question and receive a ranked list of relevant forum topic links — powered entirely by an in-process TF-IDF cosine-similarity engine (no external ML services required).


Features

  • Floating Action Button (FAB) — always visible in the bottom-left corner, out of the way of existing UI.
  • Chat panel — opens upward from the FAB with a smooth animation.
  • Natural-language query — accepts free-form questions, not just keywords.
  • TF-IDF similarity ranking — titles weighted ×3 over body text; smoothed IDF over the indexed corpus.
  • In-memory index with TTL cache — built once every 5 minutes; instant subsequent queries.
  • Admin settings page — configure topic limit, max results, and guest access from the ACP.
  • Accessible — ARIA roles, keyboard navigation, focus management, Escape to close.
  • Zero extra npm dependencies — works on any NodeBB installation as-is.
  • i18n-ready — translations for en-US, en-GB, and de included.

Architecture

Browser                          NodeBB Server
──────────────────────────────   ───────────────────────────────────────────
public/lib/main.js               library.js
  • Injects FAB + chat panel       • static:app.load  → registers admin route
  • Sends POST on submit           • static:api.routes → registers API route
  • Renders result bubbles         • filter:admin.header.build → ACP nav link
         │                                   │
         │  POST /api/v3/plugins/            │
         │        search-agent/query         │
         └──────────────────────────────────►│
                                             ▼
                                   lib/controllers.js
                                     handleQuery()
                                             │
                                             ▼
                                   lib/searchHandler.js
                                     getIndex()  ──► cache (5 min TTL)
                                     search()
                                             │
                                             ▼
                                   lib/similarity.js
                                     buildIndex()  (TF-IDF vectors)
                                     query()       (cosine similarity)
                                             │
                                   NodeBB database
                                     db.getSortedSetRevRange('topics:recent')
                                     topics.getTopicsFields()
                                     posts.getPostsFields()

Similarity algorithm

  1. Tokenisation – lowercase, strip HTML, remove punctuation, discard stop-words, keep tokens ≥ 3 chars.
  2. Document construction – topic title repeated ×3 then concatenated with main-post body (title bias).
  3. TF – raw term frequency within the document.
  4. IDF – smoothed: log((N+1) / (df+1)) + 1 to avoid zero-division on rare terms.
  5. TF-IDF vector – sparse Map<term, weight> per document.
  6. Query vector – raw TF of the query tokens (no IDF, since it is a single document).
  7. Cosine similarity – dot product of query × doc divided by the product of their L2 norms.
  8. Ranking – sort descending, return top-N (default 10).

Installation

From the NodeBB Plugin Directory

Search for Search Agent in ACP → Extend → Plugins and click Install.

Manual (development)

# Inside your NodeBB installation root
cd node_modules
git clone https://github.com/your-org/nodebb-plugin-search-agent
cd nodebb-plugin-search-agent

Then in the NodeBB ACP → Extend → Plugins, find Search Agent and click Activate, then Rebuild & Restart.


Configuration

Navigate to ACP → Plugins → Search Agent.

| Setting | Default | Description | |---|---|---| | topicLimit | 500 | Maximum number of recent topics loaded into the index. | | maxResults | 10 | Maximum results returned per query. | | guestsAllowed | off | When enabled, guests (logged-out users) can also use the widget. |

Settings are stored under the key search-agent via meta.settings.


API Reference

POST /api/v3/plugins/search-agent/query

Requires a valid session or Bearer token (unless guestsAllowed is enabled).

Request body

{ "query": "how do I reset my password?" }

Success response

{
  "status": { "code": "ok", "message": "OK" },
  "response": {
    "results": [
      { "tid": 42, "title": "Password reset guide", "url": "/topic/42/password-reset-guide", "score": 0.71 },
      { "tid": 17, "title": "Account recovery options", "url": "/topic/17/account-recovery", "score": 0.54 }
    ]
  }
}

Error codes

| HTTP | Meaning | |---|---| | 400 | Empty or too-long query | | 401/403 | Not authenticated | | 500 | Server-side error (check NodeBB logs) |


File Structure

nodebb-plugin-search-agent/
├── library.js                  Main plugin: registers hooks & routes
├── plugin.json                 Plugin manifest (hooks, assets, modules)
├── package.json
├── lib/
│   ├── controllers.js          Route handlers (admin page + query API)
│   ├── searchHandler.js        NodeBB DB integration + index caching
│   └── similarity.js           Pure-JS TF-IDF engine
├── public/lib/
│   ├── main.js                 Frontend: FAB injection, chat panel, API calls
│   ├── admin.js                ACP settings page module
│   └── acp-main.js             ACP-bundled bootstrap script
├── scss/
│   └── search-agent.scss       All styles: FAB, panel, bubbles, animations
├── templates/
│   └── admin/plugins/
│       └── search-agent.tpl    ACP settings page template
└── languages/
    ├── en-US/search-agent.json
    ├── en-GB/search-agent.json
    └── de/search-agent.json

Design Decisions

Why TF-IDF instead of a vector embedding model?
External ML services (OpenAI, HuggingFace) require API keys, network calls, and add latency. A neural embedding approach also demands significant RAM for local inference. TF-IDF runs entirely in the Node.js process with zero memory or network overhead and is very fast (<10 ms per query on 500 topics), making it the right default for a self-hosted forum plugin.

Why cache the index instead of building it per request?
topics.getTopicsFields + posts.getPostsFields are database calls that add 50–200 ms. The index build itself adds another 20–50 ms. Caching amortises this to near zero. A 5-minute TTL means new topics appear within one cache window.

Why title ×3 weight?
Forum users almost always phrase questions using words that appear in topic titles. Over-weighting the body would dilute the signal for short replies and off-topic content in long threads.

Why restrict the index to topics:recent?
For large forums (100 k+ topics) building a full-corpus index at startup would consume excessive memory. The 500-topic default covers the most active/relevant content and can be raised in settings.


Local Development

# 1. Clone NodeBB
git clone https://github.com/NodeBB/NodeBB && cd NodeBB
npm install

# 2. Link the plugin
cd node_modules
git clone <this-repo> nodebb-plugin-search-agent

# 3. Start NodeBB
cd ../..
./nodebb setup   # follow the setup wizard
./nodebb start

# 4. Activate the plugin in ACP and rebuild

License

MIT