Python Connector¶
The Python connector is a PIP package that integrates your Python applications with Patcherly for automated error detection and fixing.
Registry: PyPI — patcherly-connector — unpinned pip install resolves to latest; Python versions independently from other stacks (see Connectors overview — Package registries).
Easiest setup: if you have terminal access, use the Universal Installer — no need to configure anything manually. The steps below are for manual package installation.
Quick Start¶
Get up and running in minutes:
# 1. Install the package
pip install patcherly-connector
# 2. Pair with your Patcherly target (OAuth Device Authorization Grant)
patcherly login
# 3. Start the connector
python patcherly_agent.py
patcherly login prints a verification_uri and a short user code. Open the URL in any browser, sign in to your Patcherly dashboard, select the website/app (target), and confirm the code. Credentials are saved to ~/.patcherly/credentials.json.
Context collection consent¶
After pairing, the connector uploads environment context for AI analysis. Default is full (unlike WordPress, which defaults to off until you choose in the WP admin).
patcherly context get # current tier + source (env|file|default)
patcherly context set full|minimal|off
patcherly context upload # force collect + upload now
- Env
PATCHERLY_CONTEXT_CONSENToverrides the cache file. - Cache file:
{PATCHERLY_CACHE_DIR}/context_consent(default.patcherly_cache/context_consent). offskips uploads;minimalsends runtime/OS/framework only.
The connector will automatically: - Read OAuth credentials from ~/.patcherly/credentials.json - Start monitoring your application logs and report new errors to the dashboard - Sign requests with the per-token HMAC secret from the credential file
Note: the Python connector reports errors to Patcherly and applies approved fixes back to your code. Analysis and approval happen in the Patcherly dashboard, not on the connector itself.
Installation¶
Step 1: Install the Package¶
Or using pipenv:
Step 2: Pair with a Target (OAuth)¶
Run the login command once per target server:
Follow the prompt: open the printed URL in any browser, sign in, and confirm the user code. Credentials are saved to ~/.patcherly/credentials.json. To log out and revoke the token, run patcherly logout — Patcherly also flips the target row on the dashboard from healthy/stale to inactive immediately on the same call (no more "still says healthy three days after I logged out" surprises).
If you want to customise paths, create a .env file:
# OPTIONAL: Custom paths
PATCHERLY_BACKUP_ROOT=.patcherly_backups
PATCHERLY_QUEUE_PATH=patcherly_queue.jsonl
PATCHERLY_IDS_PATH=patcherly_ids.json
Step 3: Initialize the Agent¶
In your application's main file:
from patcherly_agent import PatcherlyAgent
# Initialize the agent — credentials are read from ~/.patcherly/credentials.json
agent = PatcherlyAgent(
log_file='logs/error.log'
)
# Start monitoring
await agent.start()
Alternative Installation: Direct File Upload¶
If you prefer to upload the connector files directly to your environment instead of using pip:
Step 1: Download and Upload Connector Files¶
- Download the Python Connector Files
- Download
python-connector.tar.gzfrom the latest connector release. - Extract it into your install directory — the universal installer's default is
/opt/patcherly-connector/on Linux/macOS and%USERPROFILE%\patcherly-connector\on Windows; you can pick any path as long as you reference the same one in the start commands and systemd unit below. Use all files from the archive — the agent needs every module (OAuth client, credential store, patcherly CLI, etc.) to pair and run; missing files break login or apply.
Tip: Most installs go through the universal installer instead (
curl https://api.patcherly.com/install | bash) which downloads and extracts the right archive for you. The manual path above is for environments where the installer can't run.
- Install Required Dependencies
- The connector requires:
httpx,asyncio(built-in) - Install dependencies:
pip install httpx - Optional (for local approvals UI):
pip install flask - Optional (for automatic .env file loading):
pip install python-dotenv- Note: If
python-dotenvis not installed, the connector will manually parse.envfiles
- Note: If
Step 2: Pair with a Target and Configure¶
Run patcherly login (from the extracted connector directory) to complete OAuth pairing. Optionally, create a .env file for custom paths:
# OPTIONAL: Custom paths
PATCHERLY_BACKUP_ROOT=.patcherly_backups
PATCHERLY_QUEUE_PATH=patcherly_queue.jsonl
PATCHERLY_IDS_PATH=patcherly_ids.json
Step 3: Start the Agent¶
Option A: Run as Standalone Script (Recommended)
The connector can be run directly as a Python script:
# From the connector directory
cd /opt/patcherly-connector
python patcherly_agent.py
# Or with command-line options
python patcherly_agent.py --server https://api.patcherly.com --log logs/error.log --interval 10
# Or from your project root
python /opt/patcherly-connector/patcherly_agent.py
Available Command-Line Options: - --log: Log file to monitor (default: agent_logs.txt) - --interval: Polling interval in seconds (default: 10) - --local-approvals: Enable local approvals UI (optional). Binds to 127.0.0.1 only and requires Authorization: Bearer <oauth-access-token> on /approvals, /approve, /reject-patch, and /api/file-content (only /status is unauthenticated). The error_id payload on /approve and /reject-patch must match ^[A-Za-z0-9_-]{1,128}$. /reject-patch requires a resolution body (manual_suggestion, manual_own, or not_needed). - --approvals-port: Port for local approvals UI (default: 8081) - --project-root: Constrain /api/file-content reads to this directory (default: the directory the connector was launched from). This is a defense-in-depth boundary so the connector cannot be turned into an arbitrary-file reader on the host. Requests must also include error_id in the signed JSON body.
Option B: Import and Run in Your Application
import sys
import os
import asyncio
# Add connector directory to Python path
connector_path = os.path.join(os.path.dirname(__file__), 'patcherly-connector')
if connector_path not in sys.path:
sys.path.insert(0, connector_path)
from patcherly_agent import PatcherlyAgent
async def main():
# Credentials are read from ~/.patcherly/credentials.json (created by patcherly login)
agent = PatcherlyAgent(
log_file='logs/error.log'
)
await agent.run(poll_interval=10) # Run with 10-second polling interval
if __name__ == "__main__":
asyncio.run(main())
Option C: Run as Background Process
# Run in background
cd /opt/patcherly-connector
nohup python patcherly_agent.py > ../logs/agent.log 2>&1 &
# Or using screen/tmux
screen -S patcherly-connector
cd /opt/patcherly-connector
python patcherly_agent.py
# Press Ctrl+A then D to detach
Option D: Run as Systemd Service (Linux)
Create /etc/systemd/system/patcherly-connector.service:
[Unit]
Description=Patcherly Python Agent
After=network.target
[Service]
Type=simple
User=your_user
WorkingDirectory=/opt/patcherly-connector
EnvironmentFile=/opt/patcherly-connector/.env
ExecStart=/usr/bin/python3 /opt/patcherly-connector/patcherly_agent.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Then enable and start:
Configuration¶
Credentials (OAuth)¶
The connector reads authentication credentials from ~/.patcherly/credentials.json, created when you run patcherly login.
Optional Settings¶
- SERVER_URL or PATCHERLY_API_BASE: Leave unset for normal use (
https://api.patcherly.com). Only set one of these if Patcherly Support gives you a specific API host — use the same value forpatcherly login --api-baseand the running agent. - PATCHERLY_BACKUP_ROOT: Backup directory (default:
.patcherly_backups) - PATCHERLY_QUEUE_PATH: Queue file path (default:
patcherly_queue.jsonl) - PATCHERLY_IDS_PATH: Workspace/target IDs cache (default:
patcherly_ids.json)
HMAC Signing¶
HMAC signing uses the per-token secret bundled in ~/.patcherly/credentials.json at OAuth issuance. You do not need to configure a secret manually: - Each OAuth token includes its own unique HMAC signing secret - The connector reads it from the credential file automatically - HMAC verification is always mandatory for fix payloads
Supported Applications & File Types¶
✅ Supported Applications¶
The Python connector is designed for Python web applications and services:
- Django - High-level Python web framework
- Flask - Lightweight WSGI web application framework
- FastAPI - Modern, fast web framework for building APIs
- Pyramid - Flexible Python web framework
- Any Python application - Custom Python servers, APIs, scripts, services
The connector automatically detects which framework you're using and includes this information in error context.
✅ Supported File Types¶
The connector can patch and validate syntax for:
.py- Python source files
❌ Not Supported¶
Other file types: - Python bytecode files (.pyc, .pyo) - Compiled extensions (.so, .pyd) - Jupyter notebooks (.ipynb) - Other languages (JavaScript, PHP, etc.)
Note: The connector focuses on Python source code files. It validates syntax using Python's ast.parse module before and after applying patches.
Features¶
Automatic Error Detection¶
The connector automatically:
- Monitors log files for errors
- Detects new error entries
- Sends error context to Patcherly
- Tracks error signatures and occurrences
Did you know? The Python agent runs separately from your app and only detects lines from log files it watches. If errors are missing in Patcherly, confirm your app writes failures to a monitored file and add any custom path under Targets → Log paths. See Custom log paths and the connectors overview.
Fix Application¶
When a fix is approved in the dashboard:
- The agent polls for approved fixes on its next loop (about every 10 seconds by default)
- Downloads the fix payload with HMAC signature verification
- Creates a backup before applying
- Applies the fix using unified diff patches
- Validates Python syntax before and after application
- Supports rollback if fix fails
Queue Management¶
- Offline Queue: Stores errors when server is unavailable
- Automatic Retry: Retries failed submissions with exponential backoff
- Queue Limits: Maximum 1000 entries (oldest-first eviction)
- Dead Letter Queue: Tracks permanent failures
Backup System¶
- Automatic Backups: Created before applying fixes (copies of all existing paths in the patch are written to your
PATCHERLY_BACKUP_ROOTdirectory) - Versioned Backups: Timestamped and error ID tagged for restoring historical versions (kept until you delete them)
- Compression: Gzip compression for storage efficiency
- Integrity Checks: SHA256 checksum verification
Usage¶
Basic Error Monitoring¶
from patcherly_agent import PatcherlyAgent
import asyncio
async def main():
# Credentials are read from ~/.patcherly/credentials.json
agent = PatcherlyAgent()
# Monitor a log file
await agent.monitor_logs('logs/application.log')
asyncio.run(main())
Manual Error Submission¶
# Submit an error manually
await agent.process_error({
'error_type': 'ValueError',
'error_message': 'Invalid input value',
'log_line': 'File "app.py", line 42, in process_data',
'traceback': '...',
'severity': 'high'
})
Check Connection Status¶
# Check connection status
status = await agent.check_connection()
print(f"Connected: {status['connected']}")
print(f"Workspace ID: {status['tenant_id']}")
print(f"Target ID: {status['target_id']}")
Security¶
HMAC Signing¶
Each OAuth token carries its own per-token HMAC signing secret, returned at issuance and stored in ~/.patcherly/credentials.json. The connector uses this secret to sign every request with X-Patcherly-Timestamp + X-Patcherly-Signature:
- Per-token secret: bound to the OAuth credential — no global shared secret
- Mandatory verification: HMAC verification is always required for fix payloads
- No manual configuration: The secret is bundled into the credential file at OAuth issuance
To rotate, run patcherly logout then patcherly login to issue a new token and secret.
OAuth Credential Management¶
- Credentials are stored in
~/.patcherly/credentials.json - Never commit this file to version control
- To revoke:
patcherly logout(revokes the token server-side) - To re-pair:
patcherly login
Verify detection end-to-end with patcherly send-test¶
After pairing, you can prove the whole pipeline (connector → API → dashboard error feed) works without waiting for a real exception. Test events only flow while you've explicitly opened a Test Mode window from your Patcherly dashboard — this gate prevents an exposed connector credential, a curious script, or a CI run from spraying synthetic traffic into your real error feed and triggering notifications. The window is per-target and lasts 30 minutes; you stay in control.
- In your Patcherly dashboard, open Targets, click your target, and flip the Test Mode toggle ON — this opens a 30-minute window for this target only.
- On the server where you ran
patcherly login, run: - The synthetic event lands in your dashboard under Errors, flagged as a sample so it does not affect your metrics or fire notifications.
The CLI auto-checks the Test Mode window (GET /v1/targets/connector-status) before sending. If the window is closed, it prints a clear "Test error window is not open for this target" message plus the exact dashboard URL where you can enable it — no traffic is sent. Pass --no-preflight to skip that check (used in tests).
Keep the connection alive on quiet hosts (patcherly heartbeat)¶
Once you've paired with patcherly login, the connection is designed to stay alive without you having to reconnect — even if the host sits idle for weeks. Every time the connector talks to Patcherly (sending an error, fetching a fix, polling status), the connection's credentials are quietly refreshed in the background.
If the host you paired is paired but rarely runs the connector (low-traffic site, weekend job server, etc.), wire a tiny once-a-day heartbeat into cron so the credentials never age out:
That one daily call (a) refreshes your credentials long before they expire, and (b) tells the dashboard your connector is still alive (so the "Connector is healthy" check in the onboarding panel stays green). Exits 0 on success, 2 if the host isn't paired yet, 1 on any HTTP / network failure — so cron will email you only when something is actually wrong.
App restart automation¶
For Python website/app (target) types on plans that include app restart automation, the connector can run post-apply shell steps after a successful patch (e.g. systemctl reload, pm2-style commands on the same host). Configuration is only in the dashboard (Targets → App restart On/Off toggle + Configure); pause without deleting the YAML via the toggle. The command list is delivered over the connector API and verified before execution.
- Guide: App restart automation
- Command forms: prefer array-form
run: ['python', 'scripts/reload.py']when you need semicolons inside-cbodies; string-formrun:still tokenises and rejects;,&&, etc. argv[0] must be allowlisted — defaults includepython/systemctl/pm2/supervisorctl. - Optional environment variables on the agent host (for example
PATCHERLY_POST_APPLY_DRY_RUN,PATCHERLY_WORKFLOW_LOCK_WAIT_SEC): use only if your connector README or support has you set them.
Troubleshooting¶
Connection Issues¶
"Cannot connect to server" - Check network connectivity and firewall (outbound HTTPS to api.patcherly.com) - Verify Patcherly service is running
"Authentication failed" / credentials missing - Check that ~/.patcherly/credentials.json exists on the target server. - If it is missing or expired, re-pair with patcherly login.
"HMAC signature mismatch" - The per-token HMAC secret is in ~/.patcherly/credentials.json; re-pair with patcherly login if the credential file is corrupted - Ensure timestamp is synchronized (check system clock / NTP) - Restart the connector after re-pairing
Error Detection Issues¶
"No errors detected" - Verify log file path is correct - Check log file has read permissions - Ensure errors are being logged - Check log format matches expected format
"Errors not submitting" - Check queue file for pending errors - Verify network connectivity - Check server logs for errors - Review connector logs
Fix Application Issues¶
"Fix application failed" - Check backup was created - Verify file permissions - Check syntax validation (Python ast.parse) - Review patch format
"Rollback failed" - Check backup integrity - Verify backup file exists - Check file permissions - Review rollback logs
Best Practices¶
Credentials¶
- Never commit
~/.patcherly/credentials.jsonor.envfiles to version control - Use separate OAuth pairings for different environments (each
patcherly loginissues a distinct token) - To rotate credentials, run
patcherly logoutthenpatcherly login
Error Handling¶
- Monitor connector logs regularly
- Set up alerts for connection failures
- Review error queue periodically
- Test fix application in staging first
Performance¶
- Use appropriate log file monitoring intervals
- Configure queue limits appropriately
- Clean up old backups regularly (delete them manually when you no longer need version history)
- Monitor disk space usage
API Reference¶
PatcherlyAgent Class¶
class PatcherlyAgent:
def __init__(self, log_file: str = 'agent_logs.txt')
async def start()
async def stop()
async def monitor_logs(log_file: str)
async def process_error(error_context: dict)
async def check_connection() -> dict
Credentials are read from ~/.patcherly/credentials.json (no constructor parameter for keys).
Methods¶
start(): Start the agent and begin monitoringstop(): Stop monitoring and cleanupmonitor_logs(log_file): Monitor a specific log fileprocess_error(error_context): Submit an error manuallycheck_connection(): Check connection status