Skip to content

Mission: Build professional, robust, and efficient software solutions using world-class standards.

Note: These are production standards. For learning side projects, prioritize speed and experimentation over perfection.

AI Agents: The operative subset of these rules (package managers, Python standards, web stack) is also in ~/.claude/CLAUDE.md → ## Dev Standards, which AI agents read at session start. Keep both in sync when updating core tooling decisions.

  • PRIORITY 1: Clear, semantic, understandable code that enhances maintainability
  • Simple and clear is ALWAYS superior to clever and complex
  • Exception: When execution speed is explicitly paramount, provide clear explanatory comments
  • Code should be self-documenting; comments explain WHY, not WHAT
  • Never use hacks or rigid fixed solutions; use robust solutions that flexibly handle all edge cases

When providing solutions, ALWAYS:

  • Ask for more details if needed to be very clear on the objective
  • Add “or better” to any objective to be achieved
  • Explore innovative, unconventional solutions combining effective insights in novel ways

Definitions of “Better” for Tech/Code:

  • Simpler, more understandable, more maintainable
  • Lower security risks, lower future risk (tech discontinuation)
  • Less vendor lock-in, better FOSS alignment
  • More efficient resource usage
  • Better error handling and debugging capability
  • Primary AI Tools: Currently using Claude Code, Cursor 2.0, Gemini 3.0
  • Supporting AI Tools: Crew AI, n8n when appropriate
  • Leverage AI for: Code generation, documentation, testing, refactoring, project orchestration
  • Critical: ALWAYS review and test AI-generated code. Never blindly commit.
  • Prefer FOSS solutions when functionality and deliverability don’t suffer
  • Avoid monthly subscription lock-ins unless significantly superior
  • Balance: Don’t be penny-wise and pound-foolish with time vs. cost
  • Priority Order: Functional and robust first. Then optimize for speed.
  • Speed is a feature, but not at the expense of correctness or maintainability
  • Ship minimal JavaScript
  • Optimize assets
  • Use SSG (Static Site Generation) by default
  • Profile before optimizing; document performance trade-offs
  • Site Framework: Astro (latest) for all websites - static content, blogs, marketing sites
  • Web Applications / PWAs: SvelteKit (adapter-static + Cloudflare Pages) for complex, state-heavy applications
  • UI Components: Use framework-appropriate component libraries
    • Currently using Shadcn-Svelte for Svelte/SvelteKit projects — add components via CLI (npx shadcn-svelte@latest add <component>)
  • Styling: Tailwind CSS
    • v4 is the target standard; SvelteKit apps currently use v3 for stability (migrate when shadcn-svelte v4 integration matures)
    • Use utility classes for layout and spacing
    • Use @apply or CSS variables for theming and reusable components
  • i18n: Paraglide (@inlang/paraglide-sveltekit) for SvelteKit apps requiring multiple languages — compiler-based, type-safe, zero runtime overhead
  • Design System: CSS variables + Utopia fluid responsive design
  • Content: Markdown (.md) or MDX (.mdx) for blog/documentation content
  • CMS: Currently using Decap CMS for blog content management
  • Static content site/blog: Astro + minimal JavaScript
  • Lightweight interactivity (menus, modals, simple state): Alpine.js or vanilla JS
  • Complex web application: Svelte or React-based framework
  • Default Rule: Use the simplest appropriate tool. Avoid over-engineering.
  • Node.js: Currently using pnpm (fast, disk-efficient)
  • Python: Currently using UV (replaces pip/poetry)
  • TypeScript: Strict mode required for production code. No any unless absolutely necessary.
  • Python: Type hints required for all non-trivial scripts. Follow PEP 8.
  • Primary: Currently using MariaDB for direct EspoCRM and Sendy integration
  • Modern Projects: Currently using PostgreSQL with Supabase
  • Local Development: SQLite with proper migration path to production
  • ORM: Currently using Prisma for type-safe database access
  • REST APIs: Follow RESTful conventions
  • Authentication: Currently using Supabase Auth or EspoCRM Portal
  • Error Handling: Consistent error response format
  • Rate Limiting: Implement for all public endpoints
  • Documentation: OpenAPI/Swagger for all endpoints
  • Primary: Currently using Cloudflare Pages for unbeatable performance
  • Alternative: Vercel for Jamstack hosting
  • CDN: Leverage Cloudflare’s global network
  • Build: Automatic builds from Git commits
  • Managed VPS: Currently using Cloudways on DigitalOcean Toronto
  • PHP Applications: EspoCRM, Sendy on LAMP stack
  • Node.js: For Astro SSR and APIs
  • Database: MariaDB on same VPS for performance
  • Version Control: GitHub with GitHub Actions for CI/CD
  • Secrets Management: Platform built-ins (Cloudflare Pages, n8n Cloud) or currently using Doppler
  • Monitoring: Currently using Uptime Kuma for service monitoring
  • Error Tracking: Currently using Sentry or similar for production error logging
project/
├── src/
│ ├── pages/ # Astro pages or app routes
│ ├── components/ # Reusable components
│ ├── layouts/ # Layout templates
│ ├── content/ # Markdown content (if applicable)
│ ├── lib/ # Utilities and helpers
│ ├── styles/ # Global CSS + design tokens
│ ├── assets/ # Images, fonts, static files
│ └── config/ # Configuration files
├── scripts/ # Build scripts, utilities
├── public/ # Static assets
├── dist/ # Build output (gitignored)
├── tests/ # Test files
├── docs/ # Documentation
│ └── Lessons.md # Learnings from development process
└── README.md # Setup and deployment guide
  • Files/Directories: kebab-case (e.g., my-component.astro, user-profile/)
  • Components: PascalCase (e.g., Button.astro, HeroSection.svelte)
  • Variables/Functions: camelCase (e.g., getUserData, isValid)
  • Constants: UPPER_SNAKE_CASE (e.g., MAX_RETRIES, API_BASE_URL)
  • Use descriptive, searchable names - avoid abbreviations and mental mapping
  • Functions/methods: Use verbs (calculateTotal, getUserData)
  • Variables: Use nouns (userEmail, totalAmount)
  • Follow SOLID principles
  • Prefer composition over inheritance
  • Use dependency injection for testability
  • Design for failure - assume things will break
  • Graceful Failure: Applications should never crash silently
  • Fail fast and fail clearly
  • Use specific exception types
  • Logging:
    • Dev: Console logging
    • Prod: Structured logging with correlation IDs in markdown format
    • Log errors with context (what, when, why)
  • Notification: Critical errors must notify developer (Email/SMS)
  • Provide actionable error messages
  • README.md for every project with setup instructions
  • Inline comments for complex business logic only (WHY, not WHAT)
  • API documentation for all public interfaces
  • Keep documentation close to code (avoid separate wikis)
  • Architecture Decisions: Document in Obsidian knowledge base as ADRs
  • Maintain single source of truth for architectural decisions
  • README.md: Setup, deployment, and contribution guidelines for every project
  • docs/Lessons.md: Capture learnings from development process
    • Document when AI or human struggles to produce results
    • Record solutions that worked well
    • Note patterns to avoid
    • Purpose: Make future development more effective and efficient
  • Inline Comments: Only for complex business logic (explain WHY, not WHAT)
  • API Documentation: Generate from OpenAPI specifications for all endpoints
  • Component Stories: Use Storybook or similar for component documentation when appropriate
  • ADRs (Architecture Decision Records): Document in Obsidian knowledge base
  • Tech Stack Decisions: Link to relevant business processes and rationale
  • Single Source of Truth: This Global-Dev-Rules.md for all development standards
  • Never commit secrets or credentials
  • Validate all inputs (client-side + server-side verification)
  • Use parameterized queries only (prevent SQL injection)
  • Follow principle of least privilege
  • Content Security Policy: Strict CSP headers
  • HTTPS: Enforce SSL/TLS everywhere
  • XSS Prevention: Escape all user content
  • CORS: Strict CORS policy configuration
  • Regular CVE scanning: Use tools like uv audit, pip-audit, safety check, or snyk
  • Keep dependencies updated to patched versions
  • Automate security scanning in CI/CD pipeline
  • Balance security patches with stability (not bleeding-edge, but not stale)
  • LCP (Largest Contentful Paint): Optimize images, lazy loading, critical resource hints
  • FID (First Input Delay): Minimize JavaScript, defer non-critical scripts
  • CLS (Cumulative Layout Shift): Define image dimensions, avoid layout shifts
  • Target: All metrics in “Good” range (green)
  • Images: Use modern formats (WebP, AVIF), responsive images with proper dimensions
  • CSS: Critical CSS inline, defer non-critical styles
  • JavaScript: Code splitting, tree shaking, minimal bundles
  • Fonts: Font display swap, preload critical fonts
  • Static Assets: Long cache headers (1 year)
  • HTML: Short cache with ETags
  • API Responses: Appropriate cache based on content type
  • CDN: Leverage Cloudflare’s caching capabilities
  • ARIA labels for interactive elements
  • Semantic HTML
  • Keyboard navigation support
  • Color contrast compliance (WCAG AA minimum)
  • Screen reader testing for critical flows

Mobile browsers enforce a minimum ~44-45px touch target on <button> elements, overriding CSS width/height regardless of units (rem, em, px). A small toggle button styled as a pill (e.g. 34×19px) will render as a square on mobile.

Fix: Use <span role="switch" tabindex="0"> (or <div role="...">) for custom-styled interactive controls. Inline/block elements don’t receive touch-target inflation. Add keyboard handlers (keydown for Space/Enter) for full accessibility if needed beyond basic dev tools.

Cloudflare _headers not applied by local dev servers

Section titled “Cloudflare _headers not applied by local dev servers”

public/_headers (Cloudflare Pages response header rules) is served as a plain static file by Python http.server and most local dev servers — it is not interpreted as HTTP headers. CSP-dependent bugs (blocked iframes, ORB-blocked images, mixed content) are invisible locally and only appear on the deployed Cloudflare Pages site.

Fix: Always test CSP-related behavior with a production or preview deployment, not local. For the monorepo template site: use web-deploy template online (not local) when debugging anything blocked by response headers.

Caching / headers / PWA freshness (hard-won, focus-pages bug recurred 3×)

Section titled “Caching / headers / PWA freshness (hard-won, focus-pages bug recurred 3×)”
  • Identify the actual web host BEFORE applying any header/cache fix — the mechanism is server-specific. .htaccess is Apache-only (IIS ignores it and even 404s .ht*); IIS/Plesk-Windows needs web.config (<clientCache cacheControlMode="DisableCache"/>); Cloudflare Pages needs _headers. Applying the wrong file is a silent no-op. Check first: curl -sI <url> → read the server: header. (talbotstevens.com = IIS today, migrating to Apache — so its focus pages ship BOTH web.config + .htaccess.)
  • Never trust HTTP cache behavior for Android PWA freshness. A no-cache header only governs future responses — it cannot evict an already-poisoned heuristic cache entry, and location.reload() honors that entry instead of hitting the network (iOS/Safari revalidates; Android Chrome does not). The durable, host-independent fix is client-side: stamp a unique <meta name="focus-build"> per build, and on load/resume fetch(url+'?_='+Date.now(), {cache:'no-store'}) — if the live build id differs, location.replace('?v='+id) (guaranteed cache-miss → fresh). Degrade gracefully offline.
  • Verify the mechanism actually landed live — uploaded ≠ applied. After any header/cache change, confirm on the wire: curl -sI <url> | grep -i cache-control. A deployed file proves nothing; only the live response header does.
  • Dedicated Gemini API key per utility — Gemini’s free tier quota is shared across all tools using the same key. Each AI utility must have its own GEMINI_API_KEY in its local .env to avoid cross-tool quota conflicts (e.g. pdf2md/.env, source_summarizer/.env).
  • Write .env files from WSL, not Windows — Copy-pasting .env content from Windows silently embeds Unicode/emoji characters in comments, garbling the file when Python’s dotenv reads it. Always write .env directly in WSL. Use ASCII-only comments in .env.example.
  • WSL cron + Windows binary paths — When a WSL cron job calls Windows binaries, use /mnt/c/... paths for discovery (os.path.exists, glob.glob). WSL interop handles execution transparently, but Linux Python cannot resolve C:\... backslash paths. Triggered whenever a refactor switches from uv.exe (Windows Python) to uv run (Linux Python) without updating path constants.
  • uv tool install breaks __file__-relative paths — When a Python CLI is installed via uv tool install, __file__ resolves to the tool’s site-packages, not the source tree. Use Path(os.environ.get("TOOL_HOME", "/known/absolute/path")) for config/data file paths in tools that have a fixed install location.
  • load_dotenv() with no path uses CWD — unreliable in cron — CWD is unpredictable in cron jobs. Always use load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), '.env')) so the .env loads from the module’s own directory, regardless of where the process was launched.
  • Schedule monitoring jobs AFTER the jobs they monitor — A monitor that runs at 6 AM before the 10 AM jobs it watches will always false-alarm. Set the monitor’s cron time to after the last monitored job in the day (e.g. if last job is 1 PM, run monitor at 2 PM).
  • set VAR=value && in cmd.exe includes trailing space in the valueset PYTHONUTF8=1 && sets PYTHONUTF8 to "1 " (with trailing space). Python’s PYTHONUTF8 only accepts exactly "0" or "1" — the space causes a fatal crash before any Python runs. Use the quoted form set "VAR=value" && (strips trailing space) or just omit set entirely if not needed.
  • Path("D:") in Python is CWD-relative, not drive rootPath("D:") / "foo" resolves to D:<cwd>\foo, not D:\foo. When addressing a Windows drive root, use Path("D:/") or Path("D:\\") explicitly.
  • External HTTP data sources must fail gracefully, not crash the pipeline — Secondary/validation sources (price feeds, external APIs) will go down or add bot-verification walls. Guard all external HTTP calls with except requests.exceptions.RequestException: return [] so one unavailable source doesn’t abort the whole update. stooq.com added a JS bot-challenge ~2026-06-14 and is no longer usable via requests.
  • PWA manifest background_color must contrast with favicon SVG foreground — If the favicon SVG is monochromatic (e.g. #004425 leaf on transparent), using the same color as background_color makes it invisible on the Android splash screen and homescreen icon. Use white (#ffffff) or a neutral background when the favicon has no built-in background fill.
  • WSL→Windows .exe interop breaks silently when /etc/binfmt.d/WSLInterop.conf exists but is empty — WSL distros booting with systemd=true ([boot] systemd=true in /etc/wsl.conf, or now default on newer WSL) register the WSLInterop binfmt handler via this conf file instead of automatically via legacy init. If the file exists but has no content, systemctl status systemd-binfmt reports success while registering nothing — so any WSL process trying to exec a Windows .exe (powershell.exe, cmd.exe, etc. via subprocess) silently fails with no clear error pointing at the cause. Check cat /proc/sys/fs/binfmt_misc/WSLInterop (should print enabled) and the conf file’s actual content, not just its existence, before assuming interop is broken for some other reason. Fix: echo ':WSLInterop:M::MZ::/init:PF' | sudo tee /etc/binfmt.d/WSLInterop.conf && sudo systemctl restart systemd-binfmt. Discovered: web-deploy auto-open-browser regression, 2026-07-08.
  • A WSL Claude session cannot live-verify Windows-native Selenium/browser automation — no local Chrome/Selenium is available in WSL, and WSL→Windows interop may itself be down (as above). curl/WebFetch can’t render JS or hold an authenticated session, so a post-login SPA page (or any JS-rendered content) is invisible from WSL. Don’t guess at a DOM/selector fix blind. Instead: broaden error handling, add failure-diagnostic capture (screenshot + page source + URL, written to a debug folder on the next real failure) to the script itself, and ask the user to trigger one real run on Windows — then read the captured artifacts to write the actual fix. Discovered: my_backup Dynalist-capture timeout, 2026-07-08/09.
  • Commit Messages: Use conventional commits format
    • feat:, fix:, docs:, refactor:, test:, chore:
  • Branching: Feature branches, no direct commits to main
  • Code Reviews: Required for all changes
  • Atomic Commits: One logical change per commit
  1. Plan: Define objective and requirements clearly, incorporating insights from docs/Lessons.md
  2. Generate: Use AI tools for boilerplate, refactoring, or implementations
  3. Verify: ALWAYS review and test AI-generated code
  4. Update docs/Lessons.md: Document useful learnings from dev process, especially when AI or human struggles to produce results, so future development efforts are more effective and efficient
  5. Iterate: Refine based on testing and world-class standards

AI agents: for how you must test your own work before reporting completion (autonomous testing, Levels 1–4, web/UI verification, anti-patterns), see the SSOT AI-Testing-Standards. The rules below are the codebase’s human + AI dev-testing philosophy.

  • Test behavior, not implementation
  • Unit tests for business logic
  • Integration tests for system boundaries
  • E2E tests for critical user paths
  • Aim for 80% coverage, focus on critical paths
  • Unit Tests: Vitest for component and utility testing
  • E2E Tests: Playwright for user flow testing
  • Performance: Lighthouse CI for performance regression
  • Accessibility: Axe-core for automated a11y testing
  • Linting: ESLint + Prettier for code consistency
  • Type Safety: TypeScript strict mode, Python type hints
  • Bundle Analysis: Analyze and optimize bundle size
  • Performance Budgets: Set and enforce performance budgets
  • Email: Amazon SES via Sendy for bulk emails
  • Analytics: Plausible Analytics for privacy-first tracking
  • Forms: Web3Forms or Formspree for form handling
  • Payments: Stripe for payment processing
  • Search: Meilisearch for site search functionality
  • Workflow Automation: Currently using n8n for data processing
  • Webhooks: Implement for real-time integrations
  • Cron Jobs: Server-side scheduling for maintenance tasks
  • Scripts and tools to automate tasks (Python/Bash)
  • Type hints for Python
  • Clear error handling and logging
  • Speed > Perfection
  • Experiment freely with new technologies
  • Document learnings, not every detail
  • Quality, Testing, and Stability are paramount
  • Follow ALL standards in this document
  • Comprehensive testing required
  • Monitoring from day one
  • Proper backup strategy (automated, tested, documented)

IF ANY TASK IS NOT VERY CLEAR OR ADDITIONAL INFORMATION IS NEEDED OR EVEN WOULD BE HELPFUL, ALWAYS ASK. IT IS MUCH MORE EFFECTIVE TO BE 100% CLEAR ON WHAT IS EXPECTED FROM THE START.

  • Follow naming conventions from this document and related naming systems
  • Never use hacks - find robust solutions
  • Review AI-generated code carefully
  • Write tests for critical paths
  • Document complex decisions
  • Run security scans
  • Check performance metrics
  • Verify error monitoring is active
  • Test backup and restore procedures
  • Review secrets management

Document Version: 1.0.0
Last Updated: 2024
Single Source of Truth: This document supersedes all previous development guidelines