| name | ax |
| description | AI-era curl for agent web fetching, structure discovery, and deterministic structured extraction with token-budgeted output. |
ax — The AI-Era Curl for Web Scraping & Extraction
Version 1.0.0
Yusuke Bebé & Contributors
AI-driven fetch, discover, extract framework
Summary
ax is a command-line tool purpose-built for AI agents to fetch web pages, discover their structure, and extract structured data — replacing the classic curl → parse → regex loop with one deterministic, token-efficient command.
When to Use ax
- You need an agent to fetch a page and extract structured data
- You want page discovery (
--outline) without dumping raw HTML
- You're extracting multi-field rows with CSS selectors (
--row, --table)
- You need token-shaped output (capped, with budget control)
- You're building a repeatable web-scraping agent task
- You're tired of
curl | grep | awk pipeline in agent code
When NOT to Use ax
- The target site requires client-side JavaScript rendering (use
Playwright or Puppeteer instead)
- You need real-time browser automation or multi-step interactions
- The content is behind authentication not solvable with headers (use direct API instead)
- You need headless browser for visual testing
Quick Start
Install ax
curl -fsSL https://ax.yusuke.run/install | sh
brew install yusukebe/tap/ax
npm install -g ax-cli
Basic Usage
ax https://api.example.com/users
ax https://example.com --outline
ax https://example.com '.item' --row 'title=a, href=a@href'
ax https://docs.example.com --md --budget 800
ax https://example.com 'table' --table --json
Integrate into Agent Workflow
ax agent-context
ITEMS=$(ax https://shop.example.com '.product' \
--row 'name=h2, price=.price' \
--where 'price < 100' \
--json)
Core Concepts
1. Fetch Mode — Live Data with Full Context
Command: ax <url>
Returns JSON-structured response: { status, ok, ms, headers, body }. Never silent.
- Every request is live (no cache by default)
- Empty bodies still produce full report
- JSON responses are automatically parsed
- Use
--body for classic curl-like stdout pipe
- 100ms+ latency typical; use
--no-check to skip SSL verification (development only)
ax https://api.github.com/repos/yusukebe/ax
2. Parse Mode — Cached HTML Discovery
Flags: --outline, --locate, --md
When you fetch a URL, the HTML is cached locally (~2 minutes) for fast subsequent probes.
--outline: Shows repeating DOM structures (no raw markup in output)
--locate 'text': Finds the CSS selector holding a given text
--md: Renders HTML as readable markdown
- Each cache hit is announced on stderr
--fresh forces refetch; --no-cache disables disk cache entirely
ax https://news.example.com --outline
3. Extract Mode — Structured Data Rows
Flags: --row, --table, --where
Pulls multi-field rows in a single command; filters with safe expression language.
ax https://shop.example.com '.item' \
--row 'name=h2, price=.price, rating=.stars' \
--where 'price > 50'
ax https://data.example.com --table --json
--row 'field1=selector, field2=selector@attr': Define fields and CSS selectors
@attr: Extract attribute (e.g., a@href); default is .textContent
--where 'expr': Filter rows; safe expression language (no code execution)
--json: JSON output instead of TSV
--limit 50: Cap result rows (default 50)
4. Token Budgeting — AI Context Optimization
Flag: --budget <tokens>
Results are shaped for LLM context windows:
- Output capped at ~50 rows by default (announced on stderr)
--budget 800 limits output to ~800 estimated tokens
- Results always include row count / truncation note
- TSV format is token-efficient; JSON is more flexible for structured parsing
ax https://catalog.example.com '.product' \
--row 'name=h2, price=.price' \
--budget 500
Usage Patterns for Agents
Pattern 1: Page Discovery (Zero Code, All Questions)
Agent doesn't know the page structure → use --outline to let agent ask:
ax https://docs.example.com --outline
Pattern 2: Batch Row Extraction
Agent needs tabular data from a repeating structure:
ax https://items.example.com '.item' \
--row 'title=h2, url=a@href, price=.price' \
--json
Pattern 3: Markdown Documentation Extraction
Agent needs human-readable docs:
ax https://guide.example.com/intro --md --budget 2000
Pattern 4: Live API Monitoring
Agent checks JSON API endpoint repeatedly:
ax https://api.status.example.com/incident-count
Pattern 5: Filter & Transform
Agent extracts rows, filters, and passes to downstream:
ax https://store.example.com '.sale-item' \
--row 'name=h2, old_price=.old-price, discount=.discount' \
--where 'discount > 30' \
--json | jq '.[] | {name, savings: (.old_price * .discount / 100)}'
Integration with Agent Skills
With deep-agents-core
Use ax in custom agent tool:
from deep_agents import tool
@tool("scrape_page")
async def scrape_page(url: str, selector: str = None, extract_mode: str = "outline"):
"""Fetch and parse web pages with ax."""
cmd = f"ax {url}"
if extract_mode == "outline":
cmd += " --outline"
elif extract_mode == "rows" and selector:
cmd += f" '{selector}' --row 'content=*' --json"
result = await run_shell(cmd)
return result
With react-grab
Use ax to extract HTML structure before targeting React elements:
ax https://app.example.com --outline
react-grab --selector '.user-card'
With research (parallel discovery)
Run ax on multiple URLs concurrently:
for url in $(cat urls.txt); do
ax "$url" --outline --budget 300 &
done | wait
Common Tasks
Task: Extract all links from a page
ax https://example.com --row 'text=a, href=a@href' --json
Task: Find a specific section
ax https://docs.example.com --locate 'Installation' --md
Task: Monitor API endpoint
ax https://api.example.com/status | jq '.body | select(.status == "ok")'
Task: Extract table and convert to CSV
ax https://data.example.com 'table.report' --table --json | \
jq -r '.[] | [.col1, .col2, .col3] | @csv'
Task: Agent-driven discovery flow
ax https://site.example.com --outline
ax https://site.example.com '.observed-selector' --row 'field=selector' --json
Best Practices
1. Always Start with --outline
Before writing selectors, use --outline to understand the page structure. It costs tokens but saves countless parse iterations.
ax https://example.com --outline
ax https://example.com '.item' --row 'name=h2'
ax https://example.com 'div.product-card' --row 'price=.cost'
2. Use --where for Client-Side Filtering
Don't extract all rows and filter in agent code — filter at the source:
ax https://shop.example.com '.item' \
--row 'name=h2, price=.price' \
--where 'price > 50 && price < 200'
ax https://shop.example.com '.item' --row 'name=h2, price=.price' --json
3. Respect Rate Limits & Robots.txt
- Check
robots.txt before automating scrapes
- Use reasonable delays between requests (
--delay <ms> if available)
- Identify your agent in User-Agent headers when possible
- Start with
--no-cache sparingly; use cache hits to reduce load
4. Token Budget for Large Datasets
Always cap results when the dataset is unknown:
ax https://catalog.example.com '.item' --budget 500
ax https://catalog.example.com '.item' --json
5. Handle Empty/Error Responses
ax never fails silently — always outputs response metadata:
ax https://down.example.com
Agent should check ok flag and status before parsing body.
Performance & Benchmarks
Cost Savings (Real Opus 4.8 Sessions)
| Task | Without ax | With ax | Savings |
|---|
| Two-page markup drift | $0.458 | $0.150 | −67% |
| 60-item catalog extraction | $0.296 (24s) | $0.104 (14s) | −65% |
| Live website with decoys | $0.248 | $0.191 | −23% |
| Markup drift (first use) | $0.664 | $0.282 | −58% |
See bench/RESULTS.md in ax repo for full methodology.
Why Faster & Cheaper?
- Token efficiency: Structured output + budget capping = fewer tokens per request
- No raw HTML:
--outline costs far fewer tokens than dumping full markup
- Fewer retries: Deterministic extraction means no "that didn't work, try again"
- Native CLI: No agent writing & debugging shell scripts mid-task
Troubleshooting
Issue: "Empty body" or "selector found 0 matches"
Cause: Selector doesn't match the page structure, or content is client-rendered.
Fix:
- Run
ax <url> --outline to verify structure
- Use
ax <url> --locate 'visible text' to find the right selector
- If empty after outline, content may be JS-rendered → try
Playwright instead
Issue: Rate limited or blocked
Cause: Too many requests or missing User-Agent.
Fix:
- Enable cache:
ax <url> (default is cached in fetch mode)
- Use
--delay <ms> between requests in scripts
- Check
robots.txt and respect crawl-delay
- Add User-Agent header:
ax <url> -H 'User-Agent: MyAgent/1.0'
Issue: "Truncated to N of M rows"
Cause: Results exceeded token budget.
Fix:
- Increase
--budget if critical data is being cut
- Or narrow
--where filter to return fewer rows
- Or split into multiple smaller queries
Routing to Other Skills
| Need | Skill | Why |
|---|
| Complex page interactions, multi-step flows | deep-agents-core with Playwright | Browser automation needed |
| React component inspection after extraction | react-grab | Combines ax discovery with element capture |
| Parallel scraping of many sites | research (multi-agent) | Orchestrate concurrent ax calls |
| Token budget optimization | react-best-practices | Structure output to fit LLM context |
| Accessibility validation of extracted markup | accessible-markup | Validate scraped content against WCAG |
Comparison: ax vs Alternatives
| Feature | curl | htmlq | Firecrawl | ax |
|---|
| Fetch URL | ✓ | ✗ | ✓ | ✓ |
Discover structure (--outline) | ✗ | ✗ | △ | ✓ |
| Multi-field extraction | ✗ | △ (N runs) | ✓ | ✓ |
Markdown extraction (--md) | ✗ | ✗ | ✓ | ✓ |
| Token-budget output | ✗ | ✗ | ✗ | ✓ |
| Zero code per task | ✗ | △ (pipe pain) | ✓ | ✓ |
| Cached parse (free probes) | ✗ | ✗ | ✗ | ✓ |
Safe filtering (--where) | ✗ | ✗ | △ | ✓ |
References
Routing Brief (for agent responses)
Use this when invoking ax from an agent task:
ax (fetch, discover, extract) → when an agent needs web data without headless browser. Use ax <url> --outline for free structure discovery, then ax <url> 'selector' --row for extraction. Token budget & safe filtering built-in. Route to Playwright if interaction needed; route to research skill for parallel multi-URL orchestration.
License
ax is open-source (check repo for license). Available under multiple install paths (shell script, Homebrew, npm).
Last updated: July 2026 — reflects ax v1.1+ features