CLI Reference

add compose / add docker

Regenerate compose.yml, or just the Dockerfile/.dockerignore, standalone into an existing project.

add compose and add docker regenerate the containerized dev infrastructure on their own, without touching any application code. Reach for them when the files were deleted, or to rebuild them cleanly after manual edits drifted from the generated shape.

go tool gpsystem add compose
go tool gpsystem add docker

new project already ships the full containerized dev stack (compose.yml, Dockerfile, .dockerignore). These two commands (re)generate that infrastructure standalone, without touching any application code: for a project where the files were deleted, or to rebuild compose.yml cleanly after manual edits drifted from the generated shape.

add compose

Renders compose.yml from scratch: the base dev stack (postgres, valkey, mailpit, rustfs, rustfs-init, migrate, worker) plus one app service for every module recorded in the manifest (gpsystem.yaml), in sorted order. It also backfills the .env.example # gpsystem:env block if it's missing.

go tool gpsystem add compose

Refuses to overwrite an existing compose.yml unless --force is given: regeneration replaces the whole file, so any service you added by hand below the # gpsystem:services anchor is lost. If you only need to wire one new module into an existing compose.yml, new module already does that via anchor insertion; reach for add compose when you want a clean rebuild instead.

go tool gpsystem add compose --force

If no Dockerfile is present, the command prints a note pointing at add docker: every service in compose.yml builds from it.

add docker

Renders the multi-stage Dockerfile (development/build/production targets) and .dockerignore that compose.yml builds against.

go tool gpsystem add docker
go tool gpsystem add docker --force   # overwrite both files

Both files are written atomically as one plan: with an existing Dockerfile or .dockerignore and no --force, the whole run aborts before writing either.

Local-replace wiring

Both commands recover every locally-replaced module's checkout path from your go.mod's replace directives, the same way new module does: whatever --replace and --replace-dev wrote at new project time (a contributor/dev-mode feature; ordinary published-module projects have none of these). For every module with a replace in effect, add compose/add docker regenerate the matching development-target bind mount and build/production-target additional_contexts entry. Regenerating on a machine without any replace directives (the common case: a project consuming published module versions) simply omits all of those lines.

add compose reads module names from gpsystem.yaml's modules map, the same source new module writes to. A manifest with zero modules recorded still gets the base stack, with no app services; a note reminds you that new module adds each one.

Copyright © 2026