composable-data-stack 0.4.0__py3-none-any.whl

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.
@@ -0,0 +1,872 @@
1
+ Metadata-Version: 2.4
2
+ Name: composable-data-stack
3
+ Version: 0.4.0
4
+ Summary: CLI for validating and composing composable data stack profiles
5
+ Author: Ronald Hensbergen
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/RonaldHensbergen/composable-data-stack
8
+ Project-URL: Documentation, https://github.com/RonaldHensbergen/composable-data-stack/tree/main/docs
9
+ Project-URL: Issues, https://github.com/RonaldHensbergen/composable-data-stack/issues
10
+ Project-URL: Repository, https://github.com/RonaldHensbergen/composable-data-stack
11
+ Keywords: data-platform,data-stack,docker-compose,infrastructure-as-code
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Software Development :: Build Tools
19
+ Classifier: Topic :: System :: Systems Administration
20
+ Requires-Python: >=3.14
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: PyYAML>=6.0
24
+ Requires-Dist: jsonschema>=4.22.0
25
+ Requires-Dist: jinja2>=3.0
26
+ Requires-Dist: packaging>=23.0
27
+ Requires-Dist: rich>=15.0
28
+ Provides-Extra: completion
29
+ Requires-Dist: argcomplete<4,>=3.0.0; extra == "completion"
30
+ Provides-Extra: dev
31
+ Requires-Dist: coverage>=7.6; extra == "dev"
32
+ Requires-Dist: bandit>=1.7; extra == "dev"
33
+ Requires-Dist: pip-audit>=2.7; extra == "dev"
34
+ Requires-Dist: ruff==0.16.2; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # 🚀 Composable Data Stack (CDS)
38
+
39
+ > **Terraform for data platforms.**
40
+ > Build, validate, secure, and evolve data stacks using modular components and explicit contracts.
41
+
42
+ ![Composable Data Stack logo](assets/branding/logo.svg)
43
+
44
+ ---
45
+
46
+ ## 🧠 What Is CDS (In 1 Minute)
47
+
48
+ Composable Data Stack (CDS) is a framework for defining and assembling data platforms from reusable modules such as orchestrators, warehouses, BI tools, and secrets providers.
49
+
50
+ ## 🤝 Get Involved
51
+
52
+ - **Star and follow** on GitHub: [RonaldHensbergen/composable-data-stack](https://github.com/RonaldHensbergen/composable-data-stack)
53
+ - **Contribute**: open a discussion, file an issue, or send a PR to help shape CDS
54
+ - **Proof it**: if you run it in a real workflow, share your feedback — good or bad
55
+
56
+ > **Note:** Development helper tools are located in the `tools/` directory (git-ignored). See `tools/pr-cli/README.md` for PR creation scripts.
57
+
58
+ Instead of hardcoding integrations or relying on fragile pipelines, CDS introduces:
59
+
60
+ - 🔧 **Modules**: reusable components (Dagster, Postgres, Superset)
61
+ - 🔗 **Contracts**: explicit interfaces between components
62
+ - 🧩 **Profiles**: fully composed, runnable stacks
63
+
64
+ Think of it as Infrastructure as Code, but for data platforms.
65
+
66
+ ---
67
+
68
+ ## ⚡ Why CDS
69
+
70
+ Modern data platforms force a trade-off:
71
+
72
+ |Approach|Problem|
73
+ |---|---|
74
+ |Monolithic stack|Rigid, hard to evolve|
75
+ |Custom pipelines|Flexible but fragile and inconsistent|
76
+
77
+ CDS gives you the best of both:
78
+
79
+ - composability without chaos
80
+ - flexibility with guarantees
81
+ - modularity with structure
82
+ - no vendor lock-in by design
83
+
84
+ ---
85
+
86
+ ## 🎯 When To Use CDS
87
+
88
+ Use CDS if you:
89
+
90
+ - want to swap tools (Airflow ↔ Dagster, Superset ↔ Metabase)
91
+ - need reproducible environments across dev, CI, and prod
92
+ - are building a platform for multiple teams
93
+ - want contract-driven integration instead of implicit coupling
94
+
95
+ CDS may be overkill if:
96
+
97
+ - you only run a single-tool stack
98
+ - you do not need interchangeable components
99
+
100
+ ---
101
+
102
+ ## 🏗️ Example
103
+
104
+ The `local-dagster-postgres-superset` profile defines:
105
+
106
+ - Dagster -> orchestration
107
+ - Postgres -> storage
108
+ - Superset -> BI
109
+
110
+ ### What CDS Does
111
+
112
+ 1. Validates module definitions
113
+ 2. Resolves contract bindings
114
+ 3. Checks compatibility and security constraints
115
+ 4. Produces a fully wired stack definition
116
+
117
+ `cds plan` resolves the full dependency graph before runtime configuration is generated, ensuring all module interactions are valid and predictable.
118
+
119
+ You can replace components without changing system behavior:
120
+
121
+ ```text
122
+ Dagster -> Airflow
123
+ Superset -> Metabase
124
+ Postgres -> MariaDB
125
+ ```
126
+
127
+ ---
128
+
129
+ ## 🗺️ Architecture Overview
130
+
131
+ CDS wires modules through **contracts**, not direct dependencies. This section has two levels: a high-level picture of what gets wired together ([Overview](#overview)), and a detailed look at what happens when you run a CDS command ([Internal Flow](#internal-flow)).
132
+
133
+ ### Overview
134
+
135
+ Below, `local-dagster-postgres-superset` wires Dagster to Postgres to Superset through contracts:
136
+
137
+ ```mermaid
138
+ ---
139
+ flowchart TD
140
+ Dagster[Dagster]
141
+ Postgres[(Postgres)]
142
+ Superset[Superset]
143
+
144
+ Dagster -->|transformation-runner| Postgres
145
+ Postgres -->|warehouse-query| Superset
146
+
147
+ classDef tool stroke:#818cf8,fill:#eef2ff
148
+ classDef database stroke:#2dd4bf,fill:#f0fdfa
149
+ classDef viz stroke:#a78bfa,fill:#f5f3ff
150
+
151
+ class Dagster tool
152
+ class Postgres database
153
+ class Superset viz
154
+ ```
155
+
156
+ ### Internal Flow
157
+
158
+ CDS splits into two phases: **compile-time**, where `cds` itself validates, resolves, and renders a plain `docker-compose.yaml`; and **runtime**, where the real `docker compose` binary builds and starts containers from that file. CDS never runs containers itself.
159
+
160
+ `cds test` runs the full compile-time pipeline in order — **validate → security → plan → render**. A `validate` (or `plan`) failure skips all downstream stages, but a **security** failure does not skip `plan`/`render`: those stages still run so `cds test` reports every stage's status in one pass, while the overall command still exits non-zero if any stage failed. `cds up` runs the same pipeline **minus security** (`validate → plan → render`), then hands off to `docker compose build`/`docker compose up`. See the [CLI table](#️-cli) below for exactly what each command runs.
161
+
162
+ - **Validate** checks profile shape, module configs, dependencies, secret refs, contract bindings, and outputs.
163
+ - **Security** (`cds test` only) runs rule-based checks against modules and resolved secrets; a failing check is reported but does not prevent `plan`/`render` from also running.
164
+ - **Plan** resolves contract bindings and substitutes secrets and defaults.
165
+ - **Render** generates the final `docker-compose.yaml`, with secret values as `${CDS_VAR}` placeholders; never the raw value.
166
+ - **Runtime** (`cds up` only): `docker compose build` (skippable with `--no-build`), then `docker compose up --detach`, then a live `cds state` view that polls until the stack settles (skippable with `--detach`). Build/up/log output is persisted to a log file (`.cds/logs/` by default). Docker Compose, not CDS, resolves `${CDS_VAR}` placeholders from a `.env` file (see `cds init`) and starts the containers.
167
+
168
+ Passing `validate → security → plan → render` proves the profile *compiles*
169
+ correctly — it is not proof that the resulting stack *runs* correctly. For the
170
+ broader success criteria used to certify a profile (booting the rendered
171
+ stack, service health, an end-to-end pipeline run, and downstream data
172
+ consumption in Superset), see
173
+ [docs/profile-testing/test-plan.md](docs/profile-testing/test-plan.md) and
174
+ [docs/profile-testing/failure-path-and-ci.md](docs/profile-testing/failure-path-and-ci.md).
175
+
176
+ ```mermaid
177
+ ---
178
+ flowchart TD
179
+ subgraph compile["Compile-time (cds)"]
180
+ direction TB
181
+ Profile[/profile.yaml/]
182
+ Validate[Validate]
183
+ Security["Security checks<br/>(cds test only)"]
184
+ Plan[Plan]
185
+ Render[Render]
186
+ Compose[/docker-compose.yaml/]
187
+ Stop1((stops here))
188
+
189
+ Profile --> Validate
190
+ Validate -->|structural + contract checks| Security
191
+ Security -->|rule-based checks| Plan
192
+ Plan -->|resolve + substitute| Render
193
+ Render --> Compose
194
+
195
+ Validate -.->|E020, E041, E042, E081| Stop1
196
+ end
197
+
198
+ subgraph runtime["Runtime (docker compose, cds up only)"]
199
+ direction TB
200
+ Build["docker compose build<br/>(skip with --no-build)"]
201
+ Up["docker compose up"]
202
+ Env[(".env file")]
203
+ Containers["running containers,<br/>real secret values injected"]
204
+
205
+ Build --> Up
206
+ Env -.->|resolves CDS_VAR| Up
207
+ Up --> Containers
208
+ end
209
+
210
+ Compose --> Build
211
+
212
+ classDef stage stroke:#818cf8,fill:#eef2ff
213
+ classDef artifact stroke:#2dd4bf,fill:#f0fdfa
214
+ classDef stop stroke:#f87171,fill:#fef2f2,stroke-dasharray: 3 3
215
+ classDef runtimeNode stroke:#a78bfa,fill:#f5f3ff
216
+
217
+ class Validate,Security,Plan,Render stage
218
+ class Profile,Compose artifact
219
+ class Stop1 stop
220
+ class Build,Up,Env,Containers runtimeNode
221
+ ```
222
+
223
+ This mirrors the [`cds` command table](#️-cli) below: `validate`, `plan`, and `render` are each callable on their own; `security` only runs as part of `cds test`, not `cds up`. Module and contract definitions follow the [Contract-First](#contract-first) design principle, so most of what "Validate" and "Plan" check comes directly from `module.yaml` and `profile.yaml`.
224
+
225
+ **See also:** [Security](#-security) for what the security stage checks, [Troubleshooting](#️-troubleshooting) for what each error code means and how to fix it, and [docs/architecture.md § Secrets and contract resolution](docs/architecture.md#secrets-and-contract-resolution) for a deeper look at how `secrets.*` and `contractRef` values actually resolve.
226
+
227
+ ## 🔐 Security
228
+
229
+ CDS includes built-in security validation to prevent unsafe configurations before a stack is deployed.
230
+
231
+ The `cds security` checks analyze profiles and modules for common risks such as:
232
+
233
+ - weak or default passwords
234
+ - missing secret configurations
235
+ - insecure service exposure
236
+ - unsafe defaults in module configuration
237
+ - incomplete contract bindings that may leak data
238
+
239
+ Security checks run as part of validation and can be extended with custom rules.
240
+
241
+ ### Example
242
+
243
+ ```bash
244
+ cds security local-dagster-postgres-superset
245
+ ```
246
+
247
+ ---
248
+
249
+ ## 📦 What You Get
250
+
251
+ When you run CDS:
252
+
253
+ - validated module graph
254
+ - resolved contract bindings
255
+ - dependency-aware execution plan
256
+ - generated Docker Compose configuration
257
+ - reproducible stack definition
258
+
259
+ This allows you to go from a declarative profile to a runnable local data stack.
260
+
261
+ ---
262
+
263
+ ## ✅ Prerequisites
264
+
265
+ CDS has separate compile-time and runtime requirements.
266
+
267
+ ### Validate, Plan, And Render
268
+
269
+ The commands `cds validate`, `cds security`, `cds plan`, and `cds render`
270
+ do not require Docker. Install:
271
+
272
+ - Python 3.14 or newer, including `pip` and `venv`
273
+ - Git when cloning and installing CDS from source
274
+ - Internet access for the initial source and Python dependency downloads
275
+
276
+ ### Build And Run A Stack
277
+
278
+ The `cds up` command and generated local profiles additionally require:
279
+
280
+ - Docker Engine (Linux) or Docker Desktop (macOS and Windows)
281
+ - Docker Compose v2, invoked as `docker compose`
282
+ - A running Docker daemon accessible to the current user
283
+ - Internet access for the initial container image pulls and builds, unless all
284
+ required artifacts are already cached
285
+ - Free host ports required by the selected profile
286
+ - Write access to the checkout for `.env`, `docker-compose.yml`, and workdir
287
+ data
288
+
289
+ Docker Desktop on Windows must use the WSL 2 backend. See the
290
+ [support policy](docs/support-policy.md) for supported operating systems and
291
+ runtime versions. For platform-specific setup from an empty machine, follow
292
+ the [complete installation guide](docs/installation.md).
293
+
294
+ For the complete example stack, allocate at least 8 GB of memory to Docker and
295
+ keep at least 10 GB of disk space free for images, build layers, volumes, and
296
+ logs. Larger workloads require additional resources.
297
+
298
+ ### Preflight Check
299
+
300
+ Linux/macOS:
301
+
302
+ ```bash
303
+ python3 --version
304
+ git --version
305
+ docker --version
306
+ docker compose version
307
+ docker info >/dev/null
308
+ ```
309
+
310
+ Windows PowerShell:
311
+
312
+ ```powershell
313
+ py --version
314
+ git --version
315
+ docker --version
316
+ docker compose version
317
+ docker info | Out-Null
318
+ ```
319
+
320
+ Python must report version 3.14 or newer, Docker Compose must report v2, and
321
+ `docker info` must complete without a daemon or permission error. Git is
322
+ optional when CDS is installed from a package rather than source.
323
+
324
+ Tools such as `make`, Node.js, and `pre-commit` are contributor tooling and are
325
+ not required to run CDS profiles.
326
+
327
+ ## 🚀 Quickstart
328
+
329
+ ### CLI package preview
330
+
331
+ The Python distribution contains the `cds` command and its built-in security
332
+ rules. After production PyPI publishing is enabled, install the isolated CLI
333
+ with:
334
+
335
+ ```bash
336
+ pipx install composable-data-stack
337
+ ```
338
+
339
+ The package does not yet download profiles, modules, image build contexts, or
340
+ runtime workdirs. Continue with a repository checkout for the reference stack,
341
+ or configure external project assets with `CDS_PROFILE_PATH` and
342
+ `CDS_MODULE_PATH`. See [Packaging](docs/packaging.md) for the current TestPyPI
343
+ flow.
344
+
345
+ ### 1. Clone
346
+
347
+ ```bash
348
+ git clone https://github.com/RonaldHensbergen/composable-data-stack.git
349
+ cd composable-data-stack
350
+ ```
351
+
352
+ ### 2. Setup Environment
353
+
354
+ Linux/macOS:
355
+
356
+ ```bash
357
+ python3 -m venv .venv
358
+ source .venv/bin/activate
359
+ pip install -e .
360
+ ```
361
+
362
+ Windows PowerShell:
363
+
364
+ ```powershell
365
+ py -m venv .venv
366
+ .\.venv\Scripts\Activate.ps1
367
+ python -m pip install -e .
368
+ ```
369
+
370
+ Windows CMD:
371
+
372
+ ```bat
373
+ py -m venv .venv
374
+ .venv\Scripts\activate.bat
375
+ python -m pip install -e .
376
+ ```
377
+
378
+ If PowerShell blocks the activation script, run
379
+ `Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass` in the same
380
+ terminal session and activate the environment again.
381
+
382
+ ### 3. Configure Environment
383
+
384
+ ```bash
385
+ cds init local-dagster-postgres-superset
386
+ ```
387
+
388
+ Set:
389
+
390
+ ```text
391
+ CDS_ANALYTICS_DB_NAME
392
+ CDS_ANALYTICS_DB_USER
393
+ CDS_DAGSTER_DB_NAME
394
+ CDS_DAGSTER_DB_USER
395
+ CDS_SUPERSET_DB_NAME
396
+ CDS_SUPERSET_DB_USER
397
+ CDS_POSTGRES_SUPERUSER_PASSWORD
398
+ CDS_ANALYTICS_DB_PASSWORD
399
+ CDS_DAGSTER_DB_PASSWORD
400
+ CDS_SUPERSET_DB_PASSWORD
401
+ CDS_SUPERSET_SECRET_KEY
402
+ CDS_SUPERSET_ADMIN_PASSWORD
403
+ ```
404
+
405
+ ### 4. Validate A Stack
406
+
407
+ ```bash
408
+ cds validate local-dagster-postgres-superset
409
+ ```
410
+
411
+ Expected output:
412
+
413
+ ```text
414
+ Profile is valid.
415
+ ```
416
+
417
+ ### 5. Check Runtime Prerequisites
418
+
419
+ ```bash
420
+ cds preflight local-dagster-postgres-superset
421
+ ```
422
+
423
+ This checks the runtime CLI and daemon, Compose support, required environment
424
+ values, and declared host ports without starting services. `cds init` only
425
+ creates configuration, while `cds validate` checks profile structure.
426
+
427
+ ### 6. Run Security Checks
428
+
429
+ ```bash
430
+ cds security local-dagster-postgres-superset
431
+ ```
432
+
433
+ ### 7. Generate A Plan
434
+
435
+ ```bash
436
+ cds plan local-dagster-postgres-superset
437
+ ```
438
+
439
+ This resolves:
440
+
441
+ - module dependencies
442
+ - contract bindings
443
+ - execution order
444
+
445
+ ### 8. Render The Stack
446
+
447
+ ```bash
448
+ cds render local-dagster-postgres-superset
449
+ ```
450
+
451
+ By default, this writes `docker-compose.yml` to the project root.
452
+
453
+ Use a custom location when needed:
454
+
455
+ ```bash
456
+ cds render local-dagster-postgres-superset --output build/docker-compose.yml
457
+ ```
458
+
459
+ This generates:
460
+
461
+ - docker-compose.yml
462
+ - service definitions
463
+ - fully wired module configuration
464
+
465
+ ### 9. Run The Stack
466
+
467
+ ```bash
468
+ cds up local-dagster-postgres-superset
469
+ ```
470
+
471
+ This runs `validate` → `plan` → `render` → `docker compose build` → `docker compose up` in one step.
472
+
473
+ `docker compose build` output is streamed to the terminal (grouped by image) and also persisted to a log file (default: `.cds/logs/up-<profile>-<timestamp>.log`; override with `--log-file`). `docker compose up` always runs detached: in the default mode its output goes only to the log file while the terminal shows the live state view; with `--detach` it is streamed to the terminal like the build output. Once the stack starts, `cds up` polls `docker compose ps` and redraws the same grouped/colored view as `cds state` until every service is healthy/running/exited or a timeout is hit (default 180s; override with `--timeout`; disable colored labels with `--no-color`). Container logs from that point on go only to the log file, not the terminal, since the terminal is showing the live state view. `cds up` exits `0` once the stack settles, or `1` on timeout or an unhealthy service.
474
+
475
+ Add `--detach` (or `-d`) to skip the live state view and return as soon as the stack starts, e.g. for scripting or CI:
476
+
477
+ ```bash
478
+ cds up local-dagster-postgres-superset --detach
479
+ ```
480
+
481
+ Use `--no-build` to skip the build step when images are already available:
482
+
483
+ ```bash
484
+ cds up local-dagster-postgres-superset --no-build
485
+ ```
486
+
487
+ ### 9. Persistent Incoming Data Folder For Dagster
488
+
489
+ The Dagster module mounts a host directory into the containers so incoming files survive reboots.
490
+
491
+ - Host path: `workdirs/shared-data/incoming`
492
+ - Container path: `/app/data/cds/incoming`
493
+
494
+ Dagster includes a sensor that detects new files in `/app/data/cds/incoming` and runs a pickup job.
495
+ Picked files are moved to:
496
+
497
+ - Host path: `workdirs/shared-data/processed`
498
+ - Container path: `/app/data/cds/processed`
499
+
500
+ Create the directories once if they do not exist:
501
+
502
+ ```bash
503
+ mkdir -p workdirs/shared-data/incoming workdirs/shared-data/processed
504
+ ```
505
+
506
+ ---
507
+
508
+ ## 🧩 Core Concepts
509
+
510
+ ### Modules
511
+
512
+ Reusable building blocks:
513
+
514
+ - orchestration (Dagster, Airflow)
515
+ - warehouse (Postgres, MariaDB)
516
+ - BI (Superset, Metabase)
517
+ - secrets (env, vault)
518
+
519
+ Structure:
520
+
521
+ ```text
522
+ modules/<category>/<name>/
523
+ ├── module.yaml
524
+ ├── defaults.yaml
525
+ ├── compose.yaml
526
+ ├── scripts/
527
+ └── tests/
528
+ ```
529
+
530
+ ### Contracts
531
+
532
+ Contracts define how modules interact.
533
+
534
+ Examples:
535
+
536
+ |Contract|Purpose|
537
+ |---|---|
538
+ |sql-database|database interface|
539
+ |http-service|service exposure|
540
+ |secrets-provider|secret resolution|
541
+
542
+ Example binding:
543
+
544
+ ```text
545
+ dagster.database -> postgres.sql-database
546
+ superset.database -> postgres.sql-database
547
+ ```
548
+
549
+ No implicit dependencies. Everything is explicit.
550
+
551
+ ### Profiles
552
+
553
+ Profiles define supported stacks:
554
+
555
+ ```text
556
+ local-dagster-postgres-superset
557
+ local-airflow-postgres-superset
558
+ integration-airflow-postgres-dbt
559
+ ```
560
+
561
+ Structure:
562
+
563
+ ```text
564
+ profiles/[profile]/
565
+ ├── profile.yaml
566
+ ├── values.yaml
567
+ └── README.md
568
+ ```
569
+
570
+ ### Environment Overlays
571
+
572
+ A profile can be promoted from local development through staging to
573
+ production without duplicating its configuration. Add an `environments/`
574
+ directory next to `profile.yaml` containing one YAML file per environment;
575
+ each file is merged over the base profile when `--environment <name>` is
576
+ passed to a profile-consuming command:
577
+
578
+ ```text
579
+ profiles/[profile]/
580
+ ├── profile.yaml
581
+ └── environments/
582
+ ├── dev.yaml
583
+ └── prod.yaml
584
+ ```
585
+
586
+ An overlay only needs to declare the values that differ from the base
587
+ profile. Module entries are merged by their stable `id` (not array
588
+ position), so an overlay can override just one field of one module:
589
+
590
+ ```yaml
591
+ # profiles/[profile]/environments/prod.yaml
592
+ metadata:
593
+ environment: production # promotes the profile's security classification
594
+
595
+ spec:
596
+ modules:
597
+ - id: postgres
598
+ config:
599
+ storage:
600
+ size: 20Gi
601
+ ```
602
+
603
+ ```bash
604
+ cds validate my-profile --environment prod
605
+ cds plan my-profile --environment prod
606
+ cds test my-profile --environment prod
607
+ cds up my-profile --environment prod
608
+ ```
609
+
610
+ `local-dagster-postgres-superset` ships a working `dev`/`prod` example under
611
+ `profiles/local-dagster-postgres-superset/environments/` you can inspect or
612
+ copy.
613
+
614
+ Setting `metadata.environment` in an overlay also changes which security
615
+ policy `cds security`/`cds test` applies (see [Security](#-security)) —
616
+ promoting to `production` enables stricter checks, so a profile that passes
617
+ locally may report new findings once resolved with `--environment prod`.
618
+ That's expected: it surfaces settings that are fine for local development but
619
+ unsafe to carry into production.
620
+
621
+ Compare what an overlay actually changes with `cds diff`, without ever
622
+ printing a secret value (profiles only ever hold secret *references*, never
623
+ resolved values):
624
+
625
+ ```bash
626
+ cds diff my-profile --from dev --to prod
627
+ ```
628
+
629
+ ```text
630
+ Differences from 'dev' to 'prod':
631
+
632
+ ~ metadata.environment: "development" -> "production"
633
+ ~ spec.modules[postgres].config.storage.size: "2Gi" -> "20Gi"
634
+ ```
635
+
636
+ Commands without `--environment` are unaffected — they behave exactly as
637
+ before and never look for an `environments/` directory.
638
+
639
+ ---
640
+
641
+ ## ⚙️ CLI
642
+
643
+ |Command|Description|
644
+ |---|---|
645
+ |cds init [profile]|Generate a project `.env` template from profile secret definitions|
646
+ |cds validate [profile]|Validate modules and contracts|
647
+ |cds preflight [profile]|Check runtime tools, required environment values, and host ports without starting services|
648
+ |cds plan [profile]|Resolve dependencies and generate an execution plan|
649
+ |cds render [profile]|Generate Docker Compose configuration from a resolved plan|
650
+ |cds up [profile]|Validate, plan, render, build, and start services with docker compose; logs output to a file and shows a live `cds state` view until the stack settles (use `--no-build` to skip build, `--detach` to skip the live view, `--log-file`/`--timeout`/`--no-color` to override defaults)|
651
+ |cds state [profile]|Show running service status grouped by health (use `--no-color` to disable colored labels)|
652
+ |cds test [profile]|One-shot smoke validation: validate, security, plan, and render|
653
+ |cds security [profile]|Run rule-based security validation on a profile|
654
+ |cds diff [profile] --from \<env\> --to \<env\>|Show effective configuration differences between two environment overlays, secrets never included|
655
+ |cds use [profile] [--clear]|Save (show/clear) a default profile so it doesn't have to be passed to other commands|
656
+ |cds completion \<bash\|zsh\|powershell\>|Print shell setup instructions for tab-completion|
657
+
658
+ `init`, `validate`, `preflight`, `plan`, `render`, `up`, `test`, and `security`
659
+ all accept `--environment <name>` (or `-e <name>`) to merge
660
+ `environments/<name>.yaml` over the base profile before resolving; see
661
+ [Environment Overlays](#environment-overlays).
662
+
663
+ `[profile]` accepts:
664
+
665
+ | Form | Example |
666
+ | ---- | ------- |
667
+ | Profile name | `local-dagster-postgres-superset` |
668
+ | Path to a `profile.yaml` file | `profiles/local-dagster-postgres-superset/profile.yaml` |
669
+ | Path to a profiles root directory | `profiles/` |
670
+
671
+ When `[profile]` is omitted, resolution falls back in order to: `CDS_PROFILE_PATH` if set (accepts the same three forms), then the default profile saved via `cds use <profile>`, then the single profile under `profiles/` if there is exactly one. An explicitly-set env var takes precedence over the persisted `cds use` default, matching common CLI convention (env vars are per-invocation and reflect the current session more reliably than a saved, gitignored default that's easy to forget about).
672
+
673
+ To view the full list of options for any command, use the `--help` flag:
674
+
675
+ ```bash
676
+ cds --help
677
+ cds validate --help
678
+ cds plan --help
679
+ ```
680
+
681
+ ---
682
+
683
+ ## 🪟 Windows Task Runner
684
+
685
+ Windows contributors without `make` can use `Makefile.ps1`, a PowerShell equivalent covering the core developer tasks:
686
+
687
+ ```powershell
688
+ # Install in editable mode
689
+ .\Makefile.ps1 install
690
+
691
+ # Validate the default profile
692
+ .\Makefile.ps1 validate
693
+
694
+ # Validate a specific profile
695
+ .\Makefile.ps1 validate-profile -P profiles/local-dagster-postgres-superset/profile.yaml
696
+
697
+ # Build distribution packages
698
+ .\Makefile.ps1 package
699
+
700
+ # List available targets
701
+ .\Makefile.ps1 help
702
+ ```
703
+
704
+ This does not replace the Linux/macOS `Makefile`, both exist side by side. Windows users can still install `make` via WSL or Chocolatey if they prefer the original workflow. `lint` and `docker-build` are not ported here. Run `yamllint .` and `npx markdownlint-cli` directly, or use `pre-commit` if it is set up in this repo. Docker Desktop's `docker build` works the same on Windows as it does elsewhere.
705
+
706
+ ---
707
+
708
+ ## 🛠️ Troubleshooting
709
+
710
+ Common errors from `cds validate`, `cds plan`, and `cds render`, and how to fix them.
711
+
712
+ | Error | Cause | Fix |
713
+ | --- | --- | --- |
714
+ | `[E020] ... YAML file not found: <path>` | The profile identifier or file path passed to `cds validate`, `cds plan`, or `cds render <profile>` doesn't resolve to an existing YAML file. | Run `cds list profiles` to see valid identifiers. Set `CDS_PROFILE_PATH` to a profile name, a `profile.yaml` file path, or a profiles root directory. |
715
+ | `[E081] ... Required secret "CDS_X_PASSWORD" not found in environment` | A secret marked `required: true` in the profile's `spec.secrets.values` is missing from the shell environment or the `.env` file in the current working directory. | Run `cds init <profile>` to generate `.env` in the project root, set the missing `CDS_*` variable, or export it directly before running the command. |
716
+ | `[E041] ... Contract ref "x.y" points to unknown module "x"` | A `consumes` binding's `contractRef` refers to a module ID that isn't defined in the profile. | Check `spec.modules` for the correct module `id`, and confirm the contract ref follows `<module-id>.<contract-name>`. |
717
+ | `[E041] ... but it does not provide "<contract-name>"` | The referenced module exists, but its `spec.provides` list doesn't expose that contract name. | Check the producing module's `module.yaml` for the contracts it actually provides, and fix the consumer's `contractRef` to match. |
718
+ | `[E042] ... Contract kind mismatch` | The consumer expects one contract kind (e.g. `sql-database`) but the producer exposes a different kind. | Point the binding at a module that provides the expected contract kind, or update the consumer's expected kind if the mismatch is intentional. |
719
+
720
+ All diagnostics print with their error code and YAML path (e.g. `spec.modules[1].config`), so search the profile file for that path to find the exact line to fix.
721
+
722
+ ---
723
+
724
+ ## 🔄 Workflow
725
+
726
+ ```text
727
+ 1. cds validate -> check module definitions
728
+ 2. cds security -> detect unsafe configurations
729
+ 3. cds plan -> resolve dependencies and bindings
730
+ 4. cds render -> generate Docker Compose stack
731
+ 5. cds up -> start services
732
+ 6. cds test -> one-shot validate + security + plan + render smoke check
733
+ ```
734
+
735
+ ---
736
+
737
+ ## 📂 Repository Structure
738
+
739
+ ```text
740
+ .
741
+ ├── cli/
742
+ ├── modules/
743
+ │ ├── bi/
744
+ │ ├── orchestration/
745
+ │ ├── secrets/
746
+ │ └── warehouse/
747
+ ├── profiles/
748
+ ├── docs/
749
+ ├── pyproject.toml
750
+ └── Makefile
751
+ ```
752
+
753
+ ---
754
+
755
+ ## 🧱 Design Principles
756
+
757
+ ### Contract-First
758
+
759
+ Modules declare:
760
+
761
+ - what they provide
762
+ - what they require
763
+ - configuration inputs
764
+ - health checks
765
+ - lifecycle hooks
766
+
767
+ ### Profile-Driven
768
+
769
+ Profiles define supported stacks.
770
+ The profile is the unit of support, not individual modules.
771
+
772
+ ### Zero Hidden Coupling
773
+
774
+ - no implicit environment variables
775
+ - no cross-module assumptions
776
+ - no shared mutable state
777
+
778
+ All interactions happen through explicit contracts.
779
+
780
+ ### Security By Default
781
+
782
+ CDS validates configurations before runtime, ensuring that:
783
+
784
+ - weak credentials are detected early
785
+ - secrets are properly configured
786
+ - services are not unintentionally exposed
787
+
788
+ Security is part of platform composition, not an afterthought.
789
+
790
+ ### One Model, Multiple Environments
791
+
792
+ The same composition model applies across:
793
+
794
+ - local development
795
+ - CI environments
796
+ - production
797
+
798
+ Only runtime packaging differs.
799
+
800
+ ---
801
+
802
+ ## 📊 Comparison
803
+
804
+ |Capability|Monolith|Custom pipelines|CDS|
805
+ |---|---|---|---|
806
+ |Swap components|❌|⚠️|✅|
807
+ |Reuse modules|❌|❌|✅|
808
+ |Explicit contracts|❌|❌|✅|
809
+ |Reproducibility|⚠️|⚠️|✅|
810
+ |Security validation|❌|❌|✅|
811
+ |Vendor lock-in|✅|⚠️|❌|
812
+
813
+ ---
814
+
815
+ ## 📌 Status
816
+
817
+ MVP ready:
818
+
819
+ - module validation
820
+ - contract resolution
821
+ - security checks
822
+ - profile composition
823
+ - Docker Compose rendering
824
+
825
+ Next:
826
+
827
+ - runtime orchestration
828
+ - Kubernetes support
829
+ - advanced secret providers
830
+ - stack bootstrap and health checks
831
+
832
+ See [docs/roadmap.md](docs/roadmap.md) for milestones and detailed status.
833
+ See [docs/support-policy.md](docs/support-policy.md) for OS support policy and platform-specific limitations.
834
+
835
+ ---
836
+
837
+ ## 🤝 Contributing
838
+
839
+ Contributions are welcome.
840
+
841
+ Please read these first:
842
+
843
+ - [CONTRIBUTING.md](CONTRIBUTING.md)
844
+ - [docs/maintainer-merge-policy.md](docs/maintainer-merge-policy.md)
845
+ - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
846
+ - [SECURITY.md](SECURITY.md)
847
+ - [SUPPORT.md](SUPPORT.md)
848
+ - [CHANGELOG.md](CHANGELOG.md)
849
+ - [RELEASE.md](RELEASE.md)
850
+
851
+ Good first contributions:
852
+
853
+ - adding new modules
854
+ - improving profile examples
855
+ - extending contract definitions
856
+ - adding validation or security rules
857
+
858
+ ---
859
+
860
+ ## 📖 Documentation
861
+
862
+ - [Quickstart](README.md#-quickstart) — get running in 5 minutes
863
+ - [From Docker Compose to CDS Profile](docs/from-docker-to-cds-profile.md) — complete transformation guide
864
+ - [Architecture](docs/architecture.md) — design and core concepts
865
+ - [Modules](docs/modules.md) — how to structure reusable components
866
+ - [Roadmap](docs/roadmap.md) — planned features and milestones
867
+
868
+ ---
869
+
870
+ ## 📜 License
871
+
872
+ See `LICENSE`.