mirror of
https://github.com/tiennm99/composes.git
synced 2026-10-11 03:13:16 +00:00
docs: split agent rules into .claude/rules and list example role names
CLAUDE.md keeps the overview and deployment rules; naming, images and comments, workspace services, and environment and secrets move to topic files that load with it. Naming gains example role names for supporting containers, as examples rather than a fixed list.
This commit is contained in:
1 parent
09506ae84f
commit
59f8d94b97
6 files changed
+189
-154
No files matched your search
@@ -0,0 +1,55 @@
|
||||
# Environment and secrets
|
||||
|
||||
## Environment variable order
|
||||
|
||||
`environment:` entries are ordered by how badly the service needs them — not
|
||||
alphabetically, and not by when they were added:
|
||||
|
||||
1. **Must have** — without it the service does not do its job, or is exposed.
|
||||
Auth secrets, the uid/gid its files belong to, host allow-lists, proxy
|
||||
trust, and the mod list that supplies the toolchain.
|
||||
2. **Should have** — it starts without these, but behaves wrongly for this
|
||||
setup: timezone, default workspace, shell, git identity, pinned tool
|
||||
versions, extra packages.
|
||||
3. **Optional** — cosmetics and conveniences; dropping one changes nothing
|
||||
functional. Window titles, prompt labels.
|
||||
|
||||
Grouping wins over the tiers. Variables that belong together stay on adjacent
|
||||
lines — `PUID`/`PGID`, `PASSWORD`/`SUDO_PASSWORD`, the four `GIT_*` entries,
|
||||
the `PASEO_*` daemon settings, `DOCKER_MODS` with the `INSTALL_PACKAGES` and
|
||||
`NODEJS_MOD_VERSION` that configure it — and the whole group sits at the tier
|
||||
of its most important member, even when a member on its own would rank lower.
|
||||
Within a group, the variable others configure comes first.
|
||||
|
||||
Optional variables are listed but commented out, in the form
|
||||
`# - KEY=${KEY:-default}` (`# KEY: ${KEY:-default}` in a map-style
|
||||
`environment:`), so the service runs without them and enabling one
|
||||
means uncommenting its line. The matching `.env.example` entry is commented out
|
||||
the same way (`# KEY=default`). Must-have and should-have variables stay active.
|
||||
|
||||
Do not write the tier into the file as a comment — the order is the
|
||||
documentation. Where every variable is required, as in `alloy`, the tiers
|
||||
collapse and the existing grouping stands.
|
||||
|
||||
`.env.example` follows its compose file's order. The names differ — one
|
||||
`PASSWORD` can feed several container variables, and `SERVICE_HOSTNAME` feeds
|
||||
`hostname:` and `HOST` — so each entry sits where the first compose entry that reads it sits.
|
||||
Reordering a compose file means reordering the `.env.example` with it.
|
||||
|
||||
## Secrets
|
||||
|
||||
Every service reads secrets from a sibling `.env`. Never commit one — the root
|
||||
`.gitignore` covers `.env`/`*.env` and re-includes `.env.example`. Keep
|
||||
`.env.example` in sync whenever a compose file gains or drops a variable.
|
||||
|
||||
`.env.example` is a template for anyone, so every value in it stays generic —
|
||||
the service's own name, a placeholder domain, or an empty string. Never a real
|
||||
hostname, git identity, email, domain or account name. Personal values are set
|
||||
per deployment, in the Coolify or Dokploy environment for that app, and live
|
||||
only in the gitignored `.env`.
|
||||
|
||||
Compose interpolation reads the deploying shell's environment before the
|
||||
`.env` file, so a variable must not share a name with anything the shell
|
||||
already exports. `HOSTNAME` is the trap: it is set inside every container,
|
||||
including the one Coolify itself runs in, and would silently win. Hence
|
||||
`SERVICE_HOSTNAME` in `code-server`, `code-server-lsio` and `paseo`.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Images and comments
|
||||
|
||||
## Installing software in an image
|
||||
|
||||
Follow the upstream project's own documented install method, or the one the
|
||||
community has settled on. Do not hand-roll a download, and do not take a stale
|
||||
distro package just because `apt install` is shorter — check what version it
|
||||
actually gives you first.
|
||||
|
||||
Where it gets installed depends on the kind of service. In a workspace service
|
||||
(see `workspace-services.md`), install tools into a location that survives a
|
||||
redeploy — the container user's home volume, such as `~/.local/bin` — not into
|
||||
the image. The
|
||||
exception is a system package that is more than a single binary — shared
|
||||
libraries, a daemon, anything that hooks into `/etc` or the system paths. That
|
||||
goes in the image, through the system package manager. Every other service
|
||||
installs into the image.
|
||||
|
||||
## Comments in compose files, Dockerfiles and scripts
|
||||
|
||||
This holds for every file in a service directory, not just the compose file.
|
||||
|
||||
A comment says *what* a section installs, configures or does, in a line or
|
||||
two. It does not explain *why*. Reasons — why not the distro package, why that
|
||||
directory, why a version is pinned, why a step runs here and not there, what
|
||||
would break if it were simplified — go in the service's `README.md`, where
|
||||
they can be read in full and where someone deciding whether to change
|
||||
something will actually look.
|
||||
|
||||
So: no rationale, no trade-offs, no cautionary notes in the file itself. When a
|
||||
choice needs defending, write the defence in the README and let the header
|
||||
comment point at it. Keep the README current whenever a file changes, otherwise
|
||||
the reasoning is simply lost rather than relocated.
|
||||
@@ -0,0 +1,58 @@
|
||||
# Naming
|
||||
|
||||
## File naming
|
||||
|
||||
Every service uses `compose.yml` — the current Compose spec name, and the
|
||||
shorter one. Not `docker-compose.yml`.
|
||||
|
||||
## Names
|
||||
|
||||
A service directory is named after the software it runs. When two services
|
||||
package the same software, the one that is not upstream's own image takes a
|
||||
suffix naming its source — `code-server-lsio` for LinuxServer's code-server —
|
||||
so both can coexist. The suffix is a directory name only, forced by the
|
||||
conflict; it is not a name to copy anywhere else.
|
||||
|
||||
Prefer each tool's official image, for the main service and for every
|
||||
supporting container alike. Upstream's official compose file or Docker guide
|
||||
is a starting point, not a spec: adapt it to the conventions in these rules
|
||||
rather than copying its layout and names as they are.
|
||||
|
||||
Inside `compose.yml`, the main service is named after its image —
|
||||
`code-server`, not `code-server-lsio`. Where the image's repository name is not
|
||||
the software's (`traffmonetizer/cli_v2`), use the software's name
|
||||
(`traffmonetizer`). A supporting container is named for its
|
||||
role, so the software behind it can be swapped without renaming: `db` for any
|
||||
database, `cache` for Redis, Valkey or Memcached, and a short role name such as
|
||||
`dockerproxy` for anything else (see the examples below). Swapping Redis for
|
||||
Valkey, MySQL for MariaDB, or one SQL database for PostgreSQL then leaves every
|
||||
name, hostname and volume as it is.
|
||||
|
||||
Role names in use or likely, as examples only — any short name that says what
|
||||
the container does is fine, and this list does not limit the choice:
|
||||
|
||||
| Role name | Typical software |
|
||||
| --- | --- |
|
||||
| `db` | PostgreSQL, MySQL, MariaDB, MongoDB, pgvector |
|
||||
| `cache` | Redis, Valkey, Memcached, KeyDB, Dragonfly |
|
||||
| `queue` / `broker` | RabbitMQ, NATS, Kafka |
|
||||
| `search` | Elasticsearch, OpenSearch, Meilisearch, Typesense |
|
||||
| `vector` | Qdrant, Weaviate, Milvus, when separate from `db` |
|
||||
| `storage` | MinIO, SeaweedFS, Garage — S3-compatible object storage |
|
||||
| `worker` | The app's own image running background jobs |
|
||||
| `scheduler` / `cron` | The app's own image running timed jobs |
|
||||
| `migrate` / `init` | One-off setup jobs that run and exit |
|
||||
| `dockerproxy` | `tecnativa/docker-socket-proxy` |
|
||||
| `proxy` | A reverse proxy inside the app, such as nginx or Caddy |
|
||||
| `mail` / `smtp` | Mailpit, a Postfix relay |
|
||||
| `browser` | Headless Chrome (browserless), for agents |
|
||||
| `tunnel` | cloudflared |
|
||||
| `backup` | A database dump or volume backup running alongside |
|
||||
|
||||
A volume is named `<service>-<what it holds>`, after the service that mounts it
|
||||
and its mount point or meaning — `code-server-home`, `code-server-workspace`,
|
||||
`db-data`, `cache-data`.
|
||||
|
||||
Services declare no networks. Coolify creates one per app and attaches every
|
||||
container to it, so there is nothing to add. Should a service ever need its own,
|
||||
it is named after the main service: `code-server-network`.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Workspace services
|
||||
|
||||
A service someone works *inside* — an editor, a coding agent, anything with a
|
||||
shell — gets exactly two named volumes: one for the container user's home
|
||||
directory, one mounted at `/workspace`. The home volume holds settings,
|
||||
credentials and CLI logins; `/workspace` holds the code. Point whatever
|
||||
variable selects the working directory at `/workspace`.
|
||||
|
||||
`code-server`, `code-server-lsio`, `paseo` and `webtop` all follow this. A service with no
|
||||
human inside it does not — an agent such as `hermes` or `openclaw` keeps the
|
||||
volume layout of its official Docker guide.
|
||||
|
||||
The split is so that wiping one does not take the other. Reinstalling an editor
|
||||
should not cost you a repository, and deleting a repository should not cost you
|
||||
your extensions and logins.
|
||||
|
||||
Check who owns `/workspace` on a fresh volume. Docker creates it `root:root`
|
||||
unless the image ships the directory, and an image that drops to a non-root
|
||||
user will not be able to write there. `code-server`, `code-server-lsio` and `webtop` need an
|
||||
explicit `chown` for this reason; `paseo` does not.
|
||||
@@ -98,7 +98,7 @@ the hypotheses and what would distinguish them instead of guessing a fix.
|
||||
|
||||
## 6. Fix and report
|
||||
|
||||
Change only `<service>/`, following this repository's `CLAUDE.md`: comments
|
||||
Change only `<service>/`, following this repository's `CLAUDE.md` and `.claude/rules/`: comments
|
||||
say *what*, reasons go in the service `README.md`, `.env.example` stays in sync
|
||||
and in compose order. Pin an exact version only when the newer release is
|
||||
proven broken, and write what breaks in the README.
|
||||
|
||||
@@ -4,89 +4,43 @@ Personal docker compose collection. One directory per service, each holding
|
||||
`compose.yml`, its own `README.md`, a committed `.env.example`, and a
|
||||
gitignored `.env`.
|
||||
|
||||
## File naming
|
||||
Topic rules live in `.claude/rules/` and load with this file:
|
||||
|
||||
Every service uses `compose.yml` — the current Compose spec name, and the
|
||||
shorter one. Not `docker-compose.yml`.
|
||||
- `naming.md` — file, directory, service, volume and network names, with
|
||||
example role names for supporting containers.
|
||||
- `images-and-comments.md` — where and how software is installed, and what
|
||||
comments in compose files, Dockerfiles and scripts may say.
|
||||
- `workspace-services.md` — the home and `/workspace` volume split for services
|
||||
someone works inside.
|
||||
- `environment-and-secrets.md` — `environment:` order, `.env.example`, and
|
||||
secrets.
|
||||
|
||||
## Names
|
||||
## Deployment target
|
||||
|
||||
A service directory is named after the software it runs. When two services
|
||||
package the same software, the one that is not upstream's own image takes a
|
||||
suffix naming its source — `code-server-lsio` for LinuxServer's code-server —
|
||||
so both can coexist. The suffix is a directory name only, forced by the
|
||||
conflict; it is not a name to copy anywhere else.
|
||||
Services are deployed through Coolify, not plain `docker compose` on a host.
|
||||
The platform owns the parts a standalone compose file would declare itself.
|
||||
|
||||
Prefer each tool's official image, for the main service and for every
|
||||
supporting container alike. Upstream's official compose file or Docker guide
|
||||
is a starting point, not a spec: adapt it to the conventions in this file
|
||||
rather than copying its layout and names as they are.
|
||||
|
||||
Inside `compose.yml`, the main service is named after its image —
|
||||
`code-server`, not `code-server-lsio`. Where the image's repository name is not
|
||||
the software's (`traffmonetizer/cli_v2`), use the software's name
|
||||
(`traffmonetizer`). A supporting container is named for its
|
||||
role, so the software behind it can be swapped without renaming: `db` for any
|
||||
database, `cache` for Redis, Valkey or Memcached, and a short role name such as
|
||||
`dockerproxy` for anything else. Swapping Redis for Valkey, MySQL for MariaDB,
|
||||
or one SQL database for PostgreSQL then leaves every name, hostname and volume
|
||||
as it is.
|
||||
|
||||
A volume is named `<service>-<what it holds>`, after the service that mounts it
|
||||
and its mount point or meaning — `code-server-home`, `code-server-workspace`,
|
||||
`db-data`, `cache-data`.
|
||||
|
||||
Services declare no networks. Coolify creates one per app and attaches every
|
||||
container to it, so there is nothing to add. Should a service ever need its own,
|
||||
it is named after the main service: `code-server-network`.
|
||||
|
||||
## Installing software in an image
|
||||
|
||||
Follow the upstream project's own documented install method, or the one the
|
||||
community has settled on. Do not hand-roll a download, and do not take a stale
|
||||
distro package just because `apt install` is shorter — check what version it
|
||||
actually gives you first.
|
||||
|
||||
Where it gets installed depends on the kind of service. In a workspace service
|
||||
(see below), install tools into a location that survives a redeploy — the
|
||||
container user's home volume, such as `~/.local/bin` — not into the image. The
|
||||
exception is a system package that is more than a single binary — shared
|
||||
libraries, a daemon, anything that hooks into `/etc` or the system paths. That
|
||||
goes in the image, through the system package manager. Every other service
|
||||
installs into the image.
|
||||
|
||||
## Comments in compose files, Dockerfiles and scripts
|
||||
|
||||
This holds for every file in a service directory, not just the compose file.
|
||||
|
||||
A comment says *what* a section installs, configures or does, in a line or
|
||||
two. It does not explain *why*. Reasons — why not the distro package, why that
|
||||
directory, why a version is pinned, why a step runs here and not there, what
|
||||
would break if it were simplified — go in the service's `README.md`, where
|
||||
they can be read in full and where someone deciding whether to change
|
||||
something will actually look.
|
||||
|
||||
So: no rationale, no trade-offs, no cautionary notes in the file itself. When a
|
||||
choice needs defending, write the defence in the README and let the header
|
||||
comment point at it. Keep the README current whenever a file changes, otherwise
|
||||
the reasoning is simply lost rather than relocated.
|
||||
|
||||
The root `README.md` is an index only — it covers the shared conventions and
|
||||
links out to each service. Per-service detail (variables, ports, storage)
|
||||
belongs in that service's README, not the root one. Adding a service means
|
||||
adding its README and a row to the root table.
|
||||
Coolify is the primary target: design, test and debug against it first.
|
||||
Dokploy is optional — keep a service working there when it costs nothing
|
||||
(the `restart:` policy below), but never trade Coolify behaviour for Dokploy
|
||||
compatibility, and do not block on Dokploy-only issues.
|
||||
|
||||
## Service READMEs stay inside their directory
|
||||
|
||||
A service's `README.md` describes that service and nothing else. It does not
|
||||
name, link to, or compare itself with another service, and it does not link up
|
||||
to the root README or CLAUDE.md. Shared conventions — the workspace volume
|
||||
to the root README, CLAUDE.md or `.claude/rules/`. Shared conventions — the workspace volume
|
||||
split, no published ports, the restart policy, secrets, variable order — are
|
||||
written once at the root and are not restated or "see the root for why"-linked
|
||||
from a service. A service README says what the service is, its variables,
|
||||
storage and wiring, and the reasons behind choices specific to that service.
|
||||
Keep it concise and minimal.
|
||||
|
||||
The root `README.md` is an index only — it covers the shared conventions and
|
||||
links out to each service. Per-service detail (variables, ports, storage)
|
||||
belongs in that service's README, not the root one. Adding a service means
|
||||
adding its README and a row to the root table.
|
||||
|
||||
This is a deployment rule, not a style preference. Each service is a separate
|
||||
Coolify app whose webhook watch path is `<service>/**`. A cross-link means
|
||||
renaming or editing one service touches another's directory and redeploys it.
|
||||
@@ -120,73 +74,6 @@ containers use.
|
||||
has no default home. Ask the user where it goes before adding it to a
|
||||
service directory.
|
||||
|
||||
## Workspace services
|
||||
|
||||
A service someone works *inside* — an editor, a coding agent, anything with a
|
||||
shell — gets exactly two named volumes: one for the container user's home
|
||||
directory, one mounted at `/workspace`. The home volume holds settings,
|
||||
credentials and CLI logins; `/workspace` holds the code. Point whatever
|
||||
variable selects the working directory at `/workspace`.
|
||||
|
||||
`code-server`, `code-server-lsio`, `paseo` and `webtop` all follow this. A service with no
|
||||
human inside it does not — an agent such as `hermes` or `openclaw` keeps the
|
||||
volume layout of its official Docker guide.
|
||||
|
||||
The split is so that wiping one does not take the other. Reinstalling an editor
|
||||
should not cost you a repository, and deleting a repository should not cost you
|
||||
your extensions and logins.
|
||||
|
||||
Check who owns `/workspace` on a fresh volume. Docker creates it `root:root`
|
||||
unless the image ships the directory, and an image that drops to a non-root
|
||||
user will not be able to write there. `code-server`, `code-server-lsio` and `webtop` need an
|
||||
explicit `chown` for this reason; `paseo` does not.
|
||||
|
||||
## Environment variable order
|
||||
|
||||
`environment:` entries are ordered by how badly the service needs them — not
|
||||
alphabetically, and not by when they were added:
|
||||
|
||||
1. **Must have** — without it the service does not do its job, or is exposed.
|
||||
Auth secrets, the uid/gid its files belong to, host allow-lists, proxy
|
||||
trust, and the mod list that supplies the toolchain.
|
||||
2. **Should have** — it starts without these, but behaves wrongly for this
|
||||
setup: timezone, default workspace, shell, git identity, pinned tool
|
||||
versions, extra packages.
|
||||
3. **Optional** — cosmetics and conveniences; dropping one changes nothing
|
||||
functional. Window titles, prompt labels.
|
||||
|
||||
Grouping wins over the tiers. Variables that belong together stay on adjacent
|
||||
lines — `PUID`/`PGID`, `PASSWORD`/`SUDO_PASSWORD`, the four `GIT_*` entries,
|
||||
the `PASEO_*` daemon settings, `DOCKER_MODS` with the `INSTALL_PACKAGES` and
|
||||
`NODEJS_MOD_VERSION` that configure it — and the whole group sits at the tier
|
||||
of its most important member, even when a member on its own would rank lower.
|
||||
Within a group, the variable others configure comes first.
|
||||
|
||||
Optional variables are listed but commented out, in the form
|
||||
`# - KEY=${KEY:-default}` (`# KEY: ${KEY:-default}` in a map-style
|
||||
`environment:`), so the service runs without them and enabling one
|
||||
means uncommenting its line. The matching `.env.example` entry is commented out
|
||||
the same way (`# KEY=default`). Must-have and should-have variables stay active.
|
||||
|
||||
Do not write the tier into the file as a comment — the order is the
|
||||
documentation. Where every variable is required, as in `alloy`, the tiers
|
||||
collapse and the existing grouping stands.
|
||||
|
||||
`.env.example` follows its compose file's order. The names differ — one
|
||||
`PASSWORD` can feed several container variables, and `SERVICE_HOSTNAME` feeds
|
||||
`hostname:` and `HOST` — so each entry sits where the first compose entry that reads it sits.
|
||||
Reordering a compose file means reordering the `.env.example` with it.
|
||||
|
||||
## Deployment target
|
||||
|
||||
Services are deployed through Coolify, not plain `docker compose` on a host.
|
||||
The platform owns the parts a standalone compose file would declare itself.
|
||||
|
||||
Coolify is the primary target: design, test and debug against it first.
|
||||
Dokploy is optional — keep a service working there when it costs nothing
|
||||
(the `restart:` policy below), but never trade Coolify behaviour for Dokploy
|
||||
compatibility, and do not block on Dokploy-only issues.
|
||||
|
||||
## Intentional omissions — do not "fix" these
|
||||
|
||||
These are deliberate, not oversights. Do not flag them as defects or add them
|
||||
@@ -209,24 +96,6 @@ policy leaves the container down after a crash or a host reboot. Setting it is
|
||||
correct on both. `traffmonetizer` sets `restart: always` on purpose, to be
|
||||
restarted as often as possible.
|
||||
|
||||
## Secrets
|
||||
|
||||
Every service reads secrets from a sibling `.env`. Never commit one — the root
|
||||
`.gitignore` covers `.env`/`*.env` and re-includes `.env.example`. Keep
|
||||
`.env.example` in sync whenever a compose file gains or drops a variable.
|
||||
|
||||
`.env.example` is a template for anyone, so every value in it stays generic —
|
||||
the service's own name, a placeholder domain, or an empty string. Never a real
|
||||
hostname, git identity, email, domain or account name. Personal values are set
|
||||
per deployment, in the Coolify or Dokploy environment for that app, and live
|
||||
only in the gitignored `.env`.
|
||||
|
||||
Compose interpolation reads the deploying shell's environment before the
|
||||
`.env` file, so a variable must not share a name with anything the shell
|
||||
already exports. `HOSTNAME` is the trap: it is set inside every container,
|
||||
including the one Coolify itself runs in, and would silently win. Hence
|
||||
`SERVICE_HOSTNAME` in `code-server`, `code-server-lsio` and `paseo`.
|
||||
|
||||
## Upstream sources
|
||||
|
||||
`sources/` is for upstream source checkouts used while debugging, cloned as
|
||||
|
||||
Reference in new issue
Block a user