Skip to main content

take-task

This skill should be used when claiming a task to work on - "take task", "візьми таск", "працюю над", "work on task X", "pick task X", "switch to task X", "claim task". Sets task to in_progress, creates/switches branch, saves the per-branch task-state file.

跳到安装

来源信息

仓库
restarter/lets-workflow
最近来源活动
2026年9月15日 18:04
检测到的 SKILL.md 语言
英语
星标
17
分支
3

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
take-task
description
This skill should be used when claiming a task to work on - "take task", "візьми таск", "працюю над", "work on task X", "pick task X", "switch to task X", "claim task". Sets task to in_progress, creates/switches branch, saves the per-branch task-state file.
# Take Task Claim a tracker task and prepare the working environment. > **IMPORTANT:** If the spec below invokes any deferred tool (e.g. `AskUserQuestion`), you MUST load and call it as specified. Never skip the call, never substitute a default answer of your own — the tool invocation is part of the contract. This is critical. ## Why This Exists Multiple flows need "claim task + prepare branch": /lets:start, mid-session task switch, direct "візьми таск X". Centralizing ensures consistent branch naming, worktree handling, and session ref saving. ## Flow ### Step 1: Resolve Task ```lets-tracker show task=<task-id> ``` Verify task exists. Then claim it (set-status is a state change - HARD-FAIL loud if the binding can't run; do NOT proceed to branch setup on a failed claim): ```lets-tracker set-status task=<task-id> status=in_progress ``` ### Step 2: Check Uncommitted Changes Before switching branches, check for uncommitted changes: ```bash git status --short ``` If changes exist and branch switch is needed, ask user: ``` AskUserQuestion( questions=[{ question: "Uncommitted changes on current branch. What to do?", header: "Uncommitted", options: [ { label: "Stash", description: "git stash, switch branch, remind to pop later" }, { label: "Commit first", description: "Commit changes, then switch branch" }, { label: "Stay", description: "Skip branch switch - work on current branch" } ], multiSelect: false }] ) ``` Handle response: - **Stash** -> `git stash`, proceed with branch switch, remind to `git stash pop` later - **Commit first** -> delegate to commit skill, then proceed with branch switch - **Stay** -> skip branch switch, warn about mixed work, then continue to Step 5 (the task was already claimed in Step 1 - save its `.task` state file for the current branch; do NOT stop before it, or detect-task/`/lets:done` are left with a claim but no boundary file). If staying on current branch (worktree, already correct) or no changes - skip this step. ### Step 3: Worktree Check ```bash GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) ``` **If in a worktree** (`$GIT_DIR` contains `worktrees/`): - Skip branch creation - use the current worktree branch as-is - Go reads the branch against the active tracker's convention: `lets worktree info --json --task-candidate --plugin-root "${CLAUDE_PLUGIN_ROOT}"`. `task_candidate.source=created` (the adapter's `branch:` / `worktree-branch:` shape, default `worktree-<task-id>-<slug>`) is this branch's task: confirm it with the user via the tracker's `show` verb. Any other result is an attached or externally named branch (e.g. `feature/foo`): rely on the task-id passed as the skill argument - never guess an id from the name by eye. No `lets` binary: the shapes are the ones detect-task Step 1 lists. - **Derived id (`.task` carries `origin: branch` or `origin: dir`).** `lets worktree adopt` guessed the id from the branch or directory name. When take-task did NOT receive the id as its argument, confirm with the user that the derived id is the task, and when Step 1's `show` returned `in_progress` (before this claim) warn in one line that it may already be claimed in another worktree. An explicit id argument supersedes the guess with no question, so unattended `--flow` / `--auto` spawns never stop here. Step 5 clears `origin:`. - Present: "In worktree, using branch: {branch}" - Jump to Step 5 **If in main repo** (`$GIT_DIR` is `.git`): - Continue with Step 4 ### Step 4: Branch Logic (main repo only) **Branch naming:** the active tracker convention names the branch, and Go renders it. Write the task title with the Write tool to `.lets/cache/title-<session6>.txt` (6 = first chars of `$CLAUDE_CODE_SESSION_ID`; the title is untrusted text and never typed into a shell), then: ```bash lets worktree branch-name --task '<task-id>' --title-file .lets/cache/title-<session6>.txt --plugin-root "${CLAUDE_PLUGIN_ROOT}" --json ``` Use `branch` (e.g. `feature/proj-ch15-fix-proxy-config`; a board file can declare `feature/PWA-45122-fix-login`). No `lets` binary: the documented default `feature/<task-id>-<slug>` (slug: lowercase, spaces to hyphens, special chars removed, max 50 chars). Check current state: - Already on correct branch -> do nothing, continue to Step 5 - Branch exists elsewhere -> `git checkout <branch>` - Branch doesn't exist -> offer choice: ``` AskUserQuestion( questions=[{ question: "How do you want to work on this task?", header: "Workspace", options: [ { label: "Branch (Recommended)", description: "Regular feature branch in current repo" }, { label: "Worktree", description: "Separate directory for parallel work in another terminal" }, { label: "Stay on current branch", description: "Skip branch creation. On {LETS_MERGE_BRANCH}: /lets:done pushes + closes (no PR). On a custom branch: normal PR flow." } ], multiSelect: false }] ) ``` Handle response: - **Branch** -> `git checkout -b <branch> {LETS_MERGE_BRANCH}` (from LETS Config) - **Worktree** -> invoke `Skill(skill: "lets:worktree", args: "create <task-id> --title-file .lets/cache/title-<session6>.txt")` (the id, not a name: the worktree command renders the adapter's `worktree-branch:` name from it), then relay how the new session opens - the worktree command's own output names it (a terminal command, or a cmux / tmux / Orca pane already running `/lets:start <task-id>`). Stop here - the worktree session continues in a separate terminal or pane. - **Stay on current branch** -> skip `git checkout -b`; stay on the current branch (could be `$LETS_MERGE_BRANCH` or any pre-existing branch). Print one line: "Staying on `{current branch}`. No new branch created." If `HEAD == $LETS_MERGE_BRANCH`, append: " Trunk-mode: `/lets:done` will push + close (no PR — same-source-target)." Continue to Step 5 (the `.task` state file is saved as usual). ### Step 5: Save Task State File Write the per-branch task-state file `.lets/sessions/.task-<branch-slug>`: `task:` (identity), `start:` (task boundary - preserved across resume of the same task, reset on a new/changed task or when the recorded SHA is no longer an ancestor of HEAD), and `session: <sha> <session-id>` (this session's boundary, always refreshed); `origin:` is cleared (the id is now confirmed) and every other line - `orc:` included - is kept. `lets worktree task-state` owns the file (merge-write under a lock, validated values); without the binary, an atomic `tmp`+`mv` rewrite keeps the other lines too. `<task-id>` is the claimed id. ```bash LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel) BRANCH=$(git branch --show-current); BRANCH_SLUG=$(echo "$BRANCH" | tr '/' '-') mkdir -p "$LETS_PROJECT_ROOT/.lets/sessions" TASK_FILE="$LETS_PROJECT_ROOT/.lets/sessions/.task-${BRANCH_SLUG}" HEAD_SHA=$(git rev-parse HEAD) CLAIMED_ID="<task-id>"; SID="$CLAUDE_CODE_SESSION_ID" PREV_TASK=""; PREV_START="" if [ -f "$TASK_FILE" ]; then PREV_TASK=$(sed -n 's/^task: //p' "$TASK_FILE" | head -1) PREV_START=$(sed -n 's/^start: //p' "$TASK_FILE" | head -1) fi # Preserve start: only when resuming the SAME task AND the recorded SHA is still an ancestor of HEAD. if [ "$PREV_TASK" = "$CLAIMED_ID" ] && [ -n "$PREV_START" ] && git merge-base --is-ancestor "$PREV_START" HEAD 2>/dev/null; then START="$PREV_START" else START="$HEAD_SHA" fi if command -v lets >/dev/null 2>&1; then # {ORC_FLAG}: --orc '<name>' when args carried orc="<name>" and this is not the merge-branch (single-quoted, '\'' escaping); else empty lets worktree task-state set --task "$CLAIMED_ID" --start "$START" --session-sha "$HEAD_SHA" --session-id "$SID" --clear-origin {ORC_FLAG} --create --json lets peers role set worker --task "$CLAIMED_ID" --session "$SID" --cwd "$LETS_PROJECT_ROOT" --json else tmp=$(mktemp "${TASK_FILE}.XXXX") { [ -f "$TASK_FILE" ] && grep -v -e '^task: ' -e '^start: ' -e '^session: ' -e '^origin: ' "$TASK_FILE" echo "task: $CLAIMED_ID" echo "start: $START" echo "session: $HEAD_SHA $SID" } > "$tmp" && mv -f "$tmp" "$TASK_FILE" fi ``` On `ok=false` surface `error.message` - the claim succeeded but the boundary file did not, so `/lets:done` cannot measure the task until it is fixed. - **Orchestrator binding (`orc="<name>"` in the args, from detect-task's `--orc` strip).** Pass it as `{ORC_FLAG}`; Go validates the name and a refusal is one line with nothing written. A trunk-mode claim (HEAD is `{LETS_MERGE_BRANCH}`) ignores it with one line - the merge-branch never carries a binding. When the envelope reports `rebound.from`, say in one line that this branch moved from that orchestrator to the new one. - **Worker role.** The second call registers this session as the task's worker so orchestrators see it in `lets peers who`. A non-ok envelope (e.g. `session_not_in_registry`) is one line - never hidden, a silent failure leaves the worker unregistered. Without the binary the no-binary branch skips it; say so in one line. ### Step 6: Context Recovery (existing branch) If the branch already existed (continuing a multi-session task): ```lets-tracker show task=<task-id> comment-list task=<task-id> ``` Read the full description and ALL comments — they hold the multi-session context. Present: "Resuming **{task title}** (`{task-id}`). Last session: {summary from the latest tracker comment}" Also surface the most recent session snapshot for this branch (the file trail `/lets:start` full-mode reads - the quick `<task-id>` path skips Step 1, so read it here): ```bash LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel) BRANCH_SLUG=$(git branch --show-current | tr '/' '-') # Task-id-named snapshot first (artifact-path naming, lets-05c4s); legacy {TS}-{branch}.md as fallback. LATEST_SNAP=$(ls -t "$LETS_PROJECT_ROOT/.lets/sessions/"*"-<task-id>-snapshot"*.md 2>/dev/null | head -1) [ -z "$LATEST_SNAP" ] && LATEST_SNAP=$(ls -t "$LETS_PROJECT_ROOT/.lets/sessions/"*"-${BRANCH_SLUG}"*.md 2>/dev/null | head -1) ``` If `$LATEST_SNAP` is non-empty, Read it and fold its `### Remaining + NEXT STEP` into the "Last session: ..." line. If empty, rely on the tracker's comments alone (fresh branch - no snapshot yet). ## Output When triggered standalone (not via `/lets:start`): ``` Task claimed: **{task title}** (`{task-id}`) Branch: {branch-name} ┌─ LETS ────────────────────────────────────────────┐ │ Plan? /lets:plan · --fast · plan-workflow │ │ Check? /lets:check │ └───────────────────────────────────────────────────┘ ``` When invoked by `/lets:start` OR `/lets:done` (via `Skill` tool) - skip this output, the calling command has its own. Per CLAUDE.md "Internal invocation = no box". ## Anti-patterns - Never create feature/ branch inside a worktree - Never work without saving session start ref - Never skip the `set-status task=<id> status=in_progress` claim - Never auto-create a feature branch when user picked "Stay on current branch" ## Integration User-facing skill. Auto-triggers on "take task X", "візьми таск". Primary consumer: `/lets:start`. See: `grep -r "take-task" commands/` for command references.
在 GitHub 查看