Files
claude-skills/.wiki/concepts/pulling-before-work-design.md

9.0 KiB
Raw Blame History

title, type, updated
title type updated
pulling-before-work — pull origin once at session start concept 2026-05-01

pulling-before-work — pull origin once at session start

2026-05-01.

Problem

When the user opens Claude in a project that has a git remote, work often starts against a stale local branch. Edits land on top of what origin had hours or days ago, and the divergence shows up only at push time — sometimes after a non-trivial chunk of work has been built on the wrong base. The user explicitly asked for a guardrail: "any work in a git project starts with a pull from the remote." Manual git pull discipline isn't reliable across machines and sessions.

The repo already has the right shape for this — policy skills (using-wiki, using-tasks, using-projects-meta, active-platform) activated by single-line triggers in each project's CLAUDE.md. The fix slots into that pattern.

Decision

Two artefacts:

  1. New policy skill pulling-before-work (under skills/pulling-before-work/SKILL.md) — owns the pull logic, activates from the CLAUDE.md trigger and from in-chat re-sync phrases.
  2. project-bootstrap v1.4.0 — adds the line pull remote before work to assets/CLAUDE.md.template, before the platform line. The existing idempotent merge in Step 5 (introduced in v1.3.0) carries the new line into existing projects on upgrade with one confirmation prompt.

This repo (claude-skills) gets the trigger added to its own CLAUDE.md as dogfood.

Skill behaviour

Activation (description field)

Trigger conditions:

  • CLAUDE.md contains the line pull remote before work — activates at session start, runs one pull cycle.
  • User says sync / resync / pull / обнови репо / git pull please / close variants — runs the pull cycle again on demand.

Stays silent (no activation, no chat output) when the cwd is not a git repo. With no origin remote or no upstream tracking, prints one informational line and exits — those are conditions the user might want to know about, not pure no-ops.

One pull cycle

1. Inside a git work-tree?           (git rev-parse --is-inside-work-tree)
   no → exit silently, no chat output.

2. Has 'origin' remote?              (git remote get-url origin)
   no → print one line "no remote, skip", exit.

3. Working tree dirty?               (git status --porcelain — non-empty)
   yes → print "working tree dirty — skipping pull. commit/stash, потом скажи 'sync'."
         exit.

4. Detached HEAD?                    (git symbolic-ref -q HEAD — empty)
   yes → print "detached HEAD — skip", exit.

5. Current branch has upstream?      (git rev-parse --abbrev-ref --symbolic-full-name @{u})
   no → print "no upstream tracking for <branch> — skip", exit.

6. git pull --ff-only                 (no args — uses configured upstream)
   classify result:
     - "Already up to date"          → "✅ already up to date with <upstream>"
     - fast-forward, N commits       → "✅ pulled N commits from <upstream>"
     - non-ff / diverged             → "⚠️ diverged from <upstream> — resolve
                                         manually (git pull --rebase or merge);
                                         skill never auto-merges/rebases."

Out of scope

  • No commit, no stash, no push.
  • No submodule recursion.
  • No non-origin remotes.
  • No detached-HEAD pulls.
  • Not invoked before each commit or each tool call — only at session start and on explicit re-sync.

Why mode 3 (start + on-demand) and not "before every commit"

User chose mode 3 explicitly during brainstorm. Pulling before every commit creates churn (a 30-minute coding session can have 5+ commits — pulling each time is noise) and shifts conflict surface late. One pull at start covers the common case (work begins on stale base); the explicit re-sync trigger handles long sessions where a teammate pushed mid-flight.

Why skip-on-dirty (option 1) and not stash-pop or prompt

Stash + pop can fail mid-pop and leave the user with a half-applied stash to resolve — exactly the kind of friction this skill is supposed to remove. Prompting at every dirty start is noise when "I've got dirty edits" is the steady state during active work. Skip-with-warning is the cheapest correct answer: it never destroys work, it tells the user what to do next, and the next sync after commit/stash gets them current.

Why --ff-only and not auto-merge/rebase

Auto-merge writes a merge commit the user didn't ask for; auto-rebase rewrites local history silently. Both are violations of "skill never makes the user lose track of where they are." --ff-only either succeeds cleanly or refuses with a message — the user retains the steering wheel for non-trivial cases.

Why explicit upstream check (step 5)

git pull --ff-only without args relies on branch.<name>.merge being set. On a branch that was created locally and never pushed (or git switch -c from a remote-tracking branch with --no-track), there is no upstream — git pull errors out. The explicit check turns that error into a clean one-line skip. Bonus: the upstream name is exactly what we want in success/diverged messages, so we capture it once and reuse.

Bootstrap integration

Template change

assets/CLAUDE.md.template gains one line, inserted before the platform line:

 talk like a caveman
 use superpowers
 use project wiki
 use task management system
 check across all projects
+pull remote before work
 we're on Windows

Position rationale: the platform line stays last because the bootstrap merge logic special-cases it (substitution on non-Windows hosts). Other trigger lines are unordered logically; placing the new one just before the platform line keeps the platform line as the visual end-anchor.

Step 5 upgrade path

Already idempotent (per bootstrap-claude-md-merge.md). The substring + append-only diff treats pull remote before work like any other trigger line: existing projects on project-bootstrap v1.4.0+ see one diff entry, one confirmation, one appended line. Re-runs after that are no-ops.

Version bump

project-bootstrap: 1.3.0 → 1.4.0. New user-visible behaviour (a new canonical trigger landing in projects) = minor bump per the versioning convention in skill-versioning.md.

pulling-before-work: starts at 1.0.0.

Files

skills/pulling-before-work/
  SKILL.md                          NEW — frontmatter + body, ~80120 lines, no assets

skills/project-bootstrap/
  SKILL.md                          version 1.3.0 → 1.4.0; mention new trigger in
                                    Step 5 commentary
  assets/CLAUDE.md.template         + "pull remote before work"

.wiki/concepts/
  pulling-before-work-design.md     NEW — this file

CLAUDE.md                           + "pull remote before work" — dogfood the trigger
                                    in the claude-skills repo itself

Validation

No unit tests — skill is markdown + shell instructions. Validation = manual smoke run on representative scenarios:

  1. Clean repo with remote, current branch tracks origin → ✅ already up to date or ✅ pulled N commits.
  2. git init-only, no remote → one-line no remote, skip.
  3. Non-git folder → silent, no output.
  4. Dirty tree (echo x > new.txt) → working tree dirty — skipping pull.
  5. Detached HEAD (git checkout <sha>) → detached HEAD — skip.
  6. Diverged branch (local commit + remote commit on same branch) → diverged warning, no auto-merge.
  7. Re-sync trigger (sync mid-session) → cycle repeats.
  8. Bootstrap upgrade on this repo → diff prompts to append pull remote before work; confirm → appended.
  9. Branch with no upstream (git switch -c local-only) → no upstream tracking for local-only — skip.

Scenarios 1, 2, 4, 8 are the load-bearing ones. The rest are edge-case assurance.

Composition with existing skills

  • active-platform — pull command (git pull --ff-only origin <branch>) is identical across Windows / Linux / macOS, so no platform branching needed inside the skill body. The active-platform contract still applies for any commands the skill prints in chat (e.g. recovery hints) — but those are git-only and platform-agnostic.
  • using-wiki / using-tasks — independent. This skill never reads or writes .wiki/ or .tasks/. No ordering constraint with them.
  • superpowers:using-superpowers — skill discovery loads pulling-before-work from the trigger line just like other policy skills. No special handling.

Pattern: lightweight policy skill from a single CLAUDE.md trigger

Same shape as active-platform: a single-line trigger in CLAUDE.md activates a small, focused skill that runs deterministic shell logic and returns to silence. Reusable for future "do this thing once at session start" guardrails — e.g. check pre-commit hooks installed, warn if main branch behind upstream. Bootstrap-template-line + tiny-policy-skill is the cheapest way to make a habit reliable across machines and sessions.