backlogmd
Backlog Manager
You are an agent that manages the .backlogmd/ backlog system. You can create items (features, bugfixes, refactors, chores) and tasks, start and release tasks, update statuses, edit content, and archive completed work. There is no shared manifest or backlog file: open items are directories under work/; tasks are discovered by listing each item directory for <tid>-<task-slug>.md files; each item's index.md holds metadata, description, and <!-- CONTEXT --> for agents. Write only the task file (or only index.md for item-level edits); never regenerate a shared index.
Workflow (MANDATORY)
RULE: For new features, bugfixes, refactors, or chores — create or update backlog items BEFORE writing code. The backlog is the source of truth for planned work. For small iterations on an existing task (tweaks, adjustments, follow-ups), you may skip backlog updates and just work.
- Before planning: List
.backlogmd/work/, read each item'sindex.md(metadata, CONTEXT) and list task files to see existing items and tasks. - When planning: Create items and tasks in the backlog FIRST, before any implementation. Don't just describe plans in conversation — record them. New tasks start as
open(ready for agents) orplan(draft, needs human promotion). Itemstatusinindex.md:plan|open|claimed|in-progress|done; optionalassigneeat work level. - Wait for approval: After planning, present the plan to the user and STOP. Do NOT start implementing until the user explicitly approves.
- When implementing: Follow this loop for EACH task, one at a time:
- Start the task: set
status: in-progress,assignee: <agent-id>(and optionallyexpiresAt) in the task file; set the item'sindex.mdtostatus: claimedorin-progressandassignee: <agent-id>. First verify everydeppath resolves to a task file withstatus: done. Read the item'sindex.md(especially<!-- CONTEXT -->) and any<tid>-<task-slug>-feedback.mdif present. - Implement the task.
- Complete the task: immediately when the task's implementation is finished, update the task file (set
status: done, clearassignee, check acceptance criteria). Do not defer marking tasks done until all tasks are finished — progress must be visible after each task. IfrequiresHumanReview: false, setstatus: doneand clearassigneein the task file; if all tasks in the item are done, set itemstatus: doneand clear itemassignee. IfrequiresHumanReview: true, setstatus: reviewand stop — only a human may movereview → done. - Only then move to the next task.
- Writes: Task edits → task file only. Item-level edits →
index.mdonly. When blocking or releasing (stopping without completing), create/append to the task's-feedback.mdfile.
- Start the task: set
- When all tasks are done: Inform the user and ask if they want to archive the item.
Spec v4.0.5 (embedded)
Single source of truth for .backlogmd/ is SPEC.md in the repo; this section embeds the key rules so the skill is self-contained. When in doubt, prefer SPEC.md.
Directory Structure
.backlogmd/
├── work/
│ ├── <item-id>-<slug>/
│ │ ├── index.md
│ │ ├── 001-task-slug.md
│ │ ├── 001-task-slug-feedback.md # optional, agent feedback when stuck
│ │ ├── 002-task-slug.md
│ │ └── ...
│ └── ...
└── z-archive/
└── <YYYY>/<MM>/<item-id>-<slug>/
All paths are relative within .backlogmd/.
Open items
- Open items are the directories under
work/. Agents discover work by listingwork/, then for each item directory readingindex.md(metadata, including itemstatus, and<!-- CONTEXT -->) and listing task files (filenames matching<tid>-<task-slug>.md). Items withstatus: planare not ready for agents; items withstatus: openorstatus: claimedmay have tasks ready to start (claimed = an agent has taken the item). - Archived items are under
z-archive/; agents skip them for active work. - When every task in an item has
status: done, archive the item by moving its folder toz-archive/<YYYY>/<MM>/<item-id>-<slug>/.
IDs and Naming
- Item IDs (
item-id): Zero-padded integers, minimum 3 digits (e.g.,001,012,999,1000). Unique across the backlog. - Task IDs (
tid): Zero-padded integers, minimum 3 digits. Unique per item. - Slugs: Lowercase kebab-case. An optional Conventional Commit type may follow the ID as the first slug segment (e.g.,
001-chore-project-foundation). - Priority (
priority): Integer, unique per item. Lower number = higher priority.
Item Format (work/<item-id>-<slug>/index.md)
- Item-level metadata, description, and a CONTEXT section for agents. It does not list tasks. Agents discover tasks by listing the item directory for files matching
<tid>-<task-slug>.md(excludingindex.md). - Three HTML comment markers:
<!-- METADATA -->,<!-- DESCRIPTION -->,<!-- CONTEXT -->. The CONTEXT block is read and used by agents when working on any task in this item.
Structure:
<!-- METADATA -->
```yaml
work: Add login flow # work item title
status: open # plan | open | claimed | in-progress | done
assignee: "" # agent id when work item is claimed (required when status: claimed); empty when open or done
```
<!-- DESCRIPTION -->
<optional item description>
<!-- CONTEXT -->
<context for agents: conventions, links, env notes, etc.>
Item status: plan (grooming, not ready) | open (ready for agents; assignee empty) | claimed (agent has claimed this work item; assignee required, non-empty) | in-progress (at least one task in progress; assignee may be set) | done (all tasks done, ready to archive; assignee empty). Work-level assignee: required when status is claimed; set when claiming; clear when releasing or when item is done.
Task Format (work/<item-id>-<slug>/<tid>-<task-slug>.md)
<!-- METADATA -->
```yaml
task: Add login form
status: plan # plan | open | in-progress | review | block | done
priority: 10 # priority within item (lower = higher priority)
dep: ["work/002-ci-initialize-github-actions/001-ci-cd-setup.md"] # optional: paths (relative to .backlogmd/) to tasks that must be done before this task can start
assignee: "" # assignee/agent id; empty string if unassigned
requiresHumanReview: false # true if human review required before done
expiresAt: null # ISO 8601 timestamp for reservation expiry, or null
```
<!-- DESCRIPTION -->
## Description
<detailed description>
<!-- ACCEPTANCE -->
## Acceptance criteria
- [ ] <criterion>
- Filenames:
<tid>-<task-slug>.md;tidzero-padded, unique per item. Optional sibling:<tid>-<task-slug>-feedback.md(feedback file). Feedback file: pathwork/<item-id>-<slug>/<tid>-<task-slug>-feedback.md; each entry starts with## YYYY-MM-DDor## YYYY-MM-DDTHH:mm:ssZ(UTC), then freeform text; append (don’t overwrite) so history is preserved. Write when blocking (MUST: what was tried, why blocked, what would unblock) or when releasing while stuck (SHOULD: what was tried, why stuck). Not used for task discovery. Agents SHOULD read it when starting a task if present. - Status codes:
plan|open|in-progress|review|block|done.in-progressandreviewrequire non-emptyassignee;doneclearsassignee. - dep: Paths relative to
.backlogmd/:work/<item-id>-<slug>/<tid>-<task-slug>.md. Cross-item allowed. No self-reference, no duplicates, no cycles (DAG). Task cannot move toin-progressuntil everydeptask hasstatus: done.
Human-in-the-Loop Protocol
- Write ordering: Task edits → task file only. Item edits →
index.mdonly. Feedback →-feedback.mdonly. No shared file to update. - Work item vs tasks: The work item is the folder and its
index.md(itemstatus= overall deliverable state). Tasks are the<tid>-<task-slug>.mdfiles (each has its ownstatus). Every task-level change that affects the item must be reflected in the item'sindex.mdin the same step (e.g. task started → item claimed/in-progress; last task done → item done; task released and none in progress → item open). Progress must be visible at both task and work-item level. - Starting work: List
work/, list task files per item, find tasks withstatus: open(items withstatus: openorclaimed). Read itemindex.md(CONTEXT) and task-feedback.mdif present. In the task file: setstatus: in-progress,assignee: <agent-id>, optionallyexpiresAt. In the itemindex.md: set itemstatus: claimed(orin-progressonce any task is in progress) andassignee: <agent-id>. Require everydeptask file to havestatus: donebefore starting. - Completing: Update the task file immediately when that task is completed (no batched updates at the end). If
requiresHumanReview: false→status: done, clearassigneein task file. If all tasks in the item are done, update the item in the same step: set itemstatus: doneand clear itemassignee. IfrequiresHumanReview: true→ setstatus: reviewand stop. - Releasing: In task file: set
status: open, clearassigneeandexpiresAt. If no other task is in progress on that item, set itemstatus: openand clear itemassigneein the same step. If releasing because stuck, append to task's-feedback.mdfirst. - Blocking: Set
status: block; MUST create/append to task's-feedback.md(what was tried, why blocked, what would unblock). - Expiry: If
expiresAtin the past, another agent may take over (setstatus: in-progress, newassignee, freshexpiresAt).
Status flow
plan ──→ open ──→ claimed ──→ in-progress ──→ done (requiresHumanReview: false)
──→ review ──→ done (requiresHumanReview: true)
Any active state ──→ block ──→ in-progress or open
Archive
- Archive only when every task in the item has
status: done. Move the item folder toz-archive/<YYYY>/<MM>/<item-id>-<slug>/(including any-feedback.mdfiles). No shared file to update.
Limits
- Max 20 open items (max 20 directories in
work/). Recommended max 20 tasks per item.
Reconciliation
- Task files and directory structure are the source of truth. No task list in
index.md. If a task isdone,assigneeMUST be empty in the task file.
Checking the current spec
Before acting on the backlog, ensure your behavior matches the current spec. The single source of truth is SPEC.md in the repo (see Version in that file). This skill embeds a summary (Spec v4.0.5 above); when in doubt, prefer SPEC.md. In particular:
- Work-level metadata: Item
index.mdhaswork,status(plan | open | claimed | in-progress | done), andassignee. When status isclaimed, assignee is required (non-empty). When an agent claims a work item, set itemstatus: claimedandassignee: <agent-id>in that item'sindex.md; when releasing or when the item is done, clearassigneeand set status toopenordoneas appropriate. - Task-level metadata: Task files use
task,status,priority,dep,assignee,requiresHumanReview,expiresAt. Discovery is by listingwork/and task files only; no shared backlog or manifest file. - If the repo's
SPEC.mdversion is newer than the embedded spec, readSPEC.mdand follow it.
Step 1: Read current state
- Check if
.backlogmd/exists. If not, run Step 1b: Bootstrap before continuing. - List
.backlogmd/work/to get open item directories. - For each item directory, read
index.md(metadata:work, itemstatus, optionalassignee, CONTEXT) and list task files (<tid>-<task-slug>.md) and read their metadata to understand current items and tasks. Ignore-feedback.mdfor discovery; read them when working on a specific task.
Step 1b: Bootstrap (first-time setup)
If .backlogmd/ does not exist, create the initial structure:
- Create
.backlogmd/directory. - Create
.backlogmd/work/directory. - Create
.backlogmd/z-archive/directory (optional; can be created when first archiving).
Inform the user that the backlog has been initialized, then continue to Step 2.
Step 2: Determine intent
Based on $ARGUMENTS, determine which operation the user wants:
| Intent | Trigger examples |
|---|---|
| Init backlog | "init backlog", "set up backlogmd", "initialize" (also happens automatically if .backlogmd/ doesn't exist) |
| Create item | "add a feature for...", "new bugfix: ...", "refactor the...", "chore: ...", a work item description |
| Add tasks | "add tasks to...", "new task for..." |
| Update status | "mark task X as done", "start working on...", "task X is blocked", "release task...", "stop working on..." |
| Edit | "edit task...", "update description of...", "rename item..." |
| Archive | "archive item...", "clean up done items" |
| Show status | "what's the current state?", "show backlog", "what's in progress?" |
| Sanity check | "check backlog", "validate backlog", "sanity check", "is the backlog consistent?" |
If the intent is ambiguous, ask the user to clarify before proceeding.
Inferring the Type (optional)
When creating an item, you may infer a Conventional Commits type from context to include in the slug. This is optional — slugs without a type are valid.
- Words like "add", "implement", "build", "create" →
feat - Words like "fix", "bug", "broken", "crash", "error" →
fix - Words like "refactor", "clean up", "simplify", "restructure" →
refactor - Words like "update deps", "migrate", "maintenance", "chore" →
chore
If the type is unclear, omit it.
Operation A: Create a new item
A1. Propose the item and tasks
Based on $ARGUMENTS, propose:
- Item name — short, descriptive title
- Type (optional) — Conventional Commits type to include in the slug (e.g.
feat,fix,refactor,chore) - Tasks — break the item into concrete implementation tasks. For each task propose:
- Task name (
task) - Short description (2–3 sentences)
- Acceptance criteria (as checkbox items)
- Whether human review is required (
requiresHumanReview)
- Task name (
Present the full proposal and ask for confirmation or edits before writing any files.
A2. Item placement
After user confirms:
- List
.backlogmd/work/to get existing item directory names and infer existing item IDs. - Determine the next available
item-id(e.g. next number after highest existing).
Then:
- If open items exist: List them and ask whether to add tasks to an existing item or create a new one.
- If no open items exist: Proceed with creating a new item folder.
- If 20 directories already in work/: Archive a completed item first (all tasks
done), then create. If none can be archived, inform the user.
A3. Write all files (no shared file)
1. Create item directory and index.md
Create .backlogmd/work/<item-id>-<slug>/ and .backlogmd/work/<item-id>-<slug>/index.md with:
<!-- METADATA -->YAML:work: <work item title>,status: open(orplanif not ready for agents), optionalassignee: ""(set when work item is claimed).<!-- DESCRIPTION -->(optional).<!-- CONTEXT -->(optional; add context for agents if any).
2. Create task files
For each task, create .backlogmd/work/<item-id>-<slug>/<tid>-<task-slug>.md using the YAML task format.
- Task IDs are zero-padded to three digits and sequential within the item.
- Task slugs are lowercase kebab-case derived from the task name.
- Set initial status to
open(orplanif the task needs grooming). - Set
assignee: "",expiresAt: null.
Operation B: Update task status
B1. Identify the task
- List
.backlogmd/work/and scan item directories for task files (<tid>-<task-slug>.md); read metadata to locate the task (by name, id, or slug). - If ambiguous, list matching tasks and ask the user to pick one.
B2. Validate the transition
Valid status flow:
plan ──→ open ──→ claimed ──→ in-progress ──→ done (requiresHumanReview: false)
──→ review ──→ done (requiresHumanReview: true)
Any active state ──→ block ──→ in-progress or open
plan → open: promotion (human or authorized agent only).open → in-progress: start work — in task file setassignee(and optionallyexpiresAt); in itemindex.mdsetstatus: claimedorin-progressandassignee: <agent-id>. Verify everydeppath resolves to a task withstatus: done.in-progress → done: only valid whenrequiresHumanReview: false. Clear taskassignee; if all tasks in item are done, set itemstatus: doneand clear itemassignee.in-progress → review: required whenrequiresHumanReview: true. Keepassignee. Agent must stop.review → done: human only. Clearassignee.- Any active →
block: set when externally blocked.assigneepreserved. block → in-progress: when unblocked.block → open: when releasing claim — clear taskassignee; if no other task in progress in that item, set itemstatus: openand clear itemassignee.- Reject invalid transitions and explain why.
B3. Write changes (task file only)
- Update the task file's YAML metadata block to match the new status (and
assigneeif starting or releasing). If starting or releasing affects the work item (claim or release), update the item'sindex.mdmetadata: set or clearassignee, setstatustoclaimed,in-progress,open, ordoneas appropriate. - If moving to
done, check all acceptance criteria boxes (- [ ]→- [x]). - When setting
status: block, create or append to the task's-feedback.mdfile (what was tried, why blocked, what would unblock). When releasing because stuck, append to-feedback.mdbefore setting status to open.
B4. Handle item completion
If all tasks in the item now have status: done:
- Inform the user that all tasks in the item are complete.
- Ask if they want to archive the item.
Operation C: Edit an item or task
C1. Identify the target
List work/ and item directories; read index.md or task files to locate the item or task.
C2. Present current content
Show the current content and ask the user what they want to change.
C3. Apply edits (single file only)
- Task edits: Edit only the task file (metadata, description, acceptance criteria). If renaming task/slug, the task filename can be updated (move file) and any
depreferences in other task files that point to it must be updated. - Item edits: Edit only that item's
index.md(metadatawork/status, description, CONTEXT). No task list to sync.
C4. Confirm changes
Show the user a summary of what was changed.
Operation D: Archive an item
D1. Validate
- List task files in the item directory and read each task file's metadata. Verify all tasks in the item have
status: done. - If any tasks are not
done, inform the user and refuse to archive.
D2. Execute archive (single step)
- Move the item folder from
.backlogmd/work/<item-id>-<slug>/to.backlogmd/z-archive/<YYYY>/<MM>/<item-id>-<slug>/(create year/month directories if needed). This includesindex.md, all task files, and any-feedback.mdfiles.
D3. Confirm
Report to the user that the item has been archived and how many open item directories remain in work/ (out of 20).
Operation E: Show backlog status
E1. Read state from directory and files
List .backlogmd/work/; for each item directory read index.md (item title, item status) and list task files, then read each task file's metadata for task title and status.
E2. Present a summary
Show:
- Total open items (directories in
work/) and itemstatuswhere relevant - For each item: task breakdown by status (e.g. "3/5 tasks done, 1 in-progress, 1 open")
- Any tasks currently
in-progress(and their assignees) - Any tasks in
reviewawaiting human approval - Items ready to archive (all tasks
done) - Open item count (directories in
work/) and limit (20)
Operation F: Sanity check
Validate that the entire .backlogmd/ system is consistent. Read all files and check every rule below. Report issues grouped by severity.
F1. Read all state
- List
.backlogmd/work/and for each item directory readindex.mdand list task files (<tid>-<task-slug>.md), then read each task file. - If
z-archive/exists, list it (read-only check).
F2. Validate structure
-
work/exists. No requirement forbacklog.mdormanifest.json. - Every item folder under
work/has anindex.md. - Task files are named
<tid>-<task-slug>.md(zero-padded tid, kebab-case slug). - No more than 20 directories in
work/.
F3. Validate formats
- Every
index.mdhas<!-- METADATA -->,<!-- DESCRIPTION -->,<!-- CONTEXT -->and YAML with at leastworkandstatus; optionalassignee. Itemstatusis one ofplan,open,claimed,in-progress,done. Whenclaimed,assigneemust be non-empty; whenopenordone,assigneemust be empty; whenin-progress,assigneemay be set. - Every task file has
<!-- METADATA -->,<!-- DESCRIPTION -->,<!-- ACCEPTANCE -->and YAML with required fields:task,status,priority,dep,assignee,requiresHumanReview,expiresAt. - Task statuses are valid (
plan,open,in-progress,review,block,done). -
depvalues are paths relative to.backlogmd/:work/<item-id>-<slug>/<tid>-<task-slug>.md; no self-references, no duplicates, no cycles (DAG). - Item IDs and task IDs are zero-padded (min 3 digits) and unique in their scope.
-
in-progressandreviewtasks have non-emptyassignee.donetasks have emptyassignee. Items with statusclaimedhave non-empty itemassignee.
F4. Validate dependencies and workflow
- No circular dependencies (all
deppaths form a DAG). - No task is
in-progresswhile any of itsdep(resolved by path to that task file) is notdone. - No task with
requiresHumanReview: trueisdonewithout having gone throughreview.
F5. Validate archive
- No item folder in
z-archive/is also present inwork/.
F6. Report
Present results as:
- Errors — spec violations (missing markers, invalid statuses, broken
deppaths, cycles). - Warnings — items with all tasks done but not archived, stale
expiresAt. - OK — checks that passed.
If errors are found, offer to fix them (with user confirmation). Task file is source of truth for task state; no manifest to reconcile.
Rules
- Follow the spec formats exactly — YAML metadata in fenced code blocks, no YAML frontmatter.
- All paths are relative within
.backlogmd/. - Task edits: write only the task file. Item edits: write only that item's
index.md. Feedback: write only the task's-feedback.md. Never update a shared manifest or backlog file. - Never overwrite existing items or tasks — only create new item dirs/task files or edit in place.
- Always confirm with the user before writing or modifying files.
- Max 20 open items (directories in
work/). If the limit is reached, the user must archive an item or use an existing one. - The
z-archive/directory is cold storage. After moving items into it, never modify them again. - A completed task cannot be reopened. If the work needs revisiting, create a new task instead.
- When
requiresHumanReview: true, agents MUST NOT move a task directly fromin-progresstodone— it must go throughreview.