Concurrent agents in one working tree

This repo is operated by multiple Claude Code sessions / scripts that share one working tree on disk. When two sessions run at once, one can wipe the other's uncommitted edits.

What you'll see in the reflog

The smoking gun is the pair:

<hash> HEAD@{...}: reset: moving to HEAD
<hash> HEAD@{...}: checkout: moving from <branch> to main

The reset: moving to HEAD line is the literal git reset --hard HEAD command running. It wipes the working tree to match the current HEAD, discarding any uncommitted changes. The checkout line is the branch switch that usually follows.

In our reflogs this pair has appeared multiple times — at unpredictable hours, not on a periodic schedule. It is not a scheduled cron or autocommit timer. It is another git-aware process (most likely another Claude Code session) starting fresh in the same working tree.

What it ISN'T

  • It is NOT dotkeeper. dotkeeper is the dotfiles auto-commit timer described in ~/.agent/AGENT.md under "dotkeeper timer policy." That timer commits-and-pushes; it doesn't git reset --hard. And dotkeeper only runs on dotfile repos, not this project repo.
  • It is NOT a cron job in this repo. Nothing in .github, scripts/, .husky (none present) or any package.json prepare hook does git reset --hard.
  • It is NOT a git hook fired by an editor save. The reset-then- checkout pair only fires occasionally, not on file save.

What it most likely IS

Another Claude Code session (or other agent / human-driven tool) working in the same checkout. The author email on commits during the windows when this fired matches Julian's GitHub no-reply (julian-corbet@users.noreply.github.com), which is just "tools authenticated as Julian" — i.e., another instance of the same agent stack. The reset+checkout pattern is consistent with a startup phase that says "discard whatever state was here and put me on main."

How to confirm if you want to find the source

# What process holds the repo lock right now?
lsof | grep '\.git'

# What other claude / git processes are running?
ps auxf | grep -E 'claude|git'

# When did the resets fire? Cross-reference with your shell history.
git reflog --date=iso | grep -E 'reset: moving to HEAD|checkout: moving from'

Knowing the source helps but doesn't fix it. The fix is workflow discipline (next section).

How to work safely around it

Treat uncommitted edits as ephemeral. The autocommit-elsewhere of someone else's session can wipe you at any moment.

  1. Commit after every meaningful edit. Small commits, often. git add -p && git commit -m "wip: ..." is fine; the messy history is recoverable via a later rebase or squash, but lost work is not.
  2. Push to your branch immediately after each commit so the work exists somewhere off-disk.
  3. Work on a branch, never directly on main if you're going to leave the tree dirty for more than a few seconds. The reset-then- checkout pattern always lands the tree on main — if you're already there with dirty edits, you lose them.
  4. Use git stash defensively if you have to step away.
  5. Watch the reflog at the start of any session that follows a gap. Suspicious resets are the signal to re-create work from a prior push, not assume "ah, files are gone, must be wrong."

What I (this agent) have learned

I earlier called this an "autocommit timer," which was wrong — I had conflated it with the dotkeeper rule from the global agent memory. The behavior is more accurately: shared-working-tree race conditions with other concurrent agents. The fix is the same (commit aggressively) but the diagnosis changes how I describe it in handoffs and how I would advise tightening if you ever wanted to: this is a process-level coordination problem, not a scheduled job to disable.

If you want true isolation, the canonical fix is git worktrees:

git worktree add ../careervector-agent-A auth-spike
git worktree add ../careervector-agent-B main
# Each agent works in its own physical directory, sharing the repo's
# objects but not the working tree. Resets in one don't touch the other.

This is heavier than the current single-tree workflow, but it's the durable fix if collisions become more frequent. Right now collisions are rare enough that defensive commits are a fine workaround.

Source: wiki/content/runbooks/CONCURRENT-AGENTS.md