git clone https://github.com/Intense-Visions/harness-engineering
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/harness-git-workflow" ~/.claude/skills/intense-visions-harness-engineering-harness-git-workflow && rm -rf "$T"
agents/skills/claude-code/harness-git-workflow/SKILL.mdHarness Git Workflow
Worktree setup, dependency installation, baseline verification, and branch finishing. Clean isolation for every workstream.
When to Use
- When starting work that should be isolated from the main branch (new feature, experiment, multi-task plan)
- When finishing a branch and deciding how to land it (merge, PR, keep, discard)
- When
oron_pr
triggers fire and worktree management is neededon_commit - When the human asks to "set up a branch" or "start a new workstream"
- NOT for simple single-file changes that do not need branch isolation
- NOT when work is already in progress on the correct branch
Process
Part A: Worktree Creation
Step 1: Choose Worktree Location
-
Check for
directory in the project root. If it exists, use it — this is the preferred location..worktrees/ -
Check CLAUDE.md or AGENTS.md for worktree preferences. Some projects specify a custom worktree directory or naming convention. Follow those instructions.
-
If neither exists, ask the user: "Where should I create the worktree? Options: (A)
in the project root, (B) a sibling directory alongside the project, (C) a custom path.".worktrees/<branch-name> -
If placing worktrees in the project directory, verify that the worktree directory is gitignored. Check
for.gitignore
or the chosen directory name. If not gitignored, add it before creating the worktree..worktrees/
Step 2: Check for Existing Worktrees
-
Run
to see active worktrees.git worktree list -
If a worktree already exists for the target branch, do not create a duplicate. Ask: "A worktree for branch
already exists at<name>
. Should I use it, or create a new branch?"<path> -
If the target directory already exists (but is not a worktree), do not overwrite. Ask the user how to proceed.
Step 3: Create Branch and Worktree
-
Create the branch from the current HEAD (or from the specified base):
git branch <branch-name> <base> -
Create the worktree:
git worktree add <path> <branch-name> -
Verify the worktree was created. Check that the directory exists and contains a
file (not a.git
directory — worktrees use a file pointing to the main repo)..git
Step 4: Auto-Detect and Run Setup
Inspect the worktree for project files and run the appropriate setup:
| File Found | Action |
|---|---|
| (or / if lockfile indicates) |
| |
| |
| |
| or |
| |
(with target) | |
If multiple project files exist (monorepo), install at the root level. Do not guess which subpackages to install — follow the project's documented setup or ask.
Step 5: Verify Clean Baseline
Before any work begins, verify the worktree is in a clean, working state:
-
Run the test suite. All tests must pass on the fresh branch before any changes.
-
Run
. Project health must be green before starting work.harness validate -
If tests fail or validation fails on the fresh branch, stop. The base branch has issues. Report: "Baseline verification failed on fresh branch: [failure details]. The base branch needs to be fixed first."
-
Record the baseline. Note the test count and validation result. This is the comparison point for the branch finishing phase.
Part B: Branch Finishing
When work on the branch is complete, follow this protocol to land the changes.
Step 1: Pre-Finish Verification
-
Run the full test suite. All tests must pass.
-
Run
. Project health must be green.harness validate -
Check for uncommitted changes. Run
. All changes must be committed. If there are uncommitted changes, commit or stash them before finishing.git status -
Check the branch is up to date. If the base branch has advanced since the worktree was created:
git fetch origin git log HEAD..origin/main --onelineIf there are new commits on the base, rebase or merge before finishing:
git rebase origin/mainRe-run tests after rebasing.
Step 2: Choose Finishing Strategy
Present 4 options to the user:
-
Merge locally. Merge the branch into the base branch on the local machine.
- Best for: small changes, solo work, when CI is not required
- Command:
git checkout main && git merge <branch>
-
Push and create PR. Push the branch to the remote and open a pull request.
- Best for: team work, changes that need review, when CI must pass
- Command:
then create PR viagit push -u origin <branch>gh pr create
-
Keep as-is. Leave the branch and worktree in place for continued work later.
- Best for: work-in-progress, experiments, paused projects
-
Discard. Delete the branch and worktree. All changes are lost.
- Best for: failed experiments, abandoned approaches
- Safety: Confirm with the user before discarding. List the commits that will be lost.
Step 3: Execute Chosen Strategy
If merge locally:
cd <main-repo-path> git merge <branch-name> # Run tests on main after merge # Run harness validate after merge git worktree remove <worktree-path> git branch -d <branch-name>
If push and create PR:
cd <worktree-path> git push -u origin <branch-name> gh pr create --title "<title>" --body "$(cat <<'EOF' ## Summary <PR body with real newlines — never use \n escape sequences> ## Test plan <checklist> EOF )" # Report the PR URL to the user # Leave worktree in place until PR is merged
If keep as-is:
No action needed. Report the worktree path and branch name for future reference.
If discard:
# Confirm with user first — list commits that will be lost git worktree remove <worktree-path> git branch -D <branch-name>
Step 3.5: Cross-Reference Conventions for Commit Messages and PR Bodies
GitHub auto-links any
#N token in commit messages, PR titles, and PR bodies to the issue or PR with that number. Treat #N as a reserved sigil — never use it for non-issue references.
- Do not use
for proposal success criteria, list ordinals, footnote refs, table rows, or any other in-document numbering. Write "criterion 9", "item 9", "step 3" instead. Using#N
to mean "criterion 9" will silently cross-reference issue #9 — which is almost certainly an unrelated issue — and add a misleading back-reference to that issue's timeline.#9 - Do reference the actual roadmap/tracker issue when finishing work tied to one. Use
for context-only links andRefs #<issue>
/Closes #<issue>
only when the merge should auto-close that issue.Fixes #<issue> - Before pushing or opening the PR, scan the commit messages and PR body for stray
tokens. For each one, confirm it points to the intended issue/PR — or rewrite it as plain text.#N
Step 4: Clean Up
-
Remove the worktree (unless keeping as-is or waiting for PR merge):
git worktree remove <worktree-path> -
Prune stale worktree references:
git worktree prune -
Verify cleanup. Run
and confirm the removed worktree is no longer listed.git worktree list
Harness Integration
— Run during baseline verification (Step 5 of Part A) and pre-finish verification (Step 1 of Part B). Ensures project health is green at both boundaries.harness validate- Test runner — Run fresh in the worktree, not in the main repo. Tests must pass both at baseline (before work) and at finish (after work).
— Verify worktree directory is gitignored if it lives inside the project tree..gitignore
Success Criteria
- Worktree was created in the correct location (
preferred, or per project convention).worktrees/ - Dependencies were auto-detected and installed
- Baseline verification passed (tests green, harness validates) before any work began
- Branch finishing strategy was chosen by the user (not assumed)
- Chosen strategy was executed correctly (merge, PR, keep, or discard)
- Worktree was cleaned up after finishing (unless keeping for continued work)
- No stale worktree references remain after cleanup
Rationalizations to Reject
| Rationalization | Reality |
|---|---|
| "The tests are probably fine on the fresh branch — they were passing on main when I last checked. I'll skip baseline verification and start working." | Baseline verification is the condition that makes branch work trustworthy. A test failure discovered at finish time is ambiguous — it could be pre-existing or introduced by the work. Skipping baseline removes the only clean comparison point. |
| "The user said 'just merge it' — I'll merge without checking if the base branch has advanced since the worktree was created." | The pre-finish check for base branch divergence is mandatory before any finishing strategy. Merging without rebasing first can produce a merge that silently breaks tests that were passing on the branch but conflict with new commits on main. |
| "The worktree directory isn't gitignored, but it's inside a nested folder that's unlikely to be committed accidentally." | The check is not about likelihood — it is about preventing accidental commits of worktree state that would corrupt the repository. If the worktree directory is not gitignored, add it before creating the worktree. No exceptions. |
| "The user chose to discard — I'll delete the branch and worktree immediately without showing the commits that will be lost." | The discard path requires showing the commit list from and receiving explicit confirmation before running and . Work is being permanently deleted; the user must see what they are losing. |
| "There's already a worktree for this branch at a different path — I'll create a second one since the user asked for a fresh setup." | Git does not allow two worktrees checked out to the same branch. Attempting to create a duplicate will fail. Instead, ask the user whether to use the existing worktree or create a new branch. Never assume a second worktree is the right answer. |
"I'll use in the commit message to refer to 'success criterion 9' in the proposal — it's obviously an in-document reference." | is GitHub's reserved syntax for issue/PR links in commits and PR bodies. It will auto-link to issue/PR #9 regardless of intent and post a misleading back-reference on that unrelated issue. Write "criterion 9" (no ) and cite the real roadmap issue separately with . |
Examples
Example: Setting Up a Worktree for a New Feature
# Check for preferred location ls .worktrees/ # exists — use it # Check gitignore grep '.worktrees' .gitignore # found — good, already gitignored # Check existing worktrees git worktree list # /Users/dev/project abc1234 [main] # No existing worktree for this feature # Create branch and worktree git branch feat/notifications main git worktree add .worktrees/notifications feat/notifications # Auto-detect setup (found package.json) cd .worktrees/notifications && npm install # Verify baseline npm test # 142 tests, all pass harness validate # passes # Ready to work. Report: # "Worktree created at .worktrees/notifications on branch feat/notifications. # 142 tests passing. harness validate green. Ready to start."
Example: Finishing a Branch with PR
# Pre-finish verification cd .worktrees/notifications npm test # 158 tests, all pass (16 new) harness validate # passes git status # clean — all committed # Check if base has advanced git fetch origin git log HEAD..origin/main --oneline # 3 new commits on main — rebase git rebase origin/main npm test # still passes after rebase # User chooses: Push and create PR git push -u origin feat/notifications gh pr create --title "feat(notifications): email and in-app notifications" --body "$(cat <<'EOF' ## Summary Implements notification service with create, list, and expiry. ## Test plan - [x] 16 new tests, all passing EOF )" # Report: "PR created: https://github.com/org/repo/pull/42 # Worktree at .worktrees/notifications kept until PR merges."
Example: Discarding a Failed Experiment
# User says: "That approach didn't work, let's scrap it." # Show what will be lost git log main..HEAD --oneline # a1b2c3d try websocket approach # d4e5f6g add socket.io dependency # "These 2 commits will be lost. Discard? (yes/no)" # Human: "yes" git worktree remove .worktrees/ws-experiment git branch -D feat/ws-experiment git worktree prune git worktree list # ws-experiment no longer listed