Projects
My projects span machine learning, programming languages, personal analytics, browser extensions, code editors, and personal tools to support my workflows. I work on projects for fun, to learn, or to solve a specific problem I have. More recent projects are listed first.
Click on a project’s heading to go to its website/repo.
2022
Meepo
A smarter search engine for a local (South African) fashion and homeware store.
I have no affiliation with said store. I built this for myself, because I was frustrated at how difficult it was to find what I wanted with the existing search engine + I was curious how well CLIP (a relatively new AI technique with open source code and models) would work here.
I think it works quite well! It’s much more forgiving than the original search engine. I don’t have to guess what exactly they decided to label a particular item. But what I like even more is that it works quite well for abstract things like “colourful shoes”.
Here’s the full stack:
- Hardware: Deployed on a 2CPU 4GB RAM VPS with docker
- Storage: SQLite + object storage (for images)
- Search: CLIP text/image neural networks + faiss similarity search index
- Pipeline: Python scripts + cron
- Web: Django serving HTML/Tailwind/daisyUI
- IDE: Developed in notebooks with nbdev
I tried to keep the implementation as simple as possible and I’m happy with the result! It took ~2 weeks to build and has been running seamlessly without my input ever since.
Check out this Twitter thread for more details.
nbdev
I’m a core developer of nbdev, an open source notebook-driven software development platform.
nbdev let’s me use exploratory programming (related to REPL-driven development and literate programming) for all of my software development.
I also came up with the idea of hooking into the Jupyter file save API and using a custom git merge driver to improve Jupyter/git integration. All of the core functionality used by these hooks was already implemented by other nbdev core developers. You can find out more in the write-up.
Plum dispatch for fastcore (experimental)
An experimental PR to fastcore (the core library powering the fastai deep learning framework), that replaces its custom type dispatch system with plum-dispatch. Both bring Julia’s multiple dispatch into Python using type annotations and decorators.
2021
EasyEquities browser extension
A browser extension for the EasyEquities investment platform built with TypeScript, React, React Router, and Mock Service Worker (to develop against a mocked version of their API).
This started with frustration that EasyEquities didn’t provide a single view of my holdings across all of my investment accounts, nor of my time-weighted returns. I made good progress but stopped building this since there’s no public EasyEquities API, and sending handcrafted requests to the internal API of my investment platform seems like a bad idea!
Repo links
A tiny command-line tool to quickly open URLs related to your repos. I made this for a smoother experience while working on a manyrepo codebase.
MyFitnessPal to SQLite
Save your personal data from MyFitnessPal to a SQLite database. I occasionally use MyFitnessPal to track my weight and calories. Inspired by the dogsheep movement, I built this to afford personal analytics on my own data.
CircleCI to SQLite
Save your personal data from CircleCI to a SQLite database. I threw this together for a quick analysis on build times at a former workplace, which we could then follow up with easy build pipeline optimisations.
Reverse engineering ncode
An attempt at reverse engineering ncode paper technology. I got all the way down from what looked like dots on paper to a matrix which I needed to decode. Perhaps I’ll get back to it some day!
Romulus
An experimental framework for creating structure-aware editors. The idea was that actions (e.g. move left, insert character) would be aware of the context surrounding the cursor location within the (tree-)structured document, thus would have slightly more intelligent behaviour.
For example, given a document ((foo)|
, where |
represents the cursor, and where ((foo))
is a known symbol represented some BlockRef
object, inserting )
would know to create a BlockRef
object in the internal tree structure. Like a hackier version of tree sitter. The vision was to use this framework to create a Roam clone using an enhanced markdown-like syntax for personal use.
Zip
Functional hierarchical zipper (tree cursor), with navigation, editing, and enumeration. A port of clojure.zip
to JavaScript that I intended to use in Romulus.
Roam tools
Tiny command-line tools for working with Roam graphs.
Roam parser
A tiny Roam parser built with Clojure and instaparse. I also live tweeted the entire development process.
Image alignment
Keypoint-based alignment of two grayscale images using ORB and RANSAC via skimage. This was completed as a take-home assignment for a job application, so I limited the implementation to a max of 8 hours.
2020
Editor
Minimal terminal text editor written in Python and curses. I wrote a corresponding step-by-step tutorial as well.
Advent of Code
I enjoyed taking part in AoC for years 2017, 2018, 2019, and 2020.
Alfred Github local
An Alfred workflow to open GitHub repo URLs via a local workspace directory. No GitHub API access needed!
pdlog
Seamless logging for pandas dataframe operations, inspired by tidylog. We used pandas in production extensively at a former workplace, and our code often ended up overwhelmed with logging logic. With pdlog it’s simple: instead of calling, say, df.dropna()
, call df.log.dropna()
and it’ll log <pdlog> dropna: dropped 1 row (17%), 5 rows remaining
.
2018
Neural networks from scratch
A basic implementation of neural networks from scratch. Shortly after my encounter with reinforcement learning (see below), I realised that deep learning was an important precursor and shifted my studies there.
Reinforcement learning from scratch
Re-implementing sections of Sutton and Barto’s Reinforcement Learning: An Introduction. My first inspiration in AI was the possibility that a computer could play games better than the best humans! I was determined to build one of these AIs myself.