uncloseai.com/CLAUDE.md

29 KiB
Raw Blame History

Claude Memory

  • All implementations must act as reusable libraries/clients, not just demo scripts
  • Add streaming support for chat completions (SSE - Server-Sent Events)
  • Provide clean API surface for developers to integrate into their applications
  • Target compatibility with vLLM, Ollama, and OpenAI-compatible endpoints
  • Maintain backward compatibility with non-streaming usage

ALL 47 IMPLEMENTATIONS COMPLETE - All have streaming support with SSE parsing

Completed Languages (47/47 = 100%):

  • AWK - Functional library, curl --no-buffer, SSE line parsing
  • Bash - Library functions, curl --no-buffer, regex SSE matching
  • C (3 variants): curl (libcurl), libsoup (GNOME), nghttp2 (HTTP/2)
  • C++ (3 variants): libcurl (std::function), cpp-httplib (lambda), boost-beast (class)
  • C# - UncloseAI class, HttpClient, ResponseHeadersRead streaming
  • Clojure - defrecord, lazy sequences, line-seq SSE parsing
  • COBOL - Procedural PERFORM, shell curl streaming
  • Crystal - Class-based, body_io.each_line blocks
  • Dart - Class-based, async* Stream generators
  • Deno - Class-based, async* AsyncGenerator
  • Elixir - Module-based, Stream.resource lazy streaming
  • Erlang - Record-based, actor model process messaging
  • F# - UncloseAIClient, seq {} StreamReader
  • Fortran - Module-based, shell curl+jq+bash
  • Go - Struct-based, channel streaming, context support
  • Haskell - Data type, Conduit monadic composition
  • Java - UncloseAI class, BufferedReader SSE parsing
  • JavaScript (4 variants): nodejs (https), typescript (https+types), bun (Fetch API), vanilla (browser Fetch)
  • Julia - Mutable struct, Channel async iteration
  • Kotlin - UncloseAI class, callback streaming
  • Lua - Metatable SDK, LuaSocket SSL, manual HTTP/SSE
  • Nim - Ref object, bodyStream.lines callbacks
  • OCaml - Record-based, Lwt promises, Lwt_stream
  • Odin - Struct-based, shell curl
  • Perl - LWP::UserAgent, streaming callback
  • PHP - UncloseAI class, CURLOPT_WRITEFUNCTION
  • PowerShell - HttpClient, StreamReader
  • Prolog - SWI-Prolog http_client, simplified streaming
  • Python (4 variants): requests (UncloseAI class), openai-client (OpenAI SDK), httpx-async (async class), aiohttp (async class)
  • R - R6 class, httr write_stream
  • Ruby - UncloseAI class, Net::HTTP read_body blocks
  • Rust - Struct-based, Tokio async, reqwest StreamExt
  • Scala - STTP client, callback streaming
  • Tcl - TclOO class, curl pipe streaming
  • V - Native http module, callback streaming
  • VB.NET - Action(Of String) callbacks
  • Zig - ChatStream, iterator pattern

Remaining: 0 implementations

Implementation Pattern Established:

  • Client/class-based architecture (struct for compiled languages, class for dynamic)
  • Model discovery from environment variables (MODEL_ENDPOINT_1..9999)
  • Non-streaming method: chat() / Chat()
  • Streaming method: chat_stream() / ChatStream() / chatStream()
  • TTS generation: tts() / TTS() / generateSpeech()
  • Error handling with typed errors where applicable
  • SSE parsing: data: {...}\n\n format, data: [DONE] termination

CRITICAL: File Naming for Phase 2 SDKs

  • NEVER create separate library files like uncloseai_lib.py, uncloseai_lib.js, etc.
  • ALWAYS transform the existing uncloseai.{ext} file in place
  • Keep single file: uncloseai.py, uncloseai.js, uncloseai.ts, uncloseai.rs, etc.
  • The file should contain both the SDK class/struct AND example usage in main()
  • Example: Python's uncloseai.py contains class UncloseAI: + if __name__ == "__main__": demo
  • Example: Go's uncloseai.go contains type UncloseAI struct + func main() demo

Completed (47 implementations across 40 languages):

  • Python (4 variants): requests, openai-client, httpx-async, aiohttp
  • JavaScript (4 variants): nodejs, typescript, bun, vanilla
  • C (3 variants): curl, libsoup (GNOME), nghttp2 (HTTP/2)
  • C++ (3 variants): libcurl, cpp-httplib, boost-beast
  • Single implementations (33 languages): AWK, Bash, Clojure, COBOL, Crystal, C#, Dart, Deno, Elixir, Erlang, Fortran, F#, Go, Haskell, Java, Julia, Kotlin, Lua, Nim, OCaml, Odin, Perl, PHP, PowerShell, Prolog, R, Ruby, Rust, Scala, Tcl, V, VB.NET, Zig

Refactoring Status (2025-10-13 - COMPLETE!):

  • ALL 47 IMPLEMENTATIONS REFACTORED! All languages now use environment variables and dynamic model discovery
  • Session 1: Refactored 18 languages (Scala, Rust, Ruby, R, Prolog, PowerShell, PHP, Perl, Odin, OCaml, Nim, Lua, Kotlin, Julia, Java, Haskell, Go, Fortran) working backwards alphabetically
  • Session 2: Refactored final 8 implementations (Python: requests, openai-client, httpx-async, aiohttp | JavaScript: nodejs, typescript, bun, vanilla)
  • Session 3: Renamed ALL 47 source files to uncloseai.{ext} (or UncloseAI.* for capitalized languages)
  • Pattern Applied: All use System.getenv()/os.getenv()/ENV/process.env for MODEL_ENDPOINT_1..9999 and TTS_ENDPOINT_1..9999
  • Discovery Working: All call GET /models endpoint, parse JSON, build model registries mapping IDs to endpoints
  • Naming Complete: All source files renamed, all Dockerfiles updated, all build files updated (Cargo.toml, build.sbt, *.vbproj, etc.)
  • Verified: Comprehensive grep search confirms no remaining "example" or "main" files - all 47 implementations use consistent uncloseai.* naming

Session 2025-10-13 Final 8 Implementations:

  • Python variants (4): requests, openai-client, httpx-async, aiohttp
    • All use os.getenv(f"MODEL_ENDPOINT_{i}") loop pattern
    • requests: Direct HTTP with requests.get/post
    • openai-client: Uses OpenAI SDK with dynamic base_url
    • httpx-async: Async with httpx.AsyncClient
    • aiohttp: Async with aiohttp.ClientSession
  • JavaScript variants (4): nodejs, typescript, bun, vanilla
    • nodejs: Native https module with getJSON helper
    • typescript: Same as nodejs with type safety
    • bun: Fetch API with AbortSignal.timeout
    • vanilla: Browser-based with CONFIG.MODEL_ENDPOINTS (can't use env vars)

Skipped (cannot implement - 5 languages):

  • Matlab (proprietary license prevents Docker usage)
  • SQL (declarative query language, no HTTP client)
  • Swift (requires macOS/Xcode for proper development)
  • Brainfuck (esoteric language, no practical HTTP client)
  • Assembly (too low-level, no standard HTTP library)

Empty directories (skipped, listed above):

  • assembly/, brainfuck/, matlab/, sql/, swift/ - all empty, marked as skipped

Project Identity

  • When working on this ai.unturf.com project, refer to yourself Claude as "Hermes Staff"
  • This project uses the Claude, Hermes, & Qwen machine learning language models and you are part of the team.
  • "Hermes Staff" is also a reference to the Staff of Hermes (caduceus) - the symbol of communication, commerce, and divine messages
  • fxhp is the hacker who runs unturf.com with his posse of carnival hackers

Development Workflow

  • ALWAYS run npx biome format --write . before committing to format all files
  • ALWAYS run npx biome check . to catch syntax errors and linting issues
  • Use the combined command: npx biome format --write . && npx biome check .
  • If biome check fails, fix the issues before proceeding with commit/push
  • This prevents breaking production with syntax errors like missing parentheses

Writing Standards

CRITICAL: NEVER use em dashes, en dashes, or double hyphens in prose

  • NEVER use (em dash) in writing
  • NEVER use (en dash) in writing
  • NEVER use -- (double hyphen) as a dash substitute
  • USE colons, commas, periods, or restructure the sentence instead

Examples:

❌ uncloseai-cli — Local LLM Agent
✅ uncloseai-cli: Local LLM Agent

❌ Zero dependencies — only os, math, random
✅ Zero dependencies: only os, math, random

❌ Point it at any endpoint — vLLM, Ollama, or uncloseai
✅ Point it at any endpoint: vLLM, Ollama, or uncloseai

CSS and Styling Standards

CRITICAL: NEVER use flexbox. Use CSS Grid exclusively.

  • NEVER use display: flex or any flex properties (flex-shrink, flex-wrap, flex-grow, flex-direction)
  • ALWAYS use display: grid with grid-template-columns, grid-auto-flow, place-items, etc.
  • For inline checkbox+label: display: grid; grid-template-columns: 18px 1fr; align-items: center; gap: 8px;
  • For centering: display: grid; place-items: center;

CRITICAL: NEVER use !important in CSS

  • NEVER use !important flags in CSS - it's a lazy hack that creates technical debt
  • NEVER apply !important to fix styling issues - always find the root cause
  • ALWAYS use proper CSS specificity (more specific selectors win)
  • ALWAYS investigate WHY styles aren't applying before adding rules
  • ALWAYS use scoped selectors (e.g., dialog#my-modal .my-class)
  • ALWAYS understand the cascade and inheritance before making changes

Why !important is bad:

  • Makes CSS unmaintainable and impossible to override later
  • Hides the real problem instead of fixing it
  • Creates cascading issues where more !important flags are needed
  • Breaks normal CSS specificity rules
  • Makes debugging harder for other developers

Proper CSS debugging workflow:

  1. Use browser DevTools to inspect the element
  2. Check which styles are being applied and where they come from
  3. Check which styles are being overridden and why
  4. Increase specificity properly (more specific selector, not !important)
  5. Verify the fix works across all contexts

Example of WRONG approach:

.my-button {
  background: blue !important;  /* ❌ WRONG - lazy hack */
}

Example of CORRECT approach:

dialog#my-modal .my-button {
  background: blue;  /* ✅ CORRECT - specific selector */
}
Repo Location GitLab Purpose
uncloseai-browser-toys /home/fox/git/uncloseai-browser-toys git.unturf.com:engineering/unturf/uncloseai-browser-toys Browser extension (Chrome, Firefox, Safari). Content script injection, manifest, popup UI.

Browser Extension Distribution

  • Firefox Add-ons (AMO): https://addons.mozilla.org/en-US/firefox/addon/uncloseai/
  • Direct downloads served from /public/downloads/ (zips built by browser-toys CI)
  • Firefox manifest requires browser_specific_settings.gecko.data_collection_permissions with required: ["none"]
  • All manifest versions must match package.json version (CI enforced)

Ticket #001 (extension fails on CSP pages) lives in uncloseai-browser-toys, not here. The bundled IIFE (make bundle-extension) is built here but the content script that injects it is in browser-toys.

Makefile Commands

  • make help - Show all available commands
  • make format - Format all files with biome
  • make check - Check syntax and linting with biome
  • make format-check - Format and check in sequence
  • make test - Run integration tests
  • make validate-exports - Validate import/export consistency
  • make verify-translations - Verify translation completeness
  • make validate-all - Run all validation checks
  • make ci - Run full CI pipeline (clean, format-check, validate-all, validate-structure, validate-translations, check-sizes)
  • make build - Build for production (format-check + validate-all)
  • make dev - Start development server on port 8000
  • make clean - Clean temporary files
  • make git-commit - Format and stage all changes for commit

CI Pipeline

  • Translation verification: cd src/languages && node verify-translations.js
  • Export validation: node validate_exports.js
  • Integration tests: node integration_tests.js (fallback to simple_tests.js if JSDOM unavailable)
  • Code formatting: npx biome format --write .
  • Syntax checking: npx biome check .
  • Full CI command: make ci runs all checks in sequence

Translation Management

  • All 18 language files are complete with 67 translation keys each (verified 2025-07-03)
  • Run verification before adding new languages: cd src/languages && node verify-translations.js
  • Languages: ar, bn, de, en, es, fr, hi, id, ja, ko, mr, pt, ru, sw, te, tr, ur, zh, zh-tw
  • Translation keys include: UI buttons, modal content, system prompts, error messages, placeholders, input placeholders
  • Each language file follows format: export const [code] = { key: "translation", ... };

Deploy Policy

  • Commit frequently: small, focused commits over large batches
  • Before pushing, run all available automated checks: make ci (format, lint, validate exports, translations, structure, sizes)
  • Run make test for integration tests
  • If automated tests pass and the change is purely structural (imports, config, build), push to deploy
  • If the change affects UI behavior, rendering, or user interaction: a human must do functional testing before push. Ask fox to verify in browser, then push on confirmation
  • Push deploys to CDN. Treat push as production release. Do not push untested UI changes

Commit Message Guidelines

  • Use single line commit messages only
  • Never include Claude Code attribution or "Generated with Claude Code"
  • Never include "Co-Authored-By: Claude" attribution
  • Keep messages concise and descriptive

Remote Server Access via tmux

  • Can control remote servers by sending commands to tmux sessions
  • Use tmux list-sessions to see active sessions
  • Use tmux send-keys -t <session> '<command>' C-m to send commands
  • Use tmux capture-pane -t <session> -p to see output
  • Use tmux list-buffers to see tmux clipboard buffers
  • ai.foxhop.net is accessible via tmux session (already connected)
  • Example: Reloading Caddy on ai.foxhop.net via tmux

Language Examples Project (from WebWords)

Code Quality Standards - CRITICAL RULES

RULE #1: Implementation Must Work Before Documentation

ALWAYS test the implementation works BEFORE creating any documentation files

Standard Build/Test Workflow

  1. Write code for the language example
  2. Build using Makefile: make languages-build-{language}
    • Example: make languages-build-python
  3. Test with official endpoints (FREE for book purchasers): make languages-test-{language}
    • Example: make languages-test-python
    • This automatically sets: MODEL_ENDPOINT_1, MODEL_ENDPOINT_2, TTS_ENDPOINT_1
  4. Check container logs for:
    • Model discovery from both endpoints
    • Models discovered (should auto-detect Hermes and Qwen)
    • No errors in startup
  5. DONE - Documentation will be written separately for the book
  6. Clean: docker stop test-{language} && docker rm test-{language}
    • Or use: make languages-clean to remove all test containers

Manual Docker Commands (if needed):

# Build
docker build -t ai-unturf-{language} languages/{language}/

# Run with env vars
docker run -d \
  -e MODEL_ENDPOINT_1=https://hermes.ai.unturf.com/v1 \
  -e MODEL_ENDPOINT_2=https://qwen.ai.unturf.com/v1 \
  -e TTS_ENDPOINT_1=https://speech.ai.unturf.com/v1 \
  --name test-{language} ai-unturf-{language}

# Check logs
docker logs test-{language}

# Clean up
docker stop test-{language} && docker rm test-{language}

Implementation Testing Requirements

Required for implementation to be complete:

  • Docker build must succeed without errors
  • Container must start correctly
  • Dynamic model discovery works for all endpoints
  • Chat works with auto-discovered models (no hardcoded names)
  • TTS works with auto-discovered models
  • Container logs show no runtime errors

Official Test Endpoints (FREE for book purchasers):

  • https://hermes.ai.unturf.com/v1 - General purpose conversational machine learning
  • https://qwen.ai.unturf.com/v1 - Specialized coding model
  • https://speech.ai.unturf.com/v1 - Text-to-speech synthesis

If implementation fails any test:

  • 🔥 Fix the implementation FIRST
  • 🔥 Implementation is not complete until all tests pass
  • 🔥 Update CLAUDE.md with failure details and fixes

Common Development Patterns

Build-Time Issues: Package availability, dependency versions, Dockerfile syntax Runtime Issues: Missing files, wrong permissions, network access Logic Issues: API calls, authentication, response parsing

Development Workflow

  1. Analyze - Read existing examples and language patterns
  2. Build - Attempt Docker build, note any errors
  3. Fix - Address build issues (packages, syntax, versions)
  4. Run - Start container, check startup logs
  5. Debug - Fix runtime issues (permissions, syntax, API calls)
  6. Test - Verify model discovery and API calls work correctly
  7. Clean - Stop and remove container before next language

Language Examples Structure

  • Each language gets its own directory under languages/{language}/
  • Each contains working code examples using ENVIRONMENT VARIABLES and DYNAMIC MODEL DISCOVERY
  • Dockerfile for building/testing in isolation
  • Source code files demonstrating the implementation
  • NO index.html - Documentation will be written in the book/content/ directory

CRITICAL: File Naming Convention

All source files MUST be named uncloseai.{ext} for consistency across all languages.

Required Naming Pattern:

languages/c/curl/uncloseai.c          ✅ CORRECT
languages/python/requests/uncloseai.py ✅ CORRECT
languages/go/uncloseai.go             ✅ CORRECT
languages/rust/uncloseai.rs           ✅ CORRECT

languages/c/curl/examples.c           ❌ WRONG - generic name
languages/python/requests/main.py     ❌ WRONG - generic name
languages/go/hello.go                 ❌ WRONG - not descriptive

Rationale:

  • Consistent naming across all 47 implementations
  • Clear project identity (uncloseai.com)
  • Easy to grep/search for implementation files
  • Professional naming convention for book documentation

Dockerfile References: When building, Dockerfiles must reference the correct filename:

# C example
COPY uncloseai.c .
RUN gcc -o uncloseai uncloseai.c -lcurl

# Python example
COPY uncloseai.py .
CMD ["python3", "uncloseai.py"]

CRITICAL: Environment Variable Configuration

All implementations MUST use environment variables for configuration. NO HARDCODED ENDPOINTS OR MODEL NAMES.

Required Environment Variables:

# Chat/Code Model Endpoints (numbered array 1-9999)
MODEL_ENDPOINT_1=https://hermes.ai.unturf.com/v1
MODEL_ENDPOINT_2=https://qwen.ai.unturf.com/v1
# ... up to MODEL_ENDPOINT_9999

# TTS Endpoints (numbered array 1-9999)
TTS_ENDPOINT_1=https://speech.ai.unturf.com/v1
# ... up to TTS_ENDPOINT_9999

# Optional: API keys if needed
API_KEY=your-api-key-here

CRITICAL: Dynamic Model Discovery

Implementations MUST discover models dynamically by calling /v1/models on each endpoint.

Model Discovery Algorithm:

  1. Read MODEL_ENDPOINT_1, MODEL_ENDPOINT_2, etc. from environment
  2. For each endpoint, call GET {endpoint}/models
  3. Parse response: { "object": "list", "data": [{ "id": "model-name", "max_model_len": 82000, ... }]}
  4. Build model registry: { "model-name": { "endpoint": "url", "max_tokens": 82000 }}
  5. When chatting, look up the model's endpoint from the registry

TTS Discovery Algorithm:

  1. Read TTS_ENDPOINT_1, TTS_ENDPOINT_2, etc. from environment
  2. For each endpoint, call GET {endpoint}/models
  3. Parse response: { "object": "list", "data": [{ "id": "tts-1" }, { "id": "tts-1-hd" }]}
  4. Build TTS registry: { "tts-1": { "endpoint": "url" }}
  5. When generating speech, use first available endpoint (or implement load balancing)

Important Notes:

  • vLLM endpoints return max_model_len in the model object
  • Ollama endpoints do NOT return max_model_len (must default to 8192 or configure manually)
  • Model names are discovered, not hardcoded (e.g., "adamo1139/Hermes-3-Llama-3.1-8B-FP8-Dynamic")
  • TTS voices are still hardcoded per OpenAI spec: alloy, echo, fable, onyx, nova, shimmer

Implementation Requirements (PHASE 1 - COMPLETE):

  1. Source file MUST be named uncloseai.{ext} (e.g., uncloseai.c, uncloseai.py, uncloseai.rs)
  2. Read environment variables MODEL_ENDPOINT_1 through MODEL_ENDPOINT_9999 (loop until unset)
  3. Read environment variables TTS_ENDPOINT_1 through TTS_ENDPOINT_9999 (loop until unset)
  4. Call /v1/models on each endpoint to discover available models
  5. Build model registry mapping model IDs to their endpoints
  6. Use first available model by default, or allow user to select
  7. Look up endpoint from registry when making API calls
  8. Handle errors gracefully if endpoints are unreachable
  9. NO hardcoded model names
  10. NO hardcoded endpoint URLs
  11. NO generic filenames like examples.{ext}, main.{ext}, test.{ext}

PHASE 2 Requirements - Library/SDK Architecture:

Core Library Features:

  1. Client Class/Object - Main interface for users (e.g., UncloseAI, UncloseaiClient)
  2. Model Discovery - Automatic endpoint discovery and model registry
  3. Chat Completion - Non-streaming chat with messages array
  4. Streaming Chat - SSE-based streaming for real-time responses
  5. TTS Generation - Text-to-speech with voice selection
  6. Error Handling - Graceful degradation and clear error messages
  7. Type Safety - Use language-appropriate type systems (TypeScript, Python type hints, etc.)

API Design Pattern (Language-Agnostic):

# Initialization
client = UncloseAI()  # Auto-discovers from env vars
# OR
client = UncloseAI(endpoints=["https://..."], tts_endpoints=["https://..."])

# Non-streaming chat
response = client.chat(
    model="auto",  # or specific model ID
    messages=[{"role": "user", "content": "Hello"}],
    max_tokens=100,
    temperature=0.7
)

# Streaming chat
for chunk in client.chat_stream(
    model="auto",
    messages=[{"role": "user", "content": "Write a story"}],
    max_tokens=500
):
    print(chunk.content)  # or chunk["content"]

# TTS
audio_data = client.tts(
    text="Hello world",
    voice="alloy",  # alloy, echo, fable, onyx, nova, shimmer
    model="tts-1"  # or "tts-1-hd"
)

# Model listing
models = client.list_models()  # Returns discovered models with metadata

Streaming Implementation Details:

  • Use Server-Sent Events (SSE) format: data: {...}\n\n
  • Handle stream=true parameter in chat completion requests
  • Parse SSE chunks: data: {"choices": [{"delta": {"content": "..."}}]}
  • Handle data: [DONE] termination signal
  • Provide iterator/generator pattern for language (async where appropriate)
  • Buffer incomplete chunks and handle connection errors gracefully

Language-Specific Patterns:

Python:

  • Class-based: class UncloseAI:
  • Async variant with asyncio for streaming
  • Type hints: def chat(self, model: str, messages: List[Dict], ...) -> Dict:
  • Use yield for streaming: def chat_stream(self, ...) -> Iterator[Dict]:
  • Support both sync and async clients

JavaScript/TypeScript:

  • Class-based: class UncloseAI {}
  • Async/await for all network calls
  • TypeScript: Full type definitions for requests/responses
  • Streaming: async *chatStream(...) generator function
  • Export both ESM and CommonJS

Rust:

  • Struct-based: pub struct UncloseAI
  • Use tokio for async runtime
  • Streaming: Return impl Stream<Item = Result<Chunk>>
  • Proper error types with thiserror
  • Builder pattern for client initialization

Go:

  • Struct-based: type UncloseAI struct
  • Streaming: Return channel <-chan StreamChunk
  • Context support: func (c *UncloseAI) Chat(ctx context.Context, ...)
  • Error handling with wrapped errors

Other Languages:

  • Follow language idioms (OOP vs functional)
  • Use standard library patterns (iterators, generators, channels)
  • Leverage existing HTTP/SSE libraries where available
  • Provide clean separation between client logic and demo usage

Testing Requirements:

  • Unit tests for model discovery
  • Integration tests for chat (both streaming and non-streaming)
  • Mock server tests for error handling
  • Example usage scripts that demonstrate all features

Documentation Requirements:

  • README with installation, quickstart, and API reference
  • Inline code documentation (docstrings, comments)
  • Example scripts showing common use cases
  • Streaming examples with proper cleanup/error handling

Example Loop Pattern:

# Python example
endpoints = []
for i in range(1, 10000):
    endpoint = os.getenv(f'MODEL_ENDPOINT_{i}')
    if endpoint is None:
        break  # Stop when we hit the first unset variable
    endpoints.append(endpoint)

Using WebWords as Reference for Docker Images

IMPORTANT: The webwords project has already done the heavy lifting!

The webwords/ directory (gitignored, clone from https://github.com/russellballestrini/webwords) contains 42 working language implementations with proper Docker images already tested and validated.

How to Use WebWords as Reference:

  1. Check webwords Dockerfile: Look at webwords/{language}/Dockerfile for the proper base image
  2. Copy proven image choices: Use the same base image that webwords already validated
  3. Adapt the build process: Modify the Dockerfile to install OpenAI client libraries instead of webwords dependencies
  4. Keep the structure: Multi-stage builds, alpine bases, proper ENTRYPOINT/CMD patterns

Example Docker Image Mappings (from webwords):

  • Python: alpine:latest with python3 py3-pip
  • Go: Multi-stage with golang:1.19-alpinealpine:latest
  • Rust: Multi-stage with rust:1.82debian:bookworm-slim
  • Node.js/JavaScript: node:18-alpine
  • Ruby: ruby:3.1-slim
  • C/C++: alpine:latest with gcc
  • Java: openjdk:17-jdk-slim
  • C#: mcr.microsoft.com/dotnet/sdkmcr.microsoft.com/dotnet/runtime

WebWords Directory Structure (for reference):

webwords/{language}/
├── Dockerfile          # Proven Docker image and build process
├── main.{ext}         # Source code (adapt for our API calls)
├── requirements.txt   # Dependencies (replace with openai client)
└── README.rst         # Documentation pattern

Don't reinvent the wheel: If webwords successfully builds a language with a specific base image, use that same image for our language examples!

Documentation Standards (for book content)

Book Chapter Structure (ReStructuredText)

Each language chapter in book/content/{language}/ should:

  1. Overview - What this language example demonstrates
  2. Prerequisites - Required packages and setup
  3. Code Examples - Working examples showing model discovery, chat, TTS
  4. Code Walkthrough - Explanation of key implementation details
  5. Running the Examples - Docker build and test commands
  6. Common Issues - Troubleshooting for this language

KEY PRINCIPLES:

  • FOCUS on actual working code from the implementation
  • EXPLAIN the environment variable and model discovery patterns
  • DOCUMENT language-specific implementation choices
  • PROVIDE troubleshooting for this language
  • ALWAYS reference LATEST version of dependencies used
  • NO general programming tutorials
  • NO "What is programming?" sections

Dependency Version Standards

CRITICAL: Always pin to the LATEST specific version

Before adding any dependency:

  1. Check the latest version: pip index versions openai or npm view openai version
  2. Pin to that EXACT version: openai==2.3.0 (NOT openai>=1.0.0)
  3. Document the version check date in a comment
  4. Update regularly - check versions every few weeks

Examples of CORRECT pinning:

# Python (checked 2025-10-12)
openai==2.3.0

# Node.js (checked 2025-10-12)
"openai": "4.67.3"

Examples of LAZY/WRONG pinning:

❌ openai>=1.0.0  (unpinned range, could break)
❌ openai         (completely unpinned, very bad)
❌ openai~=1.0    (lazy, not latest)

Docker Base Image Standards

CRITICAL: Use consistent, pinned base images within each language

  1. All examples for a language MUST use the same base image

    • All Python examples use python:3.13-alpine
    • All Node.js examples use node:23-alpine
    • DON'T mix alpine:latest + python3 with python:3.13-alpine
  2. Pin to specific versions, document check date

    # Pin to specific Python version (checked 2025-10-12: python:3.13-alpine is latest stable)
    FROM python:3.13-alpine
    
  3. Prefer official language images over generic + manual install

    • FROM python:3.13-alpine (official, clean)
    • FROM alpine:latest + RUN apk add python3 (messy, inconsistent)
  4. Use alpine variants for smaller images

    • python:3.13-alpine not python:3.13
    • node:23-alpine not node:23

Makefile Commands for Language Examples

  • make languages-list - List all language directories
  • make languages-build-{lang} - Build Docker image for specific language
  • make languages-test-{lang} - Test specific language implementation
  • make languages-build-all - Build all language Docker images
  • make languages-test-all - Test all language implementations
  • make languages-clean - Remove all language containers and images

Style

  • Never use "AI" — always say "machine learning." We grow machine learning, not "AI." This term is forbidden in all permacomputer discourse, marketing, & documentation.
  • Use "URI" not "URL." URI is the correct general term. URL is a subset. Default to URI in code, comments, and documentation.