Service Directory Layout - thekaveh/atlas GitHub Wiki
Per-service manifest folders. Each subfolder is one service family — a
logical grouping of co-lifecycled containers. Examples: supabase/ owns all
eight supabase-* containers; n8n/ owns n8n + n8n-worker + n8n-init;
open-webui/ owns open-web-ui + open-webui-init.
The root docker-compose.yml is a thin include: shell that merges every
fragment under services/<name>/compose.yml. See
docs/CONTRIBUTING-services.md for the full architecture rationale.
services/
├── README.md # this file
├── supabase/
│ ├── service.yml # manifest: env vars, sources, deps, image refs
│ ├── compose.yml # Docker Compose fragment for the family's containers
│ ├── README.md # service family overview (required by policy)
│ └── db/scripts/ # SQL init scripts (bind-mounted into supabase-db-init)
├── redis/
│ ├── service.yml
│ └── compose.yml
└── … (additional manifest and documentation-only service families)
A virtual service (e.g. cloud-providers/, tts-provider/, globals/) has
no compose fragment because it owns no containers. It still ships
service.yml plus operator-facing documentation because it owns environment
variables and source toggles that other services consume.
Current service-family and SOURCE-surface counts are generated from the manifests into the documentation home and service catalog; this file does not duplicate those changing totals.
- Edit
services/<name>/service.yml(the manifest) and/orservices/<name>/compose.yml(the fragment). - The schema lives at
bootstrapper/schemas/service.schema.json. - Run the schema lint locally:
Validates every manifest against
uv run --project bootstrapper python -m tools.validate_fragments
bootstrapper/schemas/service.schema.jsonand the cross-manifest rules. Exits non-zero on any violation. - If you changed any env-affecting field, also run the consistency tests.
They catch orphan
.env.examplekeys, manifest vars missing from.env.example, and duplicate ownership:Note:uv run --project bootstrapper pytest bootstrapper/tests/test_env_example_consistency.py
.env.exampleis AUTO-GENERATED from the manifests'env:declarations bybootstrapper/services/env_assembler.py. After adding or changing env vars in aservice.yml, regenerate it:uv run --project bootstrapper python -m services.env_assembler
tests/test_env_assembler.pyenforces byte-equivalence between the committed file and the assembler's output. Never edit.env.exampleby hand. - New service? Add the fragment's path to the
include:list in the rootdocker-compose.yml. Service order comes from thedepends_on:topology (seebootstrapper/services/topology.py). The full checklist, including CLI registration, tracks and the test fixtures, is in Adding a service.
- Lowercase kebab-case (matches the
name:field in the manifest). - Names starting with
_are reserved (e.g._user/). - Names starting with
.are ignored by the loader.
Every service family, including virtual manifests, ships documentation
describing its contract. A sibling README.md normally describes the
containers it owns, the role of any init/, build/, provider/,
extras/, or db/ subdirectories, and any non-obvious operational gotchas.
The manifest's docs: value may point to another canonical Markdown page when
an aggregate guide is authoritative.
A service with no appropriate page must carry a schema-validated
docs_exception with an explicit because clause. The clause needs at least
four substantive words and at least three distinct terms.
Generic reasons and exceptions on already-documented services fail manifest
validation.
When a service brings its own source code, init scripts, build context, or
config files, those live under a named subdirectory inside the service
folder. The full convention (app/, build/, init/,
pull/, config/, db/, provider/, extras/, workflows-stage/) is
documented in
docs/CONTRIBUTING-services.md.
Downstream forks consuming this repo as a git submodule can layer extra
services under services/_user/<name>/ without touching the upstream tree.
The folder is gitignored upstream. Full design: see
docs/CONTRIBUTING-services.md.