Context Compass is a small Chrome and Edge extension that answers a practical question: what is worth reading next, and how does it relate to the page in front of me?
It works with papers, articles, and individual posts on X, Zhihu, and Xiaohongshu. Recommendations are assembled from direct sources, citation data, visible page context, and optional discovery APIs. A language model is never used for search and is not required for the extension to work.
Project status: v0.3.1 is an experimental MVP. Paper support is the most complete path. Social-site extraction and discovery depend on visible page data and third-party API coverage.
The extension interface and generated explanations are in English. Source titles, author names, quotations, and search topics stay in their original language.
- Chrome and Edge support through Manifest V3 and WXT
- A vanilla TypeScript side panel with progressive results
- Paper lookup through Semantic Scholar, with OpenAlex fallback
- Relationship-aware ranking for citations, source links, related work, creator follow-ups, peer progress, and alternative views
- Chinese topic extraction with the browser's built-in
Intl.Segmenter - Useful operation without an AI key; AI classification is an optional final pass
- IndexedDB caching, request deduplication, timeouts, cancellation, and partial-failure handling
- One runtime dependency:
@mozilla/readability
Context Compass is currently distributed as source. Node.js 20 or newer is required to build it.
git clone https://github.com/lizr-phys/context-compass.git
cd context-compass
npm ci
npm run build- Open
chrome://extensions. - Enable Developer mode.
- Select Load unpacked.
- Choose
.output/chrome-mv3from this repository.
npm run build:edgeThen open edge://extensions, enable Developer mode, select Load unpacked, and choose .output/edge-mv3.
After loading the extension, open a supported page and click the Context Compass toolbar icon. The icon opens the side panel. See TESTING.md for a full acceptance checklist.
| Page | Extraction | Candidate sources |
|---|---|---|
| arXiv abstract | arXiv ID, citation metadata, abstract | Semantic Scholar recommendations, references, citations; OpenAlex fallback |
| arXiv PDF | arXiv ID from the URL | Same paper pipeline; the PDF is not downloaded |
| Journal page | DOI URL, citation_*, PRISM/DC, JSON-LD, limited body lookup |
Semantic Scholar and OpenAlex |
| Generic PDF | URL and visible metadata | Paper pipeline only when a DOI or arXiv ID can be established |
| Article or blog | JSON-LD, Open Graph, metadata, then gated Readability | Direct links; OpenAlex only for explicit academic claims; local search paths |
| X status | Current post, author, timestamp, public counts, mentions, quoted post, links | Page context, direct sources, optional X and Brave discovery |
| Zhihu answer or post | Current answer/post container, author, visible counts, topics, explicit related items | Page context, direct sources, optional Brave discovery |
| Xiaohongshu note | Current detail container, visible counts, tags, limited relevant cards | Page context, direct sources, optional Brave discovery |
The content script does not scan an entire feed. Extraction runs when the side panel opens, when the URL changes, or when the current main-content container changes.
The pipeline is deliberately bounded:
current page
-> content adapter
-> normalized ContentItem
-> candidate providers (in parallel)
-> relevance gate and fast ranker
-> relationship rules
-> diversity selection
-> five results
-> optional AI relationship refinement
Cached results are shown first. Fresh providers run with Promise.allSettled, and the side panel updates as useful batches arrive. Candidate pools are capped at roughly 100 items; graph refinement is limited to a small shortlist.
Paper identity follows a cheap-first order: DOI or arXiv ID in the URL, citation metadata, JSON-LD, a DOI in the main content, title and authors, and finally title lookup. The extension does not parse a complete PDF or run OCR.
Semantic Scholar requests recommendations, references, and citations independently. OpenAlex fills gaps when the initial paper set is small. Ranking combines direct citation direction, semantic or lexical proximity, bibliographic coupling, co-citation, citation count, publication date, and provider rank. The final selector reduces near-duplicate titles, repeated authors, and repeated relationship facets without forcing one item from each category.
v0.3 uses a topic profile rather than a single full-title search:
- title, body, hashtags, model names, and recognized entities receive different weights;
- Chinese text is split with
Intl.Segmenter, short adjacent phrases are retained, and low-information terms are removed; - a small set of bilingual concept aliases handles cases such as
Qwen,GLM, large language models, theoretical physics, and quantum sensing; - title-to-title, body-to-title, title-to-body, and body-to-body matches are scored separately, with candidate titles carrying the most weight.
Candidates must clear a topical admission gate before popularity can help them. Verified citation/source relationships and same-creator continuity are handled separately; related-account results, ordinary links, and search results still need local topic evidence. This prevents a viral but unrelated post—or a page that merely contains a generic word such as “research”—from outranking a quieter, specific match.
For admitted social candidates, the ranker adds:
heat = likes + 2.4*comments + 3.2*reposts + 1.4*bookmarks + 0.012*views
The value is log-scaled and combined with a 45-day recency decay, creator/account affinity, and discussion patterns such as a release, benchmark, open-source update, demo, controversy, or policy change. These patterns are boosts, not independent relevance evidence.
Brave discovery sends at most three short searches built from three or four topic anchors. Returned pages are checked again before entering the candidate pool, and an account relationship is accepted only when the result URL exposes a matching handle. OpenAlex search for a non-paper page requires both explicit academic intent and a specific topic; its results also pass a local topic check.
Direct links are not trusted solely because they appear on the page. DOI/arXiv links, recognized academic URLs, and clearly labelled original-paper links are treated as primary evidence. Other links must match the current topic, while navigation, profile, advertising, shopping, and sign-in links are discarded.
When fewer than five concrete web or social results are available, Context Compass fills the remaining positions with clearly labelled, click-to-search paths for the current platform, background reading, related research, or alternative views. These paths make no network request until clicked and are never presented as articles the extension has already verified.
No key is required to start. “Local” in the side panel means no optional social-discovery or AI provider is configured; it does not mean offline mode. Paper pages may still call the public Semantic Scholar and OpenAlex APIs.
| Setting | Required | Used for |
|---|---|---|
| Semantic Scholar API key | No | More reliable paper API limits |
| OpenAlex API key / email | No | OpenAlex paper fallback and tightly gated academic search |
| Brave Search API key | No | Recent creator, related-account, peer, and web discovery for social pages |
| X API bearer token | No | Recent public posts and metrics from the current or related X accounts |
| AI provider, model, and key | No | Relationship label and short explanation refinement after ranking |
The available relationship classifiers are OpenAI-compatible, OpenAI, Gemini's OpenAI-compatible endpoint, Anthropic, OpenRouter, Ollama, and a custom endpoint. OpenAI-compatible, custom, and local endpoints may omit a key when the server does not require one.
Enabling AI does not change retrieval. The basic five results appear first; then up to eight shortlisted candidates are sent in one small classification request. The model receives truncated text and existing evidence, not a complete page, and a failed or invalid response leaves the deterministic results intact.
The default setting is AI enabled = false.
- Page text is not sent to an AI endpoint unless AI classification is enabled.
- Academic APIs receive identifiers, titles, or candidate IDs rather than full pages.
- Brave receives short topic queries only after its key is configured.
- The X token is sent only to
api.x.com; the Brave key is sent only toapi.search.brave.com. - API credentials are stored in
chrome.storage.localand are not logged or synchronized. - Custom hosts are requested as optional permissions when their settings are saved. Unused origins are removed when settings change.
- There is no account system, telemetry, or cloud sync.
For AI classification, current-page text is capped at about 1,200 characters and each candidate at about 800 characters. Local focused-search paths are excluded from AI classification.
Side panel (Vanilla TypeScript + CSS)
| request current content
v
Content script
| URL-first adapter -> scoped metadata -> gated Readability
v
Normalized ContentItem
| runtime port
v
MV3 service worker
|- IndexedDB cache
|- paper, link, social, and fallback providers
|- relevance gate, ranker, and diversity selector
|- deterministic relationship explanations
`- optional batched AI classifier
|
`-> progressive updates to the side panel
The service worker owns network requests, credentials, caching, ranking, and classification. The content script stays event-driven and performs no provider requests. The side panel is a view over progressive pipeline events.
Useful entry points:
src/types.ts— normalized content, candidates, signals, and relationshipssrc/adapters— page detection and extractionsrc/providers— bounded candidate retrievalsrc/social/discovery.ts— topic anchors, account context, heat, and recencysrc/ranking/ranker.ts— relevance gates, ranking, deduplication, and diversitysrc/pipeline/recommend.ts— cache-first orchestration and progressive output
npm ci
npm run devBefore submitting a change:
npm run typecheck
npm test
npm run build
npm run build:edgeAdditional checks:
npm run size # raw and gzip bundle report
npm run benchmark # local fixture and warm-cache microbenchmarks
npm run smoke:providers # live Semantic Scholar smoke testFixtures cover arXiv, journal HTML, generic PDFs, articles, X, Zhihu, and Xiaohongshu. Live social sites still need a manual pass because their DOM and login walls change. Recorded bundle and timing measurements are kept in PERFORMANCE.md.
- Implement
ContentAdapterunder the relevant folder insrc/adapters. - Keep
detect()to cheap URL and metadata checks. Do not make network requests there. - Register the adapter in
src/adapters/index.ts, from most specific to generic. - Add a minimal HTML fixture that proves the adapter selects the current content rather than a feed, comments, or navigation.
- Return a normalized
ContentItemand keep extracted body text within the existing limits.
- Implement
CandidateProvider.supports()andretrieve(). - Make requests through
JsonFetcherand cache stable responses throughCacheDatabase. - Return explicit evidence and comparable signals. A search hit must not be labelled as a citation or primary source.
- Register the provider in
src/pipeline/recommend.tswithout making other providers wait for it. - If refinement is necessary, implement
refine()over a small ranked shortlist.
- Generic PDFs are not parsed and OCR is not supported. Chrome's built-in PDF viewer usually exposes only the URL and limited metadata.
- Zhihu and Xiaohongshu do not provide a stable public content-search API used by this project. Brave coverage can miss new, private, or login-gated posts and cannot recover hidden engagement counts.
- X API availability depends on the user's developer plan. A
401or403from one endpoint does not invalidate results from other providers. - The built-in account map is intentionally small. It is useful for a few known AI ecosystems, not a general social graph.
- Source tracing promotes explicit direct sources but does not yet crawl a complete
post -> news -> press release -> paperchain. - Without a discovery key, generic web and social pages may end with click-to-search paths rather than five concrete items.
- Social adapters depend on site markup. Fixtures catch known selector regressions, but a site redesign can still require an update.
- No embedding model runs in the extension; semantic coverage comes from provider results, citation structure, weighted lexical matching, and concept aliases.
Context Compass is released under the MIT License. Runtime notices are listed in THIRD_PARTY_NOTICES.md. Notes from the short architecture survey that informed the implementation are in REFERENCE_NOTES.md; code from GPL, AGPL, unlicensed, or community-license projects was not copied into this repository.