Thanks for your interest in contributing! Here's how to get started.
git clone https://github.com/bvolpato/copy-as-markdown.git
cd copy-as-markdown
pnpm install
pnpm build- Create the extractor file at
src/extractors/my-site.ts - Register it using
register():
import { register } from '../core/registry';
import * as Markdown from '../core/markdown';
import * as Utils from '../core/utils';
register({
name: 'My Site',
matches: [
'*://www.mysite.com/*',
],
// Default behavior: floating button in the bottom-right corner.
// Only add buttonPlacement: 'anchor' when an inline position is
// explicitly reviewed and ready to be enabled.
anchor: {
selector: 'header nav', // where to put the button
position: 'append', // 'append' | 'prepend' | 'before' | 'after' | 'overlay'
style: 'pill', // 'tab' | 'pill' | 'icon' | 'link'
},
async extract() {
const title = document.querySelector('h1')?.textContent?.trim() || '';
const url = Utils.getCanonicalUrl();
const metadata = { source: 'My Site', title, url };
const content = document.querySelector('article') || document.querySelector('main');
if (!content) return Markdown.buildPageMarkdown(metadata, '*No content found.*');
const cleaned = Utils.removeNoise(content, Utils.NOISE_SELECTORS);
const body = Markdown.elementToMarkdown(cleaned);
return Markdown.buildPageMarkdown(metadata, `# ${title}\n\n${body}`);
},
});- Import in main.ts: Add
import './extractors/my-site';tosrc/main.ts - Build and test:
pnpm typecheck && pnpm test:regression && pnpm package:all && pnpm verify:release && pnpm pack:library - Load the userscript or extension and verify on the target site
pnpm test:live runs optional Wayback-based diagnostics. It is not a release gate because archive availability is external and intermittent.
By default, the button should stay floating in the bottom-right corner. If you want to activate an inline placement, set:
buttonPlacement: 'anchor'Without that flag, any anchor config is treated as a dormant hook for later.
| Style | When to use | Example |
|---|---|---|
tab |
Site has a text-based nav bar | Wikipedia |
pill |
General purpose, compact gradient button | YouTube, Google Search |
icon |
Space-constrained action bars with icon buttons | X/Twitter, WhatsApp |
link |
Text-heavy action bars (uppercase links) |
If unsure, use pill — it's the most versatile and always looks good.
- Separate signal from noise. Strip ads, nav, sidebars, cookie banners.
- Preserve structure. Use the
Markdownhelpers for tables, lists, code blocks. - Include metadata. Source name, title, URL, author, date — as YAML frontmatter.
- Handle SPAs. Use
Utils.waitForElement()if content loads dynamically. - Test with real pages. Don't just guess at selectors — verify them.
- TypeScript with strict mode
- No runtime dependencies
- Use proper imports, not globals
- Keep extractors focused — one file per site
- Fork the repository
- Create a feature branch:
git checkout -b add-github-extractor - Make your changes and test them
- Run
pnpm typecheck && pnpm test:regression && pnpm package:all && pnpm verify:release && pnpm pack:library - Open a PR with a clear description of what site you're adding and what content is extracted
GitHub Actions builds and publishes browser releases. Do not create releases or upload assets manually.
-
Update
package.jsonto the nextMAJOR.MINOR.PATCHversion. -
Merge the version and release changes into
main. -
Create and push a signed tag matching that version:
version="$(node -p "require('./package.json').version")" git tag -s "v$version" -m "v$version" git push origin "v$version"
The release workflow accepts only signed strict semantic-version tags from an allowed signer. Tag version must match package.json, and tagged commit must be reachable from main. Workflow runs typechecking, browser regression tests, packaging, and manifest/archive verification before its isolated publish job receives write permission.
Scoped npm package uses same version. Run pnpm pack:library before release. Publishing @bvolpato/copy-as-markdown requires npm scope access and pnpm publish --access public. Configure npm trusted publishing before automating later publications.
- Include the URL where the button doesn't appear or doesn't work
- Note which format you're using (userscript, Chrome, Firefox)
- If the Markdown output is wrong, share a sample of what you got vs. what you expected