Skip to content

Validation engine for task and note quality (rule table + lint, commitlint-style) #5

Open

Description

@alycda

Problem

A taskbook with a few hundred items stops being a board and becomes a backlog nobody reads. On my own board (109 live items, 145 archived) a hand review on 2026-10-26 found that about a quarter of open tasks had no verb (~/containers, htop, VLC (cask)), notes split into bare tags with no content and 800-character runbooks, and 11 CA tasks repeated the same three sentences of rationale. Items like that are not actionable, and for an ADHD reader an item that cannot be acted on is an item that silently costs attention every time it scrolls past. Anyone running taskbook at 1000+ items has the same problem, diagnosis or not.

A second audience is agents. Models write to the board over tb --mcp now (#3 adds links and a size envelope for the same reason), and they produce exactly the failure modes above unless something pushes back at write time. commitlint did this for commit messages: a small rule file, a predictable error, and the writer learns the shape.

Proposal: a validation engine for items

A rule table plus an engine that evaluates every item (or one item, at write time) and reports findings with a severity.

Rule file, TOML, schema v1. One [[rule]] per predicate:

field values
id stable slug, printed in output
applies task / note / any
state tasks only: pending / in_progress / done / open (default any)
severity error / warn / info; exit 1 only when an error fired
message text; {days} {ref} {other} {len} interpolated where the kind provides them
except_boards skip items on any of these boards
kind regex (pattern, flags, negate), count (pattern, max), length (min, max), board (boards), ref (dangling #N; the archive is not consulted, tb renumbers archived items), duplicate (case- and space-folded text), overdue (tasks past _dueDate)

Regex dialect is the common subset of Oniguruma (jq) and Rust's regex crate: no lookaround, no backreferences. The point is that the same rules.toml drives a jq prototype today and a Rust implementation inside tb later.

The v1 rule set, which is just the hand review encoded:

  • task is a bare path, bare URL, or single word (error)
  • task under 25 chars (warn), over 300 chars (warn), or chaining more than three steps (warn)
  • note that starts with an action verb, or sits on @todo (error)
  • note under 25 chars outside inventory boards (warn)
  • item on My Board (error): the tag was quoted into the description
  • description ending in a literal @tag (warn): tb -e keeps old boards and leaves tags as text
  • #N naming no live item (error)
  • two live items with the same text (warn)
  • open task past its due date, with days overdue (info)

Prototype

Running now as lint/zk-lint.sh (jq 1.7+, about 90 lines) next to the data in my ~/.taskbook repo. First run over the board after the hand review: 10 errors, 12 warnings, 1 info. It caught two items on My Board, a bare-URL task, three notes tagged @todo and three references to purged items that the hand pass missed. One known false positive: an @Apps inventory note named Install macOS Catalina trips the action-verb rule.

Where it could land in tb

  1. tb --lint (or zk lint): whole-board report, exit code for scripts and motd.
  2. Write-time check in create_task, create_note, edit_item on the MCP server and the CLI: error-level findings refuse the write and return the message, so an agent gets the same feedback a human gets from commitlint.
  3. Rules file discovery: ~/.taskbook/lint/rules.toml, with the v1 set as the built-in default.

Open questions: whether warn should ever block a write (I think no); whether the verb check should stay a negative pattern (bare path, URL, single word) or grow a verb list (negative is more robust, a list is more legible); how to express rules that need the whole board (ref, duplicate) in a write-time check that only sees one item.

Related: #3 (links, backlinks, size envelope). While doing the hand review I misread two CLI behaviours as bugs (--tag writes a separate tags field that is only serialized when non-empty; -e sets the description verbatim and boards move with -m). Verified against source and by reproduction; not filing. The --move section of docs/cli-reference.md does have two errors, fixed in a separate doc PR.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions