Skip to content

Commit 0fe45e0

Browse files
NagyViktNagyVikt
andauthored
Make branch start/finish follow the active repo base by default (#17)
Hardcoded dev defaults caused agent workflows to mis-target repos whose protected base is main/master or another branch. This change makes start/finish infer base from repo context and branch metadata so agent branches launch and merge back correctly without extra flags. Constraint: Must preserve explicit --base and multiagent.baseBranch behavior Rejected: Force setup to auto-write multiagent.baseBranch | intrusive repo config mutation Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep template scripts and runtime scripts in lockstep whenever branch-resolution logic changes Tested: bash -n scripts/agent-branch-start.sh scripts/agent-branch-finish.sh templates/scripts/agent-branch-start.sh templates/scripts/agent-branch-finish.sh templates/scripts/codex-agent.sh Tested: npm test (46/46 pass) Not-tested: Real GitHub protected-branch auto-merge policy paths in live repos Co-authored-by: NagyVikt <nagy.viktordp@gmail.com>
1 parent 193bb4f commit 0fe45e0

8 files changed

Lines changed: 244 additions & 17 deletions

File tree

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ Use this exact checklist to setup multi-agent safety in this repository for Code
169169
6) Optional: protect extra branches:
170170
musafety protect add release staging
171171
172-
7) Optional: sync your current agent branch with latest dev:
172+
7) Optional: sync your current agent branch with latest base branch:
173173
musafety sync --check
174174
musafety sync
175175
```
@@ -212,7 +212,7 @@ musafety scan [--target <path>] [--json]
212212
musafety report help
213213
```
214214

215-
## Keep agent branches synced with dev
215+
## Keep agent branches synced with your base branch
216216

217217
Use sync checks before finishing agent branches:
218218

@@ -223,9 +223,16 @@ musafety sync
223223

224224
Defaults:
225225

226-
- base branch: `dev` (or `multiagent.baseBranch`)
226+
- `musafety sync` base branch: `dev` (or `multiagent.baseBranch`)
227227
- strategy: `rebase` (or `multiagent.sync.strategy`)
228228

229+
`agent-branch-start.sh` and `agent-branch-finish.sh` resolve base branch in this order:
230+
231+
1. explicit `--base`
232+
2. `multiagent.baseBranch`
233+
3. branch-linked base metadata / source upstream / current checked-out branch (context-dependent)
234+
4. fallback `dev`
235+
229236
Useful variants:
230237

231238
```sh

bin/multiagent-safety.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ const AI_SETUP_PROMPT = `Use this exact checklist to setup multi-agent safety in
147147
6) Optional: protect extra branches:
148148
musafety protect add release staging
149149
150-
7) Optional: sync your current agent branch with latest dev:
150+
7) Optional: sync your current agent branch with latest base branch:
151151
musafety sync --check
152152
musafety sync
153153
`;

scripts/agent-branch-finish.sh

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
BASE_BRANCH="dev"
4+
BASE_BRANCH=""
55
BASE_BRANCH_EXPLICIT=0
66
SOURCE_BRANCH=""
77
PUSH_ENABLED=1
@@ -64,15 +64,46 @@ fi
6464
repo_root="$(git rev-parse --show-toplevel)"
6565
current_worktree="$(pwd -P)"
6666

67+
if [[ -z "$SOURCE_BRANCH" ]]; then
68+
SOURCE_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
69+
fi
70+
71+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -z "$BASE_BRANCH" ]]; then
72+
echo "[agent-branch-finish] --base requires a non-empty branch name." >&2
73+
exit 1
74+
fi
75+
6776
if [[ "$BASE_BRANCH_EXPLICIT" -eq 0 ]]; then
6877
configured_base="$(git -C "$repo_root" config --get multiagent.baseBranch || true)"
6978
if [[ -n "$configured_base" ]]; then
7079
BASE_BRANCH="$configured_base"
7180
fi
7281
fi
7382

74-
if [[ -z "$SOURCE_BRANCH" ]]; then
75-
SOURCE_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
83+
if [[ -z "$BASE_BRANCH" ]]; then
84+
branch_stored_base="$(git -C "$repo_root" config --get "branch.${SOURCE_BRANCH}.musafetyBase" || true)"
85+
if [[ -n "$branch_stored_base" ]]; then
86+
BASE_BRANCH="$branch_stored_base"
87+
fi
88+
fi
89+
90+
if [[ -z "$BASE_BRANCH" ]]; then
91+
source_upstream="$(git -C "$repo_root" for-each-ref --format='%(upstream:short)' "refs/heads/${SOURCE_BRANCH}" | head -n 1)"
92+
source_upstream="${source_upstream:-}"
93+
if [[ "$source_upstream" == */* ]]; then
94+
BASE_BRANCH="${source_upstream#*/}"
95+
fi
96+
fi
97+
98+
if [[ -z "$BASE_BRANCH" ]]; then
99+
current_branch="$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
100+
if [[ -n "$current_branch" && "$current_branch" != "HEAD" && "$current_branch" != "$SOURCE_BRANCH" ]]; then
101+
BASE_BRANCH="$current_branch"
102+
fi
103+
fi
104+
105+
if [[ -z "$BASE_BRANCH" ]]; then
106+
BASE_BRANCH="dev"
76107
fi
77108

78109
if [[ "$SOURCE_BRANCH" == "$BASE_BRANCH" ]]; then

scripts/agent-branch-start.sh

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ set -euo pipefail
33

44
TASK_NAME="${1:-task}"
55
AGENT_NAME="${2:-agent}"
6-
BASE_BRANCH="${3:-dev}"
6+
BASE_BRANCH="${3:-}"
7+
BASE_BRANCH_EXPLICIT=0
78
WORKTREE_MODE=1
89
WORKTREE_ROOT_REL=".omx/agent-worktrees"
910

11+
if [[ -n "${3:-}" ]]; then
12+
BASE_BRANCH_EXPLICIT=1
13+
fi
14+
1015
while [[ $# -gt 0 ]]; do
1116
case "$1" in
1217
--task)
@@ -18,7 +23,8 @@ while [[ $# -gt 0 ]]; do
1823
shift 2
1924
;;
2025
--base)
21-
BASE_BRANCH="${2:-dev}"
26+
BASE_BRANCH="${2:-}"
27+
BASE_BRANCH_EXPLICIT=1
2228
shift 2
2329
;;
2430
--in-place)
@@ -80,6 +86,25 @@ fi
8086

8187
repo_root="$(git rev-parse --show-toplevel)"
8288

89+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -z "$BASE_BRANCH" ]]; then
90+
echo "[agent-branch-start] --base requires a non-empty branch name." >&2
91+
exit 1
92+
fi
93+
94+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 0 ]]; then
95+
configured_base="$(git -C "$repo_root" config --get multiagent.baseBranch || true)"
96+
if [[ -n "$configured_base" ]]; then
97+
BASE_BRANCH="$configured_base"
98+
else
99+
current_branch="$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
100+
if [[ -n "$current_branch" && "$current_branch" != "HEAD" ]]; then
101+
BASE_BRANCH="$current_branch"
102+
else
103+
BASE_BRANCH="dev"
104+
fi
105+
fi
106+
fi
107+
83108
if git show-ref --verify --quiet "refs/remotes/origin/${BASE_BRANCH}"; then
84109
git fetch origin "${BASE_BRANCH}" --quiet
85110
start_ref="origin/${BASE_BRANCH}"
@@ -123,6 +148,7 @@ if [[ "$WORKTREE_MODE" -eq 0 ]]; then
123148
fi
124149

125150
git checkout -b "$branch_name"
151+
git -C "$repo_root" config "branch.${branch_name}.musafetyBase" "$BASE_BRANCH" >/dev/null 2>&1 || true
126152
echo "[agent-branch-start] Created in-place branch: ${branch_name}"
127153
echo "$branch_name"
128154
exit 0
@@ -138,6 +164,7 @@ if [[ -e "$worktree_path" ]]; then
138164
fi
139165

140166
git -C "$repo_root" worktree add -b "$branch_name" "$worktree_path" "$start_ref"
167+
git -C "$repo_root" config "branch.${branch_name}.musafetyBase" "$BASE_BRANCH" >/dev/null 2>&1 || true
141168

142169
if git -C "$repo_root" show-ref --verify --quiet "refs/remotes/origin/${BASE_BRANCH}"; then
143170
git -C "$worktree_path" branch --set-upstream-to="origin/${BASE_BRANCH}" "$branch_name" >/dev/null 2>&1 || true

templates/scripts/agent-branch-finish.sh

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
BASE_BRANCH="dev"
4+
BASE_BRANCH=""
55
BASE_BRANCH_EXPLICIT=0
66
SOURCE_BRANCH=""
77
PUSH_ENABLED=1
@@ -64,15 +64,46 @@ fi
6464
repo_root="$(git rev-parse --show-toplevel)"
6565
current_worktree="$(pwd -P)"
6666

67+
if [[ -z "$SOURCE_BRANCH" ]]; then
68+
SOURCE_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
69+
fi
70+
71+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -z "$BASE_BRANCH" ]]; then
72+
echo "[agent-branch-finish] --base requires a non-empty branch name." >&2
73+
exit 1
74+
fi
75+
6776
if [[ "$BASE_BRANCH_EXPLICIT" -eq 0 ]]; then
6877
configured_base="$(git -C "$repo_root" config --get multiagent.baseBranch || true)"
6978
if [[ -n "$configured_base" ]]; then
7079
BASE_BRANCH="$configured_base"
7180
fi
7281
fi
7382

74-
if [[ -z "$SOURCE_BRANCH" ]]; then
75-
SOURCE_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
83+
if [[ -z "$BASE_BRANCH" ]]; then
84+
branch_stored_base="$(git -C "$repo_root" config --get "branch.${SOURCE_BRANCH}.musafetyBase" || true)"
85+
if [[ -n "$branch_stored_base" ]]; then
86+
BASE_BRANCH="$branch_stored_base"
87+
fi
88+
fi
89+
90+
if [[ -z "$BASE_BRANCH" ]]; then
91+
source_upstream="$(git -C "$repo_root" for-each-ref --format='%(upstream:short)' "refs/heads/${SOURCE_BRANCH}" | head -n 1)"
92+
source_upstream="${source_upstream:-}"
93+
if [[ "$source_upstream" == */* ]]; then
94+
BASE_BRANCH="${source_upstream#*/}"
95+
fi
96+
fi
97+
98+
if [[ -z "$BASE_BRANCH" ]]; then
99+
current_branch="$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
100+
if [[ -n "$current_branch" && "$current_branch" != "HEAD" && "$current_branch" != "$SOURCE_BRANCH" ]]; then
101+
BASE_BRANCH="$current_branch"
102+
fi
103+
fi
104+
105+
if [[ -z "$BASE_BRANCH" ]]; then
106+
BASE_BRANCH="dev"
76107
fi
77108

78109
if [[ "$SOURCE_BRANCH" == "$BASE_BRANCH" ]]; then

templates/scripts/agent-branch-start.sh

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ set -euo pipefail
33

44
TASK_NAME="task"
55
AGENT_NAME="agent"
6-
BASE_BRANCH="dev"
6+
BASE_BRANCH=""
7+
BASE_BRANCH_EXPLICIT=0
78
WORKTREE_MODE=1
89
ALLOW_IN_PLACE=0
910
WORKTREE_ROOT_REL=".omx/agent-worktrees"
@@ -20,7 +21,8 @@ while [[ $# -gt 0 ]]; do
2021
shift 2
2122
;;
2223
--base)
23-
BASE_BRANCH="${2:-dev}"
24+
BASE_BRANCH="${2:-}"
25+
BASE_BRANCH_EXPLICIT=1
2426
shift 2
2527
;;
2628
--in-place)
@@ -71,6 +73,7 @@ fi
7173

7274
if [[ "${#POSITIONAL_ARGS[@]}" -ge 3 ]]; then
7375
BASE_BRANCH="${POSITIONAL_ARGS[2]}"
76+
BASE_BRANCH_EXPLICIT=1
7477
fi
7578

7679
sanitize_slug() {
@@ -109,6 +112,25 @@ fi
109112

110113
repo_root="$(git rev-parse --show-toplevel)"
111114

115+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -z "$BASE_BRANCH" ]]; then
116+
echo "[agent-branch-start] --base requires a non-empty branch name." >&2
117+
exit 1
118+
fi
119+
120+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 0 ]]; then
121+
configured_base="$(git -C "$repo_root" config --get multiagent.baseBranch || true)"
122+
if [[ -n "$configured_base" ]]; then
123+
BASE_BRANCH="$configured_base"
124+
else
125+
current_branch="$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
126+
if [[ -n "$current_branch" && "$current_branch" != "HEAD" ]]; then
127+
BASE_BRANCH="$current_branch"
128+
else
129+
BASE_BRANCH="dev"
130+
fi
131+
fi
132+
fi
133+
112134
if git show-ref --verify --quiet "refs/remotes/origin/${BASE_BRANCH}"; then
113135
git fetch origin "${BASE_BRANCH}" --quiet
114136
start_ref="origin/${BASE_BRANCH}"
@@ -158,6 +180,7 @@ if [[ "$WORKTREE_MODE" -eq 0 ]]; then
158180
fi
159181

160182
git checkout -b "$branch_name"
183+
git -C "$repo_root" config "branch.${branch_name}.musafetyBase" "$BASE_BRANCH" >/dev/null 2>&1 || true
161184
echo "[agent-branch-start] Created in-place branch: ${branch_name}"
162185
echo "$branch_name"
163186
exit 0
@@ -173,6 +196,7 @@ if [[ -e "$worktree_path" ]]; then
173196
fi
174197

175198
git -C "$repo_root" worktree add -b "$branch_name" "$worktree_path" "$start_ref"
199+
git -C "$repo_root" config "branch.${branch_name}.musafetyBase" "$BASE_BRANCH" >/dev/null 2>&1 || true
176200

177201
if git -C "$repo_root" show-ref --verify --quiet "refs/remotes/origin/${BASE_BRANCH}"; then
178202
git -C "$worktree_path" branch --set-upstream-to="origin/${BASE_BRANCH}" "$branch_name" >/dev/null 2>&1 || true

templates/scripts/codex-agent.sh

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ set -euo pipefail
33

44
TASK_NAME="${MUSAFETY_TASK_NAME:-task}"
55
AGENT_NAME="${MUSAFETY_AGENT_NAME:-agent}"
6-
BASE_BRANCH="${MUSAFETY_BASE_BRANCH:-dev}"
6+
BASE_BRANCH="${MUSAFETY_BASE_BRANCH:-}"
7+
BASE_BRANCH_EXPLICIT=0
78
CODEX_BIN="${MUSAFETY_CODEX_BIN:-codex}"
89

10+
if [[ -n "$BASE_BRANCH" ]]; then
11+
BASE_BRANCH_EXPLICIT=1
12+
fi
13+
914
while [[ $# -gt 0 ]]; do
1015
case "$1" in
1116
--task)
@@ -18,6 +23,7 @@ while [[ $# -gt 0 ]]; do
1823
;;
1924
--base)
2025
BASE_BRANCH="${2:-$BASE_BRANCH}"
26+
BASE_BRANCH_EXPLICIT=1
2127
shift 2
2228
;;
2329
--codex-bin)
@@ -40,13 +46,19 @@ while [[ $# -gt 0 ]]; do
4046
fi
4147
if [[ $# -gt 0 && "${1:-}" != -* ]]; then
4248
BASE_BRANCH="$1"
49+
BASE_BRANCH_EXPLICIT=1
4350
shift
4451
fi
4552
break
4653
;;
4754
esac
4855
done
4956

57+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -z "$BASE_BRANCH" ]]; then
58+
echo "[codex-agent] --base requires a non-empty branch name." >&2
59+
exit 1
60+
fi
61+
5062
if ! command -v "$CODEX_BIN" >/dev/null 2>&1; then
5163
echo "[codex-agent] Missing Codex CLI command: $CODEX_BIN" >&2
5264
echo "[codex-agent] Install Codex first, then retry." >&2
@@ -58,7 +70,12 @@ if [[ ! -x "scripts/agent-branch-start.sh" ]]; then
5870
exit 1
5971
fi
6072

61-
start_output="$(bash scripts/agent-branch-start.sh "$TASK_NAME" "$AGENT_NAME" "$BASE_BRANCH")"
73+
start_args=("$TASK_NAME" "$AGENT_NAME")
74+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 ]]; then
75+
start_args+=("$BASE_BRANCH")
76+
fi
77+
78+
start_output="$(bash scripts/agent-branch-start.sh "${start_args[@]}")"
6279
printf '%s\n' "$start_output"
6380

6481
worktree_path="$(printf '%s\n' "$start_output" | sed -n 's/^\[agent-branch-start\] Worktree: //p' | tail -n1)"

0 commit comments

Comments
 (0)