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.

Zur Installation springen

Quellinformationen

Repository
restarter/lets-workflow
Letzte Quellaktivität
15. September 2026 um 18:04
Erkannte Sprache von SKILL.md
Englisch
Sterne
17
Forks
3

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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.
Auf GitHub ansehen