<!DOCTYPE html>
<html lang="en-ca" data-theme="dark" prefix="og: https://ogp.me/ns#">
<head><meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="dark">
<title>harsh - a minimalist CLI habit tracker | Daryl Manning</title>
<meta name="description" content="Introducing harsh, a minimalist command line habit tracker to help you build or break habits (written in GoLang).">
<meta name="keywords" content="gtd, dev, oss, tools, go">
<meta name="author" content="Daryl Manning">

<meta name="robots" content="index, follow">
<link rel="canonical" href="https://daryl.wakatara.com/harsh-a-minimalist-cli-habit-tracker.md">


<meta property="og:type" content="article">
<meta property="og:url" content="https://daryl.wakatara.com/harsh-a-minimalist-cli-habit-tracker.md">
<meta property="og:title" content="harsh - a minimalist CLI habit tracker">
<meta property="og:description" content="Introducing harsh, a minimalist command line habit tracker to help you build or break habits (written in GoLang).">
<meta property="og:site_name" content="Daryl Manning">


<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="harsh - a minimalist CLI habit tracker">
<meta name="twitter:description" content="Introducing harsh, a minimalist command line habit tracker to help you build or break habits (written in GoLang).">


<meta property="article:published_time" content="2020-05-26T17:06:16&#43;08:00">
<meta property="article:modified_time" content="2026-04-14T17:07:11&#43;08:00">
<meta property="article:tag" content="gtd">
<meta property="article:tag" content="dev">
<meta property="article:tag" content="oss">
<meta property="article:tag" content="tools">
<meta property="article:tag" content="go">




<link rel="stylesheet" href="/scss/style.2eb2cb6587c6a81a06e277cf38cb7f7cdafbf109a47b77eb928b2edbca380726.css" integrity="sha256-LrLLZYfGqBoG4nfPOMt/fNr78Qmke3frkosu28o4ByY=">


<link rel="preload" href="/fonts/Geist-Variable.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/GeistMono-Variable.woff2" as="font" type="font/woff2" crossorigin>




</head>
<body class="page-2020-05-26-harsh-a-minimalist-cli-habit-tracker">
    <a href="#main-content" class="skip-link">Skip to main content</a>
<header class="navbar" role="banner">
    <div class="container">
        <div class="flex">
            <div>
                <a class="brand" href="/" aria-label="Daryl Manning Home">
                    <span class="brand-text">Daryl Manning</span>
                </a>
            </div>
            <nav class="flex nav-links" role="navigation" aria-label="Main navigation">
                <a href="/posts/">Blog</a>
                <a href="/projects/">Projects</a>
                <a href="/about/">About</a>
                <button class="search-toggle" type="button" aria-label="Search" title="Search (/)">
                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <circle cx="11" cy="11" r="8"/>
                        <path d="m21 21-4.3-4.3"/>
                    </svg>
                </button>
            </nav>
            <button id="mobile-menu-button" class="mobile-menu-button" aria-label="Open navigation menu" aria-expanded="false" aria-controls="mobile-menu-overlay">
                <svg class="menu-icon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <line x1="3" y1="6" x2="21" y2="6"></line>
                    <line x1="3" y1="12" x2="21" y2="12"></line>
                    <line x1="3" y1="18" x2="21" y2="18"></line>
                </svg>
                <svg class="close-icon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <line x1="18" y1="6" x2="6" y2="18"></line>
                    <line x1="6" y1="6" x2="18" y2="18"></line>
                </svg>
            </button>
        </div>
    </div>
</header>

<div id="mobile-menu-overlay" class="mobile-menu-overlay" role="dialog" aria-modal="true" aria-label="Navigation menu" aria-hidden="true">
    <nav class="mobile-menu-content" role="navigation" aria-label="Mobile navigation">
        <a href="/posts/">Blog</a>
        <a href="/projects/">Projects</a>
        <a href="/about/">About</a>
        <button class="search-toggle mobile-search-toggle" type="button" aria-label="Search">
            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <circle cx="11" cy="11" r="8"/>
                <path d="m21 21-4.3-4.3"/>
            </svg>
            <span class="search-label">Search</span>
        </button>
    </nav>
</div>

<div class="search-overlay" role="dialog" aria-modal="true" aria-labelledby="search-title">
    <div class="search">
        <h2 id="search-title" class="sr-only">Search</h2>
        <div class="search__input-wrapper">
            <span class="search__icon" aria-hidden="true">
                <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <circle cx="11" cy="11" r="8"/>
                    <path d="m21 21-4.3-4.3"/>
                </svg>
            </span>
            <input type="search" class="search__input" placeholder="Search articles..." autocomplete="off" aria-label="Search query">
            <span class="search__shortcut" aria-hidden="true">/</span>
            <button class="search__close" type="button" aria-label="Close search" title="Close (Esc)">
                <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M18 6 6 18"/>
                    <path d="m6 6 12 12"/>
                </svg>
            </button>
        </div>
        <div class="search__results" role="listbox" aria-label="Search results"></div>
        <footer class="search__footer">
            <nav class="search__hints" aria-label="Keyboard shortcuts">
                <span class="search__hint"><kbd>↑</kbd><kbd>↓</kbd> Navigate</span>
                <span class="search__hint"><kbd>↵</kbd> Select</span>
                <span class="search__hint"><kbd>esc</kbd> Close</span>
            </nav>
        </footer>
    </div>
</div>
<main id="main-content" role="main" aria-label="Main content"><div class="container">
    
    <article>
        <header class="article-header">
            <div class="thumb">
                <div>
                    <h1>harsh - a minimalist CLI habit tracker</h1>
                    <div class="post-meta">
                        <div class="meta-line">
                            <time datetime="2020-05-26">May 26, 2020</time><span class="separator">·</span>
                            <span class="reading-time">4 min read</span>
                        </div>
                        <div class="article-taxonomies">
                            <div class="tags">
                                <a href="/tags/gtd/" class="tag">gtd</a>
                                <a href="/tags/dev/" class="tag">dev</a>
                                <a href="/tags/oss/" class="tag">oss</a>
                                <a href="/tags/tools/" class="tag">tools</a>
                                <a href="/tags/go/" class="tag">go</a>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </header>
    </article>

    <div class="article-post">
        <p>I&rsquo;m happy to announce the open source release of harsh today.</p>
<p><a href="https://github.com/wakatara/harsh">Harsh is habit tracking for geeks</a>. A simple, minimalist CLI for tracking and understanding habits. Build great habits. Break bad ones.</p>
<p>Why? Habits, both good and bad, make us. We are what we do habitually. And what we do habitually ends up <a href="/systems-and-habits-for-focus-and-productivity/">being what we accomplish</a>.</p>
<p>You can grab harsh most easily via <a href="https://brew.sh/">homebrew</a> on OSX or linux with a simple:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">λ ~ brew install wakatara/tap/harsh
</span></span></code></pre></td></tr></table>
</div>
</div><p>or on Linux via <a href="https://snapcraft.io/">snap</a> with:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">λ ~ sudo snap install harsh
</span></span></code></pre></td></tr></table>
</div>
</div><p>Otherwise, <a href="https://github.com/wakatara/harsh/releases">binaries are available in your OS and architecture of choice</a>.</p>
<p>And you can <a href="https://github.com/wakatara/harsh">find the source here</a> if you prefer compiling your own binaries.</p>
<h2 id="why-a-cli-tracker">Why a CLI tracker?</h2>
<p>A big revelation for me when I started tracking habits was how inconsistent I <em>actually</em> was despite how my brain tricked me into thinking I wasn&rsquo;t. Tracking ends up being important. So, I started testing habit trackers. Mobile were good for recording on the fly, but gave no insights into patterns and were ultimately demotivating. Emacs&rsquo; org-habits mode was overly complex and finicky.</p>
<p>Relief came with a Rust-based CLI in <a href="https://github.com/blinry/habitctl">habitctl</a> about 16 months back. Simple. One file for habits tracked, one for logging, and importantly, long-arc consistency graphs (aka Seinfeld graphs) to show long term trends and problems at a glance, and to act as motivation to keep chains going. Despite submitted PRs for fixes and features to the app though, it seems to be abandonware.</p>
<p>So, I decided to take the core ideas and build on them, cause&hellip; open source. I also built the new app in Go as I felt it reduced the friction in using (and developing) harsh as a full Rust environment was needed to compile and use habitctl (though Rust <em>is</em> cool).</p>
<p><a href="https://github.com/wakatara/harsh">harsh is the result</a> (harsh taskmaster, actually). It&rsquo;s goals: simplicity, visibility, and your consistency. I&rsquo;ve fixed core habitctl features and added support for skips, warnings (when you are about to break the chain), proper score calculation, and corrected sparklines graphing. I&rsquo;ll be adding in comment logging and parsing shortly and have an idea about how to measure changes in habit periodicity over time (eg. you move a habit 2 days to once a week once it&rsquo;s ingrained). Binaries available across major platforms to reduce barriers to adoption, and make install simple.</p>
<h2 id="so-how-does-it-work">So, how does it work?</h2>
<p>How do you use it? My harsh setup has <code>~/.config/harsh</code> directory symlinked to Dropbox so files get versioned and backed up (please feel free to write a git hook if you want one), and I have a dedicated tmux pane in iTerm2 so I have the 100 day consistency graph view given by <code>harsh log</code> and <code>harsh todo</code> up virtually all the time. It keeps me motivated and ensures visibility with multiple glances a day when switching to do command line tasks.</p>
<p>I&rsquo;ve shell aliased <code>h</code> to the <code>harsh</code> command so it&rsquo;s even quicker with <code>h log</code> (<code>h l</code>), <code>h todo</code> (<code>h t</code>), and <code>h ask</code> (<code>h a</code>). I use one log and habit file for each year and create new ones and archive the old Jan 1 (or did this year anyway).</p>
<p>When I make boo-boos I can trivially edit the log file via emacs/vim/VSCode and I keep a running commented version of the habits file to explain why X went well or poorly for a habit tracked on any given day (right now, you can put in comments manually in the file and they will still parse tho I&rsquo;d like to do that on the fly when recording.). The text file&rsquo;s format is parsable with standard text tools for data science analysis or spreadsheet for more advanced analysis than 100 days. It&rsquo;s a CLI app so it&rsquo;s targeted at engineers and data scientists.</p>
<p>PRs and feature requests welcome though I am trying to keep the app as simple, performant, and lightweight as possible. The <a href="https://github.com/wakatara/harsh">code is here on Github</a> and released under an MIT license. Please discuss issues, bugs, or features in the Github issue tracker. After this initial release I&rsquo;ll be refactoring the code from some great reviews I got on the initial code base as well as adding in a pair of features and testing an idea about how to track changes to the periodicity of habits over time (habits changing over time will surprise you.)</p>
<p>My hope is that it unambiguously improves your life and helps you, much as it did me, developing good (or breaking bad) habits. If you <em>are</em> finding it useful, lemme know by mention on <a href="https://mastodon.social/@awws">@awws on mastodon</a> or <a href="mailto:hola@wakatara.com">via mail from the blog</a>. Would love to hear back on how you&rsquo;re using it, if it&rsquo;s helped, and how it might improve.</p>

    </div>
</div>

<div class="container">
    <nav class="flex container suggested" aria-label="Post navigation">
        <a rel="prev" href="/productivity-buckets-reviews-and-visibility/" title="Previous post (older)">
            <span>← Previous</span>
            <strong>Productivity buckets, reviews, and visibility</strong>
        </a>
        <a rel="next" href="/organizing-effective-data-teams/" title="Next post (newer)">
            <span>Next →</span>
            <strong>Organizing Effective Data Teams</strong>
        </a>
    </nav>
</div>
</main><footer class="footer" role="contentinfo">
    <div class="container">
        <div class="footer__inner">
            <div class="footer__copyright">
                <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener" aria-label="Creative Commons BY-NC 4.0 License" class="footer__cc">
                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M10 9.3a2.8 2.8 0 0 0-3.5 1.9 2.8 2.8 0 0 0 1.9 3.5 2.8 2.8 0 0 0 3.5-1.9"/><path d="M17 9.3a2.8 2.8 0 0 0-3.5 1.9 2.8 2.8 0 0 0 1.9 3.5 2.8 2.8 0 0 0 3.5-1.9"/></svg>
                </a>
                <span>2004–2026 · Daryl Manning</span>
            </div>
            <div class="footer__social">
                <a href="https://github.com/wakatara" target="_blank" rel="noopener" aria-label="github"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg></a>
                <a href="https://www.linkedin.com/in/daryl-manning/" target="_blank" rel="noopener" aria-label="linkedin"><svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 1 1 0-4.124 2.062 2.062 0 0 1 0 4.124zM7.119 20.452H3.555V9h3.564v11.452z"/></svg></a>
                <a href="https://mastodon.social/@awws" target="_blank" rel="noopener me" aria-label="mastodon"><svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><path d="M23.193 7.879c0-5.206-3.411-6.732-3.411-6.732C18.062.357 15.108.025 12.041 0h-.076c-3.068.025-6.02.357-7.74 1.147 0 0-3.412 1.526-3.412 6.732 0 1.192-.023 2.618.015 4.129.124 5.092.934 10.109 5.641 11.355 2.17.574 4.034.695 5.535.612 2.722-.151 4.25-.972 4.25-.972l-.09-1.975s-1.945.613-4.13.539c-2.165-.074-4.449-.232-4.799-2.892a5.39 5.39 0 0 1-.048-.745s2.125.52 4.82.643c1.648.075 3.196-.097 4.769-.283 3.014-.36 5.638-2.218 5.968-3.916.52-2.673.477-6.524.477-6.524zm-4.024 6.71h-2.497V8.469c0-1.29-.541-1.944-1.625-1.944-1.198 0-1.798.776-1.798 2.31v3.346h-2.482V8.834c0-1.534-.6-2.31-1.798-2.31-1.084 0-1.625.655-1.625 1.945v6.119H4.847V8.286c0-1.289.328-2.313.987-3.07.68-.758 1.569-1.146 2.674-1.146 1.278 0 2.246.491 2.886 1.474L12 6.585l.605-1.04c.64-.984 1.608-1.475 2.886-1.475 1.104 0 1.994.388 2.674 1.145.659.758.986 1.782.986 3.07v6.304z"/></svg></a>
                <a href="mailto:hola@wakatara.com" target="_blank" rel="noopener" aria-label="email"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg></a>
                <a href="/index.xml" target="_blank" rel="noopener" aria-label="rss"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"/><path d="M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1"/></svg></a>
            </div>
        </div>
    </div>
</footer>
<button class="fab scroll-to-top" aria-label="Scroll to top" title="Scroll to top">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
            <path d="m18 15-6-6-6 6"/>
        </svg>
    </button>

    
    
    
    
    <script src="/js/anchors.6b032aa12665340e2fab00cce8f77954dac968c1fb1896263e477df64ebd939f.js" integrity="sha256-awMqoSZlNA4vqwDM6Pd5VNrJaMH7GJYmPkd99k69k58="></script>
    <script src="/js/scroll-to-top.55fd8003a1b31e1e1a3416423c60234b0fef9f1a4dded829f6b0a26aa2369836.js" integrity="sha256-Vf2AA6GzHh4aNBZCPGAjSw/vnxpN3tgp9rCiaqI2mDY="></script>
    <script src="/js/search.f72a184f7af354c799a8f62a7d8e43af4ec7a2d05f7fde5fd8eac0bc52ca3ab9.js" integrity="sha256-9yoYT3rzVMeZqPYqfY5Dr07HotBff95f2OrAvFLKOrk="></script>
    <script src="/js/menu.46214a24eaa73e4609fd4697aeef7307fd30c13e502469df5af17762a94881be.js" integrity="sha256-RiFKJOqnPkYJ/UaXru9zB/0wwT5QJGnfWvF3YqlIgb4="></script>
</body>
</html>
