Add internal CLAUDE.md for Claude Code bug fixing (#1453)

Provides guidelines for Claude Code instances fixing bugs in examples,
  covering testing workflow, dependency updates, prose conventions, and
  code style patterns derived from the Examples Style Manifesto.

  Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Charles Frye
2026-01-27 11:30:10 -08:00
committed by GitHub
parent 0daa3f5c49
commit dbbe250403

295
internal/CLAUDE.md Normal file
View File

@@ -0,0 +1,295 @@
# Internal Development Guide for Modal Examples
This guide is for fixing bugs in the Modal examples repository. These bugs are
typically triggered by synthetic monitoring (synmon) alerts.
## Prime Directive
**The code must run.** If example code does not run, we have failed the user.
Examples are tested regularly because code rots — external dependencies change,
APIs evolve, and artifacts move. Your job is to make the code run again.
## Scope
- Fix bugs in numbered example directories (`01_getting_started/` through
`14_clusters/`)
- Ignore the `misc/` folder entirely — it is not continuously tested
- Do not change anything in the `internal/` folder — it contains CI
infrastructure, not examples. Use its contents, including this file, to guide
your investigation and testing
## Common Bug Types
Most bugs fall into one of two categories:
1. **Dependency changes** — upstream packages release breaking changes or
deprecate APIs; other artifacts or APIs change in breaking ways
2. **Modal SDK changes** — the Modal API evolves and examples need updates
If the root cause is outside this repository (e.g., a bug in the Modal SDK
itself), report it rather than implementing a workaround. Include the error,
affected example, and any relevant context.
## Testing Examples
Run examples using the internal test runner:
```bash
MODAL_ENVIRONMENT=examples python -m internal.run_example <example_stem>
```
Where `<example_stem>` is the filename without `.py` (e.g., `hello_world` for
`01_getting_started/hello_world.py`).
This uses the `cmd` and `args` from the example's frontmatter, or defaults to
`modal run <path>`. The test environment automatically sets
`MODAL_SERVE_TIMEOUT=5.0`.
## Updating Dependencies
When fixing dependency-related bugs:
1. **Check PyPI for the latest version** of the problematic package
2. **Update to the latest working version** — not just any version that fixes
the immediate bug
3. **Confirm the new dependencies work** by running the example
4. **Fix warnings, not just errors** — examples should run cleanly without
deprecation warnings or other noise
### Pinning Requirements
Follow these pinning rules for container image dependencies:
- Pin to SemVer minor version: `~=x.y.z` or `==x.y`
- For packages with `version < 1.0`: pin to patch version `==0.y.z`
- Pin container base images to stable tags (e.g., `v1`), never `latest`
- Always specify `python_version` when using base images that support it
Example:
```python
image = (
modal.Image.from_registry("nvidia/cuda:12.8.0-devel-ubuntu22.04", add_python="3.12")
.uv_pip_install(
"vllm==0.13.0",
"huggingface-hub==0.36.0",
)
)
```
## Updating Prose
Examples use literate programming style — prose is written as markdown in
comments on their own lines:
```python
# # This is a Title
#
# This is a paragraph of prose that becomes documentation.
# It continues on multiple lines.
import modal # This comment stays with the code
# ## This is a Section Header
#
# More prose explaining the next code block.
app = modal.App("example-name")
```
**Critical rules:**
- **Always update prose when code changes affect what it describes** — the prose
is the documentation and is equally important as the code
- **Do not rename files** — file paths are referenced elsewhere and renaming
breaks links
## Code Style
### Time constants
Define `MINUTES = 60` (seconds) at module level for readable timeouts:
```python
MINUTES = 60 # seconds
@app.function(timeout=10 * MINUTES)
```
### Pin model revisions
Always pin model revisions to avoid surprises when upstream repos update:
```python
MODEL_NAME = "Qwen/Qwen3-4B-Thinking-2507-FP8"
MODEL_REVISION = "953532f942706930ec4bb870569932ef63038fdf" # pin to avoid surprises!
```
### Hugging Face downloads
Use the high-performance download flag and pin `huggingface-hub`:
```python
.uv_pip_install("huggingface-hub==0.36.0")
.env({"HF_XET_HIGH_PERFORMANCE": "1"}) # faster downloads
```
### Volume conventions
- Use descriptive kebab-case names: `"huggingface-cache"`, `"vllm-cache"`
- Always use `create_if_missing=True` for first-run convenience
```python
cache_vol = modal.Volume.from_name("huggingface-cache", create_if_missing=True)
```
### App naming
Use `example-` prefix with kebab-case:
```python
app = modal.App("example-vllm-inference")
```
### Path references
Use `Path(__file__).parent` for paths relative to the script:
```python
here = Path(__file__).parent
input_path = here / "data" / "config.yaml"
```
### Clean up warnings and logs
Examples should run cleanly. Fix deprecation warnings and suppress noisy logs —
unhandled warnings are amateurish and make debugging harder.
- Run `.entrypoint([])` on NVIDIA container images to disable license logging:
```python
modal.Image.from_registry("nvidia/cuda:12.8.0-devel-ubuntu22.04", add_python="3.12")
.entrypoint([]) # disable noisy NVIDIA license logging
```
### Use fully-qualified Modal names
Always use `modal.X` instead of importing names directly:
```python
# ✅ Good
import modal
image = modal.Image.debian_slim()
vol = modal.Volume.from_name("my-vol", create_if_missing=True)
# ❌ Bad
from modal import Image, Volume
image = Image.debian_slim()
```
### No local dependencies except `modal` and `fastapi`
Examples must not require local Python dependencies beyond `modal` (and
`fastapi` if needed). Use the Python standard library for HTTP requests and
other utilities. Dependencies inside Modal Functions are fine and encouraged.
### Each line should spark joy
Prefer clarity and economy. Use `pathlib.Path` over `os.path`. Use meaningful
variable names. Remove code that foregrounds machine concerns over reader
concerns.
## Prose Style
### Capitalize Modal product features
Modal's features are proper nouns: Image, Volume, Function, Cls, App, Secret.
Use `monospace` only when referring to the actual Python object.
```python
# ✅ "Modal Volumes provide distributed storage."
# ✅ "`modal.Volume` has a `from_name` method."
# ❌ "Modal volumes provide distributed storage."
```
### Use active, descriptive headers
Headers should express purpose, not just content:
```python
# ✅ ## Cache model weights
# ❌ ## Modal Volume
# ❌ ## Model weights loading
```
### Use blank lines for visual separation
Add a blank line before code blocks to match the visual separation in rendered
docs:
```python
# ✅ Good
# We define an image with our dependencies.
image = modal.Image.debian_slim().pip_install("torch")
# ❌ Bad
# We define an image with our dependencies.
image = modal.Image.debian_slim().pip_install("torch")
```
### Defer detailed explanations
Don't duplicate Guide content. Keep explanations brief and link to docs:
```python
# ✅ Good
# [Modal Volumes](https://modal.com/docs/guide/volumes) add distributed storage.
# Here, we use one to cache compiler artifacts.
# ❌ Bad (too much detail)
# Modal Volumes provide a high-performance distributed file system...
# (paragraph of text duplicating the Guide)
```
### Link to Modal docs
Link to relevant Modal documentation using full URLs:
```python
# We wrap inference in a Modal [Cls](https://modal.com/docs/guide/lifecycle-functions)
# that ensures models are loaded once when a new container starts.
```
Common links:
- Images: `https://modal.com/docs/guide/images`
- Volumes: `https://modal.com/docs/guide/volumes`
- GPUs: `https://modal.com/docs/guide/gpu`
- Model weights: `https://modal.com/docs/guide/model-weights`
- Lifecycle: `https://modal.com/docs/guide/lifecycle-functions`
## Linting
Before committing changes:
```bash
source venv/bin/activate
ruff check --fix <modified_files>
ruff format <modified_files>
```
See the repository root `CLAUDE.md` for full Python development rules.
## Pull Request Guidelines
See `.github/pull_request_template.md` for the full checklist. Key points:
- Example must be testable with `modal run` or have a custom `cmd` in
frontmatter
- Example must run with no arguments or have `args` defined in frontmatter
- All container dependencies must be pinned
- No local third-party dependencies required (except `fastapi`)