Skip to content

Proposal: SessionStart "git freshness" hook — warn when worktree is behind upstream #105

Description

@Kyarha

Problem

jig sessions can start on a worktree/branch that has silently drifted behind
its upstream. When that happens, the agent forms its whole premise — "what's
built", spec/slice STATUS, file contents — from stale state, before any guard
runs. In practice this bites (real incident: a local origin/main was already
18 commits ahead of the working branch at session start).

Gap in existing hooks

jig already has freshness-adjacent signals, but none covers git branch
staleness at time-zero:

  • jig-context-check.shcontext freshness (fill %, MCP count)
  • jig-project-orient.sh → orientation headline from jig artifacts
  • spec-workflow last_verifiedspec/ADR staleness

transition and slice-land do a fresh fetch at command time — but that's
later, and only if you reach those commands. There's no earlier tripwire that
fires before the agent trusts repo state.

Proposed shape

A SessionStart hook that is fetch-free (compares HEAD against the
already-known remote ref — instant, no network, can't hang), silent when
up-to-date or not in a repo, and never blocks (always exits 0). Same
soft/never-block philosophy as jig-context-check.sh.

Working prototype (running in my global config today, fired the 18-behind warning):

upstream = @{upstream}, else fall back to origin/main | origin/master
behind   = git rev-list --count HEAD..$upstream
if behind > 0: print a ⚠️ warning pointing at `git fetch && git log HEAD..$upstream --oneline`

Full script attached below.

Open questions for maintainer

  1. In scope for jig? It's pointedly relevant to the merge-main→v2 branch
    discipline, where branches silently drift.
  2. Warn-only, or nudge toward an action? (e.g. suggest a fetch/merge, or
    just inform.)
  3. Opt-out env var — assume JIG_GIT_FRESHNESS=0 to match the other hooks?
  4. Threshold — warn at any N>0 behind, or only past a floor?
  5. Fetch-free vs. optional fresh fetch — keep it strictly local (my bias:
    yes, so it can never hang a session), or offer an opt-in fetch mode?

If the shape's agreeable I'll open a PR with the hook + a test
(test_jig_git_freshness.py) matching the existing hook-test pattern.

Prototype script
#!/usr/bin/env bash
# SessionStart hook — warn if this git worktree/branch is behind its upstream,
# BEFORE any file is read or premise formed. Fetch-free, silent when fresh,
# never blocks.
set +e
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
upstream=$(git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null)
if [ -z "$upstream" ]; then
  for cand in origin/main origin/master; do
    if git rev-parse --verify -q "$cand" >/dev/null 2>&1; then upstream="$cand"; break; fi
  done
fi
[ -z "$upstream" ] && exit 0
behind=$(git rev-list --count "HEAD..$upstream" 2>/dev/null)
[ -z "$behind" ] && exit 0
if [ "$behind" -gt 0 ]; then
  echo "⚠️  GIT FRESHNESS: HEAD is $behind commit(s) behind $upstream."
  echo "   Verify against $upstream before trusting repo state:  git fetch && git log HEAD..$upstream --oneline"
fi
exit 0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions