Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions crosslink/resources/container/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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..."
Expand Down
11 changes: 9 additions & 2 deletions crosslink/src/commands/kickoff/launch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,10 +433,17 @@ pub(super) fn init_worktree_agent(
crosslink_dir: &Path,
compact_name: &str,
) -> Result<String> {
// 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")?;

Expand Down
Loading