A browser add-on that hides vibe-killing toxic posts.
  • TypeScript 81.8%
  • Python 7.9%
  • HTML 4.2%
  • JavaScript 2.8%
  • Shell 2.7%
  • Other 0.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-25 17:05:11 -05:00
public Add JSON definition subscriptions 2026-08-25 00:40:30 -05:00
src Add site definition worker inference 2026-08-25 17:05:11 -05:00
tests Add site definition worker inference 2026-08-25 17:05:11 -05:00
tools Add initial VibeGuard browser extension 2026-08-24 15:27:46 -05:00
.gitattributes Add initial VibeGuard browser extension 2026-08-24 15:27:46 -05:00
.gitignore Add cross-browser popup status handling 2026-08-24 23:32:27 -05:00
build.sh Add cross-browser popup status handling 2026-08-24 23:32:27 -05:00
DESIGN.md Add site definition worker inference 2026-08-25 17:05:11 -05:00
LICENSE Initial commit 2026-08-23 22:06:30 -05:00
package-lock.json Add initial VibeGuard browser extension 2026-08-24 15:27:46 -05:00
package.json Add initial VibeGuard browser extension 2026-08-24 15:27:46 -05:00
README.md Add site definition worker inference 2026-08-25 17:05:11 -05:00
tsconfig.json Add JSON definition subscriptions 2026-08-25 00:40:30 -05:00
vite.config.ts Add cross-browser popup status handling 2026-08-24 23:32:27 -05:00

VibeGuard

VibeGuard is a local-first browser extension that hides toxic social-media posts. Content is classified on-device; post text is never sent to a classification service.

Features

  • Local toxicity classification using Transformers.js and a quantized ONNX model.
  • Local CPU/WASM inference with ONNX Runtime.
  • Configurable toxicity threshold and filtering mode: collapse posts with a Show button or hide them completely.
  • Optional toxicity scores on filtered-post placeholders.
  • Declarative site definitions with URL patterns, selectors, and stable identifiers.
  • Built-in support for the official Mastodon web interface and Threads.
  • Versioned JSON definition collections with weekly subscriptions and manual refresh.
  • Toolbar popup with current-site status, matched definition, pause/resume control, and settings access.
  • Firefox Manifest V2 and Chromium Manifest V3 builds.

The content script is loaded broadly so it can support navigation and dynamically rendered pages, but it does not inspect page content until a validated site definition matches the current page. Site definitions are data, not executable user code.

Development

npm install
npm run typecheck
npm test
npm run build:firefox
npm run build:chromium

Each build writes a browser-specific package under dist/<mode>/. The packaged Apache 2.0 model is committed through Git LFS. Use the pinned-revision workflow below when updating it:

python3 -m venv .model-venv
. .model-venv/bin/activate
python3 -m pip install -r tools/requirements-model.txt

# Inspect architecture, labels, tokenizer, and resolved source revision.
python3 tools/convert_model.py inspect \
  --model wagesj45/toxic-comment-classifier

# Use the immutable commit printed by inspection for a release artifact.
python3 tools/convert_model.py prepare \
  --model wagesj45/toxic-comment-classifier \
  --revision <resolved-huggingface-commit>
python3 tools/convert_model.py validate

Preparation writes the Transformers.js-compatible files and model-manifest.json under public/models/toxicity/. The manifest records the source revision, Apache 2.0 license, toxic/non-toxic label indices, maximum sequence length, and int8 quantization format. Source PyTorch/safetensors weights are never copied into the extension.

If the model uses generic labels such as LABEL_0 and LABEL_1, pass --toxic-index and --non-toxic-index to prepare; the command refuses to guess an ambiguous mapping.

VibeGuard injects a lightweight content script on ordinary web pages, but reads and processes content only when a validated site definition matches the page. The extension includes a bundled definition collection for the official Mastodon web interface and Threads. The Threads definition covers both threads.com and legacy threads.net URLs using semantic and data-attribute selectors. The default subscription follows the repository's raw JSON collection and refreshes weekly, while the bundled copy remains available offline. Additional JSON subscriptions, local overrides, and disabled definitions are managed in the options page. Definitions are declarative selectors and URL patterns, never executable code.

Runtime architecture

Firefox uses a persistent MV2 background page and inference worker. Chromium uses an MV3 service worker as a router, an offscreen document, and a worker-backed classifier. Both builds share one bounded, prioritized inference queue and in-memory text-result cache.

The high-level processing path is:

Supported page
    -> validated site definition
    -> generic content discovery
    -> shared inference queue
    -> local classifier
    -> threshold and filtering mode

The model is loaded once by the shared inference backend for each browser context. Content scripts send normalized text to the background runtime and apply the returned score to the matching DOM element. Results are cached in memory to avoid repeating work when dynamic sites recreate elements.

Inference runs locally through ONNX Runtime's WASM backend using the bundled quantized model.

Options page

Open the extensions options page to change the threshold, filtering mode, and score display. The Site definitions section manages JSON subscriptions, which refresh automatically once per week and can also be refreshed manually. Local overrides can be imported from or exported to JSON and are validated before they are saved. A failed or invalid subscription update leaves the last-known-good definitions active.

The options page uses the locally bundled Bulma CSS v1.0.3 stylesheet. No options-page styling or runtime dependency is loaded from a CDN.

Click the toolbar icon to open the VibeGuard popup. It reports whether the current page is supported, names the matched site definition, and provides a persistent pause/resume control for that definition. Pausing immediately stops filtering in matching open tabs and removes VibeGuards current placeholders; resuming restarts discovery without requiring a page reload.

Browser permissions

VibeGuard requests the following permissions:

  • storage to save settings and definition configuration.
  • tabs to associate inference requests with browser tabs.
  • <all_urls> host access so supported sites can be detected and filtered.
  • offscreen in the Chromium Manifest V3 build to host the long-lived inference document.

Model and third-party licenses

The packaged toxicity model is distributed under the Apache License 2.0. Its source revision, label mapping, sequence length, and quantization details are recorded in public/models/toxicity/model-manifest.json.

VibeGuard also bundles Bulma CSS v1.0.3, which is distributed under the MIT License. The projects own code is licensed under the terms in LICENSE.

Repository layout

Path Purpose
src/content/ Generic site discovery and DOM filtering.
src/background/ Firefox and Chromium background runtimes.
src/inference/ Worker, classifier, queue, and model metadata.
src/options/ Options-page behavior and VibeGuard-specific styling.
src/shared/ Settings, site-definition validation, types, and shared utilities.
public/ Browser manifests, options HTML, bundled CSS, and model files.
tests/ Unit tests for queues, filtering, definitions, hashing, and model metadata.

Testing and packaging

Run the type checker and test suite before building a package:

npm run typecheck
npm test

Build the browser-specific packages with:

npm run build:firefox
npm run build:chromium

The generated directories are dist/firefox/ and dist/chromium/. Each contains the browser manifest, bundled JavaScript, the local bulma.css asset, and the model files required by that build. Load the generated directory as a temporary/unpacked extension during development.

To build versioned install packages for both browsers, run the shell packaging script from any directory:

./build.sh

The script runs both browser builds and writes release/vibeguard-firefox-<version>.zip and release/vibeguard-chromium-<version>.zip. The archives contain the generated extension files at their root and are ignored by Git.

Logo and icons

Place the source logo at public/logo.png. The options page displays the generated 64 px version, and build.sh uses ImageMagick to generate the browser icon sizes 16, 32, 48, 64, 96, and 128 under icons/ in each release package. Install ImageMagick before running the packaging script; it accepts either the magick or convert command.