Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
import "./.next/dev/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
82 changes: 82 additions & 0 deletions src/routes/posts/reasons_to_be_a_token_miser.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
meta:
title: Reasons to be a token miser
description: There is a school of thought that says 'Just throw money at the problem' - here's why you should be constantly optimising your token usage.
dateCreated: 2026-05-27


tags:
- "ai"

---

import { TextHighlight } from "@blacksheepcode/react-text-highlight";


1. **Less tokens = faster results**

<TextHighlight comment={<p>See: <a href="./the_time_a_task_takes_changes_your_workflow">The time required to wait for a job to complete - changes the workflow for how you do it</a></p>}>There's a big difference between a workflow that takes a day to complete vs ten minutes to complete, vs one minute to complete, vs ten seconds to complete, vs a second to complete. </TextHighlight>

If your prompt gives enough context to the LLM that it comes to an answer _without_ having to produce its own lengthy reasoning chains, then you'll get the answer quicker and stay focused on the task at hand.


2. **If a solution can be got to with less tokens, it's probably the better one**

The observation I'll make here is that sometimes the LLM gets into a state where it goes around in circles in a reasoning chain, eventually it'll stop and often the solution won't be a good one.

I propose a cludgy aphorism here - 'If an LLM hasn't come to a solution by 80K tokens (or whatever number), chances are it's going to use another 200K tokens to get there, and chances are, that solution isn't going to be a good one'.

3. **Positions yourself to avoid a rugpull**

In many cases you can get away with just throwing a large model at a problem, coming back in an hour or so, and there will be _some kind_ of working solution.

However, remember that currently AI use is subsidised by the AI providers - in some future such case it would be good to be able to move to a cheaper and/or self hosted provider.


## Practical Suggestions

1. **Make use of code generators**

For any coding work that is strictly derivative - that is - the content of the code can be trivially determined programatically - don't get AI to do this work, relegate that work to scripts.

Instead of giving your LLM the instruction:

```
After creating the node in folder `src/nodes/`, add that node to the registry in `src/nodeRegistry.ts`
```

Give it the instruction:

```
After creating the node in folder `src/nodes/` run `bun generateNodeRegistry`
```

Even better, a hook could be used.

2. **Make use of codemods**

Let's say you have some code that looks like this:

```javascript
function foo() {

return doX();
}
```

And you are conducting a refactor where you now use `doX2()` which is an async function

```javascript
//👇
async function foo() {

return doX2();
}
```

This is a complicated task that will likely have cascades beyond just the initial file being changed.

Don't just have AI come up with a plan and execute it. Have the AI create codemods - test those codemods, and execute that instead.

A big advantage of codemods is that once they're written - they're repeatable. Chances are, this change when merged will create all sorts of merge conflicts. The codemod can be used to transform the incompatable branch before doing the merge.

60 changes: 60 additions & 0 deletions src/routes/posts/the_time_a_task_takes_changes_your_workflow.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
meta:
title: The time required to wait for a job to complete - changes the workflow for how you do it
description: There's a big difference between a job that takes one hour, vs a job that takes one minute vs a job that takes less than a second
dateCreated: 2026-05-27


tags:
- "software_engineering"

---

See also [this stack exchange question](https://softwareengineering.stackexchange.com/questions/459194/is-there-a-term-pithy-law-that-represents-the-idea-that-the-time-it-takes-for-an
)

<table style={{maxWidth: "600px", "margin": "0 auto"}}>
<thead>
<tr>
<th>Duration</th>
<th>Attention/Context</th>
</tr>
</thead>
<tbody>
<tr>
<td>1s</td>
<td>Unbroken attention, no context switch</td>
</tr>
<tr>
<td>1-10s</td>
<td>Attention broken simply by boredom, potential to view another browser tab, check emails</td>
</tr>
<tr>
<td>10s-1hr</td>
<td>Almost definite context switch to small tasks or non-productive tasks</td>
</tr>
<tr>
<td>1hr+</td>
<td>A context switch is required. At large waits, the context switch is actually less disruptive, because you now have time to get into that thing</td>
</tr>
</tbody>
</table>



Where I think this is most relevant when considering the time it takes for developer tooling to run - think running tests, linting either locally or in a build server.

It can be tempting to say 'well what does it matter if the tests take fifteen minutes/two minutes/30 seconds to run - you'll waste more time waiting for the elevator/making coffee/participating in the company ping pong tournament.'

But the point isn't the actual time spent, the point is that the wait completely changes the way you do your work.

## Practical suggestions

- Adopt all the fast tool runners - bun, biome, typescript 7, etc. It's absolutely worth it.

- Shard your test runs on the build server.

- You can use tools like `lint-staged` to only run checks on a subset of files, but the problem with this is that your change might have broken something downstream from the file you are working on.
- Instead monorepo tools like NX and Turborepo have tooling to run commands only affected packages. If you make a change to package A and package B depends on it, then the tooling will run tests against both packages.
- There is similar tooling in the test runners. Bun has [`bun test --changed`](https://bun.com/blog/bun-v1.3.13#bun-test-changed) which works by using the import graph to determine which modules have changed. Be aware that if you were doing something with dynamic imports or file operations these might escape detection.
- [Vitest also has a `--changed` flag.](https://vitest.dev/guide/cli.html#changed)
Loading