NAME

App::karr::Cmd::List - List tasks with filtering and sorting

VERSION

version 0.600

SYNOPSIS

karr list
karr list --status todo,in-progress --priority high,critical
karr list --claimed-by agent-fox --compact
karr list -s docker --json
karr list --sort priority --limit 5 --json
karr list --class expedite --not-blocked
karr list --unclaimed --sort priority -n 5

DESCRIPTION

Lists tasks from the current board with optional filtering and sorting. Finished tasks are excluded by default so the output focuses on active work: that means the board's terminal statuses -- its final configured status plus archived, so done and archived on a default board, but shipped and archived on a board whose columns end in shipped. Ask for them by name with --status, or for the archive alone with --archived. Use --compact for terse one-line output and --json for machine-readable automation.

--json emits each task as the full payload "to_json_hash" in App::karr::Task builds -- the frontmatter fields plus the body when the task has one, the same shape karr show --json returns. Reading a set of tickets is therefore one call rather than one show per id; --compact is the flag for when the bodies are not wanted.

Note that karr excludes the whole terminal group here where kanban-md's list excludes only archived and still shows finished work. That is a deliberate difference, not an oversight: karr list is the agent's "what is open" view.

FILTERS AND SORTING

  • --status, --priority

    Accept comma-separated lists and only return tasks matching one of the requested values.

  • --archived

    Shows the archive and nothing else. It is a status filter, so it replaces --status rather than intersecting with it -- matching kanban-md's flag of the same name -- while the remaining filters still narrow the result.

  • --assignee, --tag, --claimed-by

    Limit the result set to a specific assignee, tag, or claim owner.

  • -s, --search

    Performs a case-insensitive substring search across title, body, and tags.

  • --class

    Limits the result to one class of service. A class the board does not configure is a usage error (exit 2) naming the classes it does configure, the same answer karr create --class gives -- kanban-md compares the string and prints an empty list instead, which reads like "no such work" when the truth is "no such class". Note that list does not render the class, so the filter narrows on a field only --json and karr show display; the validation is what keeps a typo from looking like an empty board.

  • --blocked, --not-blocked

    Show only the blocked cards, or only the unblocked ones. blocked is what the meta column already prints, so this narrows on something visible. Passing both is a usage error (exit 2): kanban-md lets --blocked win silently, and karr refuses a self-contradicting invocation instead, as it does for edit --claim --release and move --next --prev (ticket #235).

  • --unclaimed

    Shows only the cards nobody is holding right now -- claimed_by unset or empty, or set to a claim older than the board's claim_timeout. It is the answer to "what is free" that until now only karr pick could give, and pick answers it by taking the card.

    The test is not a second reading of the field: this filter calls "claim_held" in App::karr::Role::ClaimTimeout, the same method "pickable" in App::karr::Role::PickRules calls, so a card list --unclaimed shows is a card karr pick can hand out. It asks about the claim and nothing else, matching kanban-md's IsUnclaimed: blocked cards and cards with unmet dependencies are unpickable but not claimed, so they are still listed, and --blocked --unclaimed is a real query rather than an empty one. On a board with claim_timeout: 0s no claim ever expires, so there --unclaimed means claimed_by empty and nothing more.

    --unclaimed is not the negation of --claimed-by, which is where #237's reading of the pair went wrong. --claimed-by NAME is an exact string match on the field and matches an expired claim too, because the name stays on the card until something re-stamps it; --unclaimed is about who holds the card now. Passing both is a usage error (exit 2) -- see the comment in _validate_options for why that is the answer even though the two do have a common case.

  • --sort, --reverse

    Sort by id, title, status, priority, created, updated, or due, and optionally reverse the result order. Any other field is a usage error (exit 2).

    status follows the board config's own order. priority deliberately reads the config list the other way, most urgent first: --sort priority lists critical before low with the default priorities setting, so the top of a priority-sorted list is the task App::karr::Cmd::Pick would hand out, and --reverse gives the least-urgent-first view. kanban-md's ascending config order opened the list with the least urgent task when karr took this direction; it has since made the same change, so the two agree. title compares case-insensitively, as kanban-md does, so Apple sorts before banana rather than ahead of every lowercase title. The comparison is on characters and not collated, so a title starting outside ASCII sorts after every ASCII one.

    Collation is a non-goal, not a gap. --sort title is lc plus a codepoint compare, and it stays that way: Aebi, Zebra, Abi sorts Abi, Aebi, Zebra under German rules and Abi, Zebra, Aebi here. What the option promises is a stable, reproducible order that agrees with kanban-md on the same board -- not a locale-correct one. A collating sort would need a locale to collate for, and a board is read by agents on machines that share none; two hosts would then disagree about what --sort title --limit 5 returns. Anyone who needs alphabetical order for a human takes --json and sorts it where the locale is known.

    Tasks without a due date sort last. Ties are broken by id, and --reverse turns the finished list around, tied entries with it.

  • -n, --limit

    Keeps at most N tasks, applied after filtering and after sorting -- so --sort priority --limit 5 is the five most urgent open cards, not five arbitrary ones put in order. 0, the default, means no limit. A negative value is a usage error (exit 2) rather than kanban-md's silent "unlimited". The cut applies to --json and --compact exactly as it does to the table.

    This is not --last, which karr show and karr log use for a different question: --last N is the N most recent by time, --limit N is the head of whatever --sort just produced. karr list --sort updated --reverse --limit 5 is how this command spells the former.

Filters run first, then the sort, then --limit. That is kanban-md's order in board.List and it is the only one that makes the last stage mean anything.

SEE ALSO

karr, App::karr, App::karr::Cmd::Show, App::karr::Cmd::Board, App::karr::Cmd::Create, App::karr::Cmd::Pick

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/karr/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)