Git Catcher
A Python CLI tool that receives GitHub push webhooks in real time via the Smee.io SSE proxy and automatically runs git pull and a custom deploy command for allowed branches.
Works behind firewalls/NAT, and supports automatic reconnection with exponential backoff on disconnection.
Installation
pip install -r git_catcher/requirements.txt
Dependencies
| Package | Purpose |
|---|---|
httpx |
SSE stream HTTP client |
rich |
Colored console logging |
python-dotenv |
Load environment variables from .env |
InquirerPy |
Interactive CLI prompts (init command) |
hypothesis |
Property-based testing (dev) |
pytest |
Test framework (dev) |
Quick Start
1. Interactive Setup (recommended)
python -m git_catcher.main init
Or using the shortcut:
python run.py init
Answer the interactive prompts to automatically generate a .env file and docker-compose.yml.
- Auto-generate Smee.io URL (opens browser)
- Randomly generate Webhook Secret
- Select repository path and allowed branches
- Configure Slack notifications
2. Manual Setup
Copy .env.example to create a .env file and fill in the values.
cp git_catcher/.env.example git_catcher/.env
| Variable | Default | Description |
|---|---|---|
SMEE_URL |
https://smee.io/YOUR_CHANNEL_ID |
Smee.io channel URL (create at smee.io/new) |
WEBHOOK_SECRET |
"" |
GitHub Webhook Secret (signature verification skipped if not set) |
REPO_PATH |
/path/to/your/repo |
Local path to the target Git repository |
ALLOWED_BRANCHES |
main,master |
Branches to deploy (comma-separated) |
POST_PULL_COMMAND |
"" |
Shell command to run after git pull |
RECONNECT_DELAY |
1 |
Initial reconnect wait time (seconds) |
MAX_RECONNECT_DELAY |
300 |
Maximum reconnect wait time (seconds) |
ALLOWED_REPOS |
"" |
Allowed repositories (owner/repo format, comma-separated). Auto-detected from REPO_PATH git remote origin if empty |
SLACK_WEBHOOK_URL |
"" |
Slack Incoming Webhook URL. Notifications skipped if empty |
NOTIFY_ON_START |
true |
Send Slack notification on startup (true/false) |
POLL_INTERVAL |
0 |
Git status polling interval (seconds; 0 disables) |
LOG_LEVEL |
INFO |
Log level (DEBUG, INFO, WARNING, ERROR) |
LOG_FILE |
"" |
Log file path (file logging disabled if empty) |
SHOW_ALL_EVENTS |
false |
Log all push events (true/false) |
2. Create a Smee.io Channel
- Go to https://smee.io/new.
- A unique channel URL is automatically generated (e.g.
https://smee.io/AbCdEfGhIjKlMn). - Copy this URL. Use the same value for the GitHub Webhook Payload URL and
SMEE_URLin your.env.
Note: The
git-catcher initcommand automatically opens Smee.io in your browser.
3. Add a GitHub Repository Webhook
- In your GitHub repository, go to Settings → Webhooks → Add webhook.
- Configure as follows:
| Field | Value |
|---|---|
| Payload URL | Smee.io channel URL (e.g. https://smee.io/AbCdEfGhIjKlMn) |
| Content type | application/json |
| Secret | Same value as WEBHOOK_SECRET in .env |
| Which events? | Select "Just the push event" |
| Active | Checked |
- Click Add webhook to save.
Note: Leaving the Secret blank also skips signature verification in Git Catcher. Setting a Secret is recommended for security.
3-1. Receive Webhooks for All Repositories via GitHub App (optional)
If you only need a single repository, use 3. Add a GitHub Repository Webhook above. To receive push webhooks from all repositories in your personal account (including future ones), create a GitHub App.
1) Create a GitHub App
Create an app at GitHub Settings → Developer settings → GitHub Apps → New GitHub App.
| Field | Value | Notes |
|---|---|---|
| App name | Any name | e.g. my-git-catcher |
| Homepage URL | https://github.com/your-account |
Required for app identification |
| Webhook URL | Smee.io channel URL | Destination to receive webhook data |
| Webhook Secret | Same value as WEBHOOK_SECRET in .env |
Shared key to prevent payload tampering between server and GitHub |
2) Permissions and Event Subscriptions
At the bottom of the creation form, configure:
- Repository Permissions → Contents: Set to
Read-onlyor higher (required to detect code changes) - Subscribe to events → Check Push (webhook fires only on code pushes)
3) Install the App on Your Account
This is the most important step. Creating the app alone is not enough — you must install it on your account.
- On the created app page, click Install App.
- Select your account and choose All repositories.
- Click Install.
Selecting All repositories automatically applies the webhook to all existing repositories and any created in the future.
4) Security and Verification
| Item | Description |
|---|---|
Private Key (.pem) |
Generate from the app settings page. Used for authentication when calling the GitHub API from your server |
| Recent Deliveries | View sent webhook payloads and test redelivery via Redeliver in the app settings → Advanced tab |
4. .env Example
SMEE_URL must match the channel URL from Smee.io, and WEBHOOK_SECRET must match the Secret entered in GitHub Webhook settings.
SMEE_URL=https://smee.io/AbCdEfGhIjKlMn
WEBHOOK_SECRET=your-webhook-secret-here
REPO_PATH=/path/to/your/repo
ALLOWED_BRANCHES=main,master
POST_PULL_COMMAND=
ALLOWED_REPOS=
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../xxx
NOTIFY_ON_START=true
POLL_INTERVAL=0
LOG_LEVEL=INFO
LOG_FILE=
SHOW_ALL_EVENTS=false
See the environment variables table for details on each variable.
Running
Basic Usage
# Option 1: run as module
python -m git_catcher.main
# Option 2: shortcut (recommended)
python run.py
On startup, git-catcher connects to the Smee.io SSE stream and waits for GitHub push events. When a push is detected on an allowed branch, it automatically runs git fetch → git checkout → git pull → post-pull command in sequence.
Startup Notification
When NOTIFY_ON_START=true, git-catcher sends a Slack notification on startup containing:
- Repository name
- Allowed branch list
- Hostname
- External IP address
- Start time (UTC)
CLI Commands
| Command | Description |
|---|---|
git-catcher init |
Interactive setup (generates .env and docker-compose.yml) |
git-catcher run |
Run git-catcher (default behavior) |
CLI Options (run command)
| Option | Description |
|---|---|
-v |
DEBUG logging for git_catcher module only |
-vv |
DEBUG logging for all modules |
-vvvv |
Also print raw webhook payloads |
--show-all-events |
Log all push events (deployment filtering still applies) |
--log-file PATH |
Log file path (also writes DEBUG logs to file when set) |
--log-level LEVEL |
Log level (DEBUG, INFO, WARNING, ERROR) |
# Basic run
python run.py
# git_catcher module DEBUG + write to log file
python run.py -v --log-file deploy.log
# Show all push events + full DEBUG
python run.py -vv --show-all-events
# Interactive setup
python run.py init
Key Features
- Interactive setup: Answer prompts with
git-catcher initto auto-generate.envanddocker-compose.yml - Quick start: Run with
python run.py - Startup notification: Sends a Slack notification on start when
NOTIFY_ON_START=true(includes repo, branches, host, IP) - Auto repo detection: Extracts
owner/repofromREPO_PATHgit remote origin URL whenALLOWED_REPOSis not set - Slack deploy notifications: Notifies a Slack channel on deploy success/failure when
SLACK_WEBHOOK_URLis set - SSE reconnect recovery: Resumes from the last received event using
Last-Event-IDon disconnection - Rich console logging: Readable colored output with timestamp (HH:MM:SS.ms) format
Verifying It Works
-
Run Git Catcher:
python run.py -
When you see the
SSE stream connectedlog, the connection is established. -
If
NOTIFY_ON_START=true, a startup notification is sent to Slack. -
Push a commit to an allowed branch:
git add . git commit -m "test webhook" git push origin main
-
Verify the following logs appear in order in the Git Catcher terminal:
- Push detected:
[main] test webhook git fetch→git checkout→git pullcompletePOST_PULL_COMMANDexecuted (if configured)- Slack notification sent (if configured)
- Push detected:
If something is wrong, check the Recent Deliveries tab on the GitHub Webhook page to inspect delivery status.
Tests
pytest tests/ -v
Metadata
Release files for git-catcher 0.14.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| git_catcher-0.14.0.tar.gz | 25.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| git_catcher-0.14.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 44.8 kB
Release files / git_catcher-0.14.0.tar.gz
| Download URL | git_catcher-0.14.0.tar.gz |
|---|---|
| Size | 25.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8b8d29789ad6dd41799087865016454fdd188c6f696d3acdd8427ff7d92d7ff1
|
|
BLAKE2b-256 checksum How to use checksums |
f13e6868858f58b3ab31ca80af2f25fe0a868fbea38161b2b8cb18b1bd43093b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / git_catcher-0.14.0-py3-none-any.whl
| Download URL | git_catcher-0.14.0-py3-none-any.whl |
|---|---|
| Size | 19.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8dc12df3405f722f17f7b83962eb3de946602f776a3b608af1beaf5ca91de4a9
|
|
BLAKE2b-256 checksum How to use checksums |
6c5c4fe8eec4e75ca29677b55e5f8efb00b24bd9b138b1220bff781c4165f9b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|