This is a personal utilities repository designed to maintain portable, self-contained tools that persist across job changes and environment setups. The repository follows a philosophy of Docker-based, security-conscious utilities that work consistently across platforms with minimal dependency management.
- Docker-first approach: Every utility runs in an isolated Docker container
- Zero local dependencies: No need to install ffmpeg, imagemagick, rclone, or other tools locally
- Network isolation: Older utilities use
--network=noneflag for security (no network access to prevent data exfiltration) - Platform independence: Works identically on macOS, Linux, and Windows wherever Docker runs
The profile file is the primary installation mechanism for older utilities. Users simply add the contents of this file to their shell profile (.bashrc, .zshrc, etc.) to gain access to all utilities as shell functions. This approach means:
- No complex installation scripts needed
- No PATH modifications required
- Functions are immediately available in new terminal sessions
- Complete portability - just copy the profile file
The repository shows a clear evolution in utility design:
Utilities like mov-to-gif, update-pdf, reduce_framerate, heic_to_jpeg, unrar, and stabilize_video follow a simple pattern:
- Minimal Alpine Linux base images
- Single-purpose tools (ffmpeg, imagemagick, ghostscript)
- Shell functions in profile file that wrap Docker commands
- Inline execution with
docker run --rm - Security-focused with
--network=none
onedrive-backup, unraid-util, and stress represent a transition:
- Long-running container services rather than one-shot commands
- More sophisticated scripts (bash with loops, error handling)
- Environment variable configuration
- Purpose-built for specific infrastructure needs
- Still Dockerized but meant to run continuously
network-mapper and backup-photos-to-gdrive represent the current state:
- network-mapper: Full Go application with proper releases, CI/CD, multiple install methods (Homebrew, Chocolatey, Docker), extensive documentation, devcontainer development environment
- backup-photos-to-gdrive: Sophisticated bash script with retry logic, configuration validation, comprehensive environment variables, detailed documentation
Location: mov-to-gif/
Purpose: Convert QuickTime .mov files to animated GIFs for documentation
Implementation: Alpine + ffmpeg + imagemagick
- Uses ffmpeg to extract frames at 5fps with intelligent scaling
- Uses ImageMagick convert to optimize the GIF
- Credits Stack Overflow answers in source code
- Shell script:
mov-to-gif.sh
Purpose: Reduce video file size by lowering framerate to 15fps Profile function: Wraps ffmpeg in mov-to-gif container Use case: Screen recordings for colleagues where high framerate is unnecessary
Purpose: Convert Apple HEIC photos to JPEG for compatibility Profile function: Uses ImageMagick convert with 90% quality Use case: Sharing Apple photos with non-Apple users/tools
Purpose: Video stabilization using ffmpeg vidstab Profile function: Two-pass stabilization (detect then transform) Parameters: Takes zoom percentage (default 5%) Technical: Detects transforms then applies with 30-smoothing, CRF 19, slow preset
Location: update-pdf/
Purpose: Upgrade PDF files to version 1.4 for compatibility
Implementation: Alpine + ghostscript
Use case: Some upload sites require specific PDF versions
Location: stress/
Purpose: CPU, memory, and I/O stress testing container
Implementation: Sophisticated bash script with GPT-4o attribution
Features:
- Auto-detects physical CPU cores (lscpu, /proc/cpuinfo, sysctl)
- Auto-detects available memory
- Three modes: heavy (1x), medium (0.5x), light (0.25x)
- Configurable duration via
DURATIONenv var - Optional I/O thread testing via
IO_THREADSenv var - Smart worker calculation based on available resources
Location: unraid-util/
Purpose: Diagnostic container for Unraid NAS systems
Implementation: Ubuntu-based sleep-forever container
Use case: Provides tools like tcpdump that aren't available in Unraid base OS
Usage: docker exec -it util bash to access diagnostic tools
Philosophy: Ad-hoc package installation with apt install
Location: onedrive-backup/
Purpose: Continuous OneDrive backup to local storage using rclone
Implementation: rclone base image + ChatGPT-written bash script
Features:
- Hourly check with configurable
BACKUP_INTERVAL - Incremental backups (copies from last backup before syncing)
- One-year retention by default
- Requires rclone.conf with OneDrive remote named "onedrive" Philosophy: Defense against human error and cloud provider failures; "Storage is cheap, family memories are not"
Location: backup-photos-to-gdrive/
Purpose: Continuous local photos backup to Google Drive using rclone
Implementation: Modern, sophisticated bash script with extensive features
Features:
- Safe copy mode (default) vs. destructive sync mode
- Configurable intervals (default 6 hours)
- Built-in retry logic and error handling
- Configuration validation before starting
- Comprehensive logging with timestamps
- Multiple environment variables for flexibility Quality: Production-ready with extensive documentation and proper error handling
Purpose: Map Docker container IDs/names to host PIDs and UIDs
Implementation: Parses docker ps, inspects containers, reads /proc/$pid/status
Output: Container name, UID, username, PID
Use case: Troubleshooting Docker container processes on host
Purpose: Diagnostic logging for network connectivity issues Implementation: OS-aware (macOS vs Linux) network diagnostics Actions:
- Logs to
/tmp/network_blips.log - Captures gateway, interfaces, routing tables, ARP cache
- Pings Google DNS (8.8.8.8) and default gateway
- Works on both macOS (route, ifconfig, netstat) and Linux (ip) Use case: Debugging intermittent network issues with timestamped diagnostics
Purpose: Extract RAR archives using Docker
Implementation: Uses maxcnunes/unrar Docker image
Pattern: unrar e -r (extract recursively)
Location: network-mapper/
Language: Go
Status: This is the PRIMARY utility in the repository
Features:
- Cross-platform network discovery (Linux, macOS, Windows)
- Automatic subnet and gateway detection
- Port scanning and device fingerprinting
- mDNS/Bonjour discovery (Apple ecosystem)
- SSDP/UPnP discovery (media servers, IoT)
- DHCP lease table scanning
- MAC vendor identification via IEEE OUI database
- Beautiful CLI visualization with ASCII art
- Multiple installation methods (Homebrew, Chocolatey, Docker, binary releases)
Architecture:
- Professional Go codebase with proper package structure
- Multiple specialized files:
agent.go,device_detector.go,dhcp_scanner.go,dns_resolver.go,gateway.go,intelligent_discovery.go,mac_vendor.go,network_expansion.go,ping.go,scanner.go,service_discovery.go,visualizer.go - YAML-based device rules:
device_rules.yaml - Devcontainer setup for development
- Git hooks for code quality
- Comprehensive CI/CD with GitHub Actions
Documentation:
- Extensive README with badges for build status, releases, package managers
BUILD_TRANSPARENCY.mdfor addressing antivirus false positivesPACKAGE_SETUP.mdfor maintainer documentationexample_usage.mdfor user guidance- Project-specific
CLAUDE.mdwith AI assistant guidelines
CI/CD Pipeline:
- Multi-platform builds (Linux amd64/arm64, macOS, Windows)
- Automated releases with GitHub Releases
- Package manager automation (Homebrew tap, Chocolatey)
- Docker multi-arch images (GHCR)
- Smoke testing and release validation
- Automated package updates
Philosophy: "A lightweight home network security audit tool - not a high-power security tool for finding hidden subnets, but helping home users understand their environment"
- Shebang: Uses
#!/bin/shfor POSIX compatibility or#!/bin/bashwhen bash-specific features are needed - Error handling: Modern scripts use
set -efor fail-fast behavior - Configurability: Environment variables with sensible defaults (e.g.,
MODE="${MODE:-heavy}") - Documentation: Inline comments crediting sources (Stack Overflow, GPT-4o)
- Output: Echo statements for user feedback during execution
- Safety: Platform detection (
uname, conditional logic) for cross-platform scripts
FROM alpine:3.16.2
RUN apk add tool-package
COPY script.sh /usr/local/bin/tool-name- Minimal Alpine base (specific version pinning)
- Single package installation
- Script copied to
/usr/local/bin/for PATH access - No ENTRYPOINT - invoked explicitly from shell function
function tool_name() {
docker run --rm -it \
--volume=$(pwd):/content/ \
--workdir=/content/ \
--network=none \
container-name command "$1"
}--rmfor automatic cleanup-itfor interactive terminal- Volume mount current directory
- Set workdir to mounted volume
--network=nonefor security isolation- Pass first argument to container command
FROM base-image
RUN apt-get update && apt-get install -y packages
COPY script.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]- More sophisticated base images (Ubuntu for unraid-util)
- Scripts become entrypoints
- Designed to run continuously with sleep loops
- Environment variable configuration
- Standard practices: Proper package structure, separated concerns
- CLI framework: Likely using cobra or similar
- Error handling: Go idiomatic error returns
- Cross-platform: Build tags or conditional compilation for OS-specific code
- Testing: Test files alongside implementation
- Dependencies: Go modules with
go.modandgo.sum
- Markdown everywhere: README.md for all major components
- Emoji headers: Makes documentation more approachable (π, π¬, π§, etc.)
- Clear hierarchy: Overview β Installation β Usage β Details
- Why sections: Explains rationale and philosophy
- Security notes: Transparent about Docker image provenance, security measures
- Attribution: Credits tools, contributors, and AI assistance
- Transparent build process: GitHub Actions workflows are public
- Network isolation:
--network=noneon utilities that don't need network - Minimal permissions: Read-only where possible
- Image provenance: Documents Docker Hub publishing pipeline
- Account security: Documents use of FIDO2/WebAuthn for GitHub access
- Dependency pinning: Specific Alpine versions, Go dependency locking
- Multi-stage workflows: Separate build, test, release, validation
- Multi-platform builds: Uses Docker buildx for amd64/arm64
- Conditional execution: Release workflows trigger on release publish
- Secrets management: Uses GitHub Secrets for Docker Hub, package managers
- Validation steps: Smoke tests after releases
- Automated updates: Package manager update workflows
- Release notes: CI workflows do NOT edit releases to avoid permission issues; release notes are complete at creation time via
gh release create
This repository is a monorepo containing multiple independent utilities. Each utility has its own version lifecycle, release cadence, and potentially different maintainers. This creates a challenge for tagging and releases that traditional single-project repositories don't face.
All existing tags from v1.0 through v2.8.3 refer exclusively to network-mapper releases. This includes:
- Early tags without 'v' prefix:
1.0,1.1,1.1.1,1.2.1-1.2.6 - Modern tags with 'v' prefix:
v1.2.1,v1.3.0,v1.4.0,v1.5.0,v1.5.1,v2.0.0-v2.8.3
The tag v1.0.0-smart-crop was an attempt to version the smart-crop-video utility, but this approach has problems:
- It still triggered network-mapper build workflows (matching the
v*pattern) - The suffix approach is ambiguous and doesn't follow standard conventions
- Version numbers would conflict across utilities (both utilities could want v1.0.0)
Going forward, ALL releases MUST use utility-prefixed tags:
<utility-name>-v<version>
network-mapper-v2.9.0
smart-crop-video-v1.0.0
backup-photos-to-gdrive-v1.0.0
onedrive-backup-v1.0.0
stress-v1.0.0
- Utility name prefix: Use the exact directory name from the repository
- Dash separator: Always use
-between utility name and version - Version format:
v<major>.<minor>.<patch>following semantic versioning - No exceptions: Even if a utility is the "primary" utility, it must use the prefix
IMPORTANT:
- Always create a Pull Request for review before releasing
- Always use
gh(GitHub CLI) to create releases - Do not rely on manual tagging alone
When you're ready to release a utility, follow these steps:
Update version numbers in relevant files for the utility (e.g., go.mod, documentation, package files)
# Create feature/release branch if not already on one
git checkout -b feature/release-smart-crop-video-v1.2.0
# Stage and commit all changes
git add <modified-files>
git commit -m "Release message with feature summary
π€ Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>"# Push feature branch to origin
git push -u origin feature/release-smart-crop-video-v1.2.0
# Create Pull Request with detailed release notes
gh pr create --title "smart-crop-video v1.2.0 - Feature Title" --body "$(cat <<'EOF'
## Summary
Brief overview of the release and major changes.
## π Major Features
- Feature 1 description
- Feature 2 description
## π§ Configuration Options
```bash
# Example configuration
OPTION=value utility command- Fix 1
- Fix 2
Technical information for developers...
π€ Generated with Claude Code EOF )"
#### 4. Wait for PR Review and Merge
**CRITICAL**: Do not proceed with tagging and release until the PR has been:
- Reviewed by repository owner
- All CI/CD checks passing
- Merged to main branch
#### 5. Switch to Main and Pull Latest
```bash
# After PR is merged, switch to main and pull
git checkout main
git pull origin main
# Example for smart-crop-video v1.2.0
git tag smart-crop-video-v1.2.0git push origin smart-crop-video-v1.2.0CRITICAL: Use gh release create to create the GitHub release with proper release notes:
gh release create smart-crop-video-v1.2.0 \
--title "smart-crop-video v1.2.0 - Feature Title" \
--notes "$(cat <<'EOF'
## π Major Features
- Feature 1 description
- Feature 2 description
## π§ Configuration Options
```bash
# Example configuration
OPTION=value utility command- Fix 1
- Fix 2
Technical information for developers...
π€ Generated with Claude Code EOF )"
This creates a properly formatted GitHub Release with:
- Clean markdown formatting
- Organized sections (Features, Config, Bug Fixes, etc.)
- Release notes that are searchable and linkable
- Automatic association with the tag
**IMPORTANT for Docker-based utilities**: Always include Docker image information in the initial release notes when using `gh release create`. The CI/CD workflow will build and push Docker images but does NOT update release notes (to avoid permission issues). Example Docker section to include:
```markdown
## Docker Image
The Docker image is available at:
\`\`\`bash
docker pull ghcr.io/nickborgers/<utility-name>:1.2.0
docker pull ghcr.io/nickborgers/<utility-name>:latest
\`\`\`
### Supported Platforms
- linux/amd64
- linux/arm64
This ensures users have complete information immediately without requiring workflow permissions to edit releases.
After creating the release:
- Visit the GitHub Releases page to confirm it was created
- Check GitHub Actions to ensure any CI/CD workflows triggered correctly
- For network-mapper: confirm Homebrew and Chocolatey packages were updated
- For Docker-based utilities: confirm images were published to GHCR (GitHub Container Registry)
- Code Review: Repository owner can review changes before release
- CI/CD Validation: All tests and checks run before merging
- Discussion: Opportunity to discuss changes and get feedback
- History: Clear audit trail of what was released and when
- Rollback: Easy to identify and revert problematic changes
- Consistency: All releases have properly formatted notes
- Discoverability: Release notes are searchable on GitHub
- Automation: Can be scripted and integrated into workflows
- Rich Content: Supports markdown, emojis, code blocks
- Immediate: Creates release instantly, not dependent on CI/CD
# 1. Create feature branch and commit changes
git checkout -b feature/release-smart-crop-video-v1.2.0
git add smart-crop-video.py README.md
git commit -m "Add intelligent acceleration feature
Major improvements to scene selection...
π€ Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>"
# 2. Push branch and create PR
git push -u origin feature/release-smart-crop-video-v1.2.0
gh pr create --title "smart-crop-video v1.2.0 - Interactive Scene Selection" \
--body "Release notes here..."
# 3. Wait for PR review and merge by repository owner
# 4. After merge, switch to main and create release
git checkout main
git pull origin main
git tag smart-crop-video-v1.2.0
git push origin smart-crop-video-v1.2.0
# 5. Create GitHub release
gh release create smart-crop-video-v1.2.0 \
--title "smart-crop-video v1.2.0 - Interactive Scene Selection" \
--notes "Release notes here..."
# 6. Verify
gh release view smart-crop-video-v1.2.0As of this writing, the following workflows need to be updated to properly handle utility-prefixed tags:
-
.github/workflows/release.yml:- Currently triggers on
v*tags (matches ALL version tags) - Should parse the tag prefix to determine which utility to build
- Example:
network-mapper-v2.9.0should only build network-mapper
- Currently triggers on
-
.github/workflows/publish.yml:- Currently builds ALL utilities' Docker images for ANY release
- Should be split into utility-specific workflows, or add conditional logic based on tag prefix
- Example:
smart-crop-video-v1.0.0should only build smart-crop-video Docker image
-
.github/workflows/update-packages.yml:- Already has detection logic to check for network-mapper assets
- Should additionally check the tag prefix for clarity
- Only network-mapper should trigger Homebrew/Chocolatey updates
For maximum clarity, consider creating utility-specific workflows:
.github/workflows/release-network-mapper.yml(triggers onnetwork-mapper-v*).github/workflows/release-smart-crop-video.yml(triggers onsmart-crop-video-v*).github/workflows/release-backup-photos.yml(triggers onbackup-photos-to-gdrive-v*)
Alternatively, use a single workflow with conditional steps based on tag prefix parsing.
Do NOT rename or delete existing tags. They are part of the release history and users may depend on them. Instead:
- Document the transition: This section serves as that documentation
- Continue from current version: The next network-mapper release should be
network-mapper-v2.9.0(or whatever follows v2.8.3) - Update documentation: README files should reference the new tag format
- Maintain compatibility: Keep existing GitHub releases and their download URLs intact
When creating a release:
- Always use the utility-prefixed format: Never create tags like
v1.0.0without a utility prefix - Check existing versions: Look at existing tags for the specific utility to determine the next version number
- Update relevant workflows: Ensure CI/CD workflows will properly handle the new tag
- Test before tagging: Verify builds work locally before creating the tag
- Verify after release: Always check that workflows completed successfully
- Don't batch releases: Release one utility at a time to avoid confusion
To see all tags for a specific utility:
# List all network-mapper releases
git tag -l 'network-mapper-v*'
# List all smart-crop-video releases
git tag -l 'smart-crop-video-v*'
# List all tags (sorted by version)
git tag --list --sort=-version:refnameEach utility maintains its own version numbers independently:
network-mapper-v2.9.0can coexist withsmart-crop-video-v1.0.0- Version numbers have no relation between utilities
- Breaking changes in one utility don't affect others
- Each utility follows semantic versioning for its own scope
The profile file is a self-contained installation artifact. Users can:
- Clone the repo and
cat profile >> ~/.zshrc - Or just copy-paste the profile contents manually
- Reload shell or source the profile
- All functions immediately available
No additional files required - the profile file references Docker Hub images that are pre-built by CI/CD.
network-mapper uses professional distribution channels:
- Homebrew:
brew install nickborgers/tap/network-mapper - Chocolatey:
choco install network-mapper - Docker:
docker run ghcr.io/nickborgers/network-mapper:latest - Binary: Download from GitHub Releases
- Portability over complexity: Tools should follow you across jobs/machines
- Security by isolation: Docker + network-none prevents data leaks
- Zero dependency installation: Just Docker + shell profile
- Self-documenting: README files explain why and how
The repository shows increasing sophistication:
- 2020s early: Simple ffmpeg/imagemagick wrappers
- Mid: Service containers with loop-based monitoring
- Recent: Full CI/CD, package managers, professional Go applications
- Early utilities lack versioning beyond Docker tags
- Shell functions in profile don't have
--helpflags - No automated testing for shell functions
- Docker image security scanning not visible (if present)
- Proper semantic versioning
- Automated releases
- Multiple install methods
- Comprehensive documentation
- Devcontainer for contributor onboarding
- Build transparency documentation
- CI/CD with validation
- Build and test using devcontainer configuration in its folder
- After cutting a release, always confirm pipelines worked and release was successful
- This is a home network tool, not a high-power security scanner
- Goal: help users understand their environment, not find deliberately hidden subnets
- Docker must be installed and accessible
- For shell utilities: test on both Linux and macOS (Windows less critical for profile-based tools)
- Always consider security implications of network access
- Document the "why" not just the "how"
- mov-to-gif credits Stack Overflow users alexey-kozhevnikov and pleasestand
- stress script credits GPT-4o
- onedrive-backup script from ChatGPT
- Michael Jarvis credited for the original inspiration of portable shell environments
- Could add
--helpto shell functions - Consider versioning for Docker images beyond just
latest - Automated security scanning in CI/CD
- Testing framework for shell functions
- Consider migrating remaining utilities to modern approach with proper releases