Skip to content

Navigation Menu

Sign in
Sign up

feat(components-doc): smarter RelatedProjects recommendations #8

Open
Assignees
Labels
enhancementNew feature or request
Milestone

Description

Background

RelatedProjects currently picks N entries at random from the full getRegistry() pool (62 entries across clients, plugins, cli, configs, utils, themes, docs, skills, templates), excluding the current slug. Random-at-build-time works but produces arbitrary results — a client page might surface a browserslist config or a monorepo template, which isn't useful.

This issue tracks ideas for making recommendations smarter over time. Entries are roughly ordered from lowest to highest implementation cost. The first iteration ships as-is; pick from this list for follow-ups.


Ideas

1. Slug-based pairing (automatic cross-links)

Many packages share a common word in their slug:

  • sentry-clientholocron-plugin-sentry
  • github-clientholocron-plugin-github
  • cloudflare-clientholocron-plugin-cloudflare

Extract the shared noun from the current slug and prioritize entries whose slug contains the same word. No schema changes needed — works with existing LinkEntry.slug values.

// "sentry-client" → "sentry"
// "holocron-plugin-sentry" → "sentry"
function extractKeyword(slug: string): string {
 return slug.replace(/^holocron-plugin-|-client$|-config$|-utils$|-template$/g, "");
}

Fill any remaining slots with random picks.

2. Same-repo grouping

Entries sharing a githubUrl belong to the same repo. When on a client page, the other clients in the same repo are the most natural "see also". Prioritize same-githubUrl entries first, then cross-repo entries.

const sameRepo = pool.filter(e => e.githubUrl === current.githubUrl);
const crossRepo = pool.filter(e => e.githubUrl !== current.githubUrl);

3. Caller-pinned slugs + random fill

Let the MDX author guarantee specific related entries and fill remaining slots randomly:

<RelatedProjects current="sentry-client" pinned={["holocron-plugin-sentry"]} count={3} />

Pinned entries appear first; random picks fill the rest. Zero effort for pages where the relationship is obvious; still zero-config for pages where it isn't.

4. Category weighting

Group entries by repo and apply a weight table so related categories appear more often than unrelated ones. Example: from a client page, weight toward other clients (0.6) and plugins (0.3), with everything else sharing the remaining 0.1. From a plugin page, weight toward clients (0.4) and other plugins (0.4).

The category of an entry is already implied by its githubUrl (all github.com/theholocron/clients entries are clients). No schema change needed.

5. Deterministic shuffle (seed from slug)

Math.random() means each build produces different results. A seeded PRNG keyed on the current slug would make every build produce the same picks for the same page — better for caching, better for users who revisit.

A simple implementation: hash the slug to an integer and use a linear congruential generator.

6. related field in registry-doc

Add an optional related?: string[] field to LinkEntry containing explicitly declared related slugs. Authors add these to packages/registry-doc/src/clients.ts etc. when they know the relationship.

export interface LinkEntry {
 // ...existing fields
 related?: string[]; // slugs of explicitly related entries
}

RelatedProjects uses related as the first-priority pool, falls back to slug-keyword matching, then random fill.

This is the most precise option but requires ongoing curation as new packages ship.

7. Exclude dissimilar categories

Some combinations are low signal. Showing a template repo as a related project from a plugin page adds little value. Add a exclude prop (or a default exclusion list) to filter out certain registry subsets:

<RelatedProjects current="holocron-plugin-github" exclude={["templates", "docs"]} />

Or derive the category from githubUrl and apply sensible defaults internally.

8. count guard

If the pool (after exclusions and filters) has fewer entries than count, the component currently silently returns fewer cards. Warn in development, or document the minimum pool size so authors know what to expect.

9. Description in LinkEntry

The rendered cards currently show only the package name and links. Adding a description?: string to LinkEntry in registry-doc would let the component show a one-line summary under the package name — much more useful for cross-category recommendations where the package name alone may not convey what it does.

10. "More from this repo" variant

A companion component <MoreFromRepo current="github-client" /> that only shows entries sharing the same githubUrl. Useful as a sidebar or footer on pages where the repo has many packages (clients, plugins, configs).

11. npm download signal

Weight popular packages higher using the npm downloads API (https://api.npmjs.org/downloads/point/last-month/{package}). Requires a build-time fetch step. High implementation cost; probably not worth it until the registry has enough traffic to make popularity meaningful.


Non-goals for this component

  • Runtime recommendations (user-behavior-based): out of scope; the docs site is statically generated.
  • ML/embedding similarity: over-engineered for a docs index page.

Acceptance criteria for "smarter" (whichever approach ships first)

  • Slug-keyword pairing surfaces the matching client/plugin pair on pages where one exists
  • Falls back gracefully to random when no keyword match is found
  • Same output across builds for the same page (deterministic)
  • No new required props — current stays the only required field

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

enhancementNew feature or request

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

AltStyle によって変換されたページ (->オリジナル) /