Token导航 LogoToken导航

Agent Skill · 前端设计

bouncer-feed-filter(弹跳饲料过滤器)

bouncer-feed-filter 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

bouncer-feed-filter 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证信息还不明确,第三方扫描有提醒项,按安装量在前端设计类的 10,216 个 Skill 里排第 1,501。

总安装 5,363周安装 228GitHub Stars 39下载 1,879核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:bouncer-feed-filter(弹跳饲料过滤器)
来源仓库:https://github.com/aradotso/trending-skills
仓库路径:skills/bouncer-feed-filter
安装命令:
npx skills add https://github.com/aradotso/trending-skills --skill bouncer-feed-filter
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/aradotso/trending-skills --skill bouncer-feed-filter

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

bouncer-feed-filter 是一个浏览器扩展,使用 AI 实时过滤 Twitter/X 上的不想要帖子。适用场景包括定义过滤器、AI 分类和隐藏匹配帖子,提升社交媒体体验。核心能力包括本地 WebGPU 模型、云端 AI 支持和多种模型提供商集成,确保高效的内容过滤。

安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/bouncer-feed-filter

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/aradotso/trending-skills --skill bouncer-feed-…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

bouncer-feed-filter 怎么安装?

在终端执行 npx skills add https://github.com/aradotso/trending-skills --skill bouncer-feed-filter。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

bouncer-feed-filter 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

bouncer-feed-filter 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

bouncer-feed-filter 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

bouncer-feed-filter 用的人多吗?

公开数据是累计安装 5,363 次,近一周安装 228 次,下载 1,879 次,GitHub 39 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

bouncer-feed-filter 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
bouncer-feed-filter

弹跳饲料过滤器 · 本页

5,36339接触敏感数据未明确有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Bouncer Feed Filter

Skill by ara.so — Daily 2026 Skills collection.

Bouncer is a browser extension (Chrome/Edge/iOS) that uses AI to filter unwanted posts from Twitter/X feeds in real time. Users define filters in plain language ("crypto", "engagement bait", "rage politics"), and Bouncer classifies and hides matching posts using AI models — local (WebGPU via WebLLM) or cloud (OpenAI, Gemini, Anthropic, OpenRouter, Imbue).

Repository Structure

Bouncer/                  # Main extension source
  src/
    background/           # Service worker / background scripts
    content/              # Content scripts (Twitter DOM interaction)
    popup/                # Extension popup UI
    adapters/             # Site adapters (Twitter/X)
    models/               # AI backend integrations
    utils/                # Shared utilities
  icons/                  # Extension icons
  manifest.json           # Chrome extension manifest
  package.json
  tsconfig.json

Installation & Build

From Source (Chrome/Edge)

git clone https://github.com/imbue-ai/bouncer.git
cd bouncer/Bouncer
npm install
npm run build

Load in Chrome:

  1. Go to chrome://extensions
  2. Enable Developer mode
  3. Click Load unpacked → select Bouncer/ folder
  4. Navigate to twitter.com or x.com

Development Build (watch mode)

cd Bouncer
npm run dev        # watch mode with hot rebuild

Production Build

npm run build      # outputs to Bouncer/dist or inline

AI Backend Configuration

Bouncer supports multiple providers. Configure via the extension popup Settings panel.

Provider / Model Matrix

ProviderModel IDsAuth
Local WebGPUQwen3-4B, Qwen3.5-4B, Qwen3.5-4B VisionNone
OpenAIGPT-5 Nano, gpt-oss-20bAPI key
Google Gemini2.5 Flash Lite, 2.5 Flash, 3 Flash PreviewAPI key
AnthropicClaude Haiku 4.5API key
OpenRouterNemotron Nano 12B VL, Ministral 3BAccount token
ImbueDefaultNone (built-in)

API keys are stored in Chrome's chrome.storage.local — never hardcoded.

Core Architecture

1. MutationObserver — Content Script

The content script watches the Twitter feed for new posts:

// src/content/feedObserver.ts
const observer = new MutationObserver((mutations) => {
  for (const mutation of mutations) {
    for (const node of mutation.addedNodes) {
      if (node instanceof HTMLElement) {
        const post = extractPost(node);
        if (post) classifyAndFilter(post);
      }
    }
  }
});

observer.observe(document.body, { childList: true, subtree: true });

2. Post Extraction — Twitter Adapter

// src/adapters/twitter.ts
export interface ExtractedPost {
  id: string;
  text: string;
  authorHandle: string;
  imageUrls: string[];
  element: HTMLElement;
}

export function extractPost(element: HTMLElement): ExtractedPost | null {
  const article = element.querySelector('article[data-testid="tweet"]');
  if (!article) return null;

  const tweetText = article.querySelector('[data-testid="tweetText"]')?.textContent ?? '';
  const handle = article.querySelector('[data-testid="User-Name"] a')?.getAttribute('href') ?? '';
  const images = [...article.querySelectorAll('img[src*="pbs.twimg.com/media"]')]
    .map(img => (img as HTMLImageElement).src);

  return {
    id: article.closest('[data-testid]')?.getAttribute('data-testid') ?? crypto.randomUUID(),
    text: tweetText,
    authorHandle: handle.replace('/', ''),
    imageUrls: images,
    element: article as HTMLElement,
  };
}

3. Classification Request

// src/models/classify.ts
export interface ClassificationResult {
  filtered: boolean;
  matchedCategory: string | null;
  reasoning: string;
}

export async function classifyPost(
  post: ExtractedPost,
  filters: string[],
  model: ModelConfig
): Promise<ClassificationResult> {
  const prompt = buildClassificationPrompt(post.text, filters, post.imageUrls);
  const response = await model.provider.complete(prompt);
  return parseClassificationResponse(response);
}

function buildClassificationPrompt(
  text: string,
  filters: string[],
  imageUrls: string[]
): string {
  return `You are a content filter. Given a social media post, determine if it matches any of the user's filter categories.

Filter categories: ${filters.map(f => `"${f}"`).join(', ')}

Post text:
${text}

${imageUrls.length > 0 ? `The post contains ${imageUrls.length} image(s).` : ''}

Respond with JSON:
{
  "filtered": boolean,
  "matchedCategory": "category name or null",
  "reasoning": "brief explanation"
}`;
}

4. Hiding Filtered Posts

// src/content/filterUI.ts
export function hidePost(element: HTMLElement, reason: string): void {
  element.style.transition = 'opacity 0.3s ease-out';
  element.style.opacity = '0';
  setTimeout(() => {
    element.style.display = 'none';
    element.dataset.bouncerFiltered = 'true';
    element.dataset.bouncerReason = reason;
  }, 300);
}

export function showFilteredIndicator(count: number): void {
  const indicator = document.getElementById('bouncer-filtered-count');
  if (indicator) indicator.textContent = `${count} filtered`;
}

Adding a New AI Provider

// src/models/providers/myProvider.ts
import type { ModelProvider, CompletionRequest, CompletionResponse } from '../types';

export class MyProvider implements ModelProvider {
  private apiKey: string;
  private endpoint = 'https://api.myprovider.com/v1/chat/completions';

  constructor(apiKey: string) {
    this.apiKey = apiKey;
  }

  async complete(request: CompletionRequest): Promise<CompletionResponse> {
    const response = await fetch(this.endpoint, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: request.model,
        messages: [{ role: 'user', content: request.prompt }],
        max_tokens: 256,
      }),
    });

    const data = await response.json();
    return {
      text: data.choices[0].message.content,
      usage: data.usage,
    };
  }
}

Register it in the provider registry:

// src/models/registry.ts
import { MyProvider } from './providers/myProvider';

export function createProvider(config: StoredConfig): ModelProvider {
  switch (config.provider) {
    case 'my-provider':
      return new MyProvider(config.apiKey);
    // ... other cases
  }
}

Result Caching

Bouncer caches classification results so repeated posts don't trigger new inference calls:

// src/utils/cache.ts
const CACHE_KEY = 'bouncer-post-cache';

export async function getCachedResult(postId: string): Promise<ClassificationResult | null> {
  const stored = await chrome.storage.local.get(CACHE_KEY);
  const cache = stored[CACHE_KEY] ?? {};
  return cache[postId] ?? null;
}

export async function cacheResult(postId: string, result: ClassificationResult): Promise<void> {
  const stored = await chrome.storage.local.get(CACHE_KEY);
  const cache = stored[CACHE_KEY] ?? {};
  cache[postId] = result;
  // Limit cache size
  const keys = Object.keys(cache);
  if (keys.length > 1000) delete cache[keys[0]];
  await chrome.storage.local.set({ [CACHE_KEY]: cache });
}

Filter Management

Filters are stored and retrieved via chrome.storage.sync:

// src/utils/filters.ts
export async function getFilters(): Promise<string[]> {
  const result = await chrome.storage.sync.get('bouncerFilters');
  return result.bouncerFilters ?? [];
}

export async function addFilter(topic: string): Promise<void> {
  const filters = await getFilters();
  if (!filters.includes(topic)) {
    await chrome.storage.sync.set({ bouncerFilters: [...filters, topic] });
  }
}

export async function removeFilter(topic: string): Promise<void> {
  const filters = await getFilters();
  await chrome.storage.sync.set({
    bouncerFilters: filters.filter(f => f !== topic),
  });
}

Local WebGPU Models (WebLLM)

Local models run entirely in-browser via WebGPU — zero data sent externally:

// src/models/providers/webllm.ts
import { CreateMLCEngine, type MLCEngine } from '@mlc-ai/web-llm';

let engine: MLCEngine | null = null;

export async function loadLocalModel(modelId: string, onProgress?: (p: number) => void): Promise<void> {
  engine = await CreateMLCEngine(modelId, {
    initProgressCallback: (report) => onProgress?.(report.progress),
  });
}

export async function localComplete(prompt: string): Promise<string> {
  if (!engine) throw new Error('Local model not loaded');
  const response = await engine.chat.completions.create({
    messages: [{ role: 'user', content: prompt }],
    max_tokens: 256,
  });
  return response.choices[0].message.content ?? '';
}

Chrome Extension Manifest Key Points

{
  "manifest_version": 3,
  "permissions": ["storage", "activeTab", "scripting"],
  "host_permissions": ["https://twitter.com/*", "https://x.com/*"],
  "background": { "service_worker": "background.js" },
  "content_scripts": [{
    "matches": ["https://twitter.com/*", "https://x.com/*"],
    "js": ["content.js"],
    "run_at": "document_idle"
  }]
}

Troubleshooting

ProblemFix
Extension not loadingEnsure npm run build completed without errors; reload unpacked extension
Posts not being filteredCheck that filters are saved in popup; open DevTools on x.com and check console for errors
API key errorsVerify key is stored via Settings panel, not hardcoded; check provider dashboard for quota
Local model not loadingBrowser must support WebGPU (chrome://flags/#enable-unsafe-webgpu); first load downloads model (~2-4GB)
Filtered count not updatingMutationObserver may have detached; reload the page
TypeScript errors on buildRun npm install to ensure all types are present; check tsconfig.json target is ES2020+

Common Patterns

Check if a post should be processed (before API call):

async function classifyAndFilter(post: ExtractedPost): Promise<void> {
  // Skip if already processed
  if (post.element.dataset.bouncerProcessed) return;
  post.element.dataset.bouncerProcessed = 'true';

  // Check cache first
  const cached = await getCachedResult(post.id);
  if (cached) {
    if (cached.filtered) hidePost(post.element, cached.reasoning);
    return;
  }

  const filters = await getFilters();
  if (filters.length === 0) return;

  const config = await getModelConfig();
  const result = await classifyPost(post, filters, config);

  await cacheResult(post.id, result);
  if (result.filtered) hidePost(post.element, result.reasoning);
}

Storing API key securely (popup UI):

// Never log or expose the key — store only via chrome.storage.local
async function saveApiKey(provider: string, key: string): Promise<void> {
  await chrome.storage.local.set({ [`${provider}_api_key`]: key });
}

async function getApiKey(provider: string): Promise<string> {
  const result = await chrome.storage.local.get(`${provider}_api_key`);
  return result[`${provider}_api_key`] ?? '';
}

适合场景

01

调用多模型

02

代码和文本生成

03

Agent 推理流程

04

OpenRouter 模型接入

能力概览

能力 1

统一调用多种 LLM

能力 2

支持 Claude、Gemini、Kimi 等模型

能力 3

适合聊天、代码和推理任务

能力 4

可作为 Agent 模型调用入口

平台分布

Codex

38.49%
按下载量换算723

Claude

32.1%
按下载量换算603

Cursor

17.59%
按下载量换算331

Gemini CLI

9.41%
按下载量换算177

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills