diff --git a/crosslink/resources/container/entrypoint.sh b/crosslink/resources/container/entrypoint.sh index f8cf43f4..888b050a 100644 --- a/crosslink/resources/container/entrypoint.sh +++ b/crosslink/resources/container/entrypoint.sh @@ -125,10 +125,15 @@ fi # --- Crosslink init --- # Set up hooks, skills, and policy in the workspace so container agents are -# bound by the same rules as host agents. +# bound by the same rules as host agents. Plain `init` (no --force) is +# idempotent: it short-circuits when `.crosslink/` and `.claude/` already +# exist in the worktree (the common case, since both are git-committed and +# arrive with the worktree checkout). This is what prevents the entrypoint +# from re-templating `hook-config.json` on every container start and leaking +# spurious diffs into agent PRs. See GH#583. if [ -n "$WORKSPACE" ] && command -v crosslink &>/dev/null; then echo "[crosslink-entrypoint] Initializing crosslink hooks in workspace..." - gosu agent bash -c "cd '$WORKSPACE' && crosslink init --force" 2>&1 || true + gosu agent bash -c "cd '$WORKSPACE' && crosslink init" 2>&1 || true fi echo "[crosslink-entrypoint] Setup complete. Running command as agent..." diff --git a/crosslink/src/commands/kickoff/launch.rs b/crosslink/src/commands/kickoff/launch.rs index e175dc1d..19d1244c 100644 --- a/crosslink/src/commands/kickoff/launch.rs +++ b/crosslink/src/commands/kickoff/launch.rs @@ -433,10 +433,17 @@ pub(super) fn init_worktree_agent( crosslink_dir: &Path, compact_name: &str, ) -> Result { - // Run crosslink init --force in the worktree + // Run `crosslink init` in the worktree. Plain init (no --force) is + // idempotent: it short-circuits when `.crosslink/` and `.claude/` already + // exist, which is the common case for a worktree freshly checked out + // from a branch that has both committed. We keep `--skip-signing` and + // `--defaults` to suppress the TUI walkthrough on the rare path where + // init actually has work to do. Dropping `--force` here prevents the + // worktree's `hook-config.json` from being re-templated and leaking a + // spurious diff into every agent-produced PR. See GH#583. let output = Command::new("crosslink") .current_dir(worktree_dir) - .args(["init", "--force", "--skip-signing", "--defaults"]) + .args(["init", "--skip-signing", "--defaults"]) .output() .context("Failed to run crosslink init in worktree")?;