container-superposition 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +24 -15
  2. package/dist/scripts/init.js +1 -1534
  3. package/dist/scripts/init.js.map +1 -1
  4. package/dist/tool/cli/args.d.ts +20 -0
  5. package/dist/tool/cli/args.d.ts.map +1 -0
  6. package/dist/tool/cli/args.js +325 -0
  7. package/dist/tool/cli/args.js.map +1 -0
  8. package/dist/tool/cli/run.d.ts +2 -0
  9. package/dist/tool/cli/run.d.ts.map +1 -0
  10. package/dist/tool/cli/run.js +318 -0
  11. package/dist/tool/cli/run.js.map +1 -0
  12. package/dist/tool/commands/adopt.d.ts.map +1 -1
  13. package/dist/tool/commands/adopt.js +1 -27
  14. package/dist/tool/commands/adopt.js.map +1 -1
  15. package/dist/tool/commands/doctor.d.ts +3 -0
  16. package/dist/tool/commands/doctor.d.ts.map +1 -1
  17. package/dist/tool/commands/doctor.js +1068 -70
  18. package/dist/tool/commands/doctor.js.map +1 -1
  19. package/dist/tool/commands/explain.d.ts.map +1 -1
  20. package/dist/tool/commands/explain.js +18 -0
  21. package/dist/tool/commands/explain.js.map +1 -1
  22. package/dist/tool/commands/migrate.d.ts +7 -0
  23. package/dist/tool/commands/migrate.d.ts.map +1 -0
  24. package/dist/tool/commands/migrate.js +52 -0
  25. package/dist/tool/commands/migrate.js.map +1 -0
  26. package/dist/tool/questionnaire/answers.d.ts +16 -0
  27. package/dist/tool/questionnaire/answers.d.ts.map +1 -0
  28. package/dist/tool/questionnaire/answers.js +102 -0
  29. package/dist/tool/questionnaire/answers.js.map +1 -0
  30. package/dist/tool/questionnaire/composer.d.ts +3 -3
  31. package/dist/tool/questionnaire/composer.d.ts.map +1 -1
  32. package/dist/tool/questionnaire/composer.js +902 -37
  33. package/dist/tool/questionnaire/composer.js.map +1 -1
  34. package/dist/tool/questionnaire/presets.d.ts +60 -0
  35. package/dist/tool/questionnaire/presets.d.ts.map +1 -0
  36. package/dist/tool/questionnaire/presets.js +164 -0
  37. package/dist/tool/questionnaire/presets.js.map +1 -0
  38. package/dist/tool/questionnaire/questionnaire.d.ts +10 -0
  39. package/dist/tool/questionnaire/questionnaire.d.ts.map +1 -0
  40. package/dist/tool/questionnaire/questionnaire.js +580 -0
  41. package/dist/tool/questionnaire/questionnaire.js.map +1 -0
  42. package/dist/tool/schema/manifest-migrations.d.ts +5 -0
  43. package/dist/tool/schema/manifest-migrations.d.ts.map +1 -1
  44. package/dist/tool/schema/manifest-migrations.js +45 -0
  45. package/dist/tool/schema/manifest-migrations.js.map +1 -1
  46. package/dist/tool/schema/overlay-loader.d.ts.map +1 -1
  47. package/dist/tool/schema/overlay-loader.js +25 -0
  48. package/dist/tool/schema/overlay-loader.js.map +1 -1
  49. package/dist/tool/schema/project-config.d.ts +14 -2
  50. package/dist/tool/schema/project-config.d.ts.map +1 -1
  51. package/dist/tool/schema/project-config.js +277 -34
  52. package/dist/tool/schema/project-config.js.map +1 -1
  53. package/dist/tool/schema/target-rules.d.ts +78 -0
  54. package/dist/tool/schema/target-rules.d.ts.map +1 -0
  55. package/dist/tool/schema/target-rules.js +367 -0
  56. package/dist/tool/schema/target-rules.js.map +1 -0
  57. package/dist/tool/schema/types.d.ts +123 -12
  58. package/dist/tool/schema/types.d.ts.map +1 -1
  59. package/dist/tool/utils/merge.d.ts.map +1 -1
  60. package/dist/tool/utils/merge.js +9 -0
  61. package/dist/tool/utils/merge.js.map +1 -1
  62. package/dist/tool/utils/parameters.d.ts +76 -0
  63. package/dist/tool/utils/parameters.d.ts.map +1 -0
  64. package/dist/tool/utils/parameters.js +125 -0
  65. package/dist/tool/utils/parameters.js.map +1 -0
  66. package/dist/tool/utils/paths.d.ts +2 -0
  67. package/dist/tool/utils/paths.d.ts.map +1 -0
  68. package/dist/tool/utils/paths.js +31 -0
  69. package/dist/tool/utils/paths.js.map +1 -0
  70. package/docs/creating-overlays.md +151 -2
  71. package/docs/deployment-targets.md +88 -56
  72. package/docs/examples.md +20 -17
  73. package/docs/filesystem-contract.md +5 -0
  74. package/docs/minimal-and-editor.md +65 -5
  75. package/docs/overlay-imports.md +202 -101
  76. package/docs/overlays.md +162 -34
  77. package/docs/quick-reference.md +99 -0
  78. package/docs/specs/003-mkdocs2-overlay/spec.md +114 -0
  79. package/docs/specs/004-doctor-fix/spec.md +70 -0
  80. package/docs/specs/005-cuda-overlay/spec.md +101 -0
  81. package/docs/specs/006-rocm-overlay/spec.md +109 -0
  82. package/docs/specs/007-init-project-file/spec.md +66 -0
  83. package/docs/specs/007-target-aware-generation/spec.md +126 -0
  84. package/docs/specs/008-project-file-canonical/spec.md +83 -0
  85. package/docs/specs/009-project-env/spec.md +147 -0
  86. package/docs/specs/010-compose-env-materialization/spec.md +130 -0
  87. package/docs/specs/011-overlay-parameters/spec.md +235 -0
  88. package/overlays/.shared/README.md +105 -21
  89. package/overlays/.shared/compose/common-healthchecks.md +60 -0
  90. package/overlays/.shared/compose/nvidia-gpu-devcontainer.yml +22 -0
  91. package/overlays/.shared/vscode/recommended-extensions.json +15 -11
  92. package/overlays/alertmanager/setup.sh +4 -19
  93. package/overlays/alertmanager/verify.sh +8 -9
  94. package/overlays/all/README.md +43 -0
  95. package/overlays/all/devcontainer.patch.json +6 -0
  96. package/overlays/all/overlay.yml +14 -0
  97. package/overlays/amp/setup.sh +5 -0
  98. package/overlays/bun/setup.sh +10 -1
  99. package/overlays/bun/verify.sh +6 -1
  100. package/overlays/claude-code/setup.sh +5 -0
  101. package/overlays/cloudflared/setup.sh +9 -12
  102. package/overlays/codex/README.md +9 -6
  103. package/overlays/codex/devcontainer.patch.json +7 -1
  104. package/overlays/codex/setup.sh +5 -0
  105. package/overlays/codex/verify.sh +8 -0
  106. package/overlays/comfyui/.env.example +34 -0
  107. package/overlays/comfyui/README.md +342 -0
  108. package/overlays/comfyui/devcontainer.patch.json +15 -0
  109. package/overlays/comfyui/docker-compose.yml +39 -0
  110. package/overlays/comfyui/overlay.yml +20 -0
  111. package/overlays/comfyui/setup.sh +36 -0
  112. package/overlays/comfyui/verify.sh +103 -0
  113. package/overlays/commitlint/setup.sh +5 -0
  114. package/overlays/cuda/README.md +179 -0
  115. package/overlays/cuda/devcontainer.patch.json +7 -0
  116. package/overlays/cuda/overlay.yml +17 -0
  117. package/overlays/cuda/setup.sh +32 -0
  118. package/overlays/cuda/verify.sh +38 -0
  119. package/overlays/devcontainer-cli/README.md +50 -0
  120. package/overlays/devcontainer-cli/devcontainer.patch.json +13 -0
  121. package/overlays/devcontainer-cli/overlay.yml +16 -0
  122. package/overlays/devcontainer-cli/setup.sh +14 -0
  123. package/overlays/direnv/devcontainer.patch.json +6 -0
  124. package/overlays/direnv/setup.sh +7 -6
  125. package/overlays/dotnet/setup.sh +14 -7
  126. package/overlays/duckdb/devcontainer.patch.json +1 -2
  127. package/overlays/gcloud/devcontainer.patch.json +0 -6
  128. package/overlays/gcloud/setup.sh +51 -0
  129. package/overlays/gemini-cli/setup.sh +5 -0
  130. package/overlays/git-helpers/devcontainer.patch.json +2 -1
  131. package/overlays/go/setup.sh +15 -14
  132. package/overlays/jaeger/overlay.yml +2 -0
  133. package/overlays/just/setup.sh +5 -17
  134. package/overlays/k3d/README.md +201 -0
  135. package/overlays/k3d/devcontainer.patch.json +9 -0
  136. package/overlays/k3d/overlay.yml +19 -0
  137. package/overlays/k3d/setup.sh +34 -0
  138. package/overlays/k3d/verify.sh +38 -0
  139. package/overlays/keycloak/docker-compose.yml +6 -4
  140. package/overlays/keycloak/verify.sh +4 -3
  141. package/overlays/kind/devcontainer.patch.json +1 -2
  142. package/overlays/kind/setup.sh +8 -17
  143. package/overlays/minio/setup.sh +10 -18
  144. package/overlays/mkdocs/overlay.yml +2 -1
  145. package/overlays/mkdocs2/README.md +135 -0
  146. package/overlays/mkdocs2/devcontainer.patch.json +19 -0
  147. package/overlays/mkdocs2/overlay.yml +17 -0
  148. package/overlays/mkdocs2/setup.sh +67 -0
  149. package/overlays/mkdocs2/verify.sh +35 -0
  150. package/overlays/modern-cli-tools/devcontainer.patch.json +7 -1
  151. package/overlays/modern-cli-tools/setup.sh +21 -71
  152. package/overlays/mongodb/devcontainer.patch.json +0 -6
  153. package/overlays/mongodb/setup.sh +59 -0
  154. package/overlays/mysql/verify.sh +4 -3
  155. package/overlays/nats/.env.example +1 -1
  156. package/overlays/nats/README.md +1 -1
  157. package/overlays/nats/docker-compose.yml +1 -1
  158. package/overlays/ngrok/setup.sh +9 -6
  159. package/overlays/nodejs/setup.sh +5 -0
  160. package/overlays/ollama/.env.example +14 -0
  161. package/overlays/ollama/README.md +325 -0
  162. package/overlays/ollama/devcontainer.patch.json +14 -0
  163. package/overlays/ollama/docker-compose.yml +24 -0
  164. package/overlays/ollama/overlay.yml +22 -0
  165. package/overlays/ollama/setup.sh +106 -0
  166. package/overlays/ollama/verify.sh +99 -0
  167. package/overlays/open-webui/.env.example +5 -0
  168. package/overlays/open-webui/README.md +162 -0
  169. package/overlays/open-webui/devcontainer.patch.json +14 -0
  170. package/overlays/open-webui/docker-compose.yml +23 -0
  171. package/overlays/open-webui/overlay.yml +38 -0
  172. package/overlays/openapi-tools/devcontainer.patch.json +1 -2
  173. package/overlays/openapi-tools/setup.sh +9 -8
  174. package/overlays/opencode/setup.sh +5 -0
  175. package/overlays/otel-collector/overlay.yml +2 -0
  176. package/overlays/otel-collector/setup.sh +3 -16
  177. package/overlays/otel-demo-nodejs/verify.sh +8 -9
  178. package/overlays/otel-demo-python/verify.sh +16 -10
  179. package/overlays/pandoc/README.md +22 -15
  180. package/overlays/pandoc/devcontainer.patch.json +6 -2
  181. package/overlays/pandoc/setup.sh +217 -18
  182. package/overlays/pandoc/verify.sh +16 -4
  183. package/overlays/pgvector/.env.example +6 -0
  184. package/overlays/pgvector/README.md +215 -0
  185. package/overlays/pgvector/devcontainer.patch.json +23 -0
  186. package/overlays/pgvector/docker-compose.yml +32 -0
  187. package/overlays/pgvector/overlay.yml +44 -0
  188. package/overlays/playwright/devcontainer.patch.json +3 -1
  189. package/overlays/playwright/setup.sh +37 -0
  190. package/overlays/postgres/.env.example +5 -5
  191. package/overlays/postgres/devcontainer.patch.json +4 -4
  192. package/overlays/postgres/docker-compose.yml +15 -5
  193. package/overlays/postgres/overlay.yml +19 -1
  194. package/overlays/powershell/setup.sh +49 -13
  195. package/overlays/pre-commit/setup.sh +12 -3
  196. package/overlays/prometheus/overlay.yml +2 -0
  197. package/overlays/promtail/verify.sh +16 -10
  198. package/overlays/pulumi/devcontainer.patch.json +1 -1
  199. package/overlays/python/setup.sh +28 -9
  200. package/overlays/python/verify.sh +4 -2
  201. package/overlays/qdrant/.env.example +4 -0
  202. package/overlays/qdrant/README.md +216 -0
  203. package/overlays/qdrant/devcontainer.patch.json +20 -0
  204. package/overlays/qdrant/docker-compose.yml +25 -0
  205. package/overlays/qdrant/overlay.yml +40 -0
  206. package/overlays/redpanda/docker-compose.yml +3 -5
  207. package/overlays/rocm/README.md +227 -0
  208. package/overlays/rocm/devcontainer.patch.json +4 -0
  209. package/overlays/rocm/overlay.yml +17 -0
  210. package/overlays/rocm/setup.sh +45 -0
  211. package/overlays/rocm/verify.sh +47 -0
  212. package/overlays/rust/setup.sh +11 -18
  213. package/overlays/skaffold/README.md +256 -0
  214. package/overlays/skaffold/devcontainer.patch.json +9 -0
  215. package/overlays/skaffold/overlay.yml +20 -0
  216. package/overlays/skaffold/setup.sh +33 -0
  217. package/overlays/skaffold/verify.sh +24 -0
  218. package/overlays/spec-kit/setup.sh +7 -3
  219. package/overlays/sqlite/setup.sh +14 -14
  220. package/overlays/sqlserver/docker-compose.yml +3 -3
  221. package/overlays/sqlserver/verify.sh +22 -5
  222. package/overlays/tempo/verify.sh +16 -10
  223. package/overlays/tilt/devcontainer.patch.json +1 -2
  224. package/overlays/tilt/setup.sh +14 -4
  225. package/overlays/windsurf-cli/setup.sh +27 -4
  226. package/overlays/windsurf-cli/verify.sh +13 -3
  227. package/package.json +4 -2
  228. package/templates/scripts/setup-utils.sh +228 -0
  229. package/tool/schema/config.schema.json +141 -9
  230. package/tool/schema/overlay-manifest.schema.json +38 -0
  231. package/overlays/.shared/compose/common-healthchecks.yml +0 -38
  232. /package/overlays/otel-demo-nodejs/{Dockerfile-otel-demo-nodejs → Dockerfile} +0 -0
  233. /package/overlays/otel-demo-nodejs/{package-otel-demo-nodejs.json → package.json} +0 -0
  234. /package/overlays/otel-demo-nodejs/{server-otel-demo-nodejs.js → server.js} +0 -0
  235. /package/overlays/otel-demo-nodejs/{tracing-otel-demo-nodejs.js → tracing.js} +0 -0
  236. /package/overlays/otel-demo-python/{Dockerfile-otel-demo-python → Dockerfile} +0 -0
  237. /package/overlays/otel-demo-python/{app-otel-demo-python.py → app.py} +0 -0
  238. /package/overlays/otel-demo-python/{requirements-otel-demo-python.txt → requirements.txt} +0 -0
@@ -4,29 +4,39 @@ Overlays can import shared configuration fragments from `overlays/.shared/` to r
4
4
 
5
5
  ## Overview
6
6
 
7
- Import functionality allows overlays to reference common configuration files instead of duplicating them in every overlay. This promotes DRY (Don't Repeat Yourself) principles and makes it easier to maintain consistent patterns.
7
+ The import mechanism allows overlays to reference common configuration files instead of duplicating them. This promotes DRY principles and makes it easier to maintain consistent patterns.
8
+
9
+ Two import fields are supported in `overlay.yml`:
10
+
11
+ - **`imports:`** — shared devcontainer patch fragments (`.json`, `.yaml`, `.env`) applied before the overlay's own `devcontainer.patch.json`
12
+ - **`compose_imports:`** — shared docker-compose YAML fragments (`.yml`, `.yaml`) deep-merged into `docker-compose.yml` before the overlay's own `docker-compose.yml`
8
13
 
9
14
  ## Shared Directory Structure
10
15
 
11
16
  ```
12
17
  overlays/
13
18
  ├── .shared/
14
- │ ├── otel/ # OpenTelemetry configurations
15
- ├── otel-base-config.yaml # Base OTEL collector config
16
- │ │ └── instrumentation.env # Common env vars for instrumentation
17
- ├── compose/ # Docker Compose patterns
18
- │ └── common-healthchecks.yml # Standard healthcheck configurations
19
- └── vscode/ # VS Code extension sets
20
- └── recommended-extensions.json # Commonly recommended extensions
19
+ │ ├── README.md
20
+ │ ├── otel/
21
+ │ │ ├── instrumentation.env # OTEL SDK env vars imported by otel-collector, prometheus, jaeger
22
+ │ └── otel-base-config.yaml # Base OTEL collector pipeline config
23
+ ├── compose/
24
+ │ ├── nvidia-gpu-devcontainer.yml # NVIDIA GPU passthrough for the devcontainer service
25
+ └── common-healthchecks.md # Standard Docker Compose healthcheck patterns (reference only)
26
+ │ └── vscode/
27
+ │ └── recommended-extensions.json # Commonly recommended VS Code extensions (devcontainer patch format)
21
28
  ├── prometheus/
22
- │ ├── overlay.yml # Can import from .shared/
29
+ │ ├── overlay.yml # imports: [.shared/otel/instrumentation.env]
30
+ │ └── devcontainer.patch.json
31
+ ├── jaeger/
32
+ │ ├── overlay.yml # imports: [.shared/otel/instrumentation.env]
23
33
  │ └── devcontainer.patch.json
24
- └── jaeger/
25
- ├── overlay.yml # Can import from .shared/
26
- └── devcontainer.patch.json
34
+ └── ollama/
35
+ ├── overlay.yml # compose_imports: [.shared/compose/nvidia-gpu-devcontainer.yml]
36
+ └── docker-compose.yml
27
37
  ```
28
38
 
29
- ## Using Imports
39
+ ## Using `imports` (devcontainer patch fragments)
30
40
 
31
41
  Add the `imports` field to your `overlay.yml` manifest:
32
42
 
@@ -48,101 +58,186 @@ ports:
48
58
  - 9090
49
59
  imports:
50
60
  - .shared/otel/instrumentation.env
51
- - .shared/compose/common-healthchecks.yml
52
61
  ```
53
62
 
63
+ **Rules:**
64
+
65
+ - All paths **must** begin with `.shared/` — references outside `.shared/` are rejected (path traversal prevention)
66
+ - Paths are relative to `overlays/`
67
+ - Order is significant — fragments are applied in declaration order, then the overlay's own `devcontainer.patch.json`
68
+ - Missing files, unsupported types, or path traversal attempts cause generation to fail with a message identifying the overlay and the broken reference
69
+
70
+ ## Using `compose_imports` (docker-compose fragments)
71
+
72
+ Add the `compose_imports` field to your `overlay.yml` manifest to merge shared docker-compose YAML fragments into the generated `docker-compose.yml`:
73
+
74
+ ```yaml
75
+ id: ollama
76
+ name: Ollama
77
+ # ... other fields ...
78
+ compose_imports:
79
+ - .shared/compose/nvidia-gpu-devcontainer.yml
80
+ ```
81
+
82
+ **Rules:**
83
+
84
+ - All paths **must** begin with `.shared/` (same path traversal rules as `imports`)
85
+ - Files must be `.yml` or `.yaml`
86
+ - Fragments are deep-merged in declaration order, then the overlay's own `docker-compose.yml` is merged last (overlay wins on conflict)
87
+ - Missing files, wrong types, or traversal attempts cause generation to fail
88
+
54
89
  ## Supported File Types
55
90
 
56
- ### JSON Files (`.json`)
91
+ ### `imports:` devcontainer patch fragments
92
+
93
+ | Extension | How it is merged |
94
+ | ---------------- | ------------------------------------------------------------------------------ |
95
+ | `.json` | Deep-merged into `devcontainer.json` patch (same as `devcontainer.patch.json`) |
96
+ | `.yaml` / `.yml` | Loaded and deep-merged into `devcontainer.json` patch |
97
+ | `.env` | Concatenated into `.env.example` with a `# from .shared/…` comment header |
98
+ | Anything else | Rejected with a clear unsupported-type error |
99
+
100
+ ### `compose_imports:` — docker-compose fragments
57
101
 
58
- Merged as devcontainer patches, just like `devcontainer.patch.json`.
102
+ | Extension | How it is merged |
103
+ | ---------------- | --------------------------------------------------------------------------- |
104
+ | `.yaml` / `.yml` | Deep-merged into `docker-compose.yml` before the overlay's own compose file |
105
+ | Anything else | Rejected with a clear unsupported-type error |
59
106
 
60
- **Example: `.shared/vscode/recommended-extensions.json`**
107
+ ### JSON import example
61
108
 
62
- ```json
109
+ ```jsonc
110
+ // overlays/.shared/vscode/recommended-extensions.json
63
111
  {
112
+ "$schema": "https://raw.githubusercontent.com/devcontainers/spec/main/schemas/devContainer.base.schema.json",
64
113
  "customizations": {
65
114
  "vscode": {
66
115
  "extensions": [
67
116
  "streetsidesoftware.code-spell-checker",
68
117
  "usernamehw.errorlens",
69
- "editorconfig.editorconfig"
70
- ]
71
- }
72
- }
118
+ "eamodio.gitlens",
119
+ ],
120
+ },
121
+ },
73
122
  }
74
123
  ```
75
124
 
76
- ### YAML Files (`.yaml`, `.yml`)
77
-
78
- Loaded and merged as devcontainer patches. Useful for complex configurations.
79
-
80
- **Example: `.shared/otel/otel-base-config.yaml`**
125
+ ### YAML devcontainer import example
81
126
 
82
127
  ```yaml
83
- receivers:
84
- otlp:
85
- protocols:
86
- grpc:
87
- endpoint: 0.0.0.0:4317
88
- http:
89
- endpoint: 0.0.0.0:4318
128
+ # overlays/.shared/otel/otel-base-config.yaml
129
+ remoteEnv:
130
+ OTEL_SERVICE_NAME: my-service
131
+ OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
90
132
  ```
91
133
 
92
- ### Environment Files (`.env`)
134
+ ### ENV import example
93
135
 
94
- Merged into `.env.example` with a comment indicating the import source.
136
+ ```bash
137
+ # overlays/.shared/otel/instrumentation.env
138
+ # OpenTelemetry SDK Configuration
139
+ OTEL_SERVICE_NAME=my-service
140
+ OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
141
+ OTEL_EXPORTER_OTLP_PROTOCOL=grpc
142
+ OTEL_TRACES_SAMPLER=always_on
143
+ OTEL_TRACES_EXPORTER=otlp
144
+ OTEL_METRICS_EXPORTER=otlp
145
+ OTEL_LOGS_EXPORTER=otlp
146
+ ```
95
147
 
96
- **Example: `.shared/otel/instrumentation.env`**
148
+ When this `.env` fragment is imported, the generated `.env.example` will contain:
97
149
 
98
150
  ```bash
99
- # OpenTelemetry Configuration
151
+ # from .shared/otel/instrumentation.env
100
152
  OTEL_SERVICE_NAME=my-service
101
153
  OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
102
- OTEL_TRACES_SAMPLER=always_on
154
+ ...
103
155
  ```
104
156
 
105
- ## How Imports Work
157
+ ### YAML compose_import example
106
158
 
107
- 1. **Resolution**: Imports are resolved relative to the `overlays/` directory
108
- 2. **Order**: Imports are applied in the order listed, then the overlay's own files
109
- 3. **Merging**:
110
- - JSON/YAML: Deep merged into devcontainer configuration
111
- - ENV: Concatenated into `.env.example` with source comments
112
- 4. **Validation**: Doctor command validates that all imports exist and are valid
159
+ ```yaml
160
+ # overlays/.shared/compose/nvidia-gpu-devcontainer.yml
161
+ services:
162
+ devcontainer:
163
+ deploy:
164
+ resources:
165
+ reservations:
166
+ devices:
167
+ - driver: nvidia
168
+ count: all
169
+ capabilities: [gpu]
170
+ ```
113
171
 
114
- ## Benefits
172
+ When this fragment is imported via `compose_imports`, the generated `docker-compose.yml` will include the `deploy` block on the `devcontainer` service merged with contributions from all other overlays.
115
173
 
116
- ### Reduced Duplication
174
+ ## Import Ordering and Conflict Resolution
117
175
 
118
- Before imports:
176
+ ### `imports` ordering
177
+
178
+ Imports are applied in declaration order, then the overlay's own `devcontainer.patch.json` is applied last:
119
179
 
120
180
  ```
121
- prometheus/devcontainer.patch.json (200 lines with OTEL config)
122
- jaeger/devcontainer.patch.json (200 lines with OTEL config)
123
- grafana/devcontainer.patch.json (200 lines with OTEL config)
181
+ [import 1] [import 2] → … → [import N] → [overlay own patch]
124
182
  ```
125
183
 
126
- After imports:
184
+ - The **second** import wins over the first on key conflict
185
+ - The **overlay's own patch always wins** over any shared fragment
186
+
187
+ This means overlays can intentionally override shared defaults by setting the same key in their `devcontainer.patch.json`.
188
+
189
+ ### `compose_imports` ordering
190
+
191
+ For each overlay, compose fragments are merged before the overlay's own `docker-compose.yml`, in this order:
127
192
 
128
193
  ```
129
- .shared/otel/otel-base-config.yaml (50 lines, shared)
130
- prometheus/overlay.yml (imports: [.shared/otel/otel-base-config.yaml])
131
- jaeger/overlay.yml (imports: [.shared/otel/otel-base-config.yaml])
132
- grafana/overlay.yml (imports: [.shared/otel/otel-base-config.yaml])
194
+ [base template compose] → [overlay 1 compose_imports] → [overlay 1 docker-compose.yml] [overlay 2 compose_imports] → [overlay 2 docker-compose.yml] → …
133
195
  ```
134
196
 
135
- ### Consistency
197
+ - Each overlay's `docker-compose.yml` wins over its own `compose_imports`
198
+ - Later overlays win over earlier overlays on key conflict
199
+
200
+ ## Worked Example: OTEL Instrumentation
136
201
 
137
- All overlays using the same shared config stay in sync automatically.
202
+ Many observability overlays need OTEL environment variables. With imports, these are defined once:
138
203
 
139
- ### Maintainability
204
+ **`overlays/.shared/otel/instrumentation.env`** — shared once
140
205
 
141
- Update shared configuration once, all importing overlays benefit.
206
+ **`overlays/otel-collector/overlay.yml`:**
142
207
 
143
- ## Validation
208
+ ```yaml
209
+ imports:
210
+ - .shared/otel/instrumentation.env
211
+ ```
144
212
 
145
- The `doctor` command validates imports:
213
+ **`overlays/prometheus/overlay.yml`:**
214
+
215
+ ```yaml
216
+ imports:
217
+ - .shared/otel/instrumentation.env
218
+ ```
219
+
220
+ **`overlays/jaeger/overlay.yml`:**
221
+
222
+ ```yaml
223
+ imports:
224
+ - .shared/otel/instrumentation.env
225
+ ```
226
+
227
+ When any of these overlays is used, the generated `.env.example` will contain the OTEL environment variables with a comment indicating they came from the shared fragment.
228
+
229
+ ## Security: Path Traversal Prevention
230
+
231
+ Import paths are validated before any file is read:
232
+
233
+ 1. The path **must** begin with `.shared/`
234
+ 2. The resolved absolute path **must** remain inside `overlays/.shared/`
235
+
236
+ Any import that fails either check causes generation to abort with an error identifying the overlay and the rejected path. References like `../secret.json`, `/etc/passwd`, or `other-overlay/file.json` are all rejected.
237
+
238
+ ## Validation via Doctor
239
+
240
+ The `doctor` command validates all imports for every overlay:
146
241
 
147
242
  ```bash
148
243
  container-superposition doctor
@@ -150,60 +245,66 @@ container-superposition doctor
150
245
 
151
246
  Checks performed:
152
247
 
153
- - Import files exist
154
- - File types are supported (`.json`, `.yaml`, `.yml`, `.env`)
155
- - No broken import references
248
+ - Import path starts with `.shared/` (path traversal check)
249
+ - Import path resolves within `overlays/.shared/` (traversal check)
250
+ - Import file exists on disk
251
+ - File type is one of `.json`, `.yaml`, `.yml`, `.env` (for `imports:`)
252
+ - File type is one of `.yaml`, `.yml` (for `compose_imports:`)
156
253
 
157
- ## Creating Shared Configurations
254
+ Broken references are reported with the overlay ID and the bad path so maintainers can fix them quickly.
158
255
 
159
- 1. **Identify common patterns** across overlays
160
- 2. **Extract to `.shared/` subdirectory** with descriptive path
161
- 3. **Update overlays** to import the shared file
162
- 4. **Test** that composition works correctly
163
- 5. **Document** the shared file's purpose in `.shared/README.md`
256
+ ## Viewing Imports in `explain`
164
257
 
165
- ## Example: OTEL Instrumentation
258
+ When an overlay has imports, they are shown in the `explain` output:
166
259
 
167
- Many observability overlays need OTEL instrumentation. Instead of duplicating these environment variables:
260
+ ```bash
261
+ container-superposition explain prometheus
262
+ ```
263
+
264
+ ```
265
+ Shared Imports:
266
+ (Fragments from overlays/.shared/ applied before this overlay)
267
+ 📎 .shared/otel/instrumentation.env
268
+ ```
168
269
 
169
- **Create:** `overlays/.shared/otel/instrumentation.env`
270
+ When an overlay has compose_imports, they are also shown:
170
271
 
171
272
  ```bash
172
- # OpenTelemetry SDK Configuration
173
- OTEL_SERVICE_NAME=my-service
174
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
175
- OTEL_EXPORTER_OTLP_PROTOCOL=grpc
176
- OTEL_RESOURCE_ATTRIBUTES=deployment.environment=development
177
- OTEL_TRACES_SAMPLER=always_on
178
- OTEL_TRACES_EXPORTER=otlp
179
- OTEL_METRICS_EXPORTER=otlp
180
- OTEL_LOGS_EXPORTER=otlp
273
+ container-superposition explain ollama
274
+ ```
275
+
276
+ ```
277
+ Shared Compose Imports:
278
+ (docker-compose fragments from overlays/.shared/ merged before this overlay)
279
+ 🐳 .shared/compose/nvidia-gpu-devcontainer.yml
181
280
  ```
182
281
 
183
- **Import in overlays:**
282
+ ## Creating Shared Configurations
184
283
 
185
- ```yaml
186
- # overlays/prometheus/overlay.yml
187
- imports:
188
- - .shared/otel/instrumentation.env
284
+ 1. **Identify common patterns** across multiple overlays
285
+ 2. **Create `overlays/.shared/<category>/<name>.<ext>`** — use descriptive paths, one concern per file
286
+ 3. **Update overlays** to reference the fragment via `imports:` or `compose_imports:` in their `overlay.yml`
287
+ 4. **Update `.shared/README.md`** to document the fragment's purpose and which overlays use it
288
+ 5. **Test** with `npm test` and `container-superposition doctor` to verify
189
289
 
190
- # overlays/jaeger/overlay.yml
191
- imports:
192
- - .shared/otel/instrumentation.env
193
- ```
290
+ ## Downstream Impact Awareness
291
+
292
+ A single change to a shared fragment affects every overlay that imports it. Before editing a shared fragment:
194
293
 
195
- Now all OTEL-compatible overlays share the same instrumentation configuration!
294
+ - Check `.shared/README.md` to see which overlays import it
295
+ - Use `grep -r "fragment-name" overlays/*/overlay.yml` to find all importers
296
+ - Run the full test suite after any shared fragment change
196
297
 
197
298
  ## Best Practices
198
299
 
199
- 1. **Keep shared files focused** - One concern per file
200
- 2. **Use descriptive paths** - `.shared/otel/instrumentation.env` not `.shared/env1.env`
201
- 3. **Document shared files** - Add comments explaining purpose and usage
202
- 4. **Version carefully** - Changes to shared files affect all importing overlays
203
- 5. **Test imports** - Verify overlay composition works after adding imports
300
+ 1. **One concern per file** `instrumentation.env` not `all-the-things.env`
301
+ 2. **Descriptive category paths** `.shared/otel/` not `.shared/misc/`
302
+ 3. **Comment your fragments** explain purpose and usage at the top of each file
303
+ 4. **Keep fragments small** big shared files create tight coupling
304
+ 5. **Overlay-specific overrides are fine** an overlay's own patch always wins; diverging from a shared baseline is expected and supported
204
305
 
205
306
  ## See Also
206
307
 
207
308
  - [Creating Overlays](creating-overlays.md)
208
- - [Overlay Metadata](overlay-metadata-archive.md)
209
- - [Doctor Command](../README.md#doctor-command)
309
+ - `overlays/.shared/README.md` — shared fragment catalogue with usage details
310
+ - CONTRIBUTING.md — overlay authoring guide