gwm-cli 1.6.1

git worktree manager — TUI + CLI, native libgit2, per-repo bootstrap
Documentation
---
title: Config presets
description: gwm init --preset <stack> seeds an opinionated .gwm.toml for a known stack — the six built-ins (laravel, node/nuxt, rust, go, python-uv, generic), what each seeds, --list-presets and --show.
navigation:
  title: Config presets
---

# 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](/configuration/when-predicates).

```bash
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.

## The six 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`.
```

`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`   ||| — (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 .`     |
| `node`/`nuxt` | `node_modules`     | copy `.env` + `.env.local`                                  | `bun install` if `bun` on PATH, else `npm ci`; `direnv allow .`         |
| `rust`      | `target`             || `cargo fetch`; `direnv allow .`                                         |
| `go`        | `bin`                || `go mod download`                                                       |
| `python-uv` | `.venv`              || `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]]`]/configuration/gwm-toml.
- **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`"]/configuration/guards safeguard.
- **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).

## `--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:

```bash
gwm init --preset laravel --show | diff - .gwm.toml
```

## Where the bodies live

Preset bodies are embedded in the binary. The five stack presets are kept in
sync with the checked-in copies under [`examples/presets/<name>.toml`](https://github.com/kbrdn1/gwm-cli/tree/main/examples/presets)
(`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`](https://github.com/kbrdn1/gwm-cli/blob/main/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`](/configuration/gwm-toml), and validate it with
`gwm doctor`.