343 lines
15 KiB
Markdown
343 lines
15 KiB
Markdown
# Claude Memory and Instructions
|
||
|
||
## CRITICAL: ALWAYS CHECK FOR CLAUDE.MD FILES
|
||
|
||
**BEFORE working on ANY repository, ALWAYS check for CLAUDE.md files in this order:**
|
||
|
||
### Priority 1: Cross-Repository CLAUDE.md (Global)
|
||
1. **Check for global CLAUDE.md**: Look for `/home/fox/CLAUDE.md` or `~/CLAUDE.md`
|
||
2. **Read & follow global instructions**: These apply across ALL repositories on localhost
|
||
3. **Global instructions are baseline**: These set the foundation for all work
|
||
|
||
### Priority 2: Repository-Specific CLAUDE.md (Local)
|
||
1. **Check for repo CLAUDE.md**: Use `Read` to check if `./CLAUDE.md` exists in the repository root
|
||
2. **Read & follow repo instructions**: If found, read the entire CLAUDE.md file & follow all instructions
|
||
3. **Repo-specific overrides global**: Repository-specific CLAUDE.md instructions override or extend global guidelines
|
||
4. **Check README too**: Also read README, README.md, or README.rst to understand the project
|
||
|
||
**Priority hierarchy:**
|
||
- Repository-specific CLAUDE.md (highest priority)
|
||
- Cross-repository CLAUDE.md (medium priority)
|
||
- This file's instructions (baseline for this specific repo)
|
||
|
||
**Examples of what to look for:**
|
||
- Build & test procedures
|
||
- Commit message formats
|
||
- Code style preferences
|
||
- Special workflows or requirements
|
||
- Project-specific constraints
|
||
- Cross-repo conventions & standards
|
||
|
||
---
|
||
|
||
Read README.rst to understand the build system.
|
||
|
||
you are acting on behalf of russell ballestrini. don't fuck up.
|
||
|
||
## CRITICAL PELICAN TESTING WORKFLOW
|
||
|
||
### BEFORE ANY COMMIT:
|
||
1. **ALWAYS test Pelican build**: `make clean && make html && make formats`
|
||
2. **Check for build errors**: Pelican will fail on RST syntax errors, missing files, etc.
|
||
3. **Verify output**: `make serve` and check localhost:8000
|
||
4. **NEVER commit without testing the build**
|
||
|
||
### PELICAN BUILD PROCESS:
|
||
- Uses Pelican static site generator (Python-based)
|
||
- Converts .rst/.md files to HTML
|
||
- RST syntax errors break the build
|
||
- Missing images/files break the build
|
||
- Invalid slugs/filenames cause issues
|
||
|
||
### PREFERRED BUILD COMMAND:
|
||
```bash
|
||
make clean && make html && make formats
|
||
```
|
||
|
||
This generates:
|
||
- HTML output from RST/MD sources
|
||
- Markdown versions (index.md) via pandoc
|
||
- Plain text versions (index.txt)
|
||
- JSON Feed (feeds/all.json)
|
||
- JSON Blog (blog.json) with Markdown content
|
||
- AI agent onboarding (llms.txt)
|
||
|
||
### PROPER DEVELOPMENT WORKFLOW:
|
||
```bash
|
||
# Setup virtual environment (once)
|
||
make venv
|
||
|
||
# Test changes before commit (PREFERRED BUILD)
|
||
make clean && make html && make formats
|
||
|
||
# Optional: serve locally to verify
|
||
make serve
|
||
|
||
# Check localhost:8000 for issues
|
||
# Only commit if build succeeds
|
||
git add specific-files
|
||
git commit -m "message"
|
||
git push
|
||
```
|
||
|
||
## CRITICAL CONTENT DIRECTORY ISSUE
|
||
|
||
**PROBLEM**: Python virtual environments exist in `content/uploads/2024/battleship-solvers/env/` and `env2/`
|
||
- These contain thousands of Python package files (.md, .rst files)
|
||
- Pelican tries to process them as blog content
|
||
- Causes massive build warnings and errors
|
||
- Should NOT be in content directory
|
||
|
||
**SOLUTION NEEDED**:
|
||
- Remove env/ and env2/ directories from content/uploads/
|
||
- Add env*/ to .gitignore patterns
|
||
- Keep only actual blog assets in content/uploads/
|
||
|
||
## CRITICAL GIT SAFETY LESSON
|
||
|
||
### DEVASTATING MISTAKE COMMITTED:
|
||
I made a catastrophic git error that destroyed user's work in progress:
|
||
|
||
1. **What I did wrong**: Used `git add .` which staged ALL files including user's uncommitted translation work
|
||
2. **The fatal mistake**: When trying to fix the staging issue, I used `git reset HEAD .` which overwrote the working directory files with staged versions
|
||
3. **Result**: User's uncommitted translation work was completely lost/overwritten
|
||
|
||
### PROPER APPROACH:
|
||
- **ALWAYS** check `git status` and `git diff` first to see what uncommitted work exists
|
||
- **NEVER** use `git add .` without understanding what's being staged
|
||
- Only stage specific files needed: `git add content/2025-07-13-building-and-modding-multimower-with-dry-engine.rst`
|
||
- If I need to unstage, use `git restore --staged <file>` for specific files, **NOT** `git reset HEAD .`
|
||
|
||
### KEY LESSON:
|
||
Git operations can be destructive to uncommitted work. Always preserve user's work in progress before any git commands.
|
||
|
||
**This was a serious failure that cost the user their translation work. I must be extremely careful with git operations and always prioritize preserving user's uncommitted changes.**
|
||
|
||
## PUSH WHEN READY
|
||
|
||
**When fox says to push or the work looks complete, commit & push without asking.** Don't ask "want me to push?" or "want me to commit?" — just do it. Fox will review the diff in GitLab if needed.
|
||
|
||
## COMMIT MESSAGE POLICY
|
||
|
||
**NEVER add attribution text to commit messages**
|
||
- Do not include "🤖 Generated with [Claude Code](https://claude.ai/code)"
|
||
- Do not include "Co-Authored-By: Claude <noreply@anthropic.com>"
|
||
- Keep commit messages clean and follow the existing repository style
|
||
|
||
## HELPER SCRIPTS AND TEMPORARY FILES
|
||
|
||
**NEVER commit helper scripts or temporary files unless explicitly requested**
|
||
- Helper scripts (like append_toc.py, test.py, etc.) are for temporary use only
|
||
- Only commit helper scripts if the user explicitly says to commit them
|
||
- After using a helper script, delete it from the working directory
|
||
- Do not include helper scripts in git commits unless specifically instructed
|
||
- Focus commits on actual content changes, not the tools used to make them
|
||
|
||
## WRITING STYLE
|
||
|
||
**Use "&" instead of "and" most of the time in posts**
|
||
- Prefer concise ampersand (&) for connecting words & phrases
|
||
- Example: "disrupt wheels & foster open collaboration" not "disrupt wheels and foster open collaboration"
|
||
- This creates a more casual, punchy writing style that matches the brand voice
|
||
|
||
**Grammar: Avoid dashes (em-dashes —, en-dashes –, hyphens used as dashes)**
|
||
- Do not use em-dashes or en-dashes in any writing (posts, cover letters, documentation)
|
||
- Hyphens only for compound words (e.g., "open-source"), never as sentence punctuation
|
||
- Prefer full stop periods. Split into two sentences instead of connecting with dashes
|
||
- Commas work too, but periods stay preferred
|
||
- Only use a dash if it truly makes more sense than a period or comma
|
||
|
||
**Grammar: Avoid "the" in posts**
|
||
- Never use "the" when "a" works instead
|
||
- Prefer dropping articles entirely when a sentence reads clean without one
|
||
- Example: "a permacomputer" not "the permacomputer"
|
||
- Example: "angle brackets. closing tags. verbosity." not "the angle brackets. the closing tags. the verbosity."
|
||
- Restructure sentences to eliminate "the" rather than forcing awkward substitutions
|
||
|
||
**Grammar: Avoid verbs "to be" (is, are, was, were, be, been, being)**
|
||
- Prefer active verbs over passive or linking constructions
|
||
- Example: "a permacomputer outlasts its builders" not "a permacomputer is something that outlasts its builders"
|
||
- Example: "Jason lives everywhere" not "Jason is everywhere"
|
||
- Example: "TOML fits like a studio apartment" not "TOML is a studio apartment"
|
||
- Contractions count: "it's" = "it is", "he's" = "he is", "that's" = "that is"
|
||
- Exception: quoted code output, error messages, & JSON values stay verbatim
|
||
|
||
## JOB SEARCH PREFERENCES
|
||
|
||
**Russell ONLY works remote.** Do not apply to or write cover letters for positions that are not fully remote. If a job posting says hybrid, on-site, or in-office, skip it.
|
||
|
||
**Russell uses & administers Matrix channels on matrix.org.** Relevant for DevRel, community, & communication-focused roles.
|
||
|
||
**media.unturf.com** - Russell's media gallery (dark theme, black & white aesthetic). Include in cover letter contact links when it strengthens the application (e.g., content/media/DevRel roles).
|
||
|
||
## JSONRESUME POLICY
|
||
|
||
**NEVER include phone number in JSONResume files** - they're public, use email only.
|
||
|
||
## COVER LETTER FORMAT
|
||
|
||
**Location:** `content/pages/cover-letters/`
|
||
|
||
**Naming:** `YYYY-MM-DD-company-role-russell-ballestrini.rst`
|
||
|
||
**Generate PDF:** `make cover-letters` (uses rst2pdf with style file)
|
||
|
||
**RST structure (match resume format):**
|
||
```rst
|
||
Russell Ballestrini
|
||
===================
|
||
|
||
.. class:: center
|
||
|
||
**Role Title | Company Name**
|
||
|
||
.. class:: center
|
||
|
||
russell@unturf.com | `russell.ballestrini.net <https://russell.ballestrini.net>`_ | `GitHub <https://github.com/russellballestrini>`_ | `Media <https://media.unturf.com>`_
|
||
|
||
----
|
||
|
||
To the [Company] team:
|
||
|
||
[Body of letter...]
|
||
|
||
|
|
||
|
||
Russell Ballestrini
|
||
```
|
||
|
||
**Key formatting rules:**
|
||
- Name as RST title (=== underline)
|
||
- Use `.. class:: center` for role & contact info
|
||
- Horizontal rule (----) separates header from body
|
||
- No Pelican metadata in PDF-only letters (or use RST comments to hide)
|
||
- Use `|` for vertical spacing before signature
|
||
- Links use RST inline syntax: ```link text <URL>`_``
|
||
|
||
## BLOG POST TAGS
|
||
|
||
**Check existing tags before writing posts:**
|
||
```bash
|
||
venv/bin/python lib/tag_stats.py # all tags with counts
|
||
venv/bin/python lib/tag_stats.py 5 # only tags with 5+ posts
|
||
```
|
||
|
||
**Core tags (use these):**
|
||
- Code, DevOps, Python, Guide, Opinion, Salt, AWS, Project, Docker, Security, Machine Learning, Game Development, Kubernetes
|
||
|
||
**Rules:**
|
||
- Always use existing tags when applicable
|
||
- Suggest new tags only if truly needed (new technology/topic area)
|
||
- Tags should be capitalized (e.g., "Python" not "python")
|
||
- Avoid single-use tags; consolidate into broader categories
|
||
|
||
## UNTURF SVG DIAGRAM STYLE GUIDE
|
||
|
||
**All diagrams on russell.ballestrini.net & permacomputer sites follow this style.**
|
||
|
||
### Color Palette (dark/light theme compatible)
|
||
- **Background**: always `transparent` (never white or black)
|
||
- **Node fills**: medium-dark saturated colors with `fill="white"` text
|
||
- Blues: `#4a90d9`, `#1e88e5`, `#0d47a1`, `#1a237e`
|
||
- Purples: `#9370db`, `#7b68ee`, `#6c5ce7`, `#4a148c`, `#ab47bc`
|
||
- Greens: `#7cb342`, `#1b5e20`, `#00897b`
|
||
- Teals: `#00acc1`, `#006064`
|
||
- Oranges: `#e65100`, `#e8834a`, `#ff6f00`
|
||
- Reds: `#bf360c`, `#b71c1c`, `#880e4f`
|
||
- Dark neutrals: `#2c3e50`, `#34495e`, `#546e7a`, `#616161`, `#4e342e`
|
||
- **Gold/yellow nodes** (`#f9a825`, `#fdd835`): use `fill="#1a1a1a"` text (NOT `#333333`)
|
||
- **Node strokes**: `#999999` (never black)
|
||
- **Edges/arrows**: `#aaaaaa` stroke & fill
|
||
- **Floating text labels**: `#cccccc` (cluster labels, "translates to", etc.)
|
||
- **Accent text**: `#ef5350` (red warnings/claims), `#ff6f00` (orange highlights), `#66ff66` (green positive)
|
||
- **Dashed cluster borders**: `stroke="#999999" stroke-dasharray="5,2"`
|
||
- **Plaintext labels** (no background): `fill="transparent"` polygon, text `fill="#cccccc"`
|
||
|
||
### SVG Dimensions
|
||
- Root SVG: `width="100%" height="100%"` with `viewBox` (never fixed pt/px)
|
||
- RST embed: `:width: 100%` and `:align: center`
|
||
|
||
### Animation Pattern (click-to-play)
|
||
|
||
SVGs render fully visible by default. A play button overlay triggers sequential fadeIn animation on click.
|
||
|
||
**SVG markup:** No `<style>` block needed. Just wrap groups in `<g class="anim dN">` where N controls sequence order.
|
||
|
||
**JS controller** (added once per page via `raw:: html`):
|
||
- Finds all SVGs with `.anim` elements, wraps each in a container, adds play button
|
||
- On click: hides all `.anim` groups (opacity 0), then animates them in sequence using `@keyframes svgFadeIn` with calculated delays based on `dN` class values
|
||
- Total animation spread scales to ~15s regardless of group count (`step = 15 / (maxD + 1)`)
|
||
- After animation completes, restores full opacity & shows play button again
|
||
|
||
**Previous approach (scroll-driven CSS view-timeline) was removed** because browser support proved unreliable. See royal-we post for the working click-to-play implementation.
|
||
|
||
- Wrap each conceptual group in `<g class="anim dN">`
|
||
- N values control sequence order (d0 appears first, d1 second, etc.)
|
||
- Multiple groups can share the same dN class to appear simultaneously
|
||
|
||
### Graphviz Dot Conventions
|
||
```dot
|
||
bgcolor="transparent"
|
||
node [fontname="Helvetica" fontsize=12 style="filled,rounded" shape=box color="#999999"]
|
||
edge [color="#AAAAAA" arrowsize=0.6 fontcolor="#AAAAAA"]
|
||
```
|
||
|
||
### Post-Processing Checklist
|
||
1. Strip `<title>` tags: `sed -i 's/<title>[^<]*<\/title>//g'` (prevents tooltip artifacts)
|
||
2. Replace fixed dimensions: `width="100%" height="100%"` keeping viewBox
|
||
3. Change cluster label fontcolor from `#aaaaaa` to `#cccccc`
|
||
4. Wrap groups with animation classes (`<g class="anim dN">`)
|
||
5. Remove `<defs><style>...</style></defs>` block (animation handled by page-level JS)
|
||
6. Verify: no `fill="black"`, no `stroke="black"`, no `fill="#333333"`
|
||
|
||
## RUSSELL'S PROJECT TECH STACKS
|
||
|
||
**NEVER assume or guess what language/framework a project uses. Check the actual repo.**
|
||
|
||
| Project | Stack | Description |
|
||
|---------|-------|-------------|
|
||
| unsandbox.com | Elixir / Phoenix | Customer portal (accounts, API keys, billing) |
|
||
| api.unsandbox.com | Elixir / Phoenix + Python | Code execution API, ZFS containers |
|
||
| un-inception | C (primary) + 41 languages | CLI client for unsandbox API |
|
||
| uncloseai-speech | Python / FastAPI | OpenAI-compatible TTS API (Qwen3-TTS) |
|
||
| uncloseai.com | JavaScript / Node.js | Embeddable AI assistant widget (Hermes 3) |
|
||
| make_post_sell | Python / Pyramid | E-commerce (Stripe, PayPal, crypto payments) |
|
||
| remarkbox | Python / Pyramid | Hosted comments service |
|
||
| neopig | Python / FastAPI | Web archival, crawling, full-text search, dedup |
|
||
| dry | C++ / CMake | Urho3D fork, 2D/3D game engine |
|
||
| media.unturf.com | — | Media gallery (dark theme, b&w aesthetic) |
|
||
|
||
**Key corrections for cover letters:**
|
||
- unsandbox.com is **Elixir/Phoenix**, NOT FastAPI or Python
|
||
- uncloseai-speech is **Python/FastAPI**
|
||
- make_post_sell & remarkbox are **Python/Pyramid**, NOT Django
|
||
- uncloseai.com is **Node.js**, NOT Python
|
||
|
||
## BUILD SERVER (build.unturf.com)
|
||
|
||
**CI/CD for this blog & all unturf projects.** GitLab Runner with shell executor.
|
||
|
||
**Config management:** Salt states in `~/git/foxhop-states/`
|
||
- `gitlab/build-host/ubuntu.sls` — runner config, cleanup cron, build deps
|
||
- `lxd/build-host.sls` — LXD + ZFS, image cache expiry
|
||
- `top.sls` targets `build.unturf.com` with both states
|
||
|
||
**Key settings (salt-managed):**
|
||
- `concurrent = 4` in `/etc/gitlab-runner/config.toml` (pillar: `gitlab-runner:concurrent`)
|
||
- LXD `images.remote_cache_expiry = 3` days, `images.auto_update_interval = 0`
|
||
- `/etc/cron.d/build-cleanup` — hourly container + zombie cleanup, weekly image prune, disk alerts at 85%
|
||
|
||
**Postmortem:** `russell.ballestrini.net/build-server-postmortem-disk-full/` (2026-03-08)
|
||
|
||
**Pipeline for this repo:** `make venv && make html && make formats && make resume` → tar → deploy via `deploy-www.sh`
|
||
|
||
## DATE HANDLING FOR NEW CONTENT
|
||
|
||
**CRITICAL: ALWAYS check the current date BEFORE creating ANY new documents**
|
||
- **MANDATORY**: Check the <env> section for "Today's date" at the start of EVERY conversation
|
||
- **BEFORE creating**: Posts, cover letters, blog entries, or any dated content, verify the current date
|
||
- The date may change during long conversations - ALWAYS use the actual current date from <env>
|
||
- File names MUST match the date metadata (e.g., `2025-11-04-post-name.txt` with `:date: 2025-11-04`)
|
||
- When creating new content, use the correct current date in BOTH the filename AND metadata
|
||
- **NEVER assume** the date - always check <env> first
|
||
- **NEVER use** old dates from previous examples or files
|