pxcli 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. pxcli-0.3.0/PKG-INFO +746 -0
  2. pxcli-0.3.0/README.md +707 -0
  3. pxcli-0.3.0/pyproject.toml +98 -0
  4. pxcli-0.3.0/setup.cfg +4 -0
  5. pxcli-0.3.0/src/perplexity_cli/__init__.py +3 -0
  6. pxcli-0.3.0/src/perplexity_cli/api/__init__.py +15 -0
  7. pxcli-0.3.0/src/perplexity_cli/api/client.py +182 -0
  8. pxcli-0.3.0/src/perplexity_cli/api/endpoints.py +176 -0
  9. pxcli-0.3.0/src/perplexity_cli/api/models.py +181 -0
  10. pxcli-0.3.0/src/perplexity_cli/auth/__init__.py +15 -0
  11. pxcli-0.3.0/src/perplexity_cli/auth/oauth_handler.py +299 -0
  12. pxcli-0.3.0/src/perplexity_cli/auth/token_manager.py +172 -0
  13. pxcli-0.3.0/src/perplexity_cli/cli.py +861 -0
  14. pxcli-0.3.0/src/perplexity_cli/formatting/__init__.py +31 -0
  15. pxcli-0.3.0/src/perplexity_cli/formatting/base.py +69 -0
  16. pxcli-0.3.0/src/perplexity_cli/formatting/json.py +76 -0
  17. pxcli-0.3.0/src/perplexity_cli/formatting/markdown.py +89 -0
  18. pxcli-0.3.0/src/perplexity_cli/formatting/plain.py +127 -0
  19. pxcli-0.3.0/src/perplexity_cli/formatting/registry.py +83 -0
  20. pxcli-0.3.0/src/perplexity_cli/formatting/rich.py +221 -0
  21. pxcli-0.3.0/src/perplexity_cli/resources/skill.md +345 -0
  22. pxcli-0.3.0/src/perplexity_cli/threads/__init__.py +7 -0
  23. pxcli-0.3.0/src/perplexity_cli/threads/cache_manager.py +367 -0
  24. pxcli-0.3.0/src/perplexity_cli/threads/date_parser.py +139 -0
  25. pxcli-0.3.0/src/perplexity_cli/threads/exporter.py +85 -0
  26. pxcli-0.3.0/src/perplexity_cli/threads/scraper.py +348 -0
  27. pxcli-0.3.0/src/perplexity_cli/utils/__init__.py +1 -0
  28. pxcli-0.3.0/src/perplexity_cli/utils/config.py +303 -0
  29. pxcli-0.3.0/src/perplexity_cli/utils/encryption.py +94 -0
  30. pxcli-0.3.0/src/perplexity_cli/utils/logging.py +85 -0
  31. pxcli-0.3.0/src/perplexity_cli/utils/rate_limiter.py +132 -0
  32. pxcli-0.3.0/src/perplexity_cli/utils/retry.py +110 -0
  33. pxcli-0.3.0/src/perplexity_cli/utils/style_manager.py +94 -0
  34. pxcli-0.3.0/src/perplexity_cli/utils/version.py +72 -0
  35. pxcli-0.3.0/src/pxcli.egg-info/PKG-INFO +746 -0
  36. pxcli-0.3.0/src/pxcli.egg-info/SOURCES.txt +57 -0
  37. pxcli-0.3.0/src/pxcli.egg-info/dependency_links.txt +1 -0
  38. pxcli-0.3.0/src/pxcli.egg-info/entry_points.txt +3 -0
  39. pxcli-0.3.0/src/pxcli.egg-info/requires.txt +15 -0
  40. pxcli-0.3.0/src/pxcli.egg-info/top_level.txt +1 -0
  41. pxcli-0.3.0/tests/test_api_client.py +277 -0
  42. pxcli-0.3.0/tests/test_api_integration.py +118 -0
  43. pxcli-0.3.0/tests/test_auth.py +255 -0
  44. pxcli-0.3.0/tests/test_auth_integration.py +197 -0
  45. pxcli-0.3.0/tests/test_chrome_connection.py +85 -0
  46. pxcli-0.3.0/tests/test_cli.py +376 -0
  47. pxcli-0.3.0/tests/test_config_improvements.py +109 -0
  48. pxcli-0.3.0/tests/test_encryption.py +154 -0
  49. pxcli-0.3.0/tests/test_endpoints.py +188 -0
  50. pxcli-0.3.0/tests/test_formatters.py +338 -0
  51. pxcli-0.3.0/tests/test_logging.py +51 -0
  52. pxcli-0.3.0/tests/test_manual_auth.py +319 -0
  53. pxcli-0.3.0/tests/test_models.py +204 -0
  54. pxcli-0.3.0/tests/test_query_realtime.py +64 -0
  55. pxcli-0.3.0/tests/test_query_simple.py +41 -0
  56. pxcli-0.3.0/tests/test_retry.py +67 -0
  57. pxcli-0.3.0/tests/test_style_manager.py +190 -0
  58. pxcli-0.3.0/tests/test_thread_cache.py +436 -0
  59. pxcli-0.3.0/tests/test_version.py +29 -0
pxcli-0.3.0/PKG-INFO ADDED
@@ -0,0 +1,746 @@
1
+ Metadata-Version: 2.4
2
+ Name: pxcli
3
+ Version: 0.3.0
4
+ Summary: A command-line interface for querying Perplexity.ai with persistent authentication
5
+ Author-email: Jamie Mills <jamie.mills@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/jamiemills/perplexity-cli
8
+ Project-URL: Repository, https://github.com/jamiemills/perplexity-cli
9
+ Project-URL: Bug Tracker, https://github.com/jamiemills/perplexity-cli/issues
10
+ Project-URL: Source Code, https://github.com/jamiemills/perplexity-cli
11
+ Keywords: cli,perplexity,ai,query,command-line
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Internet :: WWW/HTTP
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.12
24
+ Description-Content-Type: text/markdown
25
+ Requires-Dist: click>=8.0
26
+ Requires-Dist: cryptography>=41.0
27
+ Requires-Dist: httpx>=0.25
28
+ Requires-Dist: websockets>=12.0
29
+ Requires-Dist: rich>=13.0
30
+ Requires-Dist: tenacity>=8.0
31
+ Requires-Dist: python-dateutil>=2.8.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0; extra == "dev"
34
+ Requires-Dist: pytest-mock>=3.0; extra == "dev"
35
+ Requires-Dist: pytest-cov>=7.0; extra == "dev"
36
+ Requires-Dist: pytest-asyncio>=1.2.0; extra == "dev"
37
+ Requires-Dist: ruff>=0.1; extra == "dev"
38
+ Requires-Dist: mypy>=1.0; extra == "dev"
39
+
40
+ # Perplexity CLI
41
+
42
+ A command-line interface for querying Perplexity.ai with persistent authentication and encrypted token storage.
43
+
44
+ [![PyPI](https://img.shields.io/pypi/v/pxcli)](https://pypi.org/project/pxcli/)
45
+
46
+ ## Features
47
+
48
+ - **Persistent authentication** - Token stored securely and reused across invocations
49
+ - **Encrypted tokens** - Tokens encrypted with system-derived keys
50
+ - **Multiple output formats** - Plain text, Markdown, or rich terminal output
51
+ - **Source references** - Web sources extracted and displayed
52
+ - **Thread library export** - Export your entire Perplexity thread history to CSV with timestamps
53
+ - **Date filtering** - Filter exported threads by date range
54
+ - **Configurable URLs** - Base URL and endpoints configurable via JSON or environment variables
55
+ - **Error handling** - Clear error messages with exit codes and automatic retry logic
56
+ - **Server-Sent Events** - Streams responses in real-time
57
+ - **Logging** - Configurable logging with verbose/debug modes and log file support
58
+ - **Streaming output** - Real-time streaming of query responses as they arrive
59
+
60
+ ## Installation
61
+
62
+ ### Quick Install (Recommended for Users)
63
+
64
+ The easiest way to use pxcli is with `uvx`:
65
+
66
+ ```bash
67
+ uvx pxcli auth
68
+ ```
69
+
70
+ Or install with uv pip:
71
+
72
+ ```bash
73
+ uv pip install pxcli
74
+ pxcli auth
75
+ ```
76
+
77
+ Note: The command can also be run as `perplexity-cli` for convenience.
78
+
79
+ ### Development Installation (For Contributors)
80
+
81
+ Clone and set up development environment:
82
+
83
+ ```bash
84
+ git clone https://github.com/jamiemills/perplexity-cli.git
85
+ cd perplexity-cli
86
+ uv venv --python=3.12
87
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
88
+ uv pip install -e ".[dev]"
89
+ ```
90
+
91
+ Run tests to verify setup:
92
+
93
+ ```bash
94
+ pytest
95
+ ```
96
+
97
+ ### Prerequisites
98
+
99
+ - Python 3.12 or higher
100
+ - Google Chrome (for authentication)
101
+
102
+ ## Quick Start
103
+
104
+ ### Authenticate (One Time)
105
+
106
+ ```bash
107
+ perplexity-cli auth
108
+ ```
109
+
110
+ This opens your browser to authenticate with Perplexity.ai. Your token is encrypted and stored locally.
111
+
112
+ ### Ask a Question
113
+
114
+ ```bash
115
+ perplexity-cli query "What is Python?"
116
+ ```
117
+
118
+ ### Check Status
119
+
120
+ ```bash
121
+ perplexity-cli status
122
+ ```
123
+
124
+ ### Output Formats
125
+
126
+ Query with JSON output:
127
+
128
+ ```bash
129
+ perplexity-cli query "Explain machine learning" --format json
130
+ ```
131
+
132
+ ### Verbose Mode
133
+
134
+ Get detailed logging:
135
+
136
+ ```bash
137
+ perplexity-cli query "What is AI?" --verbose
138
+ ```
139
+
140
+ ### Log Out
141
+
142
+ ```bash
143
+ perplexity-cli logout
144
+ ```
145
+
146
+ ## Configuration
147
+
148
+ ### Environment Variables
149
+
150
+ Configure perplexity-cli with environment variables:
151
+
152
+ - `PERPLEXITY_BASE_URL`: Custom API base URL (default: https://www.perplexity.ai)
153
+ - `PERPLEXITY_QUERY_ENDPOINT`: Custom query endpoint
154
+ - `PERPLEXITY_LOG_LEVEL`: Logging level - DEBUG, INFO, WARNING, ERROR (default: INFO)
155
+ - `PERPLEXITY_LOG_FILE`: Path to log file (default: ~/.config/perplexity-cli/perplexity-cli.log)
156
+ - `PERPLEXITY_RATE_LIMITING_ENABLED`: Enable/disable rate limiting (default: true)
157
+ - `PERPLEXITY_RATE_LIMITING_RPS`: Requests per period (default: 20)
158
+ - `PERPLEXITY_RATE_LIMITING_PERIOD`: Period in seconds (default: 60)
159
+
160
+ Example:
161
+
162
+ ```bash
163
+ export PERPLEXITY_LOG_LEVEL=DEBUG
164
+ perplexity-cli query "test"
165
+ ```
166
+
167
+ ### Output Formats
168
+
169
+ Available formats: `plain`, `markdown`, `rich`, `json`
170
+
171
+ Default is `rich` for terminal output with formatting. Use `--format` flag:
172
+
173
+ ```bash
174
+ perplexity-cli query "..." --format markdown
175
+ perplexity-cli query "..." --format json
176
+ ```
177
+
178
+ ### Token Management
179
+
180
+ Your authentication token is encrypted and stored at:
181
+ - **Linux/macOS**: `~/.config/perplexity-cli/token.json`
182
+ - **Windows**: `%APPDATA%\perplexity-cli\token.json`
183
+
184
+ The token is encrypted using Fernet (AES-128-CBC) with a key derived from your system hostname and OS user. Tokens are not portable between machines.
185
+
186
+ To re-authenticate:
187
+
188
+ ```bash
189
+ perplexity-cli logout
190
+ perplexity-cli auth
191
+ ```
192
+
193
+ ## Usage
194
+
195
+ ### Authentication Setup
196
+
197
+ The first time you use perplexity-cli, you need to authenticate with Perplexity.ai. This is a one-time process that extracts your session token and stores it securely on your machine.
198
+
199
+ #### Step 1: Install Chrome for Testing
200
+
201
+ Download a dedicated Chrome browser for authentication (this keeps testing separate from your main Chrome instance):
202
+
203
+ ```bash
204
+ npx @puppeteer/browsers install chrome@stable
205
+ ```
206
+
207
+ This downloads Chrome to `~/.local/bin/chrome/` (the path may change between Chrome versions).
208
+
209
+ #### Step 2: Create a Shell Alias
210
+
211
+ Set up an alias to easily run Chrome with remote debugging enabled:
212
+
213
+ ```bash
214
+ # Add this line to your shell config (~/.bashrc, ~/.zshrc, etc.)
215
+ alias chromefortesting='open ~/.local/bin/chrome/mac_arm-*/chrome-mac-arm64/Google\ Chrome\ for\ Testing.app --args "--remote-debugging-port=9222" "about:blank"'
216
+ ```
217
+
218
+ **Note:** The `mac_arm-*` pattern matches the version directory. The exact path varies by Chrome version.
219
+
220
+ #### Step 3: Start Chrome and Authenticate
221
+
222
+ ```bash
223
+ # Terminal 1: Start Chrome with debugging enabled
224
+ chromefortesting
225
+
226
+ # Terminal 2: Run authentication
227
+ perplexity-cli auth
228
+ ```
229
+
230
+ The authentication process will:
231
+ 1. Connect to Chrome via the remote debugging port
232
+ 2. Navigate to Perplexity.ai
233
+ 3. Wait for you to log in (you'll see the login page in Chrome)
234
+ 4. Extract your session token automatically
235
+ 5. Save it encrypted to `~/.config/perplexity-cli/token.json`
236
+
237
+ Once complete, you won't need to authenticate again unless you run `perplexity-cli logout`.
238
+
239
+ #### Custom Port (Optional)
240
+
241
+ If port 9222 is already in use, specify a different port:
242
+
243
+ ```bash
244
+ perplexity-cli auth --port 9223
245
+ ```
246
+
247
+ Then start Chrome with the matching port:
248
+
249
+ ```bash
250
+ alias chromefortesting='open ~/.local/bin/chrome/mac_arm-*/chrome-mac-arm64/Google\ Chrome\ for\ Testing.app --args "--remote-debugging-port=9223" "about:blank"'
251
+ ```
252
+
253
+ ### Query Perplexity
254
+
255
+ ```bash
256
+ # Default format (rich terminal output)
257
+ perplexity-cli query "What is machine learning?"
258
+
259
+ # Plain text (for scripts)
260
+ perplexity-cli query --format plain "What is Python?"
261
+
262
+ # Markdown format
263
+ perplexity-cli query --format markdown "Explain quantum computing" > answer.md
264
+
265
+ # JSON format (structured output for programmatic use)
266
+ perplexity-cli query --format json "What is machine learning?" > answer.json
267
+
268
+ # Remove citations and references section
269
+ perplexity-cli query --strip-references "What is Python?"
270
+
271
+ # Stream response in real-time
272
+ perplexity-cli query --stream "What is Python?"
273
+
274
+ # Combine options
275
+ perplexity-cli query --format plain --strip-references "What is 2+2?"
276
+
277
+ # Use in scripts
278
+ ANSWER=$(perplexity-cli query --format plain "What is 2+2?")
279
+ echo "The answer is: $ANSWER"
280
+
281
+ # Enable verbose logging
282
+ perplexity-cli --verbose query "What is Python?"
283
+
284
+ # Enable debug logging with custom log file
285
+ perplexity-cli --debug --log-file /tmp/perplexity.log query "What is Python?"
286
+ ```
287
+
288
+ ### Status and Logout
289
+
290
+ ```bash
291
+ # Check authentication status
292
+ perplexity-cli status
293
+
294
+ # Remove stored token
295
+ perplexity-cli logout
296
+ ```
297
+
298
+ ## Commands
299
+
300
+ ### `perplexity-cli auth [--port PORT]`
301
+
302
+ Authenticate with Perplexity.ai via Chrome.
303
+
304
+ **Options:**
305
+ - `--port PORT` - Chrome remote debugging port (default: 9222)
306
+
307
+ ### `perplexity-cli query QUESTION [OPTIONS]`
308
+
309
+ Submit a query and get an answer with source references.
310
+
311
+ **Arguments:**
312
+ - `QUESTION` - Your question (quoted)
313
+
314
+ **Options:**
315
+ - `--format {plain,markdown,rich,json}` - Output format (default: rich)
316
+ - `plain` - Plain text, suitable for scripts
317
+ - `markdown` - GitHub-flavoured Markdown
318
+ - `rich` - Terminal output with colours and formatting
319
+ - `json` - Structured JSON with answer and references
320
+ - `--strip-references` - Remove citations and references section
321
+ - `--stream` - Stream response in real-time as it arrives (experimental)
322
+
323
+ **Global Options:**
324
+ - `--verbose, -v` - Enable verbose output (INFO level logging)
325
+ - `--debug, -d` - Enable debug output (DEBUG level logging)
326
+ - `--log-file PATH` - Write logs to file (default: ~/.config/perplexity-cli/perplexity-cli.log)
327
+
328
+ **Exit codes:**
329
+ - `0` - Success
330
+ - `1` - Error
331
+
332
+ ### `perplexity-cli status`
333
+
334
+ Display authentication status and token information.
335
+
336
+ ### `perplexity-cli logout`
337
+
338
+ Remove stored authentication token.
339
+
340
+ ### `perplexity-cli configure STYLE`
341
+
342
+ Set a custom style prompt applied to all queries.
343
+
344
+ **Example:**
345
+ ```bash
346
+ perplexity-cli configure "be concise"
347
+ ```
348
+
349
+ ### `perplexity-cli view-style`
350
+
351
+ Display currently configured style.
352
+
353
+ ### `perplexity-cli clear-style`
354
+
355
+ Remove configured style.
356
+
357
+ ### `perplexity-cli export-threads [OPTIONS]`
358
+
359
+ Export your Perplexity.ai thread library to CSV format with creation timestamps.
360
+
361
+ Uses your stored authentication token - no browser required after initial auth setup!
362
+
363
+ **Options:**
364
+ - `--from-date DATE` - Start date for filtering (YYYY-MM-DD format, inclusive)
365
+ - `--to-date DATE` - End date for filtering (YYYY-MM-DD format, inclusive)
366
+ - `--output PATH` - Output CSV file path (default: threads-TIMESTAMP.csv)
367
+ - `--force-refresh` - Ignore local cache and fetch fresh data from Perplexity API
368
+ - `--clear-cache` - Delete local cache file before export
369
+
370
+ **Examples:**
371
+ ```bash
372
+ # Export all threads (uses cache if available)
373
+ perplexity-cli export-threads
374
+
375
+ # Export threads from 2025
376
+ perplexity-cli export-threads --from-date 2025-01-01
377
+
378
+ # Export threads from a specific date range
379
+ perplexity-cli export-threads --from-date 2025-01-01 --to-date 2025-12-31
380
+
381
+ # Export to custom file
382
+ perplexity-cli export-threads --output my-threads.csv
383
+
384
+ # Force fresh data from API (bypass cache)
385
+ perplexity-cli export-threads --force-refresh
386
+
387
+ # Clear cache and export fresh
388
+ perplexity-cli export-threads --clear-cache
389
+ ```
390
+
391
+ **Setup:**
392
+ Just authenticate once with `perplexity-cli auth` - the export command reuses your stored token. No browser needed!
393
+
394
+ **Output format:**
395
+ ```csv
396
+ created_at,title,url
397
+ 2025-12-23T23:06:00.525132Z,What is Python?,https://www.perplexity.ai/search/...
398
+ 2025-12-22T20:54:36.349239Z,Explain AI,https://www.perplexity.ai/search/...
399
+ ```
400
+
401
+ The export includes:
402
+ - **created_at** - ISO 8601 timestamp with timezone (UTC)
403
+ - **title** - Thread question/title
404
+ - **url** - Full URL to the thread
405
+
406
+ **How it works:**
407
+ The command uses your stored authentication token to call the Perplexity.ai API directly. It automatically paginates through your entire library (handles thousands of threads) and exports the results to CSV.
408
+
409
+ **Caching:**
410
+ Thread exports are automatically cached locally to improve performance. On first export, all threads are fetched and cached. On subsequent exports, the cache is used unless:
411
+ - Requested date range extends beyond cached data (smart partial updates only fetch the gap)
412
+ - `--force-refresh` flag is used to bypass cache
413
+ - Cache is cleared with `--clear-cache` flag
414
+
415
+ The cache is encrypted with the same system-derived key as your auth token and stored at `~/.config/perplexity-cli/threads-cache.json`.
416
+
417
+ ## Configuration
418
+
419
+ ### Token Storage and Encryption
420
+
421
+ Tokens are stored encrypted at `~/.config/perplexity-cli/token.json` (Linux/macOS) or `%APPDATA%\perplexity-cli\token.json` (Windows).
422
+
423
+ **Encryption:**
424
+ - Uses Fernet symmetric encryption (AES-128-CBC)
425
+ - Key derived from system hostname and OS user
426
+ - Tokens not portable between machines
427
+ - No user passwords required
428
+
429
+ **Format:**
430
+ ```json
431
+ {
432
+ "version": 1,
433
+ "encrypted": true,
434
+ "token": "encrypted_token_data"
435
+ }
436
+ ```
437
+
438
+ **File permissions:** 0600 (owner read/write only)
439
+
440
+ ### URL Configuration
441
+
442
+ Perplexity URLs are configured in `~/.config/perplexity-cli/urls.json`.
443
+
444
+ **Default configuration:**
445
+ ```json
446
+ {
447
+ "perplexity": {
448
+ "base_url": "https://www.perplexity.ai",
449
+ "query_endpoint": "https://www.perplexity.ai/rest/sse/perplexity_ask"
450
+ },
451
+ "rate_limiting": {
452
+ "enabled": true,
453
+ "requests_per_period": 20,
454
+ "period_seconds": 60,
455
+ "description": "Allow 20 requests per 60 seconds (~3s delay). Override via env vars or edit this file."
456
+ }
457
+ }
458
+ ```
459
+
460
+ To use alternative URLs, edit this file. Configuration is automatically created on first run.
461
+
462
+ **Environment Variables:**
463
+
464
+ You can override configuration values using environment variables:
465
+ - `PERPLEXITY_BASE_URL` - Overrides `perplexity.base_url`
466
+ - `PERPLEXITY_QUERY_ENDPOINT` - Overrides `perplexity.query_endpoint`
467
+
468
+ Example:
469
+ ```bash
470
+ export PERPLEXITY_BASE_URL="https://custom.example.com"
471
+ perplexity-cli query "What is Python?"
472
+ ```
473
+
474
+ ### Rate Limiting Configuration
475
+
476
+ Thread export operations are rate-limited by default to prevent overwhelming the Perplexity API and encountering 429 (Too Many Requests) errors.
477
+
478
+ **Default Rate Limit:**
479
+ - 20 requests per 60 seconds
480
+ - Approximately 3 second delay between API requests
481
+ - Safe for exporting libraries with thousands of threads
482
+
483
+ **Adjust Rate Limiting:**
484
+
485
+ Edit `~/.config/perplexity-cli/urls.json` and modify the `rate_limiting` section:
486
+
487
+ ```json
488
+ {
489
+ "rate_limiting": {
490
+ "enabled": true,
491
+ "requests_per_period": 20,
492
+ "period_seconds": 60
493
+ }
494
+ }
495
+ ```
496
+
497
+ **Common Configurations:**
498
+
499
+ ```json
500
+ {
501
+ "rate_limiting": {
502
+ "enabled": true,
503
+ "requests_per_period": 10,
504
+ "period_seconds": 60,
505
+ "description": "Conservative: ~6 second delay (10 requests/60s). Use if encountering rate limits."
506
+ }
507
+ }
508
+ ```
509
+
510
+ ```json
511
+ {
512
+ "rate_limiting": {
513
+ "enabled": true,
514
+ "requests_per_period": 30,
515
+ "period_seconds": 60,
516
+ "description": "Aggressive: ~2 second delay (30 requests/60s). Use for faster exports."
517
+ }
518
+ }
519
+ ```
520
+
521
+ ```json
522
+ {
523
+ "rate_limiting": {
524
+ "enabled": false,
525
+ "description": "Disabled: No rate limiting (not recommended, may hit API limits)."
526
+ }
527
+ }
528
+ ```
529
+
530
+ **Environment Variable Overrides:**
531
+
532
+ You can override rate limiting settings without editing the config file:
533
+
534
+ - `PERPLEXITY_RATE_LIMITING_ENABLED` - Set to "true" or "false"
535
+ - `PERPLEXITY_RATE_LIMITING_RPS` - requests_per_period (e.g., "10")
536
+ - `PERPLEXITY_RATE_LIMITING_PERIOD` - period_seconds (e.g., "60")
537
+
538
+ Example:
539
+ ```bash
540
+ # Disable rate limiting for a single export
541
+ export PERPLEXITY_RATE_LIMITING_ENABLED=false
542
+ perplexity-cli export-threads
543
+
544
+ # Use conservative rate limiting (10 requests/minute)
545
+ export PERPLEXITY_RATE_LIMITING_RPS=10
546
+ export PERPLEXITY_RATE_LIMITING_PERIOD=60
547
+ perplexity-cli export-threads
548
+ ```
549
+
550
+ ## Troubleshooting
551
+
552
+ ### "Not authenticated"
553
+
554
+ Run `perplexity-cli auth` to authenticate.
555
+
556
+ ### "Failed to decrypt token"
557
+
558
+ Token was encrypted on a different machine or with a different user. Run `perplexity-cli auth` to re-authenticate.
559
+
560
+ ### Chrome connection fails
561
+
562
+ Ensure Chrome is running with `--remote-debugging-port=9222`. Verify the port matches the one you specified.
563
+
564
+ ### Token file has insecure permissions
565
+
566
+ Token file was modified or has incorrect permissions. Delete the file and re-authenticate:
567
+ ```bash
568
+ rm ~/.config/perplexity-cli/token.json
569
+ perplexity-cli auth
570
+ ```
571
+
572
+ ## Output Formats
573
+
574
+ ### Plain
575
+
576
+ Plain text output suitable for scripts and piping.
577
+
578
+ ```bash
579
+ perplexity-cli query --format plain "What is Python?"
580
+ ```
581
+
582
+ ### Markdown
583
+
584
+ GitHub-flavoured Markdown with headers and formatting.
585
+
586
+ ```bash
587
+ perplexity-cli query --format markdown "Explain AI" > answer.md
588
+ ```
589
+
590
+ ### Rich
591
+
592
+ Terminal output with colours, bold text, and formatted tables (default).
593
+
594
+ ```bash
595
+ perplexity-cli query "What is Python?"
596
+ ```
597
+
598
+ ### JSON
599
+
600
+ Structured JSON output suitable for programmatic processing and integration with other tools.
601
+
602
+ ```bash
603
+ perplexity-cli query --format json "What is machine learning?"
604
+ ```
605
+
606
+ **Output structure:**
607
+ ```json
608
+ {
609
+ "format_version": "1.0",
610
+ "answer": "Machine learning is a subfield of artificial intelligence...",
611
+ "references": [
612
+ {
613
+ "index": 1,
614
+ "title": "Machine learning, explained | MIT Sloan",
615
+ "url": "https://mitsloan.mit.edu/ideas-made-to-matter/machine-learning-explained",
616
+ "snippet": "Machine learning is a powerful form of artificial intelligence..."
617
+ }
618
+ ]
619
+ }
620
+ ```
621
+
622
+ **Use cases:**
623
+ - Parse responses programmatically in scripts or applications
624
+ - Save structured data for later analysis
625
+ - Integrate with data pipelines
626
+ - Extract references for citation management
627
+ - Process answers through additional tools or APIs
628
+
629
+ **Examples:**
630
+
631
+ Save to file:
632
+ ```bash
633
+ perplexity-cli query --format json "What is Python?" > python.json
634
+ ```
635
+
636
+ Extract and display answer as readable text:
637
+ ```bash
638
+ # Use jq -r to render newlines as actual line breaks
639
+ perplexity-cli query --format json "What is Python?" | jq -r '.answer'
640
+ ```
641
+
642
+ Extract just the reference URLs:
643
+ ```bash
644
+ perplexity-cli query --format json "What is Python?" | jq -r '.references[] | .url'
645
+ ```
646
+
647
+ Remove references from JSON output:
648
+ ```bash
649
+ perplexity-cli query --format json --strip-references "What is Python?"
650
+ ```
651
+
652
+ Count the number of references:
653
+ ```bash
654
+ perplexity-cli query --format json "What is Python?" | jq '.references | length'
655
+ ```
656
+
657
+ Parse JSON in a script:
658
+ ```bash
659
+ python3 << 'EOF'
660
+ import json
661
+ import subprocess
662
+
663
+ result = subprocess.run(
664
+ ["perplexity-cli", "query", "--format", "json", "What is Python?"],
665
+ capture_output=True,
666
+ text=True
667
+ )
668
+ data = json.loads(result.stdout)
669
+ print(data["answer"])
670
+ for ref in data["references"]:
671
+ print(f"- {ref['title']}: {ref['url']}")
672
+ EOF
673
+ ```
674
+
675
+ **Note:** When viewing JSON output, use `jq -r` (raw output) to properly display newlines in the answer text. Without `-r`, you'll see escape sequences like `\n` instead of actual line breaks.
676
+
677
+ ## Development
678
+
679
+ ### Setup Development Environment
680
+
681
+ ```bash
682
+ git clone https://github.com/jamiemills/perplexity-cli.git
683
+ cd perplexity-cli
684
+ uv venv --python=3.12
685
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
686
+ uv pip install -e ".[dev]"
687
+ ```
688
+
689
+ ### Run Tests
690
+
691
+ ```bash
692
+ pytest
693
+ ```
694
+
695
+ ### Linting, Formatting, and Type Checking
696
+
697
+ Format code (auto-fix):
698
+
699
+ ```bash
700
+ ruff format src/
701
+ ```
702
+
703
+ Check for linting issues:
704
+
705
+ ```bash
706
+ ruff check src/
707
+ ```
708
+
709
+ Type checking:
710
+
711
+ ```bash
712
+ mypy src/
713
+ ```
714
+
715
+ For more details on development practices, see `.claude/TESTING_GUIDE.md`.
716
+
717
+ ## Security
718
+
719
+ - Tokens encrypted at rest using Fernet
720
+ - Encryption key derived from system identifiers
721
+ - File permissions restricted to owner (0600)
722
+ - Tokens validated on each request
723
+ - Token expiration detection (warns if token is >30 days old)
724
+ - Audit logging for token operations
725
+ - No credentials printed to logs
726
+
727
+ ## Contributing
728
+
729
+ Contributions are welcome. Please ensure:
730
+ - Code follows PEP 8 standards
731
+ - All tests pass
732
+ - New features include tests
733
+
734
+ ## License
735
+
736
+ MIT
737
+
738
+ ## Dependencies
739
+
740
+ - click - CLI framework
741
+ - httpx - HTTP client
742
+ - websockets - WebSocket support
743
+ - rich - Terminal formatting
744
+ - cryptography - Token encryption
745
+ - tenacity - Retry logic with exponential backoff
746
+ - python-dateutil - Date parsing for thread exports