一键导入
legion-worker
Use when dispatched by Legion controller to work on an issue in a jj workspace
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when dispatched by Legion controller to work on an issue in a jj workspace
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when subscribing sessions to Envoy topics, sending agent-to-agent messages, or reasoning about topic formats for Slack/GitHub/agent routing.
Use when coordinating Legion workers across issues, dispatching workers, monitoring progress, or routing triage items
OpenCode serve HTTP API reference. Use when interacting with sessions, reading messages/todos, aborting workers, managing workspaces, or any direct OpenCode serve API call. Each `opencode serve` process is independent with its own port; Legion runs one shared serve per daemon (default port 13381, may differ if multiple daemons coexist on the host).
Capture learnings from completed work via dual-perspective retrospective. Invoked by resuming an implement worker session — the implementer has full context, and a fresh subagent provides an outside view.
Manage GitHub issues via Projects V2. Use when LEGION_ISSUE_BACKEND=github.
Research institutional knowledge before escalating questions to users. Check docs/solutions/ and codebase patterns before asking humans.
| name | legion-worker |
| description | Use when dispatched by Legion controller to work on an issue in a jj workspace |
Router skill for Legion issue work. Dispatched by controller with a mode parameter.
The controller dispatches you with a prompt that includes your issue ID, mode, and backend:
/legion-worker implement mode for acme-widgets-42 (github backend, repo: acme/widgets)/legion-worker plan mode for ENG-21 (linear backend)Extract these values from the prompt. For GitHub issues, also derive the owner, repo,
and issue number from the issue ID (format: owner-repo-number).
Throughout this skill and its workflows, $LEGION_ISSUE_ID, $ISSUE_NUMBER, $OWNER, and
$REPO are placeholders — substitute the values you extracted from your prompt context.
Use the backend from your prompt to choose GitHub CLI or Linear MCP commands.
gh issue view $ISSUE_NUMBER --json title,body,labels,comments,state -R $OWNER/$REPOlinear_linear(action="get", id="$LEGION_ISSUE_ID")worker-done label, remove worker-active label. If you skip this, the issue silently stalls. Create a todo for this at session start (see Required Startup Todos below).
4.5. Write handoff data before signaling. Each workflow has a handoff write step — you MUST complete it and confirm .legion/$MODE.json exists before adding worker-done. If the file is missing, stop, diagnose the failure (for example: legion missing from PATH or wrong --workspace), and do not signal completion until the failure is fixed or explicitly documented in your exit comment.worker-active label when exiting (done or blocked)worker-done, send exactly one completion notification so the controller doesn't have to wait for its next polling cycle. Use envoy_publish(topic="notifications.role.legion-controller", message="Worker done: <issue> <mode> <outcome>"). If envoy_publish fails, that's fine — the label is the source of truth.timeout_seconds (typically 180s). If the subagent times out or fails, skip that step and continue with the workflow. Your primary obligation is to complete the workflow and signal worker-done. Subagent steps are quality improvements, not hard prerequisites — the downstream human/bot review is the authoritative quality gate.# Run long command in background tmux session
tmux new-session -d -s <name> '<command>'
# Monitor progress
tmux capture-pane -t <name> -p | tail -20
# Check if still running
tmux has-session -t <name> 2>/dev/null && echo "running" || echo "done"
Never run bun run serve, pulumi up, long test suites, or similar commands directly in bash.You are executing work with an approved plan. Do NOT invoke the brainstorming or writing-plans skills — your workflow has already been designed. Follow your assigned workflow file. The individual skills referenced in your workflow (TDD, subagent-driven-development, etc.) are appropriate to load and use.
jj new to create isolated commits. Never jj edit @- to go back to a parent — this changes what @ points to and makes jj abandon dangerous.jj abandon without first running jj log to verify what @ is. Abandoning the wrong commit destroys all changes on it.jj op restore recovers the last operation.jj log -r 'ancestors(@, 5)' — verify only your issue's commits are in the chain, not unrelated work.Sync with main and create a fresh commit on your branch:
jj git fetch
jj rebase -d main
jj new # Fresh commit for this session
Orient yourself in the workspace:
jj-agent-status # Shows branches, bookmark state, other agents, needs-attention items
Load repo-specific config from workspace root (if present):
if [ -f .legion/config.yml ]; then cat .legion/config.yml; fi
Then:
Fetch per-worker environment variables from the daemon (non-blocking):
# Fetch and export per-worker env vars (requires LEGION_DAEMON_PORT)
# ISSUE_ID and MODE are extracted from your dispatch prompt (see "Context from Prompt" above).
# Example: dispatched with "implement mode for sjawhar-legion-106" → ISSUE_ID=sjawhar-legion-106, MODE=implement
if [ -n "$LEGION_DAEMON_PORT" ]; then
_WORKER_ID="$(echo "${ISSUE_ID}-${MODE}" | tr '[:upper:]' '[:lower:]')"
_ENV_FILE=$(mktemp) && \
curl -fsS "http://127.0.0.1:$LEGION_DAEMON_PORT/workers/$_WORKER_ID/env" 2>/dev/null \
| jq -r '.env // {} | to_entries[] | "export " + .key + "=" + (.value | @sh)' \
> "$_ENV_FILE" && \
. "$_ENV_FILE"; \
rm -f "$_ENV_FILE"
fi
The daemon stores per-worker env vars passed via legion dispatch --env '{"KEY":"VALUE"}'.
This step retrieves them so tools like gh and jj see role-specific credentials. If the
endpoint is unavailable or returns empty, the worker proceeds with the shared process environment.
Optionally read prior handoff data (advisory, non-blocking):
legion handoff read --workspace . 2>/dev/null || echo '{}'
Prior phase data (from architect, plan, implement, etc.) is available in .legion/ on this branch. Reading it is optional — individual workflow files handle phase-specific handoff reads. This note is a reminder that this data exists. Never block on missing handoff data.
If you're resuming after user feedback, also read the issue comments for the answer.
If you previously created a PR, re-subscribe to PR topics: envoy_subscribe(["notifications.github.$OWNER.$REPO.pr.$PR_NUMBER.>"]) (the daemon re-subscribes you to issue topics automatically on resume).
Before starting any workflow work, create these todos (adapt the signal todo to your mode):
Write handoff data: complete the workflow handoff write and verify .legion/$MODE.json exists before signaling completionpending until the handoff file exists on diskSignal completion: push changes, unsubscribe from Envoy topics, add worker-done label, remove worker-active label, notify controller via Envoypending until you have actually run the label commands and verified they succeededThe signal completion todo ensures you never finish a session without updating labels. If you are about to stop or exit for any reason, check whether this todo is still pending — if so, do it now.
Before escalating to humans, always invoke /legion-oracle [your question] to search institutional knowledge (docs/solutions/, codebase patterns, past issue resolutions). Oracle answers 62% of questions without human help.
Example: /legion-oracle How does the controller handle cross-mode cleanup for envoyTopics?
Only proceed to the escalation flow below if oracle cannot answer or the answer is insufficient.
When you need human input that the oracle can't answer:
jj git pushGitHub:
gh issue comment $ISSUE_NUMBER --body "## Escalation
**Phase:** [current mode - architect/plan/implement/review]
**Completed:** [what work has been done so far]
### Blocker
[Specific question or decision needed — be precise]
### Options Considered
1. [Option A] — [trade-offs]
2. [Option B] — [trade-offs]
3. [Option C if applicable]
### Context
- **Remaining estimate:** [rough scope of remaining work after unblock]
- **Expertise needed:** [domain knowledge required to answer, e.g. 'product decision', 'API design', 'infrastructure']
- **Branch:** [current branch name if applicable]" -R $OWNER/$REPO
Linear:
linear_linear(action="comment", id=$LEGION_ISSUE_ID, body="## Escalation
**Phase:** [current mode - architect/plan/implement/review]
**Completed:** [what work has been done so far]
### Blocker
[Specific question or decision needed — be precise]
### Options Considered
1. [Option A] — [trade-offs]
2. [Option B] — [trade-offs]
3. [Option C if applicable]
### Context
- **Remaining estimate:** [rough scope of remaining work after unblock]
- **Expertise needed:** [domain knowledge required to answer, e.g. 'product decision', 'API design', 'infrastructure']
- **Branch:** [current branch name if applicable]")
user-input-needed, remove worker-activeenvoy_publish(topic="notifications.role.legion-controller", message="Worker blocked: $ISSUE_NUMBER [current mode] needs user input")
If envoy_publish fails, continue — the label is the source of truth.The controller will resume your session when the user responds.
Before pushing, verify the required handoff file exists for modes that write handoff data:
if printf '%s\n' architect plan implement test review | grep -qx "$MODE"; then
if [ ! -f ".legion/${MODE}.json" ]; then
echo "FATAL: Missing required handoff file .legion/${MODE}.json"
echo "STOP: Do NOT push or signal worker-done. Return to the workflow handoff step and diagnose the failure."
echo "If the write cannot be fixed, document the failure in your exit comment before signaling completion."
fi
fi
Always push before exiting:
jj git push
Then unsubscribe from explicit issue and PR topics (best-effort, non-blocking).
IMPORTANT: Use explicit topic list, NOT empty-array unsubscribe — empty array would
also remove notifications.agent.{sessionId} and create a delivery gap before daemon cleanup.
# Unsubscribe from issue and PR topics (substitute your actual values)
envoy_unsubscribe([
"notifications.github.$OWNER.$REPO.issue.$ISSUE_NUMBER.>",
"notifications.github.$OWNER.$REPO.pr.$PR_NUMBER.>" # only if a PR was created
])
If envoy_unsubscribe fails, continue — the daemon's DELETE /workers is the authoritative cleanup.
Then update labels:
worker-done if your mode requires it (see routing table)worker-active (the controller added this when dispatching you)Then notify the controller via Envoy (best-effort, non-blocking):
envoy_publish(topic="notifications.role.legion-controller", message="Worker done: <issue-id> <mode> completed")
If envoy_publish fails, continue — the label is the source of truth.
| Mode | Workflow | Adds worker-done |
|---|---|---|
architect | @workflows/architect.md | Yes (or on children) |
plan | @workflows/plan.md | Yes |
implement | @workflows/implement.md | Yes |
test | @workflows/test.md | Yes |
review | @workflows/review.md | Yes |
merge | @workflows/merge.md | No |
Lifecycle order: architect → plan → implement → test → review → (implement → test if changes requested) → retro → merge
Retro is not a mode — the controller resumes the implement worker's session with /legion-retro, preserving full implementation context. See the legion-retro skill.
Review signals outcome via native GitHub review API BEFORE worker-done:
gh pr review --approve) — no blocking issuesgh pr review --request-changes) — blocking issues foundLabel conventions: @references/linear-labels.md (Linear), @references/github-labels.md (GitHub)