Agent worktrees & re-signing¶
Hardened coding agents run in a sandbox that cannot reach your YubiKey — so they cannot sign commits. Rather than weaken signing (or the sandbox), dotty gives agents git worktrees where signing is switched off, and a one-command way to re-sign the history afterwards with your hardware key.
sequenceDiagram
participant A as Agent
participant W as Worktree (signing off)
participant Y as You (YubiKey)
A->>W: dotty worktree start (WorktreeCreate hook)
A->>W: commits, unsigned
Y->>W: dotty git resign --root
Y->>W: review / merge
A->>W: dotty worktree end (WorktreeRemove hook)
Lifecycle¶
dotty worktree start creates (or reuses) a
worktree on an agent/<repo>-<suffix> branch and prints its path;
dotty worktree end removes the worktree, its
tmux session, and the agent/* branch.
Where worktrees live is a per-profile setting (dotty init --worktrees):
- Repo-relative (default
.worktrees) — each repository keeps its own agent worktrees inside itself; the shared global gitignore keeps the directory out of git. - Absolute shared root — one directory for all repos' worktrees; the hardened sandboxes add it to their writable roots.
The resolved location is exported as $DOTTY_WORKTREES by the active profile's
env.zsh, which is also how the Neovim session picker
finds and groups worktree sessions under <leader>+F+S.
Hook wiring¶
Both verbs also accept their agent hook JSON on stdin, so they wire directly
into agent hooks with no glue: the scaffolded Claude Code settings map
WorktreeCreate → dotty worktree start and WorktreeRemove →
dotty worktree end. When Claude Code creates an isolated worktree for a task,
dotty places it in the configured location and names the branch; when the
worktree is discarded, dotty cleans up the branch and tmux session too.
The signing hand-off¶
Inside agent worktrees, commit and tag signing are off — the shared git
config's final include, ~/.config/dotty/active-profile/worktrees.gitconfig,
applies commit.gpgSign=false to any gitdir under .git/worktrees/. Agents
commit freely; nothing blocks on a key that isn't there.
Signing is restored two ways:
commit.sh— the shared agent memory doc teaches every agent to emit acommit.shscript with the exact commit (or re-sign) commands for you to run outside the sandbox. It's in the global gitignore, so a stray script never lands in history.dotty git resign— rebase and re-sign a range with your hardware key:
dotty git resign --root # every commit in the branch's history
dotty git resign main # just main..HEAD
dotty git resign main --reset-author
--reset-author also resets each commit's author to your current git identity
and rewrites author trailers — useful when the agent committed as itself.
Resigning rewrites history
Commits get new SHAs. dotty git resign prompts before rewriting
(skip with --yes); do it before the branch is shared, or expect a
force-push.
A typical run¶
- An agent session starts a task; the
WorktreeCreatehook callsdotty worktree start, and work happens onagent/myrepo-fix-tests. - The agent commits as it goes — unsigned, Conventional Commits.
- You review, then
dotty git resign main— every commit aftermainis re-signed by your YubiKey (touch once per commit). - Merge or propose the branch;
dotty worktree end(or theWorktreeRemovehook) cleans up the worktree, branch, and tmux session.