Guardrailed dispatch of a single GitHub issue to the correct implementation teammate
Follow this process. The issue URL is provided as the first argument (e.g. /dispatch https://github.com/lucas42/lucos_photos/issues/42). An optional owner:{name} argument may follow (e.g. /dispatch https://github.com/lucas42/lucos_photos/issues/42 owner:lucos-developer). If provided, use that owner for dispatch in Step 5 without querying labels or the project board. Do not ask for clarification -- immediately begin.
Extract the repository ({owner}/{repo}) and issue number from the URL. Fetch the issue:
~/sandboxes/lucos_agent/gh-as-agent --app lucos-issue-manager repos/{owner}/{repo}/issues/{number}
Read the full issue body and note the current labels.
Look for references to other issues described as dependencies, prerequisites, or blockers -- including cross-repo references (e.g. ). Check task-list items in a section, prose mentions like "depends on", "blocked by", "requires", or any other phrasing that indicates a prerequisite.
lucas42/other_repo#N## DependenciesFor every issue referenced as a dependency, check whether it is closed:
~/sandboxes/lucos_agent/gh-as-agent --app lucos-issue-manager repos/lucas42/{repo}/issues/{number} --jq '.state'
If any dependency is still open, do not dispatch the issue. Instead, warn the user:
Issue {url} has unresolved dependencies: {list of open dependency URLs}. It should not be implemented yet.
Then stop. Do not proceed further.
If all dependencies are closed (or no dependencies are mentioned), continue.
Check whether a pull request already exists that would close this issue:
~/sandboxes/lucos_agent/gh-as-agent --app lucos-issue-manager repos/lucas42/{repo}/issues/{number}/timeline --jq '[.[] | select(.event == "cross-referenced" and .source.issue.pull_request != null) | {pr_number: .source.issue.number, pr_title: .source.issue.title, pr_state: .source.issue.state, pr_url: .source.issue.html_url}]'
If a PR exists that references the issue and is still open, the work has likely already been done -- the PR just hasn't been merged yet. In that case:
~/sandboxes/lucos_agent/check-unsupervised <repo-name>.If no open PR exists for the issue, continue.
If the issue is on the lucos_repos repository and involves creating or modifying a convention (i.e. the work will change which repos pass or fail an audit convention), this requires the estate-rollout workflow instead of a normal implementation dispatch. Convention changes need to be verified against all repos via the dry-run diff before merging, and affected repos may need migrating.
Read the issue body. If it describes adding a new convention, modifying an existing convention's check logic, or changing what a convention considers passing/failing, use the /estate-rollout skill instead of continuing. Pass the issue context to the skill so it knows what change to make. Then stop -- the estate-rollout skill handles the rest.
More broadly, any issue whose resolution requires the same change to be applied across many repos (enabling a GitHub setting, updating a workflow file, etc.) is an estate rollout, regardless of which repo the issue lives on. Route these to /estate-rollout.
If the issue is not an estate rollout (e.g. it's a bug fix, API change, dashboard change, or infrastructure work), continue.
If an owner:{name} argument was provided (see top of this file), use that directly — skip the lookup below.
Otherwise, look up the owner from the project board (the source of truth for issue ownership). Query the issue's project board item to find the Owner field. If the issue is not on the project board, fall back to checking issue labels for owner:* labels:
~/sandboxes/lucos_agent/gh-as-agent --app lucos-issue-manager repos/lucas42/{repo}/issues/{number} --jq '[.labels[].name | select(startswith("owner:"))] | first'
Extract the teammate name by stripping the owner: prefix (e.g. owner:lucos-developer becomes teammate lucos-developer). Send a message to that teammate using SendMessage, passing the specific issue URL so they know exactly what to work on. For example:
"implement issue https://github.com/lucas42/lucos_photos/issues/42"
Wait for the teammate to respond with the result. The teammate is responsible for driving the PR review loop (see ~/.claude/pr-review-loop.md) before reporting back.
After the teammate reports back, check whether a PR was created and approved. Look for PR URLs (e.g. https://github.com/lucas42/.../pull/N) and approval confirmation in the teammate's response. If no PR was created (e.g. the teammate hit a blocker), report this to the user and stop.
If a PR was created and approved:
Determine the repository name from the PR URL (e.g. lucos_photos from https://github.com/lucas42/lucos_photos/pull/5).
Check whether the repository has unsupervised agent code enabled by running:
~/sandboxes/lucos_agent/check-unsupervised <system-name>
where <system-name> is the repository name (e.g. lucos_photos). Exit code 0 means yes (unsupervised), exit code 1 means no, exit code 2 means error.
Check for issues to unblock (always — regardless of supervised/unsupervised). Search the entire org for open issues with status:blocked that reference the closing issue number in their body or comments. Dependencies can be cross-repo (e.g. an issue on lucos_media_metadata_api blocked by an issue on lucos_media_metadata_manager), so a repo-scoped search is insufficient:
~/sandboxes/lucos_agent/gh-as-agent --app lucos-issue-manager "search/issues?q=org:lucas42+is:open+label:status:blocked+{issue_number}+in:body"
For each result, read the full issue body and comments to confirm it actually references the closing issue as a dependency (not just a casual mention). For confirmed dependents, verify that all their dependencies are resolved before removing status:blocked — not just the one that was just closed.
When unblocking an issue, you MUST do both of the following — removing the label without updating the board is incomplete:
status:blocked label from the issue.3aaf8e5e).Read ~/.claude/references/triage-reference-data.md for the full board API patterns.
If unsupervised (exit code 0):
~/sandboxes/lucos_agent/gh-as-agent --app lucos-issue-manager repos/lucas42/{repo}/commits/{head_sha}/check-runs --jq '{total_count: .total_count, checks: [.check_runs[] | {name: .name, status: .status, conclusion: .conclusion}]}'
Get the head SHA from the PR details (head.sha).
total_count is 0 (no checks created at all) or any check has conclusion: "failure": send the PR back to the developer who created it for investigation. The developer has the most context on the code and likely failure modes -- do not investigate yourself or escalate to SRE. Only if the developer identifies the failure as a pipeline/infrastructure problem (not a code/test issue) should SRE be looped in.~/sandboxes/lucos_agent/gh-as-agent --app lucos-issue-manager repos/lucas42/{repo}/pulls/{pr_number} --jq '{mergeable_state: .mergeable_state, mergeable: .mergeable}'
If mergeable_state is "behind", the branch needs rebasing before auto-merge can fire. Send the PR back to the developer who created it and ask them to rebase onto main and force-push. Wait for the developer to confirm the rebase is done before declaring the task complete.If not unsupervised (exit code 1) or error (exit code 2):