{"@attributes":{"version":"2.0"},"channel":{"title":"Home on dhruv's devlog","link":"https:\/\/devlog.dhruvs.space\/","description":"Recent content in Home on dhruv's devlog","generator":"Hugo -- gohugo.io","language":"en-us","copyright":"\u00a9 2026 dhruv","lastBuildDate":"Fri, 06 Mar 2026 00:00:00 +0000","item":[{"title":"#003: omm - support for themes","link":"https:\/\/devlog.dhruvs.space\/build-bytes\/003\/","pubDate":"Fri, 06 Mar 2026 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/build-bytes\/003\/","description":"<hr>\n<p><a href=\"https:\/\/github.com\/dhth\/omm\">omm<\/a> <a href=\"https:\/\/github.com\/dhth\/omm\/releases\/tag\/v0.7.0\">v0.7.0<\/a> is out. It now ships with a bunch of built-in themes.<\/p>\n<p>To make choosing a theme easier, <code>omm<\/code>&rsquo;s TUI allows the user to switch between\nthemes via two keymaps: <code>[<\/code> and <code>]<\/code>. Once the user has chosen their preferred\ntheme, they can have <code>omm<\/code> always start with that theme via the usual pathways\nof providing configuration (flag\/environment variable\/config file).<\/p>\n<p>This is a feature I always appreciate in the software I use; looking forward to\ngetting some feedback on this from users.<\/p>"},{"title":"#012: Building my own coding agent: Human-in-the-loop","link":"https:\/\/devlog.dhruvs.space\/log\/012\/","pubDate":"Mon, 05 Jan 2026 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/012\/","description":"<hr>\n<p>One of the first things I wanted to do after <a href=\"https:\/\/devlog.dhruvs.space\/log\/011\">setting up the foundations<\/a> for my\ncoding agent, <a href=\"https:\/\/github.com\/dhth\/agx\">agx<\/a>, was to add human-in-the-loop (HITL) controls to it. These\ncontrols allow the user to:<\/p>\n<ul>\n<li>Require explicit approval before running tool calls (creating\/editing files,\nrunning bash commands, etc.)<\/li>\n<li>Reject tool calls (with optional feedback to alter the approach taken)<\/li>\n<li>Interrupt the conversation at any time<\/li>\n<\/ul>\n<p>Controls like these are non-negotiable for any coding agent that can perform\ndestructive actions on the user&rsquo;s machine. Without them, a single hallucinated\n<code>rm -rf<\/code> or an overzealous file edit could cause real damage. However,\nimplementing HITL controls adds complexity to the agentic loop \u2014 state\nmanagement becomes trickier, and edge cases multiply. This post describes how I\nadded such controls to <code>agx<\/code> and how it led to a fundamental change in its\narchitecture.<\/p>"},{"title":"#002: punchout v1.3.0 - MCP support","link":"https:\/\/devlog.dhruvs.space\/build-bytes\/002\/","pubDate":"Wed, 24 Dec 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/build-bytes\/002\/","description":"<hr>\n<p><a href=\"https:\/\/github.com\/dhth\/punchout\/releases\/tag\/v1.3.0\">punchout<\/a> <code>v1.3.0<\/code> is out with a feature that has completely changed how I use\nthe tool: an MCP server.<\/p>\n<p>Before, I manually added JIRA worklogs via <code>punchout<\/code>&rsquo;s TUI. But now, the MCP\nserver lets me log time for several days within a matter of seconds. I only need\nto maintain a text file which roughly states what I worked on. For example:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"><code class=\"language-text\" data-lang=\"text\"><span style=\"display:flex;\"><span>2025-12-24\n<\/span><\/span><span style=\"display:flex;\"><span>candidate like this (2h)\n<\/span><\/span><span style=\"display:flex;\"><span>people data loss (1.5h)\n<\/span><\/span><span style=\"display:flex;\"><span>cap meeting (1h)\n<\/span><\/span><span style=\"display:flex;\"><span>lunch\n<\/span><\/span><span style=\"display:flex;\"><span>people data loss (1.5h)\n<\/span><\/span><span style=\"display:flex;\"><span>non cap work (3h)\n<\/span><\/span><span style=\"display:flex;\"><span>\n<\/span><\/span><span style=\"display:flex;\"><span>2025-12-25\n<\/span><\/span><span style=\"display:flex;\"><span>... and so on<\/span><\/span><\/code><\/pre><\/div><p>Here&rsquo;s Claude Code logging time for me for more than 2 weeks in less than a\nminute.<\/p>"},{"title":"#001: agx - basic human-in-the-loop style controls","link":"https:\/\/devlog.dhruvs.space\/build-bytes\/001\/","pubDate":"Mon, 22 Dec 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/build-bytes\/001\/","description":"<hr>\n<p><a href=\"https:\/\/github.com\/dhth\/agx\">agx<\/a> now asks for confirmation from the user when it wants to run a potentially\ndestructive tool call, like running a shell command, or editing a file.<\/p>\n<p>The user can also provide feedback in the same confirmation prompt to guide\n<code>agx<\/code> in a different direction (like Claude Code), which I find quite useful.<\/p>\n<div class=\"video-container\" style=\"position: relative; width: 100%; padding-bottom: 56.25%;\">\n<iframe class=\"video\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;\" src=\"https:\/\/www.youtube-nocookie.com\/embed\/f464B-hJnyc?si=CelFVMiw3GcEZH7I\" title=\"omm\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div>\n<p><strong>Next up<\/strong>: a permissions management system that tracks user&rsquo;s preference per\ntool call.<\/p>"},{"title":"#011: Building my own coding agent: The Foundations","link":"https:\/\/devlog.dhruvs.space\/log\/011\/","pubDate":"Sat, 20 Dec 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/011\/","description":"<hr>\n<p>Command line agentic AI solutions have taken the software engineering world by\nstorm. It&rsquo;s fascinating how much progress has been made in this field this year\n(Anthropic released the <a href=\"https:\/\/www.anthropic.com\/news\/claude-3-7-sonnet\">research preview<\/a>\nof Claude Code on Feb 24, 2025). Since then, a lot of other contenders have\nemerged: opencode, codex-cli, ampcode, cursor-cli, gemini-cli, copilot-cli, etc.\nI&rsquo;ve been interested in how these agentic tools work for a while now, so I&rsquo;ve\ndecided to build one of my own.<\/p>"},{"title":"#010: Porting a graph database query tool from Python to Rust","link":"https:\/\/devlog.dhruvs.space\/log\/010\/","pubDate":"Sun, 14 Dec 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/010\/","description":"<hr>\n<p>At work, we use AWS Neptune as the database of choice for a knowledge graph. We\nalso spin up local neo4j databases to test database migration code and run\nad-hoc queries. I query these databases almost daily, and didn&rsquo;t want to use a\nheavy database client for this, so I wrote <a href=\"https:\/\/github.com\/dhth\/graphc\">graphc<\/a> \u2014 <em>a command line tool to\nquery graph databases via an interactive console<\/em> \u2014 a while back. This post\ncovers the process of <a href=\"https:\/\/github.com\/dhth\/grafq\">porting<\/a> it from Python to Rust, and the reasons behind\nit.<\/p>"},{"title":"#009: Assembling a custom dashboard for open source maintenance","link":"https:\/\/devlog.dhruvs.space\/log\/009\/","pubDate":"Mon, 24 Nov 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/009\/","description":"<hr>\n<p>Over the last two years of maintaining several open source tools of varying\ncomplexity and adoption, I&rsquo;ve learned that beyond a certain scale, keeping\nrelease pipelines healthy \u2014 ensuring the tools are secure, up-to-date, and ready\nto ship \u2014 becomes increasingly complicated. In practice, this involves the\nfollowing:<\/p>\n<ul>\n<li>keeping dependency libraries updated frequently<\/li>\n<li>ensuring GitHub Actions checks are always passing<\/li>\n<li>tracking what&rsquo;s changed on the main branch since the last release<\/li>\n<\/ul>\n<p>Doing this regularly for multiple tools (<a href=\"https:\/\/tools.dhruvs.space\">~30<\/a> at the time of writing) can get\ntedious. For a while, I&rsquo;d been trying to improve visibility into these areas\nusing disparate tools. I needed one place to see it all. So, I assembled a\ndashboard that ties all of this together in one place.<\/p>"},{"title":"#008: Improving deployment visibility with small, targeted tools","link":"https:\/\/devlog.dhruvs.space\/log\/008\/","pubDate":"Thu, 13 Nov 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/008\/","description":"<hr>\n<p>One of the first things I do when I join a new team is dig into their CI\/CD\nprocess. This usually involves asking a few simple questions:<\/p>\n<blockquote>\n<p>How is infrastructure provisioned?<\/p>\n<\/blockquote>\n<blockquote>\n<p>How is software deployed?<\/p>\n<\/blockquote>\n<blockquote>\n<p>How are deployment updates communicated to the team?<\/p>\n<\/blockquote>\n<blockquote>\n<p>Are differences between environments highlighted?<\/p>\n<\/blockquote>\n<p>As a Tech Lead, I try to make sure that developers on my team have a clear sense\nof the above. Over the years, I\u2019ve found that teams move faster when everyone\nunderstands how infrastructure and application changes flow from local machines\nthrough development environments and into production. Not only that, knowing\nexactly what infrastructure is being provisioned or what changes are being\nshipped with a deployment leads to fewer surprises, and more importantly, fewer\nincidents.<\/p>"},{"title":"#007: Adapting kplay to meet new needs","link":"https:\/\/devlog.dhruvs.space\/log\/007\/","pubDate":"Sun, 21 Sep 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/007\/","description":"<hr>\n<p>Kafka is the primary system for service-to-service messaging at my workplace.\nMost topics carry messages encoded with <a href=\"https:\/\/protobuf.dev\/\">protobuf<\/a>, a binary serialization\nformat that\u2019s efficient for storage and transmission but unreadable without the\nmatching schema files. This makes inspecting message contents tricky. Tools like\n<a href=\"https:\/\/github.com\/provectus\/kafka-ui\">kafka-ui<\/a> can decode messages when given the schemas, but I prefer command-line\nsolutions.<\/p>\n<p>To fill that gap, I built <a href=\"https:\/\/github.com\/dhth\/kplay\">kplay<\/a> last year. It lets users interactively pull\nmessages from Kafka topics and view them in a TUI or web interface, with the\noption to save decoded messages locally. It quickly became a useful tool for me\nfor investigating Kafka topics.<\/p>"},{"title":"#006: Making JIRA time tracking suck less with AI","link":"https:\/\/devlog.dhruvs.space\/log\/006\/","pubDate":"Thu, 28 Aug 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/006\/","description":"<p><strong>TLDR<\/strong>: Watch this: <a href=\"https:\/\/youtu.be\/TtBye08jSo4\">https:\/\/youtu.be\/TtBye08jSo4<\/a><\/p>\n<hr>\n<p>Tracking time on JIRA is a terrible experience. The UI is unintuitive, slow, and\nrequires a lot of clicks. This is especially worse for an &ldquo;on-premise&rdquo;\ninstallation which sits behind a VPN, as it does at my place of work.<\/p>\n<p>My role involves a fair bit of context switching, which means my time tracking\nconsists of a lot of interleaved worklogs, making JIRA&rsquo;s interface even more\npainful to deal with. To make this process nicer, I created a command line tool\na while back: <a href=\"https:\/\/github.com\/dhth\/punchout\">punchout<\/a>. It&rsquo;s entirely keyboard driven, and lets you track time\non issues via a TUI. It&rsquo;s proven useful \u2014 all of my time tracking in the last\nyear has been done with it.<\/p>"},{"title":"#005: Virus scanning pre-built binaries of my tools","link":"https:\/\/devlog.dhruvs.space\/log\/005\/","pubDate":"Sun, 24 Aug 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/005\/","description":"<hr>\n<p>A user opened an <a href=\"https:\/\/github.com\/dhth\/hours\/issues\/99\">issue<\/a> on <a href=\"https:\/\/github.com\/dhth\/hours\">hours<\/a> last week informing me that Windows Defender\nhad flagged the latest release as malware. One of the vendors on <a href=\"https:\/\/www.virustotal.com\">VirusTotal<\/a> \u2014\na malware analysis platform \u2014 also detected it as malicious, which was\nconcerning.<\/p>\n<p>The detection went away after I reanalysed the file on VirusTotal. I also ran\nanalyses on several older commits and they all came back clean, so my hunch is\nthat the detection was a false positive. But it got me thinking \u2014 what if this\nhappens again, and I don&rsquo;t find out about it for weeks?<\/p>"},{"title":"#004: First foray into snapshot testing bubbletea apps","link":"https:\/\/devlog.dhruvs.space\/log\/004\/","pubDate":"Mon, 18 Aug 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/004\/","description":"<hr>\n<p>I released <a href=\"https:\/\/github.com\/dhth\/hours\/releases\/tag\/v0.6.0\">v0.6.0<\/a> of <a href=\"https:\/\/github.com\/dhth\/hours\">hours<\/a> today. It mostly includes quality-of-life\nfeatures requested by users and a few UI improvements from my side. Here&rsquo;s the\nchangelog:<\/p>\n<blockquote>\n<h4 id=\"added\">Added<\/h4>\n<ul>\n<li>Allow filtering tasks by status in analytics commands (log, report, stats)<\/li>\n<li>Keymap to finish active task log without comment<\/li>\n<li>Contextual cues in the &ldquo;Task Log Entry&rdquo; view<\/li>\n<\/ul>\n<h4 id=\"changed\">Changed<\/h4>\n<ul>\n<li>Removed date range limit for stats and log commands<\/li>\n<li>Missing end date in date range implies today (eg. 2025\/08\/12&hellip;)<\/li>\n<li>&ldquo;today&rdquo; can be used in date range (eg. 2025\/08\/12&hellip;today)<\/li>\n<li>Improved TUI navigation: esc\/q now function in more panes, returning the user\nto previous panes in a predictable manner<\/li>\n<li>User messages in the TUI remain visible for a while<\/li>\n<li>Minimum terminal width needed brought down to 80 characters (from 96)<\/li>\n<\/ul>\n<\/blockquote>\n<p>While refactoring the app for this release, I felt the need for snapshot tests\nto ensure I hadn&rsquo;t caused regressions. The app didn&rsquo;t have any, so I decided to\nset them up.<\/p>"},{"title":"#003: Jules v. GitHub Copilot coding agent for a simple task","link":"https:\/\/devlog.dhruvs.space\/log\/003\/","pubDate":"Fri, 15 Aug 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/003\/","description":"<hr>\n<p>A user opened an <a href=\"https:\/\/github.com\/dhth\/hours\/issues\/83\">issue<\/a> on <a href=\"https:\/\/github.com\/dhth\/hours\">hours<\/a> asking for a keymap to save time logs\nwithout requiring a comment. After implementing it, I realized <a href=\"https:\/\/github.com\/dhth\/punchout\">punchout<\/a> could\nbenefit from the same feature since both tools have similar time tracking\nfunctionality.<\/p>\n<p>This task seemed like a good contender for testing asynchronous coding agents \u2014\nit&rsquo;s quite simple, has a reference implementation, and doesn&rsquo;t need much new\n&ldquo;thought&rdquo;. So, I gave the task to GitHub Copilot&rsquo;s coding agent and Google Jules\nwith the same prompt, which is listed below.<\/p>"},{"title":"#002: Can GitHub Copilot agent help with go toolchain upgrades?","link":"https:\/\/devlog.dhruvs.space\/log\/002\/","pubDate":"Thu, 14 Aug 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/002\/","description":"<hr>\n<p>Go <code>1.25.0<\/code> dropped as a stable release a few days ago. Upgrading the toolchain\nfor my <a href=\"https:\/\/github.com\/dhth?tab=repositories&amp;q=&amp;type=&amp;language=go&amp;sort=\">Go tools<\/a> has always been refreshingly straightforward <em>(one of the\nlanguage&rsquo;s best qualities)<\/em>, but doing it across 10+ tools gets old real fast.<\/p>\n<p>Since I was staring down yet another round of mechanical upgrades, I figured\nthis was a good opportunity to try something different \u2014 let GitHub Copilot&rsquo;s\ncoding agent handle the grunt work. After manually upgrading a couple of\nprojects to get a feel for the process, I fired up several Copilot agent jobs\nwith this prompt:<\/p>"},{"title":"#001: Reflection on command line tools written in Rust, Go and Python","link":"https:\/\/devlog.dhruvs.space\/log\/001\/","pubDate":"Tue, 12 Aug 2025 00:00:00 +0000","guid":"https:\/\/devlog.dhruvs.space\/log\/001\/","description":"<hr>\n<p>Last week, one of my tools <a href=\"https:\/\/github.com\/dhth\/mult\">mult<\/a> got featured on <a href=\"https:\/\/terminaltrove.com\/new\/\">Terminal Trove<\/a> <em>(my ninth\nproject on there; how did that happen?)<\/em>. This brought a few new visitors to its\nGitHub page, and one of them opened an issue for a feature request.<\/p>\n<p>It had been a while since I&rsquo;d shipped any updates to this tool, but seeing the\nrequest sparked enough interest to not only fulfill it, but also add a few\nimprovements to it. It was also a good excuse to write some easy-going Go after\nseveral weeks of writing Rust and Python.<\/p>"}]}}