Working with Perplexity API on POSIX shell. Four modes: raw results, answer with citations, long research in the background, page extraction.
Before running
The installed plugin directory is usually read-only, while the scripts write to cache/.
Create a working copy and work from it:
sh scripts/prepare_runtime.sh
cd /home/claude/perplexity-search
prepare_runtime.sh copies the skill and normalizes config/.env (quotes
values containing spaces). Do not output the contents of .env in the response — on configuration errors,
name only the variable names.
Config
You need PERPLEXITY_API_KEY в config/.env:
cp config/.env.example config/.env
The key is at perplexity.ai/account/api. All other variables are optional. Details: config/README.md.
Philosophy
- The cache is limited by age, not just by key — the key (request body)
decides which entry is suitable; the TTL decides whether it can still be served.
Default is 900 s, for
research.sh— one day. Nothing older is reused. The age is always printed in the header (cache, 12m old), so that a stale answer is visible.--no-cache— a live request,--cache-ttl— its own boundary. - Context window hygiene — stdout is limited to
PPLX_PRINT_LIMIT(30 lines). Full snippets, answers, and raw JSON are stored incache/and read viacache_grep.shor Read at the required offset. - The right tool for the task — first the cheap
search.sh($5/1000 requests), synthesis by the model only when it is really needed. - Verifiable answers — every answer
ask.sh/research.shin the report has a list of sources with dates and snippets.
Choosing a script
| Need | Script | Price |
|---|---|---|
| links and citations from pages, then I'll think for myself | search.sh |
$5 / 1000 requests |
| a ready answer with sources | ask.sh |
model tokens + $0.0025 per search |
| multi-step research, report on pages | research.sh |
minutes and noticeable money |
| the contents of specific URLs | fetch_url.sh |
tokens + $0.00025 per URL |
| "have I already searched this?" | find_latest.sh, cache_grep.sh |
free |
By default use search.sh. research.sh run only when the user
explicitly asks for deep research.
Workflow
Raw output
# один запрос
sh scripts/search.sh --query "изменения в NDS 2026" --max-results 10
# до 5 углов темы в одном оплаченном запросе
sh scripts/search.sh \
--query "AI regulation EU 2026" \
--query "AI Act enforcement timeline" \
--query "AI Act penalties companies"
# только свежее и только из нужных доменов
sh scripts/search.sh --query "postgres 19 release" --recency week \
--domains "postgresql.org,news.ycombinator.com"
# без форумов
sh scripts/search.sh --query "лучший ноутбук для разработки" --domains "-reddit.com,-quora.com"
stdout — table n / date / domain / title / url. The snippets are stored in full in
cache/search/<key>.txt; read them with grep, not in full.
Answer with citations
sh scripts/ask.sh --query "что изменилось в Claude Code за последний месяц"
# дешевле и быстрее
sh scripts/ask.sh --query "курс ЦБ на сегодня" --preset fast
# ответ строго по схеме
sh scripts/ask.sh --query "топ-5 CRM для малого бизнеса" --schema schema.json
Full report (answer + sources + snippets) — in cache/ask/<key>.md.
Deep research
# фоновый запуск с ожиданием
sh scripts/research.sh --query "рынок EV-зарядок в РФ: игроки, объёмы, барьеры" \
--preset high --timeout 1800
# отправить и не ждать
sh scripts/research.sh --query "..." --no-wait
sh scripts/research.sh --resume resp_abc123
The run continues on Perplexity's side even if the script has stopped waiting —
--resume picks it up by id.
A repeated identical request does not start a second run: the script finds the id of the one already
sent (cache/research/<key>.id), checks its status and picks it up,
if it is still running or already done. A new run starts only if
the previous one failed or you explicitly asked for --no-cache.
Reading pages
sh scripts/fetch_url.sh --url "https://example.com/pricing"
sh scripts/fetch_url.sh --url "https://a.com/post" --url "https://b.com/post" \
--query "сравни выводы двух статей"
Working with the cache
# что я уже спрашивал
sh scripts/find_latest.sh --script ask --match "claude"
# поиск по накопленным результатам вместо нового запроса
sh scripts/cache_grep.sh "rate limit" --type search --context 2
sh scripts/cache_grep.sh "GDPR" --files
Scripts
sh scripts/<script>.sh [params] # у каждого есть --help
| Script | Endpoint | Description |
|---|---|---|
search.sh |
POST /search |
ranked output with snippets |
ask.sh |
POST /v1/agent |
synthesized answer with sources |
research.sh |
POST /v1/agent + polling |
long research in the background, --resume |
fetch_url.sh |
POST /v1/agent |
contents of specific URLs (fetch_url) |
find_latest.sh |
— | past runs from cache/index.tsv |
cache_grep.sh |
— | grep over accumulated results |
prepare_runtime.sh |
— | working copy of the skill in the writable directory |
Common parameters
| Param | Where | Default | Values |
|---|---|---|---|
--query, -q |
all | — | query; in search.sh repeated up to 5 times |
--recency |
search | — | hour, day, week, month, year |
--after / --before |
search | — | YYYY-MM-DD or MM/DD/YYYY |
--updated-after / --updated-before |
search | — | by page update date |
--domains |
search | — | allowlist a.com,b.com or denylist -a.com |
--country |
search | — | ISO 3166-1 alpha-2 |
--language |
search | — | ISO 639-1 |
--context-size |
search | medium |
low, medium, high |
--max-results |
search | 10 |
Search: 1–20, Agent: 1–50 |
--profile |
search | — | set of defaults from .env |
--preset |
agent | see below | fast, low, medium, high, xhigh, wide-research |
--model |
agent | from .env |
perplexity/sonar, openai/gpt-5.6-sol, anthropic/claude-sonnet-5, … |
--tools |
agent | web_search |
web_search, fetch_url, finance_search, people_search, sandbox |
--instructions |
agent | — | system instruction |
--schema |
agent | — | JSON Schema file → structured response |
--limit |
all | 30 |
lines in stdout |
--cache-ttl, --no-cache |
all | 900 |
cache management |
Mutually exclusive combinations (--recency together with explicit dates, mixed
allow/deny domains) are rejected before going to the API — no money is spent.
Who executes the request
Priority: flag > .env > the script's own default.
- set
--presetor--model— it is taken; - otherwise, if
config/.envspecifiesPPLX_PRESET/PPLX_MODEL, — they are taken; - otherwise the script default applies:
ask.sh→medium,research.sh→high,fetch_url.sh→low.
A script with its own default never overrides what you specified in .env, —
otherwise research.sh would silently count money using a different model.
Cache
cache/
├── index.tsv # created_at, script, key, query, path — для grep
├── search/<key>.json # сырой ответ
├── search/<key>.tsv # таблица результатов
├── search/<key>.txt # сниппеты целиком
├── ask/<key>.{json,md} # ответ + источники
├── research/<key>.{json,md,id}
└── fetch/<key>.{json,md}
Never read .json in full — it contains the entire API response. Work through
cache_grep.sh, and for specific parts use Read on file:line from its output.
Freshness
The cache exists so you don't pay twice for the same question within a session, not to preserve the answer forever. Therefore:
- only an entry younger than the TTL is reused; the header always shows the age
(
=== Perplexity Search (cache, 12m old): ... ===); --recency— this is a signal of "a question about something fresh", and it shortens the reuse window:hour→ maximum 5 minutes,day→ maximum one hour,week→ maximum one day. An explicit--cache-ttlis stronger — it is not trimmed;- if the facts could have changed (release, exchange rate, news, prices) —
--no-cache; research.shkeeps reports for a day, because each run costs minutes and dollars. For a fast-changing topic, set--no-cacheor--recency.
Artifacts in cache/ live forever — only the right to serve them instead of
a new request expires. Past runs are always available via find_latest.sh и
cache_grep.sh.
Limits
- Search API: maximum 5 queries in the array, 20 results, 20 domains in the filter, 50 query units/s. A multi-query is billed as one request, but it consumes the limit at one unit per line.
search_domain_filter— allowlist or denylist, you cannot mix them.--recencyand explicit dates do not work at the same time.- Models
anthropic/*requiremax_output_tokens— the scripts substitute 8192. - 429 is not billed; the scripts respect
Retry-Afterand make up toPPLX_MAX_RETRIESattempts. - Sonar Chat Completions (
/chat/completions) is considered legacy — the skill uses the Agent API (/v1/agent).
API details, response schemas and recipes: references/API_REFERENCE.md.
Tests
sh scripts/tests/run.sh
Offline, without network and key: parsing .env, building request bodies, rendering responses from fixtures, CLI contract. The HTTP layer test spins up a mock on loopback and skips itself where the sandbox does not allow opening a socket.