# Unlock Story - Release Story Lock
The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml
You MUST have already loaded and processed: {installed_path}/workflow.yaml
TEAM COORDINATION: Releasing locks makes stories available for others
HALT
Call: mcp__github__get_me()
HALT
current_user = response.login
Call: mcp__github__search_issues({
query: "repo:{{github_owner}}/{{github_repo}} label:story:{{story_key}}"
})
HALT
issue = response.items[0]
issue_number = issue.number
current_assignee = issue.assignee?.login or null
Exit (already unlocked)
HALT
Verify current_user is in scrum_masters list
HALT
Set force_unlock = true
Set notify_owner = true
Set force_unlock = false
ATOMIC UNLOCK with retry:
attempt = 0
max_attempts = 4
WHILE attempt < max_attempts:
TRY:
# 1. Remove assignee
Call: mcp__github__issue_write({
method: "update",
owner: {{github_owner}},
repo: {{github_repo}},
issue_number: {{issue_number}},
assignees: []
})
# 2. Update status label back to ready-for-dev
# Get current labels first
current_labels = issue.labels.map(l => l.name)
# Remove in-progress, add ready-for-dev
new_labels = current_labels
.filter(l => l != "status:in-progress")
# Only add ready-for-dev if story wasn't completed
IF NOT current_labels.includes("status:done"):
new_labels.push("status:ready-for-dev")
Call: mcp__github__issue_write({
method: "update",
owner: {{github_owner}},
repo: {{github_repo}},
issue_number: {{issue_number}},
labels: new_labels
})
# 3. Add unlock comment
comment_body = "🔓 **Story unlocked**\n\n"
IF force_unlock:
comment_body += "Unlocked by Scrum Master @{{current_user}}\n"
comment_body += "Previous owner: @{{current_assignee}}\n"
IF reason:
comment_body += "Reason: {{reason}}\n"
ELSE:
comment_body += "Released by @{{current_user}}\n"
IF reason:
comment_body += "Reason: {{reason}}\n"
comment_body += "\n_Story is now available for checkout._"
Call: mcp__github__add_issue_comment({
owner: {{github_owner}},
repo: {{github_repo}},
issue_number: {{issue_number}},
body: comment_body
})
# 4. Verify unlock
sleep 1 second
verification = Call: mcp__github__issue_read({
method: "get",
owner: {{github_owner}},
repo: {{github_repo}},
issue_number: {{issue_number}}
})
IF verification.assignees.length > 0:
THROW "Unlock verification failed - still has assignees"
output: "✅ GitHub Issue unassigned and verified"
BREAK
CATCH error:
attempt++
IF attempt < max_attempts:
backoff = [1000, 3000, 9000][attempt - 1]
sleep backoff ms
output: "⚠️ Retry {{attempt}}/3: {{error}}"
ELSE:
output: "❌ FAILED to unlock after 3 retries: {{error}}"
output: ""
output: "The lock may still be active in GitHub."
output: "Try again or manually unassign in GitHub UI."
HALT
lock_file = {{lock_dir}}/{{story_key}}.lock
Delete lock_file
Update cache meta to clear lock:
cache_meta = load {{cache_dir}}/.bmad-cache-meta.json
IF cache_meta.stories[{{story_key}}]:
cache_meta.stories[{{story_key}}].locked_by = null
cache_meta.stories[{{story_key}}].locked_until = null
save cache_meta