17

I frequently fall into a sort of working anti-pattern involving “rabbit holes.”¹

Here’s the form it takes (with a concrete e.g. in parentheses):

  1. Start working on something (the “real task”)
  2. Discover a misconfiguration related to the task (the Emacs mode for working with the files involved in the “real task” isn’t installed)
  3. Start fixing the misconfiguration, but run into an issue (there’s a dependency for that Emacs mode that doesn’t seem to have been ported to my OS)
  4. Begin dealing with the issue (port the dependency to my OS)
  5. Run into a problem with the issue (the dependency uses a system call that’s ambiguous on the new OS)
  6. Research the problem (hand-trace the dependency, look at manuals for the old and new OS, figure out how to fix it)
  7. Fix the problem (fork and commit my patch)
  8. Share my fix with the community (create a pull request)
  9. Try to remember why, exactly, I just spent an hour researching an arcane OS issue that has nothing to do with the “real task”
  10. Give up trying to remember, and return to #1 (the “real task”)
  11. Discover #2 again (I need a new Emacs module installed)
  12. Discover #3 again
  13. Continue until I forget one of the remaining tasks completely, or the workday ends (which will guarantee I’ll forget where I was by tomorrow).

I’d very much like an always available “what I’m working on now” stack — that way, when I get into this pattern, at step #6, I’ll have the following in a buffer, where the bottom item is always the one I’m working on now:

- Real task
  - Install foo-mode
    - Install libfoo dependency
      - Port libfoo to MyOS
        - Figure out what’s wrong with funcFoo

Then, once I complete the “figuring out” task—here, I’ve gone ahead and added a couple tasks (testing and submitting a patch) I know I’ll have to handle after I finish the one I’m on (fixing the code):

- Real task
  - Install foo-mode
    - Install libfoo dependency
      - Port libfoo to MyOS
        - Submit PR to libfoo maintainers
        - Test funcFoo
        - Fix funcFoo

Then when I’ve fixed funcFoo, I “pop” the stack to:

- Real task
  - Install foo-mode
    - Install libfoo dependency
      - Port libfoo to MyOS
        - Submit PR to libfoo maintainers
        - Test funcFoo

and I know I need to test it. Once I’ve tested it, I “pop” again and know I need to submit a pull request.

Once that’s done, I “pop” again, and my new “right now task” is Port libfoo to MyOS. Let’s say I’m lucky and funcFoo was the only blocker to porting. Then that’s already done, so I “pop” again to Install libfoo dependency.

I install the dependency, which gets me back to:

- Real task
  - Install foo-mode

I install foo-mode but then when I run M-x foo-mode RET, it doesn’t work right:

- Real task
  - Configure foo-mode

Some more items probably get pushed and popped as I look into various options and configure them, but eventually, I’ve configured my new mode, popped that off the stack, and have:

- Real task

By tracking why I keep “rabbit-holing”, maybe I can avoid the cautionary tale:

xkcd: “Cautionary” xkcd

So: is there an straightforward way to get something like what I’ve described from Emacs—most likely, with Org?

It’s a little like capture, it’s a little like agenda, it’s a little like clocking, and it’s a lot like nested outlines.² But, if any one of those is satisfactory for this purpose, I don’t know how to configure it to be so—the defaults aren’t this.

Ideally, I want the always-on availability of capture with the ability to quickly pop up and dismiss an “objective HUD” window, with the top of the stack (what I should be doing right now or the blocker to doing that) visible (the bottom of the task list in the format I used above).

The quick-and-dirty way would be to just create a single global org document (maybe now.org), put a plain nested list into it, create an interactive function that visits the now.org buffer in a small window, and bind that interactive to a global key—then call it done.

This being lightweight, ubiquitously available, and as near to frictionless as possible are the most important things. I can “manage projects” just fine, with Org or other tools, when I know ahead of time the tasks required for completion. What gets me is those times when a “this will just take a minute” diversion³ turns into something much longer, and begins to spawn mini-subprojects of its own.

So, is there a better way than that quick-and-dirty plain outline option?

It would be nice to have an “add yet another item right below (in the stack) the current one to remember to do later” command reading from the minibuffer (e.g. for reminding me to make sure I’m tracking the right branch before I try to create a pull request or other such nonsense I want to remind my future self of), a way to context-switch so that the entire rabbit hole is saved for later while I work on something else (during which, I can undoubtedly fall into a brand new rabbit hole so I need to save that too), etc.

Saving but hiding done items for later consideration rather than killing them would be nice, too, but remembering to type [SPACE] or some keychord so I can just use checkbox filtering is more friction. (Property tags with speed keys to quickly add :done, and a sparse tree view filtering them out, perhaps?)

It’s possible Org isn’t even the right solution here. I’m open to trying something else. I don’t mind hacking up my own solution, and I know how I could (the quick-and-dirty way, anyway)—I just don’t want to needlessly reinvent a wheel.


¹ Here I define “rabbit hole” as: a series of one or more unexpected subtasks, formulated and commenced in the course of doing another (planned) task, that take longer (often much longer) to complete than originally expected. This definition differs from the colloquial one in two important ways: a rabbit hole in this sense may involve subtasks absolutely necessary to complete the larger task; and it may take an amount of time that, while differing greatly from the pre-task time estimate, seems perfectly justified and reasonable—in retrospect. In order to emphasize that the rabbit hole was not optional or from a lack of discipline, some engineers call this “dependency Hell” instead.

² Actually, it’s exactly like nested outlining—except it goes inside-to-out, bottom-to-top. Chronologically, flipping it all around, it’s:

        - Fix funcFoo
        - Test funcFoo
        - Submit PR to libfoo maintainers
      - Port libfoo to MyOS
    - Install libfoo dependency
  - Install foo-mode
- Real task

but, unfortunately, neither outline-mode nor Org will let you do this trivially.

³ I’ve used GTD apps that had task chaining (a.k.a. “dependencies” or “gating items” or “blockers”) for this before, and it works in theory, but it adds enough friction that I won’t use it to track “doing something really quick” right now. David Allen himself said that you shouldn’t bother capturing tasks you can take care of in less than two minutes; just do them. The problem is when the little task turns out to be nothing close to two minutes once you’re doing it, or spawns a succession of little subtasks such that solving the diversion takes the mind away from solving the real task.

Trey
  • 865
  • 5
  • 20
  • 1
    This doesn't get you all the way there, but you could consider org-capturing a new task and clocking in to it when you need to, then when you are done, clocking out or marking done, and use `C-u M-x org-clock-goto` or similar to choose recently clocked items to go back to. Not quite a stack but might help in your situation. You probably would want to customize your capture templates to make this quick and painless. – Willy Lee Jun 21 '19 at 00:04
  • 1
    Have you tried dependencies in org mode? I did read your footnote about chaining tasks and I agree that it will add some friction, but I don't see a better way of doing it. The only other suggestion I have is that this is a topic for the org-mode mailing list, rather than for Emacs SE: the latter does not allow the kind of open-ended discussion that something like this will entail (unless somebody comes up with a fully-formed solution here, which sounds unlikely). – NickD Jun 21 '19 at 13:07
  • @NickD honestly the reason I didn’t do that is that I’ve never used Emacs for email and I imagine an HTML email wouldn’t be well-received, and I didn’t feel an ASCII email was good enough to explain my thinking. I could rewrite this in Org and email that bare, I suppose, would that show up right for most readers? Thanks! – Trey Jun 21 '19 at 16:04
  • 1
    Haven't read your entire question yet (it's long!) but this sounds a lot like the [Sidebrain](http://sidebrain.sourceforge.net/) extension. I've been meaning to try it sometime because a stack seems like the right model for the "action path" of your working activities "in the field" -- i.e. when you're actually engaged in working on something rather than at the planning stage. Even if this extension isn't as full-featured as something like Org (which I haven't used a lot), my hope is that it will be just lightweight enough and targeted enough to do this "action path" modeling well - which soun – mindthief Dec 18 '20 at 08:48
  • @mindthief I will give Sidebrain a try—it hasn’t been udpated in 14 years it looks like, there are no Emacs install packages for it as far as I can see, and it doesn’t work on my up-to-date Emacs version (I haven’t tried to port it so far, though). The docs certainly make it sound promising, though! – Trey Jan 26 '21 at 19:09
  • Looks like my answer was converted to a comment by a mod and some of the text was truncated. To finish the thought, here's the rest of the text from the answer, "... - which sounds like exactly what you're talking about." – mindthief Jan 28 '21 at 04:13
  • And, I see, too bad it isn't working on the latest Emacs. If you decide to try porting it, good luck! And I would be eager to try it someday :) I wonder if it's just repointing deprecated libs like `cl` -> `cl-lib`, or if there's more to it than that... – mindthief Jan 28 '21 at 04:17

1 Answers1

1

I tried my hand at implementing what you described. The resulting code is too long to post here but here is my take on the problem: https://github.com/zkry/rabbit-hole.el

Zac Romero
  • 175
  • 5