<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://nickdirienzo.com">
    <title>Nick DiRienzo</title>
    <link href="https://nickdirienzo.com/feed.xml" rel="self" >
    <link href="https://nickdirienzo.com" >
    <updated>2026-08-14T16:28:05Z</updated>
    <id>https://nickdirienzo.com</id>
        <entry>
            <title>
                GitHub PR Comments Live in Three Different Places
                
            </title>
            <updated>2026-08-14T16:27:57.707Z</updated>
            <id>https://nickdirienzo.com/git-hub-pr-comments-live-in-three-different-places/</id>
            <content type="html">
                &lt;p&gt;TIL that &lt;code&gt;gh pr view --json comments&lt;/code&gt; does not return inline review comments, which Copilot makes heavy use of.&lt;/p&gt;
&lt;p&gt;I found this because one of my coding agents confidently declared a PR clean while Copilot&#39;s findings (including a real bug) were left unacknowledged. The agent ran the obvious command, saw nothing, and moved on.&lt;/p&gt;
&lt;p&gt;GitHub PRs have three separate ways of accessing comments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Issue comments (the main conversation thread): &lt;code&gt;gh pr view --json comments&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Review bodies (the summary attached to an approval/request-changes): &lt;code&gt;gh pr view --json reviews&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Inline review comments (the ones anchored to actual diff lines): &lt;code&gt;gh api repos/{owner}/{repo}/pulls/{n}/comments&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is no &lt;code&gt;gh pr view&lt;/code&gt; field for the third one. If a reviewer leaves only inline comments, &lt;code&gt;gh pr view --json comments&lt;/code&gt; can return an empty &lt;code&gt;comments&lt;/code&gt; array even though the PR has actionable review feedback.&lt;/p&gt;
&lt;p&gt;And GitHub has managed to make this even more confusing by having Copilot post its review summary under the login &lt;code&gt;copilot-pull-request-reviewer[bot]&lt;/code&gt; but its inline findings under Copilot. So even if you know about the third API and filter by the reviewer you&#39;re looking for, you get an empty list.&lt;/p&gt;
&lt;p&gt;We&#39;ve since added a line to our &lt;code&gt;AGENTS.md&lt;/code&gt; telling agents to check all three channels.&lt;/p&gt;
&lt;p&gt;Hope this helps someone else.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/git-hub-pr-comments-live-in-three-different-places/" >
        </entry>
        <entry>
            <title>
                Customizing Google Ads
                
            </title>
            <updated>2026-01-27T05:59:33.451Z</updated>
            <id>https://nickdirienzo.com/customizing-google-ads/</id>
            <content type="html">
                &lt;p&gt;TIL about &lt;a href=&quot;https://myadcenter.google.com/customize&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://myadcenter.google.com/customize&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Specifically the &amp;quot;Sensitive&amp;quot; tab that lets users toggle off ads about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Alcohol&lt;/li&gt;
&lt;li&gt;Dating&lt;/li&gt;
&lt;li&gt;Gambling&lt;/li&gt;
&lt;li&gt;Pregnancy and parenting&lt;/li&gt;
&lt;li&gt;Weight loss&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;ve been seeing so many ads on YouTube these days that are just not great (they never have been). It&#39;s really not great listing to a DJ set and then have it interrupted by GLP-1 marketing. I&#39;d prefer for it to not be interrupted at all, but creators gotta make money somehow, so I don&#39;t mind some ads.&lt;/p&gt;
&lt;p&gt;At least, now I can hopefully have the peace of mind that these more egregious ads won&#39;t show up on my feed.&lt;/p&gt;
&lt;p&gt;Hope this helps someone else, because I had no idea it was even possible to turn off certain ad topics.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/customizing-google-ads/" >
        </entry>
        <entry>
            <title>
                Claude Code Personal Rules
                
            </title>
            <updated>2026-01-27T06:00:12.489Z</updated>
            <id>https://nickdirienzo.com/claude-code-personal-rules/</id>
            <content type="html">
                &lt;p&gt;Since December 2025, I&#39;ve been fully into &lt;code&gt;jj&lt;/code&gt; (see [Working with jujutsu]).&lt;/p&gt;
&lt;p&gt;Claude Code defaults to &lt;code&gt;git&lt;/code&gt; and doesn&#39;t seem to have a good grasp of using &lt;code&gt;jj&lt;/code&gt; as  a tool.&lt;/p&gt;
&lt;p&gt;We&#39;ve recently brought Claude Code back into reviewing PRs now that Opus 4.5 is effectively a mid-level engineer.&lt;/p&gt;
&lt;p&gt;While looking at the docs, I learned about &lt;a href=&quot;https://code.claude.com/docs/en/memory#user-level-rules&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;User-level Rules&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had no idea about this despite using Claude Code daily for 6 months.&lt;/p&gt;
&lt;p&gt;More to come on my usage of Claude Code, but in the meantime, &lt;a href=&quot;https://www.geoffreychallen.com/talks/2026-01-15-a-day-with-claude-using-and-teaching-coding-agents&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;a friend shared his use of Claude Code&lt;/a&gt; which is pretty similar to mine.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/claude-code-personal-rules/" >
        </entry>
        <entry>
            <title>
                PyBay 2023 - Infrastructure as a Product
                
            </title>
            <updated>2026-04-28T06:01:01.571Z</updated>
            <id>https://nickdirienzo.com/py-bay-2023-infrastructure-as-a-product/</id>
            <content type="html">
                &lt;p&gt;In 2023, I gave a talk on lessons I learned building on platform engineering teams.&lt;/p&gt;
&lt;p&gt;YouTube link &lt;a href=&quot;https://www.youtube.com/watch?v=5hbxUX4dwyk&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/py-bay-2023-infrastructure-as-a-product/" >
        </entry>
        <entry>
            <title>
                2025 UB Forge Talk - Voice AI for Builders
                
            </title>
            <updated>2026-01-27T06:01:15.375Z</updated>
            <id>https://nickdirienzo.com/2025-ub-forge-talk-voice-ai-for-builders/</id>
            <content type="html">
                &lt;p&gt;I gave this talk to the &lt;a href=&quot;https://www.ubforge.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;UB Forge&lt;/a&gt; community virtually on Sept 24, 2025.&lt;/p&gt;
&lt;p&gt;The deck is here: &lt;a href=&quot;https://dub.sh/ub-forge-voice-ai&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://dub.sh/ub-forge-voice-ai&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe something written here will show up too.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/2025-ub-forge-talk-voice-ai-for-builders/" >
        </entry>
        <entry>
            <title>
                Notes from experimenting with sprites.dev
                
            </title>
            <updated>2026-03-24T02:54:07.003Z</updated>
            <id>https://nickdirienzo.com/notes-from-experimenting-with-sprites-dev/</id>
            <content type="html">
                &lt;p&gt;Some quick notes from building out a prototype of cloud development environments powered by Fly.io&#39;s new product: &lt;a href=&quot;https://sprites.dev/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Sprites&lt;/a&gt;. (PS: &lt;a href=&quot;https://simonwillison.net/2026/Jan/9/sprites-dev/#developer-sandboxes&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;great notes&lt;/a&gt; from Simon Willison.)&lt;/p&gt;
&lt;p&gt;I wanted isolated, ephemeral-ish environments where we can spin up an army of AI coding agents in parallel. Each with its own copy of our full product stack, its own data, and no risk of stomping on other agents&#39; ports, processes, or storage. Sprites provide Firecracker VMs that start fast, idle for pennies, and feel like disposable computers rather than infrastructure to manage.&lt;/p&gt;
&lt;p&gt;It&#39;s EC2 without the overhead. &lt;code&gt;sprite console&lt;/code&gt; gets you a shell and we run &lt;code&gt;code tunnel&lt;/code&gt; as a Sprite Service for a full IDE. The single external port limitation is a blessing in disguise: smaller attack surface, and Sprite auth sits in front of the public URL automatically. Services don&#39;t pin a Sprite as running, but foreground processes do. So you get tight control over when you&#39;re paying for compute.&lt;/p&gt;
&lt;p&gt;While I&#39;d like to say we&#39;re using it, I can&#39;t yet. There have been a number of road bumps during my exploration that make Sprites not yet usable for production, let alone development environments.&lt;/p&gt;
&lt;h2 id=&quot;what-s-great&quot; tabindex=&quot;-1&quot;&gt;What&#39;s great&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Isolation: Every sprite is its own Firecracker VM with a separate kernel. No shared-kernel container escape risk, no port conflicts, no filesystem bleed between environments. This is the right security boundary for running untrusted AI-generated code.&lt;/li&gt;
&lt;li&gt;Pricing: Sprites go &amp;quot;warm&amp;quot; when not in use, meaning you only pay for storage.&lt;/li&gt;
&lt;li&gt;Pre-loaded runtimes: Node, Python, Go, Rust, Java, PostgreSQL client, git, Claude Code all come pre-installed. Our setup script went from &amp;quot;install everything from scratch&amp;quot; to &amp;quot;wire up our specific pieces.&amp;quot;&lt;/li&gt;
&lt;li&gt;Filesystem persistence: Everything written to disk survives across sessions, warm/cold cycles, and reboots. Clone once, it&#39;s there forever.&lt;/li&gt;
&lt;li&gt;Checkpoints: Snapshot your entire filesystem state. Useful for saving a known-good setup so you don&#39;t re-run a 10+ minute bootstrap.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--http-post exec&lt;/code&gt;: Reliable non-interactive command execution. WebSocket-based exec had issues with connections dropping during &lt;code&gt;git clone&lt;/code&gt;. For some reason, switching to HTTP POST fixed it immediately.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sprite-env services&lt;/code&gt;: Long-lived process management that survives session disconnects and auto-restarts on wake.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-i-m-hoping-they-build&quot; tabindex=&quot;-1&quot;&gt;What I&#39;m hoping they build&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;No fleet/pool primitives: Creating a sprite is fast, but bootstrapping a full dev environment isn&#39;t. Would love first-class support for sprite pools or template-based creation from a checkpoint, so you can claim a pre-built environment instead of building from scratch each time.&lt;/li&gt;
&lt;li&gt;No background exec: &lt;code&gt;sprite exec&lt;/code&gt; blocks until completion. Our setup takes 10+ minutes (npm install, build) and there&#39;s no way to fire-and-forget and check status later. Would love a &lt;code&gt;sprite exec --background&lt;/code&gt; that returns a job ID.&lt;/li&gt;
&lt;li&gt;Higher reliability: TCP timeouts and 5xx errors on basic operations like listing, creating, and connecting to sprites. I was evaluating this as a path toward agent sandboxes in the product, but the platform needs to be solid for interactive dev work before I can trust it with autonomous agents.&lt;/li&gt;
&lt;li&gt;CLI improvements: dropping out of &lt;code&gt;sprite console&lt;/code&gt; eats my ghostty session. Text formatting is all over the place. I have to &lt;code&gt;reset&lt;/code&gt; to get everything back.&lt;/li&gt;
&lt;/ul&gt;

            </content>
            <link href="https://nickdirienzo.com/notes-from-experimenting-with-sprites-dev/" >
        </entry>
        <entry>
            <title>
                The software supply chain is an active combat zone
                
            </title>
            <updated>2026-03-31T22:49:43.170Z</updated>
            <id>https://nickdirienzo.com/the-software-supply-chain-is-an-active-combat-zone/</id>
            <content type="html">
                &lt;p&gt;Software supply chain attacks are increasing in frequency and severity. This month alone we&#39;ve seen multiple unrelated campaigns hitting the open-source ecosystem simultaneously. This isn&#39;t one bad week. It&#39;s the new normal.&lt;/p&gt;
&lt;p&gt;Two weeks ago, an automated bot exploited a misconfigured &lt;code&gt;pull_request_target&lt;/code&gt; workflow in &lt;a href=&quot;https://thehackernews.com/2026/03/trivy-security-scanner-github-actions.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Trivy&#39;s GitHub Actions&lt;/a&gt; to steal a Personal Access Token. That gave the attackers (a group tracked as &lt;a href=&quot;https://www.sans.org/blog/when-security-scanner-became-weapon-inside-teampcp-supply-chain-campaign&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;TeamPCP&lt;/a&gt;) enough to compromise Trivy&#39;s release pipeline, poison 75 of 76 version tags, and push credential-stealing malware through official releases. From there, the stolen credentials cascaded:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;March 19:&lt;/strong&gt; Trivy compromised. Credential stealer deployed via GitHub Actions, Docker Hub, and binary releases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;March 23:&lt;/strong&gt; Checkmarx KICS VS Code extensions and GitHub Actions compromised using credentials from the Trivy breach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;March 24:&lt;/strong&gt; &lt;a href=&quot;https://futuresearch.ai/blog/litellm-attack-transcript/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;LiteLLM compromised on PyPI.&lt;/a&gt; Malicious versions harvested SSH keys, cloud credentials, and Kubernetes secrets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;March 27:&lt;/strong&gt; &lt;a href=&quot;https://telnyx.com/resources/telnyx-python-sdk-supply-chain-security-notice-march-2026&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Telnyx compromised on PyPI.&lt;/a&gt; Same playbook.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just today, &lt;a href=&quot;https://www.bleepingcomputer.com/news/security/cisco-source-code-stolen-in-trivy-linked-dev-environment-breach/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Cisco&#39;s source code was stolen&lt;/a&gt; leveraging the Trivy vector. SANS analysts believe TeamPCP may have a stockpile of compromised publishing credentials and could be operating as an Initial Access Broker. This is likely not over.&lt;/p&gt;
&lt;p&gt;Separately, and this appears to be a different actor entirely, &lt;a href=&quot;https://socket.dev/blog/axios-npm-package-compromised&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;axios was compromised&lt;/a&gt; on npm yesterday. The attacker used a stolen long-lived npm access token to publish malicious versions of one of the most widely used packages in the JavaScript ecosystem.&lt;/p&gt;
&lt;p&gt;Last September, the &lt;a href=&quot;https://www.cisa.gov/news-events/alerts/2025/09/23/widespread-supply-chain-compromise-impacting-npm-ecosystem&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Shai-Hulud campaign&lt;/a&gt; hijacked 18 popular npm packages by phishing maintainers with fake 2FA reset emails. As an engineer, we tend to think we&#39;re too smart to fall for social engineering. We run these simulations for a living at Mirage, and I can tell you: we&#39;re not. The attacks are better than most people expect.&lt;/p&gt;
&lt;p&gt;Different actors, different methods, all hitting at the same time. We can&#39;t control upstream maintainers, but we can harden how we consume their work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Save exact versions.&lt;/strong&gt; Pin direct dependencies and lock the entire dependency tree.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set a maximum package age.&lt;/strong&gt; Something sensible like 7 days so that brand new malicious versions aren&#39;t automatically installed. npm, pnpm, Yarn, and Bun all support this natively now. Renovate and Dependabot respect it too for automated PRs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pin GitHub Actions to commit SHAs, not version tags.&lt;/strong&gt; Tags can be force-pushed. This is exactly how the Trivy compromise propagated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In Node, don&#39;t allow install scripts.&lt;/strong&gt; This was what allowed the axios C2 to run. In Python it&#39;s worse: you can&#39;t prevent &lt;code&gt;.pth&lt;/code&gt; files from executing.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Software supply chain security used to be something you audited quarterly. That cadence doesn&#39;t match the threat anymore. Treat your dependency pipeline like infrastructure that&#39;s actively under attack. Because it is.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/the-software-supply-chain-is-an-active-combat-zone/" >
        </entry>
        <entry>
            <title>
                S3 Files
                
            </title>
            <updated>2026-04-07T22:12:41.714Z</updated>
            <id>https://nickdirienzo.com/s3-files/</id>
            <content type="html">
                &lt;p&gt;With AI agents depending on filesystems for searching, editing, and storing context, it was only a matter of time before AWS had a cloud-native answer.&lt;/p&gt;
&lt;p&gt;Today is that day: AWS launched S3 Files (&lt;a href=&quot;https://www.allthingsdistributed.com/2026/04/s3-files-and-the-changing-face-of-s3.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;All Things Distributed&lt;/a&gt;, &lt;a href=&quot;https://aws.amazon.com/s3/features/files/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;AWS&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This is a big deal. Agents work on filesystems. They &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;. We&#39;ve watched Claude Code and Codex shift the industry from semantic search back to grep, which spawned a wave of tools built as CLIs instead of MCP servers. As an industry we&#39;ve learned that agents are most capable when they operate like developers do, on files.&lt;/p&gt;
&lt;p&gt;S3 Files maps buckets and prefixes to NFS mounts. That means you can create filesystem sandboxes backed by S3 durability and attach them to Lambda, ECS, whatever. Lambda becomes stateless execution with a durable filesystem.&lt;/p&gt;
&lt;p&gt;Personalized agent contexts, scratchpads, durable working directories all on top of AWS primitives. That&#39;s an amazing foundation for anyone doing agentic work on AWS.&lt;/p&gt;
&lt;p&gt;The cloud is catching up to how agents actually work.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/s3-files/" >
        </entry>
        <entry>
            <title>
                Reflecting on harness engineering - lessons from engineering with AI since 2023
                
            </title>
            <updated>2026-03-06T15:42:25.346Z</updated>
            <id>https://nickdirienzo.com/reflecting-on-harness-engineering-lessons-from-engineering-with-ai-since-2023/</id>
            <content type="html">
                &lt;p&gt;I learned about &lt;a href=&quot;https://github.com/openai/symphony&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;OpenAI&#39;s Symphony project&lt;/a&gt; today. It is really impressive and reminds me of the experiment I was working on in January with &lt;a href=&quot;https://github.com/nickdirienzo/inc&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;inc&lt;/a&gt;. Symphony and OpenAI&#39;s post on &lt;a href=&quot;https://openai.com/index/harness-engineering/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Harness Engineering&lt;/a&gt; is making me move from the headspace of &amp;quot;experiment&amp;quot; to &amp;quot;how can I bring these capabilities to our daily development without a new tool.&amp;quot;&lt;/p&gt;
&lt;p&gt;I skimmed through the post when it released last month, but didn&#39;t deeply sit with it until now. As a long-time platform engineer, I agree with a lot here; these practices are what platform teams have encouraged for decades: shift left with fast feedback loops.&lt;/p&gt;
&lt;p&gt;While building Mirage, we developed much of the product with AI assistance before coding agents were a thing -- we were pasting code into the OpenAI playground and getting code back. Today, it is a 100x better experience than in 2023, thanks to tools like Claude Code and Codex.&lt;/p&gt;
&lt;p&gt;Because of that experience, our repository has continued to become more legible for our coding agents. I view our repo to be 40% aligned with the harness engineering philosophy. This is my reflection on what we do well, where we can improve, and where I disagree with OpenAI&#39;s approach.&lt;/p&gt;
&lt;h2 id=&quot;what-we-do-well&quot; tabindex=&quot;-1&quot;&gt;What we do well&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://adr.github.io/madr/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Architecture Decision Records&lt;/a&gt; (ADRs).&lt;/strong&gt; I&#39;m surprised OpenAI&#39;s post doesn&#39;t mention them. We have 40+ ADRs in &lt;code&gt;doc/architecture/decisions/&lt;/code&gt;. Before agents, ADRs were aspirational: the team agreed they were valuable but couldn&#39;t sustain the discipline of writing them. With agents, ADRs become a flywheel: the agent writes the ADR as part of implementing the decision, and future agents reference those ADRs when building features that touch the same surface. We regularly see Claude cite an ADR unprompted when making an implementation choice. If you&#39;ve appreciated ADRs before but couldn&#39;t keep up, having agents write and leverage them is a beautiful thing. We also include ADRs we&#39;ve rejected and superseded to provide context on decisions we didn&#39;t pursue.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Committed feature plans.&lt;/strong&gt; We commit specs to &lt;code&gt;doc/features/&lt;/code&gt; alongside the code. This gives PR reviewers (both human and agentic) insight into the high level vision and architecture, and whether the code aligns with the plan. We should be doing more of this -- today only some features get committed plans. The goal is all of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type-safe API contracts.&lt;/strong&gt; We use &lt;code&gt;ts-rest&lt;/code&gt; with Zod schemas for every endpoint. This is a mechanical invariant: the agent literally cannot ship an API change that doesn&#39;t match the contract. This is the kind of guardrail the post advocates: enforce the boundary, not the implementation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So much observability.&lt;/strong&gt; For an early stage startup, we have a lot of telemetry. We invested heavily in OpenTelemtry traces, logging, and metrics upfront. We ship OTel data to Observe, which our coding agent can query via Observe&#39;s MCP server. This is still heavily human-in-the-loop given the complexity of the data, but even partial agent access to o11y shortens the diagnosis loop. Before agentic programming, this investment already paid for itself; now it&#39;s becoming a foundation for agent-driven debugging.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structured logging conventions.&lt;/strong&gt; We have a specific logging format (&lt;code&gt;[Component.method] Action&lt;/code&gt;, context object, &lt;code&gt;serializeErrorLike()&lt;/code&gt; for errors). This is a pattern agents still violate, which tells me it needs to move from documentation to enforcement (a linter rule, not a paragraph in CLAUDE.md). Fortunately, GritQL makes this a lot more achievable and reduce the feedback loop for agentic development.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent-driven code review.&lt;/strong&gt; We have a Claude Code GitHub Action workflow that reviews every PR against our team&#39;s standards: type safety, multi-tenant data scoping, logging patterns, and security. It catches things humans miss because it never gets tired of checking the checklist. We&#39;ve biased our prompt to focus on getting changes out the door while still maintaining security and quality. I discovered &lt;a href=&quot;https://warden.sentry.dev/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Warden&lt;/a&gt; recently which threads the needle nicely between file-path determinism and skill execution, but maybe the table of contents approach obviates the need for this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fast CI/CD to production.&lt;/strong&gt; We have strong CI/CD practices that enable a rollout to production within 15 minutes. This matters more in an agent-driven workflow because throughput increases. More changes shipping means you need faster recovery, not more gates. The confidence to let agents ship comes from knowing you can recover quickly, not from preventing every possible mistake upfront.&lt;/p&gt;
&lt;h2 id=&quot;where-we-can-improve&quot; tabindex=&quot;-1&quot;&gt;Where we can improve&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Agents can&#39;t boot our stack yet.&lt;/strong&gt; This is the primary problem for us to solve next. The agent can&#39;t launch the app, drive it with a browser, and validate its own changes. It&#39;s working on static code, blind to whether the change actually works. This is the single biggest gap between where we are and the full harness engineering vision.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Our CLAUDE.md is the content, not the table of contents.&lt;/strong&gt; It grew to 500+ lines and agents started ignoring patterns buried in the middle. OpenAI&#39;s approach of a short AGENTS.md (~100 lines) that points to deeper domain docs is right. &amp;quot;Too much guidance becomes non-guidance&amp;quot; is something we experience daily: the agent blatantly ignores patterns that seem simple to follow, like using our error serialization utility or response handling helpers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Include more documentation.&lt;/strong&gt; While we have many documents in-repo around architectural decisions and implementation plans, we lack files describing the security model, our product sense, or a simplified high-level view of the architecture. These will further legibility within the repo and improve agentic decision making.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Documentation is better than enforcement, but enforcement is what works.&lt;/strong&gt; If agents keep violating a pattern, it&#39;s not a documentation problem: it&#39;s an enforcement problem. We need to move more conventions from prose in CLAUDE.md into automated guardrails (GritQL and tests). A lint error the agent has to fix is worth more than a paragraph it might ignore.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some ADRs have drifted.&lt;/strong&gt; We have 40+ ADRs but some represent completed transitions where the &amp;quot;decision&amp;quot; is now just &amp;quot;how it works,&amp;quot; and some foundational early decisions were never recorded. We need a doc-gardening process, which is something OpenAI does with recurring agent jobs, and we should too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better agentic access to tasks and documents.&lt;/strong&gt; While we use Notion MCPs, sometimes the documents are too complex to update and leads to a storm of failed requests with HTTP 400 status codes. This tells me that Notion is likely not the best backing store for agents, and we may want to consider a simpler document structure that is plain markdown.&lt;/p&gt;
&lt;h2 id=&quot;where-we-disagree&quot; tabindex=&quot;-1&quot;&gt;Where we disagree&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;PRs per engineer per day is an incomplete metric.&lt;/strong&gt; OpenAI reports 3.5 PRs/engineer/day. I&#39;m doing 5+ with Claude Code, with one or two more complex explorations running in the background. We use this metric too since each PR is effectively a feature (+137% output in a week compared to the previous 3 months) -- it loosely measures how frequently the system is changing. But it doesn&#39;t capture how much complexity is being added or removed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agents should have access to more context sources.&lt;/strong&gt; OpenAI deliberately keeps agents out of Slack. I understand the reasoning -- Slack is noisy and unstructured -- but I&#39;m not sure why you&#39;d limit the agent&#39;s access to context that helps it do its job. We give Claude access to Metabase and Notion via MCP so it can read task and customer context. The repo is for execution; the project management tool is for &amp;quot;why this matters to the business&amp;quot; -- where the rest of the business works.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Distinct o11y stacks per worktree is overkill.&lt;/strong&gt; OpenAI runs separate observability for each worktree. You can get the same result by adding a worktree identifier to your OTel resource attributes and filtering in your existing APM. Same data, no extra infrastructure. I&#39;d love to know how they landed on independent stacks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recurring invariant jobs are interesting, but I&#39;d start per-PR.&lt;/strong&gt; Their &amp;quot;golden principles&amp;quot; are enforced by recurring sweeps rather than per-PR gates. I&#39;d love to know why they landed here, given that most of these tech-debt cleanups are reviewed in under a minute and automerged; it feels like changes that could happen on the PR-level. I think the answer is throughput at their scale -- per-PR enforcement is synchronous and blocks the agent loop. FWIW, I think the idea of recurring agentic loops is a good one, e.g. having an agent right size infrastructure outside of what your autoscaling policies support or addressing low-priority vulnerabilities. This feels like something you would layer in over time instead of out the gate, but I&#39;ll see where I&#39;m wrong in practice.&lt;/p&gt;
&lt;h2 id=&quot;what-s-next&quot; tabindex=&quot;-1&quot;&gt;What&#39;s next&lt;/h2&gt;
&lt;p&gt;We&#39;re working on closing the feedback loop. The end state is: given a single prompt, the agent can reproduce a bug, record a video, implement a fix, validate the fix by driving the application, record a second video, and open a pull request with evidence. Escalate to a human only when judgment is required.&lt;/p&gt;
&lt;p&gt;We&#39;re not there yet, but each step gets closer. And none of it requires a dedicated platform team. I&#39;m working on a companion post with the concrete checklist for other startups.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/reflecting-on-harness-engineering-lessons-from-engineering-with-ai-since-2023/" >
        </entry>
        <entry>
            <title>
                Meditation reflection - begin again
                
            </title>
            <updated>2026-03-03T19:14:16.023Z</updated>
            <id>https://nickdirienzo.com/meditation-reflection-begin-again/</id>
            <content type="html">
                &lt;p&gt;I&#39;ve tried to meditate off and on for the last decade. It hasn&#39;t really stuck yet, but that&#39;s not to say it will never stick.&lt;/p&gt;
&lt;p&gt;I&#39;ve been thinking a lot about spirituality this year. A friend suggested to try meditation and sent me a gift subscription to &lt;a href=&quot;https://nickdirienzo.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Waking Up&lt;/a&gt;. I&#39;m fairly familiar with the mental wellness app landscape, but this is one that I never thought to try until now.&lt;/p&gt;
&lt;p&gt;One of the experiences it gets right is a slow on-ramp into the practice of meditation through their 28-day Introductory Course. It gracefully exposes you to the different nuances and challenges that appear when meditating, like background sounds, restlessness, and loss of focus.&lt;/p&gt;
&lt;p&gt;Early on in the course, Sam Harris introduces two ideas that have stuck with me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Begin again.&lt;/strong&gt; We&#39;re human and fallible. It&#39;s expected that you will fall off the practice or lose focus during a session. That&#39;s okay. Take a beat, and just begin again. Restart the count, or the in-out cycle. This concept applies to so much more than meditation too. Having a conversation go sideways? You can just begin again. Having a not so great exercise session? You can just begin again. Haven&#39;t ridden your bike to work in months? You can just begin again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disruptions during meditation.&lt;/strong&gt; I always tried meditation where it&#39;s quiet, but in one session, he talks about how people have written in saying he speaks too much during the session and this disrupts focus. His suggestion is that with a strong practice, it should just be yet another thought that you observe and move on. I commute mostly by public transit (ferry, BART, or bus). I&#39;ve started to use the moments to practice meditating. It&#39;s incredibly distracting and it&#39;s usually when my mind is starting to ramp into work mode too. I think by doing this though I might have a stronger and more practical foundation for mindfulness.&lt;/p&gt;
&lt;p&gt;So here I am, restarting a meditation practice yet again.&lt;/p&gt;
&lt;p&gt;Maybe this time it will stick. All I had to do was begin again.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/meditation-reflection-begin-again/" >
        </entry>
        <entry>
            <title>
                Lessons from Datadog&#39;s agent harness engineering
                
            </title>
            <updated>2026-03-31T19:39:46.175Z</updated>
            <id>https://nickdirienzo.com/lessons-from-datadog-s-agent-harness-engineering/</id>
            <content type="html">
                &lt;p&gt;I recently read &lt;a href=&quot;https://www.datadoghq.com/blog/ai/harness-first-agents/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Datadog&#39;s blog post&lt;/a&gt; on how they built a Redis implementation in Rust with AI. There were a number of ideas here that resonated with how I build.&lt;/p&gt;
&lt;p&gt;They leverage ADRs to encapsulate not just the new architectural capabilities and why, but also the properties and invariants of the system.&lt;/p&gt;
&lt;p&gt;They leverage ADRs to encapsulate not just the new architectural capabilities and why, but also the properties and invariants of the system. This prose is then translated by AI into a formal TLA+ specification, which feeds other verification layers: &lt;a href=&quot;https://github.com/nerdsane/redis-rust/blob/08ff584bb1afd1af8f7cdab6f6737d25cfe2ed25/docs/DST_GUIDE.md&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Deterministic Simulation Testing&lt;/a&gt; (DST), Rust-specific model checkers like &lt;a href=&quot;https://github.com/stateright/stateright&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Stateright&lt;/a&gt; and &lt;a href=&quot;https://github.com/model-checking/kani&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Kani&lt;/a&gt;, and broad system telemetry checks.&lt;/p&gt;
&lt;p&gt;This pipeline is powerful, and I think it can be leveraged for &amp;quot;less formal&amp;quot; systems building. When building features, I imagine that looking more like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Design feature implementation plan.&lt;/strong&gt; Include ADRs are necessary when making significant changes. Either document includes properties and invariants that must be true.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Translate properties into a test plan.&lt;/strong&gt; An AI coding agent translates those properties into a test plan that includes example-based unit/integration tests, as well as property-based testing (e.g. &lt;a href=&quot;https://fast-check.dev/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;fast-check&lt;/a&gt; in Node). This provides more coverage than the previous era of development at about the same speed. PBT is particularly helpful with complex systems, workflows, and algorithms that are more open-ended.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validate system behavior end-to-end.&lt;/strong&gt; End-to-end tests are an analog of DST for product development. They exercise real system behavior rather than isolated units. The agent can take this further by querying your o11y stack during test runs to find performance issues that assertions alone won&#39;t catch.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At Mirage, while we have much more unit/integration test coverage than I would have thought at this stage, we are now starting to push further with PBTs, especially around our more complex and open-world workflows. We&#39;ve discovered a handful of edge cases through early PBTs on core algorithms, and this style of testing provides additional confidence in the changes we&#39;re making.&lt;/p&gt;
&lt;p&gt;I&#39;m excited to continue evolving our harness for agentic engineering.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/lessons-from-datadog-s-agent-harness-engineering/" >
        </entry>
        <entry>
            <title>
                Flight - an experimental coding harness
                
            </title>
            <updated>2026-04-28T06:02:37.699Z</updated>
            <id>https://nickdirienzo.com/flight-an-experimental-coding-harness/</id>
            <content type="html">
                &lt;h2 id=&quot;validation-is-the-bottleneck&quot; tabindex=&quot;-1&quot;&gt;Validation is the bottleneck&lt;/h2&gt;
&lt;p&gt;I&#39;ve been a happy user of &lt;a href=&quot;https://www.conductor.build/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Conductor&lt;/a&gt; for the last few months. Having automatic worktrees and a performant orchestration tool on top of Claude Code helped move me from a couple of parallel workstreams to somewhere closer to 7+ at any given moment. I tried to do something similar with Claude desktop but the app is too slow to use as a power user.&lt;/p&gt;
&lt;p&gt;Now I&#39;m having another problem: I&#39;m resource constrained. I only have so much memory to give to running the Mirage stack, and running more than one at a time really slows down the rest of what I do (Slack, internet, Notion, etc). There&#39;s two camps for this problem: one that says buy a bigger machine and the other says run your environment in the cloud.&lt;/p&gt;
&lt;p&gt;I&#39;ve been seeing more coding harnesses (Twill.ai, Coder, Zed, and I&#39;m sure Conductor soon) try to lock you into their ecosystem and throw margin on top of rented infrastructure; rightfully so, that gives you a moat and a path to owning inference. Even Anthropic is doing this with Claude by letting you run Claude Code tasks in their infrastructure -- which if you haven&#39;t tried, is generally a great experience.&lt;/p&gt;
&lt;p&gt;But it&#39;s still insufficient. So earlier this month, I said screw it. I don&#39;t want to wait for these tools to allow an open interface to coding in our cloud. I have AI. I can do this myself.&lt;/p&gt;
&lt;h2 id=&quot;provisioning-cloud-workspaces&quot; tabindex=&quot;-1&quot;&gt;Provisioning cloud workspaces&lt;/h2&gt;
&lt;p&gt;I first experimented with &lt;a href=&quot;https://coder.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Coder&lt;/a&gt;. This worked fairly well and gave us a pathway to spin up devboxes in our cloud using HCL. This provided some sanity around what is typically a bunch of bash. After moving to EC2 instances as a provisioning surface, I found myself writing a bunch of bash anyway -- well Claude, not me.&lt;/p&gt;
&lt;p&gt;We have an EC2 template for Coder community edition that starts a pre-baked AMI of our development environment for marginally faster boot. This gives us the benefit of complete isolation of environments, allowing us to run the full stack without worrying about collisions on data, ports, or code. Each of these devboxes run ngrok for secure access, allowing us to share links to prototypes for quickly getting feedback.&lt;/p&gt;
&lt;p&gt;Today, the intention is for these devboxes to be ephemeral. This reduces our patch management surface area and costs, while allowing us to spin up many EC2 instances concurrently. Already I&#39;m seeing this step take longer than is pleasant, so we&#39;ll need to optimize here.&lt;/p&gt;
&lt;p&gt;We had the ability to spin these up, but there was friction in getting there. Logging into Coder, clicking a button, connecting to Claude via the web app. It was all rather unpleasant, despite it feeling like a step in the right direction. I believe that good &lt;a class=&quot;internal-link&quot; target=&quot;&quot; data-note-icon=&quot;&quot; href=&quot;https://nickdirienzo.com/py-bay-2023-infrastructure-as-a-product/&quot;&gt;internal tools should be products&lt;/a&gt; in their own right, so I decided to make this experience better.&lt;/p&gt;
&lt;h2 id=&quot;introducing-flight&quot; tabindex=&quot;-1&quot;&gt;Introducing Flight&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mirage-security/flight&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Flight&lt;/a&gt;  is an open-source, pluggable Claude Code orchestrator. It builds on a bunch of experiments in harness engineering we&#39;ve run over the last few months; we don&#39;t write code by hand anymore, we iterate heavily on plans, and we like validating features end-to-end. Flight gives us a frontend to provision workspaces to run the full Mirage stack in isolation, but the lifecycle scripts are just that -- any project could use this as a frontend if they wanted to.&lt;/p&gt;
&lt;p&gt;The initial release is a native Mac app built with Swift to build faster with Claude. It&#39;s built around a workflow of isolated worktrees, has native GitHub integrations (and a pluggable forge framework for others), and native support for remote worktree workspaces.&lt;/p&gt;
&lt;p&gt;Since my initial experiment, more of the team has been using and improving Flight. We&#39;re keeping it open-source so anyone can fork or contribute too. We&#39;re all shipping more code with AI, and our tools need to evolve to support high-volume code development and verification.&lt;/p&gt;
&lt;p&gt;As long as that remote workspace supports ssh, Flight can build with Claude.&lt;/p&gt;
&lt;h2 id=&quot;early-observations&quot; tabindex=&quot;-1&quot;&gt;Early observations&lt;/h2&gt;
&lt;p&gt;The team has started to use Flight in anger this week. It&#39;s early, so more notes soon.&lt;/p&gt;
&lt;p&gt;A few things that are exciting to see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The inline plan review tool changed the iteration loop more than I expected. It&#39;s a slight quality of life improvement but now I can batch review without having to copy-paste from the plan. It&#39;s like a simpler version of Ultraplan.&lt;/li&gt;
&lt;li&gt;Using Opus 4.6 1M means I don&#39;t really think about handoffs or compaction anymore. That used to be a real source of friction. This unlocks more native conversational programming.&lt;/li&gt;
&lt;li&gt;Shareable ngrok links are useful. We&#39;re giving feedback on features earlier than we ever have. It&#39;s making feature development way more collaborative and more fun because we can see live updates to the site as the agent works behind the scenes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;take-flight&quot; tabindex=&quot;-1&quot;&gt;Take flight&lt;/h2&gt;
&lt;p&gt;We have a bunch of ideas for where Flight goes next. Pluggability is the big one. I want this to work like VSCode extensions, not a monolith. Open source brought us to where we are today, and I&#39;m sad to see closed-source making such a strong comeback for developer tools and infrastructure.&lt;/p&gt;
&lt;p&gt;I would love for you to try this out, submit issues (there are many!), provide feedback, share ideas, fork it and make it your own.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/flight-an-experimental-coding-harness/" >
        </entry>
        <entry>
            <title>
                Working with jujutsu
                
            </title>
            <updated>2026-01-18T16:51:20.673Z</updated>
            <id>https://nickdirienzo.com/working-with-jujutsu/</id>
            <content type="html">
                &lt;p&gt;Scattered, thoughts, tips and tricks working with &lt;a href=&quot;https://www.jj-vcs.dev/latest/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;&lt;code&gt;jj&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I figured now would be a good time to try out &lt;code&gt;jj&lt;/code&gt; since I am 5 PRs deep in a stack. As like most of everything here, this is written largely stream of consciousness as I am learning and doing.&lt;/p&gt;
&lt;h2 id=&quot;commit-feature&quot; tabindex=&quot;-1&quot;&gt;Commit = feature&lt;/h2&gt;
&lt;p&gt;First learning: &lt;code&gt;jj&lt;/code&gt; wants you to have a mental model of commit = feature. With &lt;code&gt;git&lt;/code&gt;, you would think of a PR being the feature; even if the PR was a mess, you would likely squash and commit into &lt;code&gt;main&lt;/code&gt; to keep it clean.&lt;/p&gt;
&lt;p&gt;Because of this, I have to cleanup my &amp;quot;mess&amp;quot; of commits like: &amp;quot;yay it works&amp;quot;, &amp;quot;rename&amp;quot;, &amp;quot;etc&amp;quot;. This is reasonable since I put all my effort into PR descriptions, less so individual commits.&lt;/p&gt;
&lt;p&gt;So to take my 7 commit mess into 1 I effectively did an interactive rebase with squashing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# This is saying from this revision set squash the changes into `wutnoxrs`
jj squash --from &amp;quot;wutnoxrs..yzoxlnsx&amp;quot; --into wutnoxrs
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;everything-is-a-revision&quot; tabindex=&quot;-1&quot;&gt;Everything is a revision&lt;/h2&gt;
&lt;p&gt;Second learning: &lt;code&gt;jj&lt;/code&gt; is always operating on a commit for &lt;em&gt;everything&lt;/em&gt;. I accidentally ran the previous command as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;jj squash --from wut --into yzox
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this is saying take revision &lt;code&gt;wut&lt;/code&gt; and teleport it into &lt;code&gt;yzox&lt;/code&gt;. I thought it meant from &lt;code&gt;wut&lt;/code&gt; to &lt;code&gt;yzox&lt;/code&gt; create a new revision and squash them into that. Nope.&lt;/p&gt;
&lt;p&gt;But because everything is a revision. I can easily just run &lt;code&gt;jj undo&lt;/code&gt; and fix my oopsie.&lt;/p&gt;
&lt;h3 id=&quot;even-current-edits&quot; tabindex=&quot;-1&quot;&gt;Even current edits&lt;/h3&gt;
&lt;p&gt;With &lt;code&gt;git&lt;/code&gt;, you have to mentally differentiate between what is staged, dirty, untracked, and committed. With &lt;code&gt;jj&lt;/code&gt;, you&#39;re never not operating on a revision:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;@  omlsswzl nick 2025-12-13 22:23:52 66f2d3c2
│  (empty) (no description set)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;stacking-p-rs-is-so-much-simpler&quot; tabindex=&quot;-1&quot;&gt;Stacking PRs is so much simpler&lt;/h2&gt;
&lt;p&gt;Third learning: &lt;code&gt;jj&lt;/code&gt; effortlessly manages stacked PRs. Let&#39;s say I realize I need to make a change to PR-A while working in PR-D. I can easily do &lt;code&gt;jj edit PR-A&lt;/code&gt;, make the change, and it will auto-propagate the changes forward across the stack. Then when I push, all of those branches get pushed (effectively auto-rebased with their respective parent and pushed).&lt;/p&gt;
&lt;p&gt;While doing my own cleanup and transition from &lt;code&gt;git&lt;/code&gt; to &lt;code&gt;jj&lt;/code&gt;, I found a revision in PR-D that really should be in PR-B. Now I can take my oopsie command from earlier and actually use it appropriately. I want to take revision &lt;code&gt;qplwptqv&lt;/code&gt; and bring it to &lt;code&gt;wutnoxrs&lt;/code&gt;; that can be done with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;jj squash --from qplwptqv --into wutnoxrs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this applies that revision to the other one. This would have been so, so painful in &lt;code&gt;git&lt;/code&gt; because I would have had to cherry-pick that commit into PR-B, drop it in PR-D, and then rebase PR-C and PR-D onto the latest PR-B. &lt;code&gt;jj&lt;/code&gt; just did all of that for me.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;jj&lt;/code&gt; made it incredibly easy to take 40 commits across 5 stacked PRs and turn them into only 1 commit per PR and update everything all at once. I think this was like under 30 minutes of effort while learning how this new tool works (thanks Gemini). After I did all this squash surgery, it should be simple enough to push with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;jj git push --all
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;fixing-remote-tracking&quot; tabindex=&quot;-1&quot;&gt;Fixing remote tracking&lt;/h3&gt;
&lt;p&gt;This was terrifying to run, so I learned there&#39;s a dry-run mode (&lt;code&gt;--dry-run&lt;/code&gt;). I&#39;m glad I did because this would push &lt;em&gt;all&lt;/em&gt; of my local bookmarks with remote... and I have &lt;em&gt;many&lt;/em&gt;. Worse yet, I learned that a number of these branches are not tracked by &lt;code&gt;jj&lt;/code&gt; and wouldn&#39;t be pushed because of all the changes I made:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Warning: Non-tracking remote bookmark nvd/feature@origin exists
Hint: Run `jj bookmark track nvd/feature@origin` to import the remote bookmark.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, I tried that and it got more complicated:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nickdirienzo@Nicks-MacBook-Pro mirage % jj bookmark track nvd/feature@origin
Started tracking 1 remote bookmarks.
nvd/feature (conflicted):
  + zwxzuvzt?? 818f8d8d feat(TSK-1857): some description here
  + oksymzvq ff94891d env vars
  @origin (behind by 1 commits): oksymzvq ff94891d env vars
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hm. Okay. I can tell &lt;code&gt;jj&lt;/code&gt; to treat &lt;code&gt;zwxzuvzt&lt;/code&gt; as the bookmark right?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nickdirienzo@Nicks-MacBook-Pro mirage % jj bookmark set nvd/feature -r zwxzuvzt
Error: Change ID `zwxzuvzt` is divergent
Hint: Use commit ID to select single revision from: a7d4633daa8d, 818f8d8d4fa1
Hint: Use `change_id(zwxzuvzt)` to select all revisions
Hint: To abandon unneeded revisions, run `jj abandon &amp;lt;commit_id&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can, but I can&#39;t use the change ID. I must use the underlying commit ID. But we know that from our logs. So we can run a command like this across each of the remote branches:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;jj bookmark set nvd/feature -r 818f8d8d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After doing that for each of the bookmarks, I was able to push everything:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;jj git push -b nvd/feature-A &#92;
            -b nvd/feature-B &#92;
            -b nvd/feature-C &#92;
            -b nvd/feature-D &#92;
            -b nvd/feature-E
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I would love to run &lt;code&gt;jj git push --all&lt;/code&gt;, but my dry run listed 74 bookmarks it would push. A lot of those are very, very stale. Not only is &lt;code&gt;jj&lt;/code&gt; already making more productive with stacked PRs, but it is also encouraging me to Marie Kondo these all branches from my life.&lt;/p&gt;
&lt;h2 id=&quot;new-workflow&quot; tabindex=&quot;-1&quot;&gt;New workflow&lt;/h2&gt;
&lt;p&gt;TLDR:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Fetch any updates from origin
jj git fetch
# Sync anything that&#39;s open (see below for my aliases)
jj sync-all
# Create a new revset off main
jj new main@origin
# Do a bunch of work
...
# Describe what this is about
jj describe
# Push to origin under a new bookmark
jj git push --change @
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create new revision from where we are: &lt;code&gt;jj new&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Create new revision off &lt;code&gt;main&lt;/code&gt; (i.e. need to hotfix something or start fresh work): &lt;code&gt;jj new main@origin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I use &lt;code&gt;main@origin&lt;/code&gt; instead of setting up tracking on &lt;code&gt;main&lt;/code&gt; as a bookmark, and I think that&#39;s great — keeping &lt;code&gt;main&lt;/code&gt; immutable means I can&#39;t accidentally edit it!&lt;/p&gt;
&lt;p&gt;Instead of &lt;code&gt;git commit -m&lt;/code&gt;, you would describe a revision: &lt;code&gt;jj describe&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Prepare revision for PR: &lt;code&gt;jj git push --change @&lt;/code&gt;; this creates a bookmark, tracks it, and pushes to origin all in one go. No need to manually set up bookmarks.&lt;/p&gt;
&lt;p&gt;If you want to manage the bookmark name yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create the bookmark: &lt;code&gt;jj bookmark create $name&lt;/code&gt; ($name will be used as a branch in git)&lt;/li&gt;
&lt;li&gt;Push the change: &lt;code&gt;jj git push --bookmark $name&lt;/code&gt; (throw on &lt;code&gt;--dry-run&lt;/code&gt; if you want to double check); this makes sure it&#39;s tracked by &lt;code&gt;jj&lt;/code&gt; on origin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But honestly, bookmark names matter a lot less in &lt;code&gt;jj&lt;/code&gt;; less cognitive overhead for me.&lt;/p&gt;
&lt;p&gt;All done with those changes? Time for another &lt;code&gt;jj new&lt;/code&gt;, which locks in those changes locally under the bookmark.&lt;/p&gt;
&lt;p&gt;Lean into &lt;code&gt;jj new&lt;/code&gt; for experiments, hotfixes, etc. Don&#39;t be afraid of having &amp;quot;uncommitted&amp;quot; changes; &lt;code&gt;jj&lt;/code&gt; is managing it behind the scenes. I often use &lt;code&gt;jj new&lt;/code&gt; whenever I&#39;m about to work on something new that might cause problems with my current set of changes.&lt;/p&gt;
&lt;p&gt;Looking at diffs between local and origin: &lt;code&gt;jj diff --from $bookmark$@origin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Moving files across revisions: &lt;code&gt;jj squash -i --into &amp;lt;revision_id&amp;gt;&lt;/code&gt;. This lets you select which files you want to move from the current revision into the provided revision. To commit the squash, type &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Syncing with remote and rebasing revisions on top of the new changes from trunk:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;jj git fetch
# Sync all tracked work with the latest main
jj sync-all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have a collocated repo, so &lt;code&gt;jj git fetch&lt;/code&gt; keeps me in sync with remote. After fetching, &lt;code&gt;jj sync-all&lt;/code&gt; (a custom alias, see below) makes sure everything I&#39;m tracking is up to date.&lt;/p&gt;
&lt;h2 id=&quot;aliases&quot; tabindex=&quot;-1&quot;&gt;Aliases&lt;/h2&gt;
&lt;p&gt;Here are some aliases I&#39;ve been using to make my transition to &lt;code&gt;jj&lt;/code&gt; a bit easier.&lt;/p&gt;
&lt;p&gt;This shows all of the revisions from where we are to &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[revset-aliases]
&amp;quot;immutable_heads()&amp;quot; = &amp;quot;trunk() | tags()&amp;quot;
# Useful for showing my active work and rebasing their roots with main
active = &amp;quot;mine() ~ ::trunk()&amp;quot;

[aliases]
# Show my chain of revisions on the current stack
stack = [&amp;quot;log&amp;quot;, &amp;quot;-r&amp;quot;, &amp;quot;trunk()..@&amp;quot;]
# &amp;quot;Show me all my unmerged changes&amp;quot;
active = [&amp;quot;log&amp;quot;, &amp;quot;-r&amp;quot;, &amp;quot;active&amp;quot;]
# Rebase all of my active work with main@origin. Run after `jj git fetch`.
sync-all = [&amp;quot;rebase&amp;quot;, &amp;quot;-s&amp;quot;, &amp;quot;roots(active)&amp;quot;, &amp;quot;-d&amp;quot;, &amp;quot;main@origin&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;cleaning-up&quot; tabindex=&quot;-1&quot;&gt;Cleaning up&lt;/h2&gt;
&lt;p&gt;I have a lot of stale git branches which is making it hard to make use of &lt;code&gt;jj&lt;/code&gt; rebasing efficiently with trunk, e.g. I can&#39;t quickly do &lt;code&gt;jj rebase -s &amp;quot;roots(active)&amp;quot; -d main@origin&lt;/code&gt; to sync up my active work with latest &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I had Gemini cook up a one-liner to show me all of my work branched off trunk with context so I can decide what to abandon:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;jj log -r &amp;quot;roots(active)&amp;quot; --no-graph &#92;
  -T &#39;change_id.short() ++ &amp;quot; &amp;quot; ++ author.timestamp().format(&amp;quot;%Y-%m-%d&amp;quot;) ++ &amp;quot;   &amp;quot; ++ description.first_line() ++ &amp;quot;&#92;n&amp;quot;&#39; &#92;
  | awk &#39;$2 &amp;lt; &amp;quot;2025-12-10&amp;quot;&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since that list looks good, I had it produce another one-linear to delete them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# ONLY run this when you are ready to delete everything listed above
jj log -r &amp;quot;roots(active)&amp;quot; --no-graph &#92;
  -T &#39;change_id.short() ++ &amp;quot; &amp;quot; ++ author.timestamp().format(&amp;quot;%Y-%m-%d&amp;quot;) ++ &amp;quot;&#92;n&amp;quot;&#39; &#92;
  | awk &#39;$2 &amp;lt; &amp;quot;2025-12-10&amp;quot; {print $1 &amp;quot;::&amp;quot;}&#39; &#92;
  | xargs jj abandon
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s a bit of a yolo operation, but whatever. What&#39;s great about jujutsu is if something does go wrong, I can &lt;code&gt;jj undo&lt;/code&gt; the operation since the &lt;code&gt;abandon&lt;/code&gt; command is taking in all the revisions at once.&lt;/p&gt;
&lt;p&gt;Once that ran and abandoned 677 commits (oops), rebasing all my active work with a new fetch of main was a breeze.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/working-with-jujutsu/" >
        </entry>
        <entry>
            <title>
                Why aren&#39;t Claw skills just MCP server install instructions?
                
            </title>
            <updated>2026-03-01T20:01:05.599Z</updated>
            <id>https://nickdirienzo.com/why-aren-t-claw-skills-just-mcp-server-install-instructions/</id>
            <content type="html">
                &lt;p&gt;I&#39;ve been thinking about claws since OpenClaw released. I think we all have (e.g. &lt;a href=&quot;https://x.com/karpathy/status/2024987174077432126&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Karpathy&#39;s tweet&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;They&#39;re powerful, fun, and scary. I set up &lt;a href=&quot;https://nanoclaw.dev/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;NanoClaw&lt;/a&gt; because I really liked its security model: put the non-determinism in a container so it can&#39;t wreck your system. If you&#39;re unfamiliar, NanoClaw skills are Claude Code instructions that rewrite your fork&#39;s source code to add capabilities.&lt;/p&gt;
&lt;p&gt;I couldn&#39;t stop thinking that these skills are just plugins, but without any of the guarantees we expect from plugin architectures. No typed interfaces, no versioning, no supply chain scanning. What if the host didn&#39;t need to know about the skill&#39;s code at all and could still provide the new capabilities? I built &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;NonnaClaw&lt;/a&gt; to test that idea: an experimental fork of NanoClaw with a rebuilt skill layer that treats MCP servers as the capability boundary. I &lt;a href=&quot;https://nickdirienzo.com/exploring-external-skills-in-nano-claw/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;wrote about the process here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-spend-tokens-on-code-changes&quot; tabindex=&quot;-1&quot;&gt;Why spend tokens on code changes?&lt;/h2&gt;
&lt;p&gt;This was the first thought that led me down this rabbit hole. I didn&#39;t fully believe that personalized forks were better than a stable platform that provides plugins. What I actually wanted was determinism and a stronger security model.&lt;/p&gt;
&lt;p&gt;That led me to the question: can these skills just be MCP setup instructions? An MCP server is a normal software project. It has dependency management, versioned releases, typed interfaces, and it can be scanned for vulnerabilities the same way any package can. A skill that teaches an LLM to construct curl commands at runtime has none of that. The execution is non-deterministic, the interface is untyped, and there&#39;s nothing to scan because the &amp;quot;code&amp;quot; is regenerated from markdown on every invocation.&lt;/p&gt;
&lt;p&gt;We have plugin architectures for a reason. VSCode extensions don&#39;t patch &lt;code&gt;editor.main.js&lt;/code&gt;. They operate within a typed API that the host exposes. The extension gets capabilities without changing the application&#39;s code. NanoClaw skills rewrite the host. OpenClaw skills prompt-inject the host. Neither is a plugin architecture.&lt;/p&gt;
&lt;h2 id=&quot;putting-this-to-the-test&quot; tabindex=&quot;-1&quot;&gt;Putting this to the test&lt;/h2&gt;
&lt;p&gt;To keep the code simple and small, NonnaClaw separates the three layers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Capabilities:&lt;/strong&gt; These are provided as tool calls to MCP servers. Typed, versioned, maintained by someone else. Normal software.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; a &lt;code&gt;skill.json&lt;/code&gt; manifest declaring what to spawn and how to scope requests. Effectively a flexible authorization layer on the tools themselves for the agent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workflows:&lt;/strong&gt; orchestration skills that reference tools abstractly. Can&#39;t execute without the MCP tools present.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A skill is its own repo with two files. &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw-whatsapp&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;nonnaclaw-whatsapp&lt;/a&gt; wraps a community WhatsApp MCP server with per-group scoping. &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw-github&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;nonnaclaw-github&lt;/a&gt; wraps GitHub&#39;s official MCP server (&lt;code&gt;ghcr.io/github/github-mcp-server&lt;/code&gt;) via Docker with read-only scoping: every write operation (&lt;code&gt;merge_pull_request&lt;/code&gt;, &lt;code&gt;push_files&lt;/code&gt;, &lt;code&gt;delete_file&lt;/code&gt;, etc.) is &lt;code&gt;allow: false&lt;/code&gt;. The &lt;code&gt;SKILL.md&lt;/code&gt; runs once during install to walk through auth. After that it&#39;s out of the picture.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;whatsapp&amp;quot;,
  &amp;quot;mcp&amp;quot;: {
    &amp;quot;command&amp;quot;: &amp;quot;uv&amp;quot;,
    &amp;quot;args&amp;quot;: [&amp;quot;--directory&amp;quot;, &amp;quot;./whatsapp-mcp/whatsapp-mcp-server&amp;quot;, &amp;quot;run&amp;quot;, &amp;quot;main.py&amp;quot;],
    &amp;quot;pollTool&amp;quot;: &amp;quot;list_messages&amp;quot;
  },
  &amp;quot;scopeTemplate&amp;quot;: {
    &amp;quot;send_message&amp;quot;: { &amp;quot;allow&amp;quot;: true, &amp;quot;scopedParams&amp;quot;: [&amp;quot;recipient&amp;quot;] },
    &amp;quot;list_messages&amp;quot;: { &amp;quot;allow&amp;quot;: true, &amp;quot;scopedParams&amp;quot;: [&amp;quot;chat_jid&amp;quot;] },
    &amp;quot;list_chats&amp;quot;: { &amp;quot;allow&amp;quot;: false }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The host spawns the MCP server, bridges it to HTTP, polls for inbound messages. The agent connects through a scoping proxy that enforces per-group authorization. The agent discovers typed tools through the protocol: names, descriptions, input schemas. No prompt injection needed.&lt;/p&gt;
&lt;p&gt;After install, the skill dissolves. It&#39;s just infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;does-this-apply-to-open-claw&quot; tabindex=&quot;-1&quot;&gt;Does this apply to OpenClaw?&lt;/h2&gt;
&lt;p&gt;Since the system worked end-to-end, I started wondering: does this pattern work for OpenClaw?  OpenClaw skills work differently than NanoClaw skills, but the same layers (capabilities, configuration, workflows) are conflated.&lt;/p&gt;
&lt;p&gt;An OpenClaw skill is a &lt;code&gt;SKILL.md&lt;/code&gt; that gets injected into the agent&#39;s system prompt at runtime. The agent reads the instructions and generates bash commands, API calls, or code on the fly. No typed interface. The execution model: unversioned markdown → prompt injection → LLM generates arbitrary code → exec with agent privileges.&lt;/p&gt;
&lt;p&gt;I looked at a handful of popular skills and was surprised to see the same pattern over and over again:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Notion:&lt;/strong&gt; teaches the agent to construct &lt;code&gt;curl&lt;/code&gt; commands against the Notion API. Three competing versions on ClawHub (&lt;code&gt;notion&lt;/code&gt;, &lt;code&gt;notion-skill&lt;/code&gt;, &lt;code&gt;better-notion&lt;/code&gt;) all reimplementing the same thing. Notion ships an official MCP server (&lt;code&gt;@notionhq/notion-mcp-server&lt;/code&gt;) with typed tools and scoped permissions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; wraps &lt;code&gt;gh&lt;/code&gt; CLI. There&#39;s a GitHub MCP server on the official Docker registry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;summarize:&lt;/strong&gt; wraps a real Homebrew binary with versioned releases. The capability is already packaged software. The skill just tells the LLM to generate bash commands to call it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For every major skill I looked at, typed MCP servers already exist. It feels like the skills are worse versions of interfaces that are already out there.&lt;/p&gt;
&lt;h2 id=&quot;understanding-the-current-security-risks-with-claws&quot; tabindex=&quot;-1&quot;&gt;Understanding the current security risks with claws&lt;/h2&gt;
&lt;p&gt;ClawHub skills already ship with code. They have install scripts, &lt;code&gt;package.json&lt;/code&gt; files, versioned releases, changelogs, metadata schemas declaring required binaries and env vars. It&#39;s like 80% of a package manager, but then used prompt injection for the last 20%.&lt;/p&gt;
&lt;p&gt;This is why NanoClaw runs agents in containers with limited access. You don&#39;t have to worry about this risk vector because the agent doesn&#39;t have host access.&lt;/p&gt;
&lt;p&gt;Snyk scanned ~4,000 ClawHub skills and found &lt;a href=&quot;https://snyk.io/blog/toxicskills-malicious-ai-agent-skills-clawhub/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;36% had prompt injection vulnerabilities&lt;/a&gt;. The &lt;a href=&quot;https://www.koi.ai/blog/clawhavoc-341-malicious-clawedbot-skills-found-by-the-bot-they-were-targeting&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;ClawHavoc campaign&lt;/a&gt; documented 824 malicious skills. The attack pattern is simple: a skill looks legitimate, but its &amp;quot;Prerequisites&amp;quot; section tells you to download and run an executable. The barrier to publishing: a SKILL.md and a week-old GitHub account.&lt;/p&gt;
&lt;p&gt;An MCP server published to npm or PyPI gets the same supply chain scrutiny as any other package. It can be scanned by Snyk, Dependabot, Socket. It has typed exports that can be audited. A SKILL.md is a markdown file that an LLM interprets at runtime. There&#39;s nothing to scan because the code doesn&#39;t exist until the agent generates it.&lt;/p&gt;
&lt;h2 id=&quot;how-the-models-compare&quot; tabindex=&quot;-1&quot;&gt;How the models compare&lt;/h2&gt;
&lt;p&gt;Each approach makes different tradeoffs across the same three layers:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;OpenClaw&lt;/th&gt;
&lt;th&gt;NanoClaw&lt;/th&gt;
&lt;th&gt;NonnaClaw&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Capabilities&lt;/td&gt;
&lt;td&gt;Prompt-injected bash/curl&lt;/td&gt;
&lt;td&gt;Codemods to source&lt;/td&gt;
&lt;td&gt;MCP servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Same SKILL.md&lt;/td&gt;
&lt;td&gt;Same codemod&lt;/td&gt;
&lt;td&gt;&lt;code&gt;skill.json&lt;/code&gt; manifest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scoping&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Container isolation&lt;/td&gt;
&lt;td&gt;Container isolation + per-tool proxy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;this-is-an-experiment&quot; tabindex=&quot;-1&quot;&gt;This is an experiment&lt;/h2&gt;
&lt;p&gt;This is early. There&#39;s still work to do: securing the host layer, strengthening the MCP proxy, and some other ideas.&lt;/p&gt;
&lt;p&gt;The install-time trust problem doesn&#39;t go away. SKILL.md runs once during setup and could instruct Claude Code to do bad things. But the blast radius is one-time versus permanent prompt injection on every agent turn. Same trust model as &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The accessibility argument is real: SKILL.md is easier to write than an MCP server, and for non-developers, the AI &lt;em&gt;is&lt;/em&gt; the interface. But Claude Code can scaffold a working MCP server from a description in minutes. &lt;code&gt;package.json&lt;/code&gt; took more work than a loose shell script too, and that tradeoff was worth making. The friction argument gets weaker every month. The security argument doesn&#39;t.&lt;/p&gt;
&lt;p&gt;If you want to poke at it: &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;nonnaclaw&lt;/a&gt; is the fork. &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw-whatsapp&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;nonnaclaw-whatsapp&lt;/a&gt; is the simplest skill example: three files, wraps a community MCP server, scoped per group. If you&#39;ve built OpenClaw or NanoClaw skills and want to try converting one, I&#39;d like to know where the pattern breaks down.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/why-aren-t-claw-skills-just-mcp-server-install-instructions/" >
        </entry>
        <entry>
            <title>
                What&#39;s Left When AI Writes the Code
                
            </title>
            <updated>2026-01-27T05:57:03.848Z</updated>
            <id>https://nickdirienzo.com/what-s-left-when-ai-writes-the-code/</id>
            <content type="html">
                &lt;p&gt;The software engineer job is changing drastically and more quickly than people realize. But I think people have the wrong idea of what the job is in the first place: it&#39;s solving problems with software, not writing code. Code is just a means to an end, and now it&#39;s not even the time-consuming part.&lt;/p&gt;
&lt;p&gt;Recent models like Anthropic&#39;s Opus 4.5 can ship code as well as (or better than) a mid-level engineer. More importantly, it can write code that would take weeks in minutes. That allows us to learn faster, iterate faster, and ship faster.&lt;/p&gt;
&lt;p&gt;In the last couple of months, I&#39;ve written about 5-10% of code. In the last week, I didn&#39;t even open an editor and just worked through Claude Desktop Code. While that&#39;s anecdotal, I recently looked at some data of commits to main comparing pre-Claude and post-Claude. We had an 80% increase in contributions to main -- almost twice the output with the same team.&lt;/p&gt;
&lt;p&gt;So what&#39;s left for us to do? At least for now, the higher leverage stuff: vision, architecture, and taste.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vision&lt;/strong&gt; is clarifying what you&#39;re building and why. Knowing what makes your product unique; the subtle things that differentiate you from competitors who technically do the same thing. Claude can read your docs, your ADRs, your past conversations. But it doesn&#39;t have the empathy you&#39;ve built through every user conversation, every competitor you&#39;ve studied, every feature you decided not to build.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt; is designing sound technical systems and thinking about consequences. Claude will solve your problem, but it might overcomplicate something that should be simple, or pick an approach that doesn&#39;t meet your business where it is. It&#39;s not that Claude makes bad choices; they&#39;re usually defensible. But defensible isn&#39;t always appropriate for the context you&#39;re building in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Taste&lt;/strong&gt; is the squishiest one: having conviction in whether it feels right. Depending on context, it might be about UX, developer experience, the cognitive model of your product&#39;s nouns, or some flow that just feels off. Models can produce technically-correct solutions all day. They don&#39;t have feel. Vision tells you that you need good UX. Taste tells you this UX isn&#39;t good enough.&lt;/p&gt;
&lt;p&gt;I haven&#39;t seen the current generation of models be really good at these 3 things, even with historical ADRs, access to all the code, and clear goals/non-goals of problems to solve. I suspect we&#39;ll see models get much, much better at these areas too. Where we focus our time as engineers once they are capable in these areas, I&#39;m not yet sure.&lt;/p&gt;
&lt;p&gt;At least for me, there&#39;s still a lot of guidance and hand-holding I need to do. Fortunately, most of it at the planning level. Once the plan and architecture is aligned with my worldview, I let Claude auto-edit and I don&#39;t look at the code at all while it&#39;s developing. I act as QA in the areas it can&#39;t figure out automated testing.&lt;/p&gt;
&lt;p&gt;With tools like Coder and now Claude Desktop&#39;s Code feature (with git worktrees -- thank you), I&#39;m able to drive several sizable projects in parallel. I&#39;m unfortunately pinged constantly by the dozen or so Claude tabs that need permission to run some bash command that wasn&#39;t allowed. I&#39;m getting more and more bullish on pure yolo mode given how much autonomy Claude has while developing.&lt;/p&gt;
&lt;p&gt;Once it&#39;s done, I tell it to put up a PR and that&#39;s where I focus my time. I focus primarily on the architectural decisions it made during the process of development, which I have it write as ADRs. I double-check the data models and API contracts to align with our general direction. I&#39;ll do a cursory pass on the implementation and leave review comments; which I then tell Claude to iterate on. Depending on what&#39;s being changed, I&#39;ll look a bit more closely at certain areas, but I&#39;m mostly caring about the overall shape than the code itself.&lt;/p&gt;
&lt;p&gt;If you&#39;re an engineer wondering what to focus on: develop your vision, your architectural instincts, your taste. The code part is getting easier. The judgment part isn&#39;t (yet). Where we go from here, I&#39;m not entirely sure. In the meantime, I&#39;m shipping faster than I ever have.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/what-s-left-when-ai-writes-the-code/" >
        </entry>
        <entry>
            <title>
                What would an enterprise OpenClaw look like?
                
            </title>
            <updated>2026-03-02T04:34:57.017Z</updated>
            <id>https://nickdirienzo.com/what-would-an-enterprise-open-claw-look-like/</id>
            <content type="html">
                &lt;p&gt;Clearly my brain is obsessing over the Claw ecosystem this weekend since this is the 3rd post in 48 hours about this topic.&lt;/p&gt;
&lt;p&gt;While hacking on NonnaClaw, I couldn&#39;t help but think about what the multi-tenant SaaS architectural variant could look like. There are so many trade-offs to make when building software, but in the enterprise I&#39;ve found two things to broadly be true:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Encrypting customer data on a per-tenant basis as the default; it is the customer&#39;s data. What&#39;s left as cleartext is metadata for routing and authorization.&lt;/li&gt;
&lt;li&gt;Enabling customers to have the option for data sovereignty (e.g. bring your own bucket, bring your own key, run in their cloud, etc)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If I simplify Claw applications, they are primarily workflow orchestrations dressed up with a familiar UX (WhatsApp, etc). In addition to the data needs, the architectural requirements are:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Durable orchestration.&lt;/strong&gt; API requests to LLMs can fail, so you&#39;ll want retries, and agents can lean on workflow orchestration to perform work instead of running it long-lived in its own container. Instead of agents spawning subprocesses and passing data through files, it would use something like Temporal, Inngest, or Dapr. These workflow orchestrations also provide polling mechanisms built-in so cron moves to the application level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Runtime isolation.&lt;/strong&gt; Given the non-determinism of agents, they must be treated as &lt;a href=&quot;https://nanoclaw.dev/blog/nanoclaw-security-model&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;untrusted&lt;/a&gt;. This means each agent should run in a Docker container or v8 isolate that cannot interfere with other user requests. Kubernetes is the obvious winner here due to the ad-hoc nature of running new agents, unless v8 isolates work out which would reduce the infra footprint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent capability scoping.&lt;/strong&gt; Building on the above, not only do agents need to be run in isolation, each agent has a separate set of allowed tools and APIs. Because they are untrusted, they should not see credentials for tool use (see &lt;a href=&quot;https://www.provos.org/p/ironcurtain-secure-personal-assistant/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;IronCurtain&lt;/a&gt; and &lt;a href=&quot;https://nickdirienzo.com/why-aren-t-claw-skills-just-mcp-server-install-instructions/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;NonnaClaw&lt;/a&gt; for the single-user version of this). This requires some sort of explainable policy engine like OPA or Cedar; explainability matters here because when agents are doing real work on behalf of humans, customers need to audit exactly what an agent was and wasn&#39;t authorized to do. While runtime isolation prevents escape, this prevents unauthorized use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloud-native IO.&lt;/strong&gt; Local Claws lean on the filesystem for agent work and Node polling loops for data ingestion. This local IO model breaks when you have multiple tenants on shared infrastructure. Files become per-tenant blob storage (e.g. S3). Polling loops become event-driven ingestion: instead of 500 tenants each running their own cron, a service exposes public endpoints per customer that push events into the durable orchestration layer or are centrally scheduled in that layer in batch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Secret management.&lt;/strong&gt; Claws have a massive integration surface area. These cannot be all driven by environment variables. Instead each customer will need their own secret at runtime, that only they can configure. This causes a requirement for a technology like Hashicorp Vault, OpenBao, or secrets in the database using data encryption keys from the customer key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Execution observability.&lt;/strong&gt; LLMOps is core to the product for debugging and improvement. You&#39;ll need to trace the full lifecycle of an agent run: what did the user ask, what did the agent do, what happened in the tool loop—using customer keys to decrypt and inspect the interaction. Long-term, the same data feeds analytics and quality feedback loops that make agents better over time. Given the enterprise data requirements above, this cannot just be piped to a random LLMOps startup. Ideally, this data belongs in a storage layer that supports both per-tenant encryption and analytical queries: an Iceberg lakehouse with per-namespace KMS keys or a warehouse like Snowflake or BigQuery with per-dataset CMEK; but this could be as simple as S3 with Athena.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/what-would-an-enterprise-open-claw-look-like/" >
        </entry>
        <entry>
            <title>
                What if NanoClaw skills didn&#39;t need to change the codebase?
                
            </title>
            <updated>2026-03-01T18:29:59.003Z</updated>
            <id>https://nickdirienzo.com/what-if-nano-claw-skills-didn-t-need-to-change-the-codebase/</id>
            <content type="html">
                &lt;p&gt;I read &lt;a href=&quot;https://nanoclaw.dev/blog/nanoclaw-security-model&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Don&#39;t trust AI agents&lt;/a&gt; this morning by the creator of NanoClaw (&lt;a href=&quot;https://x.com/Gavriel_Cohen&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Gavriel Cohen&lt;/a&gt;). I generally agree with this take: we shouldn&#39;t trust our agents and provide safety-by-default for agentic behavior.&lt;/p&gt;
&lt;p&gt;NanoClaw&#39;s approach to agentic routing is using containers for isolation as a foundational primitive. This provides hardening and guardrails that are hard to workaround. I think this is a great project and have started to use it personally in my homelab.&lt;/p&gt;
&lt;p&gt;I left a &lt;a href=&quot;https://news.ycombinator.com/item?id=47196849&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;small comment&lt;/a&gt; on the HN thread, but I think this is hard to articulate in short form. I tried, but definitely wasn&#39;t able to share my thoughts well enough, so here they are... and some code that shows the thesis end-to-end.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-with-the-current-skills-contribution-model&quot; tabindex=&quot;-1&quot;&gt;The problem with the current skills contribution model&lt;/h2&gt;
&lt;p&gt;What surprises me is that despite all of the focus on security, there&#39;s still a long-term sprawl of code via the &amp;quot;features as skills&amp;quot; contribution model. These contributions aren&#39;t &lt;em&gt;just&lt;/em&gt; skills. They are instructions for Claude to modify NanoClaw&#39;s critical code paths to support the new capability.&lt;/p&gt;
&lt;p&gt;While the project says that the codebase is small enough for someone to understand in an afternoon. This won&#39;t hold for someone who&#39;s added a ton of skills that modify the core code paths, the shared SQLite database, and then has to keep their fork in sync with upstream.&lt;/p&gt;
&lt;p&gt;From a patch management perspective, I&#39;m worried too. Since every fork is personal it means that you need to have a trusted agent watching dependencies for vulnerabilities and updating appropriately. There&#39;s no version of the skill since it&#39;s intertwined with the core codepaths of NanoClaw.&lt;/p&gt;
&lt;h2 id=&quot;why-spend-tokens-on-modifying-the-code&quot; tabindex=&quot;-1&quot;&gt;Why spend tokens on modifying the code?&lt;/h2&gt;
&lt;p&gt;The AI-native response to this is: just let Claude Code handle it. I agree that this will work, but my question is: why are we spending tokens on code modifications instead of using deterministic codemods or allowing NanoClaw to properly be a framework that supports a plugin architecture.&lt;/p&gt;
&lt;p&gt;Plugin architectures are not new. We&#39;ve had them for decades, and they allow for simple interop between an application and external functionality. Think: browser extensions, VSCode extensions, and Terraform providers.&lt;/p&gt;
&lt;h2 id=&quot;skills-as-config-not-code&quot; tabindex=&quot;-1&quot;&gt;Skills as config, not code&lt;/h2&gt;
&lt;p&gt;The agent ecosystem already has a ton of &amp;quot;plugins&amp;quot; readily available with proprietary and community MCP servers. NanoClaw needs to know how to interoperate with them.&lt;/p&gt;
&lt;p&gt;What if skills were just a manifest, a small inbound script (to keep fetching non-agentic), and a set of MCP capabilities defined as config? This could look like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;skill.json&lt;/code&gt; manifest declaring which MCP servers to use for outbound (sending messages, etc.)&lt;/li&gt;
&lt;li&gt;A small standalone entrypoint script (~20-50 lines) that handles inbound (polling an API, writing events to an inbox directory)&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;SKILL.md&lt;/code&gt; with instructions for how to set it up and integrate into the runtime.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This avoids every skill modifying the SQLite database and the core event loop, which risks each one stepping on each others&#39; toes.&lt;/p&gt;
&lt;h2 id=&quot;skills-don-t-need-to-live-in-the-repo&quot; tabindex=&quot;-1&quot;&gt;Skills don&#39;t need to live in the repo&lt;/h2&gt;
&lt;p&gt;If all of this can work, this would mean that NanoClaw&#39;s contribution becomes primarily an event router, a container orchestrator for agents, and an interface for writing into inbox/outbox.&lt;/p&gt;
&lt;p&gt;Taking the idea to a further extreme, this unlocks the ability for skills to be external to the NanoClaw repository entirely. This would allow skills to be their own GitHub repos, just like MCPs with Claude Desktop.&lt;/p&gt;
&lt;p&gt;It creates a new problem of: how does NanoClaw &amp;quot;install&amp;quot; a remote skill? But we can lean on a skill for this, or provide it as a simple CLI command: &lt;code&gt;nanoclaw install&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;trying-all-of-these-ideas-out&quot; tabindex=&quot;-1&quot;&gt;Trying all of these ideas out&lt;/h2&gt;
&lt;p&gt;Could we take the ideas here and actually make it work? The criteria being: we are able to replicate the end to end onboarding workflow with WhatsApp without having WhatsApp in the codebase at all.&lt;/p&gt;
&lt;p&gt;That would give us integration one. If that works, we can try with Gmail, and then we can try with another random skill. Ideally all of these are backed by popular or official MCP servers instead of custom code.&lt;/p&gt;
&lt;h3 id=&quot;problem-1-mcp-on-its-own-is-insufficient&quot; tabindex=&quot;-1&quot;&gt;Problem 1: MCP on its own is insufficient&lt;/h3&gt;
&lt;p&gt;Containerized agents in NanoClaw are only responsible for thinking. Not for doing. Any action goes back to the host process to execute outbound messages. This means skills need to handle both inbound and outbound, not just one direction.&lt;/p&gt;
&lt;p&gt;There&#39;s also an authorization gap. MCP servers expose all their tools to any client that connects. If a containerized agent connects directly to a WhatsApp MCP server, it can send messages to anyone, not just the group it&#39;s responsible for. We need a way to scope which tools and parameters each agent is allowed to use.&lt;/p&gt;
&lt;h3 id=&quot;problem-2-global-docker-container-definition-for-agents&quot; tabindex=&quot;-1&quot;&gt;Problem 2: Global Docker container definition for agents&lt;/h3&gt;
&lt;p&gt;I skipped over this during prototyping, but each skill may need its own container runtime with OS-level dependencies. Right now, there&#39;s global sprawl across all skills instead of just on a per-skill basis. This is still an open problem. In the current architecture, MCP servers run on the host (trusted zone) so container dependencies are less of an issue for skill-specific tooling, but it&#39;s not fully solved.&lt;/p&gt;
&lt;p&gt;I&#39;d like to go back to this and make it so that skill MCP servers run in containers. Unfortunately it seems like many MCP servers don&#39;t provide Docker images, which feels like a gap in the ecosystem. Containers are a wonderfully simple deployment artifact, even if that deployment is your own computer.&lt;/p&gt;
&lt;h2 id=&quot;forking-nano-claw&quot; tabindex=&quot;-1&quot;&gt;Forking NanoClaw&lt;/h2&gt;
&lt;p&gt;I forked NanoClaw and built &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;NonnaClaw&lt;/a&gt;, an experimental project that replaces the skills-as-code model with skills-as-config backed by MCP servers. I dropped the idea of an entrypoint script and instead made it work without requiring skills to make code changes. The two main additions that make this work safely are an MCP bridge and a scoping proxy, both running on the host in the trusted zone.&lt;/p&gt;
&lt;p&gt;The bridge (&lt;code&gt;mcp-bridge.ts&lt;/code&gt;) spawns MCP servers as child processes over stdio, exposes each one as an HTTP endpoint, and polls them for inbound messages on an interval. The same MCP server that handles &lt;code&gt;list_messages&lt;/code&gt; for inbound also handles &lt;code&gt;send_message&lt;/code&gt; for outbound. Both directions, one server, no custom channel code. (If MCP servers had Docker containers, we could simplify further.)&lt;/p&gt;
&lt;p&gt;The proxy (&lt;code&gt;mcp-proxy.ts&lt;/code&gt;) sits between the agent and the bridge, enforcing per-group authorization via &lt;code&gt;scopeTemplate&lt;/code&gt; (tool allowlists and parameter pinning). For example, a family group chat can only &lt;code&gt;send_message&lt;/code&gt; to its own JID. The agent never sees tools it isn&#39;t authorized for. Both run in the trusted zone for the same reason inbound does: if they ran inside the container, a compromised agent could bypass its own restrictions.&lt;/p&gt;
&lt;p&gt;Everything else — container isolation, filesystem IPC, per-group CLAUDE.md memory, scheduled tasks, the Claude Agent SDK harness — is inherited from NanoClaw.&lt;/p&gt;
&lt;h2 id=&quot;putting-it-to-the-test&quot; tabindex=&quot;-1&quot;&gt;Putting it to the test&lt;/h2&gt;
&lt;p&gt;I built two external skills: &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw-whatsapp&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;nonnaclaw-whatsapp&lt;/a&gt; using &lt;a href=&quot;https://github.com/verygoodplugins/whatsapp-mcp&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;verygoodplugins/whatsapp-mcp&lt;/a&gt;, and &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw-github&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;nonnaclaw-github&lt;/a&gt; using Docker&#39;s official GitHub MCP server. Each with only two files: a &lt;code&gt;skill.json&lt;/code&gt; and a &lt;code&gt;SKILL.md&lt;/code&gt;. Similar to NanoClaw, &lt;code&gt;SKILL.md&lt;/code&gt; explains how to get it integrated; &lt;code&gt;skill.json&lt;/code&gt; is new to support NonnaClaw&#39;s architecture. Two MCP servers, different transports, both running through the bridge, scoped through the proxy.&lt;/p&gt;
&lt;p&gt;I ran &lt;code&gt;/install&lt;/code&gt; for both. Then I sent a WhatsApp message: &amp;quot;Wha was the last commit i made&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nickdirienzo.com/img/user/nonnaclaw.png&quot; alt=&quot;nonnaclaw.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After extracting skills to external packages, the code modification and channel machinery (~7,800 lines across the skills engine, Claude Code skills, and channel implementations) went away entirely. The core stays roughly the same size (about 170 line delta), with the new &lt;code&gt;mcp-bridge.ts&lt;/code&gt;, &lt;code&gt;skill-registry.ts&lt;/code&gt;, and &lt;code&gt;mcp-proxy.ts&lt;/code&gt;. Ideally, the core now stays relatively static except for bug fixes, security patches, and runtime improvements.&lt;/p&gt;
&lt;h2 id=&quot;where-this-goes&quot; tabindex=&quot;-1&quot;&gt;Where this goes&lt;/h2&gt;
&lt;p&gt;NonnaClaw is an experiment. &lt;a href=&quot;https://github.com/qwibitai/NanoClaw&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;NanoClaw is the real thing&lt;/a&gt;. NanoClaw&#39;s insight — a personal AI assistant should be small enough to understand, secure by isolation, and customizable — is the foundation everything here builds on.&lt;/p&gt;
&lt;p&gt;NonnaClaw explores a different answer to one question: how should skills work?&lt;/p&gt;
&lt;p&gt;If the MCP bridge approach continues to hold up, it means any MCP server is a potential skill. The ecosystem does the hard work of building and maintaining integrations. NonnaClaw just bridges them. This could enable more flexibility for container-isolated agents, without losing the security primitives. Personally, I&#39;m excited to have an MCP server sitting in front of my music library that Nonna can help me manage.&lt;/p&gt;
&lt;p&gt;If you&#39;d like to check it out, the code is at &lt;a href=&quot;https://github.com/nickdirienzo/nonnaclaw&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;github.com/nickdirienzo/nonnaclaw&lt;/a&gt;.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/what-if-nano-claw-skills-didn-t-need-to-change-the-codebase/" >
        </entry>
        <entry>
            <title>
                Typed integration testing with ts-rest, supertest, and Express
                
            </title>
            <updated>2025-05-29T05:12:00.960Z</updated>
            <id>https://nickdirienzo.com/typed-integration-testing-with-ts-rest-supertest-and-express/</id>
            <content type="html">
                &lt;p&gt;We&#39;ve been happily using &lt;code&gt;ts-rest&lt;/code&gt; at Mirage Security for about a year now. There&#39;s more to be written about why we went with &lt;code&gt;ts-rest&lt;/code&gt; and how we use it to efficiently build features. This is about testing with it because I couldn&#39;t find any clear guides on how to test &lt;code&gt;ts-rest&lt;/code&gt; and there&#39;s an unanswered &lt;a href=&quot;https://discord.com/channels/1055855205960392724/1055857825831731200/1259172105677836298&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;question in Discord&lt;/a&gt; so here&#39;s how we approached it.&lt;/p&gt;
&lt;p&gt;When building APIs, I&#39;ve found integration tests to be the more valuable kinds of tests to write than unit tests. You can codify expected end-user API behavior in tests, can validate database state, and generally have more confidence it&#39;ll work in production. With agentic coding tools like VSCode Copilot or Windsurf Cascade, the cost of writing these kinds of tests become 0 so we have way more test coverage than I would have expected at this stage while still shipping incredibly quickly.&lt;/p&gt;
&lt;p&gt;There were two problems to solve for us to get integration tests working:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How do we share database access between our test harness and the API implementations so that we can create data within the test block and have the API handler be able to use them?&lt;/li&gt;
&lt;li&gt;How do we use a ts-rest client in our test suite so we can have strong typing and generally reduce what we have to test (because our contracts will validate request input)?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wasn&#39;t sure how to solve these in this TypeScript / Node ecosystem. The codebase has been using a singleton database client which you&#39;ll see in a number of Drizzle examples (this &lt;a href=&quot;https://github.com/drizzlenext/drizzle-next&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;one&lt;/a&gt; or the &lt;a href=&quot;https://orm.drizzle.team/docs/get-started-postgresql&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;official guide&lt;/a&gt;). That works for until it doesn&#39;t. We now needed to share the database connection from outside of the application runtime so we could use it with &lt;code&gt;supertest&lt;/code&gt;, which it seems that everyone was using for testing (at least per Discord).&lt;/p&gt;
&lt;p&gt;To stay in line with &lt;a href=&quot;https://12factor.net/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;12 Factor&lt;/a&gt; principles (which is still extremely good guidance), I wanted the app to not know whether it was using a real database or a test database. To make that happen we used dependency injection. The plan was to have the request context maintain the database client handle, use an app factory (taking inspiration from &lt;a href=&quot;https://flask.palletsprojects.com/en/stable/patterns/appfactories/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Flask&lt;/a&gt;), and pass in a database client to either a managed database or a test database.&lt;/p&gt;
&lt;p&gt;There&#39;s two approaches you can take when testing with &lt;code&gt;ts-rest&lt;/code&gt;. You can hit it with &lt;code&gt;supertest&lt;/code&gt; directly, but then you lose all the client helpers and type safety. Or you can provide &lt;code&gt;initClient&lt;/code&gt; an &lt;code&gt;ApiFetcher&lt;/code&gt; with leverages &lt;code&gt;supertest&lt;/code&gt; under the hood to have the test harness get types. The former is how your non-TS users will use the API, but the latter lets us test really fast using ergonomics we&#39;re already using in the frontend.&lt;/p&gt;
&lt;p&gt;I&#39;m simplifying the code as I copy paste so I wouldn&#39;t expect it to work with a direct copy-paste to your codebase, but I hope it explains what&#39;s supposed to be happening. The full gist can be found here: &lt;a href=&quot;https://gist.github.com/nickdirienzo/73d6cfb6caf29c56219340a7546ebd9c&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://gist.github.com/nickdirienzo/73d6cfb6caf29c56219340a7546ebd9c&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The part that brings &lt;code&gt;supertest&lt;/code&gt; and &lt;code&gt;ts-rest&lt;/code&gt; together is specifically this bit: &lt;script src=&quot;https://gist.github.com/nickdirienzo/73d6cfb6caf29c56219340a7546ebd9c.js?file=tsRest.ts&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;And if there&#39;s a better way to do this, I&#39;d love to hear about it.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/typed-integration-testing-with-ts-rest-supertest-and-express/" >
        </entry>
        <entry>
            <title>
                The internet used to be weird because of humans
                
            </title>
            <updated>2025-05-29T05:19:03.481Z</updated>
            <id>https://nickdirienzo.com/the-internet-used-to-be-weird-because-of-humans/</id>
            <content type="html">
                &lt;p&gt;Maybe it&#39;s nostalgia but I miss the earlier days of the internet. The time when everything wasn&#39;t a walled garden. Communities were smaller and fragmented. Content wasn&#39;t an optimization game or AI slop. You knew you were talking to a person. It was a fun, wild time between forums and flash games.&lt;/p&gt;
&lt;p&gt;We&#39;ve already entered the next stage of the internet. No one knows what&#39;s AI generated or not, or if they&#39;re talking to a bot or a human. I was talking with a friend recently who appreciates reading Reddit comments pre-2024 because every more recent comment reads like something out of a LLM.&lt;/p&gt;
&lt;p&gt;There&#39;s more here on the experiments I&#39;m running to take back some form of control. It&#39;s harder than I thought. Convenience has won. But life is a lot more than just the convenient thing.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/the-internet-used-to-be-weird-because-of-humans/" >
        </entry>
        <entry>
            <title>
                Slack notifications via ntfy.sh
                
            </title>
            <updated>2026-02-15T22:02:41.839Z</updated>
            <id>https://nickdirienzo.com/slack-notifications-via-ntfy-sh/</id>
            <content type="html">
                &lt;p&gt;I&#39;ve been trying to not be too attached to my phone. Over the last couple of years, I&#39;ve dropped Tiktok, Instagram, YouTube Shorts (clearly, there&#39;s a pattern). Every time I have Slack on it, I end up treating it like an infinite feed too, so I try not to have it on my phone either.&lt;/p&gt;
&lt;p&gt;What&#39;s challenging is I&#39;m also on-call for everything. While we have PagerDuty setup for automated incident creation via signals, not everything is covered. So when I get @-mentioned, I&#39;d like to know right away.&lt;/p&gt;
&lt;p&gt;Fortunately, it looks like a wonderful open-source service exists to help do just that: &lt;a href=&quot;https://ntfy.sh/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://ntfy.sh/&lt;/a&gt;. Between that and Claude Code, I now have an 80 line script to do exactly what I need: when I&#39;m @-mentioned in our alerts channel, I am notified on my phone. I rarely go anywhere without my laptop, so it&#39;s really easy to jump right on as needed.&lt;/p&gt;
&lt;p&gt;Anyway it&#39;s 80 lines long. You can find &lt;a href=&quot;https://gist.github.com/nickdirienzo/66e2fe673d4fd662e609fe3984741778&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;the gist here&lt;/a&gt;, and run it wherever your heart desires.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/slack-notifications-via-ntfy-sh/" >
        </entry>
        <entry>
            <title>
                Shipping faster with conductor.build and merge queues
                
            </title>
            <updated>2026-02-28T21:41:21.988Z</updated>
            <id>https://nickdirienzo.com/shipping-faster-with-conductor-build-and-merge-queues/</id>
            <content type="html">
                &lt;p&gt;I feel like I hit a new level of productivity this week due to some changes in my tooling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;conductor.build&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I wanted a better frontend for Claude Code (partially why I was building &lt;a href=&quot;https://github.com/nickdirienzo/inc&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;inc&lt;/a&gt;, but that&#39;s more of a software factory experiment). I found that this week in &lt;a href=&quot;https://www.conductor.build/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Conductor&lt;/a&gt;. Within a day I was already telling a ton of friends about it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nickdirienzo.com/img/user/Pasted%20image%2020260211203710.png&quot; alt=&quot;Pasted image 20260211203710.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Today I had about 10 workspaces open, each with multiple tabs; it&#39;s a native Mac app so it doesn&#39;t suffer from the same performance problems that I get with Claude Desktop -- but with my usage, I&#39;ve found it too sometimes be sluggish.&lt;/p&gt;
&lt;p&gt;While I&#39;ve largely stopped using VS Code, I still go to GitHub for PR review, status check resolution, and releases. It&#39;s very possible that Conductor could be my entire command center for shipping; they already have built-in check failure resolution and merging, so I fully expect them to continue to obviate the need to go anywhere else. Excited to see where they take it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Merge Queues&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&#39;ve been meaning to set these up for months as we&#39;ve been shipping at an increasing rate with Claude Code, but our Conductor usage in the last 48 hours has made it an obvious need.&lt;/p&gt;
&lt;p&gt;Auto-merging is such an immediate payoff. Claude Code makes it a breeze to migrate our apparently 46 GHA jobs over to use merge queues.&lt;/p&gt;
&lt;p&gt;I do find it very ridiculous that this is behind the Enterprise tier on GitHub. Yes, I could explore Graphite, GitLab, and any other alternative, but I don&#39;t see a need in shifting the platform we use... yet. With GitHub&#39;s continuing outages though, I won&#39;t say it hasn&#39;t crossed my mind.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/shipping-faster-with-conductor-build-and-merge-queues/" >
        </entry>
        <entry>
            <title>
                Please stop calling your auth startup open source
                
            </title>
            <updated>2026-01-27T05:58:20.142Z</updated>
            <id>https://nickdirienzo.com/please-stop-calling-your-auth-startup-open-source/</id>
            <content type="html">
                &lt;p&gt;I saw yet another Show HN for &amp;quot;open source B2B SaaS auth-in-a-box&amp;quot; today. It feels like the 4th time in the last year. The pitch is always the same: here&#39;s everything you need to authenticate in the enterprise, all on GitHub. Except it&#39;s not &lt;em&gt;all&lt;/em&gt; on GitHub.&lt;/p&gt;
&lt;p&gt;Since companies like WorkOS have taken off and Auth0 has been acquired by Okta ignoring all the startups, I&#39;ve been seeing this trend of new companies pop up who lead with open source, build developer mindshare / adoption on GitHub and then you&#39;re stuck in their upsell funnel.&lt;/p&gt;
&lt;p&gt;My problem is &lt;em&gt;these projects aren&#39;t actually open source&lt;/em&gt;. At best they&#39;re open core -- with everything you &lt;em&gt;actually&lt;/em&gt; need to deploy these into production locked behind a paywall. At worst, it&#39;s a gross bait and switch.&lt;/p&gt;
&lt;h2 id=&quot;some-and-quot-open-source-and-quot-examples&quot; tabindex=&quot;-1&quot;&gt;Some &amp;quot;open source&amp;quot; examples&lt;/h2&gt;
&lt;p&gt;I wish I were making this up. Here are some pricing pages for some up and coming open source auth projects.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tesseral-labs/tesseral&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Tesseral&lt;/a&gt;: you can&#39;t even run on your own domain for &amp;lt; $250/mo.&lt;img src=&quot;https://nickdirienzo.com/img/user/Pasted%20image%2020250528194401.png&quot; alt=&quot;Pasted image 20250528194401.png&quot; /&gt;&lt;br /&gt;
&lt;a href=&quot;https://supertokens.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;SuperTokens&lt;/a&gt;: multi-tenancy doesn&#39;t even come in the free self-hosted version so I suppose you can only support one customer at a time.&lt;img src=&quot;https://nickdirienzo.com/img/user/Pasted%20image%2020250528194347.png&quot; alt=&quot;Pasted image 20250528194347.png&quot; /&gt;&lt;br /&gt;
&lt;s&gt;&lt;a href=&quot;https://boxyhq.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;BoxyHQ&lt;/a&gt;: you have to pay to customize branding on something you host yourself.&lt;/s&gt; Turns out &lt;a href=&quot;https://www.ory.sh/blog/introducing-ory-polis-for-enterprise-single-sign-on&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Boxy was acquired by Ory&lt;/a&gt; (congrats team Boxy!) a day after I wrote this, so I&#39;m dropping from this list.&lt;/p&gt;
&lt;p&gt;Ory’s been doing great work here for a long time. But they did raise a $22M Series A in 2022 (congrats team Ory!) so we&#39;ll see how things play out over time. Candidly, I haven&#39;t been keeping too close an eye on them but I&#39;ve only ever heard good things.&lt;/p&gt;
&lt;p&gt;Companies like WorkOS and Auth0/Okta are clear that you&#39;re locked into cloud pricing. At least they&#39;re not pretending to be an open source project. You are paying for a company to manage auth for you -- and that&#39;s fine. You know what you&#39;re buying that lock-in so you can focus on your product.&lt;/p&gt;
&lt;h2 id=&quot;how-have-we-not-solved-auth-already&quot; tabindex=&quot;-1&quot;&gt;How have we not solved auth already?&lt;/h2&gt;
&lt;p&gt;Getting authentication right is a core part of every business. You can (and probably should) outsource it -- it&#39;s not your core competency. Instead of betting your core infrastructure on a startup pretending to be open source, you can bet on something battle-tested that is truly open source.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.keycloak.org/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Keycloak&lt;/a&gt; (supported by CNCF) has been doing a fantastic job here for over 10 years. They now support &lt;a href=&quot;https://github.com/keycloak/keycloak/issues/30180&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Organizations&lt;/a&gt; and there&#39;s work to be done still, but the path is there for true open source B2B auth support. Thanks Keycloak maintainers and CNCF for doing the hard work.&lt;/p&gt;
&lt;p&gt;There&#39;s a whole &lt;a href=&quot;https://www.keycloak.org/extensions&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;ecosystem of plugins&lt;/a&gt; which gives a chance for companies to contribute back openly so everyone can benefit. Originally organizations were supported by one of these extensions and now it&#39;s becoming a part of the core functionality. This is a win for Keycloak and a win for the software industry.&lt;/p&gt;
&lt;p&gt;Auth feels like it should be solved territory by now. Logging in with Google or Microsoft Entra is a standard OAuth2 flow. A ton of companies have standardized around Okta for SSO. And supporting SSO is achievable through a number of open source projects like Keycloak, &lt;a href=&quot;https://www.passportjs.org/packages/passport-saml/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;passport-saml&lt;/a&gt;, &lt;a href=&quot;https://github.com/grafana/django-saml2-auth&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;django-saml2-auth&lt;/a&gt;, and others.&lt;/p&gt;
&lt;h2 id=&quot;where-do-we-go-from-here&quot; tabindex=&quot;-1&quot;&gt;Where do we go from here?&lt;/h2&gt;
&lt;p&gt;It&#39;s frustrating seeing a core piece of infrastructure be touted as open source when the &amp;quot;open&amp;quot; part is just lead gen.&lt;/p&gt;
&lt;p&gt;With auth being easier, the next hurdle is around identity management. That&#39;s getting easier too: Microsoft&#39;s Graph API is actually really good and Google Workspace has APIs for users. And for everything that&#39;s not Microsoft or Google there is SCIM.&lt;/p&gt;
&lt;p&gt;There are so many companies out there that rely on Microsoft or Google. I don&#39;t think you need some open-core SaaS vendor in the middle anymore. You can just directly integrate with the identity platforms.&lt;/p&gt;
&lt;p&gt;Hopefully we can stop rebuilding auth every year as a new startup and instead invest in solutions that are truly open, sustainable and portable.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/please-stop-calling-your-auth-startup-open-source/" >
        </entry>
        <entry>
            <title>
                Obsidian Digital Garden on Cloudflare
                
            </title>
            <updated>2025-05-18T02:15:58.398Z</updated>
            <id>https://nickdirienzo.com/obsidian-digital-garden-on-cloudflare/</id>
            <content type="html">
                &lt;p&gt;I&#39;m using the &lt;a href=&quot;https://dg-docs.ole.dev/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Obsidian Digital Garden Plugin&lt;/a&gt; for my &lt;a class=&quot;internal-link&quot; target=&quot;&quot; data-note-icon=&quot;&quot; href=&quot;https://nickdirienzo.com/digital-gardening/&quot;&gt;Digital Gardening&lt;/a&gt;. While I haven&#39;t used Obsidian Publish, it&#39;s reduced my barrier to publishing on the internet. Write some thoughts down, tag it as &lt;code&gt;dg-publish: true&lt;/code&gt;, &lt;code&gt;cmd+p&lt;/code&gt; Publish, done.&lt;/p&gt;
&lt;p&gt;The plugin&#39;s default recommendation is Vercel. I tend to not use Vercel for a variety of reasons.&lt;/p&gt;
&lt;p&gt;Instead I&#39;m publishing on Cloudflare Pages. I&#39;ve used Cloudflare Pages for a number of static sites and single page apps over the last couple of years. It&#39;s awesome to be able to connect a GitHub repo to Cloudflare and have them manage CICD.&lt;/p&gt;
&lt;p&gt;It&#39;ll be fun to use more of the Cloudflare products over time. If I start to lean into Cloudflare more for personal infrastructure, I&#39;ll need to figure out their Terraform provider. For now ClickOps is the way.&lt;/p&gt;
&lt;p&gt;Anyway, after connecting the repo, it didn&#39;t immediately work when selecting 11ty as the framework. It&#39;s because there&#39;s some custom build tooling. I had to set the following options and then everything was good:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Framework preset: None&lt;/li&gt;
&lt;li&gt;Build command: &lt;code&gt;npm run build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Build output directory: &lt;code&gt;dist&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a fun bonus of this side quest, Cloudflare now manages my DNS.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/obsidian-digital-garden-on-cloudflare/" >
        </entry>
        <entry>
            <title>
                Learnings from building inc
                
            </title>
            <updated>2026-01-27T06:48:56.057Z</updated>
            <id>https://nickdirienzo.com/learnings-from-building-inc/</id>
            <content type="html">
                &lt;p&gt;I&#39;m experimenting with agent orchestration on top of Claude Code. It&#39;s inspired a lot by gastown and others, but it&#39;s my own personal take on it. It&#39;s called &lt;a href=&quot;https://github.com/nickdirienzo/inc&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;inc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;More to write about this, but the short thesis is: because agents don&#39;t have human ramp up costs, we can break free of Conway&#39;s Law -- the &amp;quot;org structure&amp;quot; (ephemeral virtual teams) mirrors the problem structure, instead of the architecture mirroring the org structure.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restricting access to files is kind-of hard today with Claude Code within a spawned directory. Yes you can restrict Edit/Write, but if the agent has Bash, all bets are off. Fortunately, it seems like it will only have access to files within its spawned directory, but there&#39;s a need for improved filesystem sandboxing.&lt;/li&gt;
&lt;li&gt;I&#39;m not sure if a TUI is the way, but it&#39;s kinda neat.&lt;/li&gt;
&lt;li&gt;Agents are still really bad at complex instruction following, so guardrails are a must. Otherwise your repo will get rekt:
&lt;ul&gt;
&lt;li&gt;Case 1: Coder agents really like trying to read the default workspace files even though they operate in a completely separate codebase&lt;img src=&quot;https://nickdirienzo.com/img/user/Pasted%20image%2020260125161139.png&quot; alt=&quot;Pasted image 20260125161139.png&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Case 2: the PM agent completing a spec and spinning anyway &lt;img src=&quot;https://nickdirienzo.com/img/user/Pasted%20image%2020260125201656.png&quot; alt=&quot;Pasted image 20260125201656.png&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Claude Skills are awesome. Most of this is powered by Claude Skills and a thin CLI tool to manage file writing synchronization.&lt;/li&gt;
&lt;li&gt;The technologies we&#39;ve used as humans to communicate: files, emails, etc are still valid for agents. Right now, inc is using files to request attention, but I think the next iteration of this is to use email or some task management system. It kinda could be &lt;em&gt;anything&lt;/em&gt; that lets people communicate.&lt;/li&gt;
&lt;/ul&gt;

            </content>
            <link href="https://nickdirienzo.com/learnings-from-building-inc/" >
        </entry>
        <entry>
            <title>
                Leaning into Claude Code
                
            </title>
            <updated>2026-01-27T21:05:40.348Z</updated>
            <id>https://nickdirienzo.com/leaning-into-claude-code/</id>
            <content type="html">
                &lt;p&gt;I&#39;ve had a couple of friends ask how I use Claude Code, so figured to write it down here.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;At least at the moment, I view it as a skill on its own. Being able to stay on top of 7+ concurrent workstreams that are pretty different while still maintaining taste is tough. The current tooling doesn&#39;t make it much easier.&lt;/p&gt;
&lt;p&gt;When I first started using Claude Code more seriously (July 2025), I was mostly just using Claude Code one at a time. I was tinking about features in smaller incremental blocks instead of a larger milestone. When I first started, I was still in the prior mindset, so I would be pretty hands-on, I wasn&#39;t really doing planning, it was a lot of prompting but in the way I would delegate work to an engineer.&lt;/p&gt;
&lt;p&gt;Over the next few months, I started to get a little bit more ambitious. I introduced a self-hosted Coder instance where I could start having CC work in the background mostly autonomously. What really unlocked parallelization for me was Claude Desktop introducing Code. It has built-in support for worktrees, which made the need for Coder a bit redundant (we still have it for now).&lt;/p&gt;
&lt;p&gt;Two things shifted in my head around the same time, starting to use &lt;a class=&quot;internal-link&quot; target=&quot;&quot; data-note-icon=&quot;&quot; href=&quot;https://nickdirienzo.com/working-with-jujutsu/&quot;&gt; jj&lt;/a&gt; and seeing &lt;a href=&quot;https://x.com/bcherny/status/2007179832300581177&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Boris&#39; workflow on X&lt;/a&gt;:&lt;img src=&quot;https://nickdirienzo.com/img/user/Pasted%20image%2020260127124351.png&quot; alt=&quot;Pasted image 20260127124351.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The other change in workflow I made was Plan Mode. I articulated the product vision and the high-level architecture, and then let Claude interpret my scattered thoughts into a concrete plan it could execute on. I would review the plan as a file and send suggestions as chat, which would then update the file. Once the plan looked good, I let it auto-edit until it&#39;s ready for a PR.&lt;/p&gt;
&lt;p&gt;There&#39;s some foundational investments that make this safe to do for us. Early on I laid the groundwork for ADRs which provides historical context on why we&#39;ve made certain significant architectural decisions, we have a giant TypeScript monorepo so everything is grokkable in one directory, and we have way more test coverage than I think a seed stage company should have. The cost for code is 0 so might as well have tests.&lt;/p&gt;
&lt;p&gt;With this workflow, I started to see a natural progression from 3 -&amp;gt; 5 -&amp;gt; 7 CC tasks in parallel thanks for Claude Desktop Code having native worktree support. Sprinkled with a Coder task here and there. This enabled me to move up from code as the artifact I was reviewing to instead reviewing plans, which is where I like operating.&lt;/p&gt;
&lt;p&gt;For fun, I tried to not open my editor for a week and was largely successful. I would review the plans in chat -- which Claude Desktop makes it less painful visually. I would have it put up a PR, Claude Code would review the PR, I would then have Claude Code iterate on the changes. I would do a pass on the change and leave comments on the PR, which then I would tell CC to review and fix. This worked.&lt;/p&gt;
&lt;p&gt;With this level of work in parallel, I find myself bombarded with notifications. I haven&#39;t fully adopted full YOLO mode because I&#39;ve seen CC regress into using &lt;code&gt;sed&lt;/code&gt; instead of &lt;code&gt;Edit&lt;/code&gt;/&lt;code&gt;Write&lt;/code&gt; so it hasn&#39;t earned that level of trust yet. BUT, I think that&#39;s solvable.&lt;/p&gt;
&lt;p&gt;I think there&#39;s a more autonomous workflow here that I&#39;m &lt;a href=&quot;https://github.com/nickdirienzo/inc&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;tinkering with&lt;/a&gt;, but just moving up to the high-level alone -- even with all the road bumps in the current iteration of UX -- has enabled me to effectively double my output.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;relevant-links&quot; tabindex=&quot;-1&quot;&gt;Relevant links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://x.com/bcherny/status/2007179832300581177&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://x.com/bcherny/status/2007179832300581177&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.geoffreychallen.com/talks/2026-01-15-a-day-with-claude-using-and-teaching-coding-agents&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://www.geoffreychallen.com/talks/2026-01-15-a-day-with-claude-using-and-teaching-coding-agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://x.com/karpathy/status/2015883857489522876&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://x.com/karpathy/status/2015883857489522876&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

            </content>
            <link href="https://nickdirienzo.com/leaning-into-claude-code/" >
        </entry>
        <entry>
            <title>
                How do I have 473GB of used disk space?
                
            </title>
            <updated>2025-07-12T14:37:45.521Z</updated>
            <id>https://nickdirienzo.com/how-do-i-have-473-gb-of-used-disk-space/</id>
            <content type="html">
                &lt;p&gt;I was trying to run some tests today and out of nowhere &lt;a class=&quot;internal-link&quot; target=&quot;&quot; data-note-icon=&quot;&quot; href=&quot;https://nickdirienzo.com/goodbye-docker-desktop-hello-orb-stack/&quot;&gt;OrbStack&lt;/a&gt; crashes so all my Docker containers are no longer reachable.&lt;/p&gt;
&lt;p&gt;I see OrbStack bouncing in the dock. After trying to start containers up again, I get this lovely error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;panic: rename /Users/nickdirienzo/.orbstack/log/vmgr.log /Users/nickdirienzo/.orbstack/log/vmgr.1.log: no space left on device

goroutine 17 [running, locked to thread]:
github.com/orbstack/macvirt/vmgr.check(...)
	github.com/orbstack/macvirt/vmgr/main.go:127
github.com/orbstack/macvirt/vmgr.runSpawnDaemon()
	github.com/orbstack/macvirt/vmgr/daemon.go:114 +0x46c
github.com/orbstack/macvirt/vmgr.Main()
	github.com/orbstack/macvirt/vmgr/main.go:1208 +0xf4
github.com/orbstack/macvirt/vmgr/cgostub/mainfunc.main(...)
	github.com/orbstack/macvirt/vmgr/cgostub/mainfunc/mainfunc.go:13
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Excuse me? I have nearly half a TB in used disk and this laptop is only used for work. Where did all of this disk space go? Is this real?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nickdirienzo@Nicks-MacBook-Pro mirage % df -h
Filesystem        Size    Used   Avail Capacity iused ifree %iused  Mounted on
/dev/disk3s1s1   460Gi    10Gi   132Mi    99%    426k  1.4M   24%   /
devfs            205Ki   205Ki     0Bi   100%     710     0  100%   /dev
/dev/disk3s6     460Gi    11Gi   132Mi    99%      12  1.4M    0%   /System/Volumes/VM
/dev/disk3s2     460Gi   6.7Gi   132Mi    99%    1.2k  1.4M    0%   /System/Volumes/Preboot
/dev/disk3s4     460Gi   3.5Mi   132Mi     3%      58  1.4M    0%   /System/Volumes/Update
/dev/disk1s2     500Mi   6.0Mi   481Mi     2%       1  4.9M    0%   /System/Volumes/xarts
/dev/disk1s1     500Mi   5.4Mi   481Mi     2%      32  4.9M    0%   /System/Volumes/iSCPreboot
/dev/disk1s3     500Mi   2.4Mi   481Mi     1%      93  4.9M    0%   /System/Volumes/Hardware
/dev/disk3s5     460Gi   431Gi   132Mi   100%    5.5M  1.4M   80%   /System/Volumes/Data
map auto_home      0Bi     0Bi     0Bi   100%       0     0     -   /System/Volumes/Data/home
/dev/disk3s7     460Gi   2.0Mi   132Mi     2%     340  1.4M    0%   /Volumes/0CDCC59F-29F8-4E20-917C-C1A088D7A33D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turns out, yes this is very real. I haven&#39;t had to diagnose this issue on Mac before. On Windows, there&#39;s WinDirStat which is quite helpful. o3 pointed me to &lt;code&gt;ncdu&lt;/code&gt; which is effectively that but for the terminal. TIL! Sadly, it doesn&#39;t run in Ghostty.&lt;/p&gt;
&lt;p&gt;I ran using &lt;code&gt;ncdu -x&lt;/code&gt; which tells it to stay on the same filesystem (i.e. ignore Time Machine backups). After quickly scanning everything, it provides a helpful interactive overview:&lt;img src=&quot;https://nickdirienzo.com/img/user/Pasted%20image%2020250712063631.png&quot; alt=&quot;Pasted image 20250712063631.png&quot; /&gt;&lt;br /&gt;
The overall usage numbers at the bottom are way over my actual hardware disk so not sure what&#39;s going on there. But I have 2 obvious places to dive into: &lt;code&gt;/System&lt;/code&gt; and &lt;code&gt;/User&lt;/code&gt;. Let&#39;s start with &lt;code&gt;/User&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My home directory is using 329GB. My &lt;code&gt;code&lt;/code&gt; directory which is where I keep everything checked out is 84GB! I want to blame node modules.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;~/Library&lt;/code&gt; seems to be the bigger culprit with 151GB used. 83GB are used by &lt;code&gt;~/Library/Containers&lt;/code&gt; and nearly all of that is used by &lt;code&gt;~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I just migrated from Docker Desktop to OrbStack this week and OrbStack manages its own data elsewhere, so there&#39;s probably a duplicate 83GB elsewhere (narrator: there wasn&#39;t).&lt;/p&gt;
&lt;p&gt;OrbStack stores its data in &lt;code&gt;~/Library/Group Containers/HUAQ24HBR6.dev.orbstack/data&lt;/code&gt; per the &lt;a href=&quot;https://docs.orbstack.dev/faq#orbstack-folder&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;FAQ&lt;/a&gt;. And that also explains some of the apparent 16TB size because it has a 8TB sparse file for storing container assets. Is this also 83GB?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nickdirienzo@Nicks-MacBook-Pro data % du -h ~/Library/Group&#92; Containers/HUAQ24HBR6.dev.orbstack/data/data.img
5.5G    /Users/nickdirienzo/Library/Group Containers/HUAQ24HBR6.dev.orbstack/data/data.img
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nope. I&#39;m glad I was wrong earlier about a duplicate 83GB. Because OrbStack manages its own data, &lt;a href=&quot;https://github.com/orgs/orbstack/discussions/1606&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;it doesn&#39;t need the &lt;code&gt;Docker.raw&lt;/code&gt;&lt;/a&gt; for managing Docker container images, volumes, etc so there&#39;s a wonderful reclaim of 83GB. I thought I removed Docker Desktop via &lt;code&gt;brew&lt;/code&gt;? I guess it leaves the data around. That&#39;s good to know.&lt;/p&gt;
&lt;p&gt;I can&#39;t fully delete the full &lt;code&gt;com.docker.docker&lt;/code&gt; directory even with &lt;code&gt;sudo&lt;/code&gt;. Whatever. At least I have 83GB back. I still have 248GB of data in my home directory, what now? 79GB in my &lt;code&gt;~/code/mirage&lt;/code&gt; directory for everything related to that. Ah, 52GB for an unused dataset. Nice. Other fun finds are 1GB in Terraform providers for a single service -- I didn&#39;t realize it could be that big.&lt;/p&gt;
&lt;p&gt;Now we&#39;re at 135GB reclaimed. That&#39;s enough of a win. And no, it wasn&#39;t node&#39;s fault.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/how-do-i-have-473-gb-of-used-disk-space/" >
        </entry>
        <entry>
            <title>
                Home
                
            </title>
            <updated>2025-05-17T20:48:07.205Z</updated>
            <id>https://nickdirienzo.com/</id>
            <content type="html">
                &lt;p&gt;This is my attempt at &lt;a class=&quot;internal-link&quot; target=&quot;&quot; data-note-icon=&quot;&quot; href=&quot;https://nickdirienzo.com/digital-gardening/&quot;&gt;Digital Gardening&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;m mostly writing for me, but maybe some of these pages are helpful to you too.&lt;/p&gt;
&lt;p&gt;I&#39;m moving away from social media, but you can still find me on &lt;a href=&quot;https://www.linkedin.com/in/nickdirienzo/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;LinkedIn&lt;/a&gt; and &lt;a href=&quot;https://github.com/nickdirienzo&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/" >
        </entry>
        <entry>
            <title>
                Goodbye Docker Desktop, hello OrbStack
                
            </title>
            <updated>2025-07-12T14:11:45.387Z</updated>
            <id>https://nickdirienzo.com/goodbye-docker-desktop-hello-orb-stack/</id>
            <content type="html">
                &lt;p&gt;My partner runs a small software company. In a recent update, they shared:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We’ve dropped Docker Desktop for Mac in favor of OrbStack. We’ve been using containers for engineering work for a while and Docker has never felt good. OrbStack does everything Docker for Mac does and more, costs less, and is easier to use.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Funny enough at the same time, my Docker Desktop was having a &lt;em&gt;time&lt;/em&gt;:&lt;br /&gt;
&lt;img src=&quot;https://nickdirienzo.com/img/user/Pasted%20image%2020250712070420.png&quot; alt=&quot;Pasted image 20250712070420.png&quot; /&gt;&lt;br /&gt;
I&#39;m really not sure how Docker Desktop lost a long running database container, but it did and now I have an excuse to try a different container orchestrator. It&#39;s job is to run Docker containers and it can&#39;t even do that.&lt;/p&gt;
&lt;p&gt;After running the built-in OrbStack migration, I ran &lt;code&gt;docker ps&lt;/code&gt; and it came back super fast. I didn&#39;t do a timer comparison but I&#39;ve been noticing using &lt;code&gt;docker&lt;/code&gt; commands getting slower.&lt;/p&gt;
&lt;p&gt;Well this is amazing. I am sold. It boots so fast, the UI is snappy and clean, and everything feels better. Immediately signed up for a Pro account.&lt;/p&gt;
&lt;p&gt;I&#39;m glad people are still making great foundational software. Go team OrbStack!&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/goodbye-docker-desktop-hello-orb-stack/" >
        </entry>
        <entry>
            <title>
                Go-to message queue in 2025? For me, it&#39;s Temporal
                
            </title>
            <updated>2026-03-31T22:46:51.636Z</updated>
            <id>https://nickdirienzo.com/go-to-message-queue-in-2025-for-me-it-s-temporal/</id>
            <content type="html">
                &lt;p&gt;Sadly I don&#39;t have a lobste.rs account so I can&#39;t answer &lt;a href=&quot;https://lobste.rs/s/uwp2hd/what_s_your_go_message_queue_2025&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;the question&lt;/a&gt; there, but I had some thoughts and wanted to share.&lt;/p&gt;
&lt;p&gt;In 2025, I think most companies &lt;em&gt;don&#39;t&lt;/em&gt; need a message queue. Message queues still have their place -- like with edge ingestion or buffering -- but I&#39;m not sure I would reach for them for codifying business logic knowing systems like Temporal exist.&lt;/p&gt;
&lt;p&gt;I&#39;ve been building with Temporal for over a year now in production, so maybe I drank too much durable execution Kool-Aid.&lt;/p&gt;
&lt;p&gt;If you&#39;re starting from scratch, a better option is to use a system like Temporal, which gives you exactly-once delivery, durability, and retries out of the box.&lt;/p&gt;
&lt;p&gt;With a message queue, you have to handle all of those foundations yourself. Retries are easy, sure. Idempotency is a bit harder. Durable state that survives crashes and resumes from exactly where it left off? That’s where Temporal shines. It feels like magic.&lt;/p&gt;
&lt;p&gt;The one major trade-off here is vendor lock-in. Once you start building with Temporal and really lean into it, it&#39;s really challenging to back out of. Fortunately you can self-host but operating a Cassandra stack is not very fun.&lt;/p&gt;
&lt;p&gt;Still, for business logic, it&#39;s hard to beat what Temporal provides. Message queues feel like writing C in a world where you can just write TypeScript.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!note] Aside&lt;br /&gt;
I know this probably sounds like I’m shilling for a company -- and I guess I am. But it’s been a long time since I’ve used a developer infrastructure product that genuinely changes the way I build software and I want more people to know about it.&lt;/p&gt;
&lt;/blockquote&gt;

            </content>
            <link href="https://nickdirienzo.com/go-to-message-queue-in-2025-for-me-it-s-temporal/" >
        </entry>
        <entry>
            <title>
                Generating phone numbers with @faker-js and libphonenumber-js
                
            </title>
            <updated>2025-07-12T14:42:43.717Z</updated>
            <id>https://nickdirienzo.com/generating-phone-numbers-with-faker-js-and-libphonenumber-js/</id>
            <content type="html">
                &lt;p&gt;One of the interview questions I use for Mirage is around formatting phone numbers. If you&#39;ve worked around telephony at all, you know that this is not straightforward.&lt;/p&gt;
&lt;p&gt;For us, this problem is challenging because we sync enterprise directory data where formats are all over the place, country codes may or may not exist, and there might be nested numbers where one has preference.&lt;/p&gt;
&lt;p&gt;So I built a dataset in support of this question to dive deep. How do you approach problems like these? What options do we have when dealing with a gnarly dataset like this? Is this a good use case for AI?&lt;/p&gt;
&lt;p&gt;This isn&#39;t about how to answer those questions well, but I did find generating this dataset really interesting and fun. And I learned that &lt;code&gt;libphonenumber-js&lt;/code&gt; has a built-in function for generating example phone numbers: &lt;code&gt;getExampleNumber&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can mimic this messy data a couple of ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using &lt;code&gt;faker.phone.number()&lt;/code&gt;: by default, this uses the &lt;code&gt;&amp;quot;human&amp;quot;&lt;/code&gt; format, which generates numbers like: &amp;quot;1-317-870-1507 x49566&amp;quot;, &amp;quot;861.911.5285&amp;quot;, and &amp;quot;(978) 485-5429&amp;quot;, so we can provide cases around country codes and extensions being available or not.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;getExampleNumber&lt;/code&gt; from &lt;code&gt;libphonenumber-js&lt;/code&gt;: this lets us generate international phone numbers for arbitrary countries. For example:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import examples from &#39;libphonenumber-js/mobile/examples&#39;
import { parsePhoneNumberFromString, getExampleNumber } from &#39;libphonenumber-js&#39;;

const countryCodes = [&#39;US&#39;, &#39;GB&#39;, &#39;DE&#39;, &#39;IN&#39;, &#39;BR&#39;, &#39;JP&#39;, &#39;ZA&#39;, &#39;FR&#39;, &#39;AU&#39;, &#39;CA&#39;];
const country = countryCodes[Math.floor(Math.random() * countryCodes.length)];
const newNumber = getExampleNumber(country, examples)?.formatInternational();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is only a small part of the script that I built out for the interview problem, but I learned a thing or two so figured to write it down. I&#39;m trying to get better at this learning in public thing.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/generating-phone-numbers-with-faker-js-and-libphonenumber-js/" >
        </entry>
        <entry>
            <title>
                Digital Gardening
                
            </title>
            <updated>2025-05-17T20:35:06.263Z</updated>
            <id>https://nickdirienzo.com/digital-gardening/</id>
            <content type="html">
                &lt;p&gt;A couple months ago, I asked a friend about his homelab setup. He sent me a link to his website. I didn&#39;t even realize he had one, so I clicked around some more and came across the phrase &amp;quot;digital garden.&amp;quot;&lt;/p&gt;
&lt;p&gt;At first glance the concept resonated with me because there are many thoughts, ideas, and experiences I&#39;d like to share more publicly but every time I&#39;ve written something on the internet, I felt a ton of anxiety about making the writing compelling, relevant, and interesting.&lt;/p&gt;
&lt;p&gt;This created a really high bar for me to just write thoughts down and put them on the internet. Growing up with the internet, I dabbled with posting here and there, even creating my own &lt;a href=&quot;https://github.com/nickdirienzo/web.py-Blog&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;CMS&lt;/a&gt; on top of App Engine way back when. I wrote some things down but couldn&#39;t get into the habit of it because perfection was getting in the way. I don&#39;t think I&#39;m a very good writer, but I write a lot personally (journaling, etc) and professionally (internal memos, posts, tech specs, product docs).&lt;/p&gt;
&lt;p&gt;I don&#39;t get the same hang up with those non-public writings. I&#39;d like to carry over those practices to something public on the internet.&lt;/p&gt;
&lt;p&gt;So this is my attempt at that. I hope to write a lot more here. I expect the quality to be varied and I&#39;ll use it as an opportunity to continue writing what I learn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While looking into the idea of a digital garden, I read a number of articles about what they are and how people think about them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://maggieappleton.com/garden-history/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://maggieappleton.com/garden-history/&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;A garden is a collection of evolving ideas that aren’t strictly organised by their publication date. They’re inherently exploratory – notes are linked through contextual associations. They aren’t refined or complete - notes are published as half-finished thoughts that will grow and evolve over time. They’re less rigid, less performative, and less perfect than the personal websites we’re used to seeing.&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Gardens are &lt;strong&gt;imperfect by design&lt;/strong&gt;. They don’t hide their rough edges or claim to be a permanent source of truth.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.swyx.io/digital-garden-tos&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://www.swyx.io/digital-garden-tos&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;We have been conditioned for decades to believe in the finality and authority of the printed word. The widely accepted Rules of Good Writing exhort writers to use active voice and drop weasel words.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://elizabethtai.com/2025/05/13/pushback-against-digital-gardens/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://elizabethtai.com/2025/05/13/pushback-against-digital-gardens/&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;Digital gardens give you the freedom to &lt;a href=&quot;https://elizabethtai.com/2023/06/20/how-im-healing-from-algorithms/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;break free of preconceived&lt;/a&gt; notions or “best practices” on how to write on the Internet.&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;I write in my digital garden because I want to clarify my ideas and what I’ve learned. By writing and teaching others about my ideas and learnings, I get to solidify what I’ve learned in my brain.&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;In the end, I write in my digital garden because it makes me happy.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://elizabethtai.com/2025/05/10/digital-gardens-vs-blogging-whats-the-difference/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://elizabethtai.com/2025/05/10/digital-gardens-vs-blogging-whats-the-difference/&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;Last year or so, I discovered digital gardening, and it’s like having a light bulb go off in a path shrouded by mists. I’ve had this idea to write on the web this way, but I just didn’t know what to call it. Once I got a solidified concept, I grew extremely excited!&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;The real star of the show is the knowledge being tended in the digital garden. Personal branding is more of an afterglow of the digital garden, a side effect rather than the sole purpose of a digital garden. Digital garden content are often incomplete, works-in-progress, not always polished or even well-written.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://joelhooks.com/on-writing-more/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://joelhooks.com/on-writing-more/&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;Seriously. The idea of a &amp;quot;blog&amp;quot; needs to get over itself. Everybody is treating writing as a &amp;quot;content marketing strategy&amp;quot; and using it to &amp;quot;build a personal brand&amp;quot; which leads to the fundamental flawed idea that everything you post has to be polished to perfection and ready to be consumed.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://joelhooks.com/digital-garden/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://joelhooks.com/digital-garden/&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;What makes a garden is interesting. It&#39;s personal. Things are organized and orderly, but with a touch of chaos around the edges.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

            </content>
            <link href="https://nickdirienzo.com/digital-gardening/" >
        </entry>
        <entry>
            <title>
                Bike routes around the Bay Area
                
            </title>
            <updated>2025-07-13T20:35:22.282Z</updated>
            <id>https://nickdirienzo.com/bike-routes-around-the-bay-area/</id>
            <content type="html">
                &lt;p&gt;I started cycling in March 2025 with a new Specialized Sirrus X 2.0. While most of my day to day riding is commuting from Oakland to San Francisco, I&#39;ve found some really great routes.&lt;/p&gt;
&lt;h2 id=&quot;east-bay&quot; tabindex=&quot;-1&quot;&gt;East Bay&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Iron Horse Trail from Dublin BART to Walnut Creek BART: 16~ miles&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;sonoma-county&quot; tabindex=&quot;-1&quot;&gt;Sonoma County&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Sebastopol loop from Forestville: 16~ miles
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.komoot.com/smarttour/14611030&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;https://www.komoot.com/smarttour/14611030&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

            </content>
            <link href="https://nickdirienzo.com/bike-routes-around-the-bay-area/" >
        </entry>
        <entry>
            <title>
                About
                
            </title>
            <updated>2026-03-01T19:52:31.027Z</updated>
            <id>https://nickdirienzo.com/about/</id>
            <content type="html">
                &lt;p&gt;I&#39;m currently building &lt;a href=&quot;https://miragesecurity.ai/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Mirage Security&lt;/a&gt; with my longtime friend &lt;a href=&quot;https://rosslazer.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Ross Lazerowitz&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before Mirage, I was an early engineer at &lt;a href=&quot;https://www.modernhealth.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Modern Health&lt;/a&gt; (5th engineer, eventually Head of Foundations Engineering), spent four years at &lt;a href=&quot;https://www.optimizely.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Optimizely&lt;/a&gt;, and interned twice at Google.&lt;/p&gt;
&lt;p&gt;I studied computer science at the University at Buffalo, where I &lt;a href=&quot;https://scholar.google.com/citations?user=qwcFsGsAAAAJ&amp;amp;hl=en&amp;amp;oi=ao&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;published research&lt;/a&gt; on mobile privacy and co-founded &lt;a href=&quot;https://ubhacking.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;UB Hacking&lt;/a&gt;, the school&#39;s annual hackathon.&lt;/p&gt;
&lt;p&gt;This site is my &lt;a href=&quot;https://nickdirienzo.com/digital-gardening/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;digital garden&lt;/a&gt;: a place to think out loud about building software,&lt;br /&gt;
working with AI, and the startup journey.&lt;/p&gt;
&lt;p&gt;I&#39;m moving away from social media, but you can still find me on &lt;a href=&quot;https://www.linkedin.com/in/nickdirienzo/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;LinkedIn&lt;/a&gt; and &lt;a href=&quot;https://github.com/nickdirienzo&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/about/" >
        </entry>
        <entry>
            <title>
                A reminder on how to sell
                
            </title>
            <updated>2025-06-13T21:38:50.753Z</updated>
            <id>https://nickdirienzo.com/a-reminder-on-how-to-sell/</id>
            <content type="html">
                &lt;p&gt;I tried buying software last week and instead got a reminder on how to sell&lt;/p&gt;
&lt;p&gt;Here’s what happened:&lt;/p&gt;
&lt;p&gt;All 4 vendors had “Book a demo” as the only CTA&lt;/p&gt;
&lt;p&gt;Only 1 had pricing on their website&lt;/p&gt;
&lt;p&gt;2 no showed with zero follow up&lt;/p&gt;
&lt;p&gt;1 cancelled an hour before -- the RSVP got cut off but basically said “$80K/year minimum”&lt;/p&gt;
&lt;p&gt;1 was vibe coded in the last 4 months and might not even work&lt;/p&gt;
&lt;p&gt;I get it: we’re a small team, not an enterprise logo, not your ICP&lt;/p&gt;
&lt;p&gt;But ghosting isn’t a strategy to maximize ARR-- it’s just bad manners&lt;/p&gt;
&lt;p&gt;SaaS is a long game: today’s “unqualified” lead is tomorrow’s buyer, champion or warm intro&lt;/p&gt;
&lt;p&gt;If “Book a demo” is your CTA then please be there when someone shows up&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Discuss on &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7338976666804809729/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

            </content>
            <link href="https://nickdirienzo.com/a-reminder-on-how-to-sell/" >
        </entry>
</feed>
