fix(kickoff): stop --force-reinitting hook-config.json on every worktree + container start#591
Merged
dollspace-gay merged 1 commit intoMay 11, 2026
Conversation
…ree + container start (#732, GH#583) Both the host-side `init_worktree_agent` (in `kickoff/launch.rs`) and the container entrypoint (`entrypoint.sh`) ran `crosslink init --force` on every kickoff, unconditionally re-templating `.crosslink/hook-config.json` from the embedded default. That left a ~50-line diff in every agent-produced worktree -- top-level keys moving into `agent_overrides`, new `agent_lint_commands` / `agent_test_commands` fields appearing -- which leaked into every kickoff PR and required reviewers to remember to `git restore .crosslink/hook-config.json` before merging. ## Fix Drop `--force` from both call sites. Plain `crosslink init` short-circuits at `commands/init/mod.rs:751` when `.crosslink/` and `.claude/` already exist (the common case for any worktree checked out from a branch that committed both). That makes the init a deliberate no-op on existing state instead of an unconditional re-template. - `crosslink/resources/container/entrypoint.sh` -- container's init call. - `crosslink/src/commands/kickoff/launch.rs::init_worktree_agent` -- host-side init that runs against the freshly-created worktree before the container starts. The user-facing symptom required both fixes: the host call re-templates first, then the container call re-templates again, so dropping `--force` from only one wouldn't make the diff go away. Kept `--skip-signing` and `--defaults` on the host call because they suppress the TUI walkthrough on the rare path where init actually has work to do (`.crosslink/` or `.claude/` missing). When users genuinely want to refresh hooks they still run `crosslink init --force` manually -- the existing documented path. ## Verification - `cargo fmt --check` clean - `cargo clippy --lib --bin crosslink -- -D warnings` clean - `cargo test --bin crosslink kickoff::` 149/149 pass - `bash -n entrypoint.sh` clean Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes GH#583. The container entrypoint at
crosslink/resources/container/entrypoint.shrancrosslink init --forceon every container start, which unconditionally re-templated.crosslink/hook-config.jsonfrom the embedded default. That left a ~50-line diff in every agent-produced worktree (top-level keys moving intoagent_overrides, newagent_lint_commands/agent_test_commandsfields appearing) which leaked into every kickoff PR and required reviewers to remember togit restore .crosslink/hook-config.jsonbefore merging.Scope
Two call sites — the user's issue only named the container entrypoint, but the same bug pattern exists on the host side and the symptom required both to be fixed:
crosslink/resources/container/entrypoint.sh:131— container's init call.crosslink/src/commands/kickoff/launch.rs::init_worktree_agent— host-side init that runs against the freshly-created worktree before the container starts. The host pass re-templates first, then the container pass re-templates again; dropping--forcefrom only one wouldn't make the diff go away.Fix
Drop
--forcefrom both call sites. Plaincrosslink initshort-circuits atcommands/init/mod.rs:751when.crosslink/and.claude/already exist (the common case for any worktree checked out from a branch that committed both), making the init a deliberate no-op on existing state instead of an unconditional re-template.Kept
--skip-signingand--defaultson the host call because they suppress the TUI walkthrough on the rare path where init genuinely has work to do (one of the dirs missing). Users who want to refresh hooks deliberately still runcrosslink init --forcemanually — the existing documented path.Test plan
cargo fmt --check— cleancargo clippy --lib --bin crosslink -- -D warnings— cleancargo test --bin crosslink kickoff::— 149/149 passbash -n entrypoint.sh— cleancrosslink kickoff run --container docker ...against a repo that committed.crosslink/+.claude/, confirm the agent's firstgit diffno longer showshook-config.jsonmodified.crosslink/deliberately gitignored, confirm init still creates it (plaininitdoes the full setup when the dir is absent)🤖 Generated with Claude Code