From agentic-development-workflow
Archives OpenSpec changes, commits them, and removes the workspace after a PR is merged. The final step in the feature lifecycle.
How this skill is triggered — by the user, by Claude, or both
Slash command
/agentic-development-workflow:wrapThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Post-merge archive and workspace cleanup. Run this on the **integration branch** (`$BASE` — `main` in single-branch mode, `develop` in two-branch mode; see [git-ref](../git-ref/SKILL.md) → "Integration Branch") after the PR merges to archive the OpenSpec change and clean up the workspace.
Post-merge archive and workspace cleanup. Run this on the integration branch ($BASE — main in single-branch mode, develop in two-branch mode; see git-ref → "Integration Branch") after the PR merges to archive the OpenSpec change and clean up the workspace.
Where this fits:
/aep-onboard → /aep-scaffold → [ /aep-design → /aep-launch → /aep-build → /aep-wrap ]
▲ you are here
Session: Main session, post-merge Input: Merged PR notification Output: Archived OpenSpec change, cleaned up workspace
Run on the integration branch (
$BASE) after the PR merges. Do not run from the workspace.
# Resolve $BASE — see git-ref "Integration Branch" (override → develop → main)
BASE=$(git config --get aep.integration-branch 2>/dev/null || true)
[ -z "$BASE" ] && { git show-ref --verify --quiet refs/heads/develop \
|| git show-ref --verify --quiet refs/remotes/origin/develop; } && BASE=develop
BASE=${BASE:-main}
git fetch origin
git checkout "$BASE"
git pull --ff-only origin "$BASE"
git status
Update the local integration branch to include the merged workspace PR.
--ff-onlyis intentional — if it fails because$BASEhas unpushed local commits, push or rebase those first.After this checkout you are on the integration branch; later steps recover its name with
BASE=$(git branch --show-current)(HEAD persists across shells, so this is safe even in a fresh command).Check for lost OpenSpec changes: If the dispatch commit included OpenSpec changes that are now missing (common if the dispatch commit wasn't pushed before launching), recover them from the original dispatch commit:
# Find the original dispatch commit git log --oneline -n 20 # Restore OpenSpec files from the dispatch commit git restore --source=<dispatch-commit-sha> -- openspec/Verify the workspace is clean before archiving. If
git statusshows unexpected modified files (code inapps/,packages/, etc.), investigate before proceeding. Onlyopenspec/andproduct-context.yamlfiles should change during the wrap step.
source .feature-workspaces/<name>/.dev-workflow/ports.env 2>/dev/null
lsof -ti :$SERVER_PORT | xargs kill 2>/dev/null
lsof -ti :$WEB_PORT | xargs kill 2>/dev/null
/opsx:archive <change-name>
BASE=$(git branch --show-current) # integration branch, checked out in step 1
git add openspec/
git commit -m "chore: archive <change-name>"
git pull --ff-only origin "$BASE"
git push origin "$BASE"
Standalone mode: If
product-context.yamldoesn't exist, skip this step and proceed to step 6.
If product-context.yaml exists and this feature was a dispatched story, read the workspace signals and cross-check against the actual PR state:
# Read completion data from workspace signals
cat .feature-workspaces/<name>/.dev-workflow/signals/status.json
# Cross-check: verify actual PR state (signals can be stale)
gh pr view <pr-number> --json state,mergedAt
Signal validation: Workspace agents don't always update their signal files after merge (they may show
in_revieweven though the PR is already merged). Always cross-check the signal'sstory_statusagainst the actual PR state viagh pr view. If the PR is merged but the signal saysin_review, treat the story ascompleted.
From the signal file (corrected by PR state if needed), extract story_status, pr_url, cost_usd, completed_at, and failure_log (if present). Update the story in product-context.yaml:
# Update the matching story:
status: completed # from signal story_status
completed_at: <timestamp> # from signal completed_at
pr_url: <url> # from signal pr_url
cost_usd: <cost> # from signal cost_usd
If story_status is failed, update with failure data instead:
status: failed
failure_logs:
- <structured failure_log from signal>
After updating the story, check if any pending stories should transition to ready (all dependencies now completed). Validate and commit all transitions atomically:
# Validate YAML before committing (see product-context references/yaml-guardrails.md)
npx js-yaml product-context.yaml > /dev/null && echo "YAML OK"
BASE=$(git branch --show-current) # integration branch, checked out in step 1
git add product-context.yaml
git commit -m "chore: update story <id> status to completed"
git pull --ff-only origin "$BASE"
git push origin "$BASE"
Concurrency protocol: This is the only place where story completion status enters
product-context.yaml. Workspace agents write to signals;/aep-wrap(running on the integration branch) reads signals and writes to YAML.
Before forgetting the workspace, check for lessons captured during the build:
LESSONS=".feature-workspaces/<name>/.dev-workflow/lessons.md"
if [ -f "$LESSONS" ] && [ "$(wc -l < "$LESSONS")" -gt 12 ]; then
# File has content beyond the template header
mkdir -p lessons-learned
cp "$LESSONS" "lessons-learned/<change-name>.md"
BASE=$(git branch --show-current) # integration branch, checked out in step 1
git add lessons-learned/<change-name>.md
git commit -m "docs: archive lessons from <change-name>"
git pull --ff-only origin "$BASE"
git push origin "$BASE"
fi
Why before worktree removal: Once
git worktree removeruns, the worktree directory and its.dev-workflow/lessons.mdare gone. This is the only chance to extract them.
If the lessons file contains only the template header (no Solutions, Errors, Missing, or Summary entries), skip — don't archive empty ceremony.
executor.teardown())Stop the workspace's worker before removing the worktree — otherwise an
OS-bound worker keeps running against a deleted directory, and these orphans
accumulate across an autopilot run. The stop step is per launch mode (recorded
as backend/agent_id in autopilot state, or evident from how you launched):
# Mode-specific worker stop (each is a no-op for the other modes):
# native-bg-subagent → TaskStop(<bare-hex bg-subagent id>) (session-bound, no team)
# claude-bg → claude stop <agent_id>; claude rm <agent_id>
# codex-subagent → close_agent(<agent_id>) if still running
# codex-exec → nothing to kill (the exec process exited with the build)
# legacy → tmux kill-session -t <name> 2>/dev/null || true
git worktree remove .feature-workspaces/<name> \
|| git worktree remove --force .feature-workspaces/<name> # --force only if leftover files block removal
git worktree prune
git branch -d feat/<name> # PR was merged → branch is reachable from the integration branch, safe to delete
If git branch -d warns the branch isn't fully merged (e.g., the PR was squash-merged so commit SHAs differ), force with git branch -D feat/<name> after confirming via gh pr view <number> --json state that the PR is MERGED.
/opsx:archive from a workspace — it writes to openspec/specs/ and causes conflicts when parallel workspaces are active. Archive always runs on the integration branch ($BASE).git fetch && git pull --ff-only, run git status to verify no unexpected files are modified.openspec/changes/<name>/ is missing, the dispatch commit may have been lost. Recover from the original dispatch commit using git restore --source=<sha> before running archive.in_review after PR is merged). Always verify via gh pr view before updating product-context.yaml.git worktree remove runs, the worktree directory, signal files, and lessons.md are gone. Extract all needed data (status, lessons) first.Standalone mode: If
product-context.yamldoesn't exist, skip the layer gate check. You can still run/aep-reflectif you want to classify observations.
After archiving, check the product context:
If product-context.yaml exists and this feature was a dispatched story:
# Check: was this the last story in the current layer?
# Read product-context.yaml and check if all stories in the active layer are completed
If all stories in the current layer are completed:
layer_gates section of the YAML)layer_gates[layer].status: passed and completed_at/aep-dispatch will advance to the next layerConsider running /aep-reflect to classify observations from this feature and update the product context:
/aep-reflect
This closes the feedback loop — bugs, refinements, and discoveries get routed back to the right phase.
Pick the next story from the dispatch queue:
/aep-dispatch
Or classify feedback from the feature you just shipped:
/aep-reflect
npx claudepluginhub memorysaver/agentic-engineering-patterns --plugin agentic-development-workflowProvides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.