<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>HanLHo. - Fractional Architect &amp; Software Product Engineer - llm</title>
    <link rel="self" type="application/atom+xml" href="https://hanlho.com/tags/llm/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://hanlho.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-03-29T00:00:00+00:00</updated>
    <id>https://hanlho.com/tags/llm/atom.xml</id>
    <entry xml:lang="en">
        <title>Notes on Why AI is the Third Coming of Domain-Driven Design</title>
        <published>2026-03-29T00:00:00+00:00</published>
        <updated>2026-03-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/notes-on-why-ai-is-the-third-coming-of-domain-driven-design/"/>
        <id>https://hanlho.com/p/notes-on-why-ai-is-the-third-coming-of-domain-driven-design/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/notes-on-why-ai-is-the-third-coming-of-domain-driven-design/">&lt;p&gt;Notes on &quot;Dear Architects&quot; podcast episode: &lt;a href=&quot;https:&#x2F;&#x2F;pod.link&#x2F;1877884226&#x2F;episode&#x2F;YjhhNTA2MTItM2I3ZC00ZTUwLTkzNWEtMTI5ODVhOWVjMzMy&quot;&gt;&quot;Why AI is the Third Coming of Domain-Driven Design&quot;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The title is only a small part of the episode. My main takeaway is that, because AI changes the medium of communication to natural language, precise ubiquitous language will matter even more.&lt;&#x2F;p&gt;
&lt;p&gt;Condensed takeaways:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Modularity should make future change easier.&lt;&#x2F;li&gt;
&lt;li&gt;Coupling should be chosen deliberately.&lt;&#x2F;li&gt;
&lt;li&gt;Boundaries should reflect how teams actually work.&lt;&#x2F;li&gt;
&lt;li&gt;Modeling should optimize for usefulness, not completeness.&lt;&#x2F;li&gt;
&lt;li&gt;Architecture should record its reasoning and assumptions.&lt;&#x2F;li&gt;
&lt;li&gt;Architecture is ongoing judgment and trade-offs, not a one-time design step.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Creating architecture diagrams with C4 and coding agents</title>
        <published>2026-03-11T00:00:00+00:00</published>
        <updated>2026-03-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/creating-architecture-diagrams-with-c4-and-coding-agents/"/>
        <id>https://hanlho.com/p/creating-architecture-diagrams-with-c4-and-coding-agents/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/creating-architecture-diagrams-with-c4-and-coding-agents/">&lt;p&gt;LLMs can draw diagrams, but you get better results with a conceptual model, a validation loop, and a lightweight verification pass against the codebase than with free-form diagramming.&lt;&#x2F;p&gt;
&lt;p&gt;I used the &lt;a href=&quot;https:&#x2F;&#x2F;c4model.com&quot;&gt;C4 model&lt;&#x2F;a&gt; extensively to map architecture landscapes. Last week I saw an opportunity to catch up with it and try it out with coding agents. I found that modelling architecture in a text-based format with guardrails (a DSL with rules) is easier and more consistent for a coding agent. I tried it out on a small Rust project I know well. This post is a field note of my findings.&lt;&#x2F;p&gt;
&lt;aside class=&quot;sidebar-note sidebar-note-right&quot;&gt;
  &lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;c4model.com&quot;&gt;C4&lt;&#x2F;a&gt; is a zoom-in model for software architecture.&lt;&#x2F;p&gt;
&lt;p&gt;This post discusses only the levels we actually need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;System context: people and software systems.&lt;&#x2F;li&gt;
&lt;li&gt;Container: deployable&#x2F;runnable things inside a software system.&lt;&#x2F;li&gt;
&lt;li&gt;Component: the main building blocks inside a container.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;A key element for coding agents: C4 can be expressed as a text model (a DSL), so the architecture model can be edited like code and validated&#x2F;exported via a CLI.&lt;&#x2F;p&gt;
&lt;p&gt;C4 is model-as-code: one model, many views&#x2F;diagrams.&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;h2 id=&quot;the-test-project&quot;&gt;The test project&lt;&#x2F;h2&gt;
&lt;p&gt;To try this out, I used one of my personal projects: a text-based &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;simple-time-tracker&quot;&gt;time-tracking application&lt;&#x2F;a&gt; with two runtime modes (a CLI and a web dashboard). Both operate on the same domain and the same Markdown time-entry files.&lt;&#x2F;p&gt;
&lt;p&gt;The functionality does not matter much for this post, except for two things. First, the codebase is relatively small and easy to analyse. Second, it is well-structured: ports and adapters, plus behaviour-driven, DSL-based acceptance tests.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve used C4 on larger landscapes too. I expect the workflow to translate, but the experience will differ on larger (or less structured) codebases.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;building-the-model&quot;&gt;Building the model&lt;&#x2F;h2&gt;
&lt;p&gt;I started the coding agent session with a direct request to build C4 diagrams for the project at system and container level, with the DSL written first.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#eff1f5;color:#4f5b66;&quot;&gt;&lt;code&gt;&lt;span&gt;build me a c4 model at system level and container level (as defined by the C4 model).
&lt;&#x2F;span&gt;&lt;span&gt;Please create the DSL first
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;reference: c4model.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Below, I&#x27;ll go through the process using the diagrams, but keep in mind these are all generated from a text-based DSL. From the start, the agent produced a working model in the Structurizr DSL. I then gave it a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;simple-time-tracker&#x2F;blob&#x2F;790b4799892330714977e7092682a9c9fec72499&#x2F;justfile#L109&quot;&gt;command to run Structurizr CLI&lt;&#x2F;a&gt; as a check at each step.&lt;&#x2F;p&gt;
&lt;p&gt;To start with, the agent inspected the Rust codebase to work out the system boundary. It established one &lt;code&gt;Time Tracker&lt;&#x2F;code&gt; software system with two runtime modes: a CLI and a web dashboard. Both use the same Markdown time-entry files.&lt;&#x2F;p&gt;
&lt;p&gt;(Apologies for the dark diagrams; dark mode was enabled when I took these screenshots. To enlarge them, open the images in a new tab.)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;c4-llm-system-1.png&quot; alt=&quot;C4 system context diagram (first pass)&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here is a summary of the session:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;One of the first decisions was scope: whether to model only the web path or both runtime paths. The choice was to represent them as separate containers.&lt;&#x2F;li&gt;
&lt;li&gt;We modelled a software system, two application containers, an internal datastore for run statistics, and the Markdown time-entry files as an external dependency. That first version was structurally correct.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;c4-llm-container-1.png&quot; alt=&quot;C4 container diagram (first pass)&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;(I had completely forgotten about the runtime statistics feature ...)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;After the first version, something felt missing between the Markdown files and the CLI&#x2F;web containers: the shared core logic. In C4 terms, that isn&#x27;t another container; it belongs at component level. So I kept the container model strict and added the component level to make the shared logic explicit.&lt;&#x2F;p&gt;
&lt;p&gt;I initially asked it to model the shared core logic as a container, but the agent pushed back, and the model improved because of it. I asked it to add component views for both runtime containers instead of inventing a fake &lt;code&gt;core&lt;&#x2F;code&gt; container. That preserved a strict container model while making the architecture more insightful.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Naming discussions helped sharpen the model. The agent came up with names I was not sure about, but on a first pass it probably did a better job than I would have. One direction I set explicitly was to name things as close as possible to the codebase. The names were not bad, but this is not where I want to leave room for interpretation.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;To support those component views, we introduced a shared component fragment that both CLI and web could include. That shared layer covered parsing, domain types, reporting, and execution statistics. The result was a more accurate picture of how the code is actually organised.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;c4-llm-component-cli-1.png&quot; alt=&quot;C4 component diagram for the CLI (first pass)&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Once the model structure felt right, I shifted to presentation. I asked the agent to style it so different roles were easier to distinguish: CLI and web containers, shared components, adapters, renderers, and datastores. Then I asked for rounded boxes and a more explicit person-style user element.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The final result:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;c4-llm-system-dark-1.png&quot; alt=&quot;C4 system context diagram (styled)&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;img&#x2F;c4-llm-container-dark-1.png&quot; alt=&quot;C4 container diagram (styled)&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;img&#x2F;c4-llm-component-cli-3.png&quot; alt=&quot;C4 component diagram for the CLI (styled)&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have also made &lt;a href=&quot;https:&#x2F;&#x2F;lhohan.github.io&#x2F;simple-time-tracker&#x2F;site&#x2F;&quot;&gt;the generated static site with the diagrams&lt;&#x2F;a&gt; available as it was straightforward to do with help from the agent. You can click the small magnifying glass icons to zoom into the next level.&lt;&#x2F;p&gt;
&lt;p&gt;In summary, this result took several passes: boundaries first; then the component layer; then names aligned with the code; and finally presentation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-dsl-in-practice&quot;&gt;The DSL in practice&lt;&#x2F;h2&gt;
&lt;p&gt;One important artefact we have not discussed yet: the DSL itself. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;simple-time-tracker&#x2F;blob&#x2F;790b4799892330714977e7092682a9c9fec72499&#x2F;docs&#x2F;c4&#x2F;time-tracker.dsl&quot;&gt;Here is the full model&lt;&#x2F;a&gt; with the diagrams defined in the Structurizr DSL. All the edits were done by the agent, including the initial creation from scratch. I reviewed, asked questions, and iterated.&lt;&#x2F;p&gt;
&lt;p&gt;Before this, I typed every box and relationship by hand (scrolling up and down the file, or keeping two windows open), added tech stacks (taking care not to confuse the order of strings), and so on. Using the agent was a major documentation speed boost, and the DSL came out clean and organised the way I prefer: relationships after the element definitions, not inside them.&lt;&#x2F;p&gt;
&lt;p&gt;While I see the risk of not thinking things through, being relieved of painstaking manual element&#x2F;relationship editing, working with agent also gave me:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Iteration close to the code&lt;&#x2F;li&gt;
&lt;li&gt;Meaningful discussions on abstraction levels and naming&lt;&#x2F;li&gt;
&lt;li&gt;A knowledgeable architecture assistant at hand&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Why I think it worked: the model is defined in text, so the agent can edit it like code. C4 provides guardrails through a small number of nested abstraction levels, and the DSL keeps names, descriptions, and styles consistent across views. A CLI tool to validate the model closes the loop, so the agent can check its work as it goes.&lt;&#x2F;p&gt;
&lt;p&gt;In addition, you can ask the LLM to review the model, in the context of the actual codebase or not.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;operationalising-the-workflow&quot;&gt;Operationalising the workflow&lt;&#x2F;h2&gt;
&lt;aside class=&quot;sidebar-note sidebar-note-right&quot;&gt;
  &lt;p&gt;I used Codex CLI with Codex 5.3; any other recent coding agent and model will probably work as well.&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;p&gt;Going forward, here is how I will instruct LLMs to work with C4 and keep the architecture diagrams up to date.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;agent-skill&quot;&gt;Agent Skill&lt;&#x2F;h3&gt;
&lt;p&gt;First, after completing this experiment, I turned my learning into &lt;strong&gt;a reusable agent skill called &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;agent-chisels&#x2F;blob&#x2F;c198e00546f1274e3afcdda58dfd74423fcaa29c&#x2F;agentfiles&#x2F;shared&#x2F;skills&#x2F;modelling-c4-diagrams&#x2F;SKILL.md&quot;&gt;&lt;code&gt;modelling-c4-diagrams&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;, which I can now use from any project.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;agents-md-instructions&quot;&gt;AGENTS.md instructions&lt;&#x2F;h3&gt;
&lt;p&gt;In the project&#x27;s &lt;code&gt;AGENTS.md&lt;&#x2F;code&gt; I added &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;simple-time-tracker&#x2F;blob&#x2F;790b4799892330714977e7092682a9c9fec72499&#x2F;AGENTS.md?plain=1#L12&quot;&gt;a short reference&lt;&#x2F;a&gt; so future agents can discover the DSL files and know how to validate&#x2F;export. This avoids repeating the discovery work in each new session.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-markdown &quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d08770;&quot;&gt;**Architecture docs (C4)**&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: source DSL at &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`docs&#x2F;c4&#x2F;time-tracker.dsl`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; (shared components in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`docs&#x2F;c4&#x2F;shared-tracking-core.dsl`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;); validate with &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`just architecture-docs-validate`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;; export static site with &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`just architecture-docs-export`
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;verification&quot;&gt;Verification&lt;&#x2F;h3&gt;
&lt;p&gt;In this project, the LLM and I used the following commands to verify the output:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Validate C4 Structurizr DSL:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;structurizr-cli validate -workspace docs&#x2F;c4&#x2F;time-tracker.dsl&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Export C4 diagrams to docs&#x2F;site for inspection (and GitHub Pages publishing)
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;structurizr-cli export -workspace docs&#x2F;c4&#x2F;time-tracker.dsl -format static -output docs&#x2F;site&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;View the architecture documentation
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;open docs&#x2F;site&#x2F;index.html&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;structurizr-interface-to-llm&quot;&gt;Structurizr interface to LLM&lt;&#x2F;h3&gt;
&lt;p&gt;I found the validation loop with the CLI to work well. If the export succeeds, the DSL is valid and the views conform to the tool&#x27;s rules.&lt;&#x2F;p&gt;
&lt;p&gt;That still does not tell you whether the model is accurate, or whether the diagrams communicate well. The &lt;a href=&quot;https:&#x2F;&#x2F;c4model.com&#x2F;diagrams&#x2F;checklist&quot;&gt;C4 diagram review checklist&lt;&#x2F;a&gt; is a good yardstick.&lt;&#x2F;p&gt;
&lt;p&gt;The LLM did not seem to require much extra instruction to create a proper model and views. I pointed it to c4model.com at the beginning of the session, and that may have been enough context. (Hard to tell what it knows or does under the hood.)&lt;&#x2F;p&gt;
&lt;p&gt;The skill I created and referenced above now serves as a main interface.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The architecture model and diagrams are insightful artefacts (&quot;pictures can say more than words&quot;). But most of the thinking and modelling usually happens visually, while recording it often becomes a chore. This experiment showed me that LLMs can help keep a model up to date without turning it into a separate manual process.&lt;&#x2F;p&gt;
&lt;p&gt;When the model is constrained (C4) and expressed as text (a DSL), you can version it like code, review it like code, and validate&#x2F;export it through a CLI. Constrained text models plus validation give coding agents a better architecture-diagram workflow than free-form diagramming.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;addendum-next-experiments&quot;&gt;Addendum: Next experiments&lt;&#x2F;h2&gt;
&lt;p&gt;Some follow-ups I might try if I run this workflow again.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;keeping-the-model-in-sync&quot;&gt;Keeping the model in sync&lt;&#x2F;h3&gt;
&lt;p&gt;Work with the LLM to design how to encode parts of the architecture model directly in the codebase. Use the C4 views as shared context, then define a way to keep the model in sync with the implementation. Unless you are using a very principled framework (maybe Spring in Java?), I expect this to be quite custom per project anyway.&lt;&#x2F;p&gt;
&lt;p&gt;Coding agents may lower the barrier to getting started with this kind of non-obvious quality-improvement work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;verification-beyond-the-cli&quot;&gt;Verification beyond the CLI&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use an MCP like Chrome DevTools to inspect exported diagrams as a second verification step.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;One concrete use case: manual editing is often required to position boxes and, especially, dependencies. A visual inspection could double-check that no text boxes overlap and that lines do not cross boxes.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Coding agents could be used to evaluate the shape of the architecture outside of the code.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;publishing-and-representation&quot;&gt;Publishing and representation&lt;&#x2F;h3&gt;
&lt;p&gt;Export to Mermaid (or PlantUML) for embedding in the agent&#x27;s instructions, but keep the Structurizr DSL as the source of truth. Split the DSL so documentation for each container or component lives closer to the code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-better-llm-interface-in-tooling&quot;&gt;A better LLM interface in tooling&lt;&#x2F;h3&gt;
&lt;p&gt;This requires changes to Structurizr. It could provide build&#x2F;run instructions for LLMs via an extensive &lt;code&gt;--help&lt;&#x2F;code&gt; output, or ship &lt;a href=&quot;&#x2F;p&#x2F;add-a-cli-subcommand-to-keep-llm-instructions-in-sync&#x2F;&quot;&gt;a dedicated subcommand that prints LLM instructions&lt;&#x2F;a&gt; (similar to &lt;code&gt;bd prime&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A skill to support TIL creation</title>
        <published>2026-03-02T00:00:00+00:00</published>
        <updated>2026-03-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/a-skill-to-support-til-creation/"/>
        <id>https://hanlho.com/p/a-skill-to-support-til-creation/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/a-skill-to-support-til-creation/">&lt;p&gt;Skills are a great way to introduce capabilities in your agent flows. To support my &quot;The Day I Learned&quot; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;til?tab=readme-ov-file#today-i-learned&quot;&gt;repository&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;til.hanlho.com&quot;&gt;website&lt;&#x2F;a&gt;, I created a skill to extract learnings from coding and LLM sessions.&lt;&#x2F;p&gt;
&lt;p&gt;The skill below is installed in my global agent settings (&lt;code&gt;AGENTS.md&lt;&#x2F;code&gt;), and from each project I can call it to create a TIL in a dedicated project location.&lt;&#x2F;p&gt;
&lt;p&gt;In my &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;til&quot;&gt;til project&lt;&#x2F;a&gt;, I also have &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;til&#x2F;blob&#x2F;3ccfd2a085514871674407fceb711ec15f21c788&#x2F;.work-dir&#x2F;scripts&#x2F;scan-and-move-tils.sh&quot;&gt;a script&lt;&#x2F;a&gt; that collects these across all projects. This is usually where I do some reordering and rewriting, but this skill works well and removes friction when sharing short learning snippets. Instead of creating a markdown file manually in the correct format, this gives me a structured draft that I only need to rework. It is much easier to improve something than to start from a blank canvas.&lt;&#x2F;p&gt;
&lt;p&gt;Full skill definition:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-markdown &quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span style=&quot;background-color:#dfe1e8;color:#4f5b66;&quot;&gt;---
&lt;&#x2F;span&gt;&lt;span&gt;name: til-learning-partner
&lt;&#x2F;span&gt;&lt;span&gt;description: Use when successful tool usage should be captured as a concise, utilitarian TIL note or Tilly is mentioned.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;# TIL Learning Partner
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;## Overview
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Capture short, practical &amp;quot;Today I Learned&amp;quot; notes from successful outcomes.
&lt;&#x2F;span&gt;&lt;span&gt;Each note is a standalone markdown file in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`docs&#x2F;tils&#x2F;`&lt;&#x2F;span&gt;&lt;span&gt; with a slug-only filename.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;## Trigger Conditions
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- User asks to capture or write a TIL.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- A command&#x2F;tool outcome usage is successful and worth preserving.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- User asks to summarize what worked into a reusable note.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;## Workflow
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;1. Confirm the outcome is successful and concrete.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2. Ask one lightweight prompt: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`Capture this as a TIL?`
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;3. If user declines, do not write a file.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;4. If user confirms, extract one focused learning:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;   - Issue solved
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;   - How it was solved
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;   - Key command(s) learned
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;   - Practical takeaway
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;5. Generate a slug from the learning title and save to &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`docs&#x2F;tils&#x2F;&amp;lt;slug&amp;gt;.md`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;6. If &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`docs&#x2F;tils&#x2F;&amp;lt;slug&amp;gt;.md`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; exists, use deterministic suffixes:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;   - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`&amp;lt;slug&amp;gt;-2.md`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`&amp;lt;slug&amp;gt;-3.md`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;, and so on.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;## Output Contract
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Path: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`docs&#x2F;tils&#x2F;&amp;lt;slug&amp;gt;.md`
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Slug rules:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;  - Lowercase
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;  - ASCII-safe
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;  - Hyphen-separated words
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;  - No date in filename or slug
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;## TIL Template
&lt;&#x2F;span&gt;&lt;span&gt;~~~~&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;markdown
&lt;&#x2F;span&gt;&lt;span&gt;# TIL: &amp;lt;specific issue solved&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;## Issue
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;one concise problem statement&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;## Solution
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;what worked and why&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;## Key commands
&lt;&#x2F;span&gt;&lt;span&gt;\```bash
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;command 1&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;command 2&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;\```
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;## Takeaway
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;how to apply this next time&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;_Created: YYYY-MM-DD_
&lt;&#x2F;span&gt;&lt;span&gt;~~~~
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;## Guardrails
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Keep notes utilitarian, direct, and brief.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Cover one specific learning per file.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Avoid exploratory or uncertain phrasing.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Avoid blog-style storytelling and long introductions.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Do not invent commands or outcomes that were not observed.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Experience report: Site update using coding agents and Beads</title>
        <published>2026-03-01T00:00:00+00:00</published>
        <updated>2026-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/experience-report-site-update-using-coding-agents-and-beads/"/>
        <id>https://hanlho.com/p/experience-report-site-update-using-coding-agents-and-beads/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/experience-report-site-update-using-coding-agents-and-beads/">&lt;p&gt;This is an experience report on updating my (this!) website using coding agents and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;steveyegge&#x2F;beads&quot;&gt;Beads&lt;&#x2F;a&gt; (&#x27;a distributed, git-backed graph issue tracker for AI agents.&#x27;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;site-update-using-coding-agents&quot;&gt;Site update using coding agents&lt;&#x2F;h2&gt;
&lt;p&gt;Over the past week, I used coding agents to update my website. The result is, at least I hope so, a cleaner design and new features, delivered faster than I could have managed alone and at a design standard I probably would not have achieved on my own either.&lt;&#x2F;p&gt;
&lt;p&gt;Context: in October, I moved my blog from Hashnode to a self hosted Zola site to take more control of my online presence and potentially support freelance work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tools&quot;&gt;Tools&lt;&#x2F;h3&gt;
&lt;p&gt;For improving the overall look and feel I mostly relied on &lt;a href=&quot;https:&#x2F;&#x2F;impeccable.style&#x2F;&quot;&gt;Impeccable&lt;&#x2F;a&gt;, which is built on Anthropic&#x27;s original frontend-design skill.&lt;&#x2F;p&gt;
&lt;p&gt;It has &lt;a href=&quot;https:&#x2F;&#x2F;impeccable.style&#x2F;cheatsheet&quot;&gt;a pretty clean and clear command set&lt;&#x2F;a&gt; across diagnosis, audit, and several kinds of &lt;em&gt;gradual&lt;&#x2F;em&gt; improvements (e.g.   &lt;code&gt;&#x2F;bolder&lt;&#x2F;code&gt;). In my case, what definitely helped is that I already had a visual style in place I wanted to maintain: simple and burgundy-based.&lt;&#x2F;p&gt;
&lt;p&gt;I do not know how it compares to other kinds of frameworks, but for what I did I would recommend trying out Impeccable: easy setup and good workflows.&lt;&#x2F;p&gt;
&lt;p&gt;As for the &#x27;AI assistance&#x27;: I mostly used Codex and Opencode as coding agents, GPT-5.2 as a model for planning and analysis, and Kimi 2.5 and Gemini Flash 3 for implementation. For quality reviews, I relied entirely on the coding tools, aside from updating a size value here and there, so it&#x27;s safe to say these updates were more vibe-coded &lt;a href=&quot;https:&#x2F;&#x2F;xcancel.com&#x2F;karpathy&#x2F;status&#x2F;1886192184808149383&quot;&gt;as in its original definition&lt;&#x2F;a&gt; than actually &#x27;engineered&#x27;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;changes-made&quot;&gt;Changes made&lt;&#x2F;h3&gt;
&lt;p&gt;Looking at the completed tasks list, I completed over 50, the most important changes, aside from the content overhaul:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Visual refresh, much cleaner and more appealing, I think.&lt;&#x2F;li&gt;
&lt;li&gt;Atom feed. Maybe I&#x27;ll integrate a newsletter later, but at least people can subscribe.&lt;&#x2F;li&gt;
&lt;li&gt;Bluesky sidebar with live post rotation (note this is all handled on the client side)&lt;&#x2F;li&gt;
&lt;li&gt;Better code block readability in posts.&lt;&#x2F;li&gt;
&lt;li&gt;At the end of each post, instead of comments, I added a simple &#x27;Want to respond?&#x27; section for basic interaction.&lt;&#x2F;li&gt;
&lt;li&gt;&#x27;Tags&#x27; are now visible and browsable. I also added &#x27;categories&#x27; (&#x27;Experience Report&#x27;, &#x27;How-to&#x27;, etc.).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Last but not least: &lt;em&gt;dark mode&lt;&#x2F;em&gt;. I thought I was finished. Then, for the fun of it, I asked for a dark mode, which produced in one shot the style it has now. That &lt;em&gt;definitely&lt;&#x2F;em&gt; would have taken me ages to get right and now it took 10 mins. The only change I had to ask was regarding the styling and position of the dark mode toggle, that&#x27;s it.&lt;&#x2F;p&gt;
&lt;p&gt;The LLM also came up with some fading effect when toggling dark mode. Normally I do not like the LLM to come up with extra stuff I did not ask for, but this one pleasantly surprised me so I kept it in. Try it ... I think it looks pretty nice.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-beads-for-the-first-time&quot;&gt;Using Beads for the first time&lt;&#x2F;h2&gt;
&lt;p&gt;For every project, I have a custom Markdown-based backlog or tracking system. Each one is a little different and works better or worse depending on when I came up with the project or started it. I have tried &lt;a href=&quot;https:&#x2F;&#x2F;docs.task-master.dev&#x2F;introduction&quot;&gt;Task Master&lt;&#x2F;a&gt; before, but I could not get it working reliably or easily. Enter &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;steveyegge&#x2F;beads&quot;&gt;Beads&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Beads markets itself as an AI native task tracker and I think it shows. The tool feels designed by someone who actually uses AI to get work done.&lt;&#x2F;p&gt;
&lt;p&gt;After installing it, you can simply use it from the command line. But you can also use it to initialise your coding agents&#x27; instruction set for your projects, which means instructions will be added to your AGENTS.md (or CLAUDE.md) file. (Note: if you are working in a shared repo, you can use Beads in a shared in stealth mode, to not interfere with others: &lt;code&gt;bd init --stealth&lt;&#x2F;code&gt;.)&lt;&#x2F;p&gt;
&lt;p&gt;I found it works reasonably well and is easy to start with &lt;code&gt;bd quickstart&lt;&#x2F;code&gt;. This is the first task management system I&#x27;ve worked with that has brought some consistency across my projects.&lt;&#x2F;p&gt;
&lt;p&gt;While using it, I&#x27;ve come up with some customisations in the form of skills:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Land the plane&lt;&#x2F;code&gt;: Instead of repeating the same instructions to finish up a task, I created a skill instead of referencing the same commands in each agent instructions file. (I also needed some customization.)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Create task&lt;&#x2F;code&gt;: The command line already has a nice way to create tasks as well, but when working with an agent I prefer to use my own skill that I can just ask to create a task while dictating.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Beads is actually a pretty good name, it is just easy to create tasks and start new tasks, in other words to keep going, one task, or bead, after another.&lt;&#x2F;p&gt;
&lt;p&gt;I will have to see how it holds up when a whole backlog starts building up, but based on experiences so far, I will continue using Beads to keep track of work on personal projects.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Harness Engineering</title>
        <published>2026-02-27T00:00:00+00:00</published>
        <updated>2026-02-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/harness-engineering/"/>
        <id>https://hanlho.com/p/harness-engineering/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/harness-engineering/">&lt;p&gt;Today I heard the term “harness engineering” for the first time:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Harness engineering is the practice of building tooling, tests, and automation that let coding agents execute tasks safely and reliably.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If code is written more and more by LLMs, the focus seems to be shifting to creating guardrails so agents can validate their own work.&lt;&#x2F;p&gt;
&lt;p&gt;Heard in: &lt;a href=&quot;https:&#x2F;&#x2F;share.snipd.com&#x2F;episode&#x2F;d7924de8-b7e1-41fc-8f37-6edee96f12f6&quot;&gt;The Pragmatic Engineer - Mitchell Hashimoto’s new way of writing code&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>AI’s Opportunity: Pacing Control Loops with Development</title>
        <published>2026-02-04T00:00:00+00:00</published>
        <updated>2026-02-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/ais-opportunity-pacing-control-loops-with-development/"/>
        <id>https://hanlho.com/p/ais-opportunity-pacing-control-loops-with-development/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/ais-opportunity-pacing-control-loops-with-development/">&lt;p&gt;What caught my attention in the book &lt;em&gt;Vibe Coding&lt;&#x2F;em&gt; by Gene Kim and Steve Yegge is the idea that, as LLMs and coding agents change how we build software, control loops—tests, reviews, and other signals that tell you whether a change behaves as expected—should be faster and more integrated into development feedback loops than before. My intuition says this makes perfect sense.&lt;&#x2F;p&gt;
&lt;p&gt;For example, when there is a dedicated test stage or a QA role that tests after the fact, that role inevitably struggles to keep up with the speed of development. Over time, this makes it increasingly difficult to sustain a &#x27;testing after the fact&#x27; organisation of quality.&lt;&#x2F;p&gt;
&lt;p&gt;So how do we solve this?&lt;&#x2F;p&gt;
&lt;p&gt;Some may think that introducing AI by implementing it at the test level after the fact, could be the solution. However, at the rate of development I see and read about, this approach will be hard to keep up with. One either has to accept not fully taking advantage of what AI can help development with, or rethink how testing is integrated into the development process.&lt;&#x2F;p&gt;
&lt;p&gt;Put bluntly: if AI lets you produce a feature in hours but the first meaningful acceptance signal only arrives days later in a separate stage, quality assurance become the bottleneck.&lt;&#x2F;p&gt;
&lt;p&gt;To me, the logical consequence is a stronger shift towards automated quality controls, including acceptance tests and code reviews at the least. I refer to acceptance tests here as writing executable specifications of expected behaviour (in domain language) before or alongside the code. This implies that testing &lt;em&gt;has&lt;&#x2F;em&gt; to move earlier in the development chain &lt;em&gt;because&lt;&#x2F;em&gt; of AI.&lt;&#x2F;p&gt;
&lt;p&gt;AI is an opportunity to start writing acceptance tests if you have not yet. It pushes us to invest time in strategic test design, testing against stable contracts, testing from a behavioural point of view, and isolating test descriptions from the actual implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Put differently, the shift in development practices that LLMs are causing should inspire &lt;em&gt;more&lt;&#x2F;em&gt; adherence to testing best practices, not less. That is, if you want to keep on adding new features, fix and prevent bugs, and keep up the pace of development.&lt;&#x2F;p&gt;
&lt;p&gt;More broadly, to keep benefiting from AI over time, we should shift towards tightly coupled feedback loops embedded in everyday development. This is not limited to testing but also applies to, for example, reviews. In that sense, AI doesn’t remove quality practices; it raises the stakes if you don’t have them.&lt;&#x2F;p&gt;
&lt;p&gt;If testing &#x27;shifts left&#x27;, team structures must change as well. This evolution points towards smaller, more autonomous teams where testing, development, and feedback are inseparable rather than sequential.&lt;&#x2F;p&gt;
&lt;p&gt;AI presents us with an opportunity: not faster quality control after the fact, but to design systems, processes, and teams that make quality the fastest path forward, so control loops can keep up with the increasing pace of development loops.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Experience Report: Building a time-tracking AI assistant</title>
        <published>2026-02-04T00:00:00+00:00</published>
        <updated>2026-02-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/experience-report-building-a-time-tracking-ai-assistant/"/>
        <id>https://hanlho.com/p/experience-report-building-a-time-tracking-ai-assistant/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/experience-report-building-a-time-tracking-ai-assistant/">&lt;p&gt;This is a short experience report about using &lt;a href=&quot;https:&#x2F;&#x2F;agentskills.io&#x2F;home&quot;&gt;skills&lt;&#x2F;a&gt; (with Codex and its models) to build a personal AI assistant that helps me maintain my time-tracking log.&lt;&#x2F;p&gt;
&lt;p&gt;To set expectations: the assistant does not manage my calendar or tasks. It helps me keep a time-tracking log that lives in a Markdown file by interpreting logging requests and editing the file for me (while categorising entries correctly).&lt;&#x2F;p&gt;
&lt;p&gt;I start most days with a bit of planning, which means adding entries to that log. The format is completely custom and tailored to my needs, and I wrote a small companion CLI tool, &lt;code&gt;tt&lt;&#x2F;code&gt;, to generate reports from it. (The project is open source on GitHub, but honestly I don&#x27;t think it is useful to anyone other than me.)&lt;&#x2F;p&gt;
&lt;p&gt;To give an idea, this is what a day entry looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-markdown &quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;## TT 2026-02-04
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- #admin ##work 30m inbox and daily planning
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- #prj-content ##work 2h article outline and research notes
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- #prj-content ##work 1h 30m first draft writing
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- prj-personal-assistant #llm ##work 1h walking skeleton
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- prj-personal-assistant #llm ##work 1h create skills
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- #break ##energy 20m outdoor walk
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- #learning ##work 1h documentation reading and summary
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And using &lt;code&gt;tt&lt;&#x2F;code&gt;, I can generate reports like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-markdown &quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span&gt;Overview 2026-02-04 -&amp;gt; 2026-02-04:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- prj-content: 3h 30m
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- prj-personal-assistant: 2h 00m
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- learning: 1h 00m
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- admin: 30m
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- break: 20m
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Total: 7h 20m
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Breakdown:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- ##work: 7h 00m
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- ##energy: 20m
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Editing the file is not hard, but it is tedious. The goal of this project was not to replace my log format, but to make it easier to operate.&lt;&#x2F;p&gt;
&lt;p&gt;Today I ran a small LLM experiment to make logging less cumbersome. Instead of writing an entry like &lt;code&gt;#prj-personal-assistant #llm #codex ##work 2h Setup walking skeleton&lt;&#x2F;code&gt;, I want to be able to say: &quot;Create a new task to set up a walking skeleton, add tags codex and llm, and attribute the time to the personal assistant project.&quot; And by &quot;say&quot; I mean it literally: I dictate it in normal language, it gets transcribed and sent to the LLM. This turned out to be a surprisingly fast (and fun) experiment with promising first results.&lt;&#x2F;p&gt;
&lt;p&gt;Technical details: I used the Codex agent and its models, mostly Codex 5.2. Working with Codex was smooth, but this post is not about comparing coding agents; I suspect it would work with any capable agent that supports skills.&lt;&#x2F;p&gt;
&lt;p&gt;I started with a log file containing over a year of time entries. That history was a good dataset to prime the LLM on the format: what a day looks like, what an entry line looks like, and how entries should be categorised with tags.&lt;&#x2F;p&gt;
&lt;p&gt;From there I moved into implementation, with a small set of local files and skills.&lt;&#x2F;p&gt;
&lt;p&gt;This is the file tree I ended up with (not ready to call it &quot;architecture&quot; yet):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-markdown &quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span&gt;AGENTS.md
&lt;&#x2F;span&gt;&lt;span&gt;skills
&lt;&#x2F;span&gt;&lt;span&gt;├── tt-cli
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── references
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── command-cheatsheet.md
&lt;&#x2F;span&gt;&lt;span&gt;│   └── SKILL.md
&lt;&#x2F;span&gt;&lt;span&gt;└── tt-log
&lt;&#x2F;span&gt;&lt;span&gt;    ├── references
&lt;&#x2F;span&gt;&lt;span&gt;    │   ├── log-structure.md
&lt;&#x2F;span&gt;&lt;span&gt;    │   ├── tag-inference.md
&lt;&#x2F;span&gt;&lt;span&gt;    │   └── validation.md
&lt;&#x2F;span&gt;&lt;span&gt;    ├── scripts
&lt;&#x2F;span&gt;&lt;span&gt;    │   └── validate_tt_update.py
&lt;&#x2F;span&gt;&lt;span&gt;    └── SKILL.md
&lt;&#x2F;span&gt;&lt;span&gt;time-tracking-log.md
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;tt&lt;&#x2F;code&gt; is an abbreviation for &quot;time tracking&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;In practice, &lt;code&gt;AGENTS.md&lt;&#x2F;code&gt; tells the agent which skill to use for which capability:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-markdown &quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;### Time tracking
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;### Time tracking
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Use &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`tt`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;, the custom time-tracking CLI, for time-tracking operations.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Use &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`$tt-log`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`time-tracking-log.md`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; edits, tag inference, and 7h to 8h daily policy checks.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- Use &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`$tt-cli`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`tt`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; command discovery, report commands, and CLI troubleshooting.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;  - Rule of thumb: log edits&#x2F;validation =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`$tt-log`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;; reporting&#x2F;CLI usage questions =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;`$tt-cli`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The two skills are the heart of the implementation:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tt-cli&lt;&#x2F;code&gt; handles the &lt;code&gt;tt&lt;&#x2F;code&gt; CLI tool: command discovery, reporting, filters, and general troubleshooting.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;tt-log&lt;&#x2F;code&gt; handles log editing, task insertion, tag inference, section ordering, and policy checks.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;From the start I wanted to use skills because my custom format and tooling are a specialised capability. Initially Codex suggested a single skill, but it was clear to me that reading&#x2F;querying and writing&#x2F;editing were different responsibilities, so I pushed it in that direction (it agreed, ha!).&lt;&#x2F;p&gt;
&lt;p&gt;That split improved the quality of outcomes. Beyond maintainability, making responsibilities explicit made behaviour more predictable, because the CLI skill gives the LLM a way to validate its work. The &lt;code&gt;tt-log&lt;&#x2F;code&gt; skill can focus on reliable edits and validation, while &lt;code&gt;tt-cli&lt;&#x2F;code&gt; handles queries like &quot;how much do I still need to log today?&quot; and validates the log.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;references&lt;&#x2F;code&gt; locations for both skills were set up by the LLM while we created the skills. They are pretty clean in terms of responsibility, and reviewing and refining the split proved useful.&lt;&#x2F;p&gt;
&lt;p&gt;During implementation I also wanted basic checks for &quot;did I log enough today?&quot;, so we added a validation workflow that checks a daily target range (7h to 8h). The logic is always the same, so I had it write a script: &lt;code&gt;skills&#x2F;tt-log&#x2F;scripts&#x2F;validate_tt_update.py&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I iteratively refined the default logging rules (which tags to use for which kinds of tasks, the fact that not all my days look the same, and so on). I don&#x27;t expect it to be perfect, but I will probably tweak it over the next couple of weeks as exceptions pop up.&lt;&#x2F;p&gt;
&lt;aside class=&quot;sidebar-note sidebar-note-right&quot;&gt;
  &lt;p&gt;As an aside, when finishing up Codex proposed me to create a &#x27;one-page pdf summary&#x27; of this project. I think it did &lt;a href=&quot;&#x2F;pdfs&#x2F;codex-personal-assistant-summary.pdf&quot;&gt;a pretty good job&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;p&gt;So in short:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Created initial time-tracking skill behaviour for structured log edits based on existing time tracking data.&lt;&#x2F;li&gt;
&lt;li&gt;Split responsibilities into two dedicated skills (&lt;code&gt;tt-log&lt;&#x2F;code&gt; and &lt;code&gt;tt-cli&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Added automated validation for parse integrity, per-day totals, and a daily policy range.&lt;&#x2F;li&gt;
&lt;li&gt;Iteratively refined defaults and behaviour based on real usage (for example, a longer workout-at-noon baseline on Tuesdays).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Things I can now ask: &quot;I want to fill the rest of the day with work on a project I forgot the tag of. Give me the last 5 projects I recorded time on so I can tell you what to log to.&quot; Before, this was not hard, but it involved a bunch of small chores: checking previous days, finding the right project tag, copying it into a new line, and calculating the time left for the day.&lt;&#x2F;p&gt;
&lt;p&gt;Besides the usefulness (and fun), there was an unexpectedly valuable lesson: AI assistance works best in the same way good code does. Define clear boundaries and add executable checks so changes are easier to make and the system can validate its own work.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>On Building Reliable Software with LLMs</title>
        <published>2026-01-27T00:00:00+00:00</published>
        <updated>2026-01-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/on-building-reliable-software-with-llms/"/>
        <id>https://hanlho.com/p/on-building-reliable-software-with-llms/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/on-building-reliable-software-with-llms/">&lt;p&gt;This post captures my current thinking on how LLMs are impacting software development, particularly around software quality and engineering discipline.&lt;&#x2F;p&gt;
&lt;p&gt;My main observation: most of the best practices we&#x27;ve relied on for years are just as important—maybe even more so—in an LLM-assisted development environment. Working with LLMs requires &lt;em&gt;more&lt;&#x2F;em&gt; discipline and attention to fundamentals, not less.&lt;&#x2F;p&gt;
&lt;p&gt;When using LLMs, there is a heightened risk of losing understanding: of the problem domain, the underlying technology, and the implementation details. Code can become messy quickly without careful attention, review, and guidance. While this is certainly true, we didn&#x27;t need LLMs for this to happen. Why else have so many projects failed historically? Why is technical debt a topic in most projects?&lt;&#x2F;p&gt;
&lt;p&gt;The critical difference with LLMs is the &lt;em&gt;increased risk and temptation of velocity&lt;&#x2F;em&gt;. We move too fast and skip the practices that help us maintain and change software in the future. Discipline and &lt;a href=&quot;https:&#x2F;&#x2F;aicoding.leaflet.pub&#x2F;3mbrvhyye4k2e&quot;&gt;rigour&lt;&#x2F;a&gt; have become more important than ever.&lt;&#x2F;p&gt;
&lt;p&gt;These practices are becoming MORE crucial in an LLM-assisted workflow:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Codebase quality.&lt;&#x2F;strong&gt; This matters for LLM agents too, because they learn from existing code. A clean, well-organised codebase helps agents perform better; inconsistencies lead to poorer results. An LLM will mimic what&#x27;s already there.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Feedback loops and testing.&lt;&#x2F;strong&gt; If an LLM is helping you write code, you need reliable ways to verify it hasn&#x27;t broken anything. A well-designed, automated test suite that&#x27;s easy to extend and interpret helps maintain understanding and control of implemented functionality.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Well-designed boundaries and contracts&lt;&#x2F;strong&gt; both within and outside your application. These allow you to constrain, shape, isolate, and test the work an LLM produces.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Managing risk and technical debt.&lt;&#x2F;strong&gt; Be intentional and explicit about where you rely on LLMs and where you don&#x27;t. Document these decisions. Maintain a technical debt log with risk assessments and timelines.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Documentation of past decisions.&lt;&#x2F;strong&gt; Keep a history of architectural decisions through decision logs and ADRs, and ensure the LLM you&#x27;re working with is aware of them. I&#x27;ve had LLMs point out inconsistencies in the codebase or flag how new change requests conflict with past decisions.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Taken together, these practices are what make LLM-assisted development sustainable rather than brittle.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t think the skill gap in building and delivering software will ultimately be about prompt cleverness. LLM agents will be genuinely helpful tools, and working effectively with them will be an accelerator. However, as we rely on them more to write code—even when we review that code carefully—the most important work increasingly becomes the disciplined practice of boxing them in with testing, architecture, and contracts.&lt;&#x2F;p&gt;
&lt;p&gt;Avoid painting yourself into a corner. In an LLM-assisted workflow, that means being deliberate about where you let agents move fast, and where you slow them down with guardrails. LLMs make it easier to move fast, and easier to get stuck.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Agent Chisels: My LLM Agent Skills and Workflows</title>
        <published>2026-01-13T00:00:00+00:00</published>
        <updated>2026-01-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/agent-chisels-my-llm-agent-skills-and-workflows/"/>
        <id>https://hanlho.com/p/agent-chisels-my-llm-agent-skills-and-workflows/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/agent-chisels-my-llm-agent-skills-and-workflows/">&lt;p&gt;I have been meaning to share more about my LLM workflows and tooling for a while, partly to have a reference for conversations, but mostly to learn in public.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;agent-chisels&quot;&gt;Agent Chisels&lt;&#x2F;a&gt; is where I will be sharing the custom artefacts (primarily &lt;code&gt;skills&lt;&#x2F;code&gt;, with &lt;code&gt;commands&lt;&#x2F;code&gt; and &lt;code&gt;agents&lt;&#x2F;code&gt; to follow) that I find most useful and actively use in my daily workflow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;skills&quot;&gt;Skills&lt;&#x2F;h2&gt;
&lt;p&gt;I have shared two &lt;a href=&quot;https:&#x2F;&#x2F;agentskills.io&#x2F;home&quot;&gt;skills&lt;&#x2F;a&gt; I use almost daily. In addition, I&#x27;ve also included a third skill, more of a meta-skill for evaluating other skills, which I used when reviewing these for release. I actively use this skill to iterate and improve my skills so it fits the goal of this project.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;documenting-architectural-decisions&lt;&#x2F;code&gt;: Document and manage architectural decisions using ADRs. Supports Y-statement and traditional ADR formats. Used for creating, reviewing, or searching decision records. This repository contains several examples of decision logs created with this skill, for example, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;agent-chisels&#x2F;blob&#x2F;main&#x2F;plugins&#x2F;jj&#x2F;decision-log.md&quot;&gt;here&lt;&#x2F;a&gt; is the one for the &lt;code&gt;jj&lt;&#x2F;code&gt; plugin.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I use &lt;a href=&quot;https:&#x2F;&#x2F;www.jj-vcs.dev&#x2F;latest&#x2F;&quot;&gt;&lt;code&gt;jj&lt;&#x2F;code&gt; or &lt;code&gt;Jujutsu&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, an alternative version control system, in all my projects. Getting LLMs to work reliably with it is quite a challenge, so I have a skill to detect and remind an LLM to use &lt;code&gt;jj&lt;&#x2F;code&gt; and one to add the capability of using &lt;code&gt;jj&lt;&#x2F;code&gt;. The &lt;a href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;plugins&quot;&gt;Claude Code plugin&lt;&#x2F;a&gt; also adds a &lt;code&gt;use-jj&lt;&#x2F;code&gt; command and a hook to remind an LLM of using &lt;code&gt;jj&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;detecting-jujutsu&lt;&#x2F;code&gt; — Verify if the current repository uses Jujutsu (jj) instead of git. Used when confirming VCS state before operations.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;using-jujutsu&lt;&#x2F;code&gt; — Detailed guidance on Jujutsu (jj) VCS operations including committing, pushing, searching history, and working with revisions&#x2F;revsets.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And finally, there is the meta-skill to evaluate skills. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;agent-chisels&#x2F;blob&#x2F;main&#x2F;skills&#x2F;evaluate-skills&#x2F;examples&#x2F;EXAMPLE.md&quot;&gt;Here is an example&lt;&#x2F;a&gt; of a report generated by this skill.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;evaluating-skills&lt;&#x2F;code&gt; — A skill to evaluate skills against best practices for size, structure, examples, and prompt engineering. Use when reviewing skills for deployment, optimisation, or standards compliance.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To use these, you can use the Claude Code plugin system or install them manually; take a look at the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;agent-chisels#user-content-installation&quot;&gt;installation section&lt;&#x2F;a&gt; for more details.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-little-on-the-setup-of-the-repository&quot;&gt;A little on the setup of the repository&lt;&#x2F;h2&gt;
&lt;p&gt;I use symbolic links liberally to avoid duplication. For example, symbolic links allow me to share the independent skills with the Claude Code plugin while also using them in this project itself.&lt;&#x2F;p&gt;
&lt;p&gt;All skills I share in this repo are dynamically linked to my &lt;code&gt;~&#x2F;.claude&#x2F;skills&lt;&#x2F;code&gt; directory. Note that this is also the easiest way to make these skills &lt;a href=&quot;https:&#x2F;&#x2F;agentskills.io&#x2F;home#adoption&quot;&gt;available to other LLM CLI agents&lt;&#x2F;a&gt; like Opencode, Codex, and Mistral Vibe. In this repo, I have mostly worked with &lt;a href=&quot;https:&#x2F;&#x2F;opencode.ai&quot;&gt;Opencode&lt;&#x2F;a&gt; and the skills in the &lt;code&gt;.claude&lt;&#x2F;code&gt; location just work with it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; ls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span&gt; .claude&#x2F;skills
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;l...&lt;&#x2F;span&gt;&lt;span&gt; detecting-jujutsu -&amp;gt; ..&#x2F;..&#x2F;skills&#x2F;detecting-jujutsu
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;l...&lt;&#x2F;span&gt;&lt;span&gt; documenting-architectural-decisions -&amp;gt; ..&#x2F;..&#x2F;skills&#x2F;documenting-architectural-decisions
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;l...&lt;&#x2F;span&gt;&lt;span&gt; evaluating-skills -&amp;gt; ..&#x2F;..&#x2F;skills&#x2F;evaluating-skills
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;l...&lt;&#x2F;span&gt;&lt;span&gt; using-jujutsu -&amp;gt; ..&#x2F;..&#x2F;skills&#x2F;using-jujutsu
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d...&lt;&#x2F;span&gt;&lt;span&gt; verify-release-readiness
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;l&lt;&#x2F;code&gt; at the beginning of each line stands for symbolic link. You&#x27;ll notice one real directory in there, that is a skill only relevant to this repository.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;future-plans&quot;&gt;Future plans&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ll be adding LLM artefacts as I move my own setup more and more to this repository. Since I&#x27;m trying to reuse as much as possible (within reason) between different LLM agents, I need a central location anyway, preferably vendor neutral yet pragmatic (e.g. using the &lt;code&gt;.claude&#x2F;skills&lt;&#x2F;code&gt; location to share skills). Also, my hope is to make this repository a more live and automatically up-to-date version of the artefacts I use day to day.&lt;&#x2F;p&gt;
&lt;p&gt;Related to this, I am thinking of creating a setup similar to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;webpro&#x2F;awesome-dotfiles&quot;&gt;dotfiles&lt;&#x2F;a&gt; (where developers share configuration files) but for LLM agent configurations: &#x27;agentfiles&#x27;. I intend to share my LLM agent configurations and how I integrate them. Let me know if you would be interested in this or are already sharing.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Implementing an Urgent Feature with Opencode, Claude, and Zed</title>
        <published>2025-12-18T00:00:00+00:00</published>
        <updated>2025-12-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/implementing-an-urgent-feature-with-llms-and-zed/"/>
        <id>https://hanlho.com/p/implementing-an-urgent-feature-with-llms-and-zed/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/implementing-an-urgent-feature-with-llms-and-zed/">&lt;p&gt;This is a short post to share a positive experience I had using an LLM agent to quickly add a feature to an existing personal CLI &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;simple-time-tracker&quot;&gt;time-tracking application&lt;&#x2F;a&gt;. Below, I describe how I added it using Zed, Opencode and Claude.&lt;&#x2F;p&gt;
&lt;p&gt;To start, I wasn&#x27;t even sure the feature I needed existed in a text-based time-tracking application I use day-to-day to keep track of what I work on. My application &lt;em&gt;has&lt;&#x2F;em&gt; a way of getting the information I needed out, but the feature that should make this easy was missing details on &lt;em&gt;what&lt;&#x2F;em&gt; I had actually worked on.&lt;&#x2F;p&gt;
&lt;p&gt;So, should I invest the time and expand the feature, or accept that it was missing for now and spend a lot more time on manual work? I could try an LLM agent and see if it could help me implement the change quickly. Each choice had downsides: spending &lt;em&gt;more&lt;&#x2F;em&gt; time digging through time-tracking information to fill in timesheets is not very appealing, and implementing the feature (with or without agents) could become a time sink. I also had lots of other work planned for the day.&lt;&#x2F;p&gt;
&lt;p&gt;I decided to implement it, telling myself I’d stop if it didn’t look like I had a clear path to finish it within one hour.&lt;&#x2F;p&gt;
&lt;p&gt;Because I think it is relevant to the (spoiler) successful implementation, let me share a little about this project. It is a Rust codebase that I use to test development practices, and I think it is structured and implemented fairly well. The CLI, the main part of the application, has over 95% coverage using behaviour-driven, DSL-style acceptance tests. This setup gives the LLM models both structure and plenty of examples to follow when adding tests. I will not go into the details here, but I have added a brief example at the end. Also noteworthy: this is a small project, which definitely makes a difference.&lt;&#x2F;p&gt;
&lt;p&gt;For this implementation, I used Zed with its Opencode integration. Lately, I have been on the command line building smaller apps prompt-driven, without worrying much about the fine details. But for this project the actual implementation mattered to me, so I wanted to track changes more closely in an IDE. Opencode taps into my Claude subscription; I can use Opus for planning and Haiku for implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Honestly, I was very pleased with how smoothly this feature was implemented. What contributed to this was the plan-first approach before implementing anything. For anything non-trivial, always plan first!&lt;&#x2F;p&gt;
&lt;p&gt;Here is a high-level overview of my interaction with Opencode in Zed:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Investigate
&lt;ul&gt;
&lt;li&gt;I started with Claude Opus and asked whether the feature I needed already existed, rather than looking it up myself because I was under time pressure. It didn&#x27;t.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Plan
&lt;ul&gt;
&lt;li&gt;I asked Claude to plan the feature and use a test-driven approach. It broke the work into nine tests, and I asked it to pause after each one for me to review.&lt;&#x2F;li&gt;
&lt;li&gt;Before starting any implementation, I asked it to write the plan to a Markdown file in the backlog.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Then I reviewed the plan.&lt;&#x2F;em&gt; That sounds more superficial than what I did, but I cannot say much more than that it simply looked good.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Implementation
&lt;ul&gt;
&lt;li&gt;I switched to Claude Haiku for implementation.&lt;&#x2F;li&gt;
&lt;li&gt;It started off well and asked for feedback after each test cycle, and I asked for a refactor to remove duplication.&lt;&#x2F;li&gt;
&lt;li&gt;While it was implementing, I discovered I wanted a different kind of description for the tasks, so I told it to change that in the plan. I did not switch models for this.&lt;&#x2F;li&gt;
&lt;li&gt;The plan was updated in all the correct places.&lt;&#x2F;li&gt;
&lt;li&gt;After this, the workflow changed: it stopped asking me for feedback after each step, and before I realised it, seven of nine tests were running. Not the TDD flow I asked for, but it worked.&lt;&#x2F;li&gt;
&lt;li&gt;Instead of asking it to redo anything, I reviewed the implementation (it was not a lot of code) and continued.&lt;&#x2F;li&gt;
&lt;li&gt;I ran the program against my own data and everything worked as intended. Aside from the one refactoring to remove duplication, I did not change the code.&lt;&#x2F;li&gt;
&lt;li&gt;One loose end I had to remind it of: update the documentation.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I have shared the full session here: https:&#x2F;&#x2F;opncd.ai&#x2F;share&#x2F;aBYozahW.&lt;&#x2F;p&gt;
&lt;p&gt;There were some pitfalls of using LLMs that I ran into, and I admittedly leaned into them. Speed beating accuracy is a real risk. The feature works and the code looks good, but if I were coding hands-on I probably would have reviewed more thoroughly. It is hard to tell if the end result would have been &lt;em&gt;drastically&lt;&#x2F;em&gt; better. It requires discipline to not start running along with the agent and to not start accepting everything if the outcome is as expected. The LLM gave me what I needed and any follow-up changes should be small, but I still see little things I would have done differently if I done it manually (which other developers may disagree with too, to be fair). For example, some of the tests could do with fewer assertions. The current code organisation makes that easy to address later. &lt;em&gt;If&lt;&#x2F;em&gt; any tech debt was added, it is very small and under control, so I stopped, generated my reports and filled in my timesheets.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, working in Zed made it easy to review the code, and combining Opencode&#x27;s plan phases kept things organised. The existing, structured DSL-based test approach with plenty of examples also helped.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;extra-how-an-llm-can-work-better-with-a-well-structured-dsl&quot;&gt;Extra: How an LLM can work better with a well-structured DSL&lt;&#x2F;h2&gt;
&lt;p&gt;To give some context, what the application needed was to combine two existing flags: &lt;code&gt;breakdown&lt;&#x2F;code&gt; and &lt;code&gt;details&lt;&#x2F;code&gt;. The time &lt;code&gt;breakdown&lt;&#x2F;code&gt; reports were already implemented but were only reporting time spent per day, week, month or year. What I needed were details of the projects I had worked on. The application already had a &lt;code&gt;details&lt;&#x2F;code&gt; flag but it was not implemented for this view.&lt;&#x2F;p&gt;
&lt;p&gt;In the test DSL, the flags are set by calling methods in the &lt;code&gt;given&lt;&#x2F;code&gt; setup phase: &lt;code&gt;breakdown_flag(...)&lt;&#x2F;code&gt; and &lt;code&gt;details_flag()&lt;&#x2F;code&gt;. The breakdown feature did not implement the &lt;code&gt;details&lt;&#x2F;code&gt; flag, so it was not used in the tests for this feature. What is nice (and I credit this way of testing for it) is that the LLM was able to figure out the &lt;code&gt;details_flag&lt;&#x2F;code&gt; was already present and decided to re-use it: &lt;code&gt;Cmd::given().details_flag()....&lt;&#x2F;code&gt;. Here is an example of such a DSL test:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;breakdown_day_with_details_should_show_tasks_per_day&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; some_content = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;## TT 2020-01-01
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;- #project-a 1h Task A
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;- #project-b 2h Task B&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    Cmd::given()
&lt;&#x2F;span&gt;&lt;mark style=&quot;background-color:#a7adba30;&quot;&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;details_flag&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;&#x2F;mark&gt;&lt;mark style=&quot;background-color:#a7adba30;&quot;&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;breakdown_flag&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;day&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;&#x2F;mark&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;tags_filter&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;[&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;project-a&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;project-b&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;])
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;at_date&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2020-01-01&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;a_file_with_content&lt;&#x2F;span&gt;&lt;span&gt;(some_content)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;when_run&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;should_succeed&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;expect_task_with_duration&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;project-a&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1h 00m&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;expect_task_with_duration&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;project-b&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2h 00m&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Thank you for reading,&lt;&#x2F;p&gt;
&lt;p&gt;Hans&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My agentic coding stack for October 2025</title>
        <published>2025-10-05T00:00:00+00:00</published>
        <updated>2025-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/my-agentic-coding-stack-for-october-2025/"/>
        <id>https://hanlho.com/p/my-agentic-coding-stack-for-october-2025/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/my-agentic-coding-stack-for-october-2025/">&lt;p&gt;After wrapping my head around the constant changes in LLM subscriptions and performance, here&#x27;s my new coding stack for October 2025:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Warp Pro&lt;&#x2F;strong&gt;: my go-to agentic CLI, speedy and reliable for coding and task automation. Supports most top end LLMs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Zed Pro&lt;&#x2F;strong&gt; (using the $20 trial, then €10&#x2F;month)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;OpenCode&lt;&#x2F;strong&gt; for agentic CLI dev (local + cloud models, easy swapping, no lock-in)&lt;&#x2F;p&gt;
&lt;p&gt;I dropped Claude Code and did not subscribe to Codex. If this turns out to be a bad idea, I can always resubscribe again.&lt;&#x2F;p&gt;
&lt;p&gt;My main decision influences: cost control, flexibility and avoiding vendor lock-in (Claude Code&#x27;s past month changes have this effect).&lt;&#x2F;p&gt;
&lt;p&gt;After spending a few months in the CLI I want to look again at working more in an IDE, hence Zed is on this list.&lt;&#x2F;p&gt;
&lt;p&gt;Note: I do not subscribe to Max plans, I combine multiple lower cost plans.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Grounded decision records from AI conversations</title>
        <published>2025-09-02T00:00:00+00:00</published>
        <updated>2025-09-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/grounded-decision-records-from-ai-conversations/"/>
        <id>https://hanlho.com/p/grounded-decision-records-from-ai-conversations/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/grounded-decision-records-from-ai-conversations/">&lt;p&gt;If you&#x27;ve read some of my posts before or worked with me, you know I like using Architectural Decision Records (ADRs) &lt;a href=&quot;&#x2F;p&#x2F;less-mentioned-benefits-of-architecture-decision-records&#x2F;&quot;&gt;for lots of reasons&lt;&#x2F;a&gt;. To me the most important one is documenting the why of a decision.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;ve worked with AI models before, you&#x27;ve probably asked them for options when brainstorming solution ideas when you&#x27;re not sure about direction. In this situation, I&#x27;ve found it quite easy, maybe even more logical, to document the decision in a decision record with help from the AI model you have been working with. After all, you got feedback from it anyway.&lt;&#x2F;p&gt;
&lt;p&gt;This post briefly explains how I use Claude Code to write decision records (not necessarily architectural ones) when it&#x27;s helped me make a decision. My goal isn&#x27;t to dive into an elaborate investigation into the pros and cons of this approach, but I will touch upon a few points. The process is not specific to Claude Code but can be adapted to other AI models or tools as well.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the process I&#x27;ve been following:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. Ask for the decision record during the conversation&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After going back and forth on options and reaching a decision, I ask something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#eff1f5;color:#4f5b66;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Given&lt;&#x2F;span&gt;&lt;span&gt; your feedback, I think Option 2 is the way I want to implement.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Principally&lt;&#x2F;span&gt;&lt;span&gt; I do not want to complicate things with 2 tools at the moment.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Before&lt;&#x2F;span&gt;&lt;span&gt; implementing, summarise this into an ADR in the &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;adr&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; directory as a way of confirming our mutual understanding.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;So,&lt;&#x2F;span&gt;&lt;span&gt; write an ADR first, then ask me to confirm the ADR. Once I do, continue implementing.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The phrasing is a bit sloppy, as this is what I actually wrote in my recent changes, but that&#x27;s OK, Claude Code can work with this.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. Review and edit the generated draft&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;What it comes up with initially is actually pretty good. A lot will depend on the conversation you had with it and the input you gave it, of course. But the decision record mostly contains what was discussed and decided quite well. The text will be structured like an ADR even without me having to explain what an ADR is. It even picked up the decision record&#x27;s next number too.&lt;&#x2F;p&gt;
&lt;p&gt;Usually content editing is needed, but having a complete draft to start with makes a big difference instead of starting from a blank page. So after the draft is written, I edit it mostly on content only.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;3. Use as implementation foundation&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When done, the decision is basically documented and it can serve as the basis of our next step. To make the continuation based on the decision record only, at this point you could clear or restart the Claude Code session to start fresh.&lt;&#x2F;p&gt;
&lt;p&gt;This last step is meant to ground the decision record in reality. When you include the decision record as basis for implementation, it becomes living documentation that creates a feedback loop. During implementation you may encounter issues not anticipated during the decision making process. These can then be documented in the decision record, creating a continuous improvement cycle.&lt;&#x2F;p&gt;
&lt;p&gt;I often use my home projects as playgrounds to experiment with new ideas, technologies, and methodologies I want to try out because they&#x27;re new to me or because I want to confirm they&#x27;re still useful. This is why most of my home projects serve two purposes: build the thing and apply what I think are best practices.&lt;&#x2F;p&gt;
&lt;p&gt;In this particular project, I felt the need to create decision records. They aren&#x27;t necessarily architecture related decisions but more decisions I&#x27;d like to document to remember why I went this way. I mainly make use of the markdown format of ADRs to document my decisions.&lt;&#x2F;p&gt;
&lt;p&gt;Generally speaking, this is mostly an experiment at the moment. I&#x27;m trying this out in the setting of personal projects, but I think it may lower the bar for writing decision records in general. Not everyone wants to go to great lengths to record decisions, even if they see the value. Personally, I think it doesn&#x27;t need to take a lot of time to document a decision, yet I often end up spending much more time on it than I anticipated or hoped for when I started writing one.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lhohan&#x2F;references&#x2F;blob&#x2F;main&#x2F;adr-example&#x2F;005-enhanced-notes-status-tracking-build-command.md&quot;&gt;Here&lt;&#x2F;a&gt; is a decision record example for those interested. It is written by an LLM mostly. I know this may be controversial, but it is also useful. I do not think this is &#x27;AI slop&#x27;, if you review it and it all makes sense, I don&#x27;t see much need for a complete rewrite. Having a documented decision is worth more than not documenting because it was written by AI. I haven&#x27;t tried this in a team or organisational setting, but I&#x27;m curious to see how it works out and how people would feel about it. In any case, whoever created the decision record with help of an AI is always responsible for the decision and its recording.&lt;&#x2F;p&gt;
&lt;p&gt;Also, &quot;working with an LLM replaces thinking&quot; is an often heard argument. I agree and it&#x27;s a reason for concern for me too, the impact on my own thinking. But an LLM also comes up with good ideas. It is easy and tempting to simply accept what&#x27;s there. Maybe not all decisions require deep thinking though, and we just want to note down why we&#x27;re doing the thing we&#x27;re doing this way.&lt;&#x2F;p&gt;
&lt;p&gt;I am also thinking it may be useful to add to the decision record to what extent an LLM was used to generate the content. Firstly it will get it out of the way when people are suspicious of AI being used and to what extent. I think this is comparable to time or other constraints one has when writing ADRs or decision records in general: this may be worthwhile to document too. Sometimes there is not enough time to think deeply about the decision or consider more options and you have to make a decision with quite some unknowns. In these cases I recommend documenting this in the decision record too.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, there are quite some interesting things that can be done next. When working with Claude Code, if you would create decision records more often it makes sense to create a command to use as &#x27;saved prompt&#x27;. I actually created an agent for this as well (to try out agents mostly, I admit).&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve written about ADRs before, if you want to read more about them:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;p&#x2F;less-mentioned-benefits-of-architecture-decision-records&#x2F;&quot;&gt;Less Mentioned Benefits of Architecture Decision Records&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;p&#x2F;ground-your-adrs-with-a-verification-section&#x2F;&quot;&gt;Ground Your ADRs with a Verification Section&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Thank you for reading, Hans&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Grounding AI Instructions in Living Documentation</title>
        <published>2025-07-28T00:00:00+00:00</published>
        <updated>2025-07-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://hanlho.com/p/grounding-ai-instructions-in-living-documentation/"/>
        <id>https://hanlho.com/p/grounding-ai-instructions-in-living-documentation/</id>
        
        <content type="html" xml:base="https://hanlho.com/p/grounding-ai-instructions-in-living-documentation/">&lt;p&gt;Context engineering shows interesting potential to &lt;em&gt;ground&lt;&#x2F;em&gt; documentation to actual code, or as how I sometimes refer to it: reality.&lt;&#x2F;p&gt;
&lt;p&gt;Linking AI instruction files (&lt;a href=&quot;http:&#x2F;&#x2F;CLAUDE.md&quot;&gt;CLAUDE.md&lt;&#x2F;a&gt;, .rules, .cursorrules, etc) to development documentation may turn static docs into living resources. Each code generation cycle tests documentation accuracy and real-world application. This creates a direct feedback loop that keeps documentation aligned with actual development workflows.&lt;&#x2F;p&gt;
&lt;p&gt;Also, this coupling of documentation and implementation may create friction but I expect this to a good thing long-term. It signals opportunities for documentation improvement, encouraging streamlined, practical documentation that genuinely serves developers, while also identifying code that diverges from documented standards.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Some quick thoughts:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The feedback loop is fuzzy given how LLMs work, but an LLM can likely explain why it implemented something based on the documentation.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Documentation will likely become more actionable and directive.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The &#x27;why&#x27; behind guidelines typically belongs elsewhere, but could become an evaluation against actual code.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Developer documentation may work better in the code repository (and in markdown).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;LLMs currently work best with concise instruction files - this constraint likely benefits developer documentation too.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
</feed>
