Config

Write your first `/gtw` config

One minute of YAML and every `/gtw` subcommand runs the hooks you want — without blocking the main flow if a hook fails.

by NightMe team 5 min read

One minute of YAML and every /gtw subcommand runs the hooks you want — without blocking the main flow if a hook fails.

/gtw is a family of subcommands (fix, commit, push, pr, close, sync, back) that wrap the "open a worktree, run an agent, ship a PR" loop into IM-friendly cards. Each subcommand reads its defaults from ~/.nightme/gtw.yml before doing the work — that's where you pin the agent for /gtw pr and the shell commands that should run before/after each step.

The file is optional. A missing or unreadable yml is a silent no-op; a YAML syntax error surfaces as a warning in the command reply, never a hard failure ("hooks are additive, never block main flow").

Minimal example

# ~/.nightme/gtw.yml
fix:
  hooks:
    after:
      - codegraph init   # bare-string form: runs `codegraph init` in the worktree

commit:
  agent: pi              # default agent for /gtw commit when no -a flag

push:
  hooks:
    after:
      - type: shell      # explicit mapping form: same effect as the bare-string
        run: make lint

That gives you:

  • /gtw fix <id> — after cutting the worktree, runs codegraph init from the worktree directory. Failures are non-fatal; the worktree is still handed to the agent.
  • /gtw commit — picks pi as the agent (unless you pass -a <other> on the command line).
  • /gtw push — runs make lint from the worktree before pushing.

Schema

The top level is a fixed set of per-command subsections. Each one is independently optional — a partial yml is fine.

fix:    CmdConfig   # /gtw fix
commit: CmdConfig   # /gtw commit
push:   CmdConfig   # /gtw push
pr:     CmdConfig   # /gtw pr
close:  CmdConfig   # /gtw close
sync:   CmdConfig   # /gtw sync
back:   CmdConfig   # /gtw back

CmdConfig:
  agent: string             # optional, default ""
  hooks:
    before: []Hook          # optional, default []
    after:  []Hook          # optional, default []

Hook:
  - <bare string>           # sugar for: { type: shell, run: <string> }
  - { type: shell, run: <string> }

agent controls the default agent for subcommands that invoke one (commit, pr — and fix if you want to pin one per project). See Agent priority below for the resolution order.

hooks.before runs before the subcommand's main work; hooks.after runs after. Hooks execute sequentially in declaration order, with the chat's current working directory as their cwd. Each hook has a 30-minute timeout; a hook that exits non-zero (or times out, or fails to spawn) is logged as a warning and the next hook still runs.

Only type: shell (or the bare-string sugar) is honoured. Unknown hook types are warn-skipped.

Agent priority

When a /gtw subcommand needs to pick an agent — /gtw fix, /gtw commit, and /gtw pr invoke one — it walks three sources in order:

  1. The -a / --agent flag on the command line.
  2. <cmd>.agent from ~/.nightme/gtw.yml.
  3. The chat's currently-selected agent (/use claude).

The first non-empty wins. If the yml names an agent that isn't registered, a warning is emitted and the chat's selected agent is used as the fallback. Leave agent: "" (or omit it entirely) to defer to the chat's /use selection.

Hook environment

Every hook subprocess inherits os.Environ() and gets four GTW_* variables appended on top. PATH / HOME / LANG are not overridden — only added to.

Variable Meaning Source
GTW_REPO_ROOT Absolute path of the main repo yml + git rev-parse --show-toplevel fallback
GTW_WORKTREE Absolute path of the active worktree (or GTW_REPO_ROOT for sync) same
GTW_BRANCH Current branch in the worktree ("" if detached) git rev-parse --abbrev-ref HEAD
GTW_DEFAULT_BRANCH Upstream default branch name ("" if not discoverable) git symbolic-ref refs/remotes/origin/HEAD

Empty fields are omitted from the env, not exported as empty strings. A hook can detect "not discoverable" without parsing blanks:

hooks:
  before:
    - "[[ -n \"$GTW_DEFAULT_BRANCH\" ]] && git fetch origin $GTW_DEFAULT_BRANCH"

A fuller example

# ~/.nightme/gtw.yml

fix:
  agent: pi
  hooks:
    # before: []
    after:
      - codegraph init      # prime the codegraph index for the new worktree

commit:
  agent: pi
  # hooks: {}

push:
  agent: pi
  # hooks: {}

pr:
  agent: pi
  # hooks: {}

sync:
  agent: ""                # empty → fall through to the chat's /use agent
  # hooks: {}

Keep it short. The whole point is "every /gtw boots into a ready worktree without me thinking about it" — once you've hit that, more config is usually friction.

When to use config vs. just running setup yourself

Use gtw.yml when Do it by hand when
Every worktree needs the same setup. The worktree needs context that only exists in this chat (e.g. an uncommitted secret).
The setup is something you can express as a one-liner. The setup is genuinely one-off and not worth templating.
You want the agent to inherit the worktree ready-to-go. You're experimenting and don't care about repeatability.

Hooks that fail are surfaced in the command reply (⚠️ hook X exited N) but never abort /gtw — so a broken hook can sit in the yml while you fix it, instead of blocking the whole flow.

What's next