Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 67 additions & 7 deletions .agents/skills/git-branch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,52 @@ When an issue ID is provided, use one `gh issue view <issueID> --json
title,body,number` call for naming context. If it fails, continue only when the
request is enough and report that the issue was not verified.

## Base

This section is the single source of truth for base selection. Other skills
(`git-worktree`) reference it and copy the snippet below instead of restating a
second rule set.

Resolve the base in exactly this order, validating every candidate with a ref
check and falling through to the next one when it does not resolve:

1. the repository's documented base — the default branch the repository itself
states (for example in `CONTRIBUTING`, `README`, or `AGENTS`); skip this step
when nothing is documented;
2. `origin/HEAD` — the remote's default branch;
3. the branch the user explicitly asked for (`--base <branch>` or a branch named
in the request);
4. `main` as the last resort.

Never continue with a base that does not resolve. If no candidate resolves, list
the available remote branches, ask the user to pass `--base <branch>`, and exit
non-zero — do not silently fall back to a `main` that does not exist.

```bash
ref_exists() {
git rev-parse --verify --quiet "origin/$1" >/dev/null 2>&1 \
|| git rev-parse --verify --quiet "refs/heads/$1" >/dev/null 2>&1
}

resolve_base() {
local documented="$1" user_base="$2" origin_head cand
# 1) documented base
if [ -n "$documented" ] && ref_exists "$documented"; then echo "$documented"; return 0; fi
# 2) origin/HEAD
origin_head=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's#^origin/##')
[ -n "$origin_head" ] || origin_head=$(git remote show origin 2>/dev/null | sed -n 's/^ *HEAD branch: *//p')
# 3) user choice 4) main fallback
for cand in "$origin_head" "$user_base" main; do
if [ -n "$cand" ] && ref_exists "$cand"; then echo "$cand"; return 0; fi
done
return 1
}
```

The order is deliberate: `origin/HEAD` is checked before the user choice, so an
explicit `--base` does not override a resolvable `origin/HEAD`. Surface that
conflict to the user instead of silently reordering the rule.

## Create

Check the current worktree, branch, and target branch first. Stop if the
Expand All @@ -31,17 +77,31 @@ branch is unsafe. Validate the name with:
git check-ref-format --branch <branch-name>
```

Use the repository's documented base, otherwise `main`. In the same repository
prefer `origin/<base>` over `upstream/<base>`; use `upstream` only for a fork or
explicit guidance. Fetch or compare freshness only when it can change the
choice of base. If creating from a stale local base, confirm before updating or
use a freshly fetched remote base and report that the local base was unchanged.
Resolve the base with the snippet from the Base section, then prefer the remote
ref and use the local ref only when the remote one is missing:

```bash
git switch -c <branch-name> <base>
git switch --no-track -c <branch-name> origin/<base>
base=$(resolve_base "$documented_base" "$user_base") || {
echo "No usable base branch. Candidates:" >&2
git branch -r >&2
echo "Pass --base <branch> to choose one." >&2
exit 1
}
if git rev-parse --verify --quiet "origin/$base" >/dev/null; then
base_ref="origin/$base"
else
base_ref="$base"
fi

git switch --no-track -c <branch-name> "$base_ref"
```

In the same repository prefer `origin/<base>` over `upstream/<base>`; use
`upstream` only for a fork or explicit guidance. Fetch or compare freshness only
when it can change the choice of base. If creating from a stale local base,
confirm before updating or use a freshly fetched remote base and report that the
local base was unchanged.

Verify the resulting branch. Do not switch to an existing branch, overwrite,
reset, stash, delete, or force anything without explicit user intent. Do not
create protected/shared base branches.
67 changes: 59 additions & 8 deletions .agents/skills/git-worktree/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Use this when work should not disturb the current worktree. The new worktree
does not copy uncommitted changes, and it does not change the user's shell
directory.

## Naming and base
## Naming

Use the `git-branch` naming rules: issue work is
`<type>/<short-desc>-<issueID>`, other work uses a user-provided name, and no
Expand All @@ -18,21 +18,72 @@ call for naming context and continue from the request if it fails. Store the
worktree at `.worktrees/<branch-name>` so branch path segments are preserved.
The repository should ignore `.worktrees/`.

Default the base to `main`; same-repository work prefers `origin/<base>`, then
local `<base>`, and uses `upstream` only for fork workflows or explicit
guidance. Fetch/check freshness only when it affects the result. If the local
base is stale, confirm before using it or create from a fetched remote base and
report that the local base was unchanged.
## Base

Base selection has exactly one source of truth: the `## Base` section of the
`git-branch` skill. Do not restate or re-order it here — call `resolve_base`
from that section and use the value it returns. For reference, the order is
documented base → `origin/HEAD` → user choice → `main` fallback, and every
candidate is validated with a ref check before it is used.

Copy both helpers from `git-branch` verbatim (keep them identical when that
section changes):

```bash
ref_exists() {
git rev-parse --verify --quiet "origin/$1" >/dev/null 2>&1 \
|| git rev-parse --verify --quiet "refs/heads/$1" >/dev/null 2>&1
}

resolve_base() {
local documented="$1" user_base="$2" origin_head cand
# 1) documented base
if [ -n "$documented" ] && ref_exists "$documented"; then echo "$documented"; return 0; fi
# 2) origin/HEAD
origin_head=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's#^origin/##')
[ -n "$origin_head" ] || origin_head=$(git remote show origin 2>/dev/null | sed -n 's/^ *HEAD branch: *//p')
# 3) user choice 4) main fallback
for cand in "$origin_head" "$user_base" main; do
if [ -n "$cand" ] && ref_exists "$cand"; then echo "$cand"; return 0; fi
done
return 1
}
```

Create from the remote ref first and fall back to the local ref only when the
remote one is missing:

```bash
base=$(resolve_base "$documented_base" "$user_base") || {
echo "No usable base branch. Candidates:" >&2
git branch -r >&2
echo "Pass --base <branch> to choose one." >&2
exit 1
}
if git rev-parse --verify --quiet "origin/$base" >/dev/null; then
base_ref="origin/$base"
else
base_ref="$base"
fi
```

Same-repository work prefers `origin/<base>`; use `upstream` only for fork
workflows or explicit guidance. Fetch or compare freshness only when it can
change the choice of base. If the local base is stale, confirm before using it
or create from a fetched remote base and report that the local base was
unchanged. Never continue with a base that does not resolve, and never fall back
to a `main` branch that does not exist.

## Create

Before creating, check current status, existing worktrees/branches, and the
target path. Stop if any target already exists or dirty-work intent is unclear.
Validate the branch with `git check-ref-format --branch <branch-name>`, create
parent directories as needed, then run the equivalent of:
parent directories as needed, resolve the base as shown above, then run the
equivalent of:

```bash
git worktree add --no-track -b <branch-name> .worktrees/<branch-name> <base-ref>
git worktree add --no-track -b <branch-name> .worktrees/<branch-name> "$base_ref"
```

Verify the new worktree's branch, status, and `pwd`. Report its path, base,
Expand Down
Loading