Skip to content

Commit 139ecae

Browse files
NagyViktNagyVikt
andauthored
Keep shared ralplan lanes identifiable and handoff-ready (#235)
Plan-backed sandboxes now add a masterplan label to the worktree path and plan slug while keeping the branch and change slug stable. The plan scaffold now creates role prompt.md files plus ownership, collaboration, and cleanup-blocking checklist sections, and codex-agent preserves the same naming in both the normal and fallback launch paths. Constraint: Joined agents must reuse the owner worktree without stealing cleanup ownership from the change lane Rejected: Prefix the git branch name itself with masterplan | branch identities stay stable while the worktree and plan workspace carry the planning label Confidence: high Scope-risk: moderate Directive: Keep agent-branch-start, codex-agent, and init-plan-workspace naming logic aligned across runtime and template copies Tested: bash -n scripts/agent-branch-start.sh templates/scripts/agent-branch-start.sh scripts/codex-agent.sh templates/scripts/codex-agent.sh scripts/openspec/init-plan-workspace.sh templates/scripts/openspec/init-plan-workspace.sh; node --test --test-name-pattern "setup agent-branch-start supports optional OpenSpec auto-bootstrap toggles|codex-agent launches codex inside a fresh sandbox worktree and keeps branch/worktree by default|codex-agent restores local branch and falls back to safe worktree start when starter script switches in-place|OpenSpec plan workspace scaffold creates expected role/task structure" test/install.test.js; node --test --test-name-pattern "critical runtime helper scripts stay in sync with templates" test/metadata.test.js; node --test --test-name-pattern "merge branches replays non-conflicting changes onto a dedicated target lane" test/merge-workflow.test.js; openspec validate agent-codex-ralplan-masterplan-role-prompts-and-owne-2026-04-21-14-48 --type change --strict; openspec validate --specs Not-tested: live GitHub PR merge flow before this commit Co-authored-by: NagyVikt <nagy.viktordp@gmail.com>
1 parent bcecd9c commit 139ecae

13 files changed

Lines changed: 391 additions & 17 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-04-21
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
## Why
2+
3+
- Ralplan-created planning lanes need a visible `masterplan` identity in the
4+
sandbox worktree and OpenSpec plan folder so the owner branch is easy to find
5+
in VS Code and hand off to joined agents.
6+
- Plan role folders need copyable prompts and explicit ownership/completion
7+
checklists so helpers can reuse the same owner worktree instead of spinning up
8+
unrelated branches.
9+
10+
## What Changes
11+
12+
- Prefix plan-backed worktree and plan-workspace identities with
13+
`masterplan` while leaving branch names and change slugs stable.
14+
- Extend the plan scaffold so each role gets a default `prompt.md` plus
15+
ownership, collaboration, and cleanup-blocking checklist items.
16+
- Keep `codex-agent.sh` aligned with the new naming so both the normal launch
17+
path and the fallback sandbox path preserve the same `masterplan` labeling.
18+
19+
## Impact
20+
21+
- Touches Guardex runtime/template helper scripts and their regression suite.
22+
- Existing branches are unaffected; only newly created plan-backed sandboxes get
23+
the new worktree/plan naming.
24+
- Cleanup still stays on the owner change lane; role prompts now make that
25+
explicit for joined helpers.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
## ADDED Requirements
2+
3+
### Requirement: Plan-backed sandboxes expose a masterplan identity
4+
GuardeX plan-backed sandboxes SHALL include a `masterplan` label in the
5+
generated worktree path and OpenSpec plan workspace slug whenever OpenSpec plan
6+
bootstrap is enabled.
7+
8+
#### Scenario: agent-branch-start auto-bootstraps a shared planning lane
9+
- **GIVEN** `scripts/agent-branch-start.sh` runs with `GUARDEX_OPENSPEC_AUTO_INIT=true`
10+
- **WHEN** it creates the sandbox worktree and OpenSpec plan slug
11+
- **THEN** the worktree path includes `agent__<role>__masterplan__`
12+
- **AND** the plan folder slug starts with `agent-<role>-masterplan-`
13+
- **AND** the change slug remains based on the original branch name.
14+
15+
### Requirement: Plan role folders ship with shareable helper prompts
16+
Guardex plan workspaces SHALL scaffold each role folder with a default
17+
`prompt.md` and ownership-oriented checklist sections so joined Codex helpers
18+
can work inside the same owner branch/worktree safely.
19+
20+
#### Scenario: init-plan-workspace scaffolds role collaboration defaults
21+
- **GIVEN** the user runs `scripts/openspec/init-plan-workspace.sh <plan-slug>`
22+
- **WHEN** role folders are created for `planner`, `architect`, `critic`,
23+
`executor`, `writer`, and `verifier`
24+
- **THEN** each role folder includes `prompt.md`
25+
- **AND** each role `tasks.md` includes ownership, collaboration, and completion
26+
guidance in addition to the visible Spec/Tests/Implementation/Checkpoints sections
27+
- **AND** the prompt instructs helpers to claim files in the owner lane and to
28+
leave cleanup to the owner change tasks 4.1-4.3.
29+
30+
### Requirement: codex-agent preserves masterplan labeling across safe fallback
31+
`scripts/codex-agent.sh` SHALL preserve the same `masterplan` worktree/plan
32+
labeling whether sandbox creation uses `agent-branch-start.sh` directly or the
33+
safe fallback path.
34+
35+
#### Scenario: codex-agent falls back after an unsafe starter
36+
- **GIVEN** the starter script switches the primary checkout or otherwise fails
37+
the safe sandbox checks
38+
- **WHEN** `scripts/codex-agent.sh` creates the sandbox directly
39+
- **THEN** the fallback worktree path still includes `agent__<role>__masterplan__`
40+
- **AND** the fallback OpenSpec plan slug still starts with `agent-<role>-masterplan-`.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## 1. Specification
2+
3+
- [x] 1.1 Finalize proposal scope and acceptance criteria for `agent-codex-ralplan-masterplan-role-prompts-and-owne-2026-04-21-14-48`.
4+
- [x] 1.2 Define normative requirements in `specs/ralplan-masterplan/spec.md`.
5+
6+
## 2. Implementation
7+
8+
- [x] 2.1 Implement scoped behavior changes.
9+
- [x] 2.2 Add/update focused regression coverage.
10+
11+
## 3. Verification
12+
13+
- [x] 3.1 Run targeted project verification commands.
14+
- [x] 3.2 Run `openspec validate agent-codex-ralplan-masterplan-role-prompts-and-owne-2026-04-21-14-48 --type change --strict`.
15+
- [x] 3.3 Run `openspec validate --specs`.
16+
17+
Verification evidence:
18+
- `bash -n scripts/agent-branch-start.sh templates/scripts/agent-branch-start.sh scripts/codex-agent.sh templates/scripts/codex-agent.sh scripts/openspec/init-plan-workspace.sh templates/scripts/openspec/init-plan-workspace.sh`
19+
- `node --test --test-name-pattern "setup agent-branch-start supports optional OpenSpec auto-bootstrap toggles|codex-agent launches codex inside a fresh sandbox worktree and keeps branch/worktree by default|codex-agent restores local branch and falls back to safe worktree start when starter script switches in-place|OpenSpec plan workspace scaffold creates expected role/task structure" test/install.test.js`
20+
- `node --test --test-name-pattern "critical runtime helper scripts stay in sync with templates" test/metadata.test.js`
21+
- `node --test --test-name-pattern "merge branches replays non-conflicting changes onto a dedicated target lane" test/merge-workflow.test.js`
22+
- `openspec validate agent-codex-ralplan-masterplan-role-prompts-and-owne-2026-04-21-14-48 --type change --strict`
23+
- `openspec validate --specs` -> exit 0 with `No items found to validate.`
24+
25+
## 4. Completion
26+
27+
- [ ] 4.1 Finish the agent branch via PR merge + cleanup (`gx finish --via-pr --wait-for-merge --cleanup` or `bash scripts/agent-branch-finish.sh --branch <agent-branch> --base <base-branch> --via-pr --wait-for-merge --cleanup`).
28+
- [ ] 4.2 Record PR URL + final `MERGED` state in the completion handoff.
29+
- [ ] 4.3 Confirm sandbox cleanup (`git worktree list`, `git branch -a`) or capture a `BLOCKED:` handoff if merge/cleanup is pending.

scripts/agent-branch-start.sh

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ OPENSPEC_AUTO_INIT_RAW="${GUARDEX_OPENSPEC_AUTO_INIT:-false}"
1111
OPENSPEC_PLAN_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_PLAN_SLUG:-}"
1212
OPENSPEC_CHANGE_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_CHANGE_SLUG:-}"
1313
OPENSPEC_CAPABILITY_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_CAPABILITY_SLUG:-}"
14+
OPENSPEC_MASTERPLAN_LABEL_RAW="${GUARDEX_OPENSPEC_MASTERPLAN_LABEL-masterplan}"
1415
PRINT_NAME_ONLY=0
1516
POSITIONAL_ARGS=()
1617

@@ -226,13 +227,35 @@ normalize_bool() {
226227

227228
OPENSPEC_AUTO_INIT="$(normalize_bool "$OPENSPEC_AUTO_INIT_RAW" "1")"
228229

230+
resolve_openspec_masterplan_label() {
231+
local raw="${OPENSPEC_MASTERPLAN_LABEL_RAW:-}"
232+
local label
233+
234+
if [[ "$OPENSPEC_AUTO_INIT" -ne 1 ]] || [[ -z "$raw" ]]; then
235+
printf ''
236+
return 0
237+
fi
238+
239+
label="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-{2,}/-/g')"
240+
printf '%s' "$label"
241+
}
242+
229243
resolve_openspec_plan_slug() {
230244
local branch_name="$1"
231-
local task_slug="$2"
245+
local agent_slug="$2"
246+
local task_slug="$3"
247+
local masterplan_label=""
248+
local branch_leaf=""
232249
if [[ -n "$OPENSPEC_PLAN_SLUG_OVERRIDE" ]]; then
233250
sanitize_slug "$OPENSPEC_PLAN_SLUG_OVERRIDE" "$task_slug"
234251
return 0
235252
fi
253+
masterplan_label="$(resolve_openspec_masterplan_label)"
254+
if [[ -n "$masterplan_label" ]] && [[ "$branch_name" == "agent/${agent_slug}/"* ]]; then
255+
branch_leaf="${branch_name#agent/${agent_slug}/}"
256+
sanitize_slug "agent-${agent_slug}-${masterplan_label}-${branch_leaf}" "$task_slug"
257+
return 0
258+
fi
236259
sanitize_slug "${branch_name//\//-}" "$task_slug"
237260
}
238261

@@ -255,6 +278,22 @@ resolve_openspec_capability_slug() {
255278
sanitize_slug "$task_slug" "general-behavior"
256279
}
257280

281+
resolve_worktree_leaf() {
282+
local branch_name="$1"
283+
local agent_slug="$2"
284+
local masterplan_label=""
285+
local branch_leaf=""
286+
287+
masterplan_label="$(resolve_openspec_masterplan_label)"
288+
if [[ -n "$masterplan_label" ]] && [[ "$branch_name" == "agent/${agent_slug}/"* ]]; then
289+
branch_leaf="${branch_name#agent/${agent_slug}/}"
290+
printf 'agent__%s__%s__%s' "$agent_slug" "$masterplan_label" "$branch_leaf"
291+
return 0
292+
fi
293+
294+
printf '%s' "${branch_name//\//__}"
295+
}
296+
258297
has_local_changes() {
259298
local root="$1"
260299
if ! git -C "$root" diff --quiet; then
@@ -497,8 +536,9 @@ done
497536

498537
worktree_root="${repo_root}/${WORKTREE_ROOT_REL}"
499538
mkdir -p "$worktree_root"
500-
worktree_path="${worktree_root}/${branch_name//\//__}"
501-
openspec_plan_slug="$(resolve_openspec_plan_slug "$branch_name" "$task_slug")"
539+
worktree_leaf="$(resolve_worktree_leaf "$branch_name" "$agent_slug")"
540+
worktree_path="${worktree_root}/${worktree_leaf}"
541+
openspec_plan_slug="$(resolve_openspec_plan_slug "$branch_name" "$agent_slug" "$task_slug")"
502542
openspec_change_slug="$(resolve_openspec_change_slug "$branch_name" "$task_slug")"
503543
openspec_capability_slug="$(resolve_openspec_capability_slug "$task_slug")"
504544

scripts/codex-agent.sh

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ OPENSPEC_AUTO_INIT_RAW="${GUARDEX_OPENSPEC_AUTO_INIT:-true}"
1414
OPENSPEC_PLAN_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_PLAN_SLUG:-}"
1515
OPENSPEC_CHANGE_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_CHANGE_SLUG:-}"
1616
OPENSPEC_CAPABILITY_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_CAPABILITY_SLUG:-}"
17+
OPENSPEC_MASTERPLAN_LABEL_RAW="${GUARDEX_OPENSPEC_MASTERPLAN_LABEL-masterplan}"
1718

1819
normalize_bool() {
1920
local raw="${1:-}"
@@ -34,6 +35,19 @@ AUTO_CLEANUP="$(normalize_bool "$AUTO_CLEANUP_RAW" "1")"
3435
AUTO_WAIT_FOR_MERGE="$(normalize_bool "$AUTO_WAIT_FOR_MERGE_RAW" "1")"
3536
OPENSPEC_AUTO_INIT="$(normalize_bool "$OPENSPEC_AUTO_INIT_RAW" "1")"
3637

38+
resolve_openspec_masterplan_label() {
39+
local raw="${OPENSPEC_MASTERPLAN_LABEL_RAW:-}"
40+
local label
41+
42+
if [[ "$OPENSPEC_AUTO_INIT" -ne 1 ]] || [[ -z "$raw" ]]; then
43+
printf ''
44+
return 0
45+
fi
46+
47+
label="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-{2,}/-/g')"
48+
printf '%s' "$label"
49+
}
50+
3751
if [[ -n "$BASE_BRANCH" ]]; then
3852
BASE_BRANCH_EXPLICIT=1
3953
fi
@@ -161,11 +175,21 @@ sanitize_slug() {
161175
resolve_openspec_plan_slug() {
162176
local branch_name="$1"
163177
local task_slug
178+
local masterplan_label=""
179+
local branch_role=""
180+
local branch_leaf=""
164181
task_slug="$(sanitize_slug "$TASK_NAME" "task")"
165182
if [[ -n "$OPENSPEC_PLAN_SLUG_OVERRIDE" ]]; then
166183
sanitize_slug "$OPENSPEC_PLAN_SLUG_OVERRIDE" "$task_slug"
167184
return 0
168185
fi
186+
masterplan_label="$(resolve_openspec_masterplan_label)"
187+
if [[ -n "$masterplan_label" ]] && [[ "$branch_name" =~ ^agent/([^/]+)/(.+)$ ]]; then
188+
branch_role="${BASH_REMATCH[1]}"
189+
branch_leaf="${BASH_REMATCH[2]}"
190+
sanitize_slug "agent-${branch_role}-${masterplan_label}-${branch_leaf}" "$task_slug"
191+
return 0
192+
fi
169193
sanitize_slug "${branch_name//\//-}" "$task_slug"
170194
}
171195

@@ -190,6 +214,23 @@ resolve_openspec_capability_slug() {
190214
sanitize_slug "$task_slug" "general-behavior"
191215
}
192216

217+
resolve_worktree_leaf() {
218+
local branch_name="$1"
219+
local masterplan_label=""
220+
local branch_role=""
221+
local branch_leaf=""
222+
223+
masterplan_label="$(resolve_openspec_masterplan_label)"
224+
if [[ -n "$masterplan_label" ]] && [[ "$branch_name" =~ ^agent/([^/]+)/(.+)$ ]]; then
225+
branch_role="${BASH_REMATCH[1]}"
226+
branch_leaf="${BASH_REMATCH[2]}"
227+
printf 'agent__%s__%s__%s' "$branch_role" "$masterplan_label" "$branch_leaf"
228+
return 0
229+
fi
230+
231+
printf '%s' "${branch_name//\//__}"
232+
}
233+
193234
hydrate_local_helper_in_worktree() {
194235
local worktree="$1"
195236
local relative_path="$2"
@@ -314,7 +355,7 @@ start_sandbox_fallback() {
314355

315356
worktree_root="${repo_root}/.omx/agent-worktrees"
316357
mkdir -p "$worktree_root"
317-
worktree_path="${worktree_root}/${branch_name//\//__}"
358+
worktree_path="${worktree_root}/$(resolve_worktree_leaf "$branch_name")"
318359
if [[ -e "$worktree_path" ]]; then
319360
echo "[codex-agent] Fallback worktree path already exists: $worktree_path" >&2
320361
return 1
@@ -346,7 +387,11 @@ initial_repo_branch="$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/nu
346387
start_output=""
347388
start_status=0
348389
set +e
349-
start_output="$(GUARDEX_OPENSPEC_AUTO_INIT=0 bash "${repo_root}/scripts/agent-branch-start.sh" "${start_args[@]}" 2>&1)"
390+
start_output="$(
391+
GUARDEX_OPENSPEC_AUTO_INIT="$OPENSPEC_AUTO_INIT" \
392+
GUARDEX_OPENSPEC_MASTERPLAN_LABEL="$OPENSPEC_MASTERPLAN_LABEL_RAW" \
393+
bash "${repo_root}/scripts/agent-branch-start.sh" "${start_args[@]}" 2>&1
394+
)"
350395
start_status=$?
351396
set -e
352397

scripts/openspec/init-plan-workspace.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ write_if_missing "$PLAN_DIR/README.md" "# Plan Workspace: ${PLAN_SLUG}
5454
5555
Durable pre-implementation planning workspace.
5656
57+
Each role folder includes a copyable \`prompt.md\` for joined Codex helpers.
58+
Helpers reuse the owner branch/worktree, claim the role files they touch, and
59+
leave PR merge + sandbox cleanup to the owner change lane.
60+
5761
Use this command to update checkpoints:
5862
5963
\`\`\`bash
@@ -89,10 +93,39 @@ for role in "${ROLES[@]}"; do
8993
write_if_missing "$ROLE_DIR/README.md" "# ${role}
9094
9195
Role workspace for \`${role}\`.
96+
"
97+
98+
write_if_missing "$ROLE_DIR/prompt.md" "# ${role} prompt
99+
100+
You are the \`${role}\` lane for shared plan \`${PLAN_SLUG}\`.
101+
102+
## Scope
103+
104+
- Work inside \`openspec/plan/${PLAN_SLUG}/${role}/\` plus directly-related shared plan files you explicitly claim.
105+
- Reuse the owner's branch/worktree instead of creating a separate sandbox unless the owner says otherwise.
106+
107+
## Ownership
108+
109+
- Before editing, claim this role's files in the shared owner lane:
110+
\`python3 scripts/agent-file-locks.py claim --branch <owner-branch> openspec/plan/${PLAN_SLUG}/${role}/README.md openspec/plan/${PLAN_SLUG}/${role}/prompt.md openspec/plan/${PLAN_SLUG}/${role}/tasks.md openspec/plan/${PLAN_SLUG}/checkpoints.md\`
111+
- Record branch, worktree, and scope in \`tasks.md\`.
112+
- Do not change another role's files without reassignment.
113+
114+
## Deliverables
115+
116+
- Complete the role checklist in \`tasks.md\`.
117+
- Leave a handoff with files changed, verification, and risks.
118+
- The owner alone runs the change completion flow and sandbox cleanup after change tasks 4.1-4.3 are done.
92119
"
93120

94121
write_if_missing "$ROLE_DIR/tasks.md" "# ${role} tasks
95122
123+
## Ownership
124+
125+
- [ ] Claim this role's files in the shared owner branch/worktree before editing.
126+
- [ ] Record branch, worktree, and scope for this role.
127+
- [ ] Copy or hand off \`prompt.md\` when another agent joins this role.
128+
96129
## 1. Spec
97130
98131
- [ ] Define requirements and scope for ${role}
@@ -111,6 +144,15 @@ Role workspace for \`${role}\`.
111144
## 4. Checkpoints
112145
113146
- [ ] Publish checkpoint update for this role
147+
148+
## 5. Collaboration
149+
150+
- [ ] Leave a role handoff with files changed, verification, and risks.
151+
- [ ] Owner records \`accept\`, \`revise\`, or \`reject\` for joined output, or marks \`N/A\` if no helper joined.
152+
153+
## 6. Completion
154+
155+
- [ ] Keep sandbox cleanup blocked until change tasks 4.1-4.3 are complete.
114156
"
115157
done
116158

0 commit comments

Comments
 (0)