Utilities
Section titled “Utilities”New utility? Use the
/scaffold-utilskill. It handles the decision, scaffolding, and boilerplate for you.
Two Utility Families
Section titled “Two Utility Families”| WSL Utilities | Windows Utilities | |
|---|---|---|
| Root | /home/ta/utils/ | D:\FSS\Software\Utils\PythonUtils\ |
| Language | Python (uv tool install) or Bash | Python via uv run |
| Install | uv tool install . → global CLI binary | uv sync once, then run from project dir |
| Run | utility-name [args] from anywhere in WSL | uv run utility-name from project folder |
| Scheduler | WSL cron (if needed) | Windows Task Scheduler or WSL cron |
WSL utility subdirectories:
| Subdir | Purpose | Existing |
|---|---|---|
ai/ | AI-assisted processing, content pipelines | pdf-to-md (production) · source_summarizer (incomplete) · medium_digest (incomplete) |
web/ | Web deployment, site tooling | web-deploy |
system/ | WSL/Linux system management | — |
shell-scripts/ | Bash/shell automation | — |
Existing Windows utilities: my_backup
Decision Guide: WSL vs Windows?
Section titled “Decision Guide: WSL vs Windows?”Build a WSL utility when:
- It runs naturally in WSL/Linux (CLI tools, Bash, Python scripts)
- It calls Gemini, Claude, or another AI API → place in
ai/ - It relates to web deployment or site tooling → place in
web/ - It manages WSL/Linux system configuration → place in
system/ - It’s a Bash/shell script for automation → place in
shell-scripts/
Build a Windows utility when:
- It needs Windows-native access (Task Scheduler, wbAdmin, Robocopy, Windows Defender, registry)
- It backs up or mirrors files across Windows drives
- It must be scheduled via Task Scheduler (not just cron)
- It integrates with Windows apps (Kopia, 7-Zip, EspoCRM)
Either works when:
- Pure Python logic (file transforms, data processing, reporting)
- Decide based on where it will run most naturally
Quality Tiers
Section titled “Quality Tiers”Quick-and-Dirty
Section titled “Quick-and-Dirty”For one-off scripts or utilities you’ll use a handful of times.
Artifacts:
src/<util_name>/cli.py— main scriptpyproject.toml— entry point + dependenciesREADME.md— short: purpose, install, usage examples.env.example— if it needs secrets (ASCII-only comments)
Production-Grade
Section titled “Production-Grade”For utilities you’ll rely on daily, share, or extend over time.
Artifacts (all of quick-and-dirty, plus):
config.yaml— runtime SSOT for all configurable settingssrc/<util_name>/— modular package (cli.py,core.py,config.py,ui.py)tests/— pytest suitelogs/— rotational text logs (committed as empty dir via.gitkeep)docs/— extended docs (RESTORE.md, architecture notes)config/— static config files (ignore patterns, templates)
Standard Stack
Section titled “Standard Stack”| Concern | Tool | Notes |
|---|---|---|
| Package management | uv | Always — never pip, poetry, or venv directly |
| CLI output | rich | Console, Panel, status spinners, ✓/✗ indicators |
| CLI parsing | argparse or typer | argparse for simple; typer for complex multi-command |
| Configuration | config.yaml + pyyaml | SSOT for all settings; secrets stay in .env |
| Secrets | python-dotenv + .env | Never committed; .env.example has placeholder values |
| AI (Gemini) | google-genai | Dedicate a separate GEMINI_API_KEY per utility (quota isolation) |
| AI (Claude) | anthropic | Use claude-sonnet-4-6 or claude-haiku-4-5-20251001 |
| Logging | loguru | For production utilities; print + Rich acceptable for quick-and-dirty |
| Testing | pytest | Production tier only |
CLI always uses Rich. No raw print for status output. Every CLI must show:
- Progress/status (spinner or progress bar for long ops)
- ✓ / ✗ indicators per step
- Clean error messages — no raw tracebacks to the user
pyproject.toml Structure
Section titled “pyproject.toml Structure”[build-system]requires = ["hatchling"]build-backend = "hatchling.build"
[project]name = "utility-name"version = "0.1.0"description = "One-line description of what it does"requires-python = ">=3.10"dependencies = [ "rich>=13.0.0", "pyyaml>=6.0", "python-dotenv>=1.0.0", # add AI deps if needed: # "google-genai>=1.0.0", # "anthropic>=0.84.0",]
[project.scripts]utility-name = "utility_name.cli:main"
[tool.hatch.build.targets.wheel]packages = ["src/utility_name"]WSL AI utility install: uv tool install . → binary available globally as utility-name
Windows utility install: uv sync → run as uv run utility-name from project directory
.env.example Template
Section titled “.env.example Template”# API Keys# Get your Gemini API key from: https://aistudio.google.com/GEMINI_API_KEY=your_gemini_api_key_here
# Optional: override defaults# OUTPUT_DIR=/path/to/outputRules:
- ASCII-only comments (no Unicode, no emoji in
.env.example) - Placeholder values only — never real credentials
- Write
.envfiles from WSL, not Windows (Windows clipboard embeds invisible Unicode)
config.yaml Structure (WSL AI utilities)
Section titled “config.yaml Structure (WSL AI utilities)”defaults: provider: gemini # or 'claude' gemini_model: gemini-2.5-flash claude_model: claude-sonnet-4-6 output_dir: /path/to/output
# Source-specific or feature-specific sections belowsources: source_name: key: valueREADME Template Structure
Section titled “README Template Structure”Modelled on my_backup — the gold standard. Every README must include these sections in this order:
- Tagline + one-line description (H1 title)
- Features list — bullet points, concrete capabilities, not abstract goals
- Quick Start (CLI) — most common command first; all flags with examples
- Installation — exact commands:
- WSL AI:
uv tool install . - Windows:
uv sync, thenuv run utility-name
- WSL AI:
- Where to run — WSL or Windows? Why?
- API Key Setup (if AI) — where to get keys, what to put in
.env - Configuration —
config.yamlstructure and key settings - File Locations — table of: input dirs, output dirs, logs, config
- Development — how to run from source, run tests, contribute
Pattern: WSL AI Utility (pdf-to-md)
Section titled “Pattern: WSL AI Utility (pdf-to-md)”Location: /home/ta/utils/ai/pdf2md/
Structure:
pdf2md/├── src/pdf2md/│ ├── cli.py # Entry point: pdf-to-md│ ├── processor.py # Core logic│ └── config.py # Config loader├── config.yaml # SSOT: provider, models, output dirs, tag vocab├── pyproject.toml # Entry points + deps├── README.md└── .env # GEMINI_API_KEY (not committed)Key patterns:
config.yamldrives all runtime settings (model, output path, tag vocabulary)- Dedicated
GEMINI_API_KEY— not shared with other utilities uv tool install .makespdf-to-mdavailable as a global CLI- Rich Console for all output
Pattern: Windows Utility (my_backup)
Section titled “Pattern: Windows Utility (my_backup)”Location: D:\FSS\Software\Utils\PythonUtils\my_backup\
Structure:
my_backup/├── src/my_backup/│ ├── main.py # Entry point: uv run my_backup│ ├── config.py # PROJECT_ROOT + config loader│ ├── context.py # Pipeline state (ctx object)│ ├── pipeline.py # Execution orchestration│ ├── tasks.py # Business logic│ ├── ui.py # Rich terminal dashboard│ └── utils.py # Shell, logging infrastructure├── tests/├── docs/├── config/├── hooks/ # Pre-backup scripts├── logs/ # Rotational text logs├── config.yaml├── pyproject.toml└── README.mdKey patterns:
- Context object (
ctx) passed to every task — accumulates failures/warnings config.yamlis SSOT; secrets in.env- Multiple entry points (one per subcommand/script)
- Comprehensive pytest suite with restore verification
Coding Standards
Section titled “Coding Standards”- Type hints required on all non-trivial functions
- PEP 8 — use Ruff for linting
- Error handling: clean user-facing messages via Rich; no raw tracebacks
- Logging: hierarchical text format with timestamps; rotate logs (keep last 5)
- No hardcoded paths — all paths via
config.yamlor resolved relative toPROJECT_ROOT - Naming: lowercase with hyphens for CLI commands;
verb-noun-detailformat
Full dev rules:
D:\FSS\KB\Business\03_Processes\Software Dev\GlobalDevRules.md