Exit
Neil Belani Software Developer
open to opportunities

System Administrator@OWL360IT·Toronto, CA

Neil Belani

I keep systems running, build PCs from scratch, and make the web do fun things.

Projects 14

Countries visited

0 and counting — tap to explore

My time · Your time

MeToronto, CA
Youlocal

Theme

nb@os:~$ theme --list
❯

Contact

Selected work

Projects I'm working on.

Systems built and shipped end to end — automation pipelines, e-commerce, self-hosted infrastructure and real-time graphics. Each entry covers the problem, the approach, the technical decision that mattered, and the outcome.

AI & AutomationLive

DealerList AI

Dealership inventory published to Facebook Marketplace in bulk — listings generated, forms populated, sold units withdrawn automatically.

  • AI listings
  • Marketplace autofill
  • Inventory sync
  • SaaS

Read the case study

Problem

Facebook Marketplace is where local used-car buyers are, and it offers no bulk path for vehicle listings. Every car is a manual form: photos, mileage, trim, a description someone has to write. Across a 200-car lot that is a full-time role, so most dealerships list their twenty best vehicles and leave the rest invisible.

Approach

A platform connecting dealership inventory to Marketplace: listing copy generated per vehicle, Marketplace forms populated rather than typed, sold units withdrawn automatically, and per-salesperson attribution across the lot. Dealers work a review queue instead of a form.

Technical decision

The model writes; it never asserts. Generated copy is constrained to facts the system can verify, and anything unverifiable escalates to a human rather than becoming a confident guess. A fluent listing with one wrong specification costs a sale and the dealership's credibility — so throughput is deliberately capped in favour of accuracy.

Outcome

Live at dealerlist.ai. Product, pipeline and interface built and operated end to end.

Stack

  • AI listing generation
  • Facebook Marketplace
  • Browser extension
  • Inventory sync
  • SaaS

AI & AutomationLive

CounterList AI

A dealership’s featured parts and accessories on Facebook Marketplace — details verified from the manufacturer, forms filled, a person approving every post.

  • Parts & accessories
  • OEM lookup
  • Marketplace autofill
  • SaaS

Read the case study

Problem

Dealership parts departments carry high-margin accessories that local buyers never see. Marketplace is where those buyers shop, but every listing is a manual form, and nobody behind a parts counter has the hours to fill fifty of them.

Approach

A sister product to DealerList AI, built as its own codebase and database. Featured accessories are resolved to verified manufacturer details and imagery, the Marketplace item form is filled in the browser, and a person presses Publish on every listing. A dashboard keeps the dealership’s featured items, prices and status in one place.

Technical decision

No invented data, ever. Prices, stock and photos come from the manufacturer or the dealer, never from a model; an item with a missing price is held back rather than listed at zero. Ideas shared with DealerList are copied in and owned rather than imported, so neither product can break the other.

Outcome

Live, with a hosted dashboard and a seeded demo dealership; the counterlist.ai domain is next. Product, extension and back end built and operated end to end.

Stack

  • Browser extension
  • Manufacturer catalogue resolver
  • Supabase
  • Railway
  • SaaS

Content SystemsLive

othertenants

A short-form channel that scripts, renders and publishes itself on a schedule — with one human approval in the loop.

  • Remotion
  • GitHub Actions
  • Discord
  • Free tier only

Read the case study

Problem

Short-form only works with consistent output, and consistency is what ends solo channels. Every video is the same five jobs — select a subject, script it, render it, publish it, repeat tomorrow — and a stall in any one of them halts the whole pipeline.

Approach

A queue-driven pipeline. Subjects are scripted, rendered to vertical video with Remotion, and published to Instagram and YouTube Shorts by a scheduled GitHub Actions workflow. One manual gate remains: each finished render is posted to Discord, and nothing ships without an approval reaction.

Technical decision

A deliberate human gate inside an otherwise autonomous pipeline. Full automation was achievable, but the failure mode — publishing incorrect content to a live audience — is not reversible. Siting the gate in Discord keeps approval to a two-second action on a phone, which is the only reason it survives contact with a real schedule.

Outcome

Publishing on schedule with no server and no compute bill — scheduling and rendering both run inside free tiers.

Stack

  • Remotion
  • GitHub Actions
  • Discord approval gate
  • YouTube Shorts
  • Instagram
  • Free tier only

Content SystemsIn progress

Wildhush

Cinematic animal stories made end to end on one machine — script, images, voice and captions — for nothing a month in software.

  • Local AI
  • Video pipeline
  • Text to speech
  • $0 stack

Read the case study

Problem

Free tiers of cloud AI tools forbid commercial use, keep rights to what they make, or make it public. A faceless story channel built on them would not own its own work, and every one of them charges the moment output is used for real.

Approach

A fully local pipeline on open models: images and short hero shots generated on the GPU, narration from a local text-to-speech voice, captions from local speech recognition, and FFmpeg assembling a vertical master plus an export per platform.

Technical decision

Local and permissively licensed, end to end. Every model was chosen for a licence that allows commercial use; where a popular one does not, it was swapped for the variant that does, and FFmpeg does the assembly because the free edition of the usual editor cannot be scripted.

Outcome

Pipeline built and tested end to end; the channel itself is being shaped.

Stack

  • FLUX.1 schnell
  • Wan 2.2
  • Kokoro TTS
  • faster-whisper
  • FFmpeg
  • Python

AI & AutomationLive

Cerulean Finds

Auction lots in, a live storefront and a Marketplace-ready feed out. Nothing is entered twice.

  • HiBid
  • Storefront
  • Facebook import

Read the case study

Problem

Reselling from HiBid auctions means repeating the same data entry after every win: transcribing lot details, building a product page, then retyping all of it again to list on Facebook. In a resale business, that time is the margin.

Approach

A pipeline running from HiBid through the storefront and back out to Facebook. Won lots are ingested with their details and photographs, published as products, and exported in the shape Facebook's importer expects — so a lot is entered zero times.

Technical decision

Normalisation happens once, in the middle, rather than inside each integration. Auction data arrives inconsistently — titles vary, condition is buried in prose, photographs come in arbitrary order. Cleaning to a single internal product model means both outputs read that model instead of the source, so an additional sales channel costs one exporter rather than another parser.

Outcome

Live at ceruleanfinds.com, running the listing side of the business.

Stack

  • HiBid ingest
  • Normalised product model
  • Storefront
  • Facebook import feed

AI & AutomationLive

Second Brain

Deterministic memory for AI assistants — plain markdown, a flat index, and the same answer to the same question every time.

  • Node CLI
  • Markdown
  • No vector DB
  • Obsidian

Read the case study

Problem

Assistant memory is usually built by embedding everything into a vector database and trusting the nearest neighbour. For factual recall over a known corpus that is the wrong trade: the requirement is the correct note, not the closest one. Semantic retrieval is also unauditable — a wrong result carries no explanation and cannot be grepped.

Approach

A local vault of atomic markdown notes with a flat index — one line per note — and a Node CLI over the top.

Writes are atomic: the note, its index line and the commit land together, so the index cannot drift from what is on disk. Recall scores a query against that index and returns the matching note together with the heading and line numbers it came from, so every answer arrives with a citation that can be checked. Roughly fifty notes, each small enough that an incorrect one fails in isolation instead of contaminating its neighbours.

Technical decision

No embeddings, by design. Determinism, auditability and greppability were worth more than fuzzy matching: the same query returns the same note, the index is readable in a text editor, and a wrong answer is a fixable bug rather than a similarity score. Storing plain markdown also means the corpus outlives any single assistant.

Outcome

In daily use as the memory layer across multiple AI assistants. Git tracks history locally; there is no remote and nothing synchronises off the machine.

Stack

  • Node CLI
  • Atomic markdown notes
  • Flat text index
  • Obsidian-compatible
  • Local only

AI & AutomationLive

Helpdesk Copilot

Support mail triaged every fifteen minutes through the working day — classified, summarised and on a board before a technician opens it.

  • Ticket triage
  • Cloudflare Workers
  • MCP
  • Scheduled

Read the case study

Problem

At a managed service provider, requests arrive as email across a personal inbox and a shared support mailbox. Working out what each one is, how urgent it is and who owns it costs the first minutes of every ticket, many times a day.

Approach

A copilot that reads new mail on a schedule, classifies and summarises each request, and posts it to a triage board. The same knowledge is exposed to AI assistants through an MCP endpoint, so a technician can ask about a ticket instead of digging for it. Routine account work follows written runbooks.

Technical decision

Read-only by construction. Mail is read through the desktop client that is already signed in, so there are no new cloud permissions to grant or audit, and anything that changes a user account runs as a dry run first and waits for an explicit go.

Outcome

In daily use at the MSP I work for, running every fifteen minutes on weekdays during business hours.

Stack

  • Cloudflare Workers
  • MCP
  • PowerShell
  • Scheduled tasks
  • Runbooks

AI & AutomationLive

PS5 Price Watch

Canadian retailers checked every two hours for a console under its list price — and a desktop alert only when a deal is new.

  • Scraper
  • Scheduled task
  • Desktop alerts
  • No dependencies

Read the case study

Problem

Console deals in Canada appear and sell out between the moments anyone thinks to check, and the useful window ran up to a major game launch and Black Friday. Checking a dozen retailers by hand every few hours is not a plan.

Approach

A small watcher that reads a list of Canadian retailers, finds console listings, compares them with the list price and a set of trust rules, and raises a Windows notification when a deal it has not seen before appears. It runs as a scheduled task every two hours for the whole season.

Technical decision

Alert on what is new, not on what is there. The watcher keeps state between runs, so the same deal never alerts twice, and every rule — prices, thresholds, which sources to trust — lives in a config file rather than the code. No dependencies: Node’s built-in fetch, and an exit code that says whether anything new was found.

Outcome

Running on a schedule through the launch and Black Friday window.

Stack

  • Node
  • Built-in fetch
  • Windows Task Scheduler
  • Toast notifications
  • JSON config

AI & AutomationLive

FPL Brief

A weekly Fantasy Premier League brief, researched by AI agents: team news, fixtures, expected goals and prices, down to transfers and a captain.

  • AI research
  • Weekly brief
  • Fixture model
  • Live artifact

Read the case study

Problem

Fantasy football rewards whoever reads the most before the deadline: team news, rotation risk, fixture runs, expected goals, price changes and what the rest of a mini-league owns. Nobody has the hours for all of it every week.

Approach

A research workflow run by AI agents ahead of each deadline — team news, transfer credibility, odds, projections, price changes and league-relative ownership — distilled into one live brief with the transfers, the chip plan and the captain for the week.

Technical decision

Rules that survive a bad week. The brief keeps written principles learned the hard way — never override a strong fixture edge on one gameweek of expected goals, never sell into a price rise after a haul — so a noisy week cannot talk the plan out of what the longer data says.

Outcome

In use every gameweek this season, updated in place at the same link.

Stack

  • AI agents
  • Claude artifact
  • Expected goals
  • Fixture difficulty
  • Price tracking

Web AppsLive

Sip & Sit TO

A Toronto cafe review site maintained day to day by a non-technical operator, at zero running cost.

  • Self-serve editing
  • Photo galleries
  • Free tier only

Read the case study

Problem

A content site is only sustainable if the person running it can update it without a developer. Otherwise every new cafe, photograph or menu change becomes an engineering request and the site quietly stops being updated. The budget for a hosted CMS was zero.

Approach

A review site built around photo galleries and menus, with browser-based editing for the operator: add a cafe, add photographs to it, correct a menu. Hosting, image storage and the editing layer all run inside free tiers.

Technical decision

The editing surface was scoped to the two tasks the operator actually performs, rather than exposing a general admin panel. A generic CMS is a second product to learn; here the fields are ordered to match how the information arrives — on site, phone in hand.

Outcome

Live and maintained entirely by its operator, with no developer in the loop.

Stack

  • Static site
  • Self-serve editing
  • Photo galleries
  • Free tier hosting & storage

Web AppsLive

Cerulean Scents

A perfume storefront across hundreds of SKUs where every product image is verified before a customer can reach it.

  • Image manifest
  • Hundreds of SKUs
  • Storefront

Read the case study

Problem

A perfume catalogue is mostly photography, and vendor image sets are unreliable in several directions at once: filenames that do not match SKUs, one bottle with three shots and the next with none, the same scent spelled two ways. A catalogue that trusts the folder ships broken tiles to customers.

Approach

A storefront covering hundreds of SKUs, rendered from a verified image manifest — a checked mapping from SKU to the images that genuinely exist, generated rather than hand-maintained. Because rendering reads the manifest, a missing photograph is a known gap with a deliberate fallback instead of a broken image in front of a buyer.

Technical decision

The manifest is a build-time artifact, not a runtime lookup. Asking whether an image exists during rendering costs a request per SKU and fails in front of the customer; answering it up front turns a 404 someone else discovers into a diff reviewed before release — and keeps the storefront deployable as static output.

Outcome

Live, with the catalogue, verified imagery and commerce mechanics in place.

Stack

  • Verified image manifest
  • Static storefront
  • Build-time verification

InfrastructureLive

Immich Photo Server

A self-hosted photo library replacing Google Photos — a decade of images on owned hardware, with the features that justified the subscription.

  • Immich
  • Docker
  • Self-hosted
  • Linux

Read the case study

Problem

A growing photo library on a hosted service is both a recurring cost and a single point of vendor control over the least replaceable data a person owns. Migrating away later only gets harder as the library grows.

Approach

A self-hosted Immich deployment: full library imported, mobile auto-backup pointed at it, and the search and album features the hosted product was being paid for. Containerised, staged on existing hardware first, and written to migrate onto a dedicated Linux host without a rebuild.

Technical decision

Prove the import before buying the server. The risk in a photo migration is the data — a decade of files with inconsistent EXIF, live photos and duplicates left by earlier backup tools — not the machine. Validating against the real library on hardware already owned meant the hardware specification followed evidence rather than guesswork.

Outcome

Live and serving the full library, with mobile backup running against it.

Stack

  • Immich
  • Docker
  • Linux
  • Self-hosted storage
  • Mobile auto-backup

Web AppsLive

Ledger

A personal finance tracker that reads bank statements, checks itself against their printed totals, and never leaves home.

  • Local-first
  • Statement import
  • PWA
  • Self-hosted

Read the case study

Problem

Budgeting apps want bank credentials and a copy of every transaction in their cloud. Everything that matters is already in the monthly statement PDFs — the problem is reading them reliably, across issuers that each lay them out differently.

Approach

A local-first progressive web app. Statement PDFs from several banks and card issuers go in; transactions come out categorised, with a monthly position, cash-flow plan, insights, subscriptions and budgets. It runs in a container on a home server and is reachable from phone and PC only over a private network.

Technical decision

Every import proves itself. Each parsed statement is reconciled against the totals the bank printed on it, and a statement that does not add up is rejected rather than half-imported. Issuer quirks — amounts printed on the line below the description, interest-rate lines that look like totals — are handled per issuer and covered by that check.

Outcome

In daily use. No cloud, no CDNs, no external fonts and no bank credentials; one runtime dependency.

Stack

  • Node 24
  • node:sqlite
  • Vanilla JS PWA
  • pdf.js
  • Docker
  • Tailscale

Web AppsLive

NeoPDF

A self-hosted PDF toolkit covering the everyday Acrobat tasks — free to use, and no document ever leaves the machine.

  • Self-hosted
  • Local processing
  • No upload
  • Free

Read the case study

Problem

The operations people actually need — merge, split, reorder, sign, compress — sit behind a subscription, and the free web alternatives require uploading the document first. For files carrying signatures, invoices or identity documents, that is not an acceptable trade.

Approach

A PDF toolkit that runs entirely on the user's own machine: self-hosted, browser-based, no account and no upload step. The file never leaves the computer it started on.

Technical decision

Self-hosting is the product, not a deployment option. A privacy policy cannot be verified by the person relying on it; an architecture in which nothing is transmitted can be. That constraint gave up the conveniences a server would have provided, which is exactly why it is not negotiable later.

Outcome

Live and in use — free, self-hosted, no account required.

Stack

  • Self-hosted
  • Local processing
  • PDF toolkit
  • No upload, no account

Web AppsLive

Cerulean Arena

A physics-driven browser game — real vehicle dynamics, no install and no engine runtime in front of it.

  • Three.js
  • cannon-es
  • Vite
  • WebGL

Read the case study

Problem

Browser games usually trade away either fidelity or immediacy — a download on one side, an experience that feels scripted on the other. The target was WebGL-quality physics reachable from a link.

Approach

Vehicles accelerate down a runway, launch from curved ramps and attempt to reach defenders on a floating platform; overshoot and the far runway lets you turn around, leave the platform and the run ends. Three.js handles rendering, cannon-es solves the vehicle physics, Vite builds it.

Technical decision

Trajectories are solved, not animated. Scripted arcs are cheaper and repeat identically; delegating to a physics solver makes every landing emergent and moves the work to tuning mass, friction and ramp curvature. The simulation produces the variance that makes a second run worthwhile.

Outcome

Live and playable in the browser, with the source public.

Stack

  • Three.js
  • cannon-es
  • Vite
  • WebGL

Web AppsLive

nb.com — NB.OS

This site. A portfolio built as a desktop operating system — no framework, no build step, no dependencies to install.

  • Vanilla JS
  • No build step
  • Three.js
  • Canvas

Read the case study

Problem

A portfolio asserts capability; it rarely demonstrates it. A list of projects tells a reader what someone claims to have done. The page itself should be the evidence.

Approach

A bento landing that signs into NB.OS — a desktop with draggable windows, switchable wallpapers, a Windows/mac skin toggle, an interactive globe, a terminal, sixteen working dev tools and a printable resume. Vanilla HTML, CSS and JavaScript throughout. Three.js and globe.gl load from a CDN on demand, only at the moment an app requires them.

Technical decision

No build step, deliberately. A framework would have accelerated the window manager and guaranteed the site's decay — a lockfile that stops resolving in two years. Plain files remain openable indefinitely, and the constraint required writing the window manager, theme engine and canvas renderer directly rather than importing them.

Outcome

Live. Window manager, theme engine, wallpaper renderer and sixteen tools, with no dependencies at build time.

Stack

  • Vanilla HTML/CSS/JS
  • No build step
  • CSS design tokens
  • Canvas
  • Three.js on demand
  • globe.gl

Web AppsLive

PS5 Controller Tester

A single HTML file that diagnoses stick drift and dead inputs. Nothing to install and nothing to trust.

  • Gamepad API
  • Single file
  • Zero dependencies

Read the case study

Problem

Diagnosing a gamepad fault normally means installing software of uncertain provenance to answer a five-second question about hardware already in hand.

Approach

A one-file gamepad tester. Every button, trigger and stick axis responds live, with raw axis values displayed so drift reads as a number that will not settle rather than as a suspicion.

Technical decision

One file, no dependencies. The browser's Gamepad API already does the work; the engineering value is in adding nothing around it — no build, no bundle, nothing to install and nothing to trust.

Outcome

Live and self-contained, with nothing to maintain.

Stack

  • Gamepad API
  • Single HTML file
  • Zero dependencies

Web AppsLive

Playlist Builder

A list of track links in, a private Spotify playlist out — one sign-in, filled in batches.

  • Spotify Web API
  • OAuth
  • CLI
  • Batching

Read the case study

Problem

Moving a long list of songs into a playlist by hand means searching and adding each one. A list of links already says exactly which tracks they are.

Approach

A small command-line tool: it signs in once through the browser, creates a private playlist with a name and description, and adds every track from a text file in batches of a hundred, the most the API takes per request.

Technical decision

Credentials stay with the person running it. The app keys come from environment variables, the sign-in happens in the person’s own browser on a local callback, and nothing is stored — so the tool can be shared without sharing access.

Outcome

Built and used to assemble playlists from shared track lists.

Stack

  • Node
  • Spotify Web API
  • OAuth 2
  • Local callback server