Welcome to the lab.

The Tap Forms giveaway winners!

The Winners

The Tap Forms giveaway has ended, and I have two winners to announce!

Congratulations to:

  • Jonathan Laniado
  • Doug Lionetti

(I swear the giveaway robot has no preference for last names starting with L. It’s purely chance.)

Each winner should have received an email with a redeem link/code, please let me know if you didn’t hear anything!

But I Didn’t Win!

If you didn’t win, sorry, but Tap Forms is still worth checking out. You can easily store and work with any kind of data. It’s the missing database app for Mac and iOS. If you didn’t win, you can still save 30% on the direct version with the coupon BRETT-TF5-2023. Go to the site and click the Buy Now for Mac button to use the coupon, or download the free trial version and enter the coupon when using the in-app purchase.

Coming Soon

Next up is CleanShot X (the best screenshot app there is). Check back every Monday through December for more giveaways. Upcoming apps include:

If you want to suggest an app you’d like to see in this series, let me know on Twitter or Mastodon, and join the email list for early access!

Journal updates with weather types and conditional questions

In case you missed it, I recently released Journal, a CLI for keeping a journal with structured data that can be queried and analyzed. An update is live with a couple of nifty new features.

First, instead of just a type of weather for a question (which inserts the current condition and daily forecast), you can now specify sub-types of weather.current and/or weather.forecast. This outputs separate data entries to the JSON, and creates individual answers in the Markdown/Day One versions. You can still just use weather as the type to insert all data.

Second, you can now apply conditions to questions to determine whether they’ll be asked or not when creating an entry. Right now only time-based conditions are implemented, but I plan to add some functionality around basing a question’s appearance on the answer to a previous question, like “if health rating is less than 5, display the health notes question.” But for now you can add condition: before noon or condition: > 2pm to any question or section to only display the question(s) at certain times of day.

I needed these conditions because I like to create a mood entry in the morning with data about sleep and coffee, and in the evening I don’t want to repeat that data, but do want to ask some different questions about how the day went. I could create two separate journals for these, but this way I can compile all of my data in one file. Questions that are skipped get a null entry in the JSON, so when I’m parsing I just test for nil and skip entries that don’t contain the information I’m trying to output. Unanswered questions don’t get added to the Markdown/Day One entries at all.

This release includes a couple of bug fixes as well. I recently removed the requirement for the gum CLI, if it doesn’t exist it will now just use Readline for input. When using the gum inputs, you can’t CTRL-c to cancel an entry, which I’m trying to figure out a way around right now.

Update using gem install journal-cli. Visit the project page for more info and installation instructions.

Tap Forms for Mac giveaway!

I’m starting up giveaways again on BrettTerpstra.com, and I’m exited to kick it off with 2 free licenses for Tap Forms for Mac. It’s an amazing database product that lets you organize and access your data on any device. It’s available on Mac, iPhone, iPad and even Apple Watch. This giveaway is specifically for the Mac version.

From the developer:

Accounts, recipes, expenses, inventory — life is full of things that we don’t want to forget or misplace. Tap Forms helps you organize all kinds of things in one place — secure, searchable, and accessible on your Mac, iPhone, iPad, and Apple Watch.

Check out the Tap Forms site for more info.

Sign up below to enter. Two winners will be randomly drawn on Friday, Sept 22, at 12pm Central. Tap Forms for Mac costs $49.99, so this is a great chance at saving $50!

Sorry, this giveaway has ended.

I reached out to my mailing list to see what products people were interested in, and Tap Forms was a top pick. I have several more developers lined up to offer free stuff, so stay tuned. If you have an app you’d love to see featured, let me know. Also be sure to sign up for the mailing list so you can be the first to know about these!

A silly Jekyll plugin and a big Marked sale

So, a long time ago I wrote this Jekyll plugin that does countdowns and I don’t think I ever really used it. You just give it an end date and it inserts a countdown into the post. But I needed something to count down to, so I’m running a 40% off Marked sale using the coupon COOLPLUGINBRO until Saturday, September 16th. Here’s your countdown:

Time’s up.

Did it work? I hope so. Use this link to apply the coupon directly, or enter COOLPLUGINBRO at checkout. Learn more about Marked at marked2app.com.

Journal and integrations

I’ve made some changes to Journal (I didn’t mess with the data format this time) that add some functionality and will maybe help with integrating with some apps like Obisidian.

First, you can now define a date type. Date entries will be parsed from natural language into date objects, so on the command line you can enter something like “yesterday 5pm” or “july 20 12pm” and get a proper date object added to your JSON and Markdown entries. Great for things like logging book review dates, workout days, etc.

You can also now define a dictionary type for a question, which along with a key definition creates a nested data set with any dot notation keys that match. So you can define the following:

  - title: "Status"
    key: status
      - key: health
        type: dictionary
      - key: health.rating
        type: numeric
        prompt: Health Rating
        min: 1
        max: 10
      - key: health.notes
  	    type: multiline
        prompt: Health Notes

The data that gets output will include this format in the JSON:

  "mood": {
    "status": {
      "health": {
        "rating": 5,
        "notes": "Just some notes on my health"

This allows for more control over the structured data. It won’t be a big deal for most people as answers were already nested within section keys and could be grouped using dot syntax, this just allows the structure to go one level deeper which may help with building analytics tools.

The big change that will allow more integrations with apps like Obsidian is that all numeric and date answers are now included as YAML front matter in any individual Markdown files created. This will allow integration with existing tools like Obsidian Dataview, which allows you to create data views based on YAML data in your Obsidian notes. By pointing Journal to your Vault folder, you can have journal entries added to your vault and queryable with Dataview. I haven’t tested this, I just noted that it should be possible with the addition of the YAML data. For the time being I’m not including any string responses in the YAML, as that seems redundant since they’re also included in the body text and available to search.

This update won’t affect data saved to single Markdown files or added to Day One. If you have any ideas about how this could be made more useful, please let me know! Either via the Discussions or by contacting me directly.

Version 1.0.19 is out now, just install or upgrade with gem install journal-cli. See the project page for more details.

More na updates

I’ve put some more time into both Journal and na. The latest version of na represents quite a few hours of tinkering. See the na project page for full details. In case you’ve missed in previously, na is my command line tool for reading and modifying TaskPaper files in your projects.

I think the biggest thing I’ve added is theming. You can now control the colorized output of your actions using a file at ~/.local/share/na/theme.yaml. That file is automatically written by na if it runs and it doesn’t exist, and once it’s there, it should be pretty self explanatory. You can use {y} type placeholders (that would make the following text yellow, a full list of color abbreviations is at the top of the file), and you can also use {#RGB} and {#RRGGBB} codes to get specific colors outside of the usual ANSI coloring.

I’ve added new commands like tag (see na help tag), and a new --restore option to several commands for removing the @done tag from actions. There’s also a --replace flag you can tie into na update --search SEARCH_STRING --replace REPLACE_STRING to perform (wildcard-compatible) search and replace. Add --regex to do a regex search and replace.

There’s a bunch of other new stuff, so I’ll just post the collected changelog.


  • Global option --include_ext can be configured to use full extension when displaying filenames, allowing for command-clicking to open in compatible terminals
  • Tag command
  • Add --save NAME to na next to save more complex queries and run with na saved NAME (or just na NAME)
  • na saved --select flag to allow interactive selection of search(es)
  • Open the todos database in an editor with na todos --edit
  • A theme file is written to ~/.local/share/na/theme.yaml where you can modify the colors used for all displays
  • Allow TAG=~PATTERN comparison for regex matching in na tagged
  • na undo command to undo last change or last change to file specified in arguments
  • na update --search OLD_TEXT --replace NEW_TEXT (added –replace)


  • When displaying actions wider than the screen, wrap at words and indent 2 spaces from start of action (after prefix)
  • When not showing notes, add an asterisk at the end of an action
  • When showing notes, indent to the beginning of the action
  • Add --project to archive, complete, and update to move a modified action to a new project when saving
  • Allow na saved --delete to handle multiple arguments
  • Allow wildcards when deleting saved searches
  • Refactor request for input, no change to user experience
  • Refined wildcard (?*) handling
  • Better error message for na next when no todo is matched
  • If STDOUT isn’t a TTY, don’t enable pagination, regardless of global setting
  • Disable pagination when using –omnifocus
  • Allow –find or –grep as synonyms for –search
  • --in TODO option for na complete
  • If a search string contains @tags and –exact or –regex isn’t specified, the @tags will be extracted and passed as a –tagged search.
  • Tag handling (including values and comparisons) in tags extracted from search strings
  • na complete --project PROJ flag to move to a specific project
  • na restore --project PROJ flag to move restored action to
  • Exit gracefully if tagged command is run with invalid arguments
  • Display action affected when using update command


  • Change default :dirname coloring to fix an occasional highlighting issue
  • Error when creating new project in todo file
  • Error when last_modified.txt hasn’t been written yet
  • Nil error in action.pretty
  • Date tags containing hyphens triggered OR searches because they were initially interpreted as negative tag searches
  • Templating irregularities
  • Error thrown when running without $EDITOR variable defined in environment
  • New project not being added when requested
  • Error when na add --to PROJECT was a project that didn’t exist
  • --no-color wasn’t stripping templated hex codes
  • Escape search for tokens to allow parenthesis and other reserved characters

More details on the project page!

Important Journal CLI updates

Just a couple quick updates to the Journal CLI I published yesterday that I wanted everyone who was trying it out to know about before they have too much data in it.

First, if keys were nested using dot syntax, e.g. health.rating and health.sleep, it would create a hash like:

  "health": {
    "health": {
      "rating" : 5, 
      "sleep": 7 

As you can see, the “health” key got doubled and nested inside of the section key. This isn’t the way it was supposed to work with the dot syntax. Version 1.0.15 fixes this, if a key is repeated it’s merged with the parent key instead of nesting.

I also added options for defining custom folders to save entries in. At the top level you can include entries_folder with a path to any folder on your system. Journals will all save to that folder with subdirectories for each of their keys. You can instead define entries_folder within a journal definition, allowing each journal to have a custom location. JSON and Markdown will be written to these folders based on settings.

That should help make this tool a bit more useful, sorry for changing the data format, but better sooner than later. Check out the project page for more details.

Journal, a CLI for journaling

I recently started couple’s therapy to try and improve the often-complicated relationship between myself (ADHD, bipolar) and my partner (autistic) and all of the unique problems that combination of neurodivergence presents. As part of this, I was asked to keep a journal containing certain data points. I started off journaling in Day One, but immediately realized that I was collecting some numeric data that I wouldn’t be able to do anything with unless it was stored in a database format of some kind. So I wrote a tool.

Journal is a command-line tool that takes a configuration of journals, sections, and questions, presents the questions on the command line, and records the answers to JSON, as well as optionally creating Day One and Markdown versions of the entries. It can handle numeric data, string and multiline input, as well as automatically recording the daily weather for each entry.

To use it you need Gum installed (brew install gum). If you want to use the Day One integration, you’ll also need to install the Day One CLI. Those are the only prerequisites. You can just use gem install journal-cli to get the journal command set up. It can handle multiple journal configurations and multiple output formats. It takes some configuration, but it’s very flexible (and will probably get more flexible as new needs arise).

I haven’t written the part of this that can query the datasets created yet. That’s going to be pretty individualized based on your needs, but I think everything should be there in the JSON to allow tracking and correlations with a little statistical analysis work. I’ll dig into it more once I’ve collected enough data. In the meantime, it’s also creating nicely-formatted Day One entries so I can get an overview of my moods and journals.

See the project page for details on setup and configuration. Hopefully others will find this useful, too!