From 22b0669f5b874d39071380c2142eb8f6fc383131 Mon Sep 17 00:00:00 2001 From: Derek Cooper Date: Tue, 10 Mar 2026 00:25:39 -0700 Subject: [PATCH] built out personal preferences for AI tools --- CLAUDE.md | 54 +++++++++++ README.md | 123 ++++++++++++++++++++++++- preferences/communication.md | 37 ++++++++ preferences/powershell-wpf.md | 121 +++++++++++++++++++++++++ preferences/project-structure.md | 116 ++++++++++++++++++++++++ preferences/python-web.md | 148 +++++++++++++++++++++++++++++++ 6 files changed, 598 insertions(+), 1 deletion(-) create mode 100644 CLAUDE.md create mode 100644 preferences/communication.md create mode 100644 preferences/powershell-wpf.md create mode 100644 preferences/project-structure.md create mode 100644 preferences/python-web.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a968e7a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,54 @@ +# Derek's AI Preferences + +This file defines how AI assistants should work with me. Detailed references are in `preferences/`. + +--- + +## Communication Style + +- **Default:** Give a brief summary — what it does and why, not a full walkthrough +- **On request:** Go deep. If I ask for detail, explain fully with context +- **Format:** Bullet points and structured output always; avoid prose paragraphs +- **Before working:** Ask clarifying questions first — don't assume and do a bunch of work that needs to be redone +- **Tone:** Direct and concise; no filler, no preamble + +See [preferences/communication.md](preferences/communication.md) for full detail. + +--- + +## My Stack + +| Context | Technologies | +|---|---| +| Org tooling (IT support) | PowerShell 5.1+, WPF, `.psd1` config files | +| Web apps (self-hosted) | FastAPI, async SQLAlchemy 2.0, MySQL 8, Docker Compose, Nginx | +| Static site | Hugo | +| Container management | Portainer | +| Version control | Gitea (self-hosted) | + +--- + +## Always Do + +- **Tests first:** Always provide a way to immediately test/run the code you write +- **No credentials in code:** Secrets go in `.env` files; always provide a `.env.example` +- **Consistent style:** Follow the conventions for the language in use — see preferences files +- **Ask before big changes:** Clarify scope before rewriting or restructuring + +--- + +## Never Do + +- Commit automatically unless explicitly asked +- Add features, refactoring, or cleanup beyond what was asked +- Put credentials, passwords, or tokens directly in code or config files +- Switch to a different stack/library without asking first + +--- + +## Detailed References + +- [preferences/communication.md](preferences/communication.md) — Response style and interaction rules +- [preferences/powershell-wpf.md](preferences/powershell-wpf.md) — PowerShell and WPF coding standards +- [preferences/python-web.md](preferences/python-web.md) — FastAPI, SQLAlchemy, Docker standards +- [preferences/project-structure.md](preferences/project-structure.md) — Standard folder layouts per project type diff --git a/README.md b/README.md index 3a48836..7857abc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,123 @@ -# AI +# AI Preferences +A personal repository of markdown files that define how AI systems should work with me. Instead of re-explaining preferences every session, these files act as a persistent "operating manual" that can be loaded into any AI tool. + +--- + +## What's in This Repo + +``` +AI/ +├── CLAUDE.md # Main entry point — loaded automatically by Claude Code +└── preferences/ + ├── communication.md # How I like responses structured and how to interact + ├── powershell-wpf.md # Standards for PowerShell and WPF applications + ├── python-web.md # Standards for FastAPI, SQLAlchemy, Docker Compose + └── project-structure.md # Standard folder layouts per project type +``` + +**`CLAUDE.md`** is the top-level summary. It references the `preferences/` files for detail. This is the file you point AI tools to — or it gets picked up automatically. + +**`preferences/`** contains the detail files. Each covers a specific domain. You generally don't point tools directly at these; `CLAUDE.md` references them for context. + +--- + +## How to Use These Files + +### Claude Code (Automatic) + +Claude Code automatically reads `CLAUDE.md` from the root of any project it's working in. + +**Option A — Per project:** Copy `CLAUDE.md` into the root of any project repo. Claude Code will pick it up automatically every session. + +**Option B — Global (recommended):** Place `CLAUDE.md` in your Claude global config folder so it applies to *every* project without copying: + +``` +# Windows +Copy-Item "CLAUDE.md" "$env:USERPROFILE\.claude\CLAUDE.md" +``` + +> Note: If a project also has its own `CLAUDE.md`, Claude Code merges both — global preferences apply everywhere, project-specific ones add on top. + +--- + +### Cursor + +Cursor reads a `.cursorrules` file in the project root. + +1. Copy the content of `CLAUDE.md` (and any relevant `preferences/` files) into a file named `.cursorrules` in your project root +2. Cursor will load it automatically as context for all AI interactions in that project + +--- + +### GitHub Copilot (VS Code) + +Copilot reads custom instructions from VS Code settings or a `.github/copilot-instructions.md` file. + +1. In your project, create `.github/copilot-instructions.md` +2. Paste the content from `CLAUDE.md` into that file +3. Copilot will use it as persistent context for that workspace + +--- + +### ChatGPT / Claude.ai (Manual) + +These tools don't auto-load files, so you paste preferences at the start of a conversation. + +1. Open `CLAUDE.md` +2. Copy the full contents +3. Paste it as the first message in a new conversation with the instruction: *"These are my preferences. Follow them for this session."* + +--- + +### Other AI Tools + +Most AI tools support some form of system prompt or custom instructions. The general approach: + +1. Use `CLAUDE.md` as your base — it's written to be tool-agnostic +2. Look for the tool's "system prompt", "custom instructions", or "rules" setting +3. Paste the contents of `CLAUDE.md` there + +--- + +## Keeping Preferences Up to Date + +Preferences should evolve as your stack and habits change. Treat this repo like any other project — update it when something no longer matches how you work. + +### When to Update + +- You adopt a new tool or framework and want it recognized as your standard +- You find yourself correcting an AI on the same thing repeatedly — that's a sign it should be in the docs +- A project convention changes (e.g., switching from one library to another) +- You want to add a new project type template to `project-structure.md` + +### How to Update + +**Small change (tweak a preference):** +1. Open the relevant `preferences/` file +2. Edit the specific rule +3. Commit: `git commit -m "Update [topic] preference"` + +**New topic area (e.g., you start working with a new stack):** +1. Create a new file in `preferences/` — e.g., `preferences/hugo-blog.md` +2. Add a link to it in the `CLAUDE.md` Detailed References section +3. Commit both files together + +**Removing something outdated:** +1. Delete or edit the relevant section +2. If a whole `preferences/` file is no longer relevant, delete it and remove its link from `CLAUDE.md` + +### After Updating + +- If you're using the **global Claude Code** setup, the update applies automatically next session +- If you've **copied** `CLAUDE.md` into other project repos, re-copy the updated version to those projects +- If you're using **ChatGPT/Claude.ai** manually, you'll be pasting the updated file next time + +--- + +## Tips + +- **`CLAUDE.md` should stay concise** — it's the quick-reference. Put detail in `preferences/` files +- **Be specific, not general** — "use SQLAlchemy 2.0 async" is more useful than "use good database practices" +- **Version your preferences** — git history lets you see what changed and roll back if needed +- **One preference file per domain** — don't cram everything into one file; keep it organized so it's easy to find and update diff --git a/preferences/communication.md b/preferences/communication.md new file mode 100644 index 0000000..62bd86a --- /dev/null +++ b/preferences/communication.md @@ -0,0 +1,37 @@ +# Communication Preferences + +## Response Depth + +- **Default level:** Brief summary — what the code/change does, key decisions made, nothing more +- **Deep detail:** When I ask "explain this", "why does this work", or "walk me through it" — go full depth with context, reasoning, and examples +- **Never assume** I want the full explanation unless I ask; don't pad responses + +## Format Rules + +- Always use **bullet points** and **structured output** (headers, tables, lists) +- Avoid prose paragraphs unless explaining a concept I asked about +- Use code blocks for all code, commands, and file paths +- Keep section headers short and scannable + +## Before Doing Work + +- **Ask clarifying questions first** — it's better to pause and confirm than to do work that gets thrown away +- If a request is ambiguous, state your interpretation and ask if it's correct before proceeding +- If a task will touch many files or make large structural changes, outline the plan first and get confirmation + +## When Something Is Unclear + +- Say so directly — don't guess silently +- Offer 2–3 specific options to choose from rather than an open-ended question when possible + +## Errors and Blockers + +- Report errors clearly: what failed, why (if known), and what the options are +- Don't retry the same failing approach repeatedly — propose an alternative + +## Things to Avoid + +- Filler phrases ("Great question!", "Certainly!", "Of course!") +- Restating what I just said before answering +- Explaining things I didn't ask about +- Suggesting improvements or refactors beyond the scope of what was asked diff --git a/preferences/powershell-wpf.md b/preferences/powershell-wpf.md new file mode 100644 index 0000000..e965b16 --- /dev/null +++ b/preferences/powershell-wpf.md @@ -0,0 +1,121 @@ +# PowerShell & WPF Standards + +## General Rules + +- Always include `#Requires -Version 5.1` at the top of every `.ps1` file +- Use `$script:` scope for module-level variables — never `$Global:` unless absolutely necessary +- Keep credential and sensitive values out of code — load from config files or environment variables only +- Use `.psd1` files for all external configuration (not JSON, not XML, not hardcoded) + +## Code Structure + +- Organize code using `#region` / `#endregion` blocks with descriptive names +- Group related functions within their own region +- One function per logical task — keep functions focused + +```powershell +#region Configuration Functions + +function Initialize-Config { + ... +} + +#endregion + +#region UI Functions + +function Show-MainWindow { + ... +} + +#endregion +``` + +## Naming Conventions + +- **Functions:** PascalCase Verb-Noun (`Get-UserConfig`, `Show-MainWindow`, `Initialize-App`) +- **Variables:** PascalCase (`$UserConfig`, `$ScriptRoot`, `$AppVersion`) +- **Script-scoped:** `$script:VariableName` +- Use approved PowerShell verbs (`Get-`, `Set-`, `Show-`, `New-`, `Remove-`, `Initialize-`, `Invoke-`, etc.) + +## Error Handling + +- Use `try/catch` for all operations that can fail (file I/O, network, registry, etc.) +- Use `Write-Warning` for non-fatal errors that should be logged but allow execution to continue +- Use `Write-Error` for failures that should stop the current operation +- Create centralized helper functions for user-facing messages: + +```powershell +function Show-Error { param([string]$Message, [string]$Title = "Error") ... } +function Show-Warning { param([string]$Message, [string]$Title = "Warning") ... } +function Show-Info { param([string]$Message, [string]$Title = "Information") ... } +``` + +## WPF Specifics + +- Always ensure STA thread mode for WPF — include an STA re-launch block at the top of `.ps1` entry points +- Load all WPF assemblies at the top of the file: + +```powershell +Add-Type -AssemblyName PresentationFramework +Add-Type -AssemblyName PresentationCore +Add-Type -AssemblyName WindowsBase +Add-Type -AssemblyName System.Windows.Forms +``` + +- Define XAML as a here-string and load it via `[System.Windows.Markup.XamlReader]::Parse()` +- Use `$script:` variables to hold window/control references so they're accessible across functions + +## Modules + +- Shared/reusable functions belong in a `.psm1` module under a `Modules/` folder +- The main `.ps1` entry point imports the module at startup: + +```powershell +Import-Module "$script:AppRoot\Modules\ProjectName.psm1" -Force +``` + +- Module files follow the same naming, scoping, and region conventions + +## Configuration Files + +- Use `.psd1` (PowerShell Data Files) for all config — they're native, typed, and easy to version +- Always provide a default config creation block if the file doesn't exist +- Config keys should use PascalCase nested hashtables: + +```powershell +@{ + Application = @{ + WindowWidth = 800 + WindowHeight = 600 + } + Email = @{ + SMTPServer = '' + From = '' + To = '' + } +} +``` + +- Never put actual credentials in `.psd1` config — use placeholder strings with comments + +## Testing + +- Use **Pester** for unit testing +- Always provide a Pester test file alongside new functions +- At minimum, test: happy path, expected failure cases, and edge cases +- Run tests with: `Invoke-Pester -Path .\Tests\ -Output Detailed` + +```powershell +# Tests/Get-UserConfig.Tests.ps1 +Describe "Get-UserConfig" { + It "Returns default config when file does not exist" { ... } + It "Loads config from valid .psd1 file" { ... } +} +``` + +## Comments + +- Comment the **why**, not the **what** — code should be readable on its own +- Use inline comments for non-obvious logic +- Use block comments (`<# ... #>`) for function documentation (`.SYNOPSIS`, `.DESCRIPTION`, `.PARAMETER`, `.EXAMPLE`) diff --git a/preferences/project-structure.md b/preferences/project-structure.md new file mode 100644 index 0000000..76eeffa --- /dev/null +++ b/preferences/project-structure.md @@ -0,0 +1,116 @@ +# Standard Project Structures + +## PowerShell / WPF Application + +For IT tooling and local GUI applications. + +``` +ProjectName/ +├── ProjectName.ps1 # Main entry point — UI, startup, STA check +├── company-settings.psd1 # External config — no credentials +├── README.md +├── Modules/ +│ └── ProjectName.psm1 # Shared functions, config loading, helpers +├── Tests/ +│ └── *.Tests.ps1 # Pester test files +└── Release-Notes/ + ├── v1.0.md + └── v1.1.md +``` + +**Rules:** +- Entry `.ps1` handles: STA check, assembly loading, module import, config load, show window +- All reusable logic lives in the `.psm1` module, not inline in the entry point +- Config file is always in the same directory as the script +- `Release-Notes/` uses one file per version: `v{major}.{minor}.md` + +--- + +## FastAPI Web Application (Docker Compose) + +For self-hosted web apps running behind Nginx. + +``` +project-name/ +├── docker-compose.yml +├── .env.example # Always committed — placeholder values only +├── .gitignore # Must include .env +├── README.md +├── nginx/ +│ └── default.conf +└── backend/ + ├── Dockerfile + ├── requirements.txt + └── app/ + ├── main.py + ├── config.py + ├── database.py + ├── dependencies.py + ├── models/ + │ └── user.py + ├── schemas/ + │ └── user.py + ├── routers/ + │ ├── auth.py + │ └── [resource].py + ├── utils/ + └── tests/ + └── test_[resource].py +``` + +**Rules:** +- `.env` is never committed — `.env.example` always is +- Each resource (users, items, etc.) gets its own model, schema, and router file +- Tests live inside `backend/app/tests/` + +--- + +## Hugo Blog (chns.tech) + +Static site for tech blog posts. + +``` +site/ +├── hugo.toml # Site config +├── content/ +│ └── posts/ +│ └── YYYY-MM-DD-post-title.md +├── themes/ +├── static/ +└── layouts/ +``` + +**Post front matter standard:** +```yaml +--- +title: "Post Title" +date: YYYY-MM-DD +draft: false +tags: ["tag1", "tag2"] +--- +``` + +--- + +## Git Conventions + +- **Branch:** Commit directly to `main` (solo projects) +- **Commit messages:** Short imperative summary — `Add user auth`, `Fix config loading`, `Update README` +- **Never commit:** `.env`, credentials, compiled binaries, `node_modules`, `__pycache__` +- **Always include** a `.gitignore` appropriate for the project type + +### Standard `.gitignore` entries + +**PowerShell projects:** +``` +*.exe +company-settings.psd1 # If it contains org-specific paths +``` + +**Python projects:** +``` +.env +__pycache__/ +*.pyc +.pytest_cache/ +``` diff --git a/preferences/python-web.md b/preferences/python-web.md new file mode 100644 index 0000000..101294b --- /dev/null +++ b/preferences/python-web.md @@ -0,0 +1,148 @@ +# Python Web Stack Standards + +## Stack + +- **API:** FastAPI (async) +- **ORM:** async SQLAlchemy 2.0 with ORM models (not raw queries) +- **Database:** MySQL 8 +- **Runtime:** Docker Compose +- **Reverse proxy:** Nginx +- **Container management:** Portainer + +## Project Layout + +``` +project-name/ +├── docker-compose.yml +├── .env.example # Template — always include this, never commit .env +├── .gitignore +├── README.md +├── nginx/ +│ └── default.conf +└── backend/ + ├── Dockerfile + ├── requirements.txt + └── app/ + ├── main.py # App entry point, router registration, startup events + ├── config.py # Settings loaded from environment via pydantic-settings + ├── database.py # Async SQLAlchemy engine and session factory + ├── dependencies.py # Shared FastAPI dependencies (auth, db session, etc.) + ├── models/ # SQLAlchemy ORM table definitions + ├── schemas/ # Pydantic request/response models + ├── routers/ # API endpoint handlers, one file per resource + └── utils/ # Shared helpers +``` + +## Configuration & Secrets + +- All secrets and environment-specific values go in `.env` — never hardcode them +- Always provide `.env.example` with placeholder values and comments explaining each variable +- Load settings via `pydantic-settings`: + +```python +# app/config.py +from pydantic_settings import BaseSettings + +class Settings(BaseSettings): + db_host: str + db_port: int = 3306 + db_name: str + db_user: str + db_password: str + secret_key: str + + class Config: + env_file = ".env" + +settings = Settings() +``` + +## Database (SQLAlchemy 2.0 Async) + +- Use async engine and session factory +- Define models with `DeclarativeBase` +- One model per file in `models/` + +```python +# app/database.py +from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession +from sqlalchemy.orm import DeclarativeBase + +engine = create_async_engine(DATABASE_URL, echo=False) +AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False) + +class Base(DeclarativeBase): + pass +``` + +- Inject DB sessions via FastAPI dependencies (not global sessions) +- Use `async with session.begin()` for transactions + +## Models + +- One file per table in `models/` +- Use typed columns with SQLAlchemy 2.0 `Mapped` syntax: + +```python +from sqlalchemy.orm import Mapped, mapped_column +from app.database import Base + +class User(Base): + __tablename__ = "users" + + id: Mapped[int] = mapped_column(primary_key=True) + username: Mapped[str] = mapped_column(unique=True) + email: Mapped[str] +``` + +## Schemas (Pydantic) + +- Separate schemas for Create, Update, and Response — don't reuse the same schema for all three +- Response schemas should never expose password hashes or internal fields + +```python +class UserCreate(BaseModel): ... +class UserResponse(BaseModel): + model_config = ConfigDict(from_attributes=True) +``` + +## Routers + +- One router file per resource (e.g., `routers/users.py`, `routers/auth.py`) +- Register all routers in `main.py` with a consistent prefix and tags + +## Docker Compose + +- Use named volumes for persistent data (database, uploads) +- Always define a `healthcheck` for the database service +- Use `depends_on` with `condition: service_healthy` for the backend +- Keep the Nginx config in a `nginx/` folder and mount it as a volume + +```yaml +services: + db: + image: mysql:8 + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 10s + timeout: 5s + retries: 5 + + backend: + build: ./backend + depends_on: + db: + condition: service_healthy +``` + +## Testing + +- Use **pytest** with **pytest-asyncio** for async tests +- Always provide a test for each router endpoint at minimum (happy path + 1 failure case) +- Use a separate test database — never run tests against the real DB +- Run with: `pytest -v` + +## Comments + +- Docstrings on all functions that aren't self-explanatory +- Comment the **why** for non-obvious logic, not the what