--- /dev/null
+#!/bin/sh
+set -eu
+
+. ${0%/*}/tg-datastore.inc
+
+info() { printf "I: $@\n" >&2; }
+
+case "$1" in
+  add)
+    # tg-datastore add var=val var2=val2 ...
+    # only add to HEAD
+    shift
+    info "returns non-zero if there is already a datastore on HEAD."
+    info "adding the following data to the datastore of HEAD:"
+    for pair in "$@"; do
+      info "  ${pair%%=*}: ${pair#*=}\n"
+      printf "${pair%%=*}: ${pair#*=}\n"
+    done | tg_ds_add_data || die "E: HEAD already has a datastore"
+    ;;
+  remove)
+    # removes from HEAD
+    info "always returns zero, even if there was nothing to remove."
+    tg_ds_remove_data
+    ;;
+  list)
+    # $2 is the commit
+    info "returns non-zero if no datastore found at given commit."
+    info "prints contents of datastore otherwise."
+    tg_ds_list_data "${2:-HEAD}"
+    ;;
+  get)
+    # get parameter $2 from $3 (default HEAD)
+    info "prints the value of the parameter stored in the given commit."
+    info "prints nothing if the commit has a datastore but without the parameter."
+    info "returns non-zero if there is no datastore."
+    tg_ds_get_value "$2" ${3:-HEAD}
+    ;;
+  find)
+    # search for parameter $2 by backtracking from $3 (default HEAD)
+    info "prints the value of the parameter, or empty if parameter is not found."
+    info "returns non-zero if no datastore was found."
+    tg_ds_find_value "$2" ${3:-HEAD}
+    ;;
+  *)
+    echo "Usage: ${0##*/} [ add var=val... | remove | list | get var [commit] | find var [commit] ]"
+    ;;
+esac