Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-04-21
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## Why

- When `codex-agent` keeps a sandbox after the first lane exits early, the next
agent only gets generic merge/cleanup hints and has to reconstruct the exact
takeover flow by hand.
- Fresh OpenSpec change workspaces do not scaffold a copy-paste takeover note,
so usage-limit handoffs are inconsistent and easy to botch.

## What Changes

- Make `codex-agent` print a concrete takeover prompt with the existing branch,
sandbox path, OpenSpec artifact, and finish command whenever auto-finish does
not complete and the worktree stays alive.
- Teach `init-change-workspace.sh` to scaffold structured `Handoff:` and
`Copy prompt:` lines, and resolve the cleanup command base branch from repo
metadata instead of hardcoding `dev`.
- Add regression coverage for both the launcher handoff output and the scaffold
defaults.

## Impact

- Affects `scripts/codex-agent.sh`, `scripts/openspec/init-change-workspace.sh`,
and `test/install.test.js`.
- Keeps the existing finish pipeline intact while making quota-hit/manual
takeovers copy-pasteable instead of reconstructive.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## ADDED Requirements

### Requirement: `codex-agent` SHALL emit a takeover prompt when a sandbox is kept
`codex-agent` SHALL print a copy-paste takeover prompt whenever it leaves a
branch/worktree alive for manual follow-up.

#### Scenario: incomplete run keeps the sandbox alive
- **GIVEN** `codex-agent` keeps the sandbox because auto-finish did not complete
- **WHEN** it reports the kept worktree
- **THEN** it SHALL print a takeover prompt that references the existing branch
and sandbox path
- **AND** the prompt SHALL tell the next agent to continue from the current
state instead of creating a new sandbox
- **AND** the prompt SHALL include the cleanup/finish command for
`agent-branch-finish.sh`.

### Requirement: OpenSpec change scaffolds SHALL include structured takeover copy
OpenSpec change workspaces SHALL scaffold a structured handoff line plus a
copy-paste takeover prompt for usage-limit/manual handoffs.

#### Scenario: standard change workspace scaffold
- **WHEN** `scripts/openspec/init-change-workspace.sh` creates a non-minimal
change workspace
- **THEN** `tasks.md` SHALL include a `Handoff:` line and a `Copy prompt:` line
- **AND** the generated cleanup command SHALL resolve the branch base from repo
metadata when available.

#### Scenario: minimal notes workspace scaffold
- **WHEN** `scripts/openspec/init-change-workspace.sh` runs in minimal mode
- **THEN** `notes.md` SHALL include the same `Handoff:` and `Copy prompt:` flow
- **AND** the generated cleanup command SHALL resolve the branch base from repo
metadata when available.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## Definition of Done

This change is complete only when **all** of the following are true:

- Every checkbox below is checked.
- The agent branch reaches `MERGED` state on `origin` and the PR URL + state are recorded in the completion handoff.
- If any step blocks (test failure, conflict, ambiguous result), append a `BLOCKED:` line under section 4 explaining the blocker and **STOP**. Do not tick remaining cleanup boxes; do not silently skip the cleanup pipeline.

## Handoff

- Handoff: change=`agent-codex-improve-usage-limit-takeover-handoff-2026-04-21-23-30`; branch=`agent/codex/improve-usage-limit-takeover-handoff-2026-04-21-23-30`; scope=`OpenSpec change docs, codex-agent takeover output, change scaffold defaults, install regressions`; action=`emit a copy-paste takeover prompt and keep usage-limit/manual rescue flow inside the existing sandbox`.
- Copy prompt: Continue `agent-codex-improve-usage-limit-takeover-handoff-2026-04-21-23-30` on branch `agent/codex/improve-usage-limit-takeover-handoff-2026-04-21-23-30`. Work inside the existing sandbox, review `openspec/changes/agent-codex-improve-usage-limit-takeover-handoff-2026-04-21-23-30/tasks.md`, continue from the current state instead of creating a new sandbox, and when the work is done run `bash scripts/agent-branch-finish.sh --branch "agent/codex/improve-usage-limit-takeover-handoff-2026-04-21-23-30" --base main --via-pr --wait-for-merge --cleanup`.

## 1. Specification

- [x] 1.1 Finalize proposal scope and acceptance criteria for `agent-codex-improve-usage-limit-takeover-handoff-2026-04-21-23-30`.
- [x] 1.2 Define normative requirements in `specs/improve-usage-limit-takeover-handoff/spec.md`.

## 2. Implementation

- [x] 2.1 Implement scoped behavior changes in `scripts/codex-agent.sh` and `scripts/openspec/init-change-workspace.sh`, then mirror the same changes into the managed templates.
- [x] 2.2 Add/update focused regression coverage in `test/install.test.js` for the launcher takeover prompt and the scaffolded handoff/copy prompt defaults.

## 3. Verification

- [x] 3.1 Run targeted project verification commands. Result: `node --test --test-name-pattern "(codex-agent prints a takeover prompt when the sandbox is kept after an incomplete run|OpenSpec change workspace scaffold creates proposal/tasks/spec defaults|OpenSpec change workspace scaffold supports minimal T1 notes mode|critical runtime helper scripts stay in sync with templates)" test/install.test.js test/metadata.test.js` passed `4/4`; `bash -n scripts/codex-agent.sh scripts/openspec/init-change-workspace.sh templates/scripts/codex-agent.sh templates/scripts/openspec/init-change-workspace.sh` passed.
- [x] 3.2 Run `openspec validate agent-codex-improve-usage-limit-takeover-handoff-2026-04-21-23-30 --type change --strict`. Result: passed.
- [x] 3.3 Run `openspec validate --specs`. Result: `No items found to validate.`

## 4. Cleanup (mandatory; run before claiming completion)

- [ ] 4.1 Run the cleanup pipeline: `bash scripts/agent-branch-finish.sh --branch agent/codex/improve-usage-limit-takeover-handoff-2026-04-21-23-30 --base dev --via-pr --wait-for-merge --cleanup`. This handles commit -> push -> PR create -> merge wait -> worktree prune in one invocation.
- [ ] 4.2 Record the PR URL and final merge state (`MERGED`) in the completion handoff.
- [ ] 4.3 Confirm the sandbox worktree is gone (`git worktree list` no longer shows the agent path; `git branch -a` shows no surviving local/remote refs for the branch).
26 changes: 26 additions & 0 deletions scripts/codex-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,31 @@ resolve_worktree_base_branch() {
printf 'dev'
}

print_takeover_prompt() {
local wt="$1"
local branch="$2"
local base_branch change_slug change_artifact finish_cmd

base_branch="$(resolve_worktree_base_branch "$wt")"
if [[ -z "$base_branch" ]]; then
base_branch="dev"
fi

change_slug="$(resolve_openspec_change_slug "$branch")"
change_artifact="openspec/changes/${change_slug}/tasks.md"
if [[ ! -f "${wt}/${change_artifact}" ]]; then
change_artifact="openspec/changes/${change_slug}/notes.md"
fi
if [[ ! -f "${wt}/${change_artifact}" ]]; then
change_artifact="openspec/changes/${change_slug}/"
fi

finish_cmd="bash scripts/agent-branch-finish.sh --branch \"${branch}\" --base ${base_branch} --via-pr --wait-for-merge --cleanup"

echo "[codex-agent] Takeover sandbox: ${wt}"
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}\`."
}

sync_worktree_with_base() {
local wt="$1"
if ! has_origin_remote; then
Expand Down Expand Up @@ -952,6 +977,7 @@ else
if [[ "$auto_finish_completed" -eq 1 ]]; then
echo "[codex-agent] Branch kept intentionally. Cleanup on demand: gx cleanup --branch \"${worktree_branch}\""
else
print_takeover_prompt "$worktree_path" "$worktree_branch"
echo "[codex-agent] If finished, merge with: bash scripts/agent-branch-finish.sh --branch \"${worktree_branch}\" --base dev --via-pr --wait-for-merge"
echo "[codex-agent] Cleanup on demand: gx cleanup --branch \"${worktree_branch}\""
fi
Expand Down
32 changes: 30 additions & 2 deletions scripts/openspec/init-change-workspace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,27 @@ if [[ "$CAPABILITY_SLUG" =~ [^a-z0-9-] ]]; then
exit 1
fi

resolve_base_branch() {
local branch="$1"
local base_branch=""

if [[ -n "$branch" ]] && [[ "$branch" != "agent/<your-name>/<branch-slug>" ]]; then
base_branch="$(git config --get "branch.${branch}.guardexBase" || true)"
fi
if [[ -z "$base_branch" ]]; then
base_branch="$(git config --get multiagent.baseBranch || true)"
fi
if [[ -z "$base_branch" ]]; then
base_branch="dev"
fi

printf '%s' "$base_branch"
}

CHANGE_DIR="openspec/changes/${CHANGE_SLUG}"
SPEC_DIR="${CHANGE_DIR}/specs/${CAPABILITY_SLUG}"
TODAY="$(date -u +%Y-%m-%d)"
BASE_BRANCH="$(resolve_base_branch "$AGENT_BRANCH")"

MINIMAL_RAW="${GUARDEX_OPENSPEC_MINIMAL:-0}"
case "$(printf '%s' "$MINIMAL_RAW" | tr '[:upper:]' '[:lower:]')" in
Expand Down Expand Up @@ -53,9 +71,14 @@ Branch: \`${AGENT_BRANCH}\`

Describe the change in a sentence or two. Commit message is the spec of record.

## Handoff

- Handoff: change=\`${CHANGE_SLUG}\`; branch=\`${AGENT_BRANCH}\`; scope=\`TODO\`; action=\`continue this sandbox or finish cleanup after a usage-limit/manual takeover\`.
- Copy prompt: Continue \`${CHANGE_SLUG}\` on branch \`${AGENT_BRANCH}\`. Work inside the existing sandbox, review \`openspec/changes/${CHANGE_SLUG}/notes.md\`, continue from the current state instead of creating a new sandbox, and when the work is done run \`bash scripts/agent-branch-finish.sh --branch "${AGENT_BRANCH}" --base ${BASE_BRANCH} --via-pr --wait-for-merge --cleanup\`.

## Cleanup

- [ ] Run: \`bash scripts/agent-branch-finish.sh --branch ${AGENT_BRANCH} --base dev --via-pr --wait-for-merge --cleanup\`
- [ ] Run: \`bash scripts/agent-branch-finish.sh --branch "${AGENT_BRANCH}" --base ${BASE_BRANCH} --via-pr --wait-for-merge --cleanup\`
- [ ] Record PR URL + \`MERGED\` state in the completion handoff.
- [ ] Confirm sandbox worktree is gone (\`git worktree list\`, \`git branch -a\`).
NOTESEOF
Expand Down Expand Up @@ -91,6 +114,11 @@ This change is complete only when **all** of the following are true:
- The agent branch reaches \`MERGED\` state on \`origin\` and the PR URL + state are recorded in the completion handoff.
- If any step blocks (test failure, conflict, ambiguous result), append a \`BLOCKED:\` line under section 4 explaining the blocker and **STOP**. Do not tick remaining cleanup boxes; do not silently skip the cleanup pipeline.

## Handoff

- Handoff: change=\`${CHANGE_SLUG}\`; branch=\`${AGENT_BRANCH}\`; scope=\`TODO\`; action=\`continue this sandbox or finish cleanup after a usage-limit/manual takeover\`.
- Copy prompt: Continue \`${CHANGE_SLUG}\` on branch \`${AGENT_BRANCH}\`. Work inside the existing sandbox, review \`openspec/changes/${CHANGE_SLUG}/tasks.md\`, continue from the current state instead of creating a new sandbox, and when the work is done run \`bash scripts/agent-branch-finish.sh --branch "${AGENT_BRANCH}" --base ${BASE_BRANCH} --via-pr --wait-for-merge --cleanup\`.

## 1. Specification

- [ ] 1.1 Finalize proposal scope and acceptance criteria for \`${CHANGE_SLUG}\`.
Expand All @@ -109,7 +137,7 @@ This change is complete only when **all** of the following are true:

## 4. Cleanup (mandatory; run before claiming completion)

- [ ] 4.1 Run the cleanup pipeline: \`bash scripts/agent-branch-finish.sh --branch ${AGENT_BRANCH} --base dev --via-pr --wait-for-merge --cleanup\`. This handles commit -> push -> PR create -> merge wait -> worktree prune in one invocation.
- [ ] 4.1 Run the cleanup pipeline: \`bash scripts/agent-branch-finish.sh --branch "${AGENT_BRANCH}" --base ${BASE_BRANCH} --via-pr --wait-for-merge --cleanup\`. This handles commit -> push -> PR create -> merge wait -> worktree prune in one invocation.
- [ ] 4.2 Record the PR URL and final merge state (\`MERGED\`) in the completion handoff.
- [ ] 4.3 Confirm the sandbox worktree is gone (\`git worktree list\` no longer shows the agent path; \`git branch -a\` shows no surviving local/remote refs for the branch).
TASKSEOF
Expand Down
26 changes: 26 additions & 0 deletions templates/scripts/codex-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,31 @@ resolve_worktree_base_branch() {
printf 'dev'
}

print_takeover_prompt() {
local wt="$1"
local branch="$2"
local base_branch change_slug change_artifact finish_cmd

base_branch="$(resolve_worktree_base_branch "$wt")"
if [[ -z "$base_branch" ]]; then
base_branch="dev"
fi

change_slug="$(resolve_openspec_change_slug "$branch")"
change_artifact="openspec/changes/${change_slug}/tasks.md"
if [[ ! -f "${wt}/${change_artifact}" ]]; then
change_artifact="openspec/changes/${change_slug}/notes.md"
fi
if [[ ! -f "${wt}/${change_artifact}" ]]; then
change_artifact="openspec/changes/${change_slug}/"
fi

finish_cmd="bash scripts/agent-branch-finish.sh --branch \"${branch}\" --base ${base_branch} --via-pr --wait-for-merge --cleanup"

echo "[codex-agent] Takeover sandbox: ${wt}"
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}\`."
}

sync_worktree_with_base() {
local wt="$1"
if ! has_origin_remote; then
Expand Down Expand Up @@ -952,6 +977,7 @@ else
if [[ "$auto_finish_completed" -eq 1 ]]; then
echo "[codex-agent] Branch kept intentionally. Cleanup on demand: gx cleanup --branch \"${worktree_branch}\""
else
print_takeover_prompt "$worktree_path" "$worktree_branch"
echo "[codex-agent] If finished, merge with: bash scripts/agent-branch-finish.sh --branch \"${worktree_branch}\" --base dev --via-pr --wait-for-merge"
echo "[codex-agent] Cleanup on demand: gx cleanup --branch \"${worktree_branch}\""
fi
Expand Down
32 changes: 30 additions & 2 deletions templates/scripts/openspec/init-change-workspace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,27 @@ if [[ "$CAPABILITY_SLUG" =~ [^a-z0-9-] ]]; then
exit 1
fi

resolve_base_branch() {
local branch="$1"
local base_branch=""

if [[ -n "$branch" ]] && [[ "$branch" != "agent/<your-name>/<branch-slug>" ]]; then
base_branch="$(git config --get "branch.${branch}.guardexBase" || true)"
fi
if [[ -z "$base_branch" ]]; then
base_branch="$(git config --get multiagent.baseBranch || true)"
fi
if [[ -z "$base_branch" ]]; then
base_branch="dev"
fi

printf '%s' "$base_branch"
}

CHANGE_DIR="openspec/changes/${CHANGE_SLUG}"
SPEC_DIR="${CHANGE_DIR}/specs/${CAPABILITY_SLUG}"
TODAY="$(date -u +%Y-%m-%d)"
BASE_BRANCH="$(resolve_base_branch "$AGENT_BRANCH")"

MINIMAL_RAW="${GUARDEX_OPENSPEC_MINIMAL:-0}"
case "$(printf '%s' "$MINIMAL_RAW" | tr '[:upper:]' '[:lower:]')" in
Expand Down Expand Up @@ -53,9 +71,14 @@ Branch: \`${AGENT_BRANCH}\`

Describe the change in a sentence or two. Commit message is the spec of record.

## Handoff

- Handoff: change=\`${CHANGE_SLUG}\`; branch=\`${AGENT_BRANCH}\`; scope=\`TODO\`; action=\`continue this sandbox or finish cleanup after a usage-limit/manual takeover\`.
- Copy prompt: Continue \`${CHANGE_SLUG}\` on branch \`${AGENT_BRANCH}\`. Work inside the existing sandbox, review \`openspec/changes/${CHANGE_SLUG}/notes.md\`, continue from the current state instead of creating a new sandbox, and when the work is done run \`bash scripts/agent-branch-finish.sh --branch "${AGENT_BRANCH}" --base ${BASE_BRANCH} --via-pr --wait-for-merge --cleanup\`.

## Cleanup

- [ ] Run: \`bash scripts/agent-branch-finish.sh --branch ${AGENT_BRANCH} --base dev --via-pr --wait-for-merge --cleanup\`
- [ ] Run: \`bash scripts/agent-branch-finish.sh --branch "${AGENT_BRANCH}" --base ${BASE_BRANCH} --via-pr --wait-for-merge --cleanup\`
- [ ] Record PR URL + \`MERGED\` state in the completion handoff.
- [ ] Confirm sandbox worktree is gone (\`git worktree list\`, \`git branch -a\`).
NOTESEOF
Expand Down Expand Up @@ -91,6 +114,11 @@ This change is complete only when **all** of the following are true:
- The agent branch reaches \`MERGED\` state on \`origin\` and the PR URL + state are recorded in the completion handoff.
- If any step blocks (test failure, conflict, ambiguous result), append a \`BLOCKED:\` line under section 4 explaining the blocker and **STOP**. Do not tick remaining cleanup boxes; do not silently skip the cleanup pipeline.

## Handoff

- Handoff: change=\`${CHANGE_SLUG}\`; branch=\`${AGENT_BRANCH}\`; scope=\`TODO\`; action=\`continue this sandbox or finish cleanup after a usage-limit/manual takeover\`.
- Copy prompt: Continue \`${CHANGE_SLUG}\` on branch \`${AGENT_BRANCH}\`. Work inside the existing sandbox, review \`openspec/changes/${CHANGE_SLUG}/tasks.md\`, continue from the current state instead of creating a new sandbox, and when the work is done run \`bash scripts/agent-branch-finish.sh --branch "${AGENT_BRANCH}" --base ${BASE_BRANCH} --via-pr --wait-for-merge --cleanup\`.

## 1. Specification

- [ ] 1.1 Finalize proposal scope and acceptance criteria for \`${CHANGE_SLUG}\`.
Expand All @@ -109,7 +137,7 @@ This change is complete only when **all** of the following are true:

## 4. Cleanup (mandatory; run before claiming completion)

- [ ] 4.1 Run the cleanup pipeline: \`bash scripts/agent-branch-finish.sh --branch ${AGENT_BRANCH} --base dev --via-pr --wait-for-merge --cleanup\`. This handles commit -> push -> PR create -> merge wait -> worktree prune in one invocation.
- [ ] 4.1 Run the cleanup pipeline: \`bash scripts/agent-branch-finish.sh --branch "${AGENT_BRANCH}" --base ${BASE_BRANCH} --via-pr --wait-for-merge --cleanup\`. This handles commit -> push -> PR create -> merge wait -> worktree prune in one invocation.
- [ ] 4.2 Record the PR URL and final merge state (\`MERGED\`) in the completion handoff.
- [ ] 4.3 Confirm the sandbox worktree is gone (\`git worktree list\` no longer shows the agent path; \`git branch -a\` shows no surviving local/remote refs for the branch).
TASKSEOF
Expand Down
Loading