Skip to content

jamiemills/perplexity-cli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

161 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Perplexity CLI

A command-line interface for querying Perplexity.ai with persistent authentication and encrypted token storage.

PyPI

Features

  • Query Perplexity.ai from the terminal with a single command
  • Persistent authentication with encrypted token storage (PBKDF2-HMAC key derivation)
  • Multiple output formats -- plain text, Markdown, rich terminal, or structured JSON
  • Real-time streaming -- optional incremental output as the response arrives
  • Source references -- web sources extracted and displayed with inline citations
  • Citation stripping -- remove citation markers and references section from output
  • Response style presets -- configure a persistent style prompt applied to all queries
  • Thread library export -- export your entire Perplexity thread history to CSV
  • Date filtering -- filter exported threads by date range
  • Automatic retry -- exponential backoff on transient errors and rate limits
  • Cloudflare bypass -- Chrome TLS fingerprint impersonation via curl_cffi
  • Configurable -- URLs, rate limits, cookie storage, and debug mode all configurable via file or environment variables

Prerequisites

  • Python 3.12 or later
  • Google Chrome (for initial authentication only)

Installation

From PyPI (recommended)

Install from PyPI and run using either pxcli or perplexity-cli (both are equivalent):

# Install with uv
uv pip install pxcli

# Or run directly without installing
uvx pxcli --help

Then query using whichever name you prefer:

pxcli query "Tell me what happened in AI this week"
perplexity-cli query "Tell me what happened in AI this week"

From source

Clone the repository and install in development mode:

git clone https://github.com/jamiemills/perplexity-cli.git
cd perplexity-cli
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"
pytest  # verify setup

Both pxcli and perplexity-cli are available after installation:

pxcli query "Tell me what happened in AI this week"
perplexity-cli query "Tell me what happened in AI this week"

Quick start

1. Try it immediately (no authentication required)

pxcli query "Tell me what happened in AI this week"

The query command works without authentication for simple questions.

2. Authenticate for full features (optional, one-time setup)

pxcli auth

This opens Chrome via the DevTools Protocol, waits for you to log in to Perplexity.ai, extracts your session token, and saves it encrypted locally. See Authentication setup for full instructions.

3. Use authenticated features

After authentication, you can:

# Attach files to queries (requires auth)
pxcli query --attach README.md "What is this project?"

# Export your thread library to CSV
pxcli export-threads

# Check your authentication status
pxcli status

# Configure a response style to apply to all queries
pxcli configure "be concise and technical"

Querying

Basic usage

# Default: rich terminal output, batch mode (waits for complete response)
pxcli query "What is machine learning?"

# Stream the response as it arrives
pxcli query --stream "What is machine learning?"

# Remove citation markers [1], [2] and the references section
pxcli query --strip-references "What is machine learning?"

Output formats

Use --format (or -f) to choose the output format. The default is rich.

# Rich terminal output with colours and formatted tables (default)
pxcli query "What is Python?"

# Plain text with underlined headers (good for scripts and piping)
pxcli query --format plain "What is Python?"

# GitHub-flavoured Markdown
pxcli query --format markdown "What is Python?" > answer.md

# Structured JSON with answer text and references array
pxcli query --format json "What is Python?" > answer.json

JSON format

The JSON output has this structure:

{
  "format_version": "1.0",
  "answer": "Python is a high-level programming language...",
  "references": [
    {
      "index": 1,
      "title": "Python.org",
      "url": "https://www.python.org",
      "snippet": "Python is a programming language..."
    }
  ]
}

Useful with jq:

# Extract just the answer text (use -r so newlines render properly)
pxcli query --format json "What is Python?" | jq -r '.answer'

# Extract reference URLs
pxcli query --format json "What is Python?" | jq -r '.references[].url'

# Count references
pxcli query --format json "What is Python?" | jq '.references | length'

# Strip references from JSON output
pxcli query --format json --strip-references "What is Python?"

Combining flags

Flags can be combined freely:

pxcli query --format plain --strip-references "What is 2+2?"
pxcli query --stream --strip-references "Explain Kubernetes"
pxcli query --format markdown --strip-references "How does DNS work?" > dns.md

Scripting

# Capture output in a variable
ANSWER=$(pxcli query --format plain "What is 2+2?")
echo "The answer is: $ANSWER"

# Parse JSON in Python
python3 << 'EOF'
import json, subprocess
result = subprocess.run(
    ["pxcli", "query", "--format", "json", "What is Python?"],
    capture_output=True, text=True
)
data = json.loads(result.stdout)
print(data["answer"])
for ref in data["references"]:
    print(f"- {ref['title']}: {ref['url']}")
EOF

Response styles

Set a persistent style prompt that is appended to every query. This lets you control the tone and format of responses without repeating instructions.

# Set a style
pxcli configure "be brief and concise"

# View the current style
pxcli view-style

# Clear the style
pxcli clear-style

The style is stored in ~/.config/perplexity-cli/style.json and persists across sessions.

Authentication

Most commands require authentication, but the query command is an exception. Here's what requires authentication and what doesn't:

Commands requiring authentication

  • export-threads -- Export your thread library to CSV
  • status -- Check your authentication status
  • configure, view-style, clear-style -- Configure response styles

Commands that do NOT require authentication

  • query -- Submit queries to Perplexity.ai (works with or without a token, with exceptions below)

If you have authenticated with pxcli auth, your token will be used automatically with query. If you haven't authenticated, query will attempt to run without a token (behaviour depends on whether the Perplexity API permits unauthenticated requests).

Features requiring authentication within query

Even though the query command can run without authentication, some features require a token:

  • File attachments -- The --attach flag or file paths detected in the query text require authentication to upload files to Perplexity
  • Thread export -- The export-threads command requires authentication to access your thread library

For most users, we recommend authenticating to ensure the best experience. For automated scripts or testing, you can use query for simple questions without authentication. Any queries involving file uploads will require authentication.

Authentication setup

The first time you use pxcli, you need to authenticate with Perplexity.ai. This is a one-time process that extracts your session token via Chrome's DevTools Protocol.

Step 1: Install Chrome for Testing

Download a dedicated Chrome instance (keeps testing separate from your main browser):

npx @puppeteer/browsers install chrome@stable

This downloads Chrome to ~/.local/bin/chrome/.

Step 2: Create a shell alias

Add this to your shell configuration (~/.bashrc, ~/.zshrc, etc.):

alias chromefortesting='open ~/.local/bin/chrome/mac_arm-*/chrome-mac-arm64/Google\ Chrome\ for\ Testing.app --args "--remote-debugging-port=9222" "about:blank"'

The mac_arm-* pattern matches the version directory. Adjust the path for your platform.

Step 3: Authenticate

# Terminal 1: Start Chrome with debugging enabled
chromefortesting

# Terminal 2: Run authentication
pxcli auth

The process will:

  1. Connect to Chrome via the remote debugging port
  2. Navigate to Perplexity.ai
  3. Wait for you to log in
  4. Extract your session token
  5. Save it encrypted to ~/.config/perplexity-cli/token.json

Once complete, you do not need to authenticate again unless you run pxcli logout or the token expires.

Custom port

If port 9222 is in use:

pxcli auth --port 9223

Start Chrome with the matching port in your alias.

Thread export

Export your entire Perplexity thread history to CSV.

# Export all threads
pxcli export-threads

# Filter by date range
pxcli export-threads --from-date 2025-01-01
pxcli export-threads --from-date 2025-01-01 --to-date 2025-12-31

# Custom output file
pxcli export-threads --output my-threads.csv

# Bypass local cache
pxcli export-threads --force-refresh

# Clear cache before export
pxcli export-threads --clear-cache

Output format

created_at,title,url
2025-12-23T23:06:00.525132Z,What is Python?,https://www.perplexity.ai/search/...
2025-12-22T20:54:36.349239Z,Explain AI,https://www.perplexity.ai/search/...

Fields: created_at (ISO 8601 UTC), title, url.

Caching

Thread exports are cached locally in encrypted form at ~/.config/perplexity-cli/threads-cache.json. The cache stores only threads within the requested date range, so subsequent exports with different date filters will fetch fresh data as needed. Use --force-refresh to bypass the cache or --clear-cache to delete it.

Rate limiting

Thread export requests are rate-limited by default (20 requests per 60 seconds) to avoid HTTP 429 errors. See Rate limiting for configuration.

Configuration

Configuration file

pxcli stores feature toggles in ~/.config/perplexity-cli/config.json:

{
  "version": 1,
  "features": {
    "save_cookies": false,
    "debug_mode": false
  }
}

Manage settings with:

# View current configuration
pxcli show-config

# Enable cookie storage (saves Cloudflare cookies alongside JWT token)
pxcli set-config save_cookies true

# Enable persistent debug logging
pxcli set-config debug_mode true

# Disable
pxcli set-config save_cookies false
pxcli set-config debug_mode false

After changing save_cookies, re-authenticate for the change to take effect:

pxcli set-config save_cookies true
pxcli auth

Token storage

Tokens are encrypted and stored at:

  • Linux/macOS: ~/.config/perplexity-cli/token.json
  • Windows: %APPDATA%\perplexity-cli\token.json

Encryption uses Fernet (AES-128-CBC) with a key derived via PBKDF2-HMAC (100,000 iterations) from the system hostname and OS user. Tokens are not portable between machines. File permissions are restricted to owner only (0600).

To re-authenticate:

pxcli logout
pxcli auth

URL configuration

API endpoints are configured in ~/.config/perplexity-cli/urls.json (created automatically on first run):

{
  "perplexity": {
    "base_url": "https://www.perplexity.ai",
    "query_endpoint": "https://www.perplexity.ai/rest/sse/perplexity_ask"
  },
  "rate_limiting": {
    "enabled": true,
    "requests_per_period": 20,
    "period_seconds": 60
  }
}

Rate limiting

Rate limiting applies to thread export requests. Adjust in urls.json:

{
  "rate_limiting": {
    "enabled": true,
    "requests_per_period": 10,
    "period_seconds": 60
  }
}

Set "enabled": false to disable (not recommended).

Environment variables

Environment variables override configuration file settings. Precedence: CLI flags > environment variables > config file > defaults.

Variable Description
PERPLEXITY_BASE_URL API base URL
PERPLEXITY_QUERY_ENDPOINT Query endpoint path
PERPLEXITY_SAVE_COOKIES true or false -- override cookie storage
PERPLEXITY_DEBUG_MODE true or false -- override debug mode
PERPLEXITY_RATE_LIMITING_ENABLED true or false
PERPLEXITY_RATE_LIMITING_RPS Requests per period (integer)
PERPLEXITY_RATE_LIMITING_PERIOD Period in seconds (integer)

Command reference

Global options

pxcli [OPTIONS] COMMAND [ARGS]...

Options:
  --version        Show version and exit
  -v, --verbose    INFO level logging
  -d, --debug      DEBUG level logging
  --log-file PATH  Log file path (default: ~/.config/perplexity-cli/perplexity-cli.log)

Command options:
  query           -f {plain,markdown,rich,json}  --strip-references
                  --stream / --no-stream
  auth            --port PORT
  export-threads  --from-date DATE  --to-date DATE  --output PATH
                  --force-refresh  --clear-cache
  configure       STYLE
  set-config      KEY VALUE

pxcli auth [--port PORT]

Authenticate with Perplexity.ai via Chrome DevTools Protocol. Default port: 9222.

pxcli query QUERY [OPTIONS]

Submit a query and display the answer.

Option Description
--format, -f Output format: plain, markdown, rich (default), json
--strip-references Remove citation markers and references section
--stream / --no-stream Stream response incrementally (default: --no-stream)

Exit codes: 0 success, 1 error, 130 interrupted.

pxcli status

Display authentication status and verify token validity.

pxcli logout

Remove stored authentication token.

pxcli configure STYLE

Set a persistent style prompt applied to all queries.

pxcli view-style

Display the currently configured style.

pxcli clear-style

Remove the configured style.

pxcli set-config KEY VALUE

Set a configuration option. Keys: save_cookies, debug_mode. Values: true, false.

pxcli show-config

Display current configuration and any environment variable overrides.

pxcli show-skill

Display the Agent Skill definition for integrating pxcli with AI agents.

pxcli export-threads [OPTIONS]

Export thread library to CSV.

Option Description
--from-date DATE Start date filter (YYYY-MM-DD, inclusive)
--to-date DATE End date filter (YYYY-MM-DD, inclusive)
--output PATH Output file path (default: threads-TIMESTAMP.csv)
--force-refresh Bypass local cache
--clear-cache Delete cache before export

Troubleshooting

"Not authenticated"

Run pxcli auth to authenticate.

"Failed to decrypt token"

The token was encrypted on a different machine or with a different user. Run pxcli auth to re-authenticate.

Chrome connection fails

Ensure Chrome is running with --remote-debugging-port=9222 and the port matches what you specified.

Token file has insecure permissions

Delete the file and re-authenticate:

rm ~/.config/perplexity-cli/token.json
pxcli auth

Development

Setup

git clone https://github.com/jamiemills/perplexity-cli.git
cd perplexity-cli
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"

Testing

pytest                          # run all tests
pytest --cov=perplexity_cli     # with coverage
pytest -m integration           # integration tests only
pytest -m security              # security tests only

Linting and formatting

ruff format src/ tests/         # auto-format
ruff check src/ tests/          # lint
mypy src/                       # type check

Security

  • Tokens encrypted at rest using Fernet (AES-128-CBC)
  • Key derivation via PBKDF2-HMAC with 100,000 iterations (with backward-compatible SHA-256 fallback for legacy tokens)
  • File permissions restricted to owner (0600)
  • Token validity checked on each request
  • Token age warnings (>30 days)
  • No credentials written to logs

Dependencies

  • click -- CLI framework
  • curl-cffi -- HTTP client with Chrome TLS fingerprint impersonation (query and thread export paths)
  • rich -- Terminal formatting
  • cryptography -- Token encryption
  • tenacity -- Retry logic with exponential backoff
  • pydantic -- Data validation and serialisation
  • python-dateutil -- Date parsing for thread exports
  • websockets -- WebSocket support

Updating your .profile / .zshrc / etc

Useful functions to add into your profile e.g. $HOME/.zshrc of choice.

px() {
  local q="$*"
  uvx pxcli query --strip-references --format rich "${q}."
}

pxc() {
  local q="$*"
  uvx pxcli query --strip-references --format plain "${q}. Just give me the commands to run on a Mac. Put them on a single line"
}

after which you can run, for example

pxc "how can I find what remote branches exist for this repo"

Licence

MIT

About

Unofficial CLI client for Perplexity.ai

Resources

Stars

Watchers

Forks

Languages