Skip to content

About

Lint task handoffs (human or AI agent) for a missing owner, next step, blockers, done criteria or evidence.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

task-handoff-check

Lint a task handoff (human or AI agent) for a missing owner, next step, blockers, done criteria or evidence before someone else picks it up.

Catch incomplete or contradictory task handoffs before someone else picks up the work. This small CLI and library checks an explicit JSON document for a clear owner, next action, blockers, completion criteria and evidence references.

A passing handoff is structurally consistent. It is not proof that its claims are true, that its references exist, or that anyone is authorized to act.

An open-source engineering utility from IT Custom Solution. Python 3.10+, no runtime dependencies, no network access, no commands executed. MIT licensed.

Release and verification

Published packages are on PyPI, and release notes are on GitHub. The source tree may contain unreleased changes. The tool is MIT licensed.

The release-preparation test run passed. That link records its own revision and jobs; it is not a claim that every later commit or platform has been tested. Run the local checks for your checkout.

Install the latest published package in an activated virtual environment:

python -m pip install --upgrade task-handoff-check
task-handoff-check --version

The two-tool walkthrough shows a consistent handoff, a valid manifest and deliberate failure cases using fictional data.

Try it in one minute

git clone https://github.com/itcustomsolution/task-handoff-check.git
cd task-handoff-check
python -m task_handoff_check examples/in-progress.json
python -m task_handoff_check examples/complete.json --json
python -m task_handoff_check examples/invalid-complete.json --json

The first two checks pass. The third exits 1 because it claims complete while listing an open blocker. All examples, people and references are fictional; referenced paths deliberately need not exist. The tool never opens them.

Install the latest published release with pipx install task-handoff-check (or pip install task-handoff-check). This README describes the source tree, which can contain unreleased changes; see CHANGELOG.md and use the source installation below to get them.

To install from source in a virtual environment:

python -m venv .venv
. .venv/bin/activate
python -m pip install .
task-handoff-check --version

Installation uses setuptools as a build dependency. Running from the checkout needs only the Python standard library; no package registry release is required.

Handoff format

{
  "schema_version": 1,
  "objective": "Review the sample release notes",
  "owner": "Sample Maintainer",
  "status": "in_progress",
  "next_action": "Compare the notes with the sample changelog",
  "inputs": [
    {
      "label": "changelog",
      "path": "docs/changelog.md"
    }
  ],
  "evidence": [],
  "blockers": [],
  "completion_criteria": [
    {
      "description": "All sample changes reviewed",
      "met": false,
      "evidence": []
    }
  ],
  "updated_at": "2026-01-01T09:00:00Z"
}

All shown fields except updated_at are required. Unknown fields are errors.

Field Rule
schema_version Integer 1
objective, owner Meaningful nonempty text
status ready, in_progress, blocked, or complete
next_action Meaningful text for unfinished work; JSON null for complete
inputs, evidence Arrays of reference objects; may be empty
blockers Array of objects with description and owner; open blockers only
completion_criteria Nonempty array with description, boolean met, and evidence
updated_at Optional timestamp with seconds and timezone

A reference contains a meaningful label and exactly one path or url. Paths must be portable relative paths without traversal, control characters, reserved device names or Windows-reserved punctuation. URLs must be absolute HTTP(S) references without embedded credentials. Labels must be distinct within each array after Unicode NFC normalization and case folding.

Each criterion's evidence is an array of exact labels from the top-level evidence array. A met: true claim requires at least one such reference. Repeated evidence labels and repeated criterion descriptions are rejected. Reference content and accessibility are never checked.

blocked requires at least one open blocker and a concrete next action. Any open blocker requires blocked. complete requires all criteria to be met: true, no blockers and a null next_action. Other statuses may contain met criteria while further work remains. This is deliberately a small task state model; it is not a general workflow engine.

Blank text, control characters and exact placeholders such as TBD, todo, unknown, unassigned, n/a, none, - and ? are rejected. The tool does not understand free text semantically: an unhelpful sentence can still pass.

Optional, reproducible freshness checks

Freshness is never inferred from the machine's current time. Supply --as-of to compare timestamps; optionally specify an inclusive maximum age:

python -m task_handoff_check examples/in-progress.json \
  --as-of 2026-01-02T09:00:00Z --max-age-hours 24 --json

This example passes exactly at the 24-hour boundary. One second later it is stale. --max-age-hours must be a finite, nonnegative number and accompanied by --as-of; choosing a meaningful freshness policy is up to you. Supplying --as-of requires a valid updated_at and rejects a future update. --as-of alone compares chronology, without a maximum-age policy.

Accepted timestamps use YYYY-MM-DDTHH:MM:SS, optional 1–6 fractional digits, and Z or an explicit +HH:MM/-HH:MM offset. Leap seconds are unsupported. The timestamp remains an assertion from the document author.

Reports and exit codes

JSON reports contain ok, scope (handoff_consistency), freshness, and an issues array of code, location and message. freshness is one of not_evaluated, unavailable, timestamp_compared, future, within_limit or stale. Other schema errors can coexist with a valid timestamp comparison.

Exit Meaning
0 Consistency checks pass; or help/version displayed
1 Invalid input, inconsistent handoff or failed timestamp check
2 Invalid command-line usage or freshness options

Common issue codes: invalid_schema, unknown_field, missing_text, status_conflict, invalid_reference, duplicate_label, duplicate_criterion, incomplete_criterion, missing_evidence, unknown_evidence, invalid_timestamp, missing_timestamp, future_timestamp, stale, input_error. Messages are human-facing. --json validation reports use stdout; CLI usage errors use stderr.

Library

from task_handoff_check import load_handoff, validate_handoff

handoff = load_handoff("examples/complete.json")
report = validate_handoff(handoff)
assert report["ok"]
report = validate_handoff(
    handoff, as_of="2026-01-02T09:00:00Z", max_age_hours=24
)

validate_handoff returns issues for invalid documents and raises HandoffError for invalid freshness options. The library accepts max_age_hours as a finite, nonnegative integer or float; integers of any size are compared exactly, a float is compared exactly as the binary value it holds (so 0.1 is very slightly more than one tenth), and booleans and nonfinite values are rejected. load_handoff raises HandoffError for input errors, including numbers such as 1e999 that overflow Python's finite floating-point range. Validation does not mutate the document. Parser errors identify a location without repeating JSON content or the input filename.

Limits and development

Input must be a regular UTF-8 JSON file of at most 1 MiB; final-component symlinks, duplicate JSON keys and nonfinite numbers are rejected. Parent symlinks may be followed for the explicitly supplied input document. Use trusted local input locations; the input reader is not a filesystem sandbox.

The tool performs no authentication, authorization, link checking, ownership verification, work execution, scheduling, agent dispatch or compliance assessment. It never changes a task's state. See SECURITY.md.

python -m unittest discover -s tests -v

Tests use synthetic inputs and temporary directories. The pull-request workflow is configured for Python 3.10, 3.12 and 3.14 on Linux, plus Python 3.14 on macOS. Configured jobs are not executed by this change; workflow run results are the evidence of executed coverage. See CONTRIBUTING.md.

Using a handoff in a workflow

Use a passing report to start the next person's review: they still need to inspect the evidence, confirm authority and accept the work against agreed criteria. This utility does not connect your task systems or establish that a live handoff process works end to end.

For help mapping one IT workflow's owners, exceptions and evidence gaps, see ITC's IT Operations Workflow Review. The outcome is a practical improvement brief, with optional AI readiness where relevant. Implementation and ongoing operation are separately scoped.

The review covers one workflow: process map, exceptions, evidence gaps, ownership and access, prioritized actions, and handover. An automation brief is included only if justified. Scope, timing and fees follow inquiry; implementation is separate.

Contributing

Issues and small pull requests are welcome; see CONTRIBUTING.md. Run python -m unittest discover -s tests before opening a PR. Release history is in CHANGELOG.md.

License

MIT, see LICENSE.

About

Lint task handoffs (human or AI agent) for a missing owner, next step, blockers, done criteria or evidence.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages