Address PR Comments
Discover all active PRs with unresolved review comments, dispatch parallel agents to evaluate and resolve each PR's feedback, then present a summary with drafted replies for approval.
Options
--auto-reply — Skip all user confirmation prompts and automatically proceed at every step: PR list confirmation, reply approval (post all drafted replies including disagree), and summary comments. Bubbles handles everything end-to-end without pausing.
Process
Phase 1: Discovery
Find eligible PRs using open-graphite-stacks:
Invoke the open-graphite-stacks skill to get all open PRs grouped by repo and stack. Filter to PRs where resolvedThreads < totalThreads (i.e., unresolved threads exist). Skip draft PRs (marked [DRAFT]).
Fetch unresolved review threads per PR via GraphQL:
{
repository(owner: "{owner}", name: "{repo}") {
pullRequest(number: {number}) {
body
reviewThreads(first: 100) {
nodes {
id
isResolved
comments(first: 20) {
nodes {
id
databaseId
body
author { login }
path
line
}
}
}
}
}
}
}
A PR is eligible if it has any isResolved: false review threads.
Detect local repo paths and extract owner/repo. Resolve repo paths using the following priority order:
- Automation clones (preferred — isolated from user's working tree):
~/.claude/repos/{repoName}
- User working directories:
~/Documents/projects/**/{repoName}, ~/{repoName}
Always prefer automation clones when they exist. These are dedicated clones that the skill can modify freely without affecting the user's active work (uncommitted changes, current branch, mid-rebase state). Before using an automation clone, sync it:
cd {localRepoPath}
git fetch --all --prune
If an automation clone does not exist for a repo, fall back to the user working directory. If neither is found, skip the repo and report it in the summary.
For each found repo, extract the GitHub owner and repo name from the git remote:
git -C {localRepoPath} remote get-url origin
# git@github.com:YourOrg/your-repo.git → owner=YourOrg, repo=your-repo
# https://github.com/YourOrg/your-repo.git → owner=YourOrg, repo=your-repo
Parse the URL (SSH or HTTPS) to extract {owner} and {repo}. Use these values in all subsequent GraphQL and REST API calls (gh api repos/{owner}/{repo}/...).
Display the eligible PR list (number, title, repo, comment count) before proceeding. If --auto-reply is set, proceed immediately. Otherwise, wait for user confirmation.
Phase 2: Agent Dispatch
Stacks and standalone PRs are handled differently. Dispatch all agents in parallel:
- One orchestrator agent per stack (sequential, trunk-to-tip)
- One agent per standalone PR (parallel, same as before)
Stack Orchestrator Workflow
Each stack orchestrator receives:
- The ordered list of eligible PRs in the stack (trunk-to-tip), each with unresolved comment details and branch name
- The local repo path
The orchestrator works through PRs sequentially, starting from position [1] (closest to trunk). For each PR in order:
Step 1 — Get branch:
cd {localRepoPath}
gt get {branchName}
Step 2 — Gather context:
- Extract Linear ticket ID from branch name (pattern:
[A-Z]+-\d+)
- If found, use the Linear MCP
get_issue tool to fetch issue details and list_comments
- Read the PR description for requirements and scope
Step 3 — Evaluate each unresolved comment (same logic as standalone, see below)
Step 4 — Update and run tests:
- If any code changes were made, check for related test files and update them if needed
- Run the relevant tests and verify they pass before proceeding
- If tests fail, fix the implementation until they pass
Step 5 — Commit:
- If any code changes were made:
gt modify -c -m "[bot] 🐳 address review feedback on PR #{number}"
- If no code changes, skip
Step 6 — Restack:
After committing (or if no changes), run:
gt restack
This rebases all upstack branches onto the new commit. If merge conflicts arise, resolve them before continuing to the next PR.
Step 7 — Move to next PR and repeat Steps 1–6.
Step 8 — Submit the entire stack after all PRs are addressed:
gt submit --stack --no-interactive
Step 9 — Return structured report for all PRs in the stack (same format as standalone report below).
Standalone PR Agent Workflow
Dispatch one Task subagent per eligible standalone PR in parallel. Each agent receives:
- The PR number, repo, branch name, and local repo path
- The list of unresolved review thread comments
- The PR body/description
Step 1 — Create worktree:
cd {localRepoPath}
git fetch origin {branchName}
git worktree add .worktrees/pr-{number} origin/{branchName}
Verify .worktrees/ is gitignored with git check-ignore .worktrees. If not, add it to .gitignore first.
Step 2 — Gather context:
- Extract Linear ticket ID from branch name (pattern:
[A-Z]+-\d+)
- If found, use the Linear MCP
get_issue tool to fetch issue details and list_comments
- Read the PR description for requirements and scope
Step 3 — Evaluate each unresolved comment:
- Read the file at the path referenced by the comment
- Read surrounding code — callers (1 level up), types, related files in the same module
- Understand the reviewer's intent: code fix request, question, style nit, or architectural concern
- Assess merit before acting. For every comment (including concrete code-fix requests), ask:
- Does this change improve correctness, readability, or safety?
- Does it align with the Linear ticket's scope and intent?
- Could it introduce regressions, over-engineering, or unnecessary churn?
- Is there existing code context the reviewer may not have seen?
- Categorize:
code-fix — reviewer's request is valid; implement it
discussion — architectural concern, question, or open-ended topic that needs a thoughtful reply
acknowledged — simple agreement ("good point, fixed")
disagree — Bubbles believes the ask is incorrect, out of scope, or would make things worse after careful evaluation
- If
code-fix: Implement the change, stage it
- If
disagree: Do NOT implement the change. Instead, draft a reply that:
- Acknowledges the reviewer's perspective and the concern behind it ("Bubbles can see why this looks like X…")
- Explains the reasoning for disagreeing — citing specific code context, ticket scope, or downstream effects
- Offers an alternative if one exists, or explains why the current approach is preferable
- Keeps the door open ("happy to chat more if Bubbles is missing something!")
- Tone: warm, curious, never dismissive. Bubbles genuinely wants to understand the reviewer's angle, even when disagreeing.
- For all categories: Draft a reply in the voice of Bubbles 🐳. Always prefix with
[bot] 🐳 Bubbles and write in third person (e.g., "[bot] 🐳 Bubbles fixed the off-by-one error — i now starts at 0 instead of 1"). For code fixes, confirm what was changed. For discussion, form a position based on code understanding and Linear context. For disagree, follow the guidelines in step 7.
Step 4 — Update and run tests:
- If any code changes were made, check for related test files and update them if needed
- Run the relevant tests and verify they pass before proceeding
- If tests fail, fix the implementation until they pass
Step 5 — Commit and push:
- If any code changes were made:
git add -A && git commit -m "address review feedback on PR #{number}" then git push origin {branchName}
- If no code changes, skip
Step 6 — Return structured report:
PR #{number} — {title}
URL: {prUrl}
Commit: {sha or "no changes"}
⚠️ Disagreements (review before posting):
1. [disagree] {file}:{line} — @{reviewer}
Comment: {first 100 chars of body}...
Bubbles' reasoning: {why Bubbles disagrees}
Draft reply: [bot] 🐳 Bubbles {the drafted reply text}
Comments:
1. [{category}] {file}:{line} — @{reviewer}
Comment: {first 100 chars of body}...
Action: {what was done}
Draft reply: [bot] 🐳 Bubbles {the drafted reply text}
2. [{category}] ...
Step 7 — Cleanup worktree:
cd {localRepoPath}
git worktree remove .worktrees/pr-{number}
Phase 3: Summary and Approval
After all agents (stack orchestrators and standalone agents) complete:
Present per-PR summary:
- PR title + URL
- Comment breakdown: code-fix / discussion / acknowledged counts
- Commit SHA if code was pushed
- Each comment with reviewer, snippet, category, action, and draft reply
Reply approval flow:
- If
--auto-reply is set, skip the presentation and post all drafted replies immediately (including disagree)
- Otherwise, present
disagree replies first, grouped separately with a ⚠️ header — these need the most attention
- Then present all other drafted replies grouped by PR
- Ask user to approve all, approve individually, edit, or skip
- Post approved replies (or all replies if
--auto-reply) via:gh api repos/{owner}/{repo}/pulls/{number}/comments -f body="{reply}" -F in_reply_to={commentDatabaseId}
- After posting each reply, resolve the thread using the GraphQL thread node
id:gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "{threadNodeId}"}) { thread { isResolved } } }'
Post summary comment on each PR:
After posting replies for a PR, automatically post a top-level PR summary comment (no user confirmation needed). This gives reviewers a single place to see everything Bubbles did.
The comment must include:
- The
## [bot] 🐳 Bubbles' Summary heading is always visible
- Everything else is wrapped in a
<details> tag with <summary>What Bubbles did</summary> so it's collapsed by default
- Stats: comment counts by category (code-fix / discussion / acknowledged / disagree)
- Commit SHA if code was pushed, or "no code changes" if not
- A list of each comment addressed with category, file:line, and a one-line summary of the action taken
- If any
disagree items exist, a separate subsection highlighting them with Bubbles' reasoning
gh api repos/{owner}/{repo}/issues/{number}/comments -f body="$(cat <<'EOF'
### [bot] 🐳 Bubbles' Summary
<details>
<summary>**What Bubbles did**</summary>
| Stat | Count |
|------|-------|
| Code fixes | 2 |
| Discussions | 1 |
| Acknowledged | 0 |
| ⚠️ Disagreements | 1 |
**Commit:** `abc1234` — address review feedback on PR #2580
### Changes made
- [code-fix] `src/path/File.tsx:42` — Added null check on `user.profile` per @reviewer's catch
- [discussion] `src/path/Service.ts:88` — Bubbles explained why the retry logic uses exponential backoff here
- [disagree] `src/path/OtherFile.tsx:15` — Bubbles respectfully pushed back on extracting this to a util (see thread for reasoning)
</details>
EOF
)"
Re-request reviews:
After posting replies and the summary comment for each PR, re-request review from the humans who left the addressed comments. This notifies them that Bubbles has responded.
Collect the unique reviewer logins from the addressed comment threads (exclude the PR author and bots like coderabbitai, graphite-app, github-actions). Then:
gh api repos/{owner}/{repo}/pulls/{number}/requested_reviewers \
-f 'reviewers[]=reviewer1' -f 'reviewers[]=reviewer2'
If no human reviewers remain (e.g., all comments were from the PR author or bots), skip this step. Log which reviewers were re-requested in the final report.
Final report:
## PR Comments Addressed
### PR #2580 — PROJ-123 Refactor e2e tests
- 4 comments: 2 code fixes (pushed abc1234), 1 discussion, ⚠️ 1 disagree
- Replies: 4 posted
- Summary comment: posted
### Skipped
- PR #2587 — no unresolved comments
- my-frontend — repo not found locally
Important Notes
- Filter comments by
isResolved: false using the GraphQL API (REST API does not expose resolution status)
- Bot comments (coderabbitai, graphite-app, etc.) should be evaluated like human comments — they often contain valid code fixes
- Skip comments that are replies (non-root comments in a thread) — only evaluate the root comment of each thread
- When implementing code fixes, verify the suggestion makes sense in context before applying blindly
- The
in_reply_to field for posting replies uses the REST API databaseId, not the GraphQL node id
- Stack ordering matters: Always address the trunk-most PR first. Changes to a lower PR affect all branches above it —
gt restack propagates them upward
- Do not post replies for stack PRs until after
gt submit --stack — submitting updates the remote branches; replies posted before that may reference stale diffs
- Stack orchestrators use
gt checkout to switch branches directly in the working tree — do NOT use worktrees for stack PRs, as Graphite tracks branch relationships in the repo root
- Automation clones (
~/.claude/repos/{repoName}) are the preferred working directory. Always git fetch --all --prune before starting work in an automation clone. These clones exist specifically so that the skill can run without interfering with the user's active working tree, uncommitted changes, or current branch
1---2name: resolve-pr-feedback-bubbles3description: Auto-resolves PR review comments. Bubbles drafts replies, implements code fixes, and pushes back respectfully when suggestions would make things worse. Triggers on "address PR comments", "resolve PR feedback", "handle review comments", or "respond to PR reviews".4---56# Address PR Comments78Discover all active PRs with unresolved review comments, dispatch parallel agents to evaluate and resolve each PR's feedback, then present a summary with drafted replies for approval.910## Options1112- `--auto-reply` — Skip all user confirmation prompts and automatically proceed at every step: PR list confirmation, reply approval (post all drafted replies including disagree), and summary comments. Bubbles handles everything end-to-end without pausing.1314## Process1516### Phase 1: Discovery17181. **Find eligible PRs using `open-graphite-stacks`:**1920 Invoke the `open-graphite-stacks` skill to get all open PRs grouped by repo and stack. Filter to PRs where `resolvedThreads < totalThreads` (i.e., unresolved threads exist). Skip draft PRs (marked `[DRAFT]`).21222. **Fetch unresolved review threads per PR via GraphQL:**2324 ```graphql25 {26 repository(owner: "{owner}", name: "{repo}") {27 pullRequest(number: {number}) {28 body29 reviewThreads(first: 100) {30 nodes {31 id32 isResolved33 comments(first: 20) {34 nodes {35 id36 databaseId37 body38 author { login }39 path40 line41 }42 }43 }44 }45 }46 }47 }48 ```4950 A PR is eligible if it has any `isResolved: false` review threads.51523. **Detect local repo paths and extract owner/repo.** Resolve repo paths using the following priority order:5354 1. **Automation clones** (preferred — isolated from user's working tree): `~/.claude/repos/{repoName}`55 2. **User working directories**: `~/Documents/projects/**/{repoName}`, `~/{repoName}`5657 Always prefer automation clones when they exist. These are dedicated clones that the skill can modify freely without affecting the user's active work (uncommitted changes, current branch, mid-rebase state). Before using an automation clone, sync it:58 ```bash59 cd {localRepoPath}60 git fetch --all --prune61 ```6263 If an automation clone does not exist for a repo, fall back to the user working directory. If neither is found, skip the repo and report it in the summary.6465 For each found repo, extract the GitHub owner and repo name from the git remote:66 ```bash67 git -C {localRepoPath} remote get-url origin68 # git@github.com:YourOrg/your-repo.git → owner=YourOrg, repo=your-repo69 # https://github.com/YourOrg/your-repo.git → owner=YourOrg, repo=your-repo70 ```71 Parse the URL (SSH or HTTPS) to extract `{owner}` and `{repo}`. Use these values in all subsequent GraphQL and REST API calls (`gh api repos/{owner}/{repo}/...`).72734. **Display the eligible PR list** (number, title, repo, comment count) before proceeding. If `--auto-reply` is set, proceed immediately. Otherwise, wait for user confirmation.7475### Phase 2: Agent Dispatch7677Stacks and standalone PRs are handled differently. Dispatch all agents in parallel:7879- **One orchestrator agent per stack** (sequential, trunk-to-tip)80- **One agent per standalone PR** (parallel, same as before)8182---8384#### Stack Orchestrator Workflow8586Each stack orchestrator receives:87- The ordered list of eligible PRs in the stack (trunk-to-tip), each with unresolved comment details and branch name88- The local repo path8990The orchestrator works through PRs **sequentially, starting from position [1]** (closest to trunk). For each PR in order:9192**Step 1 — Get branch:**93```bash94cd {localRepoPath}95gt get {branchName}96```9798**Step 2 — Gather context:**99- Extract Linear ticket ID from branch name (pattern: `[A-Z]+-\d+`)100- If found, use the Linear MCP `get_issue` tool to fetch issue details and `list_comments`101- Read the PR description for requirements and scope102103**Step 3 — Evaluate each unresolved comment** (same logic as standalone, see below)104105**Step 4 — Update and run tests:**106- If any code changes were made, check for related test files and update them if needed107- Run the relevant tests and verify they pass before proceeding108- If tests fail, fix the implementation until they pass109110**Step 5 — Commit:**111- If any code changes were made: `gt modify -c -m "[bot] 🐳 address review feedback on PR #{number}"`112- If no code changes, skip113114**Step 6 — Restack:**115After committing (or if no changes), run:116```bash117gt restack118```119This rebases all upstack branches onto the new commit. If merge conflicts arise, resolve them before continuing to the next PR.120121**Step 7 — Move to next PR** and repeat Steps 1–6.122123**Step 8 — Submit the entire stack after all PRs are addressed:**124```bash125gt submit --stack --no-interactive126```127128**Step 9 — Return structured report** for all PRs in the stack (same format as standalone report below).129130---131132#### Standalone PR Agent Workflow133134Dispatch one Task subagent per eligible standalone PR in parallel. Each agent receives:135- The PR number, repo, branch name, and local repo path136- The list of unresolved review thread comments137- The PR body/description138139**Step 1 — Create worktree:**140```bash141cd {localRepoPath}142git fetch origin {branchName}143git worktree add .worktrees/pr-{number} origin/{branchName}144```145Verify `.worktrees/` is gitignored with `git check-ignore .worktrees`. If not, add it to `.gitignore` first.146147**Step 2 — Gather context:**148- Extract Linear ticket ID from branch name (pattern: `[A-Z]+-\d+`)149- If found, use the Linear MCP `get_issue` tool to fetch issue details and `list_comments`150- Read the PR description for requirements and scope151152**Step 3 — Evaluate each unresolved comment:**1531. Read the file at the path referenced by the comment1542. Read surrounding code — callers (1 level up), types, related files in the same module1553. Understand the reviewer's intent: code fix request, question, style nit, or architectural concern1564. **Assess merit before acting.** For every comment (including concrete code-fix requests), ask:157 - Does this change improve correctness, readability, or safety?158 - Does it align with the Linear ticket's scope and intent?159 - Could it introduce regressions, over-engineering, or unnecessary churn?160 - Is there existing code context the reviewer may not have seen?1615. Categorize:162 - `code-fix` — reviewer's request is valid; implement it163 - `discussion` — architectural concern, question, or open-ended topic that needs a thoughtful reply164 - `acknowledged` — simple agreement ("good point, fixed")165 - `disagree` — Bubbles believes the ask is incorrect, out of scope, or would make things worse after careful evaluation1666. **If `code-fix`:** Implement the change, stage it1677. **If `disagree`:** Do NOT implement the change. Instead, draft a reply that:168 - Acknowledges the reviewer's perspective and the concern behind it ("Bubbles can see why this looks like X…")169 - Explains the reasoning for disagreeing — citing specific code context, ticket scope, or downstream effects170 - Offers an alternative if one exists, or explains why the current approach is preferable171 - Keeps the door open ("happy to chat more if Bubbles is missing something!")172 - Tone: warm, curious, never dismissive. Bubbles genuinely wants to understand the reviewer's angle, even when disagreeing.1738. **For all categories:** Draft a reply in the voice of **Bubbles** 🐳. Always prefix with `[bot] 🐳 Bubbles` and write in third person (e.g., "[bot] 🐳 Bubbles fixed the off-by-one error — `i` now starts at 0 instead of 1"). For code fixes, confirm what was changed. For discussion, form a position based on code understanding and Linear context. For disagree, follow the guidelines in step 7.174175**Step 4 — Update and run tests:**176- If any code changes were made, check for related test files and update them if needed177- Run the relevant tests and verify they pass before proceeding178- If tests fail, fix the implementation until they pass179180**Step 5 — Commit and push:**181- If any code changes were made: `git add -A && git commit -m "address review feedback on PR #{number}"` then `git push origin {branchName}`182- If no code changes, skip183184**Step 6 — Return structured report:**185```186PR #{number} — {title}187URL: {prUrl}188Commit: {sha or "no changes"}189190⚠️ Disagreements (review before posting):1911. [disagree] {file}:{line} — @{reviewer}192 Comment: {first 100 chars of body}...193 Bubbles' reasoning: {why Bubbles disagrees}194 Draft reply: [bot] 🐳 Bubbles {the drafted reply text}195196Comments:1971. [{category}] {file}:{line} — @{reviewer}198 Comment: {first 100 chars of body}...199 Action: {what was done}200 Draft reply: [bot] 🐳 Bubbles {the drafted reply text}2012022. [{category}] ...203```204205**Step 7 — Cleanup worktree:**206```bash207cd {localRepoPath}208git worktree remove .worktrees/pr-{number}209```210211### Phase 3: Summary and Approval212213After all agents (stack orchestrators and standalone agents) complete:2142151. **Present per-PR summary:**216 - PR title + URL217 - Comment breakdown: code-fix / discussion / acknowledged counts218 - Commit SHA if code was pushed219 - Each comment with reviewer, snippet, category, action, and draft reply2202212. **Reply approval flow:**222 - If `--auto-reply` is set, skip the presentation and post all drafted replies immediately (including disagree)223 - Otherwise, present `disagree` replies first, grouped separately with a ⚠️ header — these need the most attention224 - Then present all other drafted replies grouped by PR225 - Ask user to approve all, approve individually, edit, or skip226 - Post approved replies (or all replies if `--auto-reply`) via:227 ```bash228 gh api repos/{owner}/{repo}/pulls/{number}/comments -f body="{reply}" -F in_reply_to={commentDatabaseId}229 ```230 - After posting each reply, resolve the thread using the GraphQL thread node `id`:231 ```bash232 gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "{threadNodeId}"}) { thread { isResolved } } }'233 ```2342353. **Post summary comment on each PR:**236237 After posting replies for a PR, automatically post a top-level PR summary comment (no user confirmation needed). This gives reviewers a single place to see everything Bubbles did.238239 The comment must include:240 - The `## [bot] 🐳 Bubbles' Summary` heading is always visible241 - Everything else is wrapped in a `<details>` tag with `<summary>What Bubbles did</summary>` so it's collapsed by default242 - Stats: comment counts by category (code-fix / discussion / acknowledged / disagree)243 - Commit SHA if code was pushed, or "no code changes" if not244 - A list of each comment addressed with category, file:line, and a one-line summary of the action taken245 - If any `disagree` items exist, a separate subsection highlighting them with Bubbles' reasoning246247 ```bash248 gh api repos/{owner}/{repo}/issues/{number}/comments -f body="$(cat <<'EOF'249 ### [bot] 🐳 Bubbles' Summary250251 <details>252 <summary>**What Bubbles did**</summary>253254 | Stat | Count |255 |------|-------|256 | Code fixes | 2 |257 | Discussions | 1 |258 | Acknowledged | 0 |259 | ⚠️ Disagreements | 1 |260261 **Commit:** `abc1234` — address review feedback on PR #2580262263 ### Changes made264 - [code-fix] `src/path/File.tsx:42` — Added null check on `user.profile` per @reviewer's catch265 - [discussion] `src/path/Service.ts:88` — Bubbles explained why the retry logic uses exponential backoff here266 - [disagree] `src/path/OtherFile.tsx:15` — Bubbles respectfully pushed back on extracting this to a util (see thread for reasoning)267268 </details>269 EOF270 )"271 ```2722734. **Re-request reviews:**274275 After posting replies and the summary comment for each PR, re-request review from the humans who left the addressed comments. This notifies them that Bubbles has responded.276277 Collect the unique reviewer logins from the addressed comment threads (exclude the PR author and bots like `coderabbitai`, `graphite-app`, `github-actions`). Then:278 ```bash279 gh api repos/{owner}/{repo}/pulls/{number}/requested_reviewers \280 -f 'reviewers[]=reviewer1' -f 'reviewers[]=reviewer2'281 ```282283 If no human reviewers remain (e.g., all comments were from the PR author or bots), skip this step. Log which reviewers were re-requested in the final report.2842855. **Final report:**286 ```287 ## PR Comments Addressed288289 ### PR #2580 — PROJ-123 Refactor e2e tests290 - 4 comments: 2 code fixes (pushed abc1234), 1 discussion, ⚠️ 1 disagree291 - Replies: 4 posted292 - Summary comment: posted293294 ### Skipped295 - PR #2587 — no unresolved comments296 - my-frontend — repo not found locally297 ```298299## Important Notes300301- Filter comments by `isResolved: false` using the GraphQL API (REST API does not expose resolution status)302- Bot comments (coderabbitai, graphite-app, etc.) should be evaluated like human comments — they often contain valid code fixes303- Skip comments that are replies (non-root comments in a thread) — only evaluate the root comment of each thread304- When implementing code fixes, verify the suggestion makes sense in context before applying blindly305- The `in_reply_to` field for posting replies uses the REST API `databaseId`, not the GraphQL node `id`306- **Stack ordering matters:** Always address the trunk-most PR first. Changes to a lower PR affect all branches above it — `gt restack` propagates them upward307- **Do not post replies for stack PRs until after `gt submit --stack`** — submitting updates the remote branches; replies posted before that may reference stale diffs308- Stack orchestrators use `gt checkout` to switch branches directly in the working tree — do NOT use worktrees for stack PRs, as Graphite tracks branch relationships in the repo root309- **Automation clones** (`~/.claude/repos/{repoName}`) are the preferred working directory. Always `git fetch --all --prune` before starting work in an automation clone. These clones exist specifically so that the skill can run without interfering with the user's active working tree, uncommitted changes, or current branch