Conversation
Live dogfooding of the item #15 quota/supervisor feature surfaced two bugs in the pre-existing autonomous dispatch pipeline, both fixed here: 1. `agentflare work`'s claim step resolves its own identity via `claims::owner_id()`, which falls back to agent-detector's parent-process/ env sniffing when AGENTFLARE_AGENT isn't set. Spawned headless by the supervisor (no parent agent process, no session env), that sniffing finds nothing and falls back further to owner "cli" -- which then loses to `item::claim`'s BlockedByAssignee check against whatever agent the item was actually assigned to. Fix: `run_work` now sets AGENTFLARE_AGENT from its own explicit `--agent` flag before claiming, since that flag is already a stronger, unambiguous statement of identity than any sniffing -- true whether a human types it directly or the supervisor dispatches it, so both stay in sync through the one shared code path. 2. Item-worktree creation resolved its target directory from `git rev-parse --show-toplevel` on the process's cwd, which is a perfectly valid answer from *inside* an existing linked worktree -- so a job spawned from inside one item worktree nested a fresh worktree inside it instead of alongside it in the shared `.worktrees/` location. Fix: `worktree_repo_root` now detects a linked-worktree cwd and redirects to the main checkout (derived from `--git-common-dir`, which always points at the shared `.git` regardless of which worktree it's read from). Both confirmed live against this repo's own running daemon and real backend.db: reproduced the original failures, applied the fix, restarted the daemon from the exact same (previously bug-triggering) linked-worktree cwd, and confirmed the claim succeeds and the worktree lands in the correct shared location.
📝 WalkthroughWalkthroughThe change adds canonical main-worktree resolution, redirects linked-worktree operations to that checkout, and sets the selected explicit agent identity before work claims begin. ChangesWorktree and agent flow
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/flare-git-core/src/branch.rs`:
- Around line 190-193: Update main_worktree_root to avoid deriving the checkout
root from --git-common-dir when the repository uses an external Git directory;
instead obtain the canonical main-worktree root explicitly or return None to
skip redirection for that case. Add a regression test covering git init
--separate-git-dir with a linked worktree, verifying worktree placement is not
redirected to the external Git directory.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2ab7a4aa-b964-4172-8130-4ceadb954f7c
📒 Files selected for processing (3)
crates/flare-git-core/src/branch.rssrc/cli/work.rssrc/mcp_server.rs
| pub fn main_worktree_root(repo_root: &Path) -> Option<PathBuf> { | ||
| let common_dir = run_in_opt(repo_root, &["rev-parse", "--git-common-dir"])?; | ||
| repo_root.join(common_dir).parent().map(Path::to_path_buf) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
base="$(mktemp -d)"
trap 'rm -rf "$base"' EXIT
main="$base/main"
git_dir="$base/git-data"
linked="$base/linked"
git init --initial-branch=main --separate-git-dir="$git_dir" "$main"
git -C "$main" config user.email test@example.com
git -C "$main" config user.name test
git -C "$main" commit --allow-empty -m initial
git -C "$main" worktree add -b linked-branch "$linked"
printf 'common dir: '
git -C "$linked" rev-parse --git-common-dir
printf 'primary worktree: '
git -C "$linked" worktree list --porcelain | sed -n '1s/^worktree //p'Repository: getappz/agentflare
Length of output: 426
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(branch\.rs|mcp_server\.rs)$|branch|worktree' | head -80
printf '%s\n' '--- branch symbols and callers ---'
rg -n -C 8 'main_worktree_root|worktree_repo_root|git-common-dir|worktree list' crates src tests 2>/dev/null | head -240
printf '%s\n' '--- branch outline/size ---'
if command -v ast-grep >/dev/null 2>&1; then
ast-grep outline crates/flare-git-core/src/branch.rs
fi
wc -l crates/flare-git-core/src/branch.rs 2>/dev/null || true
printf '%s\n' '--- complete separate-git-dir reproduction ---'
base="$(mktemp -d)"
trap 'rm -rf "$base"' EXIT
main="$base/main"
git_dir="$base/git-data"
linked="$base/linked"
git --version
git init --initial-branch=main --separate-git-dir="$git_dir" "$main" >/dev/null
git -C "$main" config user.email test@example.com
git -C "$main" config user.name test
git -C "$main" commit --allow-empty -m initial >/dev/null
git -C "$main" worktree add -b linked-branch "$linked" >/dev/null
printf 'main=%s\n' "$main"
printf 'git_dir=%s\n' "$git_dir"
printf 'linked=%s\n' "$linked"
printf '%s\n' 'main .git:'
cat "$main/.git"
printf '%s\n' 'linked .git:'
cat "$linked/.git"
printf '%s\n' 'linked rev-parse --git-dir:'
git -C "$linked" rev-parse --git-dir
printf '%s\n' 'linked rev-parse --git-common-dir:'
git -C "$linked" rev-parse --git-common-dir
printf '%s\n' 'linked worktree list --porcelain:'
git -C "$linked" worktree list --porcelain
printf '%s\n' 'linked worktree list:'
git -C "$linked" worktree list
printf '%s\n' 'metadata files:'
find "$git_dir" -maxdepth 3 -type f -print | sortRepository: getappz/agentflare
Length of output: 22949
🏁 Script executed:
#!/bin/bash
set -euo pipefail
base="$(mktemp -d)"
trap 'rm -rf "$base"' EXIT
main="$base/main"
git_dir="$base/git-data"
linked="$base/linked"
git init --initial-branch=main --separate-git-dir="$git_dir" "$main" >/dev/null
git -C "$main" config user.email test@example.com
git -C "$main" config user.name test
git -C "$main" commit --allow-empty -m initial >/dev/null
git -C "$main" worktree add -b linked-branch "$linked" >/dev/null
printf '%s\n' '--- config ---'
git -C "$main" config --local --list --show-origin
printf '%s\n' 'core.worktree values:'
for dir in "$main" "$linked"; do
printf 'repo=%s\n' "$dir"
git -C "$dir" config --local --get core.worktree || printf '%s\n' '<unset>'
done
printf '%s\n' '--- rev-parse values ---'
for dir in "$main" "$linked"; do
printf 'repo=%s\n' "$dir"
for arg in --show-toplevel --git-dir --git-common-dir --absolute-git-dir; do
printf '%s: ' "$arg"
git -C "$dir" rev-parse --path-format=absolute "$arg" 2>&1 || true
done
done
printf '%s\n' '--- worktree metadata ---'
printf 'common config core.worktree: '
git --git-dir="$git_dir" config --get core.worktree || printf '%s\n' '<unset>'
printf 'main .git file: '
cat "$main/.git"
printf 'linked commondir: '
cat "$git_dir/worktrees/linked/commondir"
printf 'linked gitdir file: '
cat "$git_dir/worktrees/linked/gitdir"
printf '%s\n' '--- environment-sensitive candidates ---'
git -C "$linked" rev-parse --git-path worktrees
git -C "$linked" rev-parse --git-path commondir
git -C "$linked" rev-parse --git-path configRepository: getappz/agentflare
Length of output: 1544
Handle repositories with an external Git directory before redirecting worktree placement.
--git-common-dir returns the external Git directory for git init --separate-git-dir, so main_worktree_root returns its parent instead of the main checkout. git worktree list --porcelain is not a sufficient replacement because Git reports that external directory as the first worktree in this setup. Use an explicit canonical-root source or skip the redirect for this case. Add a regression test with a separate Git directory and linked worktree.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/flare-git-core/src/branch.rs` around lines 190 - 193, Update
main_worktree_root to avoid deriving the checkout root from --git-common-dir
when the repository uses an external Git directory; instead obtain the canonical
main-worktree root explicitly or return None to skip redirection for that case.
Add a regression test covering git init --separate-git-dir with a linked
worktree, verifying worktree placement is not redirected to the external Git
directory.
Summary
agentflare worknow setsAGENTFLARE_AGENTfrom its own explicit--agentflag before claiming, so a job spawned headless by the supervisor (no parent agent process to sniff) resolves its own claim identity to the agent it was actually dispatched as, instead of falling back tocliand losing toitem::claim's BlockedByAssignee check against its own assignee.worktree_repo_rootnow detects when the process's cwd is itself a linked worktree and redirects to the main checkout (via--git-common-dir), so a job spawned from inside an existing item worktree creates its new worktree alongside it in the shared.worktrees/location instead of nesting inside it.Both found live while dogfooding the item #15 quota/supervisor feature (PR #392) against this repo's own running daemon and real backend.db -- reproduced, fixed, and re-verified live (restarted the daemon from the exact bug-triggering cwd and confirmed both the claim and the worktree path are now correct).
Test plan
cargo test --workspace(targeted: work/supervisor/quota/worktree/branch/main_worktree) -- all passcargo clippy --all-targets --all-features -- -D warnings-- cleanitem held by ? (0s) -- cannot claim; after, claim succeeds and a real headless claude-code turn starts.worktrees/task/16; new item worktree correctly landed at the top-level.worktrees/task/13, not nestedSummary by CodeRabbit
New Features
Bug Fixes