• When Does a Service-as-Software Model Make Sense?

    The service-as-software model is nacsent but expected to be experimented with in different fields as artificial intelligence techniques improve and enable new applications.

    However, slapping AI + {category} + service-as-software should draw reasonable skepticism. There are market constraints that will make adoption more difficult. There are capability gaps that will make solutions incomplete.

    So when does it makes sense for service-as-software?

    Completely replaces a function or role

    Of course taking an established function and selling a service that will replace someone’s job is not going to sell, but supplementing high-demand areas is viable. For example, there are more job openings for engineers than there are qualified people to fill them which creates demand for AI employees that can do the job fully.

    Performs work that wasn’t done before

    There are only so many hours in one day and there is work that is not financially viable to do but people want. For example, not every business can afford 24/7 support that can resolve customer issues but they certainly would like to. This latent demand could be tapped into at the right price point which would be infeasible even for a low-cost offshore vendor operation (which is notoriously hard to get right).

    Other examples:

    • Penetration testing which typically happens annually
    • Monitoring and reviewing logs of critical systems for insights
    • Hard to compile reports like annual business reviews

    The outcome is clearly defined

    The unit of work the service is delivering is ideally measurable and matches how the customer defines success. When the unit of the work is the outcome of the intent, outcome-based pricing aligns incentives clearly. This probably wouldn’t work if you define the outcome too generally (what would be the unit of work of HR?) or the job is a negative art. You could use a proxy measurement, but the further away from the real value, the less clear it becomes.

    (Some ideas drawn from A System of Agents brings Service-as-Software to life)


  • When to Be Directive

    I was at a high-end clothing store the other day. I saw one of the workers on an iPad. Curious, I looked over his shoulder to see what he was doing.

    He was making sure the clothing rack he was standing in front of matched the picture on his iPad exactly. He checked the order of each garment. He spaced each hangar exactly. He checked and then rechecked before moving on to the next one.

    This was clearly a process someone thought important enough to make each store follow precisely. Someone designed each detail intentionally so that it fit together as a pleasing whole.

    It’s okay to be directive where the details matter.

    See also:


  • Rust Memory Profiling on MacOS

    Working on my personal indexing service, I noticed that large files were getting OOM killed. That’s surprising because rust makes it fairly difficult to do bad things with memory (you can roughly approximate where memory is dropped just by reading code).

    After strugging to find a memory profiler for macOS (and not even being able to install Xcode for some reason), I settled on a stupid solution using Activity Monitor which comes pre-installed on every Mac. First, I changed the main method to execute just the code path I suspected was resulting in large memory usage (calculating embeddings) after adding logging to see which file was being worked on before getting OOM killed. Next, I opened Activity Monitor to the Memory tab and typed the name of the rust crate in the search box. Since names are consistent when running cargo run, I could see the value of memory used which gets sampled every second or so. I tried a few code changes, reran it each time, and voila—fixed! Sometimes all you need is a fast feedback loop.


  • Why I Like Incidents

    A lot of tech company workers dread incidents. They are a high-pressure and often high-stakes ordeal that requires urgent attention. I’ve witnessed some incidents that lasted for months.

    I’ve come to like incidents because I see them as moments of progress. At a minimum, the team just learned how something works (or doesn’t work). At its best, the incident process guarantees that improvements are made which prevent systems from failing the same way twice.

    So while I have that same feeling of dread whenever an incident is called, I remind myself that we are going to learn something important and this is the price of entry.


  • Use a Scenario Table to Organize Complicated Situations

    When thinking in scenarios, I find it useful to lay it out as a table. A table is the most compact way of sharing definitions with a team. A table helps you explain what’s going on in a way that is mutually exclusive and collectively exhaustive. This keeps the team organized and provides the ability to refer to each case.

    What goes into a scenario table?

    Columns and values

    Which columns determines which dimensions of the problem matter. If you are responding to an incident for example, the goal of the table is to summarize all of the ways a bad thing happened so each column would be contributing factors.

    Picking the right columns is a thinking aid to help you and the team reason about the problem. What other possible combinations of these columns exist in the system? Do we have examples and does it matter? Which can you rule out entirely?

    Labels for each case

    Since we’re in a table format, it’s easy to add a column for labeling each case (a row in the table) so they can be referred to easily. If your situation is very complicated (i.e. many columns), simply number the rows and refer to the case by number. If it’s not as complicated, use a very short name that is distinct and memorable for each case (I use the former for incidents and the latter for product brief).

    See also:


  • Emacs Sticky Buffer

    Sometimes I want an emacs buffer to always be visible but I want to ignore it when navigating between buffers.

    For example, I want a list of org-mode tasks I need to do today and I want it at the top of the window so it’s highly visible. Since I heavily use other-window and previous-multiframe-window to switch between buffers, it would slow me down if I have to visit the sticky buffer every time I’m cycling between buffers (I like to think of it as clockwise and counterclockwise).

    Here’s my first attempt at doing just that: sticky-buffer-mode.el.

    Now I can go to the buffer with the list of tasks and sticky-buffer-add and future navigation (I have previous and next bound to C-x p and C-x o) won’t visit it.


  • Manual Spam Filter

    I block every unwanted email I receive to keep my email inbox as signalful as possible (“block” is Gmail speak for “create a filter for this one email address and always send it to spam”).

    Isn’t that a lot of work?

    It’s certainly more than zero effort but the damage a low-signal email inbox is very high for me. Gmail’s built in spam filtering is good at catching the obvious stuff, but it flat out misses every cold email and recruiting agency. Missing a single important email can be the difference between closing a customer, fixing an issue, and making a hire.

    My manual email spam filter list


  • Four Levels of Product Market Fit

    First Round Capital has a helpful guide to product market fit that helps to orient founders so they can focus on the right things. Rather than a binary, yes/no, evaluation of product market fit, the guide discusses different levels.

    Level 1 - Nascent PMF is when you have some initial customers mostly from warm intros. Churn, gross margin, burn multiples, don’t really matter at this point so much as quickly discovering who the right customer is and solving their problem well.

    Level 2 - Developing PMF is when you have customers, the solution delivered is more repeatable, you have up to $1MM ARR, generating your own leads, and customers would be very dissapointed if you went away. Some metrics around go-to-market efficiency start to matter like net revenue retention, gross margin, and burn multiples because you are proving the business can effectively drive demand.

    Level 3 - Strong PMF is when demand is flooding in and this is often what founders refer to as “feeling the pull” and everything feels easier. There is strong growth of 3x revenue or higher, more leads are coming from word of mouth, and marketing/sales is very efficient with low CAC/burn multiples/churn and high gross margin and sales conversion rate.

    Level 4 - Extreme PMF is when companies earn permission to build new products that expand TAM, the brand starts to become synonymous with the product category, and the business is growing fast. Burn multiple is < 1 and there are more scalable customer acquisition channels.

    Read Levels of PMF by First Round Capital.


  • Don't Combine Domain Name Hacks

    I see a lot of startups with domain names like getbarai.co and trymspledword.io which combine multiple domain name hacks. These look untrustworthy, are hard to search, difficult to spell, and long. It’s hard enough to get anyone interested in what you are doing that introducing any friction can cause people to forget about it.

    Here’s my rule for startup domains:

    Use only one domain name hack (mispelling of a real word, made up word, prefix before a real word, non-dotcom top level domain, etc.) AND always use .com. Then, when you have the money, buy the clean .com domain name.

    For example, when I started Mosey, we started with getmosey.com (prefix hack) then mosey.so (non-dotcom TLD), then eventually bought mosey.com.

    See also:


  • Net Revenue Retention

    NRR measures the ability of a business to expand revenue over time. It’s only really useful if the company sells multiple products or one of them has some sort of usage based scaling factor that implies customers use it more over time.

    One of the misleading ways to look at NRR is when there is a single product that is usage based and scales with the growth of their customers. If the customers growth stops due to an economic condition outside of anyone’s control the NRR becomes stagnant or lower than 100%. All that measures is the growth of the economy rather than the effectiveness of the business.

    See also:


  • Personal Log

    I often find myself wondering what I did yesterday. I want to be able to reflect on the day before as I get ready in the morning for the day to come. I also don’t want to make work for myself so the effort has to be useful.

    What would make a personal log useful?

    Facts about the day to jog my memory

    Looking at my calendar to see what meetings I had is a good clue about how my day was spent and who I met with.

    Seeing the tasks I’ve captured and completed also helps.

    Then there are life log things like where I went out to eat and how much time I spent looking at a screen. These are maybe not as useful to look at daily.

    Notes and observations

    I’d like to be better and inspecting my notes and thoughts. I write an enormous about of notes from meetings and tasks, but I don’t review them as readily. Reviewing them more readily would help me turn more of what I’ve learned into permanent notes.

    Things I produced

    Concrete things I’ve produced would be great to catalog to reflect on how it went and what I learned now that it’s complete. This includes writing docs, committing code, shipping a feature, closing a sale, or any other artifact.


  • How Does Tailscale Work Without Ports Open?

    If a home computer is running on a local network with no ports exposed, how are tools like tailscale working to connect to said computer? How would the computer know that another device is trying to connect to it?

    NAT traversal over UDP.

    Firewalls allow packets from ip:port s where it has observed packets sent to ip:port. A coordination server provides a mapping of devices and ip:port. To get through the Network Address Translation layer (NAT) which rewrites packets (e.g. a home router translating packets from local devices like your phone to come from one IP address on the internet), the STUN protocol informs each device what their ip:port is so they can send packets to the peer device.

    Altogether, by sending packets over UDP and being able to get replies to the correct ip:port, no ports need to be open (though UDP egress is required).

    See also: Why you still need an SSL certificate with tailscale


  • Dokku, Tailscale, and Letsencrypt

    To set up SSL certificates for use with HTTPs on dokku you can use the letsencrypt plugin.

    sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

    Next, create an IAM user for dokku-letsencrypt with a custom policy scoped to the hosted zone in Route53. Configure dokku with IAM credentials to pass the DNS-01 challenge:

    dokku letsencrypt:set –global dns-provider route53 dokku letsencrypt:set –global dns-provider-AWS_ACCESS_KEY_ID your_key dokku letsencrypt:set –global dns-provider-AWS_SECRET_ACCESS_KEY your_secret dokku letsencrypt:set –global dns-provider-AWS_REGION aws_region dokku letsencrypt:set –global dns-provider-AWS_HOSTED_ZONE_ID your_hosted_zone dokku letsencrypt:set –global email <your@email.com>

    Enable letsencrypt for the app in dokku:

    dokku letsencrypt:enable <app>

    And set up cron job to auto renew certificates:

    dokku letsencrypt:cron-job –add