Hey - a simple command line time tracker, written in Raku and backed by SQLite.
Hey is a command line tool that tracks your time spent on various projects that may have happened along the way.
Quickie Version
Usage:
hey start [<start_args> ...] -- Start a new timer
hey stop [<stop_args> ...] -- stop an existing timer
hey log <number> <duration> -- see a log of recent timers
hey log-interrupts <number> <duration> -- see a log of recent interruptions
hey running -- lets you know if there are any timers running & what they are for
hey <name> [<start_args> ...] -- Record an interruption
hey kill timer <id> -- Remove an unwanted timer.
hey nevermind -- Cancel & delete the most recent running timer
hey kill <name> -- Remove an unwanted person / thing from interruptions
[<start_args> ...] optional time adjustment, project(s), & optional tags
[<stop_args> ...] optional id, and optional time adjustments (e.g. 4 minutes ago)
<number> number of duration units
<duration> duration string. E.g. minutes, hours, days, etc.
<name> name of person / thing that interrupted you
<id> the id of the timer to delete.
And now for some useful details to fill in the gaps...
Starting and stopping timers is pretty straightforward. At a bare minimum you just tell it to start and give it a project name: hey start @my_project
and stop it when you're done with hey stop
- Project names are prefixed with
@
. - Tag names are prefixed with
+
. Neither can contain spaces. - Every timer event must be associated with at least one project.
- Tags are optional.
- Order of tags and projects doesn't matter. They can be mixed too.
# simple usage
hey start @project +tag1 +tag2
hey stop
The start and stop of a timer can be backdated using relative or absolute times.
Time modifiers must come immediately after start/stop.
Absolute times are specified with 12 hour or 24 hour time formats. You can also just specify the hour with no minutes. The expected format is "at" followed by the time.
hey start at 4 @project +tag
hey start at 4:30 @project +tag
hey start at 16:30 @project
The system will always assume you mean the most recent corresponding time. So, if for example it's 6PM and you say at 4
it's going to assume you mean 2 hours ago. If, however it's 3PM and you say at 4
it's going to assume you meant 4 AM
. This will carry-over to the previous day if you leave a timer running overnight. And yes, it should handle year boundaries correctly and not accidentally mark something as being done in the future.
Occasionally you'll need to specify stop a timer you left running the prior day, or maybe add a record for some time you forgot to track on a past day. In that case you can also specify the date. Dates come before times and are in MM/DD format. When you do this you will need to specify the full time in 24hr format. There's no good way for Hey to know if 4:00
means 4 PM or 4 AM.
hey start at 12/16 11:50 @project
Relative times come immediately after start/stop and follow the syntax of <number> <time unit> ago
You must include "ago" as it provides a clue to the code as to what you're intending.
# backdating
hey start 4 minutes ago @project +tag1
hey start 3 days ago @project
You can use any of the following duration words.
- second
- seconds
- minute
- minutes
- hour
- hours
- day
- days
- week
- weeks
- month
- months
- year
- years
Hey supports multiple simultaneous timers. There's nothing fancy to it. The only special note is that stop
will stop the most recent one unless you provide an id.
To stop a specific timer you just give it the integer id shown in the log.
hey stop 12
Sometimes, things don't go as planned. For example, I started a timer to go walk the dogs, left my computer, and unexpectedly ended up eating lunch. That timer was no good.
To kill an unwanted timer say hey kill timer <id>
hey kill timer 4
A timer's id is shown when you create a new timer, or when you view the log.
Stop the most recently created running timer without knowing its ID.
hey nevermind
Why? Because I keep starting a timer and then finding myself being retasked. For example:
me: "I'm going to start cooking..."
hey start @cooking
wifey: "Maybe you should walk the dogs first so that they don't annoy you with constantly wanting to go in and out." me: 🤔hey nevermind
hey start @dogs +walking
hey log <number> <duration>
This uses the same duration words as in backdating.
hey log 4 days
hey log 24 hours
Note: when it comes to durations of a day or larger it uses cultural meaning not literal meaning.
So, for example:
hey log 1 day
is going to get you today's log.hey log 1 week
is going to get you this week's log. Monday is treated as the start of the week, so if it's Monday you'll only see one day worth of records.hey log 1 month
is going to get you this month's log.hey log 1 year
is going to get you this year's log.
Day's an larger all count from midnight. All times should be local.
If you want a specific and literal amount of time use seconds, minutes, or hours.
So, for example, hey log 1 day
doesn't get you the past 24 hours worth of logs. It gets you everything from midnight yesterday. If you really want 24 hours, just say hey log 24 hours
.
Summarizing timers follows the same pattern as generating a log of them. Asking for a summary of timers will produce a table displaying the amount of time spent on each project during that duration.
hey summarize timers <amount of time> <duration>
So, for example, hey summarize timers 2 days
might output something like this.
Recording an interruption is the same as recording a timer, except that you start with the name of the person / thing that interrupted you, and project is completely optional.
hey bob
hey bob at 9:15
hey bob at 10:30 +gossip
hey bob at 11:15 @project_x +questions
hey bob 20 minutes ago
hey bob 10 minutes ago @project_x +questions
This works the same as viewing your timer logs, but you say "log-interrupts" instead of "log"
hey log-interrupts <number> <duration>
You can add tags to a timer or interruption after it's been created, by running hey tag <id> <list of tags>
If you ran a marathon and wanted to tag it with your thoughts afterwards you might say hey tag 33 +hard +fulfilling
hey projects
will output a list of all the projects you've entered.
This is useful when you've forgotten what you called something, and
for integrations like shell autocomplete.
Hey is written in Raku, and uses the zef package manager for installation.
If you've already got Raku and zef
installed then just run:
zef install Hey
If you don't have Raku installed then...
My recommendation is to use Homebrew to install Rakudo Regardless of if you use Homebrew, or download from the main site, you'll want the Rakudo-Star package. This brings along a handful of other useful things, like our package manager: zef.
brew install rakudo-star
Now, go back and run the zef install Hey
command from above.
Sometimes you'll record an interruption, or some work, but forget to add a tag.
- Graph Interruptions over time, to find parts of the day where you're most likely to be able to focus, or need to hide.
- Graph Interruptions by people to find out who you need to talk to.
- Graph Interruptions by tag or projects to find out where you would best benefit from adding documentation.
It'd be nice to be able to configure things, such as when the start of the day is. Many of us work past midnight, and consider it part of the prior day's work. So, it'd be nice to have the logging use our preferred "start of day" time. Here's the GitHub issue for that feature.
I'm betting you might have ideas for configurations too. Like, maybe colors for specific data types in the report?
Pull Requests are very welcomed.
I'm using this daily now so there will be modifications and improvements over time. I'm especially interested in adding useful reporting and data extraction functionality.
Let's chat on Mastodon if you've got some ideas. Alternately, just file a new ticket on github.
Note: this app's version numbers follow strict Semantic Versioning.
The test suite uses bash_unit because testing an app where 90% of the behaviors are based upon side-effects of data that may, or may not, have been persisted in the DB is way easier to write System tests for than Unit tests. If you feel like writing some Raku unit tests with all the stubbing that that will require, I'll happily merge the PR.
Regardless of unit tests, if you do add / change functionality please include additional bash_unit tests with your PR.
The bash_unit tests can be run by changing into the bash_unit_tests
directory and running bash_unit hey_test.sh
Note that these will work on a local test database, so you don't have to worry about hurting your real time & interruption tracking data.
masukomi (A.K.A. Kay Rhodes)
- Web: masukomi.org
- Mastodon: @[email protected]
Copyright 2022 Kay Rhodes & distributed under the GNU Affero General Public License version 3.0 or later.