# duckduckgo-search-cli

- Rust CLI for DuckDuckGo search — returns results as JSON, Markdown, or plain text
- Install with: `cargo install duckduckgo-search-cli`
- Current version: v0.6.5
- Repository: https://github.com/daniloaguiarbr/duckduckgo-search-cli


## What's new in v0.6.5

- **CRITICAL FIX (MP-26)**: Windows build compiles again. `windows-sys 0.59+` changed `HANDLE` from `isize` to `*mut c_void`. Replaced `handle != 0 && handle != usize::MAX` with `!handle.is_null() && handle != INVALID_HANDLE_VALUE`.
- **CI fix (CI-01)**: 6 latent clippy errors in v0.6.4 broke the `validate` job on all 3 SOs. Fixed: `doc_markdown` on 3 strings (`PowerShell`, `rules_rust.md`, `TempDir`), `needless_return`, `missing_debug_implementations` on `ChromeBrowser` and `CircuitBreakerMap`.
- **Preventive FFI lints**: `improper_ctypes = "deny"` and `improper_ctypes_definitions = "deny"` in `Cargo.toml`.
- **WS-11**: 5 property tests (invariants) in `extraction.rs` — no new dependency.
- **WS-12**: Per-host circuit breaker in `content_fetch.rs` — 3 consecutive failures open the circuit for 30s.
- **WS-23**: WireMock test validates the `Retry-After` header on 429 responses.
- **WS-25**: `indicatif = "0.18"` added for the ProgressBar in long crawls.
- **333 tests passing**, 8 validation gates OK (fmt, clippy, test, doc, audit, deny, publish dry-run, package list).


## What's new in v0.6.4

- Adaptive anti-bot identity pool (12 identities, 4 browser families × 3 platforms)
- 5-level cascade rotation when DDG blocks (HTTP 202/403/429)
- New JSON fields: `metadados.identidade_usada` and `metadados.nivel_cascata` (additive, non-breaking)
- New CLI flags: `--probe` (pre-flight health check) and `--identity-profile` (pin profile)
- `--seed` flag now also controls identity pool rotation (previously UA only)


## Canonical Documentation

- `README.md` — overview, flags, exit codes, bilingual examples
- `docs/HOW_TO_USE.md` — pedagogical step-by-step guide
- `docs/COOKBOOK.md` — 17 ready-to-use recipes for search, ETL, and monitoring
- `docs/INTEGRATIONS.md` — integrations with 16+ AI agents (Claude, GPT, Gemini, Cursor…)
- `docs/AGENTS-GUIDE.md` — stdin/stdout contract and full JSON schema reference
- `docs/CROSS_PLATFORM.md` — setup on Linux, macOS, Windows, and Docker
- `docs/AGENTS.md` — quick integration guide for AI agents
- `docs/AGENT_RULES.md` — 30+ MUST/NEVER rules for production use by agents
- `docs/MIGRATION.md` — migration guide between versions
- `docs/TESTING.md` — test execution and categorization
- `skill/duckduckgo-search-cli-en/SKILL.md` — Claude/OpenCode skill for agents
- `skill/duckduckgo-search-cli-pt/SKILL.md` — Portuguese skill for agents
- `CHANGELOG.md` — version history (EN)
- `CHANGELOG.pt-BR.md` — version history (PT)
- `INTEGRATIONS.md` — pointer to full integration catalog
- `CONTRIBUTING.md` — contributor onboarding
- `CODE_OF_CONDUCT.md` — community standards
- `SECURITY.md` — vulnerability disclosure policy


## Quick Start

### Basic search (plain text on TTY)

```bash
timeout 30 duckduckgo-search-cli "rust async runtime"
```

### Machine-readable JSON (piped)

```bash
timeout 30 duckduckgo-search-cli -q -f json --num 10 "rust async runtime" \
  | jaq -r '.resultados[].url'
```

### Pre-flight health check (v0.6.4+, preserved in v0.6.5)

```bash
timeout 15 duckduckgo-search-cli --probe
# {"endpoint":"html","has_set_cookie":false,"latency_ms":109,"status":200,"type":"probe","url":"https://html.duckduckgo.com/html/"}
```

### Batch mode (multi-query)

```bash
printf 'query one\nquery two\nquery three\n' > /tmp/q.txt
timeout 300 duckduckgo-search-cli \
  --queries-file /tmp/q.txt \
  -q -f json --parallel 3 --per-host-limit 1 --retries 3 \
  --global-timeout 280 > /tmp/multi.json
```

### Content extraction (long crawls, WS-25 ProgressBar)

```bash
timeout 120 duckduckgo-search-cli -q -f json --num 5 \
  --fetch-content --max-content-length 5000 \
  "rust embedded systems" | jaq '.resultados[].url'
```


## Canonical Invocations

```bash
# Single query
duckduckgo-search-cli -q -f json "query" | jaq '.resultados | length'

# Multi-query (use --queries-file, NEVER shell loops)
duckduckgo-search-cli -q -f json "one" "two" | jaq '.buscas[0].resultados | length'

# Filter by URL
duckduckgo-search-cli -q -f json "rust" | jaq -r '.resultados[].url'

# Detect identity used (v0.6.4+)
duckduckgo-search-cli -q -f json "rust" | jaq -r '.metadados.identidade_usada // "n/a"'

# Detect cascade level (v0.6.4+)
duckduckgo-search-cli -q -f json "rust" | jaq '.metadados.nivel_cascata // 0'
```


## Exit Codes

| Code | Meaning           | Agent action                              |
|------|-------------------|-------------------------------------------|
| `0`  | Success           | Parse `.resultados`                       |
| `1`  | Runtime error     | Read stderr; retry once with `-v`         |
| `2`  | Config error      | Re-run `init-config --force`              |
| `3`  | Anti-bot block    | Back off 300+ s; switch `--endpoint lite` |
| `4`  | Global timeout    | Raise `--global-timeout`; reduce `--parallel` |
| `5`  | Zero results      | Refine query or change `--lang`           |


## Anti-Patterns to Avoid

- NEVER parse `text` or `markdown` output with machines (use `json` + `jaq`)
- NEVER omit `timeout` (pipelines hang indefinitely)
- NEVER pass proxy credentials in argv (use `HTTPS_PROXY` env var)
- NEVER raise `--parallel` above 5 (triggers anti-bot)
- NEVER use `--stream` (placeholder, not implemented)
- NEVER inject custom `Sec-Fetch-*` or `Accept-Language` headers


## License

Dual-licensed under MIT OR Apache-2.0. See `LICENSE` for details.
