dstask syncs your task list with git instead of a task server
Git powered terminal-based todo/note manager -- markdown note page per task. Single binary!
At a glance
- What is it?
- dstask is an MIT licensed Go tool that keeps one task per markdown file in a git repository, so syncing between machines is a git operation rather than a protocol handshake, and each task carries a full markdown note. It is a single statically linked binary and it deliberately does not support collaboration.
- Who is it for?
- dstask fits a developer who wants a task list they can read, diff and sync with the same tools they already use for code, and who is comfortable resolving a merge conflict when two machines touch the same task. It does not fit a team, since the README lists collaboration as an explicit non-feature, and it does not fit someone who wants rich scheduling, dependencies and a report generator.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 165 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The task list is a git repository
dstask is a personal task tracker designed to help you focus, and the README is direct about the audience and the trade. It is similar to Taskwarrior but uses git to synchronise instead of a special protocol.
The second sentence is the whole pitch and also the whole warning. If you're at home in the terminal, and with solving the occasional merge conflict, then dstask is for you.
The mechanism follows from that. The tasks live in a git repository, one markdown file per task, so syncing two machines is a git push and a git pull, and there is no server to run. The README compares the git approach to passwordstore style sync, in the sense of a tool that reuses an existing well understood sync mechanism rather than inventing one.
The consequence that follows is the merge conflict. Git will happily merge two different tasks, and if the same task was modified in two places, you get a conflict to resolve by hand, in a text editor, in a file you can read. For a personal task list that is almost always fine, and the README's phrasing, with solving the occasional merge conflict, is honest that it happens at all.
The upside is that the data is not in a database or a proprietary format. The task list is a directory of markdown files in a git repository, which means it diffs, it versions, it is greppable, it can be edited by hand, and it can be backed up by anything that backs up a git remote.
The requirements are correspondingly minimal. Git, and a 256-color capable terminal. The tool is a single statically linked binary, so there is no runtime to install and no library dependencies on the target machine.
Contexts are the part that makes it a system rather than a list
The feature list is short, and the first item is the one that does the work.
A powerful context system, which automatically applies filter and tags to queries and new tasks. A context is a saved set of filters and tags, and applying it means you do not have to type the filter every time. The automatic part matters, since a context that only filters queries still makes you repeat yourself on every new task, and one that also applies to new tasks means the tag lands on the task without you remembering it.
The second feature is the git powered sync, undo and resolve, which means no need to set up a sync server, and syncing between devices is easy.
The third is a quality of life fix that tells you about the data model. Task listing won't break with long task text. That is a small line, and it implies the tasks are markdown files whose summary is the first line, so a task with a long note does not produce a broken or truncated list entry. It is the kind of bug you hit once and then never think about again in a good implementation, and a good sign in a README.
The note command lets you edit a full markdown note for each task, and the README specifically calls out that checklists are useful here. So a task is a summary line plus a free-form markdown body, and the body is where the checklist, the links and the context live. That is a better fit for real work than a set of structured fields, and it is why the tool has an open command to open URLs found in specified task, including notes, in the browser.
Completion is the speed feature, with zsh and bash completion including tags and projects in current context, and PowerShell completion on Windows. Completion that knows the tags and projects in the current context is much more useful than completion of command names alone, since the tags are what you have to remember.
And there is an import tool, documented in doc/dstask-import.md, which can import GitHub issues or taskwarrior tasks. The taskwarrior import is what makes the migration path real, and there is a separate migration guide at doc/taskwarrior-migration.md.
The collaboration non-feature is stated up front
The non-features section is short and it is the most important part of the README for anyone evaluating the tool for a team.
Collaboration. This is a personal task tracker. Use another system for projects that involve multiple people. Note that it can still be beneficial to use dstask to track what you are working on in the context of a multi-person project tracked elsewhere.
That is a better answer than a refusal. A personal task tracker sitting alongside a shared project tracker is a common and reasonable arrangement, and the tool is honest that it is the wrong shape for shared work rather than pretending to support it.
The reason is structural rather than a missing feature. A task list in a git repository has no access model, so two people pushing to the same repository get merge conflicts on the same tasks, and there is no lock, no server and no concept of an assignee being authoritative. The GitHub issues import exists, and that is how information comes in from a shared system, rather than the shared system being the source of truth.
The requirements section reinforces the personal scope in a smaller way. A 256-color capable terminal is required, which is a sign that the output is a styled table with colours rather than plain lines, and the table.go and display.go files at the top of the repository are consistent with that.
The project also publishes packaging for several systems, with the unofficial packages listed for Nix, Arch through the AUR, FreeBSD and Homebrew, and a repology badge for the rest. The word unofficial in that list is precise, since the primary distribution is the releases page.
Installation is a binary on the PATH and a git repository
The installation steps are four and they are all quick, which is a fair reflection of a tool with two requirements.
First, copy the executable from the releases page to somewhere in your PATH, naming it dstask on Linux and macOS and marking it executable, or dstask.exe in a directory on PATH on Windows.
Second, enable shell completions. For bash, add source <(dstask bash-completion) to your.bashrc. For zsh, either run dstask zsh-completion > /usr/local/share/zsh/site-functions/_dstask or source completions/zsh.sh in your.zshrc. Nushell gets dstask nushell-completion | save -f ~/.config/nushell/completions/dstask.nu followed by a source line in config.nu, and PowerShell on Windows has its own section.
Third, set up an alias in your.bashrc, alias task=dstask or alias t=dstask, to make task management slightly faster. The two letter alias is a good choice for a tool you invoke many times a day.
Fourth, create or clone a ~/.dstask git repository for the data, with mkdir ~/.dstask && git -C ~/.dstask init on Linux and macOS, and the equivalent with %USERPROFILE%\.dstask on Windows.
The Windows notes add that the environment variable DSTASK_GIT_REPO can override the data location, and that on first run dstask may prompt to create the repository if it does not exist; answer y or yes to proceed.
The Windows notes also specify the terminal requirement, use Windows Terminal or PowerShell with a 256-color capable profile for best results, and the PowerShell completion section gives both a one-off invocation and a permanent profile change, including the profile creation snippet for a machine that has no profile file yet.
The completions directory at the repository root holds the scripts for each shell, and there are also.dstask-bash-completions.sh and.dstask-zsh-completions.sh at the top level, which suggests they are generated rather than hand written.
The build produces two binaries and the tests include an integration script
The Makefile is short and it reveals that there are two programs, not one.
dist/dstask: clean
go build -o dist/dstask cmd/dstask/main.go
go build -o dist/dstask-import cmd/dstask-import/main.goSo dstask itself and a separate dstask-import tool, which matches the README's mention of the import tool for GitHub issues and taskwarrior tasks. The install target copies both into /usr/local/bin, and the release target runs a do-release.sh script, with a.goreleaser.yaml and a shell.nix at the top level.
The test setup is worth a look, because it is more thorough than a typical single-binary tool's.
test:
go test -v ./...
./integrationtest.sh | cat # cat -- no tty, no confirmationsSo there is the unit test suite and then a separate integration test script, and the pipe to cat is there for a specific reason, the comment says no tty, no confirmations, which means the integration script prompts for confirmation and the pipe supplies it or suppresses the interactive check. That is a small piece of engineering care, since a test that hangs waiting for input in CI is a common failure.
The Go dependency list is the interesting part for anyone thinking about what the tool can do. The shurcooL/githubv4 and golang.org/x/oauth2 entries are the GitHub API client and the OAuth2 library, which is how the GitHub issues import authenticates. BurntSushi/toml and gopkg.in/yaml.v2 are the config formats, so the tool is configured by a TOML or YAML file. go-isatty detects whether output is a terminal, which is what lets the tool colour its output only when a human is looking at it. go-runewidth and rivo/uniseg handle the table layout, and mvdan.cc/xurls handles URL detection, which is the open command finding links in a task. logrus is the logging. uuid generates task identifiers.
The module is on Go 1.23.4, and the source layout is flat and readable, with query.go, task.go, taskset.go, git.go, display.go, table.go, config.go and the commands in commands.go, plus a cmd/ directory for the two binaries and a pkg/ directory.
Where dstask is the wrong choice
The first wrong case is a team. The README lists collaboration as a non-feature and says to use another system for projects that involve multiple people. A shared task list in a git repository has no locking and no ownership model, so two people assigning the same task will produce a conflict rather than an update.
The second wrong case is someone who wants Taskwarrior's scheduling. dstask is described as similar to Taskwarrior, but its feature list is short: contexts, tags, projects, per-task notes and git sync.
The third wrong case is a person who does not want to think about git at all. The README's own framing, and with solving the occasional merge conflict, is a signal. The data is excellent for a developer, plain files, diffable, greppable, but the sync mechanism is a distributed version control system, and for some people that is a feature they never wanted.
The fourth wrong case is a mobile or graphical workflow. The tool is a terminal application with a 256-color requirement, so a phone is out of the question without a terminal, and there is no application to look at your list with.
How it differs from Taskwarrior
The comparison worth making is with Taskwarrior, because the README names it twice, once as the thing it resembles and once as the thing it can import from.
The difference in approach is the storage and sync model. Taskwarrior synchronises with a special protocol rather than git, which is the contrast the README draws. dstask stores one markdown file per task in a git repository and synchronises with git, so the transport is something you already have configured, something that already handles authentication, and something that keeps a history.
The second difference is the data model. A dstask task is a markdown file, with a summary line and a body you can write anything in, which is why the note command exists, why checklists are recommended, and why the open command can find URLs in the notes as well as the summary. The trade is the obvious one, less structure and more freedom, and a query language that has less to work with.
The third difference is the undo and the history. The README lists git powered sync, undo and resolve as one feature, and a git repository gives you a per-task commit history for free, which is a different kind of undo from a task manager's own mechanism.
The fourth difference is the import path. The README documents a taskwarrior migration guide and an import tool that handles GitHub issues as well, so moving from Taskwarrior is a supported operation rather than a manual exercise. The GitHub issues import is also the mechanism by which shared work enters a personal tracker, which is the arrangement the non-features section recommends.
Editorial conclusion
dstask fits a developer who wants a task list they can read, diff and sync with the same tools they already use for code, and who is comfortable resolving a merge conflict when two machines touch the same task. It does not fit a team, since the README lists collaboration as an explicit non-feature, and it does not fit someone who wants rich scheduling, dependencies and a report generator. Before adopting it, set up the git repository at ~/.dstask as the README describes, decide whether the repository should be private given that the files are plain markdown, and pin v1.0.1 from 2026-01-10 rather than tracking the branch, since the last push was on 2026-05-11.
Frequently asked questions
How does dstask synchronise tasks between machines?
With git. Each task is a markdown file in a git repository, and syncing between devices is a git push and pull rather than a special protocol, so there is no need to set up a sync server. The trade is that a task modified in two places produces a merge conflict to resolve by hand.
How do I install dstask?
Copy the executable from the releases page to somewhere on your PATH, name it dstask or dstask.exe and mark it executable, enable shell completions for your shell, and create the data repository with mkdir ~/.dstask && git -C ~/.dstask init on Linux and macOS. The location can be overridden with the DSTASK_GIT_REPO environment variable.
What are dstask contexts and why do they matter?
The context system automatically applies filters and tags to queries and to new tasks, so a saved set of tags lands on a new task without being repeated. The feature list also notes that completion includes the tags and projects in the current context, which is what makes the tags practical to use.
Can I use dstask with a team?
Not for shared task management. The README lists collaboration as a non-feature and says it is a personal task tracker, and that you should use another system for projects involving multiple people, though it can still be useful to track your own work in the context of a project tracked elsewhere. There is an import tool for GitHub issues.
How do I move my tasks over from Taskwarrior?
The repository has a migration guide at doc/taskwarrior-migration.md, and the import tool, built as a separate dstask-import binary, can import taskwarrior tasks as well as GitHub issues. The Makefile builds both dstask and dstask-import, and the install target puts both on your PATH.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/naggie-dstask)