Task Management
Depth:
ait create
Create new task files with YAML frontmatter metadata. Supports standalone and parent/child task hierarchies.
Interactive mode (default — requires fzf):
- Draft management — If drafts exist in
aitasks/new/, a menu appears: select a draft to continue editing, finalize (assign real ID and commit), or delete — or create a new task - Parent selection — Choose “None - create standalone task” or select an existing task as parent from a fzf list of all tasks (shown with status/priority/effort metadata)
- Priority — Select via fzf: high, medium, low
- Effort — Select via fzf: low, medium, high
- Issue type — Select via fzf from
aitasks/metadata/task_types.txt(bug, chore, documentation, enhancement, feature, manual_verification, performance, refactor, style, test) - Status — Select via fzf: Ready, Editing, Implementing, Postponed
- Labels — Iterative loop: pick from existing labels in
aitasks/metadata/labels.txt, add a new label (auto-sanitized to lowercase alphanumeric + hyphens/underscores), or finish. New labels are persisted to the labels file for future use - Dependencies — fzf multi-select from all open tasks. For child tasks, sibling tasks appear at the top of the list. Select “None” or press Enter with nothing selected to skip
- Sibling dependency (child tasks only, when child number > 1) — Prompted whether to depend on the previous sibling (e.g., t10_1). Defaults to suggesting “Yes”
- Task name — Free text entry, auto-sanitized: lowercase, spaces to underscores, special chars removed, max 60 characters. Preview shows
draft_*_<name>.md(real ID is assigned during finalization) - Description — Iterative loop: enter text blocks, optionally add file references (fzf file walker with preview of first 50 lines, can also remove previously added references), then choose “Add more description” or “Done - create task”
- Post-creation — Choose: “Finalize now” (claim real ID and commit), “Show draft”, “Open in editor” ($EDITOR), or “Save as draft” (finalize later via
ait createor--batch --finalize)
Batch mode (for automation and scripting):
# Creates draft in aitasks/new/ (no network needed)
ait create --batch --name "fix_login_bug" --desc "Fix the login issue"
# Auto-finalize: claim real ID and commit immediately (requires network)
ait create --batch --name "add_feature" --desc "New feature" --commit
# Finalize a specific draft
ait create --batch --finalize draft_20260213_1423_fix_login.md
# Finalize all pending drafts
ait create --batch --finalize-all
# Child task (auto-finalized with --commit)
ait create --batch --parent 10 --name "subtask" --desc "First subtask" --commit
# Read description from stdin
echo "Long description" | ait create --batch --name "my_task" --desc-file -
| Option | Description |
|---|---|
--batch | Enable batch mode (non-interactive) |
--name, -n NAME | Task name (required, auto-sanitized) |
--desc, -d DESC | Task description text |
--desc-file FILE | Read description from file (use - for stdin) |
--priority, -p LEVEL | high, medium, low (default: medium) |
--effort, -e LEVEL | low, medium, high (default: medium) |
--type, -t TYPE | Issue type from task_types.txt (default: feature) |
--status, -s STATUS | Ready, Editing, Implementing, Postponed (default: Ready) |
--labels, -l LABELS | Comma-separated labels |
--deps DEPS | Comma-separated dependency task numbers |
--verifies IDS | Comma-separated task IDs this task verifies (usually a manual_verification task, but any issue type may carry it) |
--also-blocks-dependents GATES | Comma-separated gates that must also pass before this task’s dependents unblock, beyond the registry defaults. Writes also_blocks_dependents |
--file-ref REF | Add a file reference (path, path:N, or path:N-M; repeatable) |
--parent, -P NUM | Create as child of parent task number |
--no-sibling-dep | Don’t auto-add dependency on previous sibling |
--assigned-to, -a EMAIL | Assignee email |
--issue URL | Linked issue tracker URL |
--pull-request URL | Linked pull request URL |
--contributor NAME | External contributor name for Co-Authored-By |
--contributor-email EMAIL | External contributor email |
--commit | Claim real ID and commit to git immediately (auto-finalize) |
--finalize FILE | Finalize a specific draft from aitasks/new/ (claim ID, move to aitasks/, commit) |
--finalize-all | Finalize all pending drafts in aitasks/new/ |
--silent | Output only filename (for scripting) |
Key features:
- Tasks are created as drafts in
aitasks/new/by default (no network required). Finalization claims a globally unique ID from an atomic counter on theaitask-idsgit branch - Drafts use timestamp-based filenames (
draft_YYYYMMDD_HHMM_<name>.md) and are local-only (gitignored) - Child task IDs are assigned via local scan (safe because the parent’s unique ID acts as a namespace)
- Atomic counter fallback: in interactive mode, warns and asks for consent to use local scan; in batch mode, fails hard if counter is unavailable
- Child tasks stored in
aitasks/t<parent>/with namingt<parent>_<child>_<name>.md - Updates parent’s
children_to_implementlist when creating child tasks - Name sanitization: lowercase, underscores, no special characters, max 60 chars
- Duplicate ID detection:
ait lswarns if duplicate task IDs are found;ait updatefails with a suggestion to runait setup
ait ls
List and filter tasks sorted by priority, effort, and blocked status.
ait ls -v 15 # Top 15 tasks, verbose
ait ls -v -l ui,backend 10 # Filter by labels
ait ls -v -s all --tree 99 # Tree view, all statuses
ait ls -v --children 10 99 # List children of task t10
ait ls -v --no-followup-kind 15 # Genuine new work only (no auto-spawned follow-ups)
ait ls --plan-approved 15 # Tasks with an approved plan awaiting implementation
ait ls --boardcol now 15 # Tasks in the board's "now" column
| Option | Description |
|---|---|
[NUMBER] | Limit output to top N tasks |
-v | Verbose: show status, priority, effort, issue type, follow-up kind, deferred-plan marker, assigned, issue |
-s, --status STATUS | Filter by status: Ready (default), Editing, Implementing, Postponed, Done, all |
-l, --labels LABELS | Filter by labels (comma-separated, matches any) |
--type TYPE | Filter by issue type. A task with no issue_type: field counts as feature |
--boardcol COL | Filter by board column id, exactly as the board groups tasks. Validated against the project’s configured columns (plus unordered); an unknown id is rejected |
--followup-kind KIND | Filter to auto-spawned follow-ups of one kind (e.g. risk_mitigation) |
--no-followup-kind | Only tasks that are not auto-spawned follow-ups. Mutually exclusive with --followup-kind |
--plan-approved | Only tasks carrying plan_approved_at — an approved plan whose implementation was deliberately deferred, ready to be picked up without re-planning |
--no-plan-approved | Only tasks without that marker. Mutually exclusive with --plan-approved |
-c, --children PARENT | List only children of specified parent task number |
--all-levels | Show all tasks including children (flat list) |
--tree | Hierarchical tree view with children indented under parents |
Sort order (unblocked tasks first, then): priority (high > medium > low) → effort (low > medium > high). Issue type, follow-up kind and the deferred-plan marker are shown in -v output but are not sort dimensions.
Deferred approved plans. A task stopped at the planning checkpoint with “Approve and stop here” keeps its plan and returns to Ready, so it otherwise looks untouched. -v renders it as Plan: approved <YYYY-MM-DD HH:MM>; the plain listing stays filename-only, so --plan-approved is how you find these without -v. The marker is cleared as soon as it stops being true — implementation starts, the plan is replanned or aborted, the task is decomposed into children, or a remote-drift stop requires re-verification. The board surfaces the same state as a · Planned card qualifier and a dedicated In-Flight lane — see In-Flight Lanes and Workflow Phases.
Board column. --boardcol answers “what is in this column?” from the CLI, resolving each task’s column through the same rule the board renders with — so its result matches a board lane exactly, including a project whose columns have been renamed.
--boardcol unordered selects the Unsorted / Inbox lane, which is two on-disk states: tasks with no boardcol field at all, and tasks explicitly moved there, which ait board and ait update --boardcol unordered both record as boardcol: unordered. Both are one lane on the board, so both match here.
An unknown column id is rejected, naming the configured ids. That matters because the alternative — returning zero rows — is indistinguishable from “that column is empty”, which is exactly what a typo or a renamed column would produce.
Follow-up kind marks a task as auto-spawned by the workflow rather than as new work. -v shows it as a Follow-up: <kind> field, present only when the task carries one — its absence means genuine new work. --followup-kind and --type both reject an unrecognised value rather than silently matching nothing.
View modes:
- Normal (default) — Parent tasks only. Parents with pending children show “Has children” status
- Children (
--children N) — Only child tasks of parent N - All levels (
--all-levels) — Flat list of all parents and children - Tree (
--tree) — Parents with children indented using└─prefix
Unnumbered task files. A listing candidate whose name carries no task id — t_something.md, where a number should follow the t — is skipped, and a warning naming the path is written to stderr. A listing row has to be addressable: everything downstream of ait ls maps a row back to a task id, and a row with no id yields an empty one, which then asks about a task that cannot exist. Skipping it silently would be no better, because the file is usually a real task nobody can reach, so the warning is what makes the defect visible. Rename the file to the naming convention to bring it back into the listing.
This covers the files ait ls actually looks at — those matching t<...>_<...>.md. A name further from the convention, such as tbroken.md, is not a listing candidate in the first place: it is absent from the listing with no warning, because nothing ever visits it. Neither shape is reachable through ait create, which always assigns an id.
Metadata format: Supports both YAML frontmatter (primary) and legacy single-line format (--- priority:high effort:low depends:1,4).
ait update
Update task metadata fields interactively or in batch mode. Supports parent and child tasks.
Interactive mode (default — requires fzf):
- Task selection — If no task number argument given, select from fzf list of all tasks (shown with metadata). Can also pass task number directly:
ait update 25 - Field selection loop — fzf menu showing all editable fields with current values:
priority [current: medium]effort [current: low]status [current: Ready]issue_type [current: feature]dependencies [current: None]labels [current: ui,backend]description [edit in editor]rename [change filename]Done - save changesExit - discard changes
- Per-field editing:
- priority/effort/status/issue_type — fzf selection from valid values
- dependencies — fzf multi-select from all tasks (excluding current), with “Clear all dependencies” option
- labels — Iterative fzf loop: select existing label, add new label (sanitized), clear all, or done
- description — Shows current text, then offers “Open in editor” ($EDITOR with GUI editor support for VS Code, Sublime, etc.) or “Skip”
- rename — Text entry for new name (sanitized), displays preview of new filename
- Save — Select “Done” to write changes. “Exit” discards all changes
- Git commit — Prompted Y/n to commit
Batch mode (for automation):
ait update --batch 25 --priority high --status Implementing
ait update --batch 25 --add-label "urgent" --remove-label "low-priority"
ait update --batch 25 --name "new_task_name" --commit
ait update --batch 10_1 --status Done # Update child task
ait update --batch 10 --remove-child t10_1 # Remove child from parent
| Option | Description |
|---|---|
--batch | Enable batch mode |
--priority, -p LEVEL | high, medium, low |
--effort, -e LEVEL | low, medium, high |
--status, -s STATUS | Ready, Editing, Implementing, Postponed, Done |
--type TYPE | Issue type from task_types.txt |
--deps DEPS | Dependencies (comma-separated, replaces all) |
--labels, -l LABELS | Labels (comma-separated, replaces all) |
--add-label LABEL | Add a single label (repeatable) |
--remove-label LABEL | Remove a single label (repeatable) |
--description, -d DESC | Replace description text |
--desc-file FILE | Read description from file (use - for stdin) |
--name, -n NAME | Rename task (changes filename) |
--assigned-to, -a EMAIL | Assignee email (use "" to clear) |
--issue URL | Issue tracker URL (use "" to clear) |
--add-child CHILD_ID | Add child to children_to_implement |
--remove-child CHILD_ID | Remove child from children_to_implement |
--children CHILDREN | Set all children (replaces list) |
--verifies IDS | Set verifies list (comma-separated task IDs, replaces all) |
--add-verifies ID | Add one verified task ID (repeatable) |
--remove-verifies ID | Remove one verified task ID (repeatable) |
--also-blocks-dependents GATES | Set the extra dependent-unblocking gates (comma-separated, replaces all; use "" to clear) |
--file-ref REF | Add a file reference (path, path:N, or path:N-M; repeatable) |
--remove-file-ref REF | Remove a file reference (exact-string match; repeatable) |
--boardcol COL | Board column ID. Validated against the project’s configured columns (plus unordered); an unknown id is rejected. Use "" to clear |
--boardidx IDX | Board sort index |
--pull-request URL | Linked pull request URL (use "" to clear) |
--contributor NAME | External contributor name for Co-Authored-By (use "" to clear) |
--contributor-email EMAIL | External contributor email (use "" to clear) |
--folded-tasks IDS | Comma-separated task IDs merged into this task |
--folded-into NUM | Primary task number this was merged into |
--implemented-with STRING | Agent/model attribution (e.g., claudecode/opus4_7_1m) |
--commit | Auto-commit to git |
--silent | Output only filename |
Key features:
- Auto-updates
updated_attimestamp on every write - Child task format: use
10_1ort10_1to target child tasks - When a child task is set to Done, automatically removes it from parent’s
children_to_implementand warns when all children are complete - Parent tasks cannot be set to Done while
children_to_implementis non-empty