All notable user-visible changes to Taskrail will be documented in this file.
- The inherited task mutation writers now publish through one locked normal
transaction each:
task new,task rename,task repoint, andtask dependency add|removeacquire the repository mutation lock, snapshot their complete consumed and collision set, validate the full candidate ledger before the first write, and publish only their declared task and state files. A concurrent edit to any file they read or write refuses withwrite_conflictinstead of being overwritten, a handled publication failure rolls every published byte back, unrelated task files are never re-encoded, and a delegated loop child invoking any of these commands is refused. task renamepublishes its coupled move by filesystem operations rather thangit mv: nothing is staged through the Git index, the old file's removal and the renamed file's creation publish (and roll back) as one unit alongside each rewritten inbound dependency reference and the re-projectedSTATE.md. Renaming also preserves every other byte of the written task files — including frontmatter fields no Taskrail struct models — instead of re-encoding them, and healing a filename/id drift onto the task's own current filename publishes one replacement rather than a remove-plus-create of the same path. Rename and repoint--dry-runremain read-only previews and no longer require a free mutation lock.taskrail initon a layout 1 repository now reports a complete, read-only layout 2 upgrade preview (migration_preview,from_version1,to_version2): the validated candidate paths (marker, schema-2 state, byte-preserved task files, notes sidecar), committed storage mode, the default broad review-round maximum, every decoded continuation note in order with its applicableextract/dropchoices, each installed skill's classification, and the candidate's validation outcome — without changing repository bytes.init --applyfor the upgrade validates every operator gate first —--confirm-quiescent, the continuation-note selection the source makes applicable (unnecessary or already-schema-2 selections are refused), and the combined--with-skills --forcewhenever stamped skill copies require normalization — before publishing through the durable migration fence described below. LegacyAUTONOMY.tsventries at the configured planning path refuse the upgrade asunsupportedwithtask loopguidance, and the flagless preview keepsinit --with-skillson a layout 1 repository served by the current layout so skill installation is unchanged.- A fully gated
taskrail init --applynow publishes the exact previewed layout 2 candidate through one durable, recoverable transaction: the marker is fenced as layout 2 (with amigration_fencenaming the transaction id) after the originals are recorded and before any task, state, note, or skill byte changes, the complete candidate publishes and post-validates, and the strict final marker replaces the fence as the transaction's last operation. The appliedInitResultreports the same candidate paths and decisions the preview reported, records the chosen continuation-note disposition, and directs downgrade through complete Git reversion of the upgrade. Handled failures roll every candidate-written byte back before restoring the original marker; an interruption leaves the fence and the retained transaction, every other command refuses (recovery_pendingwhile the transaction is retained,migration_in_progressnamingtaskrail recoverotherwise), andtaskrail recoverderives the single safe restore, accept, or clear action — completing an interrupted migration's final marker from retained transaction evidence. taskrail recover <transaction-id> [--apply] [--json]is the one command the recovery admission fence admits: it previews the single mechanically safe action a retained durable transaction derives (restore_original,accept_candidate, orclear_fence) from journal evidence plus the complete current snapshot set, and--applyperforms exactly that action. It acquires the mutation lock naming the transaction (any holder refuseslock_held), refuses unexpected or substituted bytes withwrite_conflictwhile preserving every byte and the typed snapshot evidence, and requires the owning command's registered validator before accepting a candidate. It publishes the v0.5 envelope asRecoverResult.taskrail lock statusinspects the repository mutation lock read-only (absence, or exact owner metadata and raw-file digest) in Git and non-Git repositories, andtaskrail lock clear <lock-id> --expect-sha256 <digest>removes exactly the observed stale lock — refusing a changed lock, a provably live same-host owner, and ever touching retained transaction data. Neither command exposes a delegation token; both publish the v0.5 envelope.taskrail task dependency add|remove <task-id> <dependency-id>edits one exact-ID edge transactionally;--dry-runpreviews the validated candidate.taskrail initandretrofit --applycreateplanning/NOTES.mdfor human-owned context when absent; an existing file is untouched, and an unsafe path (symlink, directory, case alias) refuses withpath_blocked.
verify, including--create-followup, now publishes through the repository mutation lock as one normal transaction: it snapshots its selected task, state, task ledger, and artifact destination, validates the complete candidate ledger before the first write, and publishes exactly its verification artifacts, selected task, fresh follow-up tasks, and re-projectedSTATE.md— no longer re-encoding every task file or leaving half-written artifacts behind a mid-sequence failure. Selected-task frontmatter fields Taskrail does not model survive verification byte for byte. A concurrent holder of the mutation lock refuses withlock_held, an external edit landing mid-transaction refuses withwrite_conflictwhile preserving the edited bytes, and a handled publication failure rolls the whole write — including transaction-created follow-up and artifact files — back withpartial_writeevidence. Transaction publication and rollback failures now name reported repository-relative paths (never the caller's absolute repository location), restoring the portable-error contract for every writer that publishes through the transaction substrate, and verify's byte reach on the selected task is exactly its declared fields: the note, the timestamp, and nothing else. A delegated verification joins its parent's narrowed grant: it may create follow-ups only for its selected task and refusesdelegated_write_refusedwhen the granted write set does not cover exactly what it would publish.next,start,complete,block, andunblocknow publish through the repository mutation lock as one normal transaction: they snapshot their complete consumed and published set, validate the full candidate ledger before the first write, and replace only their declared task and state files instead of re-encoding every task file. A concurrent holder of the mutation lock refuses withlock_held, an external edit landing mid-transaction refuses withwrite_conflictwhile preserving the edited bytes, and a handled publication failure rolls the write back to the original bytes withpartial_writeevidence. Candidate validation refuses a transition that would introduce a validation violation the repository did not already carry, while pre-existing violations are preserved and reported in the result as before. Delegated loop children join their parent's lock narrowed to the selected task and the exact write set:start,complete,block, andunblockwithin that bound publish normally, whilenext, another task, a wider field set, or an unauthenticated join refuses withdelegated_write_refusedwithout writing.- Layout-2 migration now defaults implementation review to one broad round. The
1..2policy range and three-reviewer ceiling remain available, while the canonical workflow uses one focused reviewer by default and permits objective evidence to close repairs from its non-recursive final-diff review. - Repository discovery now preserves distinct managed, worktree, Git-common, storage, and lock identities and strictly maps layout-2 committed/local paths.
- Read-only validation, spec/task loading, reports, review evidence, artifact guards, and rename previews now preserve logical paths in either storage mode.
- All semantic commands now refuse
recovery_pendingwithout a partial result or write while canonical retained or malformed transaction state exists. taskrail validateaccepts paired task-localloop_policy/loop_reasonmetadata, treats an absent pair as implicit hold, rejects malformed pairs and legacyplanning/AUTONOMY.tsv, and preserves explicit policy across task writes.- Every
--jsoncommand now emits the v0.5 machine envelope —schema_version,command,warnings, and one ofresult/error— instead of the bare report or writer payload, and a failure emits a registered error code instead of prose-only stderr. This one-time direct-result break has no legacy switch;schema_versionversions the whole document contract. taskrail start,complete, andblockgain--json, reporting the transition and the validation re-run alongside it. Text output is unchanged.taskrail init --jsonnow reports the layout marker, the write inventory, theplanning/NOTES.mddisposition with its continuation-note choices, and — with--with-skills— every installed skill path, replacing the prosechangeslist.--with-skillsinstalls are no longer text-only.taskrail status --jsonnow reportsstoragewith the active mode, root, and physicalartifacts_dirfor transient staging.- Warnings are published only in the envelope's
warningsarray; commands no longer repeat them inside their result payloads. Text output still shows them on stderr, and they never change the exit status. taskrail import --applynow reports a partial apply as apartial_writeerror naming the paths it wrote, replacing the"partial": trueresult.- Task operands now require the exact full persisted ID, and
taskrail validaterejects broken v0.5 completion and verification metadata chains. taskrail init --with-skillsnow installs Agent Skills-compliant copies withmetadata.taskrail_version;--forcesafely normalizes legacy markers.taskrail initandretrofit --applyno longer seed generic continuation prose in freshSTATE.mdfiles; packaged workflow guidance keeps durable task context in task notes, blockers, verification reports, or follow-up tasks.
Fourth release. Taskrail makes active-spec work safer to author and select, adds atomic task rename/repoint operations and mechanical spec/gap review, and makes binary, layout, and installed-skill version skew visible before it can damage tracked state. The core remains deterministic and provider-independent.
taskrail spec diff <from> <to>— read-only, mechanical anchor-set delta between specs: definitive added/removed areas plus supplemental best-effort rename candidates. Never writes tracked state or gates validation; supports--json.taskrail task rename <id>— atomically re-slug a task's id and filename, body heading, inbound dependencies, and current-task pointer.--slugis normalized but uncapped;--titlederives a capped slug. Supports--dry-runand--json.taskrail task repoint <id>— move an open task'sspec_refwith--areaor--spec-ref, then re-projectSTATE.md. Supports--dry-runand--json.taskrail task new --area <anchor>— resolve a task'sspec_refagainst the active spec without copying its path; mutually exclusive with--spec-ref.taskrail next --include-off-spec— one-shot recovery that ranks runnable work across all specs and clearly flags an off-spec selection in text and JSON.taskrail status— active-spec drift breakdown: counts open work on and away from the active spec, then lists away-task ids andspec_refvalues. Read-only; supports--json.taskrail coverage --gaps— advisory read-only structural gap analysis over covered active-spec areas. Scope with--area; opt into an exit-code policy with--fail-on; consume structured candidates with--json.taskrail-decomposeandtaskrail-gapskills — draft tasks for uncovered spec areas and add semantic review to mechanical gap signals; proposals remain reviewable and require explicit promotion into tracked state.taskrail init --with-skills— stamp installed skills with the writing Taskrail version. Commands warn about stale copies and nameinit --with-skills --forceas the explicit remedy without blocking transitions or corrupting JSON output.
- Packaged state-writing skills now run the source checkout's
task taskrail:checkbefore tracked bytes change, refusing stale or wrongly resolved working-tree binaries without affecting installed adopter workflows. taskrail next— anchor idle selection to the active spec: onlytodotasks on that spec are ranked by default. Older runnable work is reported as skipped; an off-spec active task remains selected with a warning.taskrail task new— derive a slugged id and filename from--title(T-<n>-<slug>). Accented Latin text is folded to readable ASCII, title-derived slugs are capped, explicit--slugvalues are normalized but uncapped, and an empty normalized slug falls back to a warned bare id.taskrail import --applyandtaskrail verify --create-followup— derive capped, title-based task ids and filenames; empty slugs keep the warned bare-id fallback.
- Repository discovery now accepts macOS's system
/varalias and validates Windows 8.3 path ancestors; durable file modes use native Windows semantics. - Spec anchor parsing now ignores ATX-looking lines inside backtick and tilde fences across validation, inspection, coverage, gap analysis, and spec diff.
- Release builds now consistently report a
v-prefixed version, and publishing portably refuses missing or whitespace-only versioned changelog sections. - Every command now refuses a repository recording a
layout_versionnewer than the binary supports before reading or writing state, not only duringinit. taskrail task newandtask renamenow honor explicitly empty--slugselectors; title-derived slug caps preserve whole tokens and fall back to a bare id.taskrail task renamenow refuses an invalid post-rename preview before writing the task, inbound dependencies, orSTATE.md.- State-writing notes, reasons, task titles, follow-ups, and imported drafts now
reject concrete gitignored
planning/artifacts/paths before writing committed content that a latervalidatewould reject. taskrail import --applynow reports every file written or possibly touched by a failed apply, including failed spec writes and created tasks; JSON marks the result"partial": truewhile the command exits non-zero.taskrail verifyandtaskrail blocknow reuse## Implementation Notesin CRLF-authored tasks; the task-body guard ignores scaffold headings inside fenced examples and checks every scaffold section for duplicates.taskrail task new,task repoint, andimport --applynow write a canonicalspec_refpath and reject no-op repoints between equivalent spellings.- Layout-marker and skill-backup errors now name repository-relative paths once, avoiding machine-specific absolute paths and duplicated error text.
- Installed-skill skew warnings now ignore adopter-owned skills outside Taskrail's embedded package, including nested skills under supported install targets.
Third release. Taskrail gains read-only insight into tracked work — status,
stats, and coverage report progress, aggregate metrics, and spec-linkage
without touching state — plus a spec command family for inspecting and
authoring specs, unblock to release blocked tasks, and Windows install via
WinGet. The core CLI stays provider- and tooling-independent.
taskrail spec— spec command family.spec activate <version>repoints the active spec inSTATE.mdand re-validates (the CLI-only writer of the active spec);spec listandspec show <version>(with--anchorsforspec_refvalues) inspect specs read-only;spec add <version>scaffolds a new spec. Completion completes spec versions and<path>#<anchor>values. Supports--json.taskrail coverage— advisory read-only spec-linkage analysis: per-area decomposition and implementation coverage, a reverse map of the covering task id(s), orphan tasks, and a drift summary.--min <pct>opts into CI gating;--area <anchor>narrows to one area. Never writes state or failsvalidate. Supports--json.taskrail status— read-only snapshot: active spec, task counts, the next eligible task (marked not persisted), blockers, last verification, and a coverage/drift summary. Leaves the working tree clean. Supports--json.taskrail stats— read-only aggregate metrics: status distribution, blocked ratio, spec coverage, and dependency shape.--format dot|mermaidexports the task dependency DAG instead. Leaves the working tree clean. Supports--json.taskrail unblock <task-id>— return a blocked task to todo so it re-entersnextselection and drop itsSTATE.mdblocker entry (others keep theirs);--reasonappends a note. Supports--json.- Windows install via WinGet:
winget install Tessariq.Taskrail(amd64/arm64), with Windows.zipassets on the GitHub Release. Availability follows a moderated PR tomicrosoft/winget-pkgs.
taskrail init --with-skillsnow also installs theautonomous-recovery,autonomous-manual-test, andtaskrail-specskills;--forcereinstalls the embedded skills over existing copies, backing up any locally-modified file first. Still opt-in and non-destructive by default.- Shipped agent skills now invoke the CLI through
${TASKRAIL:-taskrail}; setTASKRAIL=/path/to/taskrailto override (it resolves to the installed binary otherwise). taskrail repairalso reconciles astatus_summaryleft stale against a singlein_progresstask; stillSTATE.md-only and dry run by default.- CLI file-read errors now name a repo-relative path instead of the absolute repository location.
taskrail task newnow allocates the next id from the highest numeric prefix across bare and slug-suffixed ids, so all-slug-suffixed repos no longer restart atT-001and collide;validatenow flags two files sharing a numeric prefix.taskrail blocknow keeps every blocked task's reason inSTATE.mdinstead of overwriting the list with only the most recent.taskrail completenow leavesstatus_summaryasblockedwhen other tasks remain blocked, instead of resetting toidle.
Second release. Taskrail builds on the stable v0.1.0 repo contract to make adoption
in existing repositories easy: guided retrofit, LLM-free import of rough notes into
spec/task drafts, opt-in shippable agent skills, a version-aware non-destructive
init, and conservative mechanical STATE.md repair — all while keeping the core
CLI provider- and tooling-independent.
taskrail repair— reconcile mechanicalSTATE.mddrift (stalecurrent_taskpointer or task counts) against the task files. Dry run by default;--applyrewritesSTATE.mdonly (never a task file) and re-validates. Judgement calls (missingspec_ref, dependency cycles, multiple in_progress) are left tovalidate. Supports--json.taskrail task new— scaffold a task file with the next free id. Requires--titleand--spec-ref; supports--priority, repeatable--dep,--json. Runsvalidate's checks at creation so an invalid task never lands.taskrail task new --follow-up <parent-id>— scaffold a follow-up: inherits the parent'sspec_refand adds it as a dependency.taskrail import— build spec/task drafts from a markdown source without an LLM.--to tasks|spec|planningpreviews a draft;--emit-promptprints a paste-ready agent prompt;--apply <draft.json>validates and writes real files. Supports--json. (--llmdeferred to v0.3.)taskrail retrofit [notes]— guided bootstrap for a non-standard repo: detect layout, scaffold, and adopt reviewed notes as tracked work. Dry run by default;--applyscaffolds without overwriting. Supports--json.taskrail init --with-skills— install the shippable tracked-work agent skills (autonomous-backlog,autonomous-task,autonomous-verify,taskrail-repair,taskrail-import,taskrail-retrofit). Opt-in; re-running never overwrites edits.taskrail initis now version-aware and non-destructive: writes a.taskrail/config.ymllayout marker, adopts an existing v0.1.0 layout, and migrates older layouts (dry run,--applyto write). Never rewrites human content.taskrail validatenow detects dependency cycles and committed references to gitignoredplanning/artifacts/paths.- Homebrew install:
brew install tessariq/tap/taskrail(macOS and Linux).
taskrail import --applyis now atomic — pre-flights all checks before writing, so a failing draft leaves the repo unchanged.taskrail verifyrecords a portable, path-free result in committedSTATE.md; gitignored artifact paths no longer leak intorelevant_artifacts.taskrail initno longer pre-creates gitignored artifact directories;verifycreates them on demand.
taskrail validateno longer fails on a fresh clone when the gitignoredplanning/artifactstree is absent.
First shippable release. Taskrail is a manual-first, LLM-provider-agnostic CLI for
repo-native tracked work, proving the repository contract, deterministic task
progression, the authoritative STATE.md, and verification as a first-class concept.
taskrail init— initialize Taskrail structure (specs/,planning/, starterSTATE.md) in the current repository.taskrail validate— validate folder layout, task shape, dependency and spec references, andSTATE.mdconsistency.taskrail next— deterministically select the next eligible task (supports--json).taskrail start <task-id>— mark a task active and updateSTATE.md.taskrail complete <task-id>— mark a task completed from an implementation perspective (supports--note).taskrail block <task-id>— mark a task blocked and record a--reason.taskrail verify <task-id>— record a verification outcome and write artifacts underplanning/artifacts/verify/; can create a follow-up task via--create-followup.taskrail version— print the CLI version (also--version), injected at build time via-ldflags.- Bootstrap repository structure, specs, planning workflow, and mirrored skills.