Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Grit – a multitree-based personal task manager (github.com/climech)
255 points by climech on April 2, 2021 | hide | past | favorite | 45 comments



I really like trying out tools that allow me to organize and track tasks, as they help me keep focused and more motivated if I know where I am, what I have done and what I need to do.

Grit is really cool, the name feels a bit unfortunate as it might have muscle memory overlap with “git” - nothing that can’t be solved with an alias but perhaps something to ponder.

I also sadly see limited use for a task tracking system that I don’t have with me at all times - I would love a way to use grit on my phone and desktop computer with some kind of sync. Otherwise it would be limited to tracking work-related stuff as when I’m not working I really don’t use the computer; the grocery list example was really nice but I don’t carry my laptop to the grocery store :)

I really like Grit, will keep an eye on how it evolves.


Agree with your point on muscle memory, although I find a shell alias to be a sustainable workaround.


I've been working in this space for my own task manager (multi-parent + infinite depth), and here's a couple things I've landed on:

- My objective is being able to show a "todo" list that is _actually actionable_. So I think early on its important to build in notions of "availability" (i.e. "this is not waiting on something else, you can work on this now")

- The dual is you kind of need nodes that represent "blockers". Here you have the parenting mechnaism that could get you there, but also stuff like setting dates on nodes (in Omnifocus this looks like the "defer until" date)

- I tried making a UI that handled N-node depth, but ended up figuring out that just displaying at most 2 levels of depth and then having fast loading when zooming in/out saved me a lot of API design headache and gets me 95% of the way there

- Even if your data is a tree structure, a lot of times just showing a flat list (perhaps with "parent node is X" annotation) is going to work out nicer. Notably with search


What's the difference between a dag and a multitree? The wikipedia article was confusing - it seems that it prevents diamond shapes? Like where 1 leads to both 2 and 3, and where 2 and 3 both lead to 4?


>prevents diamond shapes

Pretty much this, unless I'm missing something. An earlier version of the program actually used DAGs, but I found it a little underconstrained. I got pretty excited when I discovered multitrees, as it seemed to be exactly what I needed the whole time.


Why is the no diamond constraint useful here?


Without it, the structure allowed the user to create a graph like this:

    [x] Task
     ├──[x] Sub-task (1)
     │   ├──[x] Sub-sub-task (2)
     │   └──[x] Sub-sub-task
     ├──[x] Sub-task (3)
     │   ├──[x] Sub-sub-task (2)
     │   └──[x] Sub-sub-task
     └──[x] Sub-task
by creating a link from (3) to (2). The tree command would actually omit the second occurrence of (2), since the algorithm visited each node just once.


Precisely; a multi-tree has a unique path between two nodes.

On the same note, I wonder what is the relation between dags/multitrees and semilattices. They seem to be very similar concepts afaict.


Oh, so you can only crosslink from different root nodes. That makes sense.

There are so many ways to structure todos. In this case, it appears to be using subtasks specifically to break things down in various ways, and it's a cool implementation.

I personally think of todos as having dependencies, like a simplified PERT chart, which would more require a DAG. If I brought in the ability to generalize groups of that graph (or in the other direction, take a general node and "break it down" into a group of nodes), I guess I'm thinking of a multi-graph there. That sounds really hard. :)


I use a flat text file with exactly this structure, just indenting when I need a new layer.

I tried fiddling with it with vim folds but in the end just ended up deleting things I finish.

I learned this from a friend at work.


From a quick glance at the README this supports a slightly more interesting structure than an indented text file: it's actually a DAG where large subgraphs are trees. This allows links between different nodes. That's not possible in an indented text file.


I just started migrating to taskwarrior which great due to the many clients. Actually its integration with vimwiki via the taskwiki plugin [1] is quite powerfull allowing editable views. Wonder if this dag aproach could be integrated via metadata without loosing compatibility.

[1] https://github.com/tools-life/taskwiki


TiddlyWiki uses a similar data model for table of contents by default and I love it! I think the multitree constraint is a good idea over a general DAG.


Tiddlywinks is one of those things that is too good to actually monetize. It's amazing software. In you can run on it on a server or on an a flasdrive. Or just from dropbox.


Looks like a CLI version of Workflowy (https://workflowy.com) to me.


I would kill for a GUI app like Workflowy with multitrees. I really do need a graphical representation in order to best visualize what's going on.


Workflowy is good but it's really expensive for what it does, I'm glad we have grit as an alternative.


How do you handle ordering?

I noticed:

    $ grit add -p 5 Bread
    (5) -> (6)
    $ grit add -p 5 Milk
    (5) -> (7)
    $ grit add -p 5 Eggs
    (5) -> (8)
led to:

    ├──[ ] Get groceries (5)
    │   ├──[ ] Bread (6)
    │   ├──[ ] Eggs (8)
    │   └──[ ] Milk (7)
And I didn't see anything about reordering tasks in the readme. Is everything sorted by title?


Yes, it's sorted by name in natural order. I haven't decided yet which would work best as default (this vs insertion order) -- feedback is welcome. This works well for numbered book chapters, something I personally find useful. In any case, the defaults will be configurable -- when I implement config :)

(Another thing on the TODO list is adding an optional priority score for each task, and sorting those on top of the list in all tree views.)


I hope you consider global prioritization of leaf nodes, either entered individually or calculated from weights of ancestor nodes.

One big deficiency of most todo apps is lack of support for making routes through the leaf nodes. I see that you can already do this with Grit via pointers and numeric task prefixes for sorting. But that brings us back to the bad old BASIC style line numbering problems.


With weights, you can have the user enter individual weight edges between root and task node, which would simplify the design, no?


Wow a very cool idea. The idea of many root nodes for different views seems interesting. Unfortunatly it does not build on my pc, it seems to import an absolute path in the go build command of the Makefile, which it can not do. (cannot import absolute path)

Since I never really worked with go, I don't know where to start here.


Thanks! Please open an issue on github if have an account there. System information would be particularly helpful.


I've seen similar task management that syncs to CalDav:

https://f-droid.org/en/packages/org.dmfs.tasks/

Is this something you're thinking about adding?


I’m going to play with this as well since I’m learning about the whole tasks/notes space.

Do you have plans to support any form of sync? Like CalDAV or some API on top of which CalDAV or another sync method can be implemented?


Omg! This is an exciting idea. I want to build a small react version of this. Tree based tasks list are a thing I've always wanted to build.


I think I’ve built something similar in React. It looks like a nested list but each item can have multiple parents. It syncs to GitHub and is public, I use it to share my recipes.

https://verynested.cadell.dev/ https://cooking.cadell.dev/


Not a CUI but Seatable has been a tremendous help to keep my to-do in a easy to use web interface that supports mobile pretty well.

You can also self host it.


If you add confidence interval estimates to each task and a way of inputting the amount of time you can allocate to grit-managed tasks, you could calculate estimated task completion dates: https://www.liquidplanner.com/support/articles/statistically...


This looks pretty interesting! How is the data stored? Would it be difficult to sync among different machines?


Just SQLite - two tables, one for the nodes, one for edges + some fancy constraints and queries. I was tempted to make a custom binary format, but that's a big task, and it seems to work fine as it is.

As for the syncing, that would be really nice, but I haven't come up with an elegant way to do it yet. Suggestions welcome, if anyone has ideas!


git. The right storage backend is either git, or a git-like Merkle tree. This is small data. Individual files for objects are fine. Compacting is better, but not critical.

You can write git in a weekend or two: https://wyag.thb.lt/

sqlite is the wrong tool for the job, beyond an initial prototype. git and hg figured this stuff out decades ago.

Good job, by the way. This seems like the sort of thing which, if:

* it did store data in git and sync; and

* had a nice Python API

would change how I work.

The Python API, I could probably even handle myself. This is small data, and calls to shell commands are both more than adequate, and easy to script in Python.


You aren't technically wrong, I guess, but Fossil would disagree that SQLite is somehow wrong for this use-case.

Fossil does seems to have issues when the VCS grows into many many gigabytes of data, like the entire OpenBSD source tree didn't work out very well in Fossil, but the chances of a personal task manager ever growing that size is slim to none I would imagine.


I guess I'd be okay with a Merkle tree stored in SQLite, although looking over the Fossil documentation, it seems like the developers didn't get git, and what made the git data structure so clever.

I see pieces like this in the Fossil docs:

"Fossil stores its objects in a SQLite database file which provides ACID transactions" -- https://fossil-scm.org/home/doc/trunk/www/fossil-v-git.wiki

The whole point of git is that your only operations on the underlying data structure are:

1. writing an object under its hash

2. incrementing a pointer to the head of a branch, a git tag, or similar, to show which version is current

You can do (1) on an eventually consistent (or even never-really-consistent) backing store, without any sorts of strong guarantees of integrity, and the git data structure continue to guarantee integrity. If (2) goes out-of-sync, you're left in a state very similar to what happens if I'm working on my laptop, and you're working on yours. We need a merge.

With DVCS, the whole point is to make ACID irrelevant.

I hadn't heard of Fossil before, but reading over the docs, I see a lot of red flags like that.

If grit were backed bit literal git, I'll mention, you get a ton of stuff for free, mostly with regards to syncing and finishing tasks on distributed devices (e.g. my cell, my laptop, etc.)


Git and Fossil started about the same time, and initially released within a year of each other.

For the record, the people that created SQLite also created Fossil. The SQLite software(and website) was Fossil's initial use-case.

Fossil offers WAY more than what Git does, Fossil includes ticketing, forum, chat, wiki, etc. It's more on par with Gitlab/Github/etc, than it is 'git' alone.

Fossil syncs, etc, just like Git.

I think they serve different use-cases. git is nothing but the data structure(s), it's very very hard to use git, if you don't understand how the data is stored, as the UI is a very thin wrapper around it, which causes all sorts of issues for people that just want to get work done. That said, it makes Git very flexible, which is great.

Git was built for the Linux kernel way of doing things, and got co-opted into the PR model that Github pushed. I'm not saying these are wrong ways to think about the problem, but they are not the only way. Fossil is a different way.

Around ACID vs Git's data structure, the whole point is your data needs to kept safe, who cares how it's done.

I'm not trying to convert you to Fossil, but I think it's important to recognize git isn't perfect, or even perfect for it's use-case. But it clearly won the mindshare of developers because we just blindly followed Linus.

I'm of the opinion that for most projects, Mercurial, Subversion or Fossil would have been the better/easier solution for most people and while arguably not as flexible, the UI is at least 50% better and easier to understand.


If you want to keep your data safe, it matters how it's done. See MongoDB for the story of a system with a friendly UI and a train wreck back-end.

git didn't win mindshare of developers because people blindly followed Linus, anymore than relational SQL databases weren't inched out by OODBs, document databases, or all sorts of other technologies because of dumb developer entrenched mindset. git (like SQL) won because it has very, very solid theoretical underpinnings which make it work incredibly well across a surprisingly broad set of use cases and handle data robustly.

Subversion is good for virtually no one. It's like using Excel for a database. It's complex, but doesn't get the job done.

Fossil, on a cursory look, looks like nineties mysql, when it was easy to use, but didn't really work, and was kind of a cargo-cult implementation of a proper database. I will admit I could be wrong (perhaps, just lousy docs).

hg, I agree, is better than git. git is a beautiful backend with a horrible front-end. hg has an equally beautiful backend, with a clean front-end and decent libraries. I wish hg had won. It didn't.

Oh well. At the end of the day, though, for this use-case, back-end matters far more than front-end. Competent developers can and do learn to use git, and are equally productive as in hg once they get over the learning cliff.

An upside is you learn a lot by learning git (or hg) internals. If OP knew git, they would have made a better grit. It's something every developer should do. Once you're past that, the front-end, while far from clean, gets the job done.

svn doesn't get the job done.


You seem awfully confident of yourself, but I'd disagree with many of those perspectives. Just because you sound confident doesn't mean you are correct.

There is a reason there are 500,000 git tutorials that start with the basics of how git works, and still practically nobody understands git. Despite knowing the underpinnings of how it works practically required to be useful in git.

I agree the implementation matters from a data safety perspective, I mean Jepsen made a name for himself proving how terrible all the "distributed" databases suck(because it's a very hard problem to solve). But as a user, you don't usually have to care... unless it's git.

FreeBSD successfully used SVN for a long time without any major issues, as one example.


Very few git tutorials explain how git works. That's the underlying problem. Using git correctly requires knowing how it works. You solve that problem by having a reasonable userspace, like hg, or by having a proper course in college. Much like you learn databases, compilers, and operating systems, you should learn about hash trees and similar data structures.

I feel like the statement "FreeBSD successfully used SVN for a long time without any major issues" is a lot like saying "I wrote books on a typewriter without any major issues." Or "Why do I need pointers/references/data structures? I wrote my code in QuickBASIC without any major issues." Or "DOS doesn't have memory protection or multitasking, and I never had any major issues" or "I wrote my system without documentation or test infrastructure, and it's never been a problem."

At the time you switch to correctly using a DVCS, your productivity skyrockets.

If you're using SVN, you DO have a problem. You might not know you have a problem, but you do. If you're using git like svn, you also have a problem.

I agree with you that many programmers have a problem, though. Just not about the root cause or the solution.

Maybe the right solution is to write a Python implementation of git with a sane user-space. The original git was written in a couple weeks, and I don't think it'd be more than a few months of work to have feature parity.


Since you are using SQLite you can look at how fossil does syncing of their table(s). Since Fossil is just a sqlite DB.


Some sort of UUID for task identifiers so that you can beam them around without collisions.


Seems like it uses sqlite. Presumably it's trivial to sync using whatever file sync tool you want (Dropbox, or whatever) as long as you're fine without concurrent editing. For that you'd need application support or a more amenable data structure.

https://github.com/climech/grit/blob/master/db/db.go


cool. Is there a way to convert a sub-task to a sub-sub-task? Where does it keep the local sqlite database file?


It's likely to be in

  .config/grit/graph.db
Here's how I found mine, thanks to help in a different thread

  root@Flipper:/# find . -name graph.db
  ./home/mike/.config/grit/graph.db


Looks and works fantastically. Great job!


I use gnome edit markdown.

I observed task lists are just for memory references.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: