Service examples and toggle lifecycle
Full service definition, on_enable / on_disable / notes semantics, and common pitfalls.
Contents
Section titled “Contents”Full service definition
Section titled “Full service definition”type: appcontainer: app-mainrequired: truedir: ./services/maindir_internal: /workspacework_dir_internal: /workspace/srcicon: "📦"info: title: "Main Application" paths: - name: "API Documentation" path: /api/docs icon: "📖"ports: http: 80hosts: web: app.localhostconfigs: - .envdirs: - logs - home - runtimecli: mode: auto shell: bash user: www-data workdir: /workspace/srcrender: ide: enabled: true ai: enabled: trueToggle lifecycle
Section titled “Toggle lifecycle”The on_enable, on_disable, and notes blocks control what happens when a service is toggled via dwe services enable/disable.
on_enable and on_disable schema
Section titled “on_enable and on_disable schema”on_enable: requires: none | restart | deploy | deploy-or-restart # what to trigger after writing local.yml before: [command-id] # user commands run before the toggle is written after: [command-id] # user commands run after the toggle is writtenon_disable: requires: none | restart # deploy is not allowed on disable before: [command-id] after: [command-id]| Field | Default | Description |
|---|---|---|
requires | restart | What must happen for the change to take effect. none → write local.yml only; restart → trigger dwe restart; deploy → trigger dwe deploy run --service <name>; deploy-or-restart → deploy when the service has never been deployed, else restart (on_enable only). deploy and deploy-or-restart are forbidden on on_disable. |
before | — | User command IDs (from workspace/commands/) to run before the toggle write. Each must be type: shell or type: script. |
after | — | User command IDs to run after the toggle write. Same type constraint applies. |
Hook commands run with --yes (non-interactive), stdout discarded, stderr captured for error messages.
notes schema
Section titled “notes schema”notes: enable: "Run migrations after enabling this service." disable: "Safe to disable while the stack is running."Notes are shown in the plan output (dwe services enable/disable --print-plan) to guide the operator through manual follow-up steps.
Toggle plan and --apply
Section titled “Toggle plan and --apply”dwe services enable <name> (without --apply) writes local.yml and records a pending op in the deploy state journal. The pending op is displayed by dwe status until cleared. --apply executes the plan immediately (runs hooks, triggers restart or deploy as declared by requires).
Common pitfalls
Section titled “Common pitfalls”- Editing
dirinextendschild — a child that setsdircompletely replaces the parent’sdir(not merged). This is intentional for services that live in a different host directory. - Absolute paths in
dirs— dirs entries must be relative paths. Absolute paths or paths containing..are rejected byservice_dirs_ensureas a security check. - Missing
containerin child —containeris not inherited viaextends:. A child without an explicitcontainerdefaults to its folder name (the same default that applies to any service). Declarecontainerexplicitly when the folder name is not the right container name. - Forgetting
depends_on:on a child — not inherited. A child that needs a dependency must declare it explicitly. (compose:is inherited from the parent when the child omits it — see Inheritance resolution rules.) render:block under atool/infraservice — therender:block is app-only. Tool / infra entries that declare it fail to load. To attach a template pack to a non-app service it must first be retyped toapp(with the prerequisitedir:).- Pre-existing non-symlink at a managed symlink path — if
CLAUDE.md(or anothersymlinks[].linkpath) already exists as a regular file,dwe render airefuses to overwrite it and exits with an error:refuse to overwrite non-symlink file at <path>; remove it or disable via render.ai.enabled: false. Delete the file first, or setrender.ai.enabled: falsefor that service.