CLI Command Contract
====================
Taskledger uses a task-first command grammar:
.. code-block:: text
taskledger [--root PATH] [--json] [RESOURCE_REF] [--task TASK_REF] [options]
Global Options
--------------
* ``--root PATH`` selects the workspace root.
* ``--json`` is root-level only and must appear before the command group.
* Command-local ``--json`` options are not part of the public contract.
``--cwd`` remains accepted as a compatibility root alias, but docs and examples
should prefer ``--root``.
Task Scoping
------------
Task-scoped workflow commands default to the active task. Use
``--task TASK_REF`` when explicitly targeting another task.
.. code-block:: bash
taskledger plan start
taskledger plan start --task task-0001
taskledger implement resume --task task-0001 --reason "Reacquire implementation lock."
taskledger implement restart --task task-0001 --summary "Fix validation findings."
taskledger implement finish --task task-0001 --summary "Implemented."
taskledger review record --task task-0001 --result pass --summary "No blocking issues."
taskledger validate status --task task-0001
Task-resource commands accept the task as their direct positional resource:
.. code-block:: bash
taskledger task show task-0001
taskledger task cancel task-0001 --reason "Duplicate"
taskledger task archive task-0001 --reason "Hide historical task"
taskledger task unarchive task-0001 --reason "Restore task"
taskledger task report task-0001
Root reporting commands render standalone HTML:
.. code-block:: bash
taskledger report html task-0040 --output task-0040.html
taskledger report html --active --output active-task.html
taskledger report site --output .taskledger-report/
Serve supports optional positional task selection and refresh in seconds:
.. code-block:: bash
taskledger serve --refresh-seconds 2
taskledger serve --task task-0040 --refresh-seconds 2
Optional positional task refs are not supported for workflow commands.
Plan guidance command
---------------------
``taskledger plan guidance`` is a read-only planning helper command:
.. code-block:: bash
taskledger plan guidance [--task TASK_REF] [--format markdown|json]
Rules:
* defaults to the active task when ``--task`` is omitted;
* ``--format`` accepts only ``markdown`` or ``json``;
* when a planning run is active, it records a one-time guidance-view marker for
that run and appends a ``plan.guidance.viewed`` event;
* root ``--json`` continues to return the standard CLI success/error envelope.
The command payload shape is:
* ``kind``
* ``task_id``
* ``has_project_guidance``
* ``guidance``
* ``profile``
* ``question_policy``
Plan revision commands
----------------------
``taskledger plan export`` renders an editable plan draft outside durable
storage, and ``taskledger plan amend`` applies structured plan-review edits:
.. code-block:: bash
taskledger plan export [--task TASK_REF] [--version latest|N] [--file PATH] [--overwrite] [--stdout]
taskledger plan amend [--task TASK_REF] [--drop-criterion CRITERION_ID ...] [--drop-todo TODO_ID ...] [--remove-file PATH ...] --reason "..."
Plan proposal commands that accept ``--file`` reject file paths under
``.taskledger/`` because that directory is private durable ledger state.
Plan review command
-------------------
``taskledger plan review`` is a read-only approval-facing plan renderer:
.. code-block:: bash
taskledger plan review [--task TASK_REF] [--version N] [--format markdown|json] [-o PATH]
Rules:
* defaults to the active task when ``--task`` is omitted;
* defaults to the latest proposed plan in ``plan_review`` stage when ``--version`` is omitted;
* renders Markdown by default and can emit JSON-formatted content with ``--format json``;
* when ``-o/--output`` is provided, writes rendered content to a file path.
Archive import lock policy
--------------------------
Archive imports support explicit lock handling:
.. code-block:: bash
taskledger import ./taskledger-transfer.tar.gz --replace [--lock-policy drop|quarantine|keep]
taskledger import ./taskledger-task---task-0040-.tar.gz [--id-policy preserve|renumber-on-conflict|fail-on-conflict]
The default is ``quarantine`` so imported source-machine runtime locks are not
restored as active ``lock.yaml`` files. ``keep`` is diagnostic-only behavior
for full-fidelity lock restoration.
Transfer archive manifest contract
----------------------------------
Transfer archives include both machine identity and human-readable metadata:
``manifest.project.name`` and ``manifest.project.slug`` are display metadata,
while ``manifest.project.uuid`` remains the safety identity.
.. code-block:: json
{
"project": {
"uuid": "",
"name": "",
"slug": "",
"ledger_ref": ""
}
}
Import compatibility is backward-safe: older archives that only contain
``project.uuid`` and ``project.ledger_ref`` remain valid. UUID comparison is
still authoritative for import safety.
``taskledger import --dry-run`` must not mutate taskledger state for either
archive or JSON payload imports.
Export task selection
---------------------
Taskledger export supports full-ledger and task-scoped archives:
.. code-block:: bash
taskledger export
taskledger export ./backup.tar.gz
taskledger export --task task-0040
taskledger export task-0040
taskledger export task-0040 -o ./task0040.tar.gz
Positional Resource Refs
------------------------
Positional refs are reserved for the direct resource being changed or shown:
.. code-block:: bash
taskledger task create TITLE [options]
taskledger task record TITLE [options]
taskledger task activate TASK_REF
taskledger task follow-up PARENT_REF TITLE [options]
taskledger todo done TODO_ID --task TASK_REF --evidence "pytest -q"
taskledger question answer QUESTION_ID --task TASK_REF --text "Yes."
taskledger handoff show HANDOFF_ID --task TASK_REF
taskledger require add REQUIRED_TASK_REF --task TASK_REF
taskledger release show 0.4.1
Release commands
----------------
Release boundaries are durable project records, not task lifecycle states:
.. code-block:: bash
taskledger release tag 0.4.1 --at-task task-0030 --note "0.4.1 released"
taskledger release list
taskledger release show 0.4.1
taskledger release changelog 0.4.2 --since 0.4.1 --until-task task-0035 --output /tmp/taskledger-0.4.2-changelog-source.md
``release tag`` writes a durable release record under the current ledger's
``releases/`` directory.
``release changelog`` is read-oriented: it renders Markdown or JSON changelog
context from done tasks and may write an external output file, but it does not
mutate ledger state.
Ledger commands
---------------
Branch-scoped ledgers isolate ignored local task state by the checked-in
``ledger_ref`` stored in ``taskledger.toml``:
.. code-block:: bash
taskledger ledger status
taskledger ledger list
taskledger ledger fork feature-a
taskledger ledger switch main
taskledger ledger adopt --from feature-a task-0030
taskledger ledger doctor
``ledger fork`` creates a new local namespace under
``.taskledger/ledgers/[/`` and updates only Taskledger-owned ledger keys in
``taskledger.toml``. ``ledger switch`` changes the checked-in pointer to an
existing local ledger. ``ledger adopt`` copies a task from another local ledger
into the current ledger and renumbers on collision.
Storage and sync helper commands
--------------------------------
Taskledger also exposes local storage discovery and sync helpers:
.. code-block:: bash
taskledger storage where
taskledger storage move --to ../taskledger-state/project-a --mode copy|move [--adopt-existing] [--force]
taskledger sync preflight
taskledger sync status
taskledger sync commit --message "Sync project-a taskledger state"
taskledger sync export --output ./taskledger-transfer.tar.gz
taskledger sync import ./taskledger-transfer.tar.gz --dry-run
taskledger sync git status
taskledger sync git init --repo ../taskledger-state --project-path project-a
taskledger sync git commit --message "Sync project-a taskledger state"
cd "$(taskledger sync git cd)"
git pull --ff-only
git push
taskledger sync git hooks install
taskledger sync git hooks status
taskledger sync git hooks uninstall
Rules:
* ``storage where`` is read-only and reports the resolved workspace root,
config path, ``taskledger_dir``, project identity, ledger ref, Git detection,
and active lock count.
* ``storage move`` updates ``taskledger.toml`` atomically after the target has
been copied or explicitly adopted.
* ``sync preflight`` performs only local checks. It must not perform network
push/pull operations.
* ``sync status`` and ``sync commit`` operate only on the Git repository that
contains the resolved ``taskledger_dir``.
* ``sync export`` and ``sync import`` are archive aliases for the root
``export``/``import`` commands.
* ``sync git`` commands operate on a private external Git repository that stores
full project taskledger state under ``/``.
Config commands
---------------
Project config inspection and edits are available under ``config``:
.. code-block:: bash
taskledger config list
taskledger config show
taskledger config keys
taskledger config get prompt_profiles.planning.max_required_questions
taskledger config describe prompt_profiles.planning.plan_body_detail
taskledger config set prompt_profiles.planning.max_required_questions 3
taskledger config set prompt_profiles.planning.question_policy always_before_plan
Rules:
* dotted keys target nested TOML tables (for example
``prompt_profiles.planning.max_required_questions``);
* ``config keys`` lists available key names and path patterns;
* ``config describe`` provides key semantics, allowed values, defaults, and
whether a key is explicitly set;
* ``config set`` accepts TOML literals (numbers, booleans, arrays, inline
tables); when TOML parsing fails, the value is treated as a plain string;
* invalid values are rejected using standard LaunchError JSON/human envelopes.
``next-action`` result contract
-------------------------------
``taskledger next-action`` is the preferred fresh-context entrypoint for agents
and operators. It should identify the next concrete question, todo, criterion,
plan, dependency, or repair target instead of only naming a lifecycle bucket.
Human output should stay concise but actionable:
.. code-block:: text
todo-work: Implementation is in progress; 1 todos remain.
Next todo: todo-0001 -- Update next-action JSON payload.
Command: taskledger todo show todo-0001
Worker step: tester
Worker context: taskledger pipeline context tester
Worker handoff: taskledger handoff create --worker tester --summary "..."
Mark todo done after evidence exists: taskledger todo done todo-0001 --evidence "..."
Progress: 0/1 todos done
JSON output preserves the existing fields:
* ``kind``
* ``task_id``
* ``status_stage``
* ``active_stage``
* ``action``
* ``reason``
* ``blocking``
* ``next_command``
and may also include:
* ``next_item`` for the concrete target
* ``commands`` for ordered command hints with one primary command
* ``progress`` for question, todo, or validation queues
* ``worker_pipeline`` when an enabled ``guided`` worker pipeline has a pending
step; this object includes ``enabled``, ``mode``, ``next_step``,
``context_command``, and ``handoff_command``
* ``template_command`` plus ``required_plan_fields`` and
``recommended_plan_fields`` when the next step is regenerating a plan from
answered questions
* ``guidance_command`` when planning guidance should be reviewed before drafting
or regenerating a plan
Agents should inspect ``next_item``, prefer ``next_command`` when it is safe,
avoid inventing question answers, and never mark todos done without evidence.
When a task is in ``failed_validation``, ``next-action`` should direct agents
back to implementation with ``taskledger implement restart --summary SUMMARY``.
When a task persists ``planning``, ``implementing``, or ``validating`` as its
status but ``active_stage`` is missing, ``next-action`` must not report
``The task is cancelled.`` For an orphaned implementation with a still-running
latest implementation run and no active lock, it should direct agents to
``taskledger implement resume --task TASK_REF --reason "..."``.
For an approved task with a non-implementation run still marked running,
``next-action`` must not direct agents to ``taskledger implement start``.
It should report a repair-oriented action and point to ``taskledger doctor``.
Truly cancelled tasks recover through
``taskledger task uncancel --task TASK_REF --reason "..."``
Compact mutation output
........................
Mutation commands emit compact acknowledgements instead of full task or run records.
This reduces LLM context consumption during implementation loops.
The following commands produce compact output:
- ``todo add``: emits ``todo_added`` result with new todo, progress, and next command.
- ``todo done`` / ``todo undone``: emits ``todo_update`` result with todo id, status, progress, and next command.
- ``implement finish``: emits ``task_lifecycle`` result with task id, run id, status, and next command.
Human mode shows a one-line summary:
.. code-block:: text
added todo-0001 on task-0001 (0/3 done)
done todo-0001 on task-0001 (1/3 done)
finished implementation run-0001 task task-0001 -> implemented
JSON mode wraps the compact result in the standard success envelope with ``result_type``.
For full task, run, or todo details after a mutation, use:
- ``taskledger task show`` or ``taskledger status`` for task-level detail.
- ``taskledger todo show TODO_ID`` for individual todo detail.
- ``taskledger next-action`` for the next concrete step.
- ``taskledger todo next`` for the next open todo.
to a durable non-active stage rather than directly re-entering an active stage.
Run and lock repair
-------------------
Managed command wrappers
------------------------
``plan command`` and ``implement command`` mirror the inner command exit code by
default.
Use ``--allow-failure`` when you intentionally want to record a non-zero inner
exit code while returning wrapper exit code ``0``:
.. code-block:: bash
taskledger plan command -- pytest tests/ -q
taskledger plan command --allow-failure -- pytest tests/ -q
taskledger implement command -- ruff check --config=.ruff.toml .
taskledger implement command --allow-failure -- python -c "raise SystemExit(7)"
Transcript review modes
-----------------------
``task transcript`` defaults to review mode, which groups wrapper +
managed-shell pairs, highlights failures and wrapper/managed mismatches, and
flags late lifecycle commands. Raw per-record audit table is available with
``--raw``.
.. code-block:: bash
taskledger task transcript --task TASK_REF
taskledger task transcript --task TASK_REF --raw
taskledger task transcript --task TASK_REF --failures
``--review`` is the default (no flag needed). ``--raw`` shows every record
without collapsing. ``--failures`` renders only failed command rows and retry
detection. ``--raw``, ``--review``, and ``--failures`` are mutually exclusive.
``task export`` writes a Markdown file with a deterministic body combining a curated
archive report, raw task-bundle record files, and optional source-file snapshots.
It is the recommended command for handing a task to an LLM/coding agent.
.. code-block:: bash
taskledger task export TASK_REF -o task.llm.md
taskledger task export --task TASK_REF --no-source-files -o task.records.md
taskledger --json task export TASK_REF -o task.llm.md
``taskledger doctor`` and ``taskledger doctor locks`` report running runs without
matching active locks. Orphaned running planning runs can be finished only
through an explicit repair command with a reason:
.. code-block:: bash
taskledger repair run --task TASK_REF --run RUN_ID --reason "Planning was already completed."
The repair command refuses to finish non-planning runs, non-running runs, or
runs that still have a matching active lock.
Post-completion follow-up deltas
--------------------------------
``taskledger task follow-up PARENT_REF TITLE`` is the supported path for small
post-completion changes. It requires a ``done`` parent task, creates a new draft
child task with ``parent_task_id`` and ``parent_relation=follow_up``, and keeps
the parent task terminal.
Human monitoring UI
-------------------
``taskledger serve`` is a top-level human-oriented monitoring command:
.. code-block:: bash
taskledger serve [TASK_REF] [--host 127.0.0.1] [--port 8765] [--refresh-seconds 2] [--open/--no-open]
Rules:
* the MVP binds only to localhost;
* it serves read-only server-rendered HTML pages;
* browser actions are not part of the MVP;
* agents should continue to use ``next-action``, ``context``, ``view``, and
``--json`` commands as the canonical automation interface.
Focused context and handoff options
-----------------------------------
Code review commands
--------------------
``review`` stores optional durable code-review evidence without adding a new
lifecycle stage. Review evidence may be recorded before validation or after a
task has reached ``done``; storing the review remains append-only and does not
reopen the completed task:
.. code-block:: bash
taskledger review record [--task TASK_REF] --result pass|fail|blocked (--summary TEXT | --summary-file PATH) [--from-git] [--commit COMMIT] [--worker STEP_ID] [--handoff HANDOFF_ID] [--run RUN_ID]
taskledger review list [--task TASK_REF]
taskledger review show REVIEW_REF [--task TASK_REF]
JSON mode returns a stable payload with ``kind = "code_review_recorded"`` for
``review record`` and includes ``review_id``, ``task_id``, ``result``,
``source``, ``implementation_run``, ``worker_step_id``, and compact git
metadata fields when present.
Focused worker contexts keep lifecycle ``mode`` separate from worker-role
``--for``:
.. code-block:: bash
taskledger context --for planner|implementer|validator|spec-reviewer|code-reviewer|reviewer|full [--scope task|todo|run] [--todo TODO_ID] [--run RUN_ID] [--format markdown|json|text] [--task TASK_REF]
taskledger handoff create --mode planning|implementation|validation|review|full [--for planner|implementer|validator|spec-reviewer|code-reviewer|reviewer|full] [--scope task|todo|run] [--todo TODO_ID] [--run RUN_ID] [--task TASK_REF]
taskledger handoff create --worker STEP_ID [--scope task|todo|run] [--todo TODO_ID] [--run RUN_ID] [--task TASK_REF]
taskledger pipeline context STEP_ID [--scope task|todo|run] [--todo TODO_ID] [--run RUN_ID] [--format markdown|json|text] [--task TASK_REF]
taskledger handoff show HANDOFF_ID --format text|markdown|json [--task TASK_REF]
Rules:
* ``--todo`` implies ``--scope todo``.
* ``--run`` implies ``--scope run``.
* ``--scope todo`` requires ``--todo``.
* ``--scope run`` requires ``--run``.
* ``--for implementation|validation|planning|review|full`` remain accepted as
compatibility aliases.
* ``handoff create --worker`` derives mode and context from the configured
worker step and stores ``worker_step_id`` in the handoff record.
* ``pipeline context STEP_ID`` is equivalent to ``context --worker STEP_ID``.
* ``spec-reviewer`` and ``code-reviewer`` worker contexts require ``--run`` or
explicit ``--scope task`` when they are not bound to a validation/review run.
* ``handoff show --format markdown`` prints the stored snapshot body.
Removed Pre-Release Aliases
---------------------------
These aliases are intentionally not registered:
* ``task new``
* ``task clear-active``
* ``implement add-change``
* ``validate add-check``
* ``file link``
* ``file unlink``
* ``link link``
* ``link unlink``
Use ``task create``, ``task deactivate``, ``implement change``,
``validate check``, ``file add``, ``file remove``, ``link add``, and
``link remove`` instead.
Approval escape hatches
-----------------------
Plan approval escape hatches require ``--reason`` to prevent silent bypass:
+--------------------------+--------------------------------------------------+------------------------+
| Flag | Effect | Requires ``--reason`` |
+==========================+==================================================+========================+
| ``--allow-empty-criteria`` | Skip the acceptance criteria requirement | Yes |
+--------------------------+--------------------------------------------------+------------------------+
| ``--allow-open-questions`` | Approve despite open planning questions | Yes |
+--------------------------+--------------------------------------------------+------------------------+
| ``--allow-empty-todos`` | Approve despite no todos in the plan | Yes |
+--------------------------+--------------------------------------------------+------------------------+
| ``--no-materialize-todos`` | Skip materializing plan todos into the checklist | Yes |
+--------------------------+--------------------------------------------------+------------------------+
| ``--allow-agent-approval`` | Allow agent (non-user) approval | Yes (plus ``--reason``) |
+--------------------------+--------------------------------------------------+------------------------+
| ``--allow-lint-errors`` | Approve despite plan lint errors | Yes |
+--------------------------+--------------------------------------------------+------------------------+
Approval also requires ``--note`` for user approval. Agent approval additionally
requires ``--allow-agent-approval --reason "..."``.
Todo source inference
---------------------
When ``todo add`` is called without an explicit ``--source``, the source is
inferred from the active lock:
+-------------------+-----------------+
| Active lock stage | Inferred source |
+===================+=================+
| ``implementing`` | ``implementer`` |
+-------------------+-----------------+
| ``planning`` | ``planner`` |
+-------------------+-----------------+
| No active lock | ``user`` |
+-------------------+-----------------+
Plan-materialized todos always use ``source=plan``.
Storage Compatibility
---------------------
Taskledger stores project-local configuration in ``taskledger.toml`` at the
workspace root. ``.taskledger.toml`` is also read as a local override file when
it exists.
The resolved ``taskledger_dir`` defaults to ``.taskledger/`` beside that config
file, but ``taskledger init --taskledger-dir /path/to/state`` may point durable
state elsewhere. Commands resolve config files upward from the starting
directory and keep ``--root`` scoped to the source workspace, not the storage
root.
Taskledger uses:
* a workspace storage layout version in ``taskledger_dir/storage.yaml``
* per-record ``schema_version``
* per-record ``object_type``
* per-file ``file_version`` for durable Markdown/YAML/JSON record files
Storage layout version history:
* Layout 2: Introduced branch-scoped ledgers under ``taskledger_dir/ledgers//``
* Layout 3: Consolidates layout-2 root-level task state into branch-scoped ledgers; migrates legacy root ``tasks/``, ``events/``, ``intros/``, ``releases/``, and ``active-task.yaml`` into the active ledger namespace
Taskledger does not silently rewrite storage during read-only commands.
If the installed taskledger version can read but not write an older workspace,
it reports that migration is required.
To migrate:
.. code-block:: bash
taskledger migrate status
taskledger migrate plan
taskledger migrate apply --backup
After migration to layout 3, verify health with:
.. code-block:: bash
taskledger doctor
taskledger ledger doctor
Indexes under ``taskledger_dir/ledgers//indexes/`` are optional derived caches or
registries. Task, plan, and run commands must continue to work from canonical
Markdown/YAML records even when task/run/plan JSON cache files are absent. The
remaining derived caches may be plain JSON arrays with no version metadata and
can be rebuilt with:
.. code-block:: bash
taskledger reindex
A newer storage version than the installed taskledger supports is rejected with
a clear error.
Lock recovery contract
--------------------
Lock diagnostics are exposed through three surfaces:
- ``taskledger lock show --task TASK`` returns a ``diagnostics`` object and
a structured human block. The ``classification`` field names the lock
state: ``none``, ``expired``, ``active_dead_local_process``,
``active_live_local_process``, ``active_unverifiable_remote_or_unknown_process``,
``active_no_pid``, ``active_same_actor``, or ``active_other_actor``.
- ``taskledger --json next-action`` returns ``lock_status`` whenever a lock
exists, and sets ``action=repair-lock`` with a diagnostics blocker when the
active implementation lock has a dead local holder PID.
- ``taskledger implement resume --repair-expired-lock`` returns a
``LOCK_CONFLICT`` error (exit code 4) with diagnostics and remediation
commands when the existing lock is non-expired.
``--repair-expired-lock`` is not a general stale-lock takeover flag. It only
applies to locks whose ``expires_at`` is in the past. For non-expired active
locks, follow the classification returned by ``lock show`` or ``next-action``.
For non-expired active locks classified as ``active_dead_local_process``, the
canonical recovery sequence is:
.. code-block:: bash
taskledger repair lock --task TASK --reason "Holder PID ... is no longer running."
taskledger implement resume --task TASK --reason "Reacquire implementation lock after stale holder repair."
For ``active_live_local_process`` or ``active_other_actor``, do not repair;
use a handoff or wait for the holder to release. For
``active_unverifiable_remote_or_unknown_process``, do not infer staleness
from local process checks; inspect handoffs or ask the user before repairing.
]