Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Webcmd Cloud can run supported commands and browser sessions on hosted infrastru

| Plugin | Description | Author |
| --- | --- | --- |
| [`omnisearch`](./plugins/omnisearch/) | Scrape & research 12 platforms — X, Reddit, LinkedIn, Instagram, YouTube, Hacker News, Stack Overflow, GitHub, arXiv, Dev.to, Lobsters, Bluesky | [Rishet Mehra](https://github.com/Rishet11) |
| [`pypi`](./plugins/pypi/) | Inspect public Python package metadata, downloads, and releases from PyPI | [Kemal Kaya](https://github.com/yoldaolmak) |
| [`skyscanner`](./plugins/skyscanner/) | Skyscanner flight search commands for Webcmd | [Rishabh](https://github.com/rishabhraj36) |
<!-- webcmd-community-plugins:end -->
Expand Down
138 changes: 138 additions & 0 deletions plugins/omnisearch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# 🔎 OmniSearch

**OmniSearch is a research assistant that reads the internet for you.**

Ask it what people on **X, Reddit, LinkedIn, Instagram, YouTube, Hacker News, Stack Overflow, GitHub, and more** are saying, asking, and complaining about — and it brings back a clear answer with links.

**You never need to touch the command line.** This tool is for your AI agent (Claude Code, Codex, Cursor, ChatGPT), not for you. Just tell your agent what you want to learn, and it handles the rest.

---

## How to use OmniSearch (no coding needed)

There are three steps — and you only do the first one yourself.

**Step 1 — Install once (5 minutes).** You add OmniSearch to your AI assistant, like installing an app once. Your agent runs this for you:

```
webcmd plugin install github:Rishet11/webcmd-plugin-omnisearch
```

**Step 2 — Tell your agent what you want to know.**

You don't type commands. You just talk. Say something like:

> "Before I build this, find out what people actually think about it."

Your agent recognizes OmniSearch and runs it for you.

**Step 3 — Read the answer.**

You get a plain-language summary — what people say, where they say it, and links to the actual posts. No folders, no files, nothing to interpret.

---

## What you say. What your agent does.

Here are real conversations, ready to copy-paste. Swap the words in **{braces}** for your topic.

| You say | What your agent finds |
|---|---|
| "**{My idea}** — do people actually want this?" | What people say across X, Reddit, Hacker News, GitHub |
| "Find what people complain about when using **{a tool}**." | The real problems people report on Stack Overflow and GitHub |
| "Is **{this idea}** already done? Who's winning?" | The competition and reception across platforms |
| "Is **{this idea}** even technically possible yet?" | What research says is proven vs. still speculative |
| "Before I launch **{product}**, what could kill it?" | The risks, past failures, and strongest arguments for it |
| "What's the reaction to **{a product / a launch / the news}**?" | What people are saying on X, Reddit, and Hacker News right now |

### Ready-to-paste prompts for your agent

Pick one, replace **{the brackets}**, and paste it to your agent:

1. "Research **{topic/competitor/product}**. Use OmniSearch to check what people say across Reddit, X, Hacker News, and GitHub. Give me a two-paragraph summary and the 5 most-talked-about posts with links."

2. "Find what's broken or frustrating about **{topic}**. Look at Stack Overflow questions and GitHub issues, and list the 10 most common problems people mention, each with a source link."

3. "Check if **{my idea}** is technically realistic yet. Scan recent research papers and tech discussions, and tell me what's proven to work vs. still speculative."

4. "Validate my idea: **{one-line pitch}**. Gather what people are saying about it, rate how much real interest there is, and quote 3 real people with links."

5. "Do a pre-mortem on **{my startup/product}**. Find how similar things failed before, the top 3 reasons this could fail, and the strongest argument it could succeed — each with a source."

6. "What do developers complain about when using **{a tool/language}**? Summarize the biggest recurring pain points with links."

7. "Check the reaction to **{a new release / launch}**. What are people on X, Reddit, and Hacker News saying right now?"

---

## What you can research

OmniSearch reads **12 places people talk** — the big social networks (through your own accounts, quietly in the background) plus a bunch of no-login communities:

| Platform | Best at telling you |
|---|---|
| **X / Twitter** 🐦 | what people think right now |
| **Reddit** 🧑‍🤝‍🧑 | real threads and discussion |
| **LinkedIn** 💼 | professional opinions, finding people |
| **Instagram** 📸 | visual and chat culture |
| **YouTube** ▶️ | video + what's being discussed |
| **Hacker News** 🟠 | what the tech world thinks |
| **Stack Overflow** 📚 | what's actually broken |
| **GitHub** 🐙 | real problems people file |
| **Dev.to** 💜 | what developers are writing |
| **arXiv** 📄 | the latest research |
| **Lobsters** 🦞 | smart developer discussion |
| **Bluesky** 🦋 | fresh public posts |

**No login needed for most.** Only X, Reddit, LinkedIn, Instagram, and YouTube use your own account — the agent uses it quietly in the background; you never log in again.

---

## Start now

**Install OmniSearch once, then ask your agent:**

> *"Before I build this, find out what people actually think about it."*

That's the whole product.

---

## For developers

Everything below is for the agent (and for people who want to dig in). A normal user never reads this.

### The commands

```bash
# Aggregate everything about a topic
webcmd omnisearch research "<topic>" -f json

# 🏆 The community's verdict, distilled
webcmd omnisearch verdict "<topic>" -f json

# One source at a time
webcmd omnisearch hackermind "<q>" -f json
webcmd omnisearch stackoverflow "<q>" -f json
webcmd omnisearch github "<q>" -f json
webcmd omnisearch arxiv "<q>" -f json
webcmd omnisearch devto <tag> -f json
webcmd omnisearch lobsters -f json
webcmd omnisearch bluesky-posts <handle> -f json

# Logged-in social (one-time login: webcmd --profile social <site> login)
webcmd --profile social twitter search "<q>" -f json
webcmd --profile social reddit search "<q>" -f json
webcmd --profile social linkedin people-search "<q>" -f json
webcmd --profile social instagram search "<q>" -f json
```

### Output

Every command returns the same shape: `platform`, `title`, `author`, `score`, `commentCount`, `createdAt`, `url`, `text`. The `score` + `commentCount` let an agent rank results by real traction.

### How it works

All platforms live in `sources.js` behind one signature (`search(query, limit)`), so adding a new platform to `research` is about 20 lines.

Ships `SKILL.md` so agent harnesses auto-discover OmniSearch.
26 changes: 26 additions & 0 deletions plugins/omnisearch/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: omnisearch
description: Read-only, no-login web research across Hacker News, Lobste.rs, Stack
Overflow, GitHub issues, Dev.to, arXiv, and Bluesky. Use to answer "what does the
internet think / ask / struggle with" about any topic. Returns JSON via webcmd.
---

# OmniSearch skill

1. Invoke every query as `webcmd omnisearch <command> -f json`. The site name is
`omnisearch` — never call `webcmd research` or omit the site prefix.
2. Choose the command by intent:
- `research "<topic>"` — whole-space scan across all sources. Add
`--sources hn,lobsters,stackoverflow,github,arxiv` to narrow.
- `github` / `stackoverflow` — real problems people report/ask.
- `hackermind "<query>"` — HN opinions and discussions.
- `arxiv "<query>"` — research papers.
- `devto <tag>` — Dev.to articles. **Takes a TAG, not free text** (e.g. `saas`).
- `lobsters --sort active|newest|hot` — live discussion (no free query).
- `bluesky-posts <handle>` — one public account's feed.
3. `research` distributes `--limit` across sources, so use `--limit` >= 24 for
coverage. `title` and `url` are always populated; `text` may be empty (HN,
StackOverflow) or truncated (GitHub 300 chars, arXiv 200). Never fabricate a
summary from an empty `text` — cite `url` and rank by `score`.
4. GitHub search is rate-limited (~10 req/min). Space out parallel calls; do not
fan out 6 GitHub calls at once.
43 changes: 43 additions & 0 deletions plugins/omnisearch/arxiv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* OmniSearch arxiv — search arXiv research papers.
* No login. Uses the public arXiv Atom API.
*/
import { cli, Strategy } from '@agentrhq/webcmd/registry';
import { ArgumentError, CommandExecutionError, EmptyResultError } from '@agentrhq/webcmd/errors';
import { arxivSearch } from './sources.js';

function requireQuery(value) {
const s = String(value ?? '').trim();
if (!s) throw new ArgumentError('a search query is required');
return s;
}

cli({
site: 'omnisearch',
name: 'arxiv',
tags: ['search'],
access: 'read',
description: "Search arXiv research papers (no login)",
domain: 'export.arxiv.org',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'query', required: true, positional: true, help: 'Research topic' },
{ name: 'limit', type: 'int', default: 20, help: 'Number of results' },
],
columns: ['platform', 'title', 'author', 'score', 'commentCount', 'createdAt', 'url', 'text'],
func: async (kwargs) => {
const query = requireQuery(kwargs.query);
const raw = Number(kwargs.limit ?? 20);
if (!Number.isInteger(raw) || raw <= 0) throw new ArgumentError('limit must be a positive integer');
const limit = Math.min(raw, 50);
let rows;
try {
rows = await arxivSearch(query, limit);
} catch (err) {
throw new CommandExecutionError(err instanceof Error ? err.message : String(err));
}
if (!rows.length) throw new EmptyResultError('omnisearch/arxiv', `no results for "${query}"`);
return rows;
},
});
89 changes: 89 additions & 0 deletions plugins/omnisearch/bluesky-posts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* omnisearch bluesky-posts — read what a public Bluesky account is saying.
*
* No login. Uses the public Bluesky API (public.api.bsky.app) author feed
* endpoint, which returns a user's recent posts without authentication.
* This is the closest no-login analog to reading someone's public X/Twitter
* timeline.
*/
import { cli, Strategy } from '@agentrhq/webcmd/registry';
import {
ArgumentError,
CommandExecutionError,
EmptyResultError,
} from '@agentrhq/webcmd/errors';

const API = 'https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed';
const HANDLE = /^[a-zA-Z0-9][a-zA-Z0-9.-]*\.[a-zA-Z]{2,}$/;

function requireHandle(value) {
const s = String(value ?? '').trim().toLowerCase();
if (!s || !HANDLE.test(s)) {
throw new ArgumentError('bluesky handle is required, e.g. "bsky.app" or "user.bsky.social"');
}
return s;
}

cli({
site: 'omnisearch',
name: 'bluesky-posts',
access: 'read',
description: "Recent posts from a public Bluesky account (no login)",
domain: 'public.api.bsky.app',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'handle', required: true, positional: true, help: 'Bluesky handle (e.g. bsky.app)' },
{ name: 'limit', type: 'int', default: 20, help: 'Number of posts' },
],
columns: ['rank', 'uri', 'createdAt', 'text', 'likeCount', 'replyCount', 'repostCount', 'url'],
func: async (kwargs) => {
const handle = requireHandle(kwargs.handle);
const raw = Number(kwargs.limit ?? 20);
if (!Number.isInteger(raw) || raw <= 0) {
throw new ArgumentError('limit must be a positive integer');
}
const limit = Math.min(raw, 100);

const url = new URL(API);
url.searchParams.set('actor', handle);
url.searchParams.set('limit', String(limit));

let json;
try {
const res = await fetch(url, {
headers: { 'User-Agent': 'Mozilla/5.0 (compatible; webcmd-omnisearch/0.1)' },
});
if (!res.ok) {
throw new CommandExecutionError(`Bluesky API request failed: HTTP ${res.status}`);
}
json = await res.json();
} catch (err) {
if (err instanceof CommandExecutionError) throw err;
throw new CommandExecutionError(`Bluesky API request failed: ${err instanceof Error ? err.message : String(err)}`);
}

const feed = Array.isArray(json?.feed) ? json.feed : [];
if (!feed.length) {
throw new EmptyResultError('omnisearch/bluesky-posts', `no posts found for "${handle}"`);
}

return feed.slice(0, limit).map((entry, index) => {
const post = entry?.post ?? {};
const author = post.author ?? {};
const record = post.record ?? {};
const uri = String(post.uri ?? '');
const rkey = uri.split('/').pop() ?? '';
return {
rank: index + 1,
uri,
createdAt: String(record.createdAt ?? post.indexedAt ?? ''),
text: String(record.text ?? '').replace(/\s*\n+/g, ' ').trim(),
likeCount: post.likeCount ?? 0,
replyCount: post.replyCount ?? 0,
repostCount: post.repostCount ?? 0,
url: `https://bsky.app/profile/${author.handle ?? handle}/post/${rkey}`,
};
});
},
});
43 changes: 43 additions & 0 deletions plugins/omnisearch/github.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* OmniSearch github — search GitHub issues & PRs (people reporting real problems).
* No login. Uses the public GitHub search API (rate-limited to ~10/min).
*/
import { cli, Strategy } from '@agentrhq/webcmd/registry';
import { ArgumentError, CommandExecutionError, EmptyResultError } from '@agentrhq/webcmd/errors';
import { githubSearch } from './sources.js';

function requireQuery(value) {
const s = String(value ?? '').trim();
if (!s) throw new ArgumentError('a search query is required');
return s;
}

cli({
site: 'omnisearch',
name: 'github',
tags: ['search'],
access: 'read',
description: "Search GitHub issues & PRs for real problems (no login)",
domain: 'api.github.com',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'query', required: true, positional: true, help: 'Problem or feature to research' },
{ name: 'limit', type: 'int', default: 20, help: 'Number of results' },
],
columns: ['platform', 'title', 'author', 'score', 'commentCount', 'createdAt', 'url', 'text'],
func: async (kwargs) => {
const query = requireQuery(kwargs.query);
const raw = Number(kwargs.limit ?? 20);
if (!Number.isInteger(raw) || raw <= 0) throw new ArgumentError('limit must be a positive integer');
const limit = Math.min(raw, 50);
let rows;
try {
rows = await githubSearch(query, limit);
} catch (err) {
throw new CommandExecutionError(err instanceof Error ? err.message : String(err));
}
if (!rows.length) throw new EmptyResultError('omnisearch/github', `no results for "${query}"`);
return rows;
},
});
Loading