Skip to content

config: auto-infer tracker_remote from git remotes, drop the 'no tracker_remote configured' WARN noise #611

@maxine-at-forecast

Description

@maxine-at-forecast

Every crosslink invocation on a fresh project emits:

WARN no tracker_remote configured in /path/.crosslink/hook-config.json, defaulting to \"origin\"

…and then proceeds to use origin anyway. The WARN is redundant noise that appears on every invocation until someone explicitly writes tracker_remote: \"origin\" into hook-config.json. It accumulates fast across kickoff agents, hooks, and interactive shell use.

Worse: the WARN appears to trigger SOMETHING (an auto-mutation hook?) that writes tracker_remote: \"origin\" into hook-config.json programmatically. On my Mac it did this cleanly. On a Linux GPU box in the same project today, the same auto-write also serialized form-editor placeholder values into adjacent keys:

  • auto_steal_stale_locks: false → \"5\" (bool flipped to string with wrong value)
  • reminder_drift_threshold: 3 → \"0\" (int flipped to string)
  • Six bogus dot-notation duplicate keys like \"sentinel.default_agent.model\": \"(text)\" with literal (text) placeholders as values

So the auto-mutation that's silently "fixing" the missing tracker_remote is the same code path that corrupts other keys under some unknown trigger condition. (The user had not run crosslink workflow or crosslink init per history — the mutation was hook-driven, not interactive.) Worth tracking down regardless, but the cleanest fix is to make the WARN unnecessary in the first place so no hook needs to react to it.

Proposed default behavior

When hook-config.json lacks tracker_remote, infer it without warning:

  1. If there's exactly one git remote: use it. Most common case (origin).
  2. If there are multiple git remotes: prefer origin if present, else use the first lexicographic. Optionally emit a DEBUG-level log (not WARN) noting the choice for visibility.
  3. If there are zero git remotes: this is the only case where a real user-facing message is warranted — "no git remote found; configure one before sync" or similar.

This obviates the WARN entirely for the >99% of projects with an origin remote.

Optional: opportunity to override

For projects where origin is not the desired tracker_remote (e.g. multi-remote setups where someone wants upstream or a custom name), surface a one-shot interactive override:

  • On first invocation in a multi-remote project, prompt: Multiple git remotes detected (origin, upstream). Use 'origin' as tracker_remote? [Y/n/<custom>].
  • On non-interactive contexts (hooks, scripts, agents): just pick the inferred value silently and emit a DEBUG log.

The result of either path persists to hook-config.json exactly the way the current auto-mutation does — but at a deliberate, traceable point in time (CLI flow), not via a hook reacting to its own log output.

Implementation sketch

In whatever currently emits the WARN:

let tracker_remote = match hook_config.tracker_remote {
    Some(name) => name,
    None => {
        let remotes = list_git_remotes(&repo_path)?;
        match remotes.as_slice() {
            [single] => single.clone(),
            many if many.contains(&\"origin\".to_string()) => \"origin\".to_string(),
            many if !many.is_empty() => many[0].clone(),
            [] => bail!(\"no git remote configured; run `git remote add origin <url>` first\"),
        }
    }
};

Plus optionally: a one-shot persist of the chosen value back to hook-config.json only on first interactive run (gated behind isatty(stdin) and --no-persist or similar opt-out).

Cross-refs

Happy to send a PR if useful.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions