docker-zulip
CLAUDE.md766 starsChanged 6 months agoApache-2.0View on GitHub
This file provides guidance to Claude (and other AI coding assistants) for contributing to the docker-zulip codebase. Focus on making the codebase easy to understand and difficult to make dangerous mistakes. Every change should make the codebase more maintainable and easier to read. Before writing any code, understand: - Shell (bash): Primary language. Scripts use set -eux and set -o pipefail. Linted by shellcheck. - Docker: Multi-stage Dockerfile. Linted by hadolint. - Docker Compose: Service orchestration (compose.yaml). - Helm: Kubernetes…
The file
Show its rules and text
We split this CLAUDE.md into the rules it gives an agent
25 rules. About 0 are common, 13 are distinctive, and 12 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈13
Distinctive · estimate
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 12
Before writing any code, understand:
- Very specific: line 71
Docker secrets: Read from /run/secrets/zulip__*.
- Very specific: line 83
All Kubernetes resource names MUST use {{ include "zulip.fullname" .
- Very specific: line 92
Use nindent (not indent) for consistent whitespace handling.
- Very specific: line 95
Use kindIs "map" to support both scalar values and valueFrom map overrides in the environment variable loop.
- Very specific: line 100
Do not add scalar defaults in values.yaml for keys that users may override with a valueFrom map.
- Very specific: line 130
Unit tests: use helm-unittest. Test suites live in helm/zulip/tests/, one file per template.
- Very specific: line 131
Test suites live in helm/zulip/tests/, one file per template.
- Very specific: line 135
Run locally with helm unittest helm/zulip/.
- Distinctive: line 143
Follow: understand → propose → implement → verify.
- Very specific: line 156
Read the docker-zulip docs in docs/ and at https://zulip.readthedocs.io/projects/docker/
- Distinctive: line 158
Use git grep to find similar patterns before proposing changes.
- Distinctive: line 162
Before writing code, explain:
- Distinctive: line 168
Always start by rebasing onto the latest main.
- Distinctive: line 169
Do a pre-mortem: how might this break existing behavior, or need to be reverted?
- Distinctive: line 180
Be consistent with existing code: Look at surrounding code and follow the same patterns.
- Distinctive: line 184
Prefer readable code over clever code with explanatory comments.
- Distinctive: line 198
Be minimal and reviewable: Don't combine moving code with changing it.
- Distinctive: line 204
Create a commit that "fixes" a mistake from an earlier commit in the same PR.
- Distinctive: line 208
Use "Also" in a commit message — it hints the commit should be split.
- Very specific: line 237
Never: Partially fixes #123.
- Distinctive: line 272
Always output a recommended PR summary+description following the guidelines below.
- Very specific: line 282
Start with a Fixes: #... line linking the issue.
- Distinctive: line 285
Call out open questions or decisions you're uncertain about.
- Very specific: line 301
Commit discipline: https://zulip.readthedocs.io/en/latest/contributing/commit-discipline.html
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md - Guidelines for AI Contributions to docker-zulip
This file provides guidance to Claude (and other AI coding assistants) for contributing to the docker-zulip codebase.
Philosophy
Focus on making the codebase easy to understand and difficult to make dangerous mistakes. Every change should make the codebase more maintainable and easier to read.
Before writing any code, understand:
- What the existing code does and why, including relevant documentation.
- What problem you're solving, in its full scope.
- Why your approach is the right solution, and available alternatives.
- How you will verify correctness and avoid plausible regressions.
Key Technologies
- Shell (bash): Primary language. Scripts use
set -euxandset -o pipefail. Linted by shellcheck. - Docker: Multi-stage
Dockerfile. Linted by hadolint. - Docker Compose: Service orchestration (
compose.yaml). - Helm: Kubernetes deployment chart with Bitnami subcharts.
- Sphinx/MyST: Documentation in Markdown, hosted on ReadTheDocs.
- YAML: 2-space indent per
.editorconfig. - Markdown: Formatted by prettier, spell-checked by typos.
- GitHub Actions security: zizmor.
Repository Structure
Dockerfile # Multi-stage Docker image build
entrypoint.sh # Runtime entrypoint (~750 lines); the core of this repo
compose.yaml # Docker Compose: Zulip + PostgreSQL, Memcached, RabbitMQ, Redis
compose.override.yaml # Development/customization overrides
manage.py # Wrapper for Zulip's Django manage.py
upgrade-postgresql # PostgreSQL major-version upgrade helper
docs/ # Sphinx/MyST documentation source (ReadTheDocs)
docs/conf.py # Sphinx config; extracts versions from compose.yaml + Chart.yaml
docs/how-to/helm-*.md # Helm how-to guides (getting started, TLS, etc.)
ci/ # Integration tests (bash + curl against running containers)
ci/test-common.sh # Shared end-to-end test functions sourced by ci/*/test.sh
helm/zulip/ # Helm chart for Kubernetes deployment
helm/zulip/ci/ # Values files for Helm lint/test scenarios
helm/zulip/tests/ # helm-unittest suites (one per template)
.github/workflows/ # CI: Docker build, shellcheck, prettier, typos, zizmorConfiguration System (entrypoint.sh)
The entrypoint supports three configuration modes:
- Environment variables (default): Prefixed variables are applied automatically.
- Manual configuration (
MANUAL_CONFIGURATION=True): The entrypoint skips automatic config; you manage files directly. - Linked settings (
LINK_SETTINGS_TO_DATA=True): Settings files are symlinked into/datafor persistence across rebuilds.
Environment variable prefixes
SETTING_*→ written to Zulip'ssettings.py(with type inference: bool, int, list, string).CONFIG_<section>__<key>→ set viacrudiniin config files.SECRET_*→ written to Zulip'szulip-secrets.conf.
Other entrypoint features
- Docker secrets: Read from
/run/secrets/zulip__*. - Boolean normalization: Accepts true/false, yes/no, 1/0, enabled/disabled.
- Certificate modes: manual, certbot/Let's Encrypt, self-signed,
or HTTP-only (
DISABLE_HTTPS). - App commands:
app:run,app:init,app:managepy,app:backup,app:restore,app:help.
Helm Chart Conventions (helm/zulip/)
Resource naming
All Kubernetes resource names MUST use
{{ include "zulip.fullname" . }}, never bare
{{ .Release.Name }} or {{ .Chart.Name }}. This ensures names
stay consistent when nameOverride or fullnameOverride is set
and avoids cross-resource mismatches (e.g., a ConfigMap created
with one name but referenced with another).
Template patterns
- Use
nindent(notindent) for consistent whitespace handling. - Guard optional blocks with
{{- with }}so empty values don't produce empty YAML keys (e.g.,annotations: {}). - Use
kindIs "map"to support both scalar values andvalueFrommap overrides in the environment variable loop.
Values defaults
- Do not add scalar defaults in
values.yamlfor keys that users may override with avalueFrommap; Helm's coalesce cannot merge a scalar into a map and emits warnings. - Placeholder credentials (e.g.,
"123456789") are not useful defaults; omit them so users must set real values.
README vs documentation
The chart README.md is a quick-reference generated by
helm-docs from
README.md.gotmpl. Detailed how-to content belongs in docs/,
not in the README. After editing README.md.gotmpl or
values.yaml, regenerate the README:
docker run --rm -v "$(pwd)/helm/zulip:/helm-docs" -u "$(id -u)" \
jnorwood/helm-docs:latestTesting
Docker Compose integration tests
- Each
ci/<scenario>/directory has acompose.yamlandtest.sh. ci/test-common.shcontains shared end-to-end checks: realm creation, authentication, message posting, event queue verification.- CI runs a matrix over all
ci/*/directories.
Helm chart tests
- Unit tests use helm-unittest.
Test suites live in
helm/zulip/tests/, one file per template. Each suite loads values fromhelm/zulip/ci/*-values.yamland uses structural assertions (equal,contains,matchRegex,hasDocuments) to verify rendered output at specific paths. Run locally withhelm unittest helm/zulip/. - Schema validation uses kubeconform against all values scenarios.
- Functional tests deploy into a KIND cluster via
helm/zulip/ci/test.sh.
Workflow
Follow: understand → propose → implement → verify.
1. Understand Before Coding
# Read relevant documentation
cat docs/how-to/<relevant-area>.md
# Search for patterns in the codebase
git grep "functionName"
git log --oneline -20 -- entrypoint.sh- Read the docker-zulip docs in
docs/and at https://zulip.readthedocs.io/projects/docker/ - Use
git grepto find similar patterns before proposing changes.
2. Propose an Approach
Before writing code, explain:
- Your understanding of the problem
- What changes are needed and why
- How changes fit existing patterns
- What could break and how to prevent regressions
- Always start by rebasing onto the latest
main. - Do a pre-mortem: how might this break existing behavior, or need to be reverted?
3. Implement in Minimal, Coherent Commits
Each commit should be self-contained, reviewable via
git show --color-moved, and pass lint/tests independently. If
extracting new files or moving code, do that in a separate commit.
Code Style
- Be consistent with existing code. Look at surrounding code and follow the same patterns.
- Use clear, greppable names. Future developers will
git grepto find relevant code. - Prefer readable code over clever code with explanatory comments. Comments should explain "why", not "what".
Commit Discipline
Each commit is a minimal coherent idea. This is non-negotiable.
Each Commit Must:
- Be coherent: One logical change, completely and atomically.
- Pass tests: Include test updates in the same commit as code changes.
- Not introduce regressions: Work is ordered so no commit makes things worse.
- Be minimal and reviewable: Don't combine moving code with changing it; use small prep commits for no-op refactoring.
Never:
- Mix multiple separable changes in a single commit.
- Create a commit that "fixes" a mistake from an earlier commit in the same PR; instead, use the rebasing techniques below to amend the original commit.
- Include debugging code, commented-out code, or temporary TODOs.
- Use "Also" in a commit message — it hints the commit should be split.
Commit Message Format
subsystem: Summary in 72 characters or less.
The body explains why and how. Include context that helps reviewers
understand your reasoning and verification, without repeating details
visible in the diff metadata.
Line-wrap at 68-70 characters, except URLs and verbatim content.
Fixes #123.Subsystem prefix: lower-case, before the colon. End summary with a period.
- Good:
ci: Use GHCR registry cache for main branch Docker builds. - Good:
helm: Allow for adding annotations to the service. - Good:
entrypoint: Add support for AUTH_LDAP_* settings. - Bad:
Fix bug,Update code,gather_subscriptions was broken
Linking issues:
Fixes #123.— automatically closes the issue.Fixes part of #123.— does not close (for partial fixes).- Never:
Partially fixes #123.(GitHub ignores "partially").
Rebasing Commits (Non-Interactive)
Since git rebase -i requires an interactive editor, use
GIT_SEQUENCE_EDITOR to supply the todo list via a script:
Squashing fixups:
git commit --fixup=<target-hash>, then:GIT_SEQUENCE_EDITOR=/path/to/todo-script.sh git rebase -i <base>Note:
--autosquashalone without-idoes not reorder or squash anything.Rewording messages: In the todo script, use
execlines:pick <hash> Original message exec GIT_EDITOR=/path/to/new-msg-script.sh git commit --amend
Self-Review Checklist
- PR addresses all points in the issue
- Code follows existing patterns
- Names are clear and greppable
- Each commit is a minimal coherent idea
- Commit messages and PR description are well done
- No debugging code or unnecessary comments remain
- No secrets or credentials in environment variable defaults
- Documentation updated if behavior changes
- Refactoring is complete (
git grepfor remaining occurrences)
Always output a recommended PR summary+description following the guidelines below.
Pull Request Guidelines
PR Description Should:
Output the PR description in a markdown code block so formatting copy-pastes correctly into GitHub.
- Start with a
Fixes: #...line linking the issue. - Explain why the change is needed, not just what changed.
- Link to relevant issues or discussions.
- Call out open questions or decisions you're uncertain about.
PR Description Should Not:
- Regurgitate information visible from the diff.
- Make claims you haven't verified.
When to Pause and Discuss
- The approach involves security-sensitive code
- The change affects many files (>10)
- The feature design isn't fully specified
- Existing tests are failing for unclear reasons
Key Documentation Links
- Commit discipline: https://zulip.readthedocs.io/en/latest/contributing/commit-discipline.html
- Docker environment variables: https://zulip.readthedocs.io/projects/docker/en/latest/reference/environment-vars.html
- Docker Compose guide: https://zulip.readthedocs.io/projects/docker/en/latest/how-to/compose-index.html
- Helm chart: https://zulip.readthedocs.io/projects/docker/en/latest/how-to/helm-index.html
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

