15 KiB
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)
- Check for global CLAUDE.md: Look for
/home/fox/CLAUDE.mdor~/CLAUDE.md - Read & follow global instructions: These apply across ALL repositories on localhost
- Global instructions are baseline: These set the foundation for all work
Priority 2: Repository-Specific CLAUDE.md (Local)
- Check for repo CLAUDE.md: Use
Readto check if./CLAUDE.mdexists in the repository root - Read & follow repo instructions: If found, read the entire CLAUDE.md file & follow all instructions
- Repo-specific overrides global: Repository-specific CLAUDE.md instructions override or extend global guidelines
- 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:
- ALWAYS test Pelican build:
make clean && make html && make formats - Check for build errors: Pelican will fail on RST syntax errors, missing files, etc.
- Verify output:
make serveand check localhost:8000 - 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:
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:
# 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:
- What I did wrong: Used
git add .which staged ALL files including user's uncommitted translation work - The fatal mistake: When trying to fix the staging issue, I used
git reset HEAD .which overwrote the working directory files with staged versions - Result: User's uncommitted translation work was completely lost/overwritten
PROPER APPROACH:
- ALWAYS check
git statusandgit difffirst 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, NOTgit 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"
- 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: "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: "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):
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:: centerfor 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 `_``
BLOG POST TAGS
Check existing tags before writing posts:
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
- Blues:
- Gold/yellow nodes (
#f9a825,#fdd835): usefill="#1a1a1a"text (NOT#333333) - Node strokes:
#999999(never black) - Edges/arrows:
#aaaaaastroke & 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, textfill="#cccccc"
SVG Dimensions
- Root SVG:
width="100%" height="100%"withviewBox(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
.animelements, wraps each in a container, adds play button - On click: hides all
.animgroups (opacity 0), then animates them in sequence using@keyframes svgFadeInwith calculated delays based ondNclass 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
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
- Strip
<title>tags:sed -i 's/<title>[^<]*<\/title>//g'(prevents tooltip artifacts) - Replace fixed dimensions:
width="100%" height="100%"keeping viewBox - Change cluster label fontcolor from
#aaaaaato#cccccc - Wrap groups with animation classes (
<g class="anim dN">) - Remove
<defs><style>...</style></defs>block (animation handled by page-level JS) - Verify: no
fill="black", nostroke="black", nofill="#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 depslxd/build-host.sls— LXD + ZFS, image cache expirytop.slstargetsbuild.unturf.comwith both states
Key settings (salt-managed):
concurrent = 4in/etc/gitlab-runner/config.toml(pillar:gitlab-runner:concurrent)- LXD
images.remote_cache_expiry = 3days,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 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
- File names MUST match the date metadata (e.g.,
2025-11-04-post-name.txtwith: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 first
- NEVER use old dates from previous examples or files