Skip to content
gwmgwmgwmv1.10.0

Config presets

gwm init --preset <name> writes an opinionated .gwm.toml tailored to a known stack instead of the generic documented template (issue #37). Each preset seeds the same building blocks you would otherwise hand-write: a [worktree] naming convention, [[bootstrap.no_symlink]] invariants, [[bootstrap.copy]] / [[bootstrap.guard]] rules, and [[hooks.post_create]] install hooks gated by when predicates.

Terminal window
gwm init --preset rust # write a Rust-flavoured .gwm.toml
gwm init --list-presets # enumerate the built-ins, write nothing
gwm init --preset node --show # print the resolved TOML to stdout, write nothing

gwm init with no --preset flag stays byte-for-byte the generic template: presets are purely additive.

Run gwm init --list-presets for the authoritative one-line descriptions (it needs no git repo and writes nothing):

generic The fully-documented default template (same as `gwm init`).
go Go module: bin/ no-symlink + `go mod download`.
laravel Laravel: env copies + AWS-RDS guard + vendor/ no-symlink + composer install.
node Node / Nuxt: node_modules/ no-symlink + bun-or-npm install. (alias: nuxt)
python-uv Python (uv): .venv/ no-symlink + `uv sync`.
rust Rust crate: target/ no-symlink + `cargo fetch`.
symfony Symfony: .env.local copy + AWS-RDS guard + vendor/ and var/ no-symlink + composer install.

nuxt is an alias of node: both resolve to the same body. Every preset shares the default [worktree] block (base = "{home}/cc-worktree/{repo}", path_pattern = "{type}-{issue}-{desc}", branch_pattern = "{type}/#{issue}-{desc}"); the table below lists only what each one adds on top.

Preset No-symlink invariant File copies / guards post_create hook(s)
generic (none) (none) (none), the documented default, same as gwm init
laravel vendor copy .env (guarded no-aws-rds) + .env.testing composer install --no-interaction --prefer-dist; direnv allow .
symfony vendor, var copy .env.local (guarded no-aws-rds) + .env.test.local composer install --no-interaction --prefer-dist; direnv allow .
node/nuxt node_modules copy .env + .env.local bun install if bun on PATH, else npm ci; direnv allow .
rust target (none) cargo fetch; direnv allow .
go bin (none) go mod download
python-uv .venv (none) uv sync

A few details worth calling out:

  • No-symlink invariants keep each worktree’s build artefacts / dependency tree its own rather than inheriting a symlink to the main repo’s. This is why rust refuses target/, go refuses bin/, node/nuxt refuse node_modules/, python-uv refuses .venv/, and laravel refuses vendor/. See [[bootstrap.no_symlink]]. symfony refuses vendor/ too, plus var/: it holds the compiled service container and the cached routes, so sharing it between two worktrees running different code is worse than a slow first request.
  • The Laravel no-aws-rds guard copies .env only when it does not point at an Amazon RDS host (deny_patterns = ["amazonaws\\.com", "\\.rds\\."]); on a match it seeds from .env.example instead. This is the original “no production RDS in a worktree .env” safeguard. symfony reuses the same guard on the file Symfony actually gitignores, .env.local, and seeds it from .env rather than .env.example, since in Symfony’s convention it is .env that is committed and holds the neutral defaults.
  • Install hooks are gated by when predicates, so they no-op cleanly when the project file is absent (composer install only fires on file_exists:composer.json, uv sync only on file_exists:pyproject.toml, and so on). The node/nuxt package-manager split is two mutually exclusive hooks: when = "file_exists:package.json && cmd_exists:bun" for bun install, and when = "file_exists:package.json && !cmd_exists:bun" for the npm ci fallback.
  • on_fail is warn for the install hooks (a failed install is reported but does not abort the worktree) and ignore for the optional direnv allow . step (silent when .envrc is absent).

gwm init --list-presets enumerates the built-ins with their one-line descriptions and exits without writing anything. It needs no git repo, so it is safe to run anywhere as a reminder of the available stacks.

gwm init --preset <name> --show prints the resolved preset TOML to stdout instead of writing .gwm.toml. Use it to diff a preset against an existing config before committing to it:

Terminal window
gwm init --preset laravel --show | diff - .gwm.toml

Preset bodies are embedded in the binary. The six stack presets are kept in sync with the checked-in copies under examples/presets/<name>.toml (node.toml backs both node and nuxt). Read those files for the exact, fully-commented source of each. The generic preset has no file of its own: its body is examples/gwm.toml.example, the complete annotated schema, which is also what gwm init writes with no --preset.

Once written, a preset’s .gwm.toml is an ordinary config: edit it by hand or with gwm config set, and validate it with gwm doctor.