Skip to content

Commit e521a0e

Browse files
NagyViktNagyVikt
andauthored
Make Guardex resume hints harder to misuse (#538)
Guardex startup output was mixing status, worktree paths, and finish guidance into long human sentences. This commit keeps parser-stable status lines intact while giving agents a scannable branch/worktree/next block and making cleanup part of every printed finish command. Constraint: Existing consumers parse the Created branch and Worktree lines, so those lines stay unchanged. Rejected: Reword all startup output | too much compatibility risk for a small guidance fix Confidence: high Scope-risk: narrow Directive: Keep scripts and templates in parity when changing launcher output. Tested: bash -n scripts/agent-branch-start.sh scripts/codex-agent.sh templates/scripts/agent-branch-start.sh templates/scripts/codex-agent.sh Tested: git diff --check Tested: diff -u scripts/agent-branch-start.sh templates/scripts/agent-branch-start.sh Tested: diff -u scripts/codex-agent.sh templates/scripts/codex-agent.sh Tested: node --test test/branch.test.js test/sandbox.test.js Not-tested: Full npm test; known unrelated test/metadata.test.js cosign v4.1.1/v4.1.2 baseline drift. Co-authored-by: NagyVikt <nagy.viktordp@gmail.com>
1 parent 7aa1089 commit e521a0e

7 files changed

Lines changed: 101 additions & 31 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Improve Guard startup output design
2+
3+
## Problem
4+
5+
Guardex startup and takeover hints were hard to scan: machine-readable status,
6+
human next steps, and finish/cleanup guidance were mixed into long lines.
7+
8+
## Scope
9+
10+
- Keep existing parser-stable `[agent-branch-start] Created branch` and
11+
`[agent-branch-start] Worktree` lines.
12+
- Replace the human next-step block with aligned branch/worktree/next fields.
13+
- Replace the long Codex takeover sentence with a scannable resume block.
14+
- Include `--cleanup` in finish guidance.
15+
16+
## Verification
17+
18+
- `bash -n scripts/agent-branch-start.sh scripts/codex-agent.sh templates/scripts/agent-branch-start.sh templates/scripts/codex-agent.sh`
19+
- `node --test test/branch.test.js test/sandbox.test.js test/metadata.test.js`

scripts/agent-branch-start.sh

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -389,11 +389,27 @@ print_reused_agent_worktree() {
389389
echo "[agent-branch-start] OpenSpec tier: ${OPENSPEC_TIER}"
390390
echo "[agent-branch-start] OpenSpec change: existing worktree"
391391
echo "[agent-branch-start] OpenSpec plan: existing worktree"
392-
echo "[agent-branch-start] Next steps:"
393-
echo " cd \"${worktree_path}\""
394-
echo " gx locks claim --branch \"${branch_name}\" <file...>"
395-
echo " # continue work in this existing sandbox"
396-
echo " gx branch finish --branch \"${branch_name}\" --via-pr --wait-for-merge"
392+
print_agent_next_steps "$branch_name" "$worktree_path" "continue work in this existing sandbox" "$BASE_BRANCH"
393+
}
394+
395+
print_agent_next_steps() {
396+
local branch_name="$1"
397+
local worktree_path="$2"
398+
local work_step="$3"
399+
local base_branch="${4:-main}"
400+
401+
if [[ -z "$base_branch" ]]; then
402+
base_branch="main"
403+
fi
404+
405+
echo "[agent-branch-start] Ready:"
406+
echo " branch: ${branch_name}"
407+
echo " worktree: ${worktree_path}"
408+
echo " next:"
409+
echo " cd \"${worktree_path}\""
410+
echo " gx locks claim --branch \"${branch_name}\" <file...>"
411+
echo " # ${work_step}"
412+
echo " gx branch finish --branch \"${branch_name}\" --base ${base_branch} --via-pr --wait-for-merge --cleanup"
397413
}
398414

399415
has_local_changes() {
@@ -842,8 +858,4 @@ if [[ "$OPENSPEC_SKIP_PLAN" -eq 1 ]]; then
842858
else
843859
echo "[agent-branch-start] OpenSpec plan: openspec/plan/${openspec_plan_slug}"
844860
fi
845-
echo "[agent-branch-start] Next steps:"
846-
echo " cd \"${worktree_path}\""
847-
echo " gx locks claim --branch \"${branch_name}\" <file...>"
848-
echo " # implement + commit"
849-
echo " gx branch finish --branch \"${branch_name}\" --base ${BASE_BRANCH} --via-pr --wait-for-merge"
861+
print_agent_next_steps "$branch_name" "$worktree_path" "implement + commit" "$BASE_BRANCH"

scripts/codex-agent.sh

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -735,9 +735,14 @@ print_takeover_prompt() {
735735

736736
finish_cmd="gx branch finish --branch \"${branch}\" --base ${base_branch} --via-pr --wait-for-merge --cleanup"
737737

738-
echo "[codex-agent] Takeover sandbox: ${wt}"
739-
echo "[codex-agent] Takeover routing: $(describe_task_routing) (${TASK_ROUTING_REASON})"
740-
echo "[codex-agent] Takeover prompt: Continue \`${change_slug}\` on branch \`${branch}\`. Work inside \`${wt}\`, review \`${change_artifact}\`, continue from the current state instead of creating a new sandbox, and when the work is done run \`${finish_cmd}\`."
738+
echo "[codex-agent] Resume this sandbox:"
739+
echo " change: ${change_slug}"
740+
echo " branch: ${branch}"
741+
echo " worktree: ${wt}"
742+
echo " spec: ${change_artifact}"
743+
echo " routing: $(describe_task_routing) (${TASK_ROUTING_REASON})"
744+
echo " rule: continue current state; do not create a new sandbox"
745+
echo " finish: ${finish_cmd}"
741746
}
742747

743748
sync_worktree_with_base() {
@@ -1161,7 +1166,11 @@ else
11611166
echo "[codex-agent] Branch kept intentionally. Cleanup on demand: gx cleanup --branch \"${worktree_branch}\""
11621167
else
11631168
print_takeover_prompt "$worktree_path" "$worktree_branch"
1164-
echo "[codex-agent] If finished, merge with: gx branch finish --branch \"${worktree_branch}\" --base dev --via-pr --wait-for-merge"
1169+
finish_base_branch="$(resolve_worktree_base_branch "$worktree_path")"
1170+
if [[ -z "$finish_base_branch" ]]; then
1171+
finish_base_branch="dev"
1172+
fi
1173+
echo "[codex-agent] If finished, merge with: gx branch finish --branch \"${worktree_branch}\" --base ${finish_base_branch} --via-pr --wait-for-merge --cleanup"
11651174
echo "[codex-agent] Cleanup on demand: gx cleanup --branch \"${worktree_branch}\""
11661175
fi
11671176
fi

templates/scripts/agent-branch-start.sh

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -389,11 +389,27 @@ print_reused_agent_worktree() {
389389
echo "[agent-branch-start] OpenSpec tier: ${OPENSPEC_TIER}"
390390
echo "[agent-branch-start] OpenSpec change: existing worktree"
391391
echo "[agent-branch-start] OpenSpec plan: existing worktree"
392-
echo "[agent-branch-start] Next steps:"
393-
echo " cd \"${worktree_path}\""
394-
echo " gx locks claim --branch \"${branch_name}\" <file...>"
395-
echo " # continue work in this existing sandbox"
396-
echo " gx branch finish --branch \"${branch_name}\" --via-pr --wait-for-merge"
392+
print_agent_next_steps "$branch_name" "$worktree_path" "continue work in this existing sandbox" "$BASE_BRANCH"
393+
}
394+
395+
print_agent_next_steps() {
396+
local branch_name="$1"
397+
local worktree_path="$2"
398+
local work_step="$3"
399+
local base_branch="${4:-main}"
400+
401+
if [[ -z "$base_branch" ]]; then
402+
base_branch="main"
403+
fi
404+
405+
echo "[agent-branch-start] Ready:"
406+
echo " branch: ${branch_name}"
407+
echo " worktree: ${worktree_path}"
408+
echo " next:"
409+
echo " cd \"${worktree_path}\""
410+
echo " gx locks claim --branch \"${branch_name}\" <file...>"
411+
echo " # ${work_step}"
412+
echo " gx branch finish --branch \"${branch_name}\" --base ${base_branch} --via-pr --wait-for-merge --cleanup"
397413
}
398414

399415
has_local_changes() {
@@ -842,8 +858,4 @@ if [[ "$OPENSPEC_SKIP_PLAN" -eq 1 ]]; then
842858
else
843859
echo "[agent-branch-start] OpenSpec plan: openspec/plan/${openspec_plan_slug}"
844860
fi
845-
echo "[agent-branch-start] Next steps:"
846-
echo " cd \"${worktree_path}\""
847-
echo " gx locks claim --branch \"${branch_name}\" <file...>"
848-
echo " # implement + commit"
849-
echo " gx branch finish --branch \"${branch_name}\" --base ${BASE_BRANCH} --via-pr --wait-for-merge"
861+
print_agent_next_steps "$branch_name" "$worktree_path" "implement + commit" "$BASE_BRANCH"

templates/scripts/codex-agent.sh

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -735,9 +735,14 @@ print_takeover_prompt() {
735735

736736
finish_cmd="gx branch finish --branch \"${branch}\" --base ${base_branch} --via-pr --wait-for-merge --cleanup"
737737

738-
echo "[codex-agent] Takeover sandbox: ${wt}"
739-
echo "[codex-agent] Takeover routing: $(describe_task_routing) (${TASK_ROUTING_REASON})"
740-
echo "[codex-agent] Takeover prompt: Continue \`${change_slug}\` on branch \`${branch}\`. Work inside \`${wt}\`, review \`${change_artifact}\`, continue from the current state instead of creating a new sandbox, and when the work is done run \`${finish_cmd}\`."
738+
echo "[codex-agent] Resume this sandbox:"
739+
echo " change: ${change_slug}"
740+
echo " branch: ${branch}"
741+
echo " worktree: ${wt}"
742+
echo " spec: ${change_artifact}"
743+
echo " routing: $(describe_task_routing) (${TASK_ROUTING_REASON})"
744+
echo " rule: continue current state; do not create a new sandbox"
745+
echo " finish: ${finish_cmd}"
741746
}
742747

743748
sync_worktree_with_base() {
@@ -1161,7 +1166,11 @@ else
11611166
echo "[codex-agent] Branch kept intentionally. Cleanup on demand: gx cleanup --branch \"${worktree_branch}\""
11621167
else
11631168
print_takeover_prompt "$worktree_path" "$worktree_branch"
1164-
echo "[codex-agent] If finished, merge with: gx branch finish --branch \"${worktree_branch}\" --base dev --via-pr --wait-for-merge"
1169+
finish_base_branch="$(resolve_worktree_base_branch "$worktree_path")"
1170+
if [[ -z "$finish_base_branch" ]]; then
1171+
finish_base_branch="dev"
1172+
fi
1173+
echo "[codex-agent] If finished, merge with: gx branch finish --branch \"${worktree_branch}\" --base ${finish_base_branch} --via-pr --wait-for-merge --cleanup"
11651174
echo "[codex-agent] Cleanup on demand: gx cleanup --branch \"${worktree_branch}\""
11661175
fi
11671176
fi

test/branch.test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,13 @@ test('agent-branch-start honors T1 notes-only OpenSpec scaffolding', () => {
439439
assert.equal(result.status, 0, result.stderr || result.stdout);
440440
assert.match(result.stdout, /\[agent-branch-start\] OpenSpec tier: T1/);
441441
assert.match(result.stdout, /\[agent-branch-start\] OpenSpec plan: skipped by tier T1/);
442+
assert.match(result.stdout, /\[agent-branch-start\] Ready:/);
443+
assert.match(result.stdout, / branch: agent\/codex\/simple-tighten-copy-/);
444+
assert.match(result.stdout, / next:\n cd "/);
445+
assert.match(
446+
result.stdout,
447+
/gx branch finish --branch "agent\/codex\/simple-tighten-copy-[^"]+" --base dev --via-pr --wait-for-merge --cleanup/,
448+
);
442449

443450
const createdWorktree = extractCreatedWorktree(result.stdout);
444451
const changeSlug = extractOpenSpecChangeSlug(result.stdout);

test/sandbox.test.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -580,12 +580,14 @@ test('codex-agent prints a takeover prompt when the sandbox is kept after an inc
580580
const launchedBranch = extractCreatedBranch(launch.stdout);
581581
const changeSlug = launchedBranch.replace(/\//g, '-');
582582
assert.match(combinedOutput, /\[codex-agent\] Sandbox worktree kept:/);
583-
assert.match(combinedOutput, new RegExp(`\\[codex-agent\\] Takeover sandbox: ${escapeRegexLiteral(fs.readFileSync(cwdMarker, 'utf8').trim())}`));
583+
assert.match(combinedOutput, /\[codex-agent\] Resume this sandbox:/);
584+
assert.match(combinedOutput, new RegExp(` worktree: ${escapeRegexLiteral(fs.readFileSync(cwdMarker, 'utf8').trim())}`));
584585
assert.match(
585586
combinedOutput,
586-
new RegExp(`\\[codex-agent\\] Takeover prompt: Continue \`${escapeRegexLiteral(changeSlug)}\` on branch \`${escapeRegexLiteral(launchedBranch)}\``),
587+
new RegExp(` change: ${escapeRegexLiteral(changeSlug)}`),
587588
);
588-
assert.match(combinedOutput, /continue from the current state instead of creating a new sandbox/);
589+
assert.match(combinedOutput, new RegExp(` branch: ${escapeRegexLiteral(launchedBranch)}`));
590+
assert.match(combinedOutput, /rule: continue current state; do not create a new sandbox/);
589591
assert.match(
590592
combinedOutput,
591593
new RegExp(`openspec/changes/${escapeRegexLiteral(changeSlug)}/tasks\\.md`),

0 commit comments

Comments
 (0)