
Safe Push
- 61 installs
- 93 repo stars
- Updated May 14, 2026
- thatrebeccarae/claude-marketing
Helps with ai & agent building tasks.
About
safe-push is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- safe-push
- AI & Agent Building
- AI-coding skill
Safe Push by the numbers
- 61 all-time installs (skills.sh)
- +8 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #6,381 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thatrebeccarae/claude-marketing --skill safe-pushAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 61 |
|---|---|
| repo stars | ★ 93 |
| Last updated | May 14, 2026 |
| Repository | thatrebeccarae/claude-marketing ↗ |
What it does
Helps with ai & agent building tasks.
Files
Safe Push
Pre-push hygiene check for GitHub repositories. Use when the user asks to push code, especially to public repos.
Trigger
When the user says "push", "safe push", "push to GitHub", or runs /safe-push.
Install
The skill loads patterns from ~/.claude/safe-push-blocklist. Copy the bundled template and customize:
cp safe-push-blocklist.template ~/.claude/safe-push-blocklist
$EDITOR ~/.claude/safe-push-blocklistThe template includes commented-out examples for client names, hostnames, IP ranges, tracking IDs, and Slack token shapes. Replace them with values specific to your environment.
If the file is missing, the skill runs with a warning instead of erroring — but personal pattern checks are skipped, so creating it is strongly recommended.
Procedure
1. Classify the repo
# Check if public repo
git remote -v
# Check for .public-repo marker
test -f .public-repo && echo "PUBLIC" || echo "private or unmarked"If public (or pushing to a public remote): apply ALL checks below. If private: apply only the PII scan (step 2).
2. PII and secrets scan
Load your personal pattern list from ~/.claude/safe-push-blocklist and scan against it. The same patterns apply to diff content (step 2) AND commit messages (step 3) — both run from the same source of truth.
Default mode — scan the diff against the target branch:
# Load personal patterns (graceful fallback if file missing):
if [ -f ~/.claude/safe-push-blocklist ]; then
PATTERNS=$(grep -v '^#' ~/.claude/safe-push-blocklist | grep -v '^$' | paste -sd '|' -)
else
PATTERNS=""
echo "WARNING: ~/.claude/safe-push-blocklist not found. Personal pattern checks skipped."
fi
git diff origin/main...HEAD
[ -n "$PATTERNS" ] && git diff origin/main...HEAD | grep -nE "$PATTERNS" \
|| echo "NO MATCHES IN DIFF"Full repo mode (/safe-push --full) — scan ALL tracked files, not just the diff. Use this for baseline audits, first-time pushes of existing repos, or periodic hygiene checks:
git ls-files | xargs grep -n -E "$PATTERNS" \
--include='*.md' --include='*.py' --include='*.js' --include='*.ts' \
--include='*.html' --include='*.sh' --include='*.json' \
--include='*.yml' --include='*.yaml'Check for these categories (your ~/.claude/safe-push-blocklist covers the regex-able ones):
- Client names or internal project codenames
- Personal infrastructure: hostnames, internal directory names, device IDs, hardware models, self-hosted service names
- Email addresses (personal or client), phone numbers, addresses
- API keys, tokens, secrets (AWS, GitHub, Slack, Telegram, generic)
- Private IP addresses, internal hostnames
- Private key material
- Slack tokens (
xoxb-), Slack channel IDs - Tracking IDs: GA4 (
G-XXXXXXXXXX), GTM (GTM-XXXXXXX)
Edit ~/.claude/safe-push-blocklist to maintain your personal patterns. Never hardcode real client names or infrastructure identifiers inside this skill file — the blocklist is the source of truth.
If anything is found:
- List each finding with file, line number, and what was detected
- Ask the user to fix before proceeding
- Do NOT push until resolved
3. Commit message audit
Review the FULL commit message — both subject (title) and body (description) — for every commit in the push range. Sensitive patterns can hide in either:
# Print the full message (subject + body) for every commit:
git log origin/main..HEAD --format="===%h %s===%n%b"
# Programmatically scan the full message text against the same
# blocklist used for diff content (graceful fallback if file missing):
if [ -f ~/.claude/safe-push-blocklist ]; then
PATTERNS=$(grep -v '^#' ~/.claude/safe-push-blocklist | grep -v '^$' | paste -sd '|' -)
git log origin/main..HEAD --format="%B" | grep -nE "$PATTERNS" \
|| echo "NO MATCHES IN MESSAGES"
else
echo "WARNING: ~/.claude/safe-push-blocklist not found. Personal pattern checks skipped on commit messages."
fiThe same patterns from ~/.claude/safe-push-blocklist that block diff content (step 2) ALSO block commit messages. Apply the full blocklist to BOTH title and body — not just the diff. For public repos, also flag:
- Personal info (email, phone, address) — categorical, not always pattern-matched
- Private repo names you own (e.g., upstream dev mirrors) — soft-warn, ask user before pushing
- Vague messages ("fix", "update", "wip") — suggest rewrites
If issues found, suggest interactive rebase to clean messages (with user approval).
4. Staggered push (rate limiting)
To avoid triggering GitHub bulk action / automation abuse detection:
- If pushing a single branch with < 50 commits: push normally
- If pushing multiple branches or > 50 commits:
- Push one branch at a time
- Wait 5 seconds between branch pushes
- For very large pushes (100+ commits), break into batches of 50 and wait 10 seconds between batches
- If creating a new repo and pushing initial content with multiple branches:
- Push main/default branch first
- Wait 10 seconds
- Push remaining branches one at a time with 5-second gaps
- NEVER use
git push --allorgit push --mirrorto a public remote without staggering
# Example staggered multi-branch push
for branch in main develop feature/foo; do
git push origin "$branch"
sleep 5
done5. Final confirmation
Before executing the push, present a summary:
- Repository: name and public/private status
- Branch(es) being pushed
- Number of commits
- Full commit message preview for every commit in the push range (both title and body) — even on amended commits and commits authored in this session
- Any warnings from steps 2-4
- Push strategy (direct or staggered)
Show the full commit messages with:
git log origin/main..HEAD --format="commit %h%n%n%s%n%n%b%n---"The user must visually confirm each message before push. This catches:
- Amended commits where the original audit no longer applies
- Body content that wasn't surfaced in step 3 because of grep gaps
- Anything authored ad-hoc in this session that didn't go through a content review
Wait for explicit user confirmation before pushing.
6. Push and verify
After pushing:
git push origin <branch>
# Verify
git log origin/<branch> --oneline -5Report success and the remote URL.
Configuration files
- `~/.claude/safe-push-blocklist` — Your personal pattern blocklist. One regex per line; comments start with
#. Loaded on every/safe-pushinvocation. Edit this file to add or remove patterns; never hardcode patterns in this skill file. See Install above for setup. - Repo-local `.pii-allowlist` — One regex per line, matches are excluded from PII scan (used to allow false positives like example keys in docs).
- Repo-local `.commit-msg-blocklist` — Terms that should never appear in public commit messages for this specific repo.
Notes
- This skill does NOT bypass the global pre-commit hook — they work together
- For projects with a public/private repo split (dev mirror → public release): always push to the dev repo first, sync via your sync script, then safe-push the public repo
- When in doubt, treat a repo as public
Safe Push — Examples
Example 1: Standard Push to Public Repo
Prompt:
Push my changes to the public repo.
Expected behavior: 1. Detects .public-repo marker → applies all checks 2. Scans diff: finds no secrets or PII 3. Audits commit messages: all descriptive, no blocked terms 4. Summary: "Public repo, 3 commits on main, no issues found. Push directly?" 5. User confirms → pushes → verifies with git log
---
Example 2: PII Detected in Diff
Prompt:
Push this branch to origin.
Expected behavior: 1. Scans diff → finds issues:
config.py:12— email addressjohn.doe@company.comsettings.json:8— private IP192.168.1.50.env.example:3— looks like a real API keysk-live-abc123...
2. Reports all findings with file and line number 3. Blocks push: "3 issues found. Fix these before pushing." 4. Does NOT push until resolved
---
Example 3: Vague Commit Messages
Prompt:
Safe push to the public repo.
Expected behavior: 1. PII scan passes 2. Commit message audit flags:
a1b2c3d fix— too vague, suggest: "fix: [describe what was fixed]"e4f5g6h update— too vague, suggest: "update: [describe what changed]"
3. Suggests interactive rebase to clean messages (with user approval) 4. Does not push until messages are acceptable
---
Example 4: Large Push with Staggering
Prompt:
Push all branches to the new public remote.
Expected behavior: 1. Detects multiple branches: main (120 commits), develop (45 commits), feature/auth (8 commits) 2. PII scan on all branches — clean 3. Proposes staggered strategy:
- Push
mainfirst (in batches of 50: 3 batches, 10s gaps) - Wait 10s
- Push
develop(single push, < 50 commits) - Wait 5s
- Push
feature/auth(single push)
4. User confirms → executes with progress updates
MIT License
Copyright (c) 2026 Rebecca Rae Barton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Safe Push — Reference
Secret Detection Patterns
API Keys and Tokens
| Pattern | Description |
|---|---|
AKIA[0-9A-Z]{16} | AWS Access Key ID |
[0-9a-zA-Z/+]{40} (near AWS context) | AWS Secret Access Key |
ghp_[0-9a-zA-Z]{36} | GitHub Personal Access Token |
gho_[0-9a-zA-Z]{36} | GitHub OAuth Token |
ghs_[0-9a-zA-Z]{36} | GitHub Server Token |
github_pat_[0-9a-zA-Z_]{82} | GitHub Fine-grained PAT |
xoxb-[0-9]+-[0-9]+-[a-zA-Z0-9]+ | Slack Bot Token |
xoxp-[0-9]+-[0-9]+-[a-zA-Z0-9]+ | Slack User Token |
sk-[a-zA-Z0-9]{48} | OpenAI API Key |
sk-ant-[a-zA-Z0-9-_]{90,} | Anthropic API Key |
SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43} | SendGrid API Key |
sk_live_[0-9a-zA-Z]{24,} | Stripe Secret Key |
pk_live_[0-9a-zA-Z]{24,} | Stripe Publishable Key |
sq0[a-z]{3}-[0-9A-Za-z_-]{22,} | Square API Key |
Private Keys
| Pattern | Description |
|---|---|
-----BEGIN RSA PRIVATE KEY----- | RSA Private Key |
-----BEGIN OPENSSH PRIVATE KEY----- | SSH Private Key |
-----BEGIN PGP PRIVATE KEY BLOCK----- | PGP Private Key |
-----BEGIN EC PRIVATE KEY----- | EC Private Key |
-----BEGIN DSA PRIVATE KEY----- | DSA Private Key |
Generic Secrets
| Pattern | Description |
|---|---|
password\s*[:=]\s*['"][^'"]+['"] | Hardcoded password |
secret\s*[:=]\s*['"][^'"]+['"] | Hardcoded secret |
api[_-]?key\s*[:=]\s*['"][^'"]+['"] | Generic API key assignment |
token\s*[:=]\s*['"][^'"]+['"] | Generic token assignment |
bearer\s+[a-zA-Z0-9_\-.~+/]+=* | Bearer token in code |
PII Patterns
| Pattern | Description |
|---|---|
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} | Email address |
\b\d{3}[-.]?\d{3}[-.]?\d{4}\b | US phone number |
\b\d{3}-\d{2}-\d{4}\b | SSN |
\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b (RFC 1918) | Private IP address |
RFC 1918 Private IP Ranges
10.0.0.0/8 → 10.x.x.x
172.16.0.0/12 → 172.16.x.x through 172.31.x.x
192.168.0.0/16 → 192.168.x.xAlso flag Tailscale CGNAT range: 100.64.0.0/10 (100.64.x.x through 100.127.x.x).
Staggered Push Implementation
# Multi-branch staggered push
branches=("main" "develop" "feature/new-feature")
for branch in "${branches[@]}"; do
echo "Pushing $branch..."
git push origin "$branch"
sleep 5
done
# Large commit batch push
total_commits=$(git rev-list --count origin/main..HEAD)
if [ "$total_commits" -gt 50 ]; then
echo "Large push detected ($total_commits commits). Staggering..."
# Push in batches using refspecs
commits=($(git rev-list --reverse origin/main..HEAD))
batch_size=50
for ((i=0; i<${#commits[@]}; i+=batch_size)); do
batch_end=$((i + batch_size - 1))
if [ $batch_end -ge ${#commits[@]} ]; then
git push origin HEAD:refs/heads/main
else
git push origin "${commits[$batch_end]}:refs/heads/main"
fi
echo "Pushed batch $((i/batch_size + 1)). Waiting 10s..."
sleep 10
done
fiExample .pii-allowlist
# Documentation examples
user@example\.com
test@example\.com
admin@example\.com
# RFC 5737 documentation IP ranges (safe to publish)
192\.0\.2\.\d+
198\.51\.100\.\d+
203\.0\.113\.\d+
# Example domains
example\.com
example\.org
example\.net
# Test fixtures
test-api-key-\w+
FAKE_TOKEN_\w+Example .commit-msg-blocklist
# Client names (add your own)
# client-name-here
# Internal infrastructure
# internal-hostname
# staging.internal
# Project codenames
# project-codenameCommit Message Quality Guide
Bad Messages (Flag These)
fix
update
wip
changes
stuff
miscGood Message Patterns
feat: add email validation to signup form
fix: prevent duplicate webhook deliveries
refactor: extract shared auth logic into middleware
docs: add API rate limit documentation
chore: upgrade dependencies to latest patch versionsPre-commit Hook Integration
Safe-push complements (does not replace) pre-commit hooks. Recommended pairing:
| Layer | Catches | When |
|---|---|---|
| Pre-commit hook | Secrets in staged files | Before each commit |
| Safe-push | Secrets across full diff, commit messages, push rate | Before each push |
Both layers should use the same .pii-allowlist for consistency.
# ~/.claude/safe-push-blocklist
# Personal patterns blocked from public commits and diffs.
# One regex (extended POSIX) per line. Lines starting with # are ignored.
# Loaded by the safe-push skill on every public push.
#
# These patterns are scanned against BOTH diff content and commit
# messages (title + body). Customize with values specific to YOUR
# environment, then move this file to ~/.claude/safe-push-blocklist:
#
# cp safe-push-blocklist.template ~/.claude/safe-push-blocklist
# $EDITOR ~/.claude/safe-push-blocklist
#
# Examples below are commented out. Uncomment and adapt the ones
# relevant to you, and add your own.
# === Client / customer names ===
# acme-corp
# globex-inc
# === Personal infrastructure ===
# Hostnames (your workstation, NAS, lab machines)
# myhostname(\.local)?
# Internal directory names (your workspace folders)
# my-projects-dir
# Private IP ranges you use (Tailscale, LAN)
# 100\.64\..*
# 192\.168\..*
# Device identifiers / serials
# MYDEVICEID
# Hardware models (in personal-infra context)
# Mac Studio M2
# === Self-hosted service names (when they appear in infra context) ===
# \bminiflux\b
# \bsyncthing\b
# === Universal blockers (already broadly safe to enable) ===
# Slack tokens and channel IDs
# xoxb-
# \bC[A-Z0-9]{10}\b
# Tracking IDs (paste the specific IDs you don't want public)
# G-XXXXXXXXXX
# GTM-XXXXXXX
# Add more patterns specific to your environment below.