Repository navigation
Releases: dimitritholen/tasqx
Release list
tasqx v0.14.0
Token spend is now measured, not guessed. A task done in Claude Code gets its
token counts from the transcript that did the work, and tasqx tokens recompute
backfills that measurement for tasks completed before this release (D188).
Changed
- Token spend comes from the Claude Code transcript. tasqx finds the session
that did a task by the task's own start or completion call in the transcript
(thetasqx_start_timer/tasqx_complete_taskMCP call, or a Bash
tasqx start/tasqx done, within ten minutes of the task's window), counts
that session's subagent logs once, and records the result at confidencehigh.
It supersedes a self-reported count for the same task; self-report remains the
fallback when no transcript is found. Tasks running in parallel in one session
contest the samples their windows share, and a contested sample is counted for
neither (D50, D188). - The HTML report names its windows. The token section reads "Token spend ·
all time", and throughput bars are labelled by their Monday–Sunday span
("21–27 Sep", "28 Sep – 4 Oct"), with the current week's tooltip marked
partial (#818). tasqx_complete_tasksays the transcript wins. Its description now tells
agents that a transcript measurement takes precedence and self-report is the
fallback.
Added
tasqx tokens recomputebackfills measurements. For every done Claude Code
task with no measured (log-parse or OTLP) row, recompute locates its transcript
and appends ahighmeasurement beside any self-report (locate); a task it
cannot measure — no transcript found, or every sample contested — is reported
asskipped. Dry-run by default,--applywrites, and a second run changes
nothing (#817, #819).- tasqx-core:
compute_attribution_located,pending_attributions_locatedand
LocatedNeighbourcarry the tasks located to the same session file, so their
overlapping windows contest each other (#816).
Fixed
- A replayed transcript message counts once. Samples dedupe on message id
plus request id, with a timestamp fallback for subagent replays (#816). - Recompute keeps a located measurement.
tokens recompute --applyno longer
downgrades a transcript-locatedhighrow, or deletes it beside a self-report
(#817). tasqx tokens --helpdescribes recompute's real scope (#820).
Deprecated
- tasqx-core:
attribution::compute_attributionandpending_attributions
are thin wrappers over the_locatedvariants and will be removed in the next
minor release.
What's Changed
- fix(report): the token section named no window and week bars named only a Monday (#818) by @dimitritholen in #148
- feat(tokens): a transcript located by the task's own call beats a self-report (#816, D188) by @dimitritholen in #149
- feat(tokens): tokens recompute backfills located transcripts for self-reported tasks (#817, D188) by @dimitritholen in #151
- docs(cli): tokens recompute help describes the D188 locate pass (#820) by @dimitritholen in #153
- fix(tokens): recompute locates for every done Claude Code task with no log-parse row (#819) by @dimitritholen in #152
- bump(release): tasqx 0.14.0 (#821) by @dimitritholen in #154
Full Changelog: v0.13.0...v0.14.0
tasqx v0.13.0
This release is about moving a store between machines and keeping memory
honest about what it read. store.import can now merge two live stores
instead of only restoring one, and preview that merge first. An imported doc
remembers the file it came from, so a search or brief says when that file has
moved on. The MCP server hands an agent the rulings that apply without an extra
call, and the desktop preview gains a Memory Explorer and a knowledge graph.
No existing answer changes, except that four unused public items leave
tasqx-core (see Changed).
Added
store.importmerges.merge: trueunions a task the store already
holds instead of replacing it: notes, checks, tags and edges are combined,
and scalar fields take the newermodified(D185).dry_run: truepreviews
an import without keeping it (D184).- Memory knows where a doc came from. An imported doc records its origin
file.tasqx memory import --refreshre-reads every doc whose file changed
and reports the ones that vanished, a search or brief hit saysstalewhen
its file moved on since the import, and MCPinitializerefreshes imported
docs from disk so a session opens on the working tree (D180, D182). tasqx_start_timeranswers the task's memory. Starting a task over MCP
returns the memory hitstasqx_brief_taskwould (three by default;
include_memory: falseskips them), andtasqx_list_taskswith@working
andtasqx_add_taskcarry up to three ruling titles for the project (D186).- Links travel in the archive.
store.exportandstore.importcarry the
links table, and an import resolves link ends (D180, D181). - ripwire hint.
tasqx setup, MCPinitializeand both installers say
whether ripwire is on PATH and name its repository; tasqx never fetches it
(D178). - Desktop preview. A dashboard, task table and inspector, and projects
screen (#691); a Memory Explorer to search, browse, open, add and remove
memory docs and task notes (#692); and a knowledge graph of a task and
memory neighbourhood with filters, pins, saved views and inferred-edge
promotion (#693).
Changed
memory import'ssourceis relative to the git top level, sodocs/,
./docs/and an absolute path name one doc (D178, D179).tasqx-corepublic API:attribution::totals_in_window,
attribution::totals_in_window_excluding,types::Projectandtypes::Tag
are removed; nothing used them. Nothing else in the API changed.- Internal only: the CLI renderer is split into modules and duplicated core
helpers are collapsed, checked against a 122-screen behaviour baseline CI now
compares on every PR (D187). CI also fails a PR on an unused dependency or a
semver break intasqx-core.
Fixed
- Import: the duplicate-source scan was quadratic and a dry run minted a
differentdropped_idthan the real run (D183); a doc two machines minted was
refused as a conflict nobody could resolve (D182); a short_id another task
holds, a payload id reaching another row, an unvalidated stamp, an annotation
after its tombstone and a self-link all slipped through (D177, D181, D185). - Memory: a literal backslash and a symlink alias collapsed onto the wrong
source, a symlink alias refused the whole batch, and a dead superseded scan
failed a committed import (D179).
What's Changed
- chore(agent): the one-review rule was prose an agent could skip, and the force-push denials missed a flag order by @dimitritholen in #103
- feat(desktop): read-only dashboard and task workspace (#691) by @dimitritholen in #104
- docs(positioning): the organiser for your AI, on every public surface (D175) by @dimitritholen in #105
- test(concurrency): racing starts prove no interval closed from the stored column, not from a clocked read (D166) by @dimitritholen in #107
- docs(readme): open on an SVG map of what the organiser holds, not the VHS recording (D176) by @dimitritholen in #106
- docs(readme): quick start above the map's walk-through, and the shell section shows commands, not captures by @dimitritholen in #108
- refactor(memory): the markdown doc reader lives in tasqx-core so the engine can re-read a file by @dimitritholen in #109
- fix(import): the short_id another task here holds, and the remedy that did not exist (D177) by @dimitritholen in #110
- feat(setup): initialize and setup say whether ripwire is on PATH, and never fetch it (D178) by @dimitritholen in #111
- fix(import): the payload's own uniqueness, decided before the first row and not from the row order (D177) by @dimitritholen in #113
- fix(memory): import's source is relative to the git toplevel, so docs/, ./docs/ and an absolute path are one doc (D179) by @dimitritholen in #114
- feat(setup): the ripwire hint names the upstream repository, in setup and both installers (D178) by @dimitritholen in #115
- fix(memory): a symlink alias refused the batch, and a dead superseded scan failed a committed import (D179) by @dimitritholen in #116
- feat(memory): an imported doc remembers its origin file — path, mtime, size — so freshness can be checked later (D180) by @dimitritholen in #118
- feat(memory): import --refresh re-reads every doc whose file changed, and reports the ones that vanished (D180) by @dimitritholen in #119
- feat(api): the links table the archive never carried, and the ends an import resolves (D181) by @dimitritholen in #120
- feat(mcp): initialize refreshes imported docs from disk, so a session opens on the working tree (D180) by @dimitritholen in #121
- feat(memory): a search or brief hit says stale when its file moved on since the import (D180) by @dimitritholen in #122
- fix(import): the annotation node_exists still called a node after its tombstone (D181) by @dimitritholen in #123
- docs(design): memory freshness is checked against the file on demand, never watched, and code is mapped live, never indexed (D182) by @dimitritholen in #124
- fix(import): the doc two machines minted twice, refused as a conflict nobody could resolve (D183) by @dimitritholen in #125
- feat(api): store.import takes dry_run, previewing a merge before it is kept (D184) by @dimitritholen in #127
- fix(import): a duplicate source, a live payload id and a staged link payload all slipped past the D183 merge (task #800) by @dimitritholen in #126
- feat(api): store.import takes merge, unioning a known task's notes, checks, tags, edges and measurements instead of replacing them (D185) by @dimitritholen in #128
- fix(import): under merge, a note follows the winner, a check its own clock, and a child owned elsewhere or a repeated token id is refused (task #802) by @dimitritholen in #129
- docs(brand): the logo assets, and the wordmark at the top of the README by @dimitritholen in #130
- fix(import): child ownership decided over the whole payload before any row, and check timestamps read through the date gate (task #803) by @dimitritholen in #131
- docs(brand): the transparent wordmark, framed so it renders, at the top of the README by @dimitritholen in #132
- fix(import): the duplicate-source scan is linear, and a dry run and a real run report the same merge for a doc without id (task #801) by @dimitritholen in #133
- fix(memory): a unix backslash kept, the real file wins its alias group, and --json names the aliases skipped (task #798) by @dimitritholen in #134
- docs(brand): the outlined wordmark, framed so it renders, at the top of the README by @dimitritholen in #135
- docs(brand): the outline widened from six units to ten, reframed once more by @dimitritholen in #136
- test(core): a transitive cycle, a handed-over clock, cancel from done and the transition matrix, each pinned in tasqx-core (#80) by @dimitritholen in #137
- ci(gates): machete and semver-checks gates, pedantic clippy and bloat reports (#739) by @dimitritholen in #138
- feat(desktop): Memory Explorer — search, browse, edit and cross-navigate memory docs and task annotations (#692) by @dimitritholen in #140
- feat(mcp): tasqx_start_timer answers task.brief's memory, and list/add gain a rulings addendum (D186, #97) by @dimitritholen in #139
- ci(gates): the two #739 gates green — drop the unused serde_json from src-tauri, pin cargo-semver-checks 0.50.0 for rustdoc v60 (#805) by @dimitritholen in #141
- test(desktop): await the daemon's exit before removing its scratch store, so Windows teardow...
tasqx v0.12.0
This release is mostly about what tasqx reports back, and about being able to
correct it. A running clock now counts toward tracked time, a total that went
wrong can be adjusted with the reason on the record, a note can be edited in
place instead of deleted and retyped, and a harness that reports a single
token number finally has somewhere to put it. Exports stop over-sharing: a
filtered one carries only what its tasks need. Tags become lowercase
everywhere, which merges duplicates in an existing store the first time 0.12.0
opens it, so read the first Changed entry before upgrading.
Added
- A token count that isn't split into input and output. Many agent
harnesses report one number, and there was nowhere to put it: the whole
count had to go ininput_tokensor be dropped.total_tokensis now its
own kind of measurement, taken bytasqx doneandtasqx_complete_task
and refused beside a split count. It is never folded into the four buckets,
shows as "total (unsplit)" wherever a task's tokens are shown, and counts in
full toward the budget gauge. - Recording a token count after the fact.
tasqx tokens add 602 --total 37898and the new MCP tooltasqx_add_tokensattach a count to a task that
is already done, without hand-building an API envelope. Over MCP the
measurement is always recorded as a self-report at medium confidence — an
agent cannot certify its own count as telemetry-grade — and what each
confidence grade means is now written down in the tool descriptions and the
token-accounting guide. - Correcting tracked time, with a reason.
tasqx adjust <ref> <delta> --reason <text>(MCPtasqx_adjust_tracked) folds a signed amount into a
task's tracked total instead of overwriting it, records the delta and the
reason on an event, and can be taken back withtasqx undo. The task shows
the running correction beside its tracked time, so hours banked by a stalled
harness no longer quietly skew what a task cost. An adjustment that would
take the total below zero, or that carries no reason, is refused. - Editing an annotation in place.
tasqx annotate <ref> --edit <id> <text>(MCPtasqx_update_annotation) replaces a note's body and keeps its
id, its position and when it was written, so correcting a wrong description
no longer means deleting the note and promoting the next one into its place.
Search re-indexes the new text,--expected-revguards against a concurrent
edit, and the change is undoable. - Sorting by estimate or tracked time.
tasqx list --sort estimateand
--sort tracked(alsosortover the API and MCP) rank the biggest items
first, which is what grooming a backlog actually needs and what urgency
cannot answer. Both compare real durations rather than the stored text, so
four hours outranks ninety minutes, and a task with no estimate — or one
never started — sorts last whichever direction you ask for. - Charts take the same filter as everything else.
tasqx chart throughput,heatmapandburndownnow accept the filter language
list,reportandagendaalready take, sotasqx chart burndown project:work +urgentdraws the chart for one project's urgent work instead
of the whole store.chart burndown --project <name>still works and means
the same thing. - Scoping a whole imported folder.
tasqx memory import <dir> --project <name>files every document in that folder under one project in a single
call, which is what an agent reaching tasqx through the CLI alone needed to
land its imports scoped. Re-importing without the flag leaves a document's
project alone; naming one moves it. Every memory hit now also says which
project it came from, so a cross-project result is recognisable.
Changed
- Tags are lowercase and cannot contain whitespace.
+Perfand+perf
used to be two different tags, and+has spaceneeded quoting everywhere it
was named. A tag is now stored in one spelling — lowercased — by every door
that writes one, filters lowercase what they match against, and whitespace
is refused with the hyphenated form suggested. An existing store is migrated
the first time 0.12.0 opens it: names are lowercased, runs of whitespace
become a hyphen, and duplicates are merged with no task losing a tag. Each
task touched records an event listing what changed, whichtasqx undo
deliberately refuses to reverse. - A filtered export carries only what its tasks need.
tasqx export project:ledgerused to filter the tasks and then ship every memory
document from every project, every project row and the entire event log —
a leak the moment the file is shared. It now carries only the projects the
filter names or its tasks reference, only the documents scoped to those
projects, and only the events of what it exports; the header reports what
was dropped.--include-unscopedwidens it to documents that belong to no
project, and is refused when there is no filter to widen. An unfiltered
export is byte-for-byte what it always was. - A recurring task's next occurrence keeps its description and its checks.
A spawn used to come back with its fields only: no description note, no
acceptance checks, and nothing saying which task it followed. It now copies
the description verbatim and every check, reset to open, and records the
task it came from — shown as "every week from #604" on the card. A brief on
a spawn also opens with a "Last time" section quoting the previous
occurrence's delivery note. - Errors over MCP name MCP remedies. A stale-revision conflict used to
tell an agent to runtasqx show 1 --jsonand retry with--expected-rev,
a shell command and a flag over a transport that has neither. It now names
tasqx_get_taskortasqx_get_memoryandexpected_rev, and the CLI keeps
its own wording — including formemory update, which had the fault the
other way round and printed an MCP tool name at a shell. - A check can be named by its position.
check.setandcheck.remove
take either a check id or a 1-based position in the order the task lists
them, and on the CLI an all-digit word is read as a position. A miss no
longer answers with the id you mistyped and nothing else: it lists every
check by position, id and first words, as does removing an annotation that
is not there, and completing a task with a check name that matches none. - A title with CLI shorthand in it comes back with a warning. Adding a
task titledfix crash +bug due:fridayover the API or MCP stored the whole
line as the title, with no tag, no due date and nothing said. The title is
still stored as written — only the CLI expands shorthand — but the response
now names the words that looked like shorthand.
Fixed
- A task card could lose its Description and Delivered rows, because both
were read from whichever page of annotations the call happened to ask for:
asking for no annotations dropped both. They are now read independently of
the page. Completion also pins the delivery note, so a remark written
afterwards no longer replaces it in the Delivered row; reopening a task
clears the pin. tasqx briefhanded the task's own notes back as memory hits, verbatim,
below the card that had already printed them in full. They are now excluded
from the search itself rather than after the fact, so the hits a brief shows
are all from elsewhere and a sibling task's ruling can no longer be crowded
off the page by notes that were never going to be shown.- Tracked time read as zero while a clock was running. Starting a task and
working for two hours leftlist,show,brief, the card and the report
summary all reporting no tracked time at all, because only closed intervals
counted. Every one of them now includes the interval still open, and the
card's status row says so:tracked 4m (running). The dashboard, which was
adding the elapsed time itself, no longer counts it twice. - Importing a store could roll a memory document back to an older
revision. Restoring an export taken before a document was edited replaced
its title and body with the stale snapshot, silently, and reopened the
overwrite that the revision guard exists to prevent. The import now refuses
with a conflict, the same way it already did for a task. - An imported document's timestamps were stored exactly as written, so a
hand-written import with a lowercasezor a UTC offset sorted by its own
characters andmemory listcould show an older document above a newer one.
Document timestamps now pass the same date check a task's do, and an
unreadable one is refused by name. - Two memory documents could claim the same source. Re-importing a folder
then replaced whichever one the database happened to find first, leaving the
other stale, and a single import naming one source twice reported two
documents where it had written one. A source now names exactly one document:
adding, updating or importing onto a source another document holds is a
conflict that names it, and an import naming a source twice is refused
before anything is written. An existing store keeps the source on the most
recently modified of a set of duplicates and clears it on the others,
deleting nothing. - Two gaps in the telemetry tests, neither of which changed how tasqx
behaves: a test could fail on Windows CI because it raced the daemon's idle
shutdown rather than anything it was meant to check, and the warning that
fires when OpenTelemetry is enabled with no daemon reachable was only ever
tested for the case where nothing answers.
What's Changed
- docs(scripts): docs-capture.sh never said its piped rows render the terminal layout, so a card change looked fixture-neutral and reddened CI (#714) by @dimitritholen in #84
- fix(test): the otlp idl...
tasqx v0.11.0
This release is mostly about getting tasqx set up and understood. tasqx setup
installs the Claude Code integration in one screen, the API and MCP reference
pages are generated from the engine itself instead of hand-typed prose, and the
README is now a short pitch that links out to the wiki for everything else.
Four bugs are fixed, from a sort order that could favour an older task to a
memory snippet that read as two paragraphs.
Added
tasqx setupinstalls the Claude Code integration in one screen. It
registers the MCP server (claude mcp add --scope user) and writes the
bundledtasqx-workflowandretroskills to~/.claude/skills, shown as
an interactive checklist on a terminal or a flat list with--list. A skill
file that differs from the bundled one is kept unless you tick it or pass
--force, and setup never touches~/.claude.jsonitself — it drives
claude mcp add, because Claude Code owns that file.- A generated API and MCP reference. The reference pages
tasqx docsand
the documentation site render now come from the engine's own parameter
table, the MCP tool schemas and the documented response shapes, instead of
prose that could drift from what the server actually does. Objects also
gained their own pages — Task, Project, Annotation, Check, Dependency,
Memory document, Event and Token measurement — each listing the fields that
belong to it, exactly once, alongside the methods that read or write it. - The README is the pitch; the wiki is the manual. It opens on why you'd
want tasqx and links out todocs/wikifor install fine print, the MCP tool
roster and everything else you only need once you're using it. It now opens
on a VHS-recorded hero GIF showing the loop a user repeats — add a task with
its project, due date, priority, tag and estimate, make a second task wait
on it, then find the first again by fuzzy search down to its card — and
several feature rows carry their own short GIFs.
Changed
- Agent guidance now recommends the task card only when a person is
deciding on a task — one being proposed, or one asked about by name.
Starting or completing a task is one line instead
(▶ #<id> <title> · <priority> · <estimate> · <passed>/<total> checks/
✔ #<id> done · <passed>/<total> checks · unblocked #<n>), built from
information the agent already holds. The card itself renders the same as
before.
Fixed
task.list/tasqx listsorted by created or modified time could put an
older task above a newer one when one timestamp landed on a whole second
and the other didn't — the comparison ran on the timestamp text, where a
trailingZoutranks a digit. Both sort orders now compare true time.- The dashboard's detail overlay showed "blocked by #N" in red for every
dependency, even when the task itself was done or its blocker was done or
cancelled. It now shows only the blockers that are actually still open. tasqx briefandtasqx showon a terminal packed acceptance checks into
the two-column field grid, crowding a short check beside a field like
rev. Checks now print in their own block below the fields, one per line.- A memory hit's snippet in a task brief could split across a blank line
and read as two paragraphs, in the MCP/markdown and card views alike. It
now prints on one line. - Every API method's guard against an unknown parameter key and a missing
required one now has test coverage across the board, closing gaps where
25 of 42 methods went unchecked for an unknown key and only the first of
several missing required keys was ever probed. The guards themselves were
already correct; no method's accepted input changed. - The documentation site's tables no longer run off a phone screen, and
the install section on GitHub Pages offers the right installer for each OS
and architecture instead of only Homebrew or acargo buildline.
What's Changed
- feat(docs): the API and MCP pages described methods and tools in hand-typed prose nothing compared with the engine (D158) by @dimitritholen in #54
- feat(cli):
tasqx setupinstalls the MCP server and the tasqx-workflow and retro skills from one checklist screen (D158) by @dimitritholen in #55 - feat(design): freeze tasqx desktop as api-only tauri client by @dimitritholen in #57
- feat(docs): the reference answered "what does this method return" but never "what is a task", and the Objects section was an empty heading (D161) by @dimitritholen in #59
- feat(docs): the README read as a manual, with the promise below the fold and the caveats above it; it is now the pitch, and the reference detail lives in the wiki (D162) by @dimitritholen in #60
- fix(docs): the Pages install section only offered a cargo build, while the wiki and README lead with Homebrew, Scoop and the installer scripts by @dimitritholen in #62
- fix(docs): the acceptance pass found tables running off a phone, field descriptions cut off at every width, and raw backticks in the reference (D149) by @dimitritholen in #61
- feat(docs): the README opened on a still dashboard that could not show tasqx moving — a VHS tape over the demo store records add, next and the dashboard into hero.gif (D163) by @dimitritholen in #64
- docs(skills): land-tasqx-pr told the agent to list and resolve review threads with inline gh commands the worktree guard refuses by @dimitritholen in #63
- feat(docs): the README said nothing about ordering work — a "Work in the right order" row with deps.gif shows done naming the task it unblocked and next picking it up by @dimitritholen in #65
- feat(docs): the README claimed long-term memory without showing it — a "Decisions you can find again" row with memory.gif imports a folder of decisions and finds a ruling by two words with its source file by @dimitritholen in #66
- feat(docs): report --outcomes on the demo store was zeros and dashes, so the README could not show it — the demo history gains rework, forced and dropped work, estimates with tracked time, notes, checks and token spend, and an outcomes.gif row shows the result by @dimitritholen in #67
- feat(docs): the hero GIF showed a plain add, next and a dashboard that sold little of the loop — it now adds a task with every modifier, makes a second wait on it, and finds the first in pick by fuzzy search down to its card (D163 amended) by @dimitritholen in #69
- feat(docs): the README promised agents a one-call brief without showing one — a "Briefed before it starts" row with brief.gif shows done 50 unblocking #51 and brief 51 handing over #50's conclusion and matching memory by @dimitritholen in #70
- docs(agents): landing a task sat through four minutes of CI and every Qodo round before the next task could start — each task gets its own branch and builder, and its PR merges itself by @dimitritholen in #71
- test(recurrence): a recurring occurrence could lose its project, tags, priority, estimate and budget_tokens with the suite green by @dimitritholen in #72
- docs(skills): land-tasqx-pr step 4 never read a merged PR's review threads, could block about 20 minutes waiting on Qodo, and its closing line always claimed 2/2 checks by @dimitritholen in #73
- test(dispatch): 25 of 42 methods could accept an unknown key, and a second missing required param was never probed, with the suite green by @dimitritholen in #74
- docs(skills): land-tasqx-pr deferred a merged PR at every boundary when Qodo never finished, so its task could never close by @dimitritholen in #75
- chore(guard): stop duplicating the permission denies; allow --force-with-lease on task branches by @dimitritholen in #76
- docs(mcp): card for decisions, one line for routine task events (D164) by @dimitritholen in #77
- fix(memory): brief's markdown printed a snippet's line breaks, so one memory hit read as two paragraphs ("description How an SDK…" / "Cut the…") by @dimitritholen in #79
- fix(engine): task.list sort:created/sort:modified compared the timestamp text, so a whole-second stamp sorted above a later fractional one by @dimitritholen in #80
- fix(tui): the dashboard detail overlay printed "blocked by #N" for every dependency edge, so a done task or one with a done blocker showed a red blocker line by @dimitritholen in #81
- fix(cli): brief and show on a terminal packed the acceptance checks into the two-column field grid by @dimitritholen in #78
- fix(cli): the card's check block dropped a check with an empty body and ran a multi-line check body together (PR #78 review) by @dimitritholen in #82
- chore(release): 0.11.0 by @dimitritholen in #83
Full Changelog: v0.10.0...v0.11.0
tasqx v0.10.0
This release is mostly about AI agents. A correction you give once is now
remembered: a memory doc can be marked standing, and every new MCP session
starts with that project's standing rulings. The tool list an agent pays for
on every prompt is about a quarter smaller, and a task can be shown as a card.
Two defaults changed in ways a script or an agent setup can notice, so read
the first section before upgrading.
Changed: check these before upgrading
tasqx donerefuses a task that still has open blockers. It used to
complete it silently, which left a dependent done ahead of the work it
depended on. It now exits withconflict(exit 5) and names each open
blocker.--force(MCPforce: true) completes it anyway, the override is
recorded on the event, andtasqx report --outcomescounts it under a new
forcedmetric. A script that completes tasks out of dependency order needs
--forceor a reorder.- MCP reads answer less by default.
tasqx_get_taskandtasqx_brief_task
send the rendered view only, andinclude_json: truebrings back the JSON
block.tasqx_list_taskssends nine fields per row with null keys left out,
andfields: []returns the whole row.tasqx_search_memoryand the brief
leave out each hit's bm25rank, andinclude_rank: truerestores it.
tasqx_list_memorypages twenty rows ofid,title,sourceand
modified, andinclude_preview: truerestores the rest. The JSON API and
the CLI still return every field, so this affects only agents that parsed
the dropped ones. - The brief shows five memory hits instead of ten, in the CLI, the JSON
API and MCP alike.--memory-limit(memory_limit) still asks for more.
Added
- Standing memory.
tasqx memory add --standingmarks a doc as a ruling
for every session of its project, or of every project when it has none.
memory update --standing true|falsesets or clears the mark, and
memory list --standingshows the marked docs. Over MCP,tasqx_add_memory,
tasqx_update_memoryandtasqx_list_memorytakestanding. An existing
store gains the flag when it is opened, and exports carry it. Past fifteen
standing docs in one project,addanswers with a hint to merge or clear
some. - New MCP sessions start with the project's standing rulings. The
initializeinstructions now end with them. The project is taken from the
foldertasqx mcp serveruns in, or the nearest parent folder named after a
project, so a git worktree finds its repo. Failing that, the default project
is used. Standing rulings come first and are never dropped. The project's
newest other docs fill the rest of a 3 KB budget, under a separate heading
that marks them as context rather than rules. With nothing to show, the
instructions are exactly what 0.9.0 sent. - Task cards.
tasqx show,brief,nextandwhytake--cardand
print a task as a fixed 72-column box, with--asciifor plain borders.
tasqx_get_task,tasqx_brief_taskandtasqx_complete_tasktake
view: "card", so an agent can hand a person the same box. A completion
asked for the card answers with the closing card, which saves a second read. - Shorter tool descriptions. Every MCP tool description now states only
its contract. The whole tool list shrank from 42.7 KB to about 31 KB, which
is roughly 3,000 fewer tokens on every prompt for clients that load all
tools up front. The reasoning moved to DESIGN.md, where
tasqx_search_memoryfinds it once the docs are imported. - The brief keeps room for rulings. Half of the brief's memory hits are
reserved for knowledge docs, so a project's many task notes can no longer
bury the decisions that govern it. - A documentation site. The guide
tasqx docsopens offline is also
published at https://dimitritholen.github.io/tasqx/ on every push tomain.
Its screens are real captured terminal output shown as text, and CI fails
when a screen no longer matches what the binary prints. TASQX_NOWpins the clock. Set it to an RFC 3339 instant and every date
tasqx prints or stores uses that instant. It exists for reproducible
screenshots and tests, andtasqx aboutsays when a pin is active. An
invalid value exits 2 before anything is written.
Fixed
- A done task could still report unmet blockers, so
task.getanswered
blocked: falsenext to a non-empty blocker list. A closed task now has
none, and every reader uses the same rule. tasqx_get_taskcould exceed the MCP response budget when the caller
named its own page size. The budget now always holds. An oversized note is
cut in the response with a marker, the store keeps it whole, and
max_body_bytesraises the cap.memory listcould show an older doc above a newer one when their
timestamps had different lengths. It now orders by the actual instant.- Re-importing a markdown folder did not bump a doc's revision, so an
update holding the old revision could overwrite the import. The import now
bumps it, and that update gets a conflict instead. - An MCP call with
arguments: nullskippedtasqx_list_tasks' defaults. tasqx docscould exit outside its JSON envelope when the page could
not be written.
What's Changed
- feat(brief): the ruling a hundred sibling notes buried, and the half-page now reserved for it (D147) by @dimitritholen in #24
- docs(claude): every change to main goes through a pull request by @dimitritholen in #25
- feat(docs): Stripe-style shell for the guide — sectioned sidebar, reference columns, code tabs, search, theme switch (#645) by @dimitritholen in #28
- feat(docs): publish the guide to GitHub Pages from CI on every push to main (#650) by @dimitritholen in #27
- fix(mcp): the response budget holds for every get_task answer; oversized bodies are cut with a marker (D148) by @dimitritholen in #29
- docs(skills): land-tasqx-pr — the sequence that gets a task branch through protected main without a retry by @dimitritholen in #30
- feat(clock): pin the clock with TASQX_NOW so captured docs screens are reproducible (D148a, #643) by @dimitritholen in #26
- feat(docs): the wiki and the guides are pages of the site, rendered from the repository's own markdown (#649) by @dimitritholen in #31
- fix(engine): task.done refuses a task with open blockers; force overrides and is recorded (D150) by @dimitritholen in #32
- feat(docs): captured terminal screens rendered as text — ansi_html, a fixture manifest, and a CI drift job (D149, #644) by @dimitritholen in #33
- docs(skill): tasqx-workflow keeps only what the MCP instructions and CLAUDE.md do not say by @dimitritholen in #35
- feat(mcp): tasqx_get_task and tasqx_brief_task answer the rendered view alone by default; include_json: true adds the JSON block (D151) by @dimitritholen in #37
- feat(mcp): tasqx_list_tasks sent 22 keys per row, most of them null, to an agent that reads nine (D152) by @dimitritholen in #38
- feat(mcp): tasqx_complete_task takes
view: "card"and answers the closing card ahead of its JSON (D153, #673) by @dimitritholen in #39 - docs: the guides still taught a per-completion retro hook that was retired today, and six pages never heard of D147–D152 by @dimitritholen in #40
- docs(guide): the embedded retro skill still promised every annotation after the skill itself learned the D148 cut by @dimitritholen in #41
- feat(mcp): memory reads slim down — brief page of five, rank and list preview opt-in (D154) by @dimitritholen in #42
- docs(mcp): the tool table and the wiki's agent page never learned that tasqx_complete_task answers the closing card (D153) by @dimitritholen in #43
- docs(skills): land-tasqx-pr pulled main from inside the worktree the harness had isolated, and closed with a launcher that refuses every rebase merge by @dimitritholen in #44
- feat(mcp): tool descriptions carry the contract, not the reasoning — roster 42.7 KB → 30.9 KB (D155) by @dimitritholen in #45
- feat(docs): README pictures rasterised from the site's own render path; freeze retired (#651) by @dimitritholen in #36
- feat(memory): a doc carries a
standingflag — add/update/list/get/search/export carry it, soft cap of fifteen per scope answers a hint (D156, #101) by @dimitritholen in #46 - feat(docs): the Commands page documented twelve verbs by hand and typed their output; it is now derived per verb from cmddoc and clap (D149) by @dimitritholen in #47
- fix(complete): a zero lookup budget returns before the worker starts (#683) by @dimitritholen in #49
- docs(site): the Overview page draws how the pieces fit as an inline SVG coloured from the theme variables, in place of box-drawing text that overflowed its column (#684) by @dimitritholen in #50
- feat(mcp): initialize appends the session's standing rulings to the D141 instructions (D157, #96) by @dimitritholen in https://...
tasqx v0.9.0
One addition aimed at the first minute after claude mcp add tasqx — the
server now tells an agent when to use it, not only what it can call — and one
ordering defect that could hand any reader the wrong annotation.
Added
initializecarriesinstructions. Every MCP host that surfaces server
instructions (Claude Code and Cursor put them in the agent's system prompt)
now receives a condensed workflow with no setup: search memory before
deciding, track multi-step work as tasks, brief, start, annotate and
complete each one, store decisions with their reasons, import your markdown
on day one, and always spell the verb. The text is built from the server's
scope: under the default read-only scope it names no write tool, says once
that the server is read-only, and tells the agent to put what it could not
store into its reply instead of dropping it. A test binds every tool name in
the text to the live roster, so a renamed tool cannot ship inside a system
prompt that calls the old name. The paste-anywhere block in
Giving an agent memory in any client
remains the fuller version, for hosts that ignore or truncate the field.
Fixed
- Annotations could come back out of order, with a newer note paged out and
an older one in its place. The sort key was the stored timestamp text,
whose fractional second is variable-length — trailing zeros trimmed, the
fraction gone at a whole second — and compared as text an older stamp can
sort above a newer one. Two notes written inside the same millisecond, which
is what an agent annotating in a burst produces, were enough to trigger it.
Ordering now follows the time-ordered id, soshow,brief's "what the
prerequisite concluded",task.getpaging andstore.exportall agree on
which note is the newest. Token measurements, ordered the same way, got the
same fix.
Full Changelog: v0.8.0...v0.9.0
tasqx v0.8.0
Five things an AI agent does with tasqx got cheaper, provable, or both — and
one of them was a bug. Nothing here changes how tasqx behaves for a person at a
terminal, apart from two new verbs and two new rows on tasqx show.
Added
tasqx report --outcomesanswers the questiontasqx reportnever did:
not what the work cost, but whether it worked. Rework (completions that came
back), estimate calibration, token cost, completions with no annotation,
abandoned work, budget overruns and unproven completions. It reads history
the store already holds, so it has something to say the first time you run
it. Every rate prints ascount/nrather than a percentage, deliberately:
3/12 and 3/3 are the same percentage and very different news.tasqx brief <ref>is everything needed before starting a task, in one
read: the task, each prerequisite with what it concluded (its newest
annotation), what this task blocks, and relevant memory — under a query tasqx
derives from the task's own title, tags and project. You do not supply search
terms, which matters because a guessed term that finds nothing looks exactly
like a store with nothing in it.tasqx check add|set|rmputs acceptance criteria somewhere a completion
can be held to them. tasqx never RUNS a check: the criterion is a claim and
the evidence is a citation, both stored verbatim. Completing with one still
open is not refused — it is counted byreport --outcomes.--budget-tokensonaddandmodify: a size gauge over fresh tokens
(input, output and cache creation; cache reads are not counted). It stops
nothing. An overrun is a signal that the task was probably too big to hand
over whole.- Five MCP tools:
tasqx_brief_taskandtasqx_outcomeson the read
scope,tasqx_add_check/tasqx_set_check/tasqx_remove_checkon write.
tasqx_complete_tasktakeschecks_passedandevidence. memory.searchgainsinclude_unscoped, which widens a project scope to
documents belonging to no project — whattasqx memory importproduces, so a
strict scope used to hide every imported ADR.
Fixed
- A timer another session was holding is no longer stopped silently. Two
agents on one store, neither passing--keep: the secondstartstopped
every active task, so the first agent's task leftactivewhile it was still
working, its remaining time went untracked, and only the second agent was
told. Starting against a clock a different session holds is now refused;
--keepstill runs both deliberately. A person at a shell sees no change. - A dashboard test asserted a panel equalled itself and had stopped guarding
what its name claimed.
What's Changed
- docs(design): four rulings on measuring and cutting the cost of agent work (D136, D137, D138, D139) by @dimitritholen in #23
Full Changelog: v0.7.0...v0.8.0
tasqx v0.7.0
The terminal was rebuilt around a single house style: every table, card and
chart now follows the same rules. This release also adds a task browser, a
memory browser and a much more useful HTML report.
Changed
-
Every screen reads the same way.
listandagenda:- carry a state rail on the left and an urgency gauge beside each figure
- spell dates as calendar days (
today 23:59,tomorrow,Sun) - draw no table rules
projects,report,memory search,config listand the theme screens now
follow the same layout. Every table fits the terminal it is printed on, and no
number is ever cut to make a row fit. -
Write commands answer with a card.
addand the eighteen verbs that change
a task print the task they touched, with what changed in bold. Output piped
from a write verb is different from 0.6. -
show,nextandwhyspell dates as calendar days, say each fact once,
and explain themselves. -
pickis a task browser. It showslist's rows, searches with/, opens a
task's card on Enter and starts it withs. Closing it without starting
anything exits 0. -
The dashboard is one scoped task list with PROJECTS, BURNDOWN, PULSE and
EFFORT beside it. The burndown now draws a real shape. -
tasqx manualfits the terminal it is read on and opens every page its
contents list. -
Charts: the heatmap no longer paints a good day in the danger colour, and
the throughput chart labels its series properly.
Added
tasqx memory liston a terminal is a browser with a live preview and a
search.- Memory search:
- words are stemmed, so
testalso findstests - results report
totalandhas_more - search can be scoped to a project
- a stored document can be updated in place
- words are stemmed, so
- HTML report (
tasqx report --html):- opens with what needs attention
- header tiles jump to their sections
- search, cross-filtering, a sortable table and per-task panels, all offline
- light by default, with a dark switch
- a totals row and human-readable durations
tasqx about: who made tasqx, which build you are running, and where its
store lives.listflags:--sort,--limit,--offsetand--fields.- Filtering on
priority:H|M|L. - Correcting tracked time with
modify: set it or clear it, and the change is
logged. - Dependencies: a blocking task can now say which tasks it blocks.
tasqx config describe, for settings whose unit a bare number does not
show.- Escaping in titles:
\!and\+put a literal!or+in a title. - Tokens:
task.listhas atokensfield and a-tokenssort- a self-reported token count can be removed
otlp.statusanswers whether telemetry is reaching tasqx- the daemon announces a first-run attribution backlog instead of working
through it silently
- MCP and the JSON API:
tasqx_cancel_tasktasqx_remove_annotation, which scrubs the annotation's body from storagetask.modifyechoes the resolved value of every field it settask.addechoes the title, due date, tags and scheduled date it stored- the annotation body echo can be switched off with
include_body: false
Fixed
More than a hundred fixes across the CLI, memory, reports, the dashboard, pick,
filters, themes, the daemon, MCP and token attribution. The most visible:
undocould reverse the wrong event after an import.- Several write commands reported values other than the ones they stored.
- Some screens drew clipped or blank rows at narrow widths.
The full list is in the commits on the release page.
Full Changelog: v0.6.0...v0.7.0
tasqx v0.6.0
What's Changed
- the scoop bucket: a generated manifest, its guard, and the deny rule that blocked the generators by @dimitritholen in #17
- the package managers go first, and D77 records why (PM-5) by @dimitritholen in #18
- a tag bumps the tap and the bucket itself (PM-4) by @dimitritholen in #19
- feat(show): a status-colored rail card for tasqx show (D78) by @dimitritholen in #20
- chore(release): 0.6.0 — the rail card ships by @dimitritholen in #21
Full Changelog: v0.5.1...v0.6.0
tasqx v0.5.1
What's Changed
- The task card: framed add echo and ledger show on interactive terminals (D76) by @dimitritholen in #15
- refactor: the audit pass — 34 units toward the quality bar, behavior preserved by @dimitritholen in #16
Full Changelog: v0.5.0...v0.5.1