# Tasks

> Work with markdown-based task lists in .llm/todo.md files. Use when managing tasks, working with todo lists, extracting incomplete tasks, marking tasks complete, or implementing tasks from a task list.

- Skill: `motlin/tasks` (Agent Skill)
- Install (CLI): `npx skillmds@latest add motlin/tasks`
- Raw SKILL.md: https://api.skillmd.com/api/skills/motlin/tasks/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: motlin (https://skillmd.com/u/motlin)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/motlin/tasks

---


# Markdown Task Management

This skill enables working with the markdown task list stored in `.llm/todo.md`.

Resolve `<plugin-root>` before running plugin scripts:

- In Claude Code, use `${CLAUDE_PLUGIN_ROOT}`.
- In Codex, use the plugin root that contains this `skills/tasks/SKILL.md` file.

## Scripts

### task_get.py - Extract Next Task

Extract the first incomplete task with its context:

```bash
python <plugin-root>/scripts/task_get.py .llm/todo.md
```

Returns the first `[ ]` checkbox line with all indented context lines below it.

**Exit codes**: 0 (success), 1 (file not found or error)

### task_add.py - Add New Task

Add a new task:

```bash
python <plugin-root>/scripts/task_add.py .llm/todo.md "Task description
  Context line 1
  Context line 2"
```

When adding more than one task, chain the calls into a single bash command with `&&` rather than running a separate command per task:

```bash
python <plugin-root>/scripts/task_add.py .llm/todo.md "First task
  Context line 1" && \
python <plugin-root>/scripts/task_add.py .llm/todo.md "Second task" && \
python <plugin-root>/scripts/task_add.py .llm/todo.md "Third task"
```

Running the whole batch as one command keeps the write window to `.llm/todo.md` extremely short, so concurrent sessions writing to the same file are far less likely to interleave their tasks.

Creates the `.llm/` directory and `todo.md` file if they do not exist, and appends the new task with a `[ ]` checkbox. The script preserves all indentation in multi-line strings.

**Exit codes**: 0 (success), 1 (error)

### task_mark.py - Mark Task

Mark the first incomplete task with a marker character:

```bash
python <plugin-root>/scripts/task_mark.py .llm/todo.md
python <plugin-root>/scripts/task_mark.py .llm/todo.md --marker='!' --reason='precommit failed on the parser rewrite'
```

Changes the first `[ ]` to `[x]` by default. Pass `--marker` with any single non-space character (e.g. `!`, `>`, `-`) to use a different marker.

`--reason` appends the failure as an indented context line at the end of the task body, above any trailing blank line:

```markdown
- [!] Require authentication on API routes.
  Reuse `validateJwt` from `/workspace/project/src/auth/tokens.ts`.
  Blocked 2026-08-19 session 94aec27b: validateJwt does not exist; the repo uses `verifyToken`
```

The reason lives in the task body so it survives archive, recovery, and reinstatement, and so `task_get.py` hands it to the next attempt along with the rest of the context. Quote the concrete failure — the failing command, the assertion, the missing symbol — rather than restating the task.

`--reason` is **required** with `--marker='!'`; blocking a task without one exits 1 and leaves the file untouched. It is optional for every other marker.

**Exit codes**: 0 (success), 1 (no incomplete tasks, missing reason for `!`, or error)

### task_archive.py - Archive Task List

Archive a completed task list:

```bash
python <plugin-root>/scripts/task_archive.py .llm/todo.md
```

Moves the file to `.llm/YYYY-MM-DD-todo.md` where YYYY-MM-DD is today's date.

Blocked `[!]` tasks never reach the archive. Each one moves into a fresh `.llm/todo.md` with its indented context, still marked `[!]`, so `task_get.py` keeps skipping it and `task_unblock.py` stays the deliberate way to reopen it. The script prints the archive path and how many blocked tasks it carried forward.

**Exit codes**: 0 (success), 1 (file not found or error)

### task_unblock.py - Recover Blocked Tasks

Move blocked `[!]` tasks out of archived task lists and back into `.llm/todo.md`:

```bash
python <plugin-root>/scripts/task_unblock.py .llm --dry-run
python <plugin-root>/scripts/task_unblock.py .llm
```

Scans every `.llm/*todo*.md`, including the live `.llm/todo.md`, and moves each `[!]` task with its indented context into `.llm/todo.md` as an open `[ ]` task, stamped with an indented `Recovered <yyyy-mm-dd> session <session-id>` line. Recovery is a move, so the task disappears from the archive it came from and re-running the script cannot duplicate it. Emptied archive files stay on disk, and existing `Blocked` lines are preserved so a task's full round-trip history stays readable.

Recovery rewrites historical archive files. Always run `--dry-run` first and confirm the report with the user before running it for real.

**Exit codes**: 0 (success, including when nothing is blocked), 1 (directory not found or error)

## Task Format

The task list is in `.llm/todo.md`.

NEVER use the `Read` tool on `.llm/todo.md`. Always interact with the task list exclusively through the Python scripts.

### Task States

- `[ ]` - Not started (ready to work on)
- `[x]` - Completed
- `[!]` - Blocked after failed attempt

### Task Structure

Each task includes indented context lines with full implementation details:

- Absolute file paths
- Exact function/class names
- Code analogies to existing patterns
- Dependencies and prerequisites
- Expected outcomes

### Standalone Context

Each task is extracted and executed in isolation. Every task must contain ALL context needed to implement it. Repeat shared context in every related task. Never reference other tasks.

If tasks were created from a plan file, include the plan file path in each task so the implementing agent can read the full context.

## Plan Mode

When using Claude Code's native plan mode to design an implementation before creating tasks:

1. The plan file is written to `~/.claude/plans/<auto-generated-name>.md` (e.g., `~/.claude/plans/abstract-knitting-garden.md`)
2. **Before adding any tasks**, archive the plan locally:
    - Create the `.llm/plans/` directory if it does not exist
    - Move the file from `~/.claude/plans/<auto-generated-name>.md` to `.llm/plans/<yyyy-mm-dd>-<descriptive-name>.md`
    - Choose a concise, meaningful name that describes the plan's purpose (e.g., `2025-12-04-thread-safety-tests.md`, `2025-12-04-plugin-hook-system.md`)
3. Include the **absolute path** to the archived `.llm/plans/` file in each task so the implementing agent can read the full context

When using Codex planning, store the plan under `.llm/plans/<yyyy-mm-dd>-<descriptive-name>.md` before adding tasks, then include that absolute path in each task.

