[{"content":"If you\u0026rsquo;ve ever tuned a CUDA kernel, you know the dance: pick a block size, count registers per thread (or let nvcc tell you with --ptxas-options=-v), figure out how much shared memory you\u0026rsquo;re using, and then work out how many of those blocks can actually live on an SM at once. NVIDIA used to ship a spreadsheet for this - it was great, but a spreadsheet is exactly the friction I don\u0026rsquo;t want when I\u0026rsquo;m halfway through optimising a kernel and just want a quick \u0026ldquo;is the limiting factor registers or shared memory here?\u0026rdquo; answer.\nThe CUDA occupancy calculator on the Toolbelt is the same idea, just as a page you can pull up next to your editor. You pick a GPU, plug in block size, registers per thread, and shared memory per block, and it gives you the resident blocks per SM, the theoretical occupancy, and - the bit I actually use - which resource is the bottleneck. There\u0026rsquo;s also a sweep over candidate block sizes so you can see at a glance whether jumping from 128 to 256 threads buys you anything.\nIt\u0026rsquo;s not a replacement for actually profiling with Nsight Compute (nothing is), but it\u0026rsquo;s a really fast way to rule out the obvious \u0026ldquo;you\u0026rsquo;re register-bound, drop the block size\u0026rdquo; class of mistake before you spend an hour on a profile.\n","permalink":"https://widgita.xyz/posts/2026/04/a-cuda-occupancy-calculator-you-can-just-pull-up/","summary":"\u003cp\u003eIf you\u0026rsquo;ve ever tuned a CUDA kernel, you know the dance: pick a block size, count registers per thread (or let \u003ccode\u003envcc\u003c/code\u003e tell you with \u003ccode\u003e--ptxas-options=-v\u003c/code\u003e), figure out how much shared memory you\u0026rsquo;re using, and then work out how many of those blocks can actually live on an SM at once. NVIDIA used to ship a spreadsheet for this - it was great, but a spreadsheet is exactly the friction I don\u0026rsquo;t want when I\u0026rsquo;m halfway through optimising a kernel and just want a quick \u0026ldquo;is the limiting factor \u003cem\u003eregisters\u003c/em\u003e or \u003cem\u003eshared memory\u003c/em\u003e here?\u0026rdquo; answer.\u003c/p\u003e","title":"A CUDA Occupancy Calculator You Can Just Pull Up"},{"content":"Every now and then I need to peek inside a JWT - debugging an auth flow, sanity-checking what scopes a CI service account actually has, or figuring out why a token is being rejected at 23:00 the night before a release. And every time, I\u0026rsquo;d catch myself reaching for whatever JWT decoder Google surfaced first, pasting in a token, and then immediately feeling slightly icky about it. That token might be a service credential. It might still be valid for another six hours. And I just handed it to some random subdomain.\nSo one of the first things I built into the Widgita Toolbelt was a JWT decoder that runs entirely in the browser. Paste a token, get the header and payload split out cleanly, see when it expires (and whether it already has), and that\u0026rsquo;s it. No request leaves your machine for the decoding itself — the page is static HTML and a small chunk of vanilla JS. You can verify that yourself in the network tab, which is kind of the whole point.\nIt deliberately doesn\u0026rsquo;t verify signatures (that needs the issuer\u0026rsquo;s key and is a different problem), but for the 95% case of \u0026ldquo;what\u0026rsquo;s actually in this thing\u0026rdquo;, it\u0026rsquo;s the tool I keep open in a pinned tab.\n","permalink":"https://widgita.xyz/posts/2026/04/a-jwt-decoder-that-doesnt-phone-home/","summary":"\u003cp\u003eEvery now and then I need to peek inside a JWT - debugging an auth flow, sanity-checking what scopes a CI service account actually has, or figuring out \u003cem\u003ewhy\u003c/em\u003e a token is being rejected at 23:00 the night before a release. And every time, I\u0026rsquo;d catch myself reaching for whatever JWT decoder Google surfaced first, pasting in a token, and then immediately feeling slightly icky about it. That token might be a service credential. It might still be valid for another six hours. And I just handed it to some random subdomain.\u003c/p\u003e","title":"A JWT Decoder That Doesn't Phone Home"},{"content":"I used file watching loops for almost my entire career (professionally and personally). It\u0026rsquo;s always been a for loop or os.walk or similar (C/C++/Python/SBCL/\u0026hellip;), and it was always lots of boilerplate code. Not difficult, just a bunch of lines to maintain and make sure they catch all corner cases.\nWhile setting up this blogging pipeline (thank goodness I can just concentrate on the typing part and deployment happens automagically) I got to learn about gorakhargosh\u0026rsquo;s watchdog Python library. You should totally check out their GitHub page for the project! It\u0026rsquo;s a bit dated, but does the job perfectly fine!\nBasically, all you do is:\nfrom watchdog.observers import Observer from watchdog.events import FileSystemEventHandler, FileSystemEvent WATCH_THIS_PATH = \u0026#34;/home/me/Documents\u0026#34; class FileChangeHandler(FileSystemEventHandler): def __init__(self, path): super().__init__() self.path = path def on_any_event(self, event: FileSystemEvent): if event.is_directory: return rel_path = Path(event.src_path).relative_to(VAULT_PATH) timestamp = datetime.now(TIMEZONE).strftime(\u0026#34;%H:%M:%S\u0026#34;) match event.event_type: case \u0026#34;created\u0026#34;: print(f\u0026#34;[{timestamp}] + {rel_path}\u0026#34;) case \u0026#34;modified\u0026#34;: print(f\u0026#34;[{timestamp}] ~ {rel_path}\u0026#34;) case \u0026#34;deleted\u0026#34;: print(f\u0026#34;[{timestamp}] - {rel_path}\u0026#34;) case \u0026#34;moved\u0026#34;: rel_dest = Path(event.dest_path).relative_to(VAULT_PATH) print(f\u0026#34;[{timestamp}] → {rel_path} -\u0026gt; {rel_dest}\u0026#34;) case _: return handler = FileChangeHandler() observer = Observer() observer.schedule(handler, str(WATCH_THIS_PATH), recursive=True) observer.start() try: while True: now = datetime.now(TIMEZONE) seconds_until_midnight = ( (24 - now.hour - 1) * 3600 + (60 - now.minute - 1) * 60 + (60 - now.second) ) time.sleep(min(seconds_until_midnight, 60)) except KeyboardInterrupt: pass observer.stop() observer.join() This gives you a basic scaffolding for watching a folder and reacting to any file changes (and even by what happened to the file exactly - created, modified, deleted, moved).\nThis is an amazingly handy library. Self-contained, and it gets the job done, cleanly.\n","permalink":"https://widgita.xyz/posts/2026/04/automated-folder-watching/","summary":"\u003cp\u003eI used file watching loops for almost my entire career (professionally and personally). It\u0026rsquo;s always been a \u003ccode\u003efor\u003c/code\u003e loop or \u003ccode\u003eos.walk\u003c/code\u003e or similar (C/C++/Python/SBCL/\u0026hellip;), and it was always lots of boilerplate code. Not difficult, just a bunch of lines to maintain and make sure they catch all corner cases.\u003c/p\u003e\n\u003cp\u003eWhile setting up this blogging pipeline (thank goodness I can just concentrate on the \u003cem\u003etyping\u003c/em\u003e part and deployment happens automagically) I got to learn about gorakhargosh\u0026rsquo;s \u003ccode\u003ewatchdog\u003c/code\u003e Python library. You should totally check out \u003ca href=\"https://github.com/gorakhargosh/watchdog\"\u003etheir GitHub page\u003c/a\u003e for the project! It\u0026rsquo;s a bit dated, but does the job perfectly fine!\u003c/p\u003e","title":"Automated Folder Watching"},{"content":"Half my life as an engineer is moving things between configuration formats. A Helm chart wants YAML, the Rust crate wants TOML, the GitHub Action wants YAML again (but a slightly different dialect, naturally), and the thing I\u0026rsquo;m shipping it all into wants JSON. I always end up doing one of two things: opening some random web converter and pasting in a config that probably contains internal hostnames, or writing a five-line Python snippet that I\u0026rsquo;ll write again next week because I never bother to save it.\nThe JSON ↔ YAML ↔ TOML converter on the Toolbelt is the version of that random web converter that I actually trust. Same as the rest of the tools, it parses and serialises entirely in the browser - your config never leaves the page. What I appreciate most is that when something doesn\u0026rsquo;t parse, it tells you where (line and column) and what it expected, instead of the usual \u0026ldquo;syntax error\u0026rdquo; wall. YAML in particular has roughly seventeen ways to be subtly wrong, and a useful diagnostic saves a lot of squinting.\nIt also formats and lints the input in place, which is handy when you just want to clean up an kubectl get -o yaml blob before sticking it in a PR.\n","permalink":"https://widgita.xyz/posts/2026/04/converting-between-json-yaml-and-toml-without-the-awkwardness/","summary":"\u003cp\u003eHalf my life as an engineer is moving things between configuration formats. A Helm chart wants YAML, the Rust crate wants TOML, the GitHub Action wants YAML again (but a slightly different dialect, naturally), and the thing I\u0026rsquo;m shipping it all into wants JSON. I always end up doing one of two things: opening some random web converter and pasting in a config that probably contains internal hostnames, or writing a five-line Python snippet that I\u0026rsquo;ll write again next week because I never bother to save it.\u003c/p\u003e","title":"Converting Between JSON, YAML, and TOML Without the Awkwardness"},{"content":"The question I get asked most often when someone wants to ship an LLM-powered feature is, basically, \u0026ldquo;okay but what\u0026rsquo;s this going to cost?\u0026rdquo; And the honest answer is it depends on a lot of things you haven\u0026rsquo;t decided yet: which model, what precision, how many tokens per request, how many requests per second at peak, whether you self-host or pay an API provider per token, and whether you can tolerate the cold-start of a serverless GPU. Most of those have order-of-magnitude effects, so a back-of-envelope number can be off by 10x in either direction.\nThe LLM inference cost estimator on the Toolbelt is my attempt at making that back-of-envelope a bit less hand-wavy. You describe the workload - model, precision, traffic profile - and it gives you an engineering estimate of how many GPUs you\u0026rsquo;d need and what the monthly bill looks like across a few common providers and self-hosted GPU options. The point isn\u0026rsquo;t to give you a number you\u0026rsquo;d staple to a contract; it\u0026rsquo;s to give you a defensible number you can use to decide whether to keep going, switch model size, or just call the OpenAI API and move on.\nAll the reference data (GPU specs, provider prices, model presets) is shipped with the page and dated, so you can see exactly when the numbers were last refreshed. As with the rest of the Toolbelt, nothing about your workload leaves your browser.\n","permalink":"https://widgita.xyz/posts/2026/04/how-much-will-serving-this-llm-actually-cost/","summary":"\u003cp\u003eThe question I get asked most often when someone wants to ship an LLM-powered feature is, basically, \u0026ldquo;okay but what\u0026rsquo;s this going to cost?\u0026rdquo; And the honest answer is \u003cem\u003eit depends on a lot of things you haven\u0026rsquo;t decided yet\u003c/em\u003e: which model, what precision, how many tokens per request, how many requests per second at peak, whether you self-host or pay an API provider per token, and whether you can tolerate the cold-start of a serverless GPU. Most of those have order-of-magnitude effects, so a back-of-envelope number can be off by 10x in either direction.\u003c/p\u003e","title":"How Much Will Serving This LLM Actually Cost?"},{"content":"Welcome to Widgita. This first post confirms that the Hugo pipeline picks up Markdown straight from my Obsidian vault and deploys it to my blog.\nI always wanted to try out this level of automation, and I love the fact that it integrates well with my favourite tools.\nThis blog will be my personal scratchpad for any experiments, tryouts, developments, projects, etc. that I do. Mainly for my half personal/half professional growth; and maybe someone else finds interesting crumbs of knowledge, tooling links, or inspiration in it.\n","permalink":"https://widgita.xyz/posts/2026/04/posting-pipeline-all-set-up/","summary":"\u003cp\u003eWelcome to Widgita. This first post confirms that the Hugo pipeline picks up\nMarkdown straight from my Obsidian vault and deploys it to my blog.\u003c/p\u003e\n\u003cp\u003eI always wanted to try out this level of automation, and I love the fact that it integrates well with my favourite tools.\u003c/p\u003e\n\u003cp\u003eThis blog will be my personal scratchpad for any experiments, tryouts, developments, projects, etc. that I do. Mainly for my half personal/half professional growth; and maybe someone else finds interesting crumbs of knowledge, tooling links, or inspiration in it.\u003c/p\u003e","title":"Posting Pipeline All Set Up"},{"content":"Cron is one of those things I\u0026rsquo;ve been using for twenty-odd years and still occasionally stare at for thirty seconds before committing. Is */15 9-17 * * 1-5 what I think it is? Does 0 0 * * 0 fire at midnight Sunday or Monday? And does that depend on the box\u0026rsquo;s timezone or UTC? Most of the time you can squint and reason your way through it, but \u0026ldquo;most of the time\u0026rdquo; is exactly the kind of confidence level you don\u0026rsquo;t want when the cron in question is the nightly DB backup.\nThe cron expression explainer on the Toolbelt is meant to take the squinting out of the loop. You paste an expression, and it gives you a plain-English summary, a per-field breakdown (so you can see which field is doing the weird thing), and the next handful of run times in a timezone of your choice. The schedule preview is the bit I use most - it\u0026rsquo;s much faster to confirm \u0026ldquo;yes, that fires at the times I expect\u0026rdquo; than to reason about the cardinality of */15 from first principles.\nIt handles the standard 5-field syntax plus the common shortcuts (@daily, @weekly, etc.). No more \u0026ldquo;I think this is right, let\u0026rsquo;s see in production\u0026rdquo;.\n","permalink":"https://widgita.xyz/posts/2026/04/stop-second-guessing-cron-expressions/","summary":"\u003cp\u003eCron is one of those things I\u0026rsquo;ve been using for twenty-odd years and still occasionally stare at for thirty seconds before committing. Is \u003ccode\u003e*/15 9-17 * * 1-5\u003c/code\u003e what I think it is? Does \u003ccode\u003e0 0 * * 0\u003c/code\u003e fire at midnight Sunday or Monday? And does that depend on the box\u0026rsquo;s timezone or UTC? Most of the time you can squint and reason your way through it, but \u0026ldquo;most of the time\u0026rdquo; is exactly the kind of confidence level you don\u0026rsquo;t want when the cron in question is the nightly DB backup.\u003c/p\u003e","title":"Stop Second-Guessing Cron Expressions"}]