|
1 | 1 | <div align="center"> |
2 | 2 |
|
3 | | -<img src="s_maw.svg" alt="maw" width="400"> |
| 3 | +<img src="https://raw.githubusercontent.com/memvid/maw/main/s_maw.svg" alt="maw" width="400"> |
4 | 4 |
|
5 | 5 | **Crawl any site. Search it forever.** |
6 | 6 |
|
|
14 | 14 |
|
15 | 15 | --- |
16 | 16 |
|
17 | | -Feed the maw. It never forgets. |
18 | | - |
19 | 17 | ```bash |
20 | 18 | npx @memvid/maw https://stripe.com/docs |
21 | 19 | ``` |
22 | 20 |
|
23 | | -That's it. The entire Stripe docs are now in a 40MB file you can search and ask questions to. Offline. Forever. |
24 | | - |
25 | | -## Why? |
| 21 | +30 seconds later you have the entire Stripe documentation in a single 40MB file. Search it. Ask it questions. Works offline. Works forever. |
26 | 22 |
|
27 | | -Because you shouldn't need to keep 47 browser tabs open or bookmark links you'll never read again. Crawl once, query forever. |
28 | | - |
29 | | -```bash |
30 | | -# later, when you actually need it |
31 | | -maw ask stripe.mv2 "how do webhooks work?" |
32 | | -``` |
| 23 | +No more bookmarking docs you'll forget about. No more 47 browser tabs. No more "I read this somewhere but can't find it." |
33 | 24 |
|
34 | 25 | ## Install |
35 | 26 |
|
36 | 27 | ```bash |
37 | 28 | npm i -g @memvid/maw |
38 | 29 | ``` |
39 | 30 |
|
40 | | -Or just use `npx @memvid/maw` without installing. |
| 31 | +Or just `npx @memvid/maw` if you don't want to install anything. |
41 | 32 |
|
42 | | -## What it does |
| 33 | +## The basics |
43 | 34 |
|
44 | | -``` |
45 | | -maw https://react.dev → react.mv2 (312 pages, 18s) |
46 | | -maw https://docs.python.org → python.mv2 (2,847 pages, 4min) |
47 | | -maw . → repo.mv2 (your local git repo) |
48 | | -maw https://news.ycombinator.com/item?id=12345 → just that page |
| 35 | +```bash |
| 36 | +maw https://react.dev # crawls entire site → maw.mv2 |
| 37 | +maw find maw.mv2 "useEffect" # instant search |
| 38 | +maw ask maw.mv2 "when should I use useCallback vs useMemo?" # AI answers |
49 | 39 | ``` |
50 | 40 |
|
51 | | -Smart defaults: |
52 | | -- **Single page URL?** Fetches just that page |
53 | | -- **Domain root?** Crawls the whole site |
54 | | -- **Local path?** Reads your git repo |
55 | | -- **Protected site?** Auto-switches to stealth browser |
| 41 | +That last one needs `OPENAI_API_KEY` in your env. The first two work out of the box. |
56 | 42 |
|
57 | | -## Commands |
| 43 | +## What can you crawl? |
58 | 44 |
|
59 | | -### Crawl |
| 45 | +Basically anything. |
60 | 46 |
|
61 | 47 | ```bash |
62 | | -maw <url> # → maw.mv2 |
63 | | -maw <url> -o docs.mv2 # custom output |
64 | | -maw <url> docs.mv2 # same thing (appends if exists) |
65 | | -maw <url> --depth 5 --max-pages 500 # go deeper |
| 48 | +maw https://docs.python.org # documentation (2,847 pages, ~4 min) |
| 49 | +maw https://paulgraham.com # blogs |
| 50 | +maw . # your local codebase |
| 51 | +maw https://github.com/user/repo # any git repo |
| 52 | +maw "https://news.ycombinator.com/item?id=12345" # single pages |
66 | 53 | ``` |
67 | 54 |
|
68 | | -### Query |
| 55 | +It figures out the right approach automatically: |
| 56 | +- Single page URL → fetches just that page |
| 57 | +- Domain root → crawls everything it can find |
| 58 | +- Local path → reads your files directly |
| 59 | +- Cloudflare/bot protection → switches to stealth browser |
69 | 60 |
|
| 61 | +## Commands |
| 62 | + |
| 63 | +**Crawl** |
70 | 64 | ```bash |
71 | | -maw find docs.mv2 "authentication" # full-text search |
72 | | -maw ask docs.mv2 "how does X work?" # AI answer (needs OPENAI_API_KEY) |
73 | | -maw list docs.mv2 # see what's inside |
| 65 | +maw <url> # saves to maw.mv2 |
| 66 | +maw <url> -o docs.mv2 # custom output file |
| 67 | +maw <url> docs.mv2 # same (appends if file exists) |
| 68 | +maw <url> --depth 5 --max-pages 500 # go deeper |
74 | 69 | ``` |
75 | 70 |
|
76 | | -### Preview |
77 | | - |
| 71 | +**Search** |
78 | 72 | ```bash |
79 | | -maw preview stripe.com # shows sitemap, estimated page count |
| 73 | +maw find docs.mv2 "authentication" # keyword search |
| 74 | +maw ask docs.mv2 "how do I do X?" # AI-powered answers |
| 75 | +maw list docs.mv2 # see what's in there |
80 | 76 | ``` |
81 | 77 |
|
82 | | -### Export |
| 78 | +**Preview before crawling** |
| 79 | +```bash |
| 80 | +maw preview stripe.com # shows sitemap, page count estimate |
| 81 | +``` |
83 | 82 |
|
| 83 | +**Export** |
84 | 84 | ```bash |
85 | | -maw export docs.mv2 -f markdown -o docs.md |
86 | | -maw export docs.mv2 -f json -o docs.json |
| 85 | +maw export docs.mv2 -f markdown # dump everything to markdown |
| 86 | +maw export docs.mv2 -f json # or json |
87 | 87 | ``` |
88 | 88 |
|
89 | | -## Embeddings |
| 89 | +## Semantic search |
| 90 | + |
| 91 | +By default you get keyword search (BM25). It's fast and works well for most things. |
90 | 92 |
|
91 | 93 | Want semantic search? Add `--embed`: |
92 | 94 |
|
93 | 95 | ```bash |
94 | | -maw https://docs.whatever.com --embed openai |
| 96 | +maw https://kubernetes.io/docs --embed openai |
95 | 97 | ``` |
96 | 98 |
|
97 | | -Uses OpenAI embeddings for semantic search. Costs ~$0.01 per 1000 pages. Without it, you get BM25 keyword search (still good, just different). |
| 99 | +Costs about $0.01 per 1000 pages. Your queries will understand meaning, not just keywords. |
98 | 100 |
|
99 | | -## How it works |
100 | | - |
101 | | -Most sites work with a simple fetch. When that fails (Cloudflare, JS-heavy SPAs), maw falls back to a real browser. When *that* fails (aggressive anti-bot), it uses stealth mode. |
| 101 | +## How it handles protected sites |
102 | 102 |
|
103 | 103 | ``` |
104 | | -fetch (fast) → playwright (slower) → rebrowser (stealth) |
105 | | - ↓ ↓ ↓ |
106 | | - works? blocked? blocked? |
107 | | - ↓ ↓ ↓ |
108 | | - done retry done |
| 104 | +fetch (fast) → playwright (real browser) → rebrowser (stealth) |
109 | 105 | ``` |
110 | 106 |
|
111 | | -90% of sites never need the browser. The 10% that do, just work. |
| 107 | +90% of sites work with a simple fetch. The other 10% get a real browser. If that's blocked too, stealth mode usually gets through. |
| 108 | + |
| 109 | +You don't have to think about this. It just tries each approach until something works. |
112 | 110 |
|
113 | | -## Options |
| 111 | +## All the flags |
114 | 112 |
|
115 | | -| Flag | Description | Default | |
116 | | -|------|-------------|---------| |
| 113 | +| Flag | What it does | Default | |
| 114 | +|------|--------------|---------| |
117 | 115 | | `-o, --output <file>` | Output file | `maw.mv2` | |
118 | | -| `-d, --depth <n>` | Crawl depth | `2` | |
119 | | -| `-m, --max-pages <n>` | Max pages to crawl | `150` | |
| 116 | +| `-d, --depth <n>` | How deep to crawl | `2` | |
| 117 | +| `-m, --max-pages <n>` | Stop after this many pages | `150` | |
120 | 118 | | `-c, --concurrency <n>` | Parallel requests | `10` | |
121 | | -| `-r, --rate-limit <n>` | Requests per second | `10` | |
122 | | -| `--include <regex>` | Only crawl matching URLs | - | |
123 | | -| `--exclude <regex>` | Skip matching URLs | - | |
| 119 | +| `-r, --rate-limit <n>` | Max requests/second | `10` | |
| 120 | +| `--include <regex>` | Only crawl URLs matching this | - | |
| 121 | +| `--exclude <regex>` | Skip URLs matching this | - | |
124 | 122 | | `--browser` | Force browser mode | - | |
125 | 123 | | `--stealth` | Force stealth mode | - | |
126 | | -| `--embed [model]` | Enable embeddings | - | |
| 124 | +| `--embed [model]` | Enable semantic embeddings | - | |
127 | 125 | | `--no-robots` | Ignore robots.txt | - | |
128 | | -| `--no-sitemap` | Skip sitemap discovery | - | |
| 126 | +| `--no-sitemap` | Don't use sitemap.xml | - | |
129 | 127 |
|
130 | 128 | ## Examples |
131 | 129 |
|
132 | 130 | ```bash |
133 | | -# documentation sites |
| 131 | +# grab some docs |
134 | 132 | maw https://react.dev |
135 | 133 | maw https://docs.python.org |
136 | 134 | maw https://stripe.com/docs |
137 | 135 |
|
138 | | -# news/blogs |
| 136 | +# archive a blog |
139 | 137 | maw https://paulgraham.com/articles.html |
140 | | -maw "https://news.ycombinator.com/item?id=40000000" |
141 | 138 |
|
142 | | -# your own repos |
143 | | -maw . -o my-project.mv2 |
144 | | -maw https://github.com/user/repo |
| 139 | +# your own code |
| 140 | +maw . |
| 141 | +maw https://github.com/your/repo |
145 | 142 |
|
146 | | -# combine multiple sources |
| 143 | +# combine sources into one file |
147 | 144 | maw https://react.dev https://nextjs.org -o frontend.mv2 |
148 | 145 |
|
149 | | -# deep crawl with embeddings |
| 146 | +# big crawl with semantic search |
150 | 147 | maw https://kubernetes.io/docs --depth 4 --max-pages 1000 --embed openai |
151 | 148 | ``` |
152 | 149 |
|
153 | 150 | ## Limits |
154 | 151 |
|
155 | | -Files up to **50MB** work without any API key. That's roughly 500-2000 pages depending on content. |
| 152 | +Up to **50MB** works without an API key. That's roughly 500-2000 pages depending on how much text is on each page. |
156 | 153 |
|
157 | | -For bigger crawls, get a key at [memvid.com](https://memvid.com). |
| 154 | +Need more? Get a key at [memvid.com](https://memvid.com). |
158 | 155 |
|
159 | 156 | ## FAQ |
160 | 157 |
|
161 | 158 | **Is this legal?** |
162 | 159 |
|
163 | | -Respects robots.txt by default. Use `--no-robots` at your own discretion. |
| 160 | +Respects robots.txt by default. What you do with `--no-robots` is your business. |
164 | 161 |
|
165 | | -**Why .mv2?** |
| 162 | +**What's an .mv2 file?** |
166 | 163 |
|
167 | | -It's a [memvid](https://memvid.com) file — single-file database with full-text search, embeddings, and temporal queries baked in. Think SQLite but for documents. |
| 164 | +A [memvid](https://memvid.com) file. Single-file database with search built in. Like SQLite but for documents and memory. |
168 | 165 |
|
169 | | -**Can I use it programmatically?** |
| 166 | +**Programmatic usage?** |
170 | 167 |
|
171 | 168 | ```javascript |
172 | | -import { crawl, query } from 'maw' |
| 169 | +import { maw, find, ask } from '@memvid/maw' |
173 | 170 |
|
174 | | -await crawl('https://example.com', { output: 'site.mv2' }) |
175 | | -const results = await query('site.mv2', 'search term') |
| 171 | +await maw(['https://example.com'], { output: 'site.mv2' }) |
| 172 | +const results = await find('site.mv2', 'search term') |
| 173 | +const answer = await ask('site.mv2', 'explain this to me') |
176 | 174 | ``` |
177 | 175 |
|
178 | | -**What about rate limiting?** |
| 176 | +**Will I get rate limited?** |
179 | 177 |
|
180 | | -Default is 10 req/sec with automatic backoff. Most sites won't notice you. If you're hitting APIs, consider `--rate-limit 2`. |
| 178 | +Default is 10 req/sec with backoff. Most sites won't notice. If you're worried, use `--rate-limit 2`. |
181 | 179 |
|
182 | | -**Does it handle JavaScript-rendered content?** |
| 180 | +**JS-rendered content?** |
183 | 181 |
|
184 | | -Yes. If fetch fails, it automatically tries Playwright. For heavily protected sites, use `--stealth`. |
| 182 | +Works. Falls back to a real browser automatically when needed. |
185 | 183 |
|
186 | 184 | --- |
187 | 185 |
|
|
0 commit comments