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.
gwm init --preset rust # write a Rust-flavoured .gwm.tomlgwm init --list-presets # enumerate the built-ins, write nothinggwm init --preset node --show # print the resolved TOML to stdout, write nothinggwm init with no --preset flag stays byte-for-byte the generic template:
presets are purely additive.
The seven built-ins
Section titled “The seven built-ins”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
rustrefusestarget/,gorefusesbin/,node/nuxtrefusenode_modules/,python-uvrefuses.venv/, andlaravelrefusesvendor/. See[[bootstrap.no_symlink]].symfonyrefusesvendor/too, plusvar/: 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-rdsguard copies.envonly when it does not point at an Amazon RDS host (deny_patterns = ["amazonaws\\.com", "\\.rds\\."]); on a match it seeds from.env.exampleinstead. This is the original “no production RDS in a worktree.env” safeguard.symfonyreuses the same guard on the file Symfony actually gitignores,.env.local, and seeds it from.envrather than.env.example, since in Symfony’s convention it is.envthat is committed and holds the neutral defaults. - Install hooks are gated by
whenpredicates, so they no-op cleanly when the project file is absent (composer installonly fires onfile_exists:composer.json,uv synconly onfile_exists:pyproject.toml, and so on). Thenode/nuxtpackage-manager split is two mutually exclusive hooks:when = "file_exists:package.json && cmd_exists:bun"forbun install, andwhen = "file_exists:package.json && !cmd_exists:bun"for thenpm cifallback. on_failiswarnfor the install hooks (a failed install is reported but does not abort the worktree) andignorefor the optionaldirenv allow .step (silent when.envrcis absent).
--list-presets and --show
Section titled “--list-presets and --show”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:
gwm init --preset laravel --show | diff - .gwm.tomlWhere the bodies live
Section titled “Where the bodies live”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.