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"
|
model = "sonnet-4.6"
|
||||||
max_turns = 50
|
max_turns = 50
|
||||||
max_budget_usd = 5.00
|
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."
|
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]]
|
[[agent]]
|
||||||
@@ -63,7 +63,7 @@ role = "Full-stack engineer. Implements features across all components."
|
|||||||
model = "sonnet-4.6"
|
model = "sonnet-4.6"
|
||||||
max_turns = 50
|
max_turns = 50
|
||||||
max_budget_usd = 5.00
|
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."
|
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]]
|
[[agent]]
|
||||||
@@ -72,7 +72,7 @@ role = "Full-stack engineer. Implements features across all components."
|
|||||||
model = "sonnet-4.6"
|
model = "sonnet-4.6"
|
||||||
max_turns = 50
|
max_turns = 50
|
||||||
max_budget_usd = 5.00
|
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."
|
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]]
|
[[agent]]
|
||||||
@@ -81,7 +81,7 @@ role = "Senior full-stack engineer for complex tasks. Implements features across
|
|||||||
model = "opus"
|
model = "opus"
|
||||||
max_turns = 80
|
max_turns = 80
|
||||||
max_budget_usd = 20.00
|
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."
|
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]]
|
[[agent]]
|
||||||
|
|||||||
@@ -71,8 +71,12 @@ pub async fn create_worktree(
|
|||||||
let base_branch = detect_base_branch(project_root);
|
let base_branch = detect_base_branch(project_root);
|
||||||
let root = project_root.to_path_buf();
|
let root = project_root.to_path_buf();
|
||||||
|
|
||||||
// Already exists — reuse
|
// Already exists — reuse (ensure sparse checkout is configured)
|
||||||
if wt_path.exists() {
|
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)?;
|
write_mcp_json(&wt_path, port)?;
|
||||||
run_setup_commands(&wt_path, config).await?;
|
run_setup_commands(&wt_path, config).await?;
|
||||||
return Ok(WorktreeInfo {
|
return Ok(WorktreeInfo {
|
||||||
@@ -143,6 +147,62 @@ fn create_worktree_sync(
|
|||||||
return Err(format!("git worktree add failed: {stderr}"));
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,4 +440,40 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert!(wt_path.exists());
|
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