Fork me on Github

klog

klog is a plain-text file format and a command line tool for time tracking. It is free and open-source software distributed under the MIT License.

Find the source code on Github: github.com/jotaen/klog

Get klog

  1. Download the latest version and unzip
  2. Right-click on the binary and select “Open” (due to Gatekeeper)
  3. Copy to path, e.g. mv klog /usr/local/bin/klog (might require sudo)
  1. Download the latest version and unzip
  2. Copy to path, e.g. mv klog /usr/local/bin/klog (might require sudo)
  1. Download the latest version and unzip
  2. Copy to path, e.g. to C:\Windows\System32 (might require admin privileges)

As an alternative you can also use the Linux binary on the Windows Subsystem for Linux.

In order to not miss any updates you can either subscribe to the release notifications on Github (at the top right: “Watch” → “Custom” → “Releases”), or you occasionally check by running klog version.

Introduction

The idea behind klog is to store data in plain-text files in a simple and human-readable format. The notation is similar to how you would write down the information into a physical notebook using pen and paper. Manipulating your data is as easy as opening the file in a text editor and making changes to the copy. By using the klog command line tool you can search, evaluate and manipulate your data from the terminal.

Screen recording of the demo described below

Let’s say you started a new job and want to use klog for tracking work times. For that, you create a file worktimes.klg with the following content:

2018-03-24
First day at my new job
8:30 - 17:00
-45m Lunch break

This means: at the 24th of March 2018 you came to the office at 8:30 in the morning and went home at 17:00 in the afternoon. Somewhere throughout the day there was a 45-minute lunch break. That effectively results in a total time of 7 hours and 45 minutes for that day.

As you see, klog files almost read like a lightweight journal. It supports various notations for tracking times, which are convenient to write and intuitive to understand. You can capture short summaries about your activities along the time data, which may help you later on to make sense of what you did back in the day. And by using tags you are able to run fine-granular evaluations on your data.

With the klog command line tool you can interact with your files. For instance, you could evaluate the resulting total time with the following command:

klog total worktimes.klg
Total: 7h45m
(In 1 record)

Or you add an extra 30 minutes:

klog track --today '30m' worktimes.klg

This appends a new entry to the respective record in the file.

File Format

Version 1.0 (Specification)

klog data is stored in .klg files in a plain-text format. The data is grouped into blocks (called “records”), which are separated by one blank line from each other. Each record is a standalone and self-contained data structure that holds time-tracking information for a specific calendar date.

2018-03-24
First day at my new job
8:30 - 17:00
-45m Lunch break

2018-03-25
8h15m

2018-03-26
More onboarding. Also started
to work on my first small project!
8:30 - 11:15
11:15 - 12:20 Meeting with Sarah
4h

Records

Each record is made up of three parts:

  1. The date, formatted either YYYY-MM-DD or YYYY/MM/DD.
  2. Optionally, one or more lines of summary text.
  3. Time entries (see below).

The computed total time of a record is the sum of all its entries.

Time entries

Entries are the actual time values that you track. Each entry represents an amount of time that you spent on something. Entries appear one per line and are indented by one level. They start with the time value and can optionally be followed by a summary text.

2019-07-22
1h
8:00 - 9:00

Both entries in this example are worth 1 hour each, resulting in a total time of 2 hours for that day.

There are three types of entries:

The indentation is either 1 tab or 2–4 spaces. The order of entries can be arbitrary and has no influence on the result. There can be any number of entries per record.

Summaries

The purpose of summaries is to capture arbitrary information alongside the data for future reference.

2020-02-18
Woke up this morning with the plan
to make the world a better place
10h Watched movies

Summaries are optional and can appear:

Tagging / categorising

Summaries can contain #hashtags that allow for more fine-granular filtering of the data.

2019-07-22
Did some #sports
2h #badminton session with Max
18:00 - 19:00 Went out for a #run

If a tag appears in the overall record summary, then all entries will match when filtering for that tag. If a tag appears in an entry summary, only the respective entry will match.

In this example, the total time for the tag #sports would be 3h, and the total time for #run would be 1h.

Tip: The klog CLI supports wildcard searching at the end of tags, so e.g. providing the filter flag --tag=sports... would match the tag #sports_run. That way you can structure your tags in a hierarchical way.

Open-ended time ranges

In case you just begin an activity (without knowing when it will end) you can already log it in your file as an open-ended time range.

2019-07-26
Started to read my new book
16:30 - ?

Open-ended time ranges are denoted by replacing the end time with a question mark, otherwise they work the same as normal entries. Note, that there can only be one open-ended range per record, and it doesn’t count towards the total time as long as it’s open.

Should-total

For some use-cases it’s helpful to specify a certain overall time goal that you want to achieve. This is called “should-total” in klog and appears after the date of the record. It is a duration value, followed by an exclamation mark and wrapped in parentheses. For example, let’s say you are supposed to work 7½ hours per day:

2019-07-26 (7h30m!)
8:00 - 16:00 Work
-45m Lunch break

When evaluating the record you can calculate the difference between should-total and actual total time, in order to see whether you have reached your designated goal. A should-total value always applies to the entire record with all its entries.

Day shifting

Sometimes you start an activity in the evening and end it after midnight, just so that start and end time don’t belong to the same calendar date. For this case it is possible to “shift over” a time to the previous or to the next day by adding the < prefix, or the > suffix, respectively.

2019-07-26
<23:30 - 8:00 Worked a night shift
22:30 - 1:45> Watched some movies

When filtering records, keep in mind that these entries are still associated with the date they are recorded under, so the total time for the above date 2019-07-26 is 11h45m. (If there are records for the adjacent days, their total time won’t be affected.)

Command line tool

v3.0

The command line tool allows you to display and search records in files, pretty print and evaluate them, and apply some basic manipulations. The following sections demonstrate the usage of the subcommands. (They are not a complete reference, though.) In order to learn about all flags and options please run klog with the --help flag (which is also available on the subcommands).

In case there are syntax errors in the input text, klog cannot process it and displays an error message instead, which hopefully helps you fix the problem. Also some commands emit warnings to draw your attention to potential logical issues in your data.

For the evaluation commands you can specify input in one of the following ways:

Tip: Most shells have native support for glob patterns, so in case you want to organise your records throughout multiple files (e.g. one file per month) you can process them all at once by passing the glob pattern *.klg.

Most of the subcommands provide filter options which allow you to select a specific date range, or to only consider certain tags. For example, if you want to evaluate all records in sport.klg since January 2018 that are tagged with #biking, you would do:

klog total --since=2018-01-01 --tag=biking sport.klg
Total: 116h21m
(In 37 records)

print

With the print subcommand you can pretty-print one or multiple files onto the terminal. Printing is a good way to double-check that the syntax in a file is all correct.

klog print worktimes.klg
 
2018-03-24
First day at my new job
8:30 - 17:00
-45m Lunch break

total

The total subcommand evaluates the total time of the records from one or more files.

klog total sport.klg
Total: 60h36m
(In 15 records)

Remember that open time ranges are not taken into account by default. You can factor them in by passing the --now flag.

In case you set should-totals for your records you can use the --diff option to calculate the difference between the should-total and the actual total:

klog total --diff sport.klg
Total: 16h45m
Should: 18h!
Diff: -1h15m
(In 6 records)

report

Prints a report of the records as a timeline (like in a calendar).

klog report 2020.klg
Total
2020 Jan Wed 28. 6h20m
Sun 30. 3h50m
Feb Tue 3. 7h
Fri 5. 6h15m
========
23h25m

The data can be aggregated by day, week, month, quarter or year, by using the --aggregate option. (The default is by day.)

Use with the --fill option to print a consecutive stream of all dates.

tags

Displays an overview of all available tags and a breakdown of the aggregated total times for each of them.

klog tags sports.klg
#running 13h
#biking 9h
#sports 21h

today

Evaluates the total time, where today and all other records are displayed separately. (In case there are no records today, it falls back to yesterday.)

klog today times.klg
Total
Today 5h7m
Other 162h19m
========
All 167h26m

By using the --follow flag you can keep the shell process open and see your data being updated live.

In case you have set should-total times, then --diff and --now will forecast the end-time at which your designated time goal will be reached.

klog today --diff --now times.klg
Total Should Diff End-Time
Today 5h7m 8h! -2h53m 18:00
Other 162h19m 160h! +2h19m
===========================
All 167h26m 168h! -34m 17:26

track

Add a new entry to a record:

klog track '1h30m' sports.klg

The entry will be added if there is already a record at that date. Otherwise a new record will be created and inserted into the file.

If you don’t specify a date then klog will look for a record at today’s date. Say, today was the 14th of February 2012, then the above example command would append a new entry so that the resulting record would look like this:

2012-02-14
8:15 - 9:45 Morning run
1h30m

You can not just track time values that way, but you can also add the summary text right away. (Effectively, the argument is just the entire entry line as it is supposed to appear in the record.)

klog track '8:00-16:00 Workday' work.klg

Note that you should wrap the value into single quotes in order for your shell to treat it as single argument and to avoid special characters to be interpreted. In case you want to track a negative duration please remember to escape the leading minus with two backslashes:

klog track '\\-30m Coffee break' work.klg

start

Starts a new open-ended time range:

klog start work.klg

The open-ended range will be added as a new entry if there is already a record at that date. Otherwise a new record will be created and inserted into the file. You can also specify a date explicitly through the --date flag.

By default the current time is used as start time. You can optionally specify it with the --time 5:00 flag. If you want, you can use the alias klog in.

stop

Stops an ongoing open-ended time range:

klog stop work.klg

It works in the same way as klog start does. If there is no open-ended range at the specified date it will look for on at the previous date and close that with a shifted time.

create

Creates a new record:

klog create reading.klg

By default the current day is used as date. You can also specify a date explicitly via the --date flag. The command assumes the records in the file to be in chronological order and inserts it at the right position. You can specify a should-total via the --should flag.

bookmarks

Bookmarks allow you to reference often-used files from anywhere via a short alias. That way you don’t have to specify the full path of a .klg file, or navigate to the directory where it’s stored. Bookmark names are identified by the @ prefix.

The following command defines a bookmark @work pointing to the file ~/work/2021-01.klg

klog bookmarks set ~/work/2021-01.klg @work

With that bookmark, you can now use @work as input argument for klog commands. It will be automatically resolved to the designated file, regardless of your current working directory.

klog total @work

Additionally, you can also specify one unnamed bookmark. This is useful in case you only use one .klg file anyway. (Internally, it’s identified by the special name @default.)

klog bookmarks set ~/work.klg
klog total

The following subcommands are available to manage your bookmarks:

klog bookmarks list
klog bookmarks set
klog bookmarks unset
klog bookmarks clear
Note: On Windows Powershell, the @ operator is reserved syntax. Therefore, when using Windows Powershell, you either have to escape bookmark names with a backtick (`@mybookmark) or wrap them in quotes ('@mybookmark').

edit

Open a .klg file in your favourite editor (based on the $EDITOR environment variable). This is especially helpful in conjunction with bookmarks.

klog edit ~/documents/times.klg
klog edit @times

json

Converts records into a JSON data structure that allows you to process the data by means of other tools or scripts programmatically.

klog json somefile.klg

Run with the --pretty flag in order to explore the output structure – it should be self-explanatory. (Also try it on a file with syntax errors, to see how the error structure looks.)

Remember that klog checks stdin for input as well, which might be handy when you invoke it as subprocess from another program.

widget (MacOS only)

On MacOS there is an experimental menu bar (systray) widget bundled into the command line tool. It displays an ongoing counter of the current day and the statistics of a file. As source file the default (unnamed) bookmark is used. You can launch the widget by running:

klog widget

Use the --detach option to run the widget standalone (detached from the shell process).

version

Displays which version of the command line tool you are on. This also checks online whether there is a new version available.

klog version

FAQ

Is it possible to use to-the-second precision, like 1h10m30s or 8:23:49?

No, this is not supported. The reason is that it would effectively prohibit mixing values with and without seconds, which leads to a lot of hassle. Keep in mind, klog is for tracking time of activities, it’s not a stopwatch.

Can I capture timezone information?

No. In case you are affected by a timezone change or a switch to daylight saving time you need to account for that yourself. Realistically, this doesn’t happen all too often anyway, so it’s a tradeoff for simplicity to omit the timezone information altogether.

Can there be multiple records for the same date in one file?

Yes, as many as you want.

Can a record be empty?

Yes. The only requirement for a record is that it contains a date. Apart from that, it can be empty.

Do records have to be sorted in a specific order?

No, the order is up to you.

How many entries can a record have?

As many as you want, including none and five thousand. You can also freely mix the different kinds of entries (durations, negative durations, time ranges). The only exception are open-ended ranges, of which there can only be one per record.

Are there any logical constraints when tracking times?

klog generally doesn’t impose too many restrictions. Examples of things that are allowed:

There might be valid reasons for such use cases, so klog deliberately is not stricter than necessary. What the command line tool does do, however, is to raise warnings about certain potential issues, for example when it detects an open-ended time range at a past date.

Are summaries mandatory?

No, you don’t have to write summaries. Summaries are an optional way to keep notes that help you keep track of what you did.

Can I organise records throughout multiple files?

Yes. klog is not opinionated about the way you structure your data across files and folders. It’s actually useful practice to have separate files, e.g. one for each month or for different kinds of activities. When you evaluate files using the CLI tool, you can always pass multiple file names, or you can make use of glob patterns (e.g. 2021-*.klg, which expands to 2021-01, 2021-02 etc.). This, along with tags, allows you to come up with a structure that meets your personal needs.

Can I customise or extend klog?

Not directly, but it’s possible to wrap klog in your own tools or utilities. Learn more about this in the section on Extensions.

Is there a formal specification of the file format?

Yes, you find it here.

Extensions

This is a collection of publicly available extensions. If you have built a utility for klog, please share it here so that it can be added to this list.

VSCode

Editor plugin for VSCode for syntax-highlighting and snippets.
See: github.com/vladdeSV/vscode-klog
(Maintained by @vladdeSV)

Write your own extension

In order to tailor klog to your own needs and workflows, you can extend or enhance its functionality in one of the following ways:

In case you need the klog logo for anything, see here.