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.

Aller à l'installation

Informations de source

Dépôt
restarter/lets-workflow
Dernière activité de la source
27 septembre 2026 à 18:17
Langue détectée de SKILL.md
anglais
Étoiles
17
Forks
3

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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 **Tracker protocol:** `Skill(skill: "lets:protocol-tracker")` before this and any later `lets-tracker` block here, unless its text is in your current context. ```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 **Team worktree** - `lets worktree info --json` reports a top-level `team`: this worktree belongs to a standing team and moves between tasks through `lets worktree switch`. Skip the generic question below and go to **Step 2T**. No `team` -> continue here. 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 2T: Team worktree - park, then switch Read `${CLAUDE_PLUGIN_ROOT}/protocol/worktrees.md` before this step unless its text is in your current context (standing-team worktree, park never stash). A team worktree never stashes. `git status --short`; changes present -> list them, and list separately every NEW path a park would need to name - untracked (`git ls-files --others --exclude-standard`) and staged additions (`git diff --cached --diff-filter=ACR --name-only HEAD`). Ignored files are never parked; they stay on disk. Then: ``` AskUserQuestion( questions=[{ question: "Uncommitted changes on {branch} before switching to {task-id}. What to do?", header: "Uncommitted", options: [ { label: "Commit first", description: "Commit them with /lets:commit, then switch" }, { label: "Park", description: "Commit them as wip(<id>): park on this branch; unparked when you come back" }, { label: "Stay", description: "Skip the switch - keep working on {branch}" } ], multiSelect: false }] ) ``` - **Commit first** -> delegate to the commit skill, then the switch below. - **Park** -> ask which of the listed new paths go into the park commit. `--include` names only the paths the user confirmed; an unconfirmed new path makes the switch refuse (`untracked_present`, nothing touched) - say so, and let the user confirm it or remove it. - **Stay** -> no switch; warn about mixed work, then Step 5 as in Step 2's Stay. No changes -> the switch below directly. The switch, from the team worktree: ```bash lets worktree switch --task '<task-id>' --title-file .lets/cache/title-<session6>.txt --json # Park: add --park and one --include '<path>' per confirmed new path ``` (The title file is written as in Step 4, with the Write tool.) Render the result: - `ok=true` -> "Switched to `{branch}`" (`created` -> "cut from `{base}`", with the staleness warning when `base_stale`); `park` -> name the park commit; `unpark` -> `unparked` (the parked changes are staged again), `parked_pushed` / `parked_unverified` / `parked_kept` (the park stays a commit - say why). - A refusal -> show `error.kind` and `error.message`, change nothing, stop: `dirty_worktree`, `index_unmerged`, `operation_in_progress`, `detached_head` (exit 14 - the tree must be sorted out first), `untracked_present` (list `new_paths`, back to the Park question), `members_live` (a live implementer writes in this tree - wait for it or dismiss it), `no_remote_base`, `target_is_merge_branch`, `session_held` (switch from the team's lead session). `lets worktree switch` wrote the target branch's task-state (`task`, `start`, `session` through the session guard, `orc` carried from the old branch), so Step 5's own write - its `--session-sha`, unguarded - is skipped on this path. Its tail still runs on the new branch, passing only what switch did not write: ```bash LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel) # {ORC_FLAG} as in Step 5: --orc '<name>' when args carried orc="<name>", else empty lets worktree task-state set --clear-origin {ORC_FLAG} --json lets peers role set worker --task "<task-id>" --session "$CLAUDE_CODE_SESSION_ID" --cwd "$LETS_PROJECT_ROOT" --json ``` The first clears `origin:` and applies a requested orchestrator binding (an explicit `--orc` wins over the carried one); the second registers this session as the task's worker. Each failure is Step 5's one-line report - never hidden. Then rewrite the team file's `## 7. Current task` section (`.lets/teams/<team>.md`; the lead is its only writer): the task as **Title** (`id`), its branch, the phase, the next step, and `Resume artefacts:`. Then Step 6. ### Step 3: Worktree Check ```bash GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) ``` **If in a worktree** (`$GIT_DIR` contains `worktrees/`): - A team worktree (Step 2T ran) never reaches here - its branch comes from `lets worktree switch`, not from the current branch. - 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):
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub