setup.yml
Interactive setup questions for fresh projects.
Contents
Section titled “Contents”- Purpose
- How it works
- Structure
- Top-level fields
- Question entry fields
- Question types
- Validation presets
- Write scope rules
- Examples
- Related commands
Purpose
Section titled “Purpose”workspace/setup.yml defines interactive prompts that run when a developer first enters a fresh project (one without a workspace/local.yml or with an empty one). The wizard collects answers, writes them into workspace/local.yml as merged settings, and then proceeds to deployment.
Use setup questions for one-time per-developer configuration:
- API keys or secrets (stored in
local.yml, which is gitignored) - Service toggles (which optional tools the developer wants to enable)
- Port overrides (when local port conflicts exist)
- Custom paths or hostnames
The setup wizard is part of the broader dwe deploy flow — running dwe deploy with no subcommand opens an interactive menu that includes a Wizard option when setup questions are present.
How it works
Section titled “How it works”- Developer runs
dwe deployin an interactive terminal on a fresh project. - The CLI probes for port conflicts and loads
workspace/setup.yml(if present). - If both are empty (no questions, no conflicts), no wizard runs — proceed directly to deploy.
- If either has content, the menu opens with a Wizard option.
- Wizard runs:
- First, port-conflict prompts (if any) — developer chooses override ports.
- Then, setup questions (if any) — developer answers each prompt.
- Finally, both answers are deep-merged into
workspace/local.ymland written atomically.
- Config is reloaded from the updated
local.yml, preflight runs, and deploy proceeds normally.
If the developer cancels at any wizard step (Ctrl-C), local.yml is left untouched — no partial writes.
Structure
Section titled “Structure”questions: - id: api-key title: GitHub Token description: Personal access token for private repos (optional) type: input required: false writes: vars.db.api_key
- id: enable-postgres title: Enable PostgreSQL? type: confirm required: false writes: services.postgres.enabled
- id: http-port title: Web server port description: Port to run the local app on type: input required: true writes: services.web.ports.http validate: preset: port
- id: select-locale title: Preferred language type: select required: true writes: vars.app.locale options: - value: en label: English - value: fr label: Français - value: de label: Deutsch
- id: enable-caching title: Use Redis caching? type: confirm writes: vars.app.cache.enableThe file is optional. When absent, the wizard (if invoked) handles port conflicts only.
Top-level fields
Section titled “Top-level fields”| Field | Type | Required | Description |
|---|---|---|---|
questions | list | yes | Question entries (see below). May be empty. |
Unknown top-level fields are rejected at load time (strict decoding).
Question entry fields
Section titled “Question entry fields”| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique identifier for this question. Used as the key when collecting answers. |
type | string | yes | One of input, select, multiselect, confirm. Unknown values are rejected by validation. |
title | string | yes | Prompt text shown to the developer. |
description | string | no | Longer explanation shown below the title. |
required | bool | no | If true (default false), the wizard enforces a non-empty answer before proceeding. For confirm, required is ignored (always optional). |
writes | string | yes | Dot-path where the answer is stored in local.yml. Must be unique across all questions. See Write scope rules. |
options | list | no | Valid for select and multiselect only. List of {value, label} pairs. Required for both types. |
validate | object | no | Optional validation rules. Has two fields (mutually exclusive): preset (a named preset like port / hostname) or regex (a regular expression pattern). Only meaningful for type: input. |
Schema rules enforced at load time:
idmust be unique across entries.writesmust be unique across entries and follow dot-path syntax rules (see below).- Unknown top-level fields inside a question are rejected.
Schema rules enforced by validation (run via dwe validate):
typemust be one of the four known values.writesmust follow the scope and syntax rules below.validate.presetandvalidate.regexcannot both be set.validate.*is only meaningful fortype: input; setting either onselect,multiselect, orconfirmis an error.selectandmultiselectmust have non-emptyoptionswith unique, non-emptyvaluestrings.- Service-overlay writes have type consistency rules (see Write scope rules).
Question types
Section titled “Question types”A free-text input field with optional validation.
Returns: string (or int if a numeric preset is used — see Validation presets)
Example:
- id: db-password type: input title: Database password required: true writes: vars.db.passwordselect
Section titled “select”A single-choice dropdown. Developer picks one value.
Returns: string (the chosen option’s value)
Example:
- id: log-level type: select title: Logging level required: true writes: vars.app.log_level options: - value: debug label: Debug (verbose) - value: info label: Info (normal) - value: error label: Error (quiet)multiselect
Section titled “multiselect”A multi-choice list. Developer picks zero or more values.
Returns: []string (slice of chosen value fields)
Example:
- id: plugins type: multiselect title: Plugins to enable writes: vars.app.plugins options: - value: auth label: Authentication - value: logging label: Logging - value: metrics label: Metricsconfirm
Section titled “confirm”A yes/no toggle.
Returns: bool (true for yes, false for no)
Example:
- id: enable-debug type: confirm title: Enable debug mode? writes: vars.app.debugNote: required: true on a confirm is a no-op and produces a validation warning. A confirm always yields a valid answer (either true or false).
Validation presets
Section titled “Validation presets”Presets are shorthand validators for common patterns. Each preset defines what values are accepted AND what Go type is written to local.yml.
Use validate: { preset: <name> } inside a question’s validate block.
Validates a port number (1–65535) and writes an int.
- id: http-port type: input title: Web server port writes: services.web.ports.http validate: preset: portThe developer’s input "8080" is stored as the integer 8080 in local.yml, so templates can use it as a number.
hostname
Section titled “hostname”Validates a DNS hostname (RFC 1123 short-name format) and writes a string.
- id: postgres-host type: input title: Postgres hostname writes: services.postgres.hosts.internal validate: preset: hostnameValidates a non-empty filesystem path and writes a string.
- id: workspace-dir type: input title: Workspace directory writes: vars.app.workspace validate: preset: pathnon-empty
Section titled “non-empty”Validates that the input is not blank (whitespace-only is rejected) and writes a string.
- id: api-key type: input title: API key writes: vars.db.api_key validate: preset: non-emptyNo preset, no regex
Section titled “No preset, no regex”If neither preset nor regex is set, the input is accepted as-is (any non-empty string when required: true, any string otherwise).
- id: app-name type: input title: Application name writes: vars.app.name # No validation; any input is acceptedCustom regex
Section titled “Custom regex”Validate the input against a regular expression pattern. The pattern is matched as an un-anchored Go regex (substring match); add ^ and $ anchors yourself to require a full match.
- id: email type: input title: Email address writes: vars.user.email validate: regex: "^[a-z0-9+._-]+@[a-z0-9.-]+$"Pattern must compile as a valid Go regex. Invalid patterns are caught by dwe validate before the wizard ever runs.
Write scope rules
Section titled “Write scope rules”The writes: field is a dot-path that determines where in workspace/local.yml the answer is stored. Not all paths are allowed — the wizard enforces rules to ensure answers merge safely with the config schema.
Forbidden top-level namespaces
Section titled “Forbidden top-level namespaces”These top-level keys are reserved and cannot be written by the wizard:
info.*— immutable project metadatastyles.*— UI color configurationdocker.*— engine policy configuration
Attempting to write to any of these triggers a validation error.
Service-overlay leaf shapes
Section titled “Service-overlay leaf shapes”When writing under services.<name>., only three exact leaf paths are allowed:
| Path | Type | Question type | Description |
|---|---|---|---|
services.<name>.enabled | bool | confirm (required) | Toggle service enabled state. |
services.<name>.ports.<port_name> | int | input with preset: port (required) | Override a declared service port. |
services.<name>.hosts.<host_name> | string | input (any preset OK) | Override a declared service hostname. |
Examples of allowed writes:
services.web.enabled— must come from atype: confirmquestionservices.web.ports.http— must come from atype: inputwithvalidate.preset: portservices.postgres.hosts.internal— can come from anytype: input
Examples of forbidden writes:
services.web(missing the leaf.enabled/.ports.X/.hosts.X) — would overwrite the entire service configservices.web.ports(missing the specific port name) — would overwrite all portsservices.web.container— not in the allowed leaf setservices.web.ports.httpfrom atype: select— wrong question type for the path
Validation error messages cite the specific constraint that failed (e.g., “service ports require type: input with validate.preset: port”).
Non-service paths
Section titled “Non-service paths”Custom values belong under the vars: sandbox. The root of the merged config is strict — a top-level db: / app: / custom: key in local.yml is rejected at load time — so write custom answers under vars.*, where any nesting is allowed and any question type is fine:
- writes: vars.db.name # ✓ allowed- writes: vars.db.connection.host # ✓ allowed- writes: vars.db.connection.port # ✓ allowed- writes: vars.app.feature_flags # ✓ allowed- writes: vars.custom.setting # ✓ allowedThe wizard writes the typed answer value verbatim (string for input / select, bool for confirm, slice for multiselect) and trusts the consuming config (templates, exports, etc.) to handle it appropriately.
Examples
Section titled “Examples”Minimal setup with just a port override
Section titled “Minimal setup with just a port override”questions: []If port conflicts exist, the wizard opens and prompts for overrides. No question entries needed.
API key + service toggle
Section titled “API key + service toggle”questions: - id: github-token type: input title: GitHub personal access token description: Used for private repo access. Leave blank to skip. required: false writes: vars.secrets.github_token validate: preset: non-empty
- id: enable-postgres type: confirm title: Enable PostgreSQL? writes: services.postgres.enabledService with custom hostname
Section titled “Service with custom hostname”questions: - id: database-host type: input title: Database hostname description: The address where your database lives required: true writes: services.postgres.hosts.internal validate: preset: hostname
- id: db-port type: input title: Database port required: true writes: services.postgres.ports.db validate: preset: portMulti-choice plugins
Section titled “Multi-choice plugins”questions: - id: enabled-plugins type: multiselect title: Plugins to enable description: Select any combination (space to toggle, enter to confirm) required: false writes: vars.app.plugins options: - value: auth label: Authentication - value: analytics label: Analytics - value: export label: Export to S3 - value: webhooks label: WebhooksComplex custom namespace
Section titled “Complex custom namespace”questions: - id: workspace-root type: input title: Workspace root directory required: true writes: vars.workspace.root validate: preset: path
- id: cache-backend type: select title: Cache backend required: true writes: vars.cache.backend options: - value: redis label: Redis - value: memcached label: Memcached - value: local label: Local (in-memory, not persistent)
- id: enable-profiling type: confirm title: Enable performance profiling? writes: vars.debug.profilingRelated commands
Section titled “Related commands”dwe deploy— opens the wizard menu on fresh projectsdwe validate— checksworkspace/setup.ymlschema and writes pathsdwe validate setup— validates only the setup domain