Skip to content

fix(kickoff): stop --force-reinitting hook-config.json on every worktree + container start#591

Merged
dollspace-gay merged 1 commit into
developfrom
fix/583-entrypoint-init-force-rewrites-hook-config
May 11, 2026
Merged

fix(kickoff): stop --force-reinitting hook-config.json on every worktree + container start#591
dollspace-gay merged 1 commit into
developfrom
fix/583-entrypoint-init-force-rewrites-hook-config

Conversation

@dollspace-gay
Copy link
Copy Markdown

@dollspace-gay dollspace-gay commented May 11, 2026

Summary

Closes GH#583. The container entrypoint at crosslink/resources/container/entrypoint.sh ran crosslink init --force on every container start, which unconditionally re-templated .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.

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 --force from only one wouldn't make the diff go away.

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), making the init a deliberate no-op on existing state instead of an unconditional re-template.

Kept --skip-signing and --defaults on 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 run crosslink init --force manually — the existing documented path.

Test plan

  • 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
  • Manual: run crosslink kickoff run --container docker ... against a repo that committed .crosslink/ + .claude/, confirm the agent's first git diff no longer shows hook-config.json modified
  • Manual: same against a repo with .crosslink/ deliberately gitignored, confirm init still creates it (plain init does the full setup when the dir is absent)

🤖 Generated with Claude Code

…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>
@dollspace-gay dollspace-gay self-assigned this May 11, 2026
@dollspace-gay dollspace-gay merged commit f99595b into develop May 11, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kickoff entrypoint: crosslink init --force rewrites .crosslink/hook-config.json on every container start

1 participant