Claude
Skills
Sign in
Back

task-done

Included with Lifetime
$97 forever

Close a taskwarrior task with landing commit annotation and optional GitHub issue/PR close. Use when finishing a coordination task or marking a work order complete.

Ads & Marketing

What this skill does


# /taskwarrior:task-done

Close a task with full coordination hygiene: annotate with the landing commit, drain the tracker entry, optionally close the GitHub issue.

## When to Use This Skill

| Use this skill when... | Use `task-add` / `task-status` / `task-coordinate` instead when... |
|---|---|
| Closing a task whose work has landed in a commit | Filing a brand-new task — use `task-add` |
| Draining a linked blueprint tracker entry to `done` | Reading current queue state without mutating it — use `task-status` |
| Closing a `ghid`-linked GitHub issue or commenting on a `ghpr` PR | Picking the next dispatch candidate from the queue — use `task-coordinate` |
| Closing many tasks in one pass (queue cleanup, triage sweep) | See **Bulk-close patterns** below — the naive `for id in 1 2 3; do task $id done; done` loop silently closes the wrong tasks |

## Context

- Task CLI available: !`task --version`
- Git repo detected: !`find . -maxdepth 1 -name '.git' -print -quit`
- GH auth: !`gh auth status`

Git probes (`git remote`, `git rev-parse --short HEAD`,
`git branch --show-current`) write to stderr in a no-git cwd, and stderr
from a Context backtick aborts the skill before its body runs. HEAD
commit, current branch, and remote-presence checks happen in the body
(Steps 2 and 5) via the Bash tool where `2>/dev/null` and exit-code
handling are tolerated.

## Parameters

Parse `$ARGUMENTS`:

- `$0` — task ID (required)
- `$1` — commit hash (optional; defaults to `HEAD`)
- `--no-gh` — skip GitHub close/comment even when remote is present
- `--no-tracker` — skip blueprint tracker drain
- `--drain-identity` — also clear `agent` / `pid` / `host` / `branch` / `worktree` UDAs after closing (default keeps them as audit trail)
- `--no-coworker-marker` — skip the `/git:coworker-check --release` step

## Execution

Execute this workflow:

### Step 1: Load the task

```bash
task "$TASKID" export | jq '.[0]'
```

Never use `task $TASKID info` or `task $TASKID list` — both can exit 1 and
cancel parallel siblings. `export | jq` returns valid JSON even when the
task is already closed (treat empty as "no such open task" and abort).

Capture: `bpid`, `bpdoc`, `ghid`, `ghpr`, `tags`, `description`, plus
identity UDAs `agent`, `pid`, `host`, `branch`, `worktree`, and `start`
(if the task was claimed via `/taskwarrior:task-claim`).

### Step 2: Resolve commit hash

If `$1` is unset, read `git rev-parse --short HEAD`. Confirm the HEAD commit
actually touches work this task covers before annotating — a stale HEAD is
a common footgun.

### Step 3: Annotate and close

```bash
task "$TASKID" annotate "landed: $COMMIT_SHORT $COMMIT_SUBJECT"
task "$TASKID" done
```

Annotation first, then done — if close fails (e.g. dependencies), the
annotation is still captured.

Taskwarrior auto-stops a `+ACTIVE` task on `done`, so an explicit
`task stop` is not needed. The task transition removes `+ACTIVE` and
records the duration. If you want to drain the identity UDAs (so the
closed task does not retain the stamp), do so separately after the
close — see Step 4b below.

### Step 4b: Drain identity UDAs (optional)

After the task is closed, optionally clear the identity stamp left by
the original claim:

```bash
task "$TASKID" modify agent: pid: host: branch: worktree:
```

Default behaviour is to **leave** these set on closed tasks — the audit
trail of "who claimed and landed this" is useful in `task-status`
recently-completed reports. Drain them only when the user explicitly
asks (e.g. compliance / privacy hygiene), or when handing the queue
file off to another team.

### Step 4: Drain the blueprint tracker

If `bpdoc` is set and points to a valid path, read the file and advance
its status marker in place. Typical patterns by tracker format:

- Feature-tracker JSON: `status: in_progress` → `status: done`, append
  evidence entry citing the commit
- Work-order markdown: check off the relevant bullet, add landed-in line
- PRP: flip the "Implementation" status field

Use `Edit` with a narrow `old_string` / `new_string` pair — do not rewrite
the file. When `bpdoc` references a shared tracker (manifest.json, global
feature-tracker), fall back to reporting "manual tracker update required"
rather than concurrent-write the shared file.

### Step 5: Close linked GitHub items (optional)

When GitHub mode is active and `--no-gh` was not passed:

- `ghid` set → offer `gh issue close "$GHID" --comment "Closed by $COMMIT_SHORT (branch $BRANCH)"`
- `ghpr` set → offer `gh pr comment "$GHPR" --body "Linked task closed: $COMMIT_SHORT"`

Always confirm before mutating GitHub state — the user may want to close
the issue as part of the PR merge rather than ahead of time.

### Step 5b: Drop the coworker-check marker

If the task was `+ACTIVE` (claimed via `/taskwarrior:task-claim`), the
matching git-side session marker should be released so destructive ops
in this clone are no longer guarded:

```
Use SlashCommand to invoke `/git:coworker-check --release`.
```

Skip when the user has more work in flight on this branch — releasing
the marker lifts the cross-agent guard.

### Step 6: Report

Print:

- Task closed: id + description + new status
- Commit annotated: `$COMMIT_SHORT`
- Tracker drained: path + diff summary, or "skipped"
- GitHub: "issue #N closed" / "PR #N commented" / "skipped"
- Unblocked siblings: any tasks whose `depends:` pointed at this one now
  free to start (query via `task depends:$TASKID export | jq`)

## Agentic Optimizations

| Context | Command |
|---------|---------|
| Load task | `task "$TASKID" export \| jq '.[0]'` |
| Annotate + close | Two separate calls (hook-friendly) |
| Blocked children | `task depends:"$TASKID" export \| jq '.[]'` |
| Skip empty-result failures | Always `export \| jq` |

## Quick Reference

| Step | Command |
|------|---------|
| Load | `task ID export \| jq` |
| Annotate | `task ID annotate "msg"` |
| Close | `task ID done` |
| Check unblocked siblings | `task depends:ID export \| jq '.[]'` |
| GitHub close | `gh issue close N --comment "msg"` |
| PR comment | `gh pr comment N --body "msg"` |

## Bulk-close patterns

Closing many tasks in one pass has two silent foot-guns. The obvious shape — `for id in 1 2 3; do task $id done; done` — reports success while doing the wrong thing.

### Foot-gun 1: numeric IDs renumber after every `task done`

Numeric IDs are a display index over **pending** tasks. The moment one closes, every higher ID shifts down by one. A loop over numeric IDs closes the original first task, then keeps targeting wrong tasks as IDs slide underneath the iterator. No error surfaces.

**Fix: use UUIDs** (immutable). The same applies to any iterated state-changing op — `annotate`, `modify`, `delete`.

```sh
# WRONG — IDs shift mid-loop
for id in 35 36 37 38 39; do task "$id" done; done

# Correct — capture immutable UUIDs first
UUIDS=$(task status:pending project:myrepo export | jq -r '.[].uuid')
for u in $UUIDS; do task "$u" done </dev/null; done    # stdin redirect — see below
```

### Foot-gun 2: `task done` consumes loop stdin

`task done` reads from stdin (for confirmation prompts). In a shell `for` loop, the loop's input is *also* stdin — so `task done` eats subsequent iterations and the loop exits early, usually after one or two passes, with no error.

Symptom: a loop over 15 UUIDs reports "processed 15" but only 1 task closed.

```sh
# Fix A — redirect stdin per inner command
for u in $UUIDS; do
  task "$u" rc.confirmation=no done </dev/null
done

# Fix B — xargs (preferred; each invocation runs in its own subshell with no
# stdin link to the source loop)
echo "$UUIDS" | xargs -I {} sh -c 'task rc.confirmation=no {} done'
```

### Always pass `rc.confirmation=no` for batch closes

Without it, taskwarrior may prompt "this task is blocked by N other tasks, complete anyway? (yes/no)" per task, hanging the loop. `rc.confirmation=no` makes batch closes deterministic.

### Annotate before `done`, not after

Once `completed`, a task's `id` becomes 0

Related in Ads & Marketing