⚠️ This tool is in alpha stage. The most basic time tracking features recording, deletion, editing, search as well as syncing are implemented, but a lot of features (especially nice visual summaries) are missing.
annextimelog
- ⏱️ Git Annex-backed Time Tracking
This is a brainstorm for a Git Annex-backed time tracker.
The idea originated across some of my Mastodon threads:
The gist is that I was (and still am) unhappy with the existing time tracking solutions. I worked with hledger's timeclock and timewarrior each for quite some time and built my own workflow and scripts around them.
✅ Requirements
Over the years, the below features turned out to be my personal requirements for a time-tracking system (TL;DR: easy and intuitive recording, hassle-free syncing, data export for further analysis).
Here is a table comparing annextimelog with timewarrior and hledger timeclock:
✅ = feature available, 🟡 = partly available, ❌ = not available
feature | timewarrior | hledger timeclock | annextimelog |
---|
precise start and end times | ✅ | ✅ | ✅ as git-annex metadata |
tracking of overlapping/simultaneous periods | ❌ | 🟡 (separate files) | ✅ backend can do it |
nice, colourful, graphical summary | ✅ | 🟡 | ✅ with Python rich , more planned |
plain text data storage | ✅ | ✅ | 🟡 buried in git-annex branch |
git-friendly, merge conflict free data format | 🟡¹ | 🟡¹ | ✅ git-annex’ own merge strategy |
arbitrary tags attachable to tracked periods | ✅ | 🟡 hledger tags² | ✅ just git-annex metadata |
arbitrary notes attachable to tracked periods | 🟡³ | 🟡 hledger tags² | ✅ just git-annex metadata |
tags can have values | ❌ | ✅ hledger tags² | ✅ just git-annex metadata |
files attach-/linkable to tracked periods | ❌ | 🟡 path as file: tag | 🟡 annexed files, linking is planned |
cli to start, stop, edit, etc. tracked periods | ✅⁴ | ❌ own scripts needed | 🟡 recording and editing |
plugin system | 🟡⁵ | 🟡⁶ (hledger’s own) | ❌ git-style plugin system planned |
data export to common format | ✅ (JSON) | ✅ (CSV, JSON) | ✅ as timeclock, JSON, cli commands |
syncing functionality built-in | ❌ | ❌ | ✅ git-annex’s purpose is syncing |
multi-user support | ❌ | ❌ | ✅ nothing in the way, just use tags |
¹last line is always modified, merge conflicts can arise when working from different machines
²hledger tags have limitations, e.g. no spaces, colons, commas, etc.
³timewarrior annotations can't contain newlines for example. I wrote an extension to edit your annotation in your $EDITOR
and optionally GPG-encrypt it, which lets you add newlines. Quite an inconvenience.
⁴timewarrior’s cli has some nasty inconveniences (e.g. no shortcut for ‘yesterday’, must painfully type out the full date, no intelligence to operate only on yesterday, gets confused and errors out in certain combinations of start/end times, etc…)
⁵timewarrior extensions (here mine) are just fed the data via STDIN, not other command-line arguments. Not as useful as the git-style plugin system.
⁶for the analysis part, hledger
plugins can be used. But as there is no actual cli to manage the data, there’s no plugin system for that.
🛠️ Implementation
To learn more about how annextimelog
works under the hood with git-annex as backend, have a look at doc/implementation.
📦 Installation
You can run this tool if you have nix installed:
nix shell gitlab:nobodyinperson/annextimelog
nix profile install gitlab:nobodyinperson/annextimelog
On Arch Linux you can install from the AUR with your favorite helper, or directly with pacman from this user repository.
paru -S annextimelog
Otherwise, you can install it like any other Python package, e.g. with pip
or better pipx
:
pipx install annextimelog
pipx install git+https://gitlab.com/nobodyinperson/annextimelog
Note that in this case you will need to install git-annex manually.
Any of the above makes the annextimelog
(or atl
) command available.
❓ Usage
usage: annextimelog [-h] [--no-config] [-c key=value] [--repo REPO] [-n]
[--force] [-v] [-q] [-O {rich,console,json,timeclock,cli}]
[--version | --version-only]
{test,git,config,sync,sy,track,tr,delete,del,rm,remove,edit,ed,mod,change,upd,update,stop,cont,summary,su,ls,list,find,search}
...
⏱️ Time tracker based on Git Annex
options:
-h, --help show this help message and exit
--no-config Ignore config from git
-c key=value Set a temporary config 'key=value' or just 'key' (implicit '=true'). If not present, 'annextimelog.' will be prepended to the key. The following keys are available: emojis, color, commit, confirm, fast, weekstartssunday, longlist, listall, matchconditions, outputformat, dryrun, slowdown.
--force Just do it. Ignore potential data loss.
--version show version information and exit
--version-only show only version and exit
Data:
--repo REPO Backend repository to use. Defaults to $ANNEXTIMELOGREPO, $ANNEXTIMELOG_REPO or $XDG_DATA_HOME/annextimelog (currently: /tmp/annextimelog)
-n, --dry-run don't actually store, modify or delete events in the repo. Useful for testing what exactly commands would do.Note that the automatic repo creation is still performed.
Output:
Options changing output behaviour
-v, --verbose verbose output. More -v ⮕ more output
-q, --quiet less output. More -q ⮕ less output
-O {rich,console,json,timeclock,cli}, --output-format {rich,console,json,timeclock,cli}
Select output format. Defaults to 'console'.
Subcommands:
{test,git,config,sync,sy,track,tr,delete,del,rm,remove,edit,ed,mod,change,upd,update,stop,cont,summary,su,ls,list,find,search}
test run test suite
git Access the underlying git repository
config Convenience wrapper around 'atl git config [annextimelog.]key [value], e.g. 'atl config emojis false' will set the annextimelog.emojis config to false.
sync (sy) sync data
track (tr) record a time period
delete (del, rm, remove)
delete an event
edit (ed, mod, change, upd, update)
modify an event
stop set end of seleted currently open-end events to now
cont continue a closed event now or at a given time
summary (su, ls, list, find, search)
show a summary of tracked periods
🛠️ Usage
Logging events:
> atl tr work @office
> atl stop work
> atl cont work
> atl tr work for 4h @home with client=smallcorp on project=topsecret
> atl tr 10 - 11 @doctor
> atl tr y22:00 - 30min ago sleep @home quality=meh
> atl -vvv tr ...
Note: Common prepositions like 'with', 'about', etc. are ignored. See the full list with
> python -c 'from annextimelog.token import Noop;print(Noop.FILLERWORDS)'
Listing events:
> atl
> atl ls
> atl ls .open
> atl ls .openend
> atl ls week
> atl ls yesterday
> atl ls until 2days ago
> atl -O json ls -a
> atl -O timeclock ls -a | hledger -f timeclock:- bal --daily
Editing events:
> atl stop
> atl mod .openend set end=now
> atl mod id=jajekwka project=secret
> atl mod id=LXKGrBGA end=now
> atl mod id=LXKGrBGA until 18
> atl mod @home where note=text
Continuing events:
> atl cont work @office
> atl cont work @office until 15
> atl cont work set project=A
Removing events:
> atl rm id=O3YzvZ4m
> atl rm @work sleep
Syncing:
> atl git remote add git@gitlab.com:you/yourrepo
> atl sync
Configuration
> atl -c key=value ...
> atl config key value
> atl config color ...
> atl config commit ...
> atl config confirm ...
> atl config dryrun ...
> atl config emojis ...
> atl config fast ...
> atl config listall ...
> atl config longlist ...
> atl config matchconditions ...
> atl config outputformat ...
> atl config slowdown ...
> atl config weekstartssunday ...
🛠️ Development
This project uses poetry, so you can run the following in this repository to get into a development environment:
poetry install
poetry shell
Other:
just watch-mypy
just watch-test
just test-tokens work @home note=bla myfield+=one,two,three 2h ago until now
just test-with-python-version 3.10