
Brave Search
Let your agent search the web and pull readable page content as markdown for grounding specs, docs, and decisions.
Overview
Brave Search is an agent skill most often used in Idea (also Validate and Build) that retrieves web pages and converts readable content to markdown for agent research.
Install
npx skills add https://github.com/badlogic/pi-skills --skill brave-searchWhat is this skill?
- Fetches remote pages with browser-like headers and timeout handling
- Extracts readable article body via Mozilla Readability before conversion
- Emits clean markdown using Turndown with GFM plugin support
- CLI usage pattern: content script with a single URL argument
- Normalizes noisy HTML (empty links, excess newlines) for agent context windows
- 15 second fetch timeout via AbortSignal.timeout
Adoption & trust: 615 installs on skills.sh; 1.9k GitHub stars; 1/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need trustworthy page text in markdown inside the agent session without brittle copy-paste from noisy websites.
Who is it for?
Agent-first developers who research competitors, docs, and articles programmatically during planning and implementation.
Skip if: Workflows that require authenticated scraping, heavy JavaScript SPAs without a dedicated browser tool, or offline-only environments.
When should I use this skill?
The agent needs to search or open a URL and return readable markdown content for research or doc grounding.
What do I get? / Deliverables
A URL resolves to structured markdown suitable for summarization, comparison, or spec grounding in the same chat thread.
- Markdown extraction of main page content from a given URL
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Discovery and reading external sources is where research skills first sit on the journey, before you commit to build scope. Brave-search style workflows support competitor scans, doc lookups, and article ingestion during early research.
Where it fits
Pull a competitor landing page into markdown to compare positioning bullets.
Ingest a vendor pricing doc to sanity-check feature scope before building.
Load an official API reference chapter as markdown while implementing an integration.
Summarize a long industry article without leaving the agent session.
How it compares
Lightweight fetch-and-markdown integration, not a full managed search API product page or MCP replacement by itself.
Common Questions / FAQ
Who is brave-search for?
Solo builders using pi-skills-compatible agents who need quick web page text as markdown for research and implementation support.
When should I use brave-search?
In Idea when scouting markets and reading articles, in Validate when checking competitor positioning, and in Build when pulling official documentation into context.
Is brave-search safe to install?
It performs outbound HTTP fetches; review the Security Audits panel on this Prism page and avoid fetching sensitive or untrusted URLs on prod credentials.
SKILL.md
READMESKILL.md - Brave Search
node_modules/ #!/usr/bin/env node import { Readability } from "@mozilla/readability"; import { JSDOM } from "jsdom"; import TurndownService from "turndown"; import { gfm } from "turndown-plugin-gfm"; const url = process.argv[2]; if (!url) { console.log("Usage: content.js <url>"); console.log("\nExtracts readable content from a webpage as markdown."); console.log("\nExamples:"); console.log(" content.js https://example.com/article"); console.log(" content.js https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html"); process.exit(1); } function htmlToMarkdown(html) { const turndown = new TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" }); turndown.use(gfm); turndown.addRule("removeEmptyLinks", { filter: (node) => node.nodeName === "A" && !node.textContent?.trim(), replacement: () => "", }); return turndown .turndown(html) .replace(/\[\\?\[\s*\\?\]\]\([^)]*\)/g, "") .replace(/ +/g, " ") .replace(/\s+,/g, ",") .replace(/\s+\./g, ".") .replace(/\n{3,}/g, "\n\n") .trim(); } try { const response = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.9", }, signal: AbortSignal.timeout(15000), }); if (!response.ok) { console.error(`HTTP ${response.status}: ${response.statusText}`); process.exit(1); } const html = await response.text(); const dom = new JSDOM(html, { url }); const reader = new Readability(dom.window.document); const article = reader.parse(); if (article && article.content) { if (article.title) { console.log(`# ${article.title}\n`); } console.log(htmlToMarkdown(article.content)); process.exit(0); } // Fallback: try to extract main content const fallbackDoc = new JSDOM(html, { url }); const body = fallbackDoc.window.document; body.querySelectorAll("script, style, noscript, nav, header, footer, aside").forEach(el => el.remove()); const title = body.querySelector("title")?.textContent?.trim(); const main = body.querySelector("main, article, [role='main'], .content, #content") || body.body; if (title) { console.log(`# ${title}\n`); } const text = main?.innerHTML || ""; if (text.trim().length > 100) { console.log(htmlToMarkdown(text)); } else { console.error("Could not extract readable content from this page."); process.exit(1); } } catch (e) { console.error(`Error: ${e.message}`); process.exit(1); } { "name": "brave-search", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "brave-search", "version": "1.0.0", "license": "MIT", "dependencies": { "@mozilla/readability": "^0.6.0", "jsdom": "^27.0.1", "turndown": "^7.2.2", "turndown-plugin-gfm": "^1.0.2" } }, "node_modules/@asamuzakjp/css-color": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.0.tgz", "integrity": "sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==", "license": "MIT", "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "lru-cache": "^11.2.2" } }, "node_modules/@asamuzakjp/dom-selector": { "version": "6.7.5", "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.5.tgz", "integrity": "sha512-Eks6dY8zau4m4wNRQjRVaKQRTalNcPcBvU1ZQ35w5kKRk1gUeNCkVLsRiATurjASTp3TKM4H10wsI50nx3NZdw==", "license": "MIT", "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.2" } }, "node_modules/@asamuzakjp/nwsapi": { "versio