Sparse checkout excludes .story_kit/work/ from agent worktrees
Configures sparse checkout on new and existing worktrees to exclude the pipeline state directory. This prevents feature branches from containing .story_kit/work/ file moves that cause rename/delete merge conflicts when merging back to master. Also removes "pick up the story from .story_kit/work/" instruction from agent prompts since the story content is already in the prompt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -54,7 +54,7 @@ role = "Full-stack engineer. Implements features across all components."
|
||||
model = "sonnet-4.6"
|
||||
max_turns = 50
|
||||
max_budget_usd = 5.00
|
||||
prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. Pick up the story from .story_kit/work/ - move it to work/2_current/ if needed. Follow the SDTW process through implementation and verification (Steps 1-3). The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop. If the user asks to review your changes, tell them to run: cd \"{{worktree_path}}\" && git difftool {{base_branch}}...HEAD\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates (cargo clippy + tests) when your process exits and advance the pipeline based on the results."
|
||||
prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. The story details are in your prompt above. Follow the SDTW process through implementation and verification (Steps 1-3). The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop. If the user asks to review your changes, tell them to run: cd \"{{worktree_path}}\" && git difftool {{base_branch}}...HEAD\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates (cargo clippy + tests) when your process exits and advance the pipeline based on the results."
|
||||
system_prompt = "You are a full-stack engineer working autonomously in a git worktree. Follow the Story-Driven Test Workflow strictly. Run cargo clippy and biome checks before considering work complete. Commit all your work before finishing - use a descriptive commit message. Do not accept stories, move them to archived, or merge to master - a human will do that. Do not coordinate with other agents - focus on your assigned story. The server automatically runs acceptance gates when your process exits."
|
||||
|
||||
[[agent]]
|
||||
@@ -63,7 +63,7 @@ role = "Full-stack engineer. Implements features across all components."
|
||||
model = "sonnet-4.6"
|
||||
max_turns = 50
|
||||
max_budget_usd = 5.00
|
||||
prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. Pick up the story from .story_kit/work/ - move it to work/2_current/ if needed. Follow the SDTW process through implementation and verification (Steps 1-3). The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop. If the user asks to review your changes, tell them to run: cd \"{{worktree_path}}\" && git difftool {{base_branch}}...HEAD\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates (cargo clippy + tests) when your process exits and advance the pipeline based on the results."
|
||||
prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. The story details are in your prompt above. Follow the SDTW process through implementation and verification (Steps 1-3). The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop. If the user asks to review your changes, tell them to run: cd \"{{worktree_path}}\" && git difftool {{base_branch}}...HEAD\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates (cargo clippy + tests) when your process exits and advance the pipeline based on the results."
|
||||
system_prompt = "You are a full-stack engineer working autonomously in a git worktree. Follow the Story-Driven Test Workflow strictly. Run cargo clippy and biome checks before considering work complete. Commit all your work before finishing - use a descriptive commit message. Do not accept stories, move them to archived, or merge to master - a human will do that. Do not coordinate with other agents - focus on your assigned story. The server automatically runs acceptance gates when your process exits."
|
||||
|
||||
[[agent]]
|
||||
@@ -72,7 +72,7 @@ role = "Full-stack engineer. Implements features across all components."
|
||||
model = "sonnet-4.6"
|
||||
max_turns = 50
|
||||
max_budget_usd = 5.00
|
||||
prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. Pick up the story from .story_kit/work/ - move it to work/2_current/ if needed. Follow the SDTW process through implementation and verification (Steps 1-3). The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop. If the user asks to review your changes, tell them to run: cd \"{{worktree_path}}\" && git difftool {{base_branch}}...HEAD\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates (cargo clippy + tests) when your process exits and advance the pipeline based on the results."
|
||||
prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. The story details are in your prompt above. Follow the SDTW process through implementation and verification (Steps 1-3). The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop. If the user asks to review your changes, tell them to run: cd \"{{worktree_path}}\" && git difftool {{base_branch}}...HEAD\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates (cargo clippy + tests) when your process exits and advance the pipeline based on the results."
|
||||
system_prompt = "You are a full-stack engineer working autonomously in a git worktree. Follow the Story-Driven Test Workflow strictly. Run cargo clippy and biome checks before considering work complete. Commit all your work before finishing - use a descriptive commit message. Do not accept stories, move them to archived, or merge to master - a human will do that. Do not coordinate with other agents - focus on your assigned story. The server automatically runs acceptance gates when your process exits."
|
||||
|
||||
[[agent]]
|
||||
@@ -81,7 +81,7 @@ role = "Senior full-stack engineer for complex tasks. Implements features across
|
||||
model = "opus"
|
||||
max_turns = 80
|
||||
max_budget_usd = 20.00
|
||||
prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. Pick up the story from .story_kit/work/ - move it to work/2_current/ if needed. Follow the SDTW process through implementation and verification (Steps 1-3). The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop. If the user asks to review your changes, tell them to run: cd \"{{worktree_path}}\" && git difftool {{base_branch}}...HEAD\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates (cargo clippy + tests) when your process exits and advance the pipeline based on the results."
|
||||
prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. The story details are in your prompt above. Follow the SDTW process through implementation and verification (Steps 1-3). The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop. If the user asks to review your changes, tell them to run: cd \"{{worktree_path}}\" && git difftool {{base_branch}}...HEAD\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates (cargo clippy + tests) when your process exits and advance the pipeline based on the results."
|
||||
system_prompt = "You are a senior full-stack engineer working autonomously in a git worktree. You handle complex tasks requiring deep architectural understanding. Follow the Story-Driven Test Workflow strictly. Run cargo clippy and biome checks before considering work complete. Commit all your work before finishing - use a descriptive commit message. Do not accept stories, move them to archived, or merge to master - a human will do that. Do not coordinate with other agents - focus on your assigned story. The server automatically runs acceptance gates when your process exits."
|
||||
|
||||
[[agent]]
|
||||
|
||||
@@ -71,8 +71,12 @@ pub async fn create_worktree(
|
||||
let base_branch = detect_base_branch(project_root);
|
||||
let root = project_root.to_path_buf();
|
||||
|
||||
// Already exists — reuse
|
||||
// Already exists — reuse (ensure sparse checkout is configured)
|
||||
if wt_path.exists() {
|
||||
let wt_clone = wt_path.clone();
|
||||
tokio::task::spawn_blocking(move || configure_sparse_checkout(&wt_clone))
|
||||
.await
|
||||
.map_err(|e| format!("spawn_blocking: {e}"))??;
|
||||
write_mcp_json(&wt_path, port)?;
|
||||
run_setup_commands(&wt_path, config).await?;
|
||||
return Ok(WorktreeInfo {
|
||||
@@ -143,6 +147,62 @@ fn create_worktree_sync(
|
||||
return Err(format!("git worktree add failed: {stderr}"));
|
||||
}
|
||||
|
||||
// Enable sparse checkout to exclude pipeline files from the worktree.
|
||||
// This prevents .story_kit/work/ changes from ending up in feature branches,
|
||||
// which cause rename/delete merge conflicts when merging back to master.
|
||||
configure_sparse_checkout(wt_path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Configure sparse checkout on a worktree to exclude `.story_kit/work/`.
|
||||
///
|
||||
/// This prevents pipeline file moves (upcoming → current → qa → merge → archived)
|
||||
/// from being committed on feature branches, which avoids rename/delete merge
|
||||
/// conflicts when merging back to master.
|
||||
fn configure_sparse_checkout(wt_path: &Path) -> Result<(), String> {
|
||||
// Enable sparse checkout via git config (non-cone mode for pattern support)
|
||||
let output = Command::new("git")
|
||||
.args(["config", "core.sparseCheckout", "true"])
|
||||
.current_dir(wt_path)
|
||||
.output()
|
||||
.map_err(|e| format!("sparse-checkout config: {e}"))?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
return Err(format!("sparse-checkout config failed: {stderr}"));
|
||||
}
|
||||
|
||||
// Resolve the actual git dir (worktrees use a .git file pointing elsewhere)
|
||||
let git_dir_output = Command::new("git")
|
||||
.args(["rev-parse", "--git-dir"])
|
||||
.current_dir(wt_path)
|
||||
.output()
|
||||
.map_err(|e| format!("git rev-parse --git-dir: {e}"))?;
|
||||
|
||||
let git_dir = PathBuf::from(
|
||||
String::from_utf8_lossy(&git_dir_output.stdout).trim().to_string(),
|
||||
);
|
||||
|
||||
// Write sparse-checkout patterns: include everything, exclude .story_kit/work/
|
||||
let info_dir = git_dir.join("info");
|
||||
std::fs::create_dir_all(&info_dir)
|
||||
.map_err(|e| format!("Create sparse-checkout dir: {e}"))?;
|
||||
std::fs::write(info_dir.join("sparse-checkout"), "/*\n!.story_kit/work/\n")
|
||||
.map_err(|e| format!("Write sparse-checkout: {e}"))?;
|
||||
|
||||
// Re-read the working tree to apply sparse checkout rules
|
||||
let output = Command::new("git")
|
||||
.args(["read-tree", "-mu", "HEAD"])
|
||||
.current_dir(wt_path)
|
||||
.output()
|
||||
.map_err(|e| format!("git read-tree: {e}"))?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
return Err(format!("git read-tree failed: {stderr}"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -380,4 +440,40 @@ mod tests {
|
||||
);
|
||||
assert!(wt_path.exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sparse_checkout_excludes_story_kit_work() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let project_root = tmp.path().join("my-project");
|
||||
fs::create_dir_all(&project_root).unwrap();
|
||||
init_git_repo(&project_root);
|
||||
|
||||
// Create a tracked file under .story_kit/work/ on the initial branch
|
||||
let work_dir = project_root.join(".story_kit").join("work");
|
||||
fs::create_dir_all(&work_dir).unwrap();
|
||||
fs::write(work_dir.join("test_story.md"), "# Test").unwrap();
|
||||
Command::new("git")
|
||||
.args(["add", "."])
|
||||
.current_dir(&project_root)
|
||||
.output()
|
||||
.unwrap();
|
||||
Command::new("git")
|
||||
.args(["commit", "-m", "add work file"])
|
||||
.current_dir(&project_root)
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let wt_path = tmp.path().join("my-worktree");
|
||||
let branch = "feature/test-sparse";
|
||||
create_worktree_sync(&project_root, &wt_path, branch).unwrap();
|
||||
|
||||
// .story_kit/work/ should not exist in the worktree
|
||||
assert!(
|
||||
!wt_path.join(".story_kit").join("work").exists(),
|
||||
".story_kit/work/ should be excluded by sparse checkout"
|
||||
);
|
||||
|
||||
// Other files should still exist
|
||||
assert!(wt_path.join(".git").exists());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user