Skip to content

Service Directory Layout

Atlas Docs Bot edited this page Oct 10, 2026 · 1 revision

9.7. Service Directory Layout

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.

1. Layout

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.

2. Adding or changing a service

  1. Edit services/<name>/service.yml (the manifest) and/or services/<name>/compose.yml (the fragment).
  2. The schema lives at bootstrapper/schemas/service.schema.json.
  3. Run the schema lint locally:
    uv run --project bootstrapper python -m tools.validate_fragments
    Validates every manifest against bootstrapper/schemas/service.schema.json and the cross-manifest rules. Exits non-zero on any violation.
  4. If you changed any env-affecting field, also run the consistency tests. They catch orphan .env.example keys, manifest vars missing from .env.example, and duplicate ownership:
    uv run --project bootstrapper pytest bootstrapper/tests/test_env_example_consistency.py
    Note: .env.example is AUTO-GENERATED from the manifests' env: declarations by bootstrapper/services/env_assembler.py. After adding or changing env vars in a service.yml, regenerate it:
    uv run --project bootstrapper python -m services.env_assembler
    tests/test_env_assembler.py enforces byte-equivalence between the committed file and the assembler's output. Never edit .env.example by hand.
  5. New service? Add the fragment's path to the include: list in the root docker-compose.yml. Service order comes from the depends_on: topology (see bootstrapper/services/topology.py). The full checklist, including CLI registration, tracks and the test fixtures, is in Adding a service.

3. Folder-name rules

  • 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.

4. Per-service README.md

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.

5. Subfolder convention

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.

6. _user/ overlay slot

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.

Atlas Documentation

Clone this wiki locally