<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>Torrin Leonard's blog</title>
	<subtitle>Notes on building software, running a homelab and the tools worth owning.</subtitle>
	<link rel="self" type="application/atom+xml" href="https://torrin.me/feed.xml"/>
	<link rel="alternate" type="text/html" href="https://torrin.me/blog"/>
	<id>https://torrin.me/blog</id>
	<updated>2026-09-30T18:20:00.000Z</updated>
	<author><name>Torrin Leonard</name><uri>https://torrin.me</uri></author>
	<entry>
		<title>KWBuilds Is Now Builderloo, With a Forum for Waterloo Builders</title>
		<link rel="alternate" type="text/html" href="https://torrin.me/blog/builderloo-rebrand"/>
		<id>https://torrin.me/blog/builderloo-rebrand</id>
		<published>2026-09-30T18:20:00.000Z</published>
		<updated>2026-09-30T18:20:00.000Z</updated>
		<summary>I rebranded KWBuilds as Builderloo. It lists Waterloo Region startups and events, it has a forum for posting what you're building, and The Weekly is back.</summary>
		<content type="html">&lt;div class=&quot;aw0&quot;&gt;&lt;p class=&quot;aw1&quot;&gt;I made a short about this. This is the longer version.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Dg0fRq_TtHo&quot;&gt;&lt;img src=&quot;https://torrin.me/media/builderloo-rebrand/youtube-Dg0fRq_TtHo.39e255df.jpg&quot; alt=&quot;KWBuilds is now Builderloo&quot; width=&quot;480&quot; height=&quot;270&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;I created a new website. Well, actually I rebranded an old one that I wasn't really happy with. The new site is called &lt;a href=&quot;https://builderloo.ca&quot; class=&quot;aw3&quot;&gt;builderloo.ca&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;why-it-exists&quot; class=&quot;aw2&quot;&gt;Why it exists&lt;/h2&gt;&lt;p class=&quot;aw1&quot;&gt;I created this website because I really wanted visibility into the Waterloo tech ecosystem. There's a lot of startups, there's a lot of events, there's a lot of people building really cool stuff, but there isn't a place to actually go and see it.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;So I made that website, and originally it took the shape of kwbuilds.ca. But the site itself wasn't really engaging. It was very black and white. So with Builderloo, I wanted to go in a different direction. Builderloo has a bright, colourful theme that in my mind represents what Waterloo Region tech is.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;kwbuilds.ca still works. Every old link sends you to the same page on builderloo.ca.&lt;/p&gt;&lt;h2 id=&quot;whats-on-it&quot; class=&quot;aw2&quot;&gt;What's on it&lt;/h2&gt;&lt;p class=&quot;aw1&quot;&gt;On the website you'll find a list of startups that are local to the Waterloo Region, and the events taking place throughout the region. There are also news articles that mention startups operating here, and a jobs page.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;On September 30 the site listed 698 local startups, 79 upcoming events and 114 open roles in the region.&lt;/p&gt;&lt;h2 id=&quot;the-forum&quot; class=&quot;aw2&quot;&gt;The forum&lt;/h2&gt;&lt;p class=&quot;aw1&quot;&gt;All of that's great, but I wasn't really happy with just leaving it there. The American tech sector has their own platform. They have Hacker News. And it's very saturated in American content. There isn't really a place built for Canadian entrepreneurs and Canadian builders.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;So I wanted to create a local forum where people could post about the stuff they're building, whether that's a startup or something as simple as a GitHub project. It's super simple. You post a link or a description of whatever you're working on, and you can get points and get visibility for your project.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;Start a title with Show:, Ask:, Jobs: or Event: and it goes in that section.&lt;/p&gt;&lt;h2 id=&quot;the-weekly&quot; class=&quot;aw2&quot;&gt;The Weekly&lt;/h2&gt;&lt;p class=&quot;aw1&quot;&gt;I've also restarted the KWBuilds newsletter under Builderloo. Every Monday morning you'll get a report on the week before: the new startups that joined, the startups mentioned in the news, who's hiring, and a bunch of other numbers about the ecosystem we live in.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;You can sign up on &lt;a href=&quot;https://builderloo.ca&quot; class=&quot;aw3&quot;&gt;builderloo.ca&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;If you're building something in Waterloo Region, post it on the forum.&lt;/p&gt;&lt;/div&gt;</content>
	</entry>
	<entry>
		<title>Claude Code Ignores My Rules, So a Tiny Model Checks Every Commit</title>
		<link rel="alternate" type="text/html" href="https://torrin.me/blog/jev-commit-rules"/>
		<id>https://torrin.me/blog/jev-commit-rules</id>
		<published>2026-09-27T00:00:00.000Z</published>
		<updated>2026-09-27T00:00:00.000Z</updated>
		<summary>Claude Code keeps sneaking metaphors into my comments, and markdown rules didn't stop it. So a small decision model called Jev now checks every commit against my rules.</summary>
		<content type="html">&lt;div class=&quot;aw0&quot;&gt;&lt;p class=&quot;aw10&quot;&gt;I made a short about this. This is the longer version.&lt;/p&gt;&lt;p class=&quot;aw10&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=DAcykJSP8XA&quot;&gt;&lt;img src=&quot;https://torrin.me/media/jev-commit-rules/youtube-DAcykJSP8XA.74c587ca.jpg&quot; alt=&quot;Jev checking Claude Code's commits&quot; width=&quot;480&quot; height=&quot;270&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;aw10&quot;&gt;Claude Code makes tons of mistakes. Whenever I'm using it, it always tries to sneak analogies and little metaphors into my comments and into the commit messages of my code base. It's really annoying.&lt;/p&gt;&lt;h2 id=&quot;rules-in-markdown-dont-stick&quot; class=&quot;aw11&quot;&gt;Rules in markdown don't stick&lt;/h2&gt;&lt;p class=&quot;aw10&quot;&gt;For the past year I've been setting up rules that Claude has to follow, in different markdown files, and constantly tweaking system prompts to get it to do what I want. Right now that's 11 CLAUDE.md files and 32 skills on my laptop, and 304 commits across my repos that edit a CLAUDE.md or AGENTS.md file.&lt;/p&gt;&lt;p class=&quot;aw10&quot;&gt;Even when I define a rule in a skill, in a memory or in my global CLAUDE.md, Claude still forgets it and breaks it. And when the next model comes out, it all kind of goes out the window and isn't as effective anymore.&lt;/p&gt;&lt;p class=&quot;aw10&quot;&gt;Here are three comments Claude wrote in my repos after I'd told it not to write like this:&lt;/p&gt;&lt;ul class=&quot;aw1&quot;&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw12&quot;&gt;&quot;in the accent on the page's paper.&quot;&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw12&quot;&gt;&quot;Silence would pass every other check here, so this one listens.&quot;&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw12&quot;&gt;&quot;so a listen lands on its drums, not its intro.&quot;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;jev&quot; class=&quot;aw11&quot;&gt;Jev&lt;/h2&gt;&lt;p class=&quot;aw10&quot;&gt;Last week a new model came out called &lt;a href=&quot;https://typesafe.ai&quot; class=&quot;aw14&quot;&gt;Jev&lt;/a&gt;, made by TypeSafe. The cool thing about it is that it's just a pure decision model. It doesn't output any text at all. You send it some text and a question about that text, and it gives back an answer your program can use, with how sure it is.&lt;/p&gt;&lt;p class=&quot;aw10&quot;&gt;It's really fast. In a test I ran on the 1,560 startups in &lt;a href=&quot;https://kwbuilds.ca&quot; class=&quot;aw14&quot;&gt;kwbuilds.ca&lt;/a&gt;, Jev's median answer took 213 ms. Claude Sonnet 5 took 1,262 ms on the same questions. Jev did all 1,560 for $0.19. Sonnet cost $1.64 for 150 of them.&lt;/p&gt;&lt;h2 id=&quot;the-setup&quot; class=&quot;aw11&quot;&gt;The setup&lt;/h2&gt;&lt;p class=&quot;aw10&quot;&gt;So I tasked Jev with guarding the commits to all the projects I'm working on. There are four rules right now:&lt;/p&gt;&lt;div tabindex=&quot;0&quot; class=&quot;aw3&quot;&gt;&lt;table class=&quot;aw4&quot;&gt;&lt;thead class=&quot;aw5&quot;&gt;&lt;tr&gt;&lt;th scope=&quot;col&quot; class=&quot;aw6&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;Rule&lt;/span&gt;&lt;/th&gt;&lt;th scope=&quot;col&quot; class=&quot;aw6&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;Checked by&lt;/span&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr class=&quot;aw7&quot;&gt;&lt;td class=&quot;aw8&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;No em dashes or dashes used as punctuation&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;aw8&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;regex&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;aw7&quot;&gt;&lt;td class=&quot;aw8&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;No semicolons in comments&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;aw8&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;regex&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;aw7&quot;&gt;&lt;td class=&quot;aw8&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;No metaphors, analogies or allegory&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;aw8&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;Jev&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;aw7&quot;&gt;&lt;td class=&quot;aw8&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;Speak plainly&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;aw8&quot;&gt;&lt;span class=&quot;aw13&quot;&gt;Jev&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p class=&quot;aw10&quot;&gt;The first two are easy, so they're a regex. There isn't a regex for a metaphor or an analogy. Maybe there is, maybe it's really complicated. So for those I ask Jev a question:&lt;/p&gt;&lt;blockquote class=&quot;aw9&quot;&gt;&lt;p class=&quot;aw12&quot;&gt;Does the text describe something as if it were something else: a metaphor, analogy or allegory?&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;aw10&quot;&gt;After Claude Code makes a commit, a hook sends every new comment, every doc block and the commit message through the rules. Anything Jev scores over 0.7 goes back to Claude, and Claude fixes it in the next commit. The drums comment above scored 0.77, and Claude rewrote it:&lt;/p&gt;&lt;ul class=&quot;aw1&quot;&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw12&quot;&gt;Before: &quot;so a listen lands on its drums, not its intro.&quot;&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw12&quot;&gt;After: &quot;so the recording has the drums in it and not the intro's fade.&quot;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;aw10&quot;&gt;The beauty of it is that I can create as many rules as I want.&lt;/p&gt;&lt;h2 id=&quot;where-it-slips&quot; class=&quot;aw11&quot;&gt;Where it slips&lt;/h2&gt;&lt;p class=&quot;aw10&quot;&gt;It isn't perfect. It flagged &quot;an older experiment bakes byte-identical to before&quot; at 0.83 as a metaphor, and that one is literal: the output really is the same bytes. So Claude doesn't just take the score. It judges the ones near the cutoff and records a verdict (fixed, false positive, missed or ok), and I use those verdicts to tune the cutoff.&lt;/p&gt;&lt;p class=&quot;aw10&quot;&gt;It also doesn't block a commit yet. The score comes back after the commit lands, so the fix is a second commit. Blocking before the commit is the next step.&lt;/p&gt;&lt;h2 id=&quot;whats-next&quot; class=&quot;aw11&quot;&gt;What's next&lt;/h2&gt;&lt;p class=&quot;aw10&quot;&gt;I've also been playing with &lt;a href=&quot;https://huggingface.co/convaiinnovations/laya&quot; class=&quot;aw14&quot;&gt;Laya&lt;/a&gt;, an open source model built on the same idea. It runs on my ThinkPad, which is kind of cool. It's slower because it's running on my laptop, about 590 ms for four questions, but it's also free. I haven't set it up with the commit check yet. That's next.&lt;/p&gt;&lt;p class=&quot;aw10&quot;&gt;It's a really annoying problem, and I think this is one of the best uses for this kind of model.&lt;/p&gt;&lt;/div&gt;</content>
	</entry>
	<entry>
		<title>I Wrote a Web Framework, and I Didn't Write It for People</title>
		<link rel="alternate" type="text/html" href="https://torrin.me/blog/aweft-for-agents"/>
		<id>https://torrin.me/blog/aweft-for-agents</id>
		<published>2026-09-23T22:10:00.000Z</published>
		<updated>2026-09-23T22:10:00.000Z</updated>
		<summary>Every framework assumes a human is reading the docs. An agent opens the repo cold every time, so I built aweft for that reader instead.</summary>
		<content type="html">&lt;div class=&quot;aw0&quot;&gt;&lt;p class=&quot;aw3&quot;&gt;I made a short about this: &lt;a href=&quot;https://www.youtube.com/shorts/Dcsu7z7do_0&quot; class=&quot;aw6&quot;&gt;watch it here&lt;/a&gt;. This is the longer version.&lt;/p&gt;&lt;p class=&quot;aw3&quot;&gt;Over the past year I've been building a lot with Claude Code. I built three sites, &lt;a href=&quot;https://maccobylab.com&quot; class=&quot;aw6&quot;&gt;maccobylab.com&lt;/a&gt;, &lt;a href=&quot;https://kwbuilds.ca&quot; class=&quot;aw6&quot;&gt;kwbuilds.ca&lt;/a&gt; and this one, all running on the same stack. It's called &lt;a href=&quot;https://aweft.dev&quot; class=&quot;aw6&quot;&gt;aweft&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;the-problem&quot; class=&quot;aw4&quot;&gt;The problem&lt;/h2&gt;&lt;p class=&quot;aw3&quot;&gt;Every framework I've ever used assumes a human is reading the documentation. You learn it once, you find the quirks, and you build up a picture in your head of how to use it properly.&lt;/p&gt;&lt;p class=&quot;aw3&quot;&gt;An agent doesn't get to keep that picture. Every time I open Claude Code, it starts cold. It has to read the repo again and relearn everything I told it in the last chat. Reading the docs every time isn't the problem. The problem is that it makes the same mistakes over and over again.&lt;/p&gt;&lt;p class=&quot;aw3&quot;&gt;So I kept asking myself the same question: what does a framework look like when it's built for agents?&lt;/p&gt;&lt;h2 id=&quot;the-boring-answer&quot; class=&quot;aw4&quot;&gt;The boring answer&lt;/h2&gt;&lt;p class=&quot;aw3&quot;&gt;The answer I found is boring. It's the best practices software teams have used for the last three decades. It's everything the cranky senior developer on your team loves about his repo:&lt;/p&gt;&lt;ul class=&quot;aw1&quot;&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;A ton of tests.&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;A strict linter you don't really get the point of.&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;Templates to follow, documentation, examples.&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;Logs that actually tell you what to fix, instead of telling you to go kick rocks.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;aw3&quot;&gt;None of that is new. What I couldn't find was a stack that does all of it in one place, consistently, every single time, with the same tools.&lt;/p&gt;&lt;h2 id=&quot;what-aweft-does&quot; class=&quot;aw4&quot;&gt;What aweft does&lt;/h2&gt;&lt;p class=&quot;aw3&quot;&gt;aweft puts all of that in one place and gives the agent room to fail fast, somewhere safe.&lt;/p&gt;&lt;ul class=&quot;aw1&quot;&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;&lt;strong class=&quot;aw7&quot;&gt;One reactive system, end to end.&lt;/strong&gt; An observer-based signals system carries every piece of data from the database, through the backend, to the DOM your users see.&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;&lt;strong class=&quot;aw7&quot;&gt;State you can inspect.&lt;/strong&gt; Every piece of state that passes through the stack can be logged and inspected. When something fails or breaks a schema, the agent building the system can see exactly what happened, in production or on your laptop.&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;&lt;strong class=&quot;aw7&quot;&gt;A build system that holds the line.&lt;/strong&gt; Frontend and backend modules have to match the systems you set up, instead of whatever the agent makes up on the fly.&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;&lt;strong class=&quot;aw7&quot;&gt;Standards in the build.&lt;/strong&gt; WCAG accessibility and ASVS security checks are part of the build, so the tests fail when an agent breaks something.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;aw3&quot;&gt;It's 23 packages behind one gate, with more than 250 design notes, one per decision.&lt;/p&gt;&lt;h2 id=&quot;why&quot; class=&quot;aw4&quot;&gt;Why&lt;/h2&gt;&lt;p class=&quot;aw3&quot;&gt;Humans have spent decades figuring out how to build really good software. aweft gives agents the tools and the guardrails to do the same.&lt;/p&gt;&lt;p class=&quot;aw3&quot;&gt;It's MIT licensed. Check it out on &lt;a href=&quot;https://github.com/torrinworx/aweft&quot; class=&quot;aw6&quot;&gt;GitHub&lt;/a&gt; or at &lt;a href=&quot;https://aweft.dev&quot; class=&quot;aw6&quot;&gt;aweft.dev&lt;/a&gt;, and build something great.&lt;/p&gt;&lt;/div&gt;</content>
	</entry>
	<entry>
		<title>I Walked Into Elevate and Walked Out of Nrth</title>
		<link rel="alternate" type="text/html" href="https://torrin.me/blog/nrth-day-one"/>
		<id>https://torrin.me/blog/nrth-day-one</id>
		<published>2026-09-23T16:05:00.000Z</published>
		<updated>2026-09-23T16:05:00.000Z</updated>
		<summary>Day one of the festival that used to be Elevate. They renamed it during their own opening night, and I happened to be in the room.</summary>
		<content type="html">&lt;div class=&quot;aw0&quot;&gt;&lt;p class=&quot;aw3&quot;&gt;I went to the opening night of Elevate at Meridian Hall in Toronto on Tuesday night. About an hour and fifteen minutes in, a video played that ended with &quot;The world has changed, and so we're changing too.&quot; Then the CEO came out on stage as the CEO of &lt;strong class=&quot;aw6&quot;&gt;Nrth&lt;/strong&gt;.&lt;/p&gt;&lt;p class=&quot;aw3&quot;&gt;Elevate renamed itself in the middle of its own kickoff.&lt;/p&gt;&lt;p class=&quot;aw3&quot;&gt;Looking back, the clues were there. The branding in the hall felt a little off, and our badges had no name or logo on them. She called that out on stage: you could leave your badge blank to prove you were there for the reveal, or grab a Nrth sticker on the way out. When I walked out of the hall, the whole place had changed over. New signs, and blue everywhere. It was a fun thing to see happen live.&lt;/p&gt;&lt;h2 id=&quot;why-the-rename&quot; class=&quot;aw4&quot;&gt;Why the rename&lt;/h2&gt;&lt;p class=&quot;aw3&quot;&gt;The CEO said that when they started Elevate in 2017, the idea was that you shouldn't have to leave Canada to build a company that matters globally. They still believe that. But she said people don't only want a spotlight anymore. They want direction: which technologies actually matter, who to partner with, and how to make decisions when things move this fast. That's what Nrth is supposed to be.&lt;/p&gt;&lt;h2 id=&quot;the-rest-of-the-night&quot; class=&quot;aw4&quot;&gt;The rest of the night&lt;/h2&gt;&lt;p class=&quot;aw3&quot;&gt;Before the reveal there was a round of short startup pitches. They ranged from at-home breast cancer screening to software for grocery stores that still order stock the way they did 30 years ago.&lt;/p&gt;&lt;p class=&quot;aw3&quot;&gt;After it, the host summed up the program pretty honestly: &quot;AI, a little more AI, a little more AI, a little more AI, and then basketball.&quot; A few things stuck with me:&lt;/p&gt;&lt;ul class=&quot;aw1&quot;&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;&lt;strong class=&quot;aw6&quot;&gt;Cohere and TD&lt;/strong&gt; talked about AI moving past pilots and proofs of concept. Their point was that the hard part now isn't the technology. It's getting a company to actually adopt it.&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;&lt;strong class=&quot;aw6&quot;&gt;DuckDuckGo&lt;/strong&gt; argued that the best way to protect people's data is to not collect it in the first place. They also showed a spoof ad for &quot;anti-surveillance smart glasses&quot;, which were just normal sunglasses.&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw2&quot;&gt;&lt;p class=&quot;aw5&quot;&gt;&lt;strong class=&quot;aw6&quot;&gt;Mistral&lt;/strong&gt; talked about sovereign AI: owning your models, data and compute so nobody can switch them off on you.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;aw3&quot;&gt;As someone who builds AI products, the adoption point is the one I keep thinking about. Nobody on stage was short on models. Everyone was trying to figure out how to get people to use them well.&lt;/p&gt;&lt;h2 id=&quot;days-two-and-three&quot; class=&quot;aw4&quot;&gt;Days two and three&lt;/h2&gt;&lt;p class=&quot;aw3&quot;&gt;That was only opening night. I met some great people and made some good connections, and I'm back for the next two days. If you're at Nrth, send me a message and let's meet up. I'll write up the rest when it's over.&lt;/p&gt;&lt;/div&gt;</content>
	</entry>
	<entry>
		<title>Kimai time tracker setup guide.</title>
		<link rel="alternate" type="text/html" href="https://torrin.me/blog/kimai-setup"/>
		<id>https://torrin.me/blog/kimai-setup</id>
		<published>2026-01-29T04:17:00.000Z</published>
		<updated>2026-01-29T04:17:00.000Z</updated>
		<summary>A quick, copy-paste Docker Compose setup for running Kimai with a MySQL backend. It walks you through creating a .env, launching the stack, and getting Kimai reachable on port 8001.</summary>
		<content type="html">&lt;div class=&quot;aw0&quot;&gt;&lt;blockquote class=&quot;aw1&quot;&gt;&lt;p class=&quot;aw14&quot;&gt;Read the full story of how Kimai saved my parent's company $28,800 (post coming) Official docs: https://www.kimai.org/documentation/docker-compose.html&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id=&quot;quick-kimai-docker-compose-setup&quot; class=&quot;aw6&quot;&gt;Quick Kimai (Docker Compose) Setup&lt;/h2&gt;&lt;ol class=&quot;aw2&quot;&gt;&lt;li class=&quot;aw3&quot;&gt;&lt;p class=&quot;aw14&quot;&gt;Create a folder and add these two files:&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p class=&quot;aw7&quot;&gt;&lt;strong class=&quot;aw15&quot;&gt;&lt;code class=&quot;aw16&quot;&gt;.env&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; class=&quot;aw4&quot;&gt;&lt;code&gt;&lt;span class=&quot;aw8&quot;&gt;DATABASE_NAME&lt;/span&gt;&lt;span class=&quot;aw9&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;aw10&quot;&gt;kimai&lt;/span&gt;
&lt;span class=&quot;aw8&quot;&gt;DATABASE_USER&lt;/span&gt;&lt;span class=&quot;aw9&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;aw10&quot;&gt;kimai&lt;/span&gt;
&lt;span class=&quot;aw8&quot;&gt;DATABASE_PASSWORD&lt;/span&gt;&lt;span class=&quot;aw9&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;aw10&quot;&gt;change-me&lt;/span&gt;
&lt;span class=&quot;aw8&quot;&gt;DATABASE_ROOT_PASSWORD&lt;/span&gt;&lt;span class=&quot;aw9&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;aw10&quot;&gt;change-me-too&lt;/span&gt;

&lt;span class=&quot;aw8&quot;&gt;ADMIN_EMAIL&lt;/span&gt;&lt;span class=&quot;aw9&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;aw10&quot;&gt;admin@example.com&lt;/span&gt;
&lt;span class=&quot;aw8&quot;&gt;ADMIN_PASSWORD&lt;/span&gt;&lt;span class=&quot;aw9&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;aw10&quot;&gt;change-this-now&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;aw7&quot;&gt;&lt;strong class=&quot;aw15&quot;&gt;&lt;code class=&quot;aw16&quot;&gt;docker-compose.yml&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; class=&quot;aw4&quot;&gt;&lt;code&gt;&lt;span class=&quot;aw11&quot;&gt;services&lt;/span&gt;:
  &lt;span class=&quot;aw11&quot;&gt;sqldb&lt;/span&gt;:
    &lt;span class=&quot;aw11&quot;&gt;image&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;mysql:8.3&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;volumes&lt;/span&gt;:
      - &lt;span class=&quot;aw10&quot;&gt;./mysql:/var/lib/mysql&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;environment&lt;/span&gt;:
      &lt;span class=&quot;aw11&quot;&gt;MYSQL_DATABASE&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;${DATABASE_NAME}&lt;/span&gt;
      &lt;span class=&quot;aw11&quot;&gt;MYSQL_USER&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;${DATABASE_USER}&lt;/span&gt;
      &lt;span class=&quot;aw11&quot;&gt;MYSQL_PASSWORD&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;${DATABASE_PASSWORD}&lt;/span&gt;
      &lt;span class=&quot;aw11&quot;&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;${DATABASE_ROOT_PASSWORD}&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;command&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;--default-storage-engine innodb&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;restart&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;healthcheck&lt;/span&gt;:
      &lt;span class=&quot;aw11&quot;&gt;test&lt;/span&gt;: [&lt;span class=&quot;aw10&quot;&gt;&quot;CMD-SHELL&quot;&lt;/span&gt;, &lt;span class=&quot;aw10&quot;&gt;&quot;mysqladmin -p$$MYSQL_ROOT_PASSWORD ping -h localhost&quot;&lt;/span&gt;]
      &lt;span class=&quot;aw11&quot;&gt;interval&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;20s&lt;/span&gt;
      &lt;span class=&quot;aw11&quot;&gt;start_period&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;10s&lt;/span&gt;
      &lt;span class=&quot;aw11&quot;&gt;timeout&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;10s&lt;/span&gt;
      &lt;span class=&quot;aw11&quot;&gt;retries&lt;/span&gt;: &lt;span class=&quot;aw12&quot;&gt;3&lt;/span&gt;

  &lt;span class=&quot;aw11&quot;&gt;kimai&lt;/span&gt;:
    &lt;span class=&quot;aw11&quot;&gt;image&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;kimai/kimai2:apache&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;depends_on&lt;/span&gt;:
      - &lt;span class=&quot;aw10&quot;&gt;sqldb&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;volumes&lt;/span&gt;:
      - &lt;span class=&quot;aw10&quot;&gt;./data:/opt/kimai/var/data&lt;/span&gt;
      - &lt;span class=&quot;aw10&quot;&gt;./plugins:/opt/kimai/var/plugins&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;ports&lt;/span&gt;:
      - &lt;span class=&quot;aw10&quot;&gt;&quot;8001:8001&quot;&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;environment&lt;/span&gt;:
      &lt;span class=&quot;aw11&quot;&gt;ADMINMAIL&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;${ADMIN_EMAIL}&lt;/span&gt;
      &lt;span class=&quot;aw11&quot;&gt;ADMINPASS&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;${ADMIN_PASSWORD}&lt;/span&gt;
      &lt;span class=&quot;aw11&quot;&gt;DATABASE_URL&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;&quot;mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@sqldb/${DATABASE_NAME}?charset=utf8mb4&amp;amp;serverVersion=8.3.0&quot;&lt;/span&gt;
    &lt;span class=&quot;aw11&quot;&gt;restart&lt;/span&gt;: &lt;span class=&quot;aw10&quot;&gt;unless-stopped&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&quot;2&quot; class=&quot;aw2&quot;&gt;&lt;li class=&quot;aw3&quot;&gt;&lt;p class=&quot;aw14&quot;&gt;Start it:&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; class=&quot;aw4&quot;&gt;&lt;code&gt;&lt;span class=&quot;aw13&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;aw10&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;aw10&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;aw10&quot;&gt;-d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&quot;3&quot; class=&quot;aw2&quot;&gt;&lt;li class=&quot;aw3&quot;&gt;&lt;p class=&quot;aw14&quot;&gt;Open it:&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;ul class=&quot;aw5&quot;&gt;&lt;li class=&quot;aw3&quot;&gt;&lt;p class=&quot;aw14&quot;&gt;http://localhost:8001&lt;/p&gt;&lt;/li&gt;&lt;li class=&quot;aw3&quot;&gt;&lt;p class=&quot;aw14&quot;&gt;Login: &lt;code class=&quot;aw16&quot;&gt;${ADMIN_EMAIL}&lt;/code&gt; / &lt;code class=&quot;aw16&quot;&gt;${ADMIN_PASSWORD}&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</content>
	</entry>
	<entry>
		<title>When is the best time to Open Source?</title>
		<link rel="alternate" type="text/html" href="https://torrin.me/blog/when-to-open-source"/>
		<id>https://torrin.me/blog/when-to-open-source</id>
		<published>2025-07-15T00:00:00.000Z</published>
		<updated>2025-07-15T00:00:00.000Z</updated>
		<summary>When is the best time to take that private repo public? Does it matter if everything is working?</summary>
		<content type="html">&lt;div class=&quot;aw0&quot;&gt;&lt;p class=&quot;aw1&quot;&gt;Open sourcing a project you've been working on for months is daunting. It means complete strangers are going to be able to use and critique your code, your choices, and ultimately your intelligence. Sounds scary and anxiety inducing, right?&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;Wrong. In reality, and I don't mean to knock your project, in the vast majority of cases no one will care.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;Why am I saying this? Because it makes it important to open source your project immediately, if your intent is to gain an audience, a following, and grow a user base. Open source early and often. It doesn't matter what the quality of the code is, or even if everything is fully functional and working. The idea with open sourcing before anything is ready is that you expose your idea to the internet, to Google, to people just browsing around GitHub, Reddit, or dev.to.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;People are too protective of their code. They think they are mastermind artists, and everything must be in its place. It must be production ready before others lay their hands on it.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;The honest truth: no one cares, and no one will even know your code exists. When you go open source, the commit history of your git repo is etched in the stone that Linus Torvalds cut from the mountain himself. Unless you're a masochist, that is.&lt;/p&gt;&lt;p class=&quot;aw1&quot;&gt;I did this with &lt;a href=&quot;https://github.com/torrinworx/aweft&quot; class=&quot;aw2&quot;&gt;aweft&lt;/a&gt;, my UI stack, in September 2026. It went public in five batches over two days: the working notes out of the repo and a vocabulary check in, a pass over every source file, test, recipe and README, the front door (the README, the licence, the contributing guide, the manifests), the history tidied in a fresh clone, and then five fresh agent builders handed nothing but the repo and asked to build a page from it. Their friction list fell from 37 entries to 29, their workarounds from 21 to 2, and none of them got stuck. That last batch is the one that mattered: the repo had to stand on its own for a stranger, and the way to find out was to hand it to one.&lt;/p&gt;&lt;/div&gt;</content>
	</entry>
</feed>
