CLI Command Contract

Taskledger uses a task-first command grammar:

taskledger [--root PATH] [--json] <area> <verb> [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 was removed in v0.7.0; use --root to select the workspace root.

Task Scoping

Task-scoped workflow commands default to the active task. Use --task TASK_REF when explicitly targeting another task.

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 implement snapshot refresh --task task-0001 --reason "Accept current workspace as the implementation snapshot."
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:

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
taskledger task show tl:task-0001
taskledger task show tl-task-0001

Reference parsing helpers are available:

taskledger ref show task-0001
taskledger ref parse TL-TASK-0001

Fresh-session and monitoring commands are top-level read surfaces:

taskledger usage [TASK_REF] [--task TASK_REF] [-q]
taskledger --json usage
taskledger monitor [TASK_REF] [--task TASK_REF] [--refresh-seconds 2] [--once] [--max-events 10] [--max-ready 10] [--plain] [--no-clear]

Optional positional task refs are not supported for workflow commands.

Plan guidance command

taskledger plan guidance is a read-only planning helper command that always prints built-in plan-input guidance. When a project prompt profile is configured it appends project-local advisory guidance:

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;

  • has_project_guidance indicates whether a project prompt profile exists, not whether any guidance is available. Built-in guidance is always returned.

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:

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 "..."
taskledger plan upsert [--task TASK_REF] [--file PATH] [--auto-revise]

Plan revision preparation should happen before submitting a revision, so export or check failures do not leave an active planning run:

taskledger plan export --version latest --file ./plan.revision.md
# edit ./plan.revision.md
taskledger plan check --file ./plan.revision.md
taskledger plan upsert --auto-revise --file ./plan.revision.md

When an edited ./plan.md already exists, check and submit it directly with plan upsert --auto-revise --file ./plan.md; do not export over it. Auto-revision proposes a version only. Explicit user approval is still required before implementation.

Plan proposal commands that accept --file reject file paths under .taskledger/ because that directory is private durable ledger state.

Plan check command

taskledger plan check validates editable plan input without creating, revising, proposing, accepting, locking, or releasing anything:

taskledger plan check [--task TASK_REF] [--file PATH] [--strict]

Rules:

  • --file defaults to plan.md when omitted;

  • --strict upgrades unknown-field warnings to errors and fails on any warning;

  • task context is optional; task_id appears in the payload when resolvable;

  • JSON uses the root --json option:

    taskledger --json plan check --file ./plan.md
    

Payload shape:

  • kind (plan_input_check)

  • task_id

  • passed

  • strict

  • summary ({errors, warnings})

  • issues

  • parsed

Plan schema command

taskledger plan schema prints the editable plan input schema and one valid example:

taskledger plan schema

Payload shape:

  • kind (plan_input_schema)

  • schema

Plan review command

taskledger plan review is a read-only approval-facing plan renderer:

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.

Taskledger stores task-local work state and opaque links. Cross-ledger semantics belong to an organizer such as ledgerdeck.

Relevant commands for external artifact references:

taskledger link add --url specs/behavior/features/checkout/payment.feature --label "behavior spec"
taskledger file link specs/behavior/features/checkout/payment.feature --kind doc --label "behavior spec"
taskledger validate check --criterion ac-0001 --status pass --evidence "pytest tests/test_checkout_payment.py::test_payment_flow"

Rules:

  • Links are opaque. Taskledger does not parse or interpret linked files.

  • Validation evidence is recorded through generic validate check.

  • validate command -- ... records managed validation command evidence during an active validation run.

  • A non-zero validation command does not create a ValidationCheck; explicitly classify and record criteria with validate check.

  • A passing implementation command may be adopted explicitly as validation evidence with validate check --from-implementation-check CHECK_ID only when Taskledger reports an exact final/current workspace snapshot match.

  • This is evidence reuse, not a generic command cache. Rerun validation when fresh execution or external runtime state matters.

Archive import lock policy

Archive imports support explicit lock handling:

taskledger import ./taskledger-transfer.tar.gz --replace [--lock-policy drop|quarantine|keep]
taskledger import ./taskledger-task-<project>-<ledger>-task-0040-<ts>.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.

{
  "project": {
    "uuid": "<project_uuid>",
    "name": "<project_name>",
    "slug": "<project_slug>",
    "ledger_ref": "<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:

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:

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:

taskledger release tag 0.4.1 --at-task task-0030 --note "0.4.1 released"
taskledger release list
taskledger release show 0.4.1

release tag writes a durable release record under the current ledger’s releases/ directory. Release boundaries must point to done tasks. Taskledger does not provide changelog entry, changelog context, or docs/changelog.md build commands; those belong to the separate releaseledger tool. Load both skills when cross-ledger release notes need task context.

Legacy branch-scoped ledger commands (migration only)

In legacy projects without a canonical manifest, branch-scoped ledgers isolate ignored local task state by the checked-in ledger_ref stored in taskledger.toml:

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/<ref>/ 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:

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 export --output ./taskledger-transfer.tar.gz
taskledger 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.

  • In legacy projects, 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.

  • export and import are root-level archive transfer commands; sync remains focused on storage and Git synchronization.

  • sync git commands operate on a private external Git repository that stores full project taskledger state under <repo>/<project_path>.

Config commands

Project config inspection and edits are available under config:

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:

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 implemented task whose validation is blocked by IMPLEMENTATION_SNAPSHOT_MISMATCH, next-action must point to validate-reconcile and the audited recovery command taskledger implement snapshot refresh --reason "...", not to implement restart unless the task is actually in failed_validation. 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. Successful todo done renews the active implementation lease only when the current execution proves ownership. Read-only commands and other sessions do not renew it.

  • implement finish: emits task_lifecycle result with task id, run id, status, and next command.

Human mode shows a one-line summary:

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

A missing canonical task record can leave the active-task pointer and runtime lock in place. Forced deactivation clears only the dangling pointer. It does not silently remove the lock:

taskledger task deactivate --force --reason "Clear dangling active task after record loss."
taskledger repair locks
taskledger repair locks --apply --reason "Preserve and remove the orphaned runtime lock."

repair locks is dry-run by default. It reports orphan_missing_task separately from expired and dead-process locks, copies the orphan lock to the recovery audit area, removes the runtime lock, and updates derived lock indexes. Inspect the dry-run before applying.

Doctor also reports nonempty task allocation directories that lack task.md. Allocation repair is dry-run by default, and applying requires an explicit --task-id or deliberate --all scope, the reviewed plan fingerprint, and a reason. Review physical source identity separately from any display alias:

taskledger repair allocations
taskledger repair allocations --task-id task-0019
taskledger repair allocations --task-id task-0019 --apply --plan-id PLAN_ID --reason "Quarantine the reviewed physical source."
taskledger repair allocations --audit

The dry-run result includes top-level apply_safe, plan_id, and next_command, plus incomplete_allocations entries containing physical_source, source_kind, legacy_source_id, source_fingerprint, repair_mode, per-entry apply_safe, collision_findings, surviving_identity, planned_quarantine, and nullable planned_tombstone. Modes are quarantine_and_tombstone for an eligible orphan, quarantine_shadowed_legacy_source for one stale legacy source with exactly one live UUID owner, and blocked_identity_conflict for ambiguity. A shadowed-source repair preserves the existing live owner and must not create a second tombstone. When any selected entry is blocked, top-level apply_safe is false and next_command is null; resolve the ownership ambiguity instead of applying the plan.

Prior repairs with a misattributed tombstone can be reconciled only when event and quarantine provenance support the physical source. The dry-run is also the required review step:

taskledger repair allocations --reconcile-source-id task-0019 --tombstone-id task-0037
taskledger repair allocations --reconcile-source-id task-0019 --tombstone-id task-0037 --apply --plan-id PLAN_ID --reason "Correct the tombstone to the physical source ID."

Reconciliation preserves the old tombstone and quarantine payload and records an audit event. Do not delete either by hand. Use taskledger repair allocations --audit to inspect prior repair provenance.

repair relation backfills a known relationship UUID for one UUID task bundle or requirement sidecar. It is dry-run by default; apply only the exact reviewed plan:

taskledger repair relation --task-uuid TASK_UUID --field parent_task_uuid
taskledger repair relation --task-uuid TASK_UUID --field parent_task_uuid --apply --plan-id PLAN_ID --reason "Backfill the reviewed parent UUID."

Maintenance garbage collection

taskledger maintenance gc is an explicit maintenance operation and is dry-run by default:

taskledger maintenance gc
taskledger maintenance gc --scope artifacts --task task-0042 --older-than 30d
taskledger maintenance gc --apply --scope runtime --older-than 14d --reason "Prune retained terminal snapshots."

Scopes are all, runtime, artifacts, and cache. Default retention is 14 days for terminal workspace snapshots, 30 days for unreferenced artifacts, and 7 days for quarantined cache generations. --older-than overrides the selected scopes. --task limits runtime/artifact cleanup to one canonical task ID and cannot be used with cache cleanup.

Artifact cleanup marks references from canonical task, run, todo, check, review, handoff, event, and agent-log records. Only old unreferenced artifacts owned by terminal, unlocked work are eligible. Runtime cleanup targets detailed manifests for terminal runs whose canonical summary hashes remain. Cache cleanup removes only old quarantined index generations, never the active indexes. Evidence/runtime deletion requires both --apply and --reason; every apply writes a durable report and attempts a project-level audit event. Canonical task history is never a GC target, and task completion does not run GC.

Managed command wrappers

plan command and implement command mirror the inner command exit code by default. Both wrappers pass the argument vector after -- to the child without a shell. They execute the child from the CLI invocation directory, or the explicit --root directory, even when Taskledger discovers an ancestor workspace root for ledger state, artifacts, and logs.

Managed command artifacts are bounded by the project artifact_max_bytes setting, defaulting to the 20,000,000-byte hard ceiling. Oversized persisted evidence is marked and retains both its beginning and end; only the durable artifact is truncated, not the child command’s exit code or CLI stdout/stderr contract. validate command uses the same managed execution behavior during an active validation run, but records command evidence only. It never automatically maps a non-zero child exit to a criterion result.

Managed commands preserve the caller environment, but resolve child executable lookup deterministically. A usable inherited VIRTUAL_ENV takes precedence. Otherwise Taskledger checks <command-cwd>/.venv, <command-cwd>/venv, then the workspace root’s .venv and venv, in that order. A candidate must contain pyvenv.cfg and a platform-appropriate Python executable. For an auto-detected environment, only the child environment is changed: its scripts directory is prepended to PATH, VIRTUAL_ENV is set, and inherited PYTHONHOME is removed. If no candidate is valid, the inherited environment is used unchanged. PYTHONPATH is preserved. This does not rewrite argv, invoke a shell, change the parent environment, or activate project environments for Taskledger’s internal subprocesses. Portable commands such as python -m pytest, pytest, ruff, and mypy remain valid.

Captured stdout and stderr are included in the command result. Human mode emits those streams before the recorded-command summary, while JSON mode keeps them only inside the single JSON result envelope. The result and managed-shell log also record the child cwd. --allow-failure changes only the wrapper exit code; the recorded child exit code and failed check remain unchanged.

Use --allow-failure when you intentionally want to record a non-zero inner exit code while returning wrapper exit code 0:

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)"
taskledger validate command -- pytest tests/ -q
taskledger validate 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.

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.

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:

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 usage is the compact fresh-session startup command:

taskledger usage [TASK_REF] [--task TASK_REF] [-q]
taskledger --json usage

Rules:

  • it is read-only and must not claim handoffs, repair locks, or mutate task state;

  • root --json returns the standard CLI envelope with result.kind == "usage";

  • it summarizes actor, harness, active work, inbox items, and ready tasks;

  • agents should continue to use next-action, todo next, and other JSON commands as the canonical same-session automation interface.

taskledger monitor is the dependency-free human-oriented terminal monitor:

taskledger monitor [TASK_REF] [--task TASK_REF] [--refresh-seconds 2] [--once] [--max-events 10] [--max-ready 10] [--plain] [--no-clear]

Rules:

  • it is read-only and never mutates .taskledger/ state;

  • root --json prints a single monitor_snapshot payload and exits;

  • non-JSON mode refreshes on a timer until interrupted;

  • --plain disables styling and --no-clear appends snapshots instead of clearing the terminal;

  • it replaces the removed server/TUI surface; agents should keep using JSON commands for automation.

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:

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.

When a user explicitly asks an agent for a review, the agent should persist the final review with taskledger review record before answering. A chat-only review is not durable task evidence. Post-completion review records are append-only and do not reopen the task.

Focused worker contexts keep lifecycle mode separate from worker-role --for:

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 accepts the role names shown above; spec and code normalize to spec-reviewer and code-reviewer.

  • 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 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:

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 canonical project configuration in schema-3 .ledger/ledger.toml and Taskledger config in .ledger/taskledger/config.toml. Legacy taskledger.toml and .taskledger.toml remain readable for explicit migration.

The default data mount is persistent external storage at ../ledger; indexes is cache storage. A local .ledger/ledger.local.toml may select user-data. Commands keep --root scoped to the source workspace, not the storage root.

Taskledger uses:

  • storage layout version 6 in the UUID-scoped data root’s storage.yaml

  • schema-2 canonical ledger state

  • per-record schema_version

  • per-record object_type

  • per-file file_version for durable Markdown/YAML/JSON record files

Storage layout history is maintained by migration receipts. The current layout keeps branch-scoped ledgers under <data-root>/ledgers/<ledger_ref>/.

Within each ledger, canonical task bundles live at tasks/<uuidv7>/task.md. UUIDv7 is the stable storage identity and relationship key; task-#### remains the derived user-facing alias and is never a directory name. Layout 5 to 6 migration deterministically converts legacy numeric task bundles before the first mutation, preserves ordinal gaps and reserved identities, and is recoverable. Read-only commands do not migrate.

Other legacy storage-root or topology migrations remain explicit:

taskledger storage validate
taskledger migrate plan
taskledger migrate apply

After migration to layout 6, verify health with:

taskledger doctor
taskledger ledger doctor

Checkout-scoped indexes under the resolved cache mount are optional derived caches or registries. Read-only commands continue to work from canonical Markdown/YAML records and do not initialize a missing cache. Before a canonical mutation, Taskledger initializes a missing or empty cache binding and rebuilds the derived indexes. A non-empty cache without its binding marker is atomically quarantined beside the cache and rebuilt from canonical records. Conflicting or invalid markers, symlinks, and non-directory cache paths are not adopted automatically. The remaining derived caches may be plain JSON arrays with no version metadata and can be rebuilt explicitly with:

taskledger repair index

taskledger repair index uses the same recovery path and reports any quarantine location. The indexes mount is fixed to cache storage, so taskledger storage set indexes cache is an idempotent topology request; non-cache indexes storage is rejected directly.

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_current_execution, active_harness_session, active_same_actor, or active_other_actor. active_current_execution requires matching strong execution evidence, such as a shared harness session ID or a stable same-host owner PID; actor-name equality alone is not ownership proof.

  • 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 when a non-expired lock belongs to another or unknown execution. If the selected run is already active and classification is active_current_execution, resume succeeds as a no-op with changed=false, preserving the existing lock and run IDs without a repair or release event. For ordinary continuation, inspect next-action and continue the todo loop; do not use implement resume or lock repair while this execution owns the lock. --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:

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.

Layout and migration commands

taskledger config path reports the project-located Taskledger configuration. taskledger storage path data|runtime|logs|indexes reports named resolved mounts. Use storage validate, storage set, and storage clear-override for schema-3 storage selection. storage set changes topology only; use the explicit migration commands for data relocation. Legacy layout conversion remains explicit through migrate status, migrate plan, and migrate apply.

Migration inspection and apply share these options:

--sibling-ledger-root PATH
--source-data-root PATH
--source-checkout-id ID
--project-uuid UUID

The canonical project UUID is selected when a legacy Taskledger UUID differs. The legacy UUID is retained as source metadata. --source-data-root is the recovery override for a specific data root. --source-checkout-id accepts an identifier, not a filesystem path. Backups are automatic. Other ledger registrations are preserved, sources are not retired by default, and authoritative split-brain targets are refused without mutation. --create-sibling-store only initializes the sibling root marker; it does not repair target metadata.