Dec. 30, 2022

Mastodon is a real breeze to develop for. I was able to use nbb (Clojure scripting on Node.js) to post an image using the API in a few minutes. Here's how.

Step 1: Create a new Mastodon app.

Go to Preferences -> Development -> New Application, or visit /settings/applications/new on your Mastodon server.


Step 2: Store the access token

Once that is done copy the "Access token" and your server's URL. Put them in an env file:

export MASTO_SERVER=...

Get these into your current environment (or use direnv etc.):

. ./env

Step 3: Set up nbb & libraries

echo {} > package.json
npm i nbb masto

Step 4: Create the code

In a file called post-image.cljs put the following code:

(ns post-image
    [promesa.core :as p]
    [applied-science.js-interop :as j]
    ["fs" :refer [readFileSync]]
    ["process" :refer [env]]
    ["masto" :refer [login]]))

(p/let [masto (login #js {:url (j/get env :MASTO_SERVER) :accessToken (j/get env :MASTO_ACCESS_TOK)})
        attachment (j/call-in masto [:v2 :mediaAttachments :create] #js {:file (readFileSync (last argv))
                                                                         :description "Test image"})
        status (j/call-in masto [:v1 :statuses :create] #js {:status "Hello this is a test!"
                                                             :visibility "public"
                                                             :mediaIds #js [(j/get attachment :id)]})]
  (js/console.log status))

Step 5: Test it.

npx nbb post-image.cljs some-image.png

Congratulations, you now have an nbb script which can post images to Mastodon. Enjoy!

Nov. 2, 2022

It's been a while since I posted an update. So this is it! The tl;dr is I'm working on a sound effects generator micro-SaaS and I am nearly ready for launch.


In February this year I was working on the iOS port of one of my music apps when I decided to pivot. Safari iOS bugs were taking a lot of time and really dragging me down. I decided to focus back on pure web based music applications. I love the web and I love making web audio apps.

I decided to convert one of my online web audio apps to a subscription micro-SaaS business. To do this I had to build a bunch of infrastructure. I was tinkering with server side ClojureScript and my new web framework, Sitefox (here is an interview I did about Sitefox on the ClojureStream podcast:

I really wanted to build everything on top of this highly productive stack. So I made a plan:

  1. add authentication to Sitefox (ClojureScript backend web framework).

  2. make it easier to integrate Stripe (new library).

  3. use those two pieces to convert some existing apps into micro-SaaS apps.

  4. 🌱 open source as much as possible.

I've been carrying out this plan since February. I've added authentication to Sitefox and I've also made a Stripe integration library. Now I am in the process of doing #3 - converting an existing web app into a micro-SaaS app.

The app I have chosen to convert is a sound effects generator called Jsfxr. This is a wonderful little piece of software written by Eric Fredricksen. I started contributing to, and eventually maintaining this public domain codebase some years ago. At one point I put it up online under the domain Some years later I checked the stats of the site and it was getting more than ten thousand hits per month. Wow!

Software developers generally hate marketing. We just love to build stuff. But it's difficult to get people to use the thing you have built, without resorting to all kinds of unpleasant shenanigans like telling people about what you built, and communicating with other human beings.

So discovering my existing site already had traffic was exciting. All I have to do is build something that the visitors might want. So that's what I've been doing - I've been working hard on a Pro version of Jsfxr. It's going super well. It has been really fun to work on this codebase using an all-ClojureScript stack, and I am just about ready for launch.

If you're interested you can read a log of the development process in this Twitter thread. I will post an update when it's ready for launch.

Thanks for tuning in!

April 2, 2022

Dear YouTube,

What the actual heck? Here I was, innocently demonstrating how to install Nextcloud on a Linux VPS server. I just want to help other people liberate their data. Nextcloud is super cool and powerful and I want to share the good news. My video got a bunch of views and people seemed to find it really useful. Hooray!


Then suddenly, without warning, you can cancelled my completely innocuous video. I appealed, and you rejected my appeal with no explanation at all. You say my video contains "harmful and dangerous content". Really? What exactly is harmful and dangerous in this video? No reasonable person could find anything in this video that could be construed as "harmful".


Is this really about protecting viewers? Or is it about protecting your parent company? In the opening frames of my video I spoke about replacing proprietary services like Dropbox, Google, and Apple. Was my video cancelled because it's dangerous to users, or because this idea is dangerous to your parent company?

The only remotely harmful and dangerous thing here is that people might switch away from centralized services like those provided by your parent company, to Free, Libre, and Open Source Software provided by awesome hackers working in the public good.

Of course, I have no recourse now. Your interface does not allow me any way to speak to a human being about this. I feel completely powerless to do anything about it.

I've read about this kind of thing happening to others, many times on Hacker News. I always thought it was just bad luck and that will never happen to me. I have also read this exact thing from people this happened to previously.

Here is the original video, hosted on Vimeo, just so everybody can see exactly how innocuous it is. It's literally a how-to video for installing Nextcloud on an Ubuntu VPS.

So if you're reading this and you host videos on YouTube, I implore you, please make sure you take backups. Make sure you have a second copy of your precious videos. Make sure you have a plan for hosting elsewhere in case you get cancelled too for no good reason.

If somebody from YouTube is willing to un-cancel my video and remove all strikes from my account, I will update this post.

Update: after engaging @TeamYouTube on Twitter the original video has been restored. I did not receive further correspondence from them. To migate against this happening again in future I will mirror my videos on multiple platforms.

Feb. 5, 2022


Gather round friends for a true and epic tale of glorious Indie Hacking. How I built and launched a micro-SaaS product in 26 weeks. How I discovered the quiet joy of incremental progress. How I weathered a Hacker News ban and a barrage of sniping comments and landed the first paying customer, only to come undone at the last moment, defeat snatched from the jaws of victory. 26 weeks of work gurgling down the internet's drain hole. And finally dear reader, what I will salvage from the wreckage that may help us in future ventures.

That Wednesday morning I was up with the cock. 6am bright and early. The kids were still asleep and my wife too making this the perfect time to GTD. I creaked my way through the house into my office, opened up my XPS 13 and sat in the glow of Gvim, code sparkling from my fingertips.

This day I would be a veritable @jdnoc. I would put in those Deep Work hours, chipping away at the product, posting new articles for SEO, reading feedback, testing and triaging bugs. And so it went.

For 25 weeks I had done this. Half a year of one-day-per-week stone cold indie software development. Writing code, building in public on Twitter. I had sat down on days like this when I was pumped to work and code flowed freely, and also on days when I was grinding all day long sweating out every line from a creased forehead. I ignored my feelings, hot and cold, and incremented away on the feature set week by week. Today was no different.

By 2pm I looked at my GitHub project board. Tickets had whipped by like restaurant napkins in a New York harbour bluster. The "TODO MVP" column was empty. I had moved every ticket into "Done". A strange feeling came over me. This was it. This was launch day. An excitement grew in my belly as I began to plan the launch on Twitter, PH, IH, HN. This ship was set to sail.

The launch

I set the Product Hunt launch to start one hour later at 3pm my time. I posted a link on Hacker News with the title "Show HN: Download Twitter data without API keys". I drafted an Indie Hackers launch post with the links to give everything a boost. Then I shared the Hacker News link around with a few friends and on my Twitter account.

Then came the first sign. The first warning that fate was not to smile upon the little micro-SaaS that could.


Hmm that's odd. It became apparent my Show HN post had been shadow-banned. I could see it when logged in but none of my friends were able to load the page. What was going on? I was overcome with confusion. For what possible reason would the link to my site be banned? I emailed the mods that evening without much hope of receiving a reply and went to sleep.

The next morning I woke to an email from a very nice Hacker News moderator. It was super polite and informative which I am grateful for. Here is a summary of what they told me. I'm sharing in case it is useful for your own HN posting:

  • The HN software thought I was violating the rule against using the site mainly for "self promotion".
  • The software starts filtering posts once the percentage of posts about your own stuff is too high.
  • It's best to have a track record of interesting links from other sources and occasionally post your own stuff - the software is adaptive so you can start doing that and you'll stop getting filtered.
  • The best posts for HN are ones that can't be predicted from an existing sequence of posts ("out-of-the-way topics that rarely get any attention").

The Hacker News moderator said my submission history did not look too bad and I should be able to get it back on track. They kindly offered to unblock my post and push it back onto the front page and finally gave the following tip about posting Show HN projects:

Add a comment to the thread giving the backstory of how you came to work on this, and explaining what's different about it. That tends to seed discussion in a good direction.

The bit about seeding discussion in a good direction turned out to be wrong, but I think this is on the whole good advice. A good rule of thumb is "be human" and "don't spam".

I had a busy day on Friday and in the evening I did as the moderator suggested and added a comment with the development story. I emailed the moderator back gratefully to let them know and went to sleep.

The first customer

The next morning I woke to an awesome surprise. The first paying customer! It's happening! They had paid $5 for the 24 hour access tier so they could download their Twitter favourites to a CSV file. They seemed to be having trouble downloading the data but I thought it must be some user interface issue and decided to check out how the Hacker News post had fared overnight before looking into it.


A fantastic result. 1.5hrs on the front page and 25 comments! My server registered around 7,000 individual visitors to the site when normally there are 30 per day. I dived in to see what people were writing in the HN comments.







Uh oh.

The fall

Like a fool I ignored the noble sages of Hacker News. I was Prometheus to their Zeus. They watched in horror as I made off with the stolen fire of their secret Twitter API access codes, and brought it to all humanity in the form of an easy to use one-click interface. I had driven them mad with my barefaced democratic liberation of the Twitter API.

Alas they were right. I should have taken heed.


Very soon Hephaestus the god of Twitter API Authentication shackled me to the Mountain of Access Revocation. Just like that, the TweetFeast account was permanently suspended. All API requests broke instantly and my appeals to the Twitter API team went unheeded. Without Twitter API access there is no hope for my app and it was done for. Which brings us to today.

I refunded the one paying user. I updated the home page and closed the sign ups. My app now lies burning in the water, gurgling, bobbing gently downwards. A moment of silence, friends. Soon she will be subsumed by the waves of obscurity and the internet will know her no more. Alack, alas, so long little SaaS.

So ends my misadventure in Twitter API development and so ends this story.


Well not quite. I must be able to salvage something from the ruins of this experience. What can we rescue and what can we learn?

1. Sharing the source code

First off, I am open-sourcing TweetFeast. If you are into LISP or Clojure or server-side ClojureScript you might find the codebase useful. Here are some highlights:

Hopefully there is stuff in there that is useful to people building full-stack apps in ClojureScript. Get the TweetFeast source code on GitHub.

2. General advice

If you're going to build something on a Big Corp API, be careful. Read the terms. Ask around and see if anybody else has done what you are trying to do. When you launch pay attention to the way you word the capabilities of your product.

I once worked on an app that went into the App Store with no problem despite violating a whole section in the terms of service. That was because some people inside Apple liked the app and gave it the green light. Rules at these companies are not laws. They are subject to individual whims and a lot depends on signaling.

I suspect a major reason TweetFeast was shut down is because of the way I worded the launch post. There are multiple products which do a very similar thing to TweetFeast (download CSVs of Twitter data) and have been running for years, and I suspect it is because they did not position themselves as an "API workaround".

The final take away is about posting on Hacker News. First of all, remember to be a good citizen and don't only post "Show HN" links. Share stuff that is interesting if you want to keep your self-promotion score healthy. Secondly, don't worry about the haters. Yes, the app got banned, but it also got a customer within half an hour of posting. Before that first customer a lot of people found the beta useful. Hacker News commenters often overlook the value that other people see (especially non-technical people). So don't take it to heart. They are wrong famously often.

3. What I got out of it

It might seem like this experience was an epic fail, but I actually got a tremendous amount of value from building and shipping TweetFeast.

  1. I got to road test my full-stack ClojureScript library Sitefox and it worked great.
  2. I got to hone my self-hosted deployment skills some more with Piku.
  3. I managed to overcome Shiny Object Syndrome, stay focused for 26 weeks, and ship goddamn it.
  4. I now know how much effort it takes to build a minimal micro-SaaS MVP (one month of full time dev days).
  5. I wrote a bunch of code I can re-use again (Stripe integration, Twitter auth).
  6. I learned a bunch of new stuff about UX, UI, design, and SaaS app architecture.
  7. I learned an important lesson about building on 3rd party APIs.

Finally, the best part. I get my day back. I get back one day per week to work on something else. That's very exciting!

What's next

I think I will re-use most of this code to try and build another micro-SaaS, but not on Twitter. A straight up web app most likely. My music apps are doing ok, and so I'll probably try to do something in this space. Whatever I do, I'll post about it here and you can also follow along on Twitter.

Thank you very much for reading, I appreciate it!

Onward. 👉

Jan. 10, 2022

My son asked me to make a spaceship for his lizard toys. This is it.




Lizard persons not depicted.