Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[author]
name = "Craig Hill"
role = "Machine Learning, AI Applications and Data Engineer"
current_focus = "How to make coding fun again in an AI world"

[blog]
topics = [
    "artificial intelligence",
    "zettelkasten",
]
frequency = "irregular random rolling releases"

[contact]
github = "github.com/craigtkhill"
linkedin = "linkedin.com/in/craigtkhill"

I've been having a lot of thoughts about AI lately. These thoughts on how we are using AI revolve around a singular point. Sure, developers are losing their precision, creativity, autonomy, but most severely, coding is not fun.

There was a branching point at which using AI to help code stopped being fun. This was around the time that developers started trading Copilot's basic line completion for more cursor-style vibe coding IDEs.

I notice that as LLMs take bigger and bigger steps, the quality of their output declines. Sure, they might do fantastically on benchmarks, but their benchmarks do not match my real-world use case. So I can't rely on their APIs for a stable workflow. I'm not saying we should stop using AI for development. But we should stop relying on it. I don't want AI tools that write all the code. I want tools to write the code the way I want to write it.

REQUIREMENTS

As a developer...

  • I want a pair programmer who helps me improve my coding skills, so that I can learn better practices and techniques through our collaboration.
  • I want a pair programmer who reviews and validates my code without writing it for me, so that I can catch errors and improve code quality.
  • I want to work with immediate feedback, so that I can validate code quickly and avoid wasting time moving slowly in big, imprecise steps.
  • I want to achieve a flow state so that I can be maximally productive and engaged with my work.
  • I want to refine my code line-by-line in real time, so that I can catch issues immediately rather than dealing with large, error-prone walls of code.
  • I want to understand my codebase and how it functions, so that I can maintain full ownership and knowledge of my system.
  • I want to maintain full control over system architecture and design decisions, so that the overall structure reflects my vision and requirements.

As far as I can tell in my research, no one else is implementing AI to meet these requirements. The direction we are collectively heading has become so painful that I find myself in desperate need to try something different.

The goal is to make programming fun again, and who knows, maybe it will give me an advantage in reducing the amount of slop I need to clean up. Maybe there is a reason everyone is going in the same direction. However, it's not working for me.

Before we dive into trying to make AI work better, here are some of the things I think AI does quite well.

Socratic Method

Use AI to ask you questions to get you thinking. Use AI to ask you questions about what you are not thinking about. AI is great for this to help you clarify your ideas. The opportunity of using AI to make breakthroughs in many fields, including mathematics, will be simply helping you identify ideas you were unaware of and apply it to your problem.

AI is useful when you have no clue how to do something and want to get to an answer quickly. But it is useless for finding optimal answers. If you are pressed for time and you don't care enough about an answer to invest more time into it, then AI is certainly better than traditional web search or following your gut. If it is something more serious, then you will need to check your answers.

Simple Debugging

If you have a bug in your code, you should always try to figure it out yourself. It's a muscle that you need to keep flexing. Oftentimes, the error is simple to catch, especially if you use tools with helpful error messages. However, if you find yourself staring at a problem to the point that your brain is skipping over gaps, trying to figure out what might be going on, it's helpful to throw it into AI to get a second opinion. Usually, it works pretty well. But always be wary of false positives and don't ask AI to seek bugs that might be there. Its response is usually too noisy and unless you know what you are doing and can separate the wheat from the chaff, it's often counterproductive to take its suggestions wholesale.

Rapid Prototyping

When you know what you want, AI sucks. When you don't know what you want, AI is great. AI can be useful for experimentation as long as the results don't need to be reliable. And with the cost of writing crappy code being reduced, you can now perform more experiments faster. In problems where there is less time involved, AI performs better (2-hour projects). However, when given more time, humans perform better (both AI and humans get 32-hour time budgets) Problems involving more code favor humans, while fewer favor AI. Also, if you think this is a trend that's changing, and there is evidence of a so-called Moore's Law of AI that suggests AI can exponentially perform tasks that take longer and longer, then I have news for you. It's true, but it comes at the cost of precision. An AI can perform tasks that take longer and longer, but when you look a the steps it takes to get there, its assumptions are often wildly off, providing a rocky foundation on which to build from.

RE-Bench performance vs time budget Performance comparison showing optimal time allocations vary by agent type, with AI agents making faster initial progress but humans improving more rapidly with additional time. Source: Wijk et al. (2025). RE-Bench: Evaluating frontier AI R&D capabilities of language model agents against human experts. METR.

Self-Made Tools and Systems

If you know how to use your tools, using AI often isn't that helpful. If you know how to write code and know what you want, then it is often faster to write the code yourself rather than repeatedly prompt AI until it gives you the code you are looking for. Sometimes you may have processes that you understand very well and are worthwhile automating. AI is great for these tasks. However, I suggest you create a system that uses AI to funnel data into it rather than using the AI (and I mean specifically the model) as the system itself. Not only is this more reliable, but it will also give you an advantage, so long as your system isn't easily sherlocked, you'll have access to something that makes you more productive than anyone else has.

Deeptech Breakthroughs

AI is terrible, especially if you ask it about a domain you know nothing about. But if you know a domain very well and ask the right questions, it can reveal insights that can help you make breakthroughs. Granted, 90% of its suggestions will be pure hocum but if you know your stuff, AI can still be helpful, and you can identify a little golden nugget to explore. Always, check its sources. AI does make progress in deep technical challenges. Google DeepMind created AlphaEvolve, an AI system that found an algorithm to multiply 4x4 complex-valued matrices using 48 scalar multiplications, improving upon Strassen's 1969 algorithm. You should think about this sort of discovery exactly like evolution, the probablility of a new discovery or improvement is extremely small, so if you are prepared to burn down the rainforest and you know how to evaluate an answer is correct, you can make a breakthrough, hopefully that breakthrough is on how not to burn down the rainforest.

The future of AI-assisted software engineering is not writing code; it's pair programming. Pair programming with a colleague is where you take turns to be the driver and navigator.

  • Driver:
    • Controls the keyboard and mouse
    • Writes the actual code
    • Focuses on the immediate task of implementing the current line or function
    • Handles the tactical, detailed work of coding syntax and mechanics
  • Navigator:
    • Reviews the code as it's being written
    • Thinks about the bigger picture and overall direction
    • Spot potential issues, bugs, or improvements
    • Considers the broader architecture and design decisions
    • Asks questions and suggests alternatives

The reason to pair program is to get extra eyes on the code, spread understanding, reduce technical debt, and share learning.

Right now, the way we are using AI can be considered pair programming where the human is the navigator, prompting AI to drive the code generation. But what if the software engineer is the driver and AI the navigator?

Limitations are good

If you find yourself using AI to fix every problem, it can be difficult to wean yourself off. You need immense coding skills you set yourself apart from AI, and you won't learn those relying on AI.

At first, it can feel like you are moving at a glacial pace. Using AI gets you there quickly, but you need to slow down to really learn something. To let the thoughts marinate in your brain and take root, you need to go slow so that you can go fast later.

Start projects where there is no rush, no expectations, build those skills slowly, and limit your AI use.

Here are some ideas for limiting your AI use.

  1. Restrict yourself to basic plans.
  2. Devote half your time to thinking without AI.
  3. Ban yourself from copy/pasting code.
  4. Read the documentation first to understand how a library works.
  5. Use smaller locally hosted models
  6. Develop your tools and use them.

The number one slop stopper is to stop copy/pasting code. When AI isn't changing large sections of your code, you are forced to read and understand what it is doing. So keep the slop out of your IDE and find ways to make it harder for you to copy/paste code. Use AI, let it show you how to do something, but never copy/paste large blocks of code.

What you should work on

  • If AI can't figure something out in three prompts, then you know that's a good sign it's worth your while investigating with human intelligence.

Advantage in an AI world

If you just know how to use the models that everyone uses or the tools that everyone uses, then you will be a commodity.

AI cannot do the really interesting stuff, which is solving really hard problems that involve understanding whole systems, and AI cannot understand the larger context of lots of decisions.

However, AI can guide decisions in systems, and that makes them powerful.

AI makes predictions, and predictions are a key input into decisions. But we also need judgment and data. And as humans, we can bring that all together.

It will be our own individual human-driven systems, and I think systems that are opinionated, consistent, and deterministic, that will work better for true applications of AI. Systems enable defensibility and can scale. Systems are hard to copy because they are complex. And in an AI world, our superpower might be to build our systems that use AI to augment our decisions and allow us to do things that only we as individuals can do.

In other words, it's the applications built on top of AI that will be what separates the leaders from the pack.

Introduction

A Zettelkasten (German for "Note Box") is a garden for growing ideas you accumulate throughout your life. Over time it builds and becomes an architecture to structure your philosophy, help you to solve problems, and guide decisions.

Rather than scatter your digital knowledge throughout different projects, a Zettelkasten acts as your central knowledge management repository. It is the one place where everything you learn goes regardless of the project you are working on.

When you look online at other people's Zettelkasten systems, you'll notice each system is unique and personalized. And it should be. The workflow for your Zettelkasten should grow from your personal experience and needs as you use it. However, it can be daunting starting out, looking at how almost everyone makes their process super complicated. They take notes of everything they read. They spend hours writing their notes. And hours more fiddling with their processes. You don't need this. You need a system that's simple, portable, efficient, and practical. My process is much simpler. Capture, Nurture, and Share. Just read and listen and observe with a question in mind and write down what seems insightful and useful to you. Over time, you will develop an intuition to capture only that which resonates with you.

Think of consuming information as a panning for gold, the more you pan the more small amounts of gold build in the pan. You don't need to take notes on everything. Your system doesn't need to get bloated with information. You just need to pan for the few nuggets of gold that touch you every day in your digital garden's stream of thoughts to reap the benefits.

And this book will show you how to unlock the gold rush.

Connecting Ideas

The Unix philosophy suggests that programs should do one thing and do it well and your notes should do the same.

A rule of thumb is to keep notes short enough and to fit on a single screen without scrolling (and you should break this rule when needed). When you are constrained, you are forced to think about the fundamentals of the idea you want to convey. This is the key idea of atomic notes.

However, I go further, notes should not just be atomic, they should also be modular. You should design your notes in such a way that you can easily move, link, and duplicate them in your knowledge system without any rewriting or refactoring. This modularity allows you to easily connect and reconnect notes together.

Progress is rarely made by brute-force thinking. Good ideas are rarely conjured from the ether. Progress is more often made by making connections.

Writers make connections between ideas. Engineers make connections between things. Business leaders make connections between people.

By connecting notes we expand our learning and understanding. By connecting ideas, we develop a framework to represent the data and facts of our respective areas of interest, enabling us to become experts in our field. All that's left then is to elaborate on our network of connected ideas in a meaningful way.

Capture Nurture Share

The first elements of a Zettelkasten involve capturing, nurturing, and sharing.

Capture

To capture I have a simple note app that takes in all my random thoughts. I call this my "Mind Dump".

Nurture

To nurture, each day I look at this random collection of notes, thematically organize them and paste the contents into a file that's related to the content. Then I choose some areas I wish to clarify and organize these thoughts into coherent ideas. Turning each thought into an individual note.

Share

Finally, through this book, I express these thoughts. The process of which refines my thinking and leads me further to nurture my ideas.

Time-Context-Category-Hierarchy

TCCH: A Latch Method alternative

To decide where to put our notes in relation to each other, it is helpful to use this process of organization.

Time

Time and attention are our most scarce resources. It is also the one most useful in making or notes discoverable when we need them most. The first note should form the entry point to other notes that we can time-bound. For example, I have a note that I check daily that reaches all other time-related notes. This is useful for creating a routine of identifying and nurturing notes that are of most critical importance now.

Context

These are notes that are grouped related to a specific problem or occasion you have encountered or may encounter. They work a little bit like Time except there is no requirement schedule them in advance. You just access the information as needed when you encounter the context, enabling you to can act on the fly to any situation.

Category

These are the broad categories notes can belong to. You can think of them as genres for books or departments in a government. They largely should not overlap with each other. Although there's no need to strictly enforce this. It's just useful to know which category a thought belongs to or whether to create a new category.

Hierarchy

This is where things get interesting. In your categories you can break ideas into themes with as many layers of depth as you like. I suggest you tackle this iteratively and over time. Ditto for the broad categories. You want your broad categories to emerge as you merge and split ideas apart and group them into themes. Keep going until your ideas can't be split apart and your broad themes are mutually exclusive. This will leave you with a hierarchy of notes with different levels of detail going right down to the most fine-grained. These are the atoms which you can now reassemble into an interesting chemistry of ideas.

Zettelkasten Refactor Tool

To help manage my Zettelkasten, I'm building zrt - the Zettelkasten Refactor Tool. zrt has two primary goals.

  1. to be a command line tool to help nurture Zettelkasten notes and
  2. to be an introductory project for me to learn the Rust programming language.

My ordinary workflow involves using Obsidian. However, certain tasks require specific tools to help me with challenges I face. Chief among them for me right now is the question of "What notes should I organize next?".

While I could create a plugin for Obsidian, I wanted something that doesn't rely on any particular interface and that could be extended to work with any workflow, including Vim.

Hence, I started creating this cli tool in Rust. Welcome to the user guide and documentation for zrt.

YAML Frontmatter

The first thing you need to know about zrt is that it uses yaml frontmatter to organize metadata about your notes.

Your YAML frontmatter should look like this and be placed at the very top of the file.

---
tags:
  - refactored
  - blogged
---

Note The refactored tag lets me know that this note has already been processed and the blogged tag informs me that I have shared this note.

The tags you use are completely flexible. You can tag however you see fit.

Ignoring Folders

If there are files and folders you don't want to consider in your refactoring, you can add a .zrtignore file to the root of your obsidian vault or knowledge management folder.

It works like a .gitignore file.

# /.zrtignore
ARCHIVE/
CALENDAR/
DRAWINGS/
IMAGES/
.git/

now the files in these folders will be ignored by the zrt tool.