Tweet after Hugo deploy, using jq to access an index.json and twurl to tweet via the Twitter API

I’m tweeting my microblog posts to Twitter by extracting data from my lunr search index at, and I thought the script might be helpful for someone. I use a zsh function to do it but you can adapt it:

function hugotweet01 {
  : ${1?ERROR integer value for arg is required}

  rm -rf ${_targetdir}
  cd ${_workingdir}
  ${_hugobin} -d ${_targetdir}

  _tweetdata=$(cat ${_targetdir}/index.json | ${_jqbin} --arg recindex $1 --raw-output '.[$recindex|tonumber] | "RC Logr–"+.content[:128]+"... "+.ref')
  # echo ${_twurldata}
  ${_twurlbin} -d "${_twurldata}" /1.1/statuses/update.json


  • you have a lunr index building at There are a few examples of how, in this forum.
  • you have ruby installed and have Twitter’s twurl set up and working manually, ex-script. You need to register an app at and note that they kind of put you through the questionnaire gauntlet these days. Also, especially if you’re on macos, I strongly recommend getting your ruby set up to work via rbenv and to not use the system ruby. You need to initialize twurl with the keys that you get from registering the twitter app.
  • you have a fresh version of jq installed


Points about the script:

  • The first line with the colon is a noop, and you can use this as a pretty portable test for existence of a var. The “canonical” way is usually [ -z = $1 ] but this way is pretty portable and easy.
  • After the noop check I just set some bins and paths, just in case the execution environment is different from my interactive environment.
  • Script moves on to delete the generated hugo site from tmp, and recreate it, so that there is a fresh index.json.
  • Next we push index.json to jq, pull the $1 arg (expects an integer, zero for the latest post) into a var that jq will be able to access, filter the json by extracting just the data that corresponds to the integer in that arg, then passes that to a statement that trims content to 128 chars and appends the post url. The basic concept for the jq filtering is as follows where .content and .ref are keys in the json, and the plus sign is used to concatenate (google jqplay to try filtering yourself):
    • jq --raw-output '.[0] | "RC Logr–"+.content[:75]+"... "+.ref'
  • Then we prep that string with a url param to pass to twurl, then pass it to twurl with the right syntax to actually make the tweet.


You can manually tweet whatever past post you want, by changing the integer.

# Latest
$ hugotweet01 0
# Second oldest
$ hugotweet01 1

Look at to see the 0th, 1st, 2nd etc datapoints in the index. You’ll have to adjust the jq filter based on your actual data.

I call this function in my deploy function after a brief sleep, to make sure the site is deployed to the server, before I go and tweet about it. Like:

...hugo deploy commands...
sleep 30
hugotweet01 0

Very cool. Thanks for sharing.

My pleasure. I have an elgato stream deck, with which I’m triggering a post generate script, and the deploy script. Press one button, and the editor opens with a post ready for writing. Write, save and close, then press another button to deploy. Super simple.

Also I should mention, I tried a bunch of various scripts besides twurl, but it turns out they were all pretty fragile and buggy. Twurl was written by an ex-Twitter guy, and I guess they incorporated it as official at some point. I think it is probably safe to assume it will be maintained.

1 Like

Followup: making a post with ’ or " in it, will cause twurl to cut the tweet off at that character. Something in the script is munging up the escaping, or something…