Docker modular stack
Define, scaffold, and lint Docker services for any project. Three modes: (1) Scaffold — copy curated templates (postgres, valkey, grafana, langfuse, litellm, 30+ more) into a new project with generated docker-compose.yaml, .env, and Taskfile; (2) Add — given any tool's documentation, derive a compliant service.yaml from scratch; (3) Lint — validate any service definition against the project's conventions. Use when setting up a docker stack, adding a new docker service from docs, or checking whether a service definition is correct.From its SKILL.md
npx -y skills add knvpk/Agentic --skill docker-modular-stackAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
9.8 KB, ~2.5k tokens by cl100k_base, as published. Nobody here has run it
docker-modular-stack
Three modes — read the user's intent and pick one:
| User says | Mode |
|---|---|
| "set up docker stack", "scaffold services", "add postgres/grafana/…" (named template) | Scaffold |
| "add [tool] to docker", "create a service for [tool]", provides docs/URL/README | Add new tool |
| "check this service", "does this follow the conventions", "lint this yaml" | Lint |
MODE A — Scaffold from templates
A1 — Collect inputs
Ask before doing anything else:
- Project slug (kebab-case, e.g.
my-app) — Compose project name, DNS zone prefix. Lowercase + hyphens only. - Docker network prefix (e.g.
10.9) — first two octets of subnet. Remind user to check for conflicts:docker network ls. - Networking mode —
coredns(default) ortraefik.- CoreDNS: DNS-based
.internalhostnames; systemd-resolved config generated in Taskfile. - Traefik: HTTP reverse proxy; ports 80/443 on host; label-based routing.
- CoreDNS: DNS-based
Derive: DNS_ZONE = {slug}.internal, COMPOSE_NETWORK = {slug}_main.
A2 — Show service menu
Read references/catalog.md for the full list. Present grouped by layer:
NETWORK: [ ] coredns [ ] traefik [ ] kong
DATA: [ ] postgres [ ] clickhouse [ ] valkey [ ] redis
[ ] minio [ ] neo4j [ ] falkor_db [ ] chroma
OBSERVABILITY: [ ] grafana [ ] tempo [ ] otel-collector
[ ] langfuse [ ] phoenix [ ] hyperdx
COMMUNICATIONS: [ ] mailpit [ ] mailslurper
APP_DEPENDENCY: [ ] authentik [ ] oryd [ ] graphiti
APP: [ ] litellm [ ] hasura [ ] kestra [ ] hermes
[ ] archon [ ] paperclip [ ] tensorzero
[ ] mission_control [ ] prefect
[ ] ollama [ ] webui [ ] inspector
CoreDNS mode: auto-include coredns.
A3 — Auto-resolve dependencies
otel-collector → clickhouse
graphiti → falkor_db
grafana → postgres, clickhouse
authentik → postgres, valkey
oryd → postgres
hasura → postgres
kestra → postgres
litellm → postgres
langfuse → postgres, clickhouse, minio, valkey
webui → ollama (only auto-add if ollama also selected)
Deduplicate. Inform the user what was auto-added.
A4 — Copy service files
Copy from assets/services/{service}/ → {project-root}/docker/{service}/. Apply substitutions:
| Placeholder | Replace with |
|---|---|
PLACEHOLDER_DNS_ZONE | {slug}.internal |
PLACEHOLDER_NET_PREFIX | {prefix} |
PLACEHOLDER_COMPOSE_NETWORK | {slug}_main |
Files containing PLACEHOLDER_DNS_ZONE: coredns/Corefile, langfuse.yaml, litellm/service.yaml.
Flat services (no folder — copy as docker/{name}.yaml):
redis.yaml, valkey.yaml, minio.yaml, chroma.yaml, phoenix.yaml, hyperdx.yaml, mailpit.yaml, mailslurper.yaml, langfuse.yaml, ollama.yaml, webui.yaml, inspector.yaml, neo4j.yaml.
A5 — Generate docker-compose.yaml
name: "{slug}"
include:
- docker/{service}/service.yaml # folder services
- docker/{service}.yaml # flat services
networks:
main:
driver: bridge
ipam:
config:
- subnet: {prefix}.0.0/16
gateway: "{prefix}.0.1"
A6 — Generate .env
Open assets/env.template. Splice sections for selected services using the header map:
| Section header | Service(s) |
|---|---|
Postgres (db) | postgres |
ClickHouse (analytics_db) | clickhouse |
Valkey / Redis (cache) | valkey, redis |
Neo4j (graph_db) | neo4j |
FalkorDB (graph_db1) | falkor_db |
MinIO / Object Store (os) | minio |
Authentik (idp) | authentik |
Ory Hydra (oauth2) + Ory Kratos (users) | oryd |
Hasura | hasura |
LiteLLM | litellm |
Langfuse | langfuse |
Grafana | grafana |
Graphiti | graphiti |
Archon | archon |
Hermes | hermes |
Paperclip | paperclip |
HyperDX | hyperdx |
AWS | litellm, tensorzero, paperclip (include if any selected) |
OpenAI | litellm, tensorzero (include if any selected) |
Open WebUI | webui |
Chroma | chroma |
Misc | always include |
A7 — Generate Taskfile.yaml
CoreDNS:
version: "3"
dotenv: ['.env']
tasks:
dns:setup:
desc: Forward {DNS_ZONE} queries to CoreDNS. Requires sudo.
cmds:
- sudo mkdir -p /etc/systemd/resolved.conf.d
- |
sudo tee /etc/systemd/resolved.conf.d/{slug}.conf > /dev/null <<'EOF'
[Resolve]
DNS={prefix}.255.254
Domains=~{DNS_ZONE}
EOF
- sudo systemctl restart systemd-resolved
dns:teardown:
cmds:
- sudo rm -f /etc/systemd/resolved.conf.d/{slug}.conf
- sudo systemctl restart systemd-resolved
Traefik:
version: "3"
dotenv: ['.env']
tasks:
hosts:setup:
desc: Add /etc/hosts entries for Traefik services. Requires sudo.
cmds:
- sudo tee -a /etc/hosts <<'EOF'
127.0.0.1 traefik.{slug}.local
EOF
hosts:teardown:
cmds:
- sudo sed -i '/{slug}\.local/d' /etc/hosts
MODE B — Add new tool from documentation
Use when the user provides a tool name, Docker Hub URL, README, or any documentation for a service not in the template library.
B1 — Extract from docs
Read the provided documentation and extract:
- Image: exact name on Docker Hub / GHCR. Check available tags.
- Required env vars: what must be set for the container to start.
- Optional env vars: configuration knobs.
- Ports: which ports the container listens on and what they serve (UI vs. API vs. internal).
- Volumes: what data directories need persistence.
- Healthcheck: any
/health,/ping, or/_statusendpoint; or a CLI command the image ships. - Dependencies: does it need a database, cache, or other service?
B2 — Make conventions decisions
Apply the conventions checklist (see below) to every decision:
- Layer — classify by role: network / data / observability / communications / app_dependency / app.
- Container name — generic purpose noun, not the tool name (e.g.
metrics_dbnotprometheus). - Image tag — pick the most recent stable, non-RC tag. Prefer
:{version}-alpine, then:{version}-slim, then:{version}. - Custom packages — if the base image needs additions, write a
Dockerfile FROM {image}:{tag}and comment outimage:inservice.yaml. - IP (CoreDNS mode) — assign from the correct layer range (see catalog.md).
- File layout — flat
.yamlif no config files; folder withservice.yaml+config/if config is needed.
B3 — Write the service file
Produce a service.yaml (or flat {tool}.yaml) that passes every item in the conventions checklist. Then:
- Add it to
docker/in the project. - Add its
include:line todocker-compose.yaml. - Add its env vars to
.env. - If CoreDNS: add its hostname to
coredns/Corefile(new stanza or entry).
MODE C — Lint / review
Run this checklist against any service definition the user provides. Report each failure with the rule that was violated.
Conventions checklist
File structure
- Flat
.yamlif no config files; folder withservice.yaml+config/if config needed - Folder/file name matches the tool name exactly (kebab-case)
Naming
- Container service name is a generic purpose noun, not the tool name
- No
container_name:field anywhere
Labels
- Every service and helper container has a
layer=label - Helper containers inherit the same layer as their parent
Images
- Tag is pinned to a specific version — not
latest,main, or any floating tag - Alpine variant used if available (
:{version}-alpine); slim second; full debian/ubuntu only if no alternative - Tag is a stable release — no
-rc,-m0x,-beta,-alpha,-milestonesuffixes - If custom packages needed:
Dockerfileextends upstream image; originalimage:line is commented out inservice.yaml
Networking
- No ports exposed to host unless the port serves a UI for external access
- Inter-service comms use Docker network service names, not
localhost - CoreDNS mode: static IP assigned from correct layer range (see catalog.md)
CoreDNS networking (check only when networking mode is CoreDNS)
- Service names contain no underscores — underscores are not valid DNS hostname characters; use hyphens (e.g.
mission-controlnotmission_control) - Authentik service (
idp-server) includesAUTHENTIK_LISTEN__HTTP: "0.0.0.0:80"— without this, Authentik binds at port 9000 and all cross-service SSO URLs must include:9000
Volumes
- Named (managed) volumes used for data
- Bind mounts used only for config files
Service definition
- Healthcheck present if the image supports one
-
condition: service_healthyused independs_onwhen dependency has a healthcheck - Helper containers (worker, beat, mcp) defined in the same file as their parent service
- No init-containers
- Env vars use inline
KEY: "value"syntax — not- KEY=VALUEarray form
What ships with it: 56 files
57.1 KB alongside SKILL.md, 1 of them executable
assets/
- env.template7.7 KB
- services/archon/Dockerfile121 B
- services/archon/service.yaml586 B
- services/authentik/service.yaml1.2 KB
- services/chroma.yaml391 B
- services/clickhouse/init_scripts/initdb.sql36 B
- services/clickhouse/service.yaml704 B
- services/coredns/Corefile170 B
- services/coredns/Dockerfile349 B
- services/coredns/service.yaml236 B
- services/falkor_db/service.yaml875 B
- services/grafana/service.yaml1.1 KB
- services/graphiti/config.yaml1.8 KB
- services/graphiti/service.yaml449 B
- services/hasura/service.yaml1.2 KB
- services/hermes/config.yaml80 B
- services/hermes/Dockerfile145 B
- services/hermes/service.yaml811 B
- services/hyperdx.yaml165 B
- services/inspector.yaml156 B
- services/kestra/config/application.yaml630 B
- services/kestra/service.yaml517 B
- services/kong/config/kong.yml4.1 KB
- services/kong/service.yaml477 B
- services/langfuse.yaml4.2 KB
- services/litellm/config.yaml4.1 KB
- services/litellm/service.yaml1.9 KB
- services/mailpit.yaml221 B
- services/mailslurper.yaml96 B
- services/minio.yaml607 B
- services/mission_control/service.yaml259 B
- services/neo4j/service.yaml426 B
- services/neo4j.yaml0 B
- services/ollama.yaml522 B
- services/oryd/config/hydra.yml411 B
- services/oryd/resources/client_unified_app.json407 B
- services/oryd/service.yaml952 B
- services/otel-collector/config.yaml464 B
- services/otel-collector/service.yaml444 B
- services/paperclip/Dockerfile596 B
16 more files not listed here. See all 56 in the repository.
Gives 0 of the 12 instructions most docs writing skills give in ~2.5k tokens
Counted across 1,637 of the 3,044 authors here whose files we hold, read 2026-08-07
- Announce the skill at startin 54 of 1637, across 26 files
- Convert legacy doc files before editingin 45 of 1637, across 7 files
- Predict questions readers might askin 42 of 1637, across 4 files
- Generate clarifying questions for initial contextin 42 of 1637, across 3 files
- Create document scaffold with placeholder textin 42 of 1637, across 3 files
- Brainstorm content options for each sectionin 42 of 1637, across 3 files
- Test the document with a fresh context-less instancein 42 of 1637, across 3 files
- Include exact file paths in every taskin 42 of 1637, across 15 files
- Ask interview questions one at a timein 42 of 1637, across 27 files
- Apply surgical edits during refinementin 41 of 1637, across 2 files
- Offer structured workflow or freeformin 40 of 1637, across 1 file
- Ask for document meta-contextin 40 of 1637, across 2 files
Said here and by no other author read
- collect project slug subnet and networking mode
- present service menu grouped by layer
- auto resolve and deduplicate service dependencies
- copy service files applying placeholder substitutions
- generate docker compose file including selected services
- splice environment variable sections for selected services
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.