Skip to content

info.yml

Info dashboard configuration.

workspace/info.yml declares the content of the dwe info dashboard: sections, items, conditional visibility, and template expressions. The CLI renders it on every dwe info invocation.

Loaded separately. Not merged with the 3-layer config.

sections:
- id: <section-id>
title: "Optional Section Title" # shown as a bordered box header
items:
- type: <item-type>
<item-fields>
footer: true
FieldTypeDefaultDescription
sectionslistOrdered list of section definitions.
footerboolfalseWhen true, a closing table-header line is rendered after all sections.
FieldTypeDefaultDescription
idstringUnique identifier for the section
titlestringOptional header rendered above the item list
itemslistOrdered list of item definitions
hide_on_emptyboolfalseSkip the section entirely (no title, no frame) when no item survives when-filtering. Note: subgroups have a different default (true).
TypeRenders asRequired fields
definitionLabel — Value row, with optional iconname, value
infoInfo-coloured text linetext
warningWarning-coloured text linetext
auto-urlsDynamically generated URLs organized by service
auto-hostsDynamically generated hostnames from services
subgroupContainer with optional title and nested itemsitems
separatorBlank line spacer

All items accept an optional when: (Go template expression). Items with a falsy when are dropped from the rendered output. All items support an optional decorative boolean flag (see Decorative items).

Note on auto-urls and auto-hosts rendering: auto-urls and auto-hosts items expand at render time (when dwe info is executed), not at YAML load time. The expansion consults the current configuration and iterates enabled services in deploy order, so the dashboard always reflects the latest service definitions and state.

A label + value pair, rendered as Label — Value.

- type: definition
name: Project
value: "{{ .Project.FullName }}"
icon: "🔗"
indent: 2
when: "{{ .State }}"
FieldDescription
nameLabel text
valueValue text (plain string or template expression)
iconOptional emoji or symbol prepended to value. Prefer codepoints with Emoji_Presentation=Yes (e.g. 📦, 🐳, 💾); text-default codepoints like 🛢, 🗄, are flagged by dwe validate and dropped at render time to keep columns aligned — see icon field in the services reference for the full caveat.
indentOptional leading whitespace count. Default for definition items is 2; pass 0 to flush left. Negative values are rejected.
whenCondition; item hidden if falsy

An informational text line.

- type: info
text: '127.0.0.1 {{ (index .Services "main").Host "web" }}'
indent: 0
when: '{{ (index .Services "adminer").Enabled }}'
FieldDescription
textMessage text (plain string or template expression)
indentOptional leading whitespace count
whenCondition; item hidden if falsy

A warning text line (rendered in warning color).

- type: warning
text: "Please add this to your /etc/hosts file:"
FieldDescription
textWarning text (plain string or template expression)
whenCondition; item hidden if falsy

Dynamically generates a list of service URLs from the project’s configured services. Services declare their hosts and ports in workspace/services/<name>/service.yml; auto-urls renders them with optional filtering and customization.

- type: auto-urls
include: [app, tool]
hide: [varnish]
hide_paths:
main: ["SPX profiler"]
port_via: nginx
when: "{{ .Services }}"
FieldTypeDefaultDescription
includelist[app, tool]Service types to include: any combination of app, tool, infra.
hidelistService folder keys to exclude entirely. Unknown keys are silently ignored.
hide_pathsmapExclude individual sub-paths by service key and path name (e.g. main: ["SPX profiler"] hides the path named “SPX profiler” under the service “main”).
port_viastringauto-detectedOverride which service to use as the front proxy for generating main URLs. When empty, auto-detection searches for a single enabled type: infra service declaring either ports.http: 80 (http traffic) or ports.https: 443 (https traffic). Explicitly named missing services are flagged by dwe validate, not at render time. Auto-detection returns no proxy when zero candidates or multiple candidates are found (in that case, only direct localhost:<port> URLs render).
whenstringCondition; item hidden if falsy.

port_via auto-detection examples:

With auto-detection (default — no port_via: field):

# Auto-detects if exactly one infra service has ports.http: 80
- type: auto-urls
include: [app, tool]

In this case, if a service named nginx has ports: {http: 80} and it is of type infra and enabled, it is auto-selected. App and tool services will then render as proxied URL | localhost:port (if they declare their own ports) or just proxied URL (if host-only). Other services without auto-detected proxy render as localhost:port only.

With explicit port_via: override:

# Always use named service as proxy, even if it's not type: infra
- type: auto-urls
include: [app, tool]
port_via: api_gateway

When port_via is explicitly set but names a nonexistent service, dwe info silently renders no proxy (direct/host-only URLs); the missing service is flagged only by dwe validate (SeverityError). A named service is used for proxy URL construction regardless of its type:.

When auto-detection finds zero or multiple infra services with the target port, no proxy is selected and services render using only their direct ports (or with just hosts if no port exists):

# No eligible infra service found → app/tool with only localhost:<port> URLs
- type: auto-urls
include: [app, tool]

Services contribute to auto-urls via their info: block in service.yml (see services/index.md for the schema). Each service may declare:

  • title — override the service header (defaults to title-cased folder name)
  • primary_host — which hosts entry to surface as the main URL (default: web)
  • primary_port — which ports entry to surface (default: http)
  • paths — ordered list of sub-paths under the main URL

Services without an info block are included in the include types but render only their main URL if hosts and ports exist.

URL assembly rules:

  • hosts[primary_host] and ports[primary_port] (direct binding) → <proxied URL> | <direct URL>
  • only hosts[primary_host]<proxied URL> (if port_via available)
  • only ports[primary_port]http://localhost:<port>
  • neither → row silently omitted

<proxied URL> uses the port_via service’s ports for scheme/port selection, but the routed service’s own info.scheme (when set) takes precedence and also pins which proxy listener (http vs https) is looked up — see Reverse-proxy URLs in services/fields.md for the full precedence chain. <direct URL> uses the service’s own port. Within <proxied URL>, ports :80 (http) and :443 (https) are omitted; the <direct URL> always shows its port.

Dynamically generates a list of all hostnames from services for /etc/hosts configuration.

- type: auto-hosts
include: [app, tool, infra]
ip: 127.0.0.1
hide: [varnish]
when: "{{ .Services }}"
FieldTypeDefaultDescription
includelist[app, tool, infra]Service types to include: any combination of app, tool, infra.
ipstring127.0.0.1IP address to associate with all hostnames. Values are not validated for IP format here; dwe validate emits a warning if parsing fails.
hidelistService folder keys to exclude entirely. Unknown keys are silently ignored.
whenstringCondition; item hidden if falsy.

Renders every hosts entry from included services in a two-column table (IP Hostname), preserving deploy order, deduplicating hostnames, and skipping empty values, the literal localhost, and any *.localhost host (these resolve to 127.0.0.1 automatically and need no /etc/hosts entry).

A container item that groups related items and optionally displays a title.

- type: subgroup
title: "Tools"
hide_on_empty: false
items:
- type: definition
name: Adminer
icon: "🛢"
value: '{{ appURL ((index .Services "adminer").Host "web") ((index .Services "main").Port "http") .Runtime.UseHTTPS }}'
when: '{{ (index .Services "adminer").Enabled }}'
- type: definition
name: RedisInsight
icon: "📊"
value: '{{ appURL ((index .Services "redis_insight").Host "web") ((index .Services "main").Port "http") .Runtime.UseHTTPS }}'
when: '{{ (index .Services "redis_insight").Enabled }}'
FieldTypeDefaultDescription
titlestringOptional header for the subgroup (plain string or template expression). When empty, the subgroup is rendered without a heading.
itemslistRequired. Ordered list of child item definitions. Can contain any item type, including nested subgroups.
whenstringCondition; when falsy the entire subgroup (including all children) is skipped. When truthy, each child item is evaluated for its own when condition.
hide_on_emptybooltrueSkip the subgroup entirely when no child item survives when-filtering. (Opposite of section default; subgroups default to true.)
decorativeboolfalseWhen true, the subgroup never counts as content for the parent’s hide_on_empty check, even if it produces output.

Subgroups can be nested arbitrarily.

A blank line used to space content within a section.

- type: separator

No fields. Useful when adjacent items need visual breathing room without introducing a new section.

By default, items fall into two categories: content items that count toward section visibility, and decorative items that do not.

TypeDefault decorative
definitionfalse
infofalse
warningfalse
subgroupfalse
separatortrue

The decorative flag on any item type overrides its default:

- type: warning
text: "Only informational"
decorative: true # Makes this warning not count as content
- type: separator
decorative: false # Makes this separator count as content, keeping the section visible

When hide_on_empty: true on a section or subgroup, the block is skipped entirely if no item survives both when filtering and the content-vs-decorative check. A block with only decorative items (or no items) may still render if it has a title and hide_on_empty: false.

All text, value, and when fields support Go template syntax evaluated against the resolved project config.

ExpressionTypeDescription
{{ .Project.Name }}stringProject name
{{ .Project.FullName }}stringCombined prefix + name
{{ .State }}stringActive state (empty if none)
{{ .Runtime.UseHTTPS }}boolHTTPS enabled.
{{ .Runtime.SPX.Path }}stringSPX profiler path.
{{ (index .Services "main").Enabled }}boolWhether the service main is enabled (required services are always true).
{{ (index .Services "main").Container }}stringContainer name on the main service.
{{ (index .Services "main").Port "http" }}intNamed port lookup. Port(name) is a method on ServiceConfig (returns 0 if absent).
{{ (index .Services "main").Host "web" }}stringNamed host lookup. Host(name) returns "" if absent.
{{ (index .Services "main").PortScheme "http" }}stringPer-port scheme override declared on the entry (rich form). Returns "" if no override is set.
{{ (index .Services "main").EffectiveScheme "http" .Runtime.UseHTTPS }}stringResolves the effective URL scheme ("http" / "https") through the precedence chain: per-port → info.schemeruntime.use_https.
{{ .AppServices }} / {{ .ToolServices }} / {{ .InfraServices }}map[string]ServiceConfigFiltered subsets by type: — handy for {{ range }} over a single category.

Info templates have access to the standard DWE DWE template surface: the appURL domain helper plus the sprout registries (std, strings, numeric, slices, maps, regexp, conversion, time, filesystem, semver). See Templates for the full helper reference.

Example using appURL:

value: '{{ appURL ((index .Services "main").Host "web") ((index .Services "main").Port "http") .Runtime.UseHTTPS }}'
# → http://laravel.localhost (or https://… when use_https is true)

when fields accept any template expression that evaluates to a truthy/falsy value. Empty string, false, and 0 are falsy; anything else is truthy.

when: "{{ .State }}" # show only when state is non-empty
when: '{{ (index .Services "adminer").Enabled }}' # show only when adminer is enabled
when: "{{ .Runtime.SPX.Path }}" # show only when SPX path is set
footer: true

When true, a footer line is rendered below all sections (typically shows help hint).

When workspace/info.yml does not exist, a built-in default configuration is used. It renders two sections:

  1. URLs section with an auto-urls item (default include: [app, tool]; no filtering)
  2. Hosts section with a warning and an auto-hosts item (default include: [app, tool, infra])

This allows projects without an info.yml to immediately see a sensible dashboard showing all services’ connectivity, constructed entirely from the service definitions in workspace/services/*/service.yml. Services contribute details via their info: blocks (title, paths, host/port keys). No info.yml editing is required to get started.

An empty or all-comment workspace/info.yml — one that decodes no top-level keys at all — is treated exactly like an absent file, so the built-in default stays active. This is what the scaffolded (fully commented) info.yml relies on.

To customize the dashboard, create a workspace/info.yml with your own sections and items. Once the file decodes any top-level key it is treated as authored and the built-in default is not used: a deliberate sections: [] renders an empty dashboard rather than restoring the default, and a file carrying only footer: true is honoured as written.

dwe validate reports these three states separately under config.info — inert (default silently active) and sections: [] at Info severity, an authored dashboard with real content at OK.

sections:
- id: dwe_info
items:
- type: subgroup
title: DWE
hide_on_empty: false
items:
- type: definition
name: Project
value: "{{ .Project.FullName }}"
- type: definition
name: State
value: "{{ .State }}"
when: "{{ .State }}"
- id: urls
title: URLs
items:
# Automatically render all app and tool services with their hosts/ports
- type: auto-urls
include: [app, tool]
hide: [varnish]
hide_paths:
main: ["SPX profiler"]
port_via: nginx
- id: credentials
title: Credentials
items:
- type: subgroup
title: Database
hide_on_empty: true
items:
- type: definition
name: User
value: "{{ .Project.Name }}_user"
- type: subgroup
title: API Key
hide_on_empty: true
items:
- type: warning
text: "Check .env for sensitive credentials"
- id: hosts
title: Hosts
items:
- type: warning
text: "Add these to your /etc/hosts:"
# Automatically render all service hostnames
- type: auto-hosts
include: [app, tool, infra]
footer: true
  • Bare when: values without template syntaxwhen: .State is not valid; must be when: "{{ .State }}".
  • Missing quotes around template expressions — YAML parses {{ ... }} as a flow mapping if unquoted. Always quote template strings.
  • Service lookup syntax — Go’s text/template requires index for map access by string key: (index .Services "main") returns a ServiceConfig. From there, struct fields are PascalCase (.Container, .Enabled) and ports / hosts use the Port / Host accessor methods with the port/host name as argument: (index .Services "main").Port "http". Parentheses around the index expression are required so the method dispatches on the returned ServiceConfig.
  • Using config keys not exposed at the top level — only fields surfaced by the resolved project config (see the table above) are available as direct template paths like .Project.Name. Custom keys added to defaults.yml live under .Raw and need to be accessed via index or dot-paths against Raw (e.g. index .Raw "myKey").
  • appURL argument order — the order is host, port, useHTTPS, then optional path. Swapping port and useHTTPS produces incorrect URLs silently. When linking a tool routed via the main reverse proxy, combine the tool’s hostname with the main service’s port: appURL ((index .Services "adminer").Host "web") ((index .Services "main").Port "http") .Runtime.UseHTTPS.
  • hide_on_empty with decorative items — By default, content items like definition, info, and warning count toward section visibility, but separator does not. Use the decorative flag to override: set decorative: true on a content item to exclude it from the visibility calculation, or set decorative: false on a separator to make it count as content. A section with hide_on_empty: true is fully hidden if no content item (after when filtering) survives.
  • Footer rendering with hide_on_empty — When footer: true, the footer is only rendered if at least one section produced output. If all sections are hidden via hide_on_empty, the footer is also suppressed.
  • dwe info — render the full dashboard
  • dwe (no args) — shows a built-in compact summary (not from info.yml)