AI Chief of Staff
My specialized AI agent that can execute complex tasks on my behalf. It's connected to my AI brain, which is able to make decisions similar to how I would, thanks to over 16,000 interactions I fed it.
Open case studyLeadershipEngineeringDesign

My specialized AI agent that can execute complex tasks on my behalf. It's connected to my AI brain, which is able to make decisions similar to how I would, thanks to over 16,000 interactions I fed it.
Open case study
I placed four of the top AI models in a digital world where they can battle or form alliances and observed what they did.
Open case study
Change the game
Open case study
Gear S2 - Campaign website
Open case study
Enterprise CMS website
Open case study
Platform for Google events
Open case study
Placeholder entry. Replace with a real project before launch.
Open case studyAn engineering leader who never stopped being an engineer.
I am an engineering leader who never stopped being an engineer. I have shipped products end to end, from data ingestion through to the interface, and lately most of that has been AI.
When one of our AI products started failing on three quarters of every large document it read, I went and learned prompt compression and sub-agent patterns myself, brought them back to the team, and we took the failure rate from eighty per cent to zero. It got sixty-seven per cent faster on the way.
I have been taking things apart since I was six. Toys first, then PCs, then interfaces, then the systems behind them, and now the models. Leading teams is mostly the same instinct pointed at people and architecture instead of hardware, and the question has not changed: how does this work, why does it pull you in, and how do I make it better?
Great design draws us in. It makes things usable. Great development keeps us there, because it makes things useful. The marriage of the two is what I have spent my career on, and I love it most when they arrive together.
How can I make myself replaceable?
My management philosophy comes down to one question I ask myself: how can I make myself replaceable? People grow most when they have clarity on what success looks like, the autonomy and trust to find their own way through, and consistent, pointed feedback along the way. My engineers would describe my style as collaborative, structured, trusting and autonomous. I am a hands-on coach early on, then I deliberately step back so people can grow into ownership.
Five tech leads I coached now own their roadmaps and operate without me in the room. One of them is an engineering manager. That is the measure I actually care about.
The hardest part of working this way is the discipline to refrain from stepping in, especially when you can see something about to go wrong and you know exactly how to fix it. Letting someone experience it and then coaching them through the reflection is almost always more effective than solving it for them. The risk is stepping back too early, before somebody is ready, and I guard against that by being explicit about what success looks like and staying closely observant at the start.
When somebody wants a decision from me, I ask for four things: the problem, the options they considered, the tradeoffs, and their recommendation. I call it the Decision Stack. It turns "here is a problem" into "here is my call, tell me if I am wrong", which is the difference between reporting and owning.
I evaluate engineers on two pillars. Impact, which is reliability, performance and scalability. And communication and leadership, which is alignment, clarity and knowledge-sharing. The higher the level, the more each dial turns from replicating systems to designing ones with leverage across the organisation. AI usage is written into every rung of that ladder rather than sitting beside it.
On team structure, I aim for roughly thirty per cent senior, forty per cent mid and thirty per cent junior. It creates growth paths without sacrificing delivery on complex work. I keep a primary and a secondary on every project so no single person is a point of failure. Team structure should not be static: my job is to evolve it to serve the business and the engineers at the same time.
Leading outside my own depth taught me the most. My strongest background is the front end, and early on I could not always pressure-test a backend proposal in the moment. Rather than trying to become an expert in everything, I made RFCs mandatory for significant work and changed the questions I asked. Instead of implementation details, I anchor on production risk, scale and maintainability: what happens if this fails, how do we mitigate it, what will this cost in production? My job leading outside my core depth is not to match the experts technically. It is to build the conditions that let the right decisions surface.
From the engineering career matrix my teams are evaluated against.
Five pieces on TypeScript's error messages, static typing, and what to do with an engineer who is failing in the wrong role. Read over thirty thousand times.
30,000+reads on Medium
Poor Performer? You Might Just Have Them in the Wrong RoleI once managed a junior engineer who was struggling in a conventional software-development position.
The TypeScript Guide I Wish I Had
A Cheat sheet for Python and Typescript static typing
Conquering a complex error in TypescriptHow to read and understand the Object Literal error
How To Read Errors in TypeScriptTypeScript can be riddled with errors and warnings, for seemingly every little thing. Take this function for example:If you would like to collaborate, or you think I would be a great fit for a role you are sourcing, please get in touch. You can also find me on LinkedIn or GitHub.
My specialized AI agent that can execute complex tasks on my behalf. It's connected to my AI brain, which is able to make decisions similar to how I would, thanks to over 16,000 interactions I fed it.
A colleague posts a possible incident in a watched Slack channel. Users cannot complete payment at checkout, 87 affected so far. My workspace, my drill - and the agent does not know the difference.
The watcher normally waits two minutes in case more messages follow. That phrasing cancels the wait. It sends me one direct message: the first line says nothing has been done yet, and underneath it, two buttons. That message is the only human gate in the system. Per-action approval during an incident is six prompts arriving at the exact moment nobody reads them.
I press yes. The buttons disappear before any work starts - that ordering is pinned by a test - and the run begins. It reads the next hour off my calendar, cancels only what is genuinely in the way, messages each organiser separately without telling any of them what the incident is, opens a war room, then writes me a severity report.
Seven of these have run end to end. They average 78 seconds and 26 cents.

15,470 documents. Chat exports from four services, PDFs, Medium drafts, work documents, transcribed talks, and 248 of my own coding sessions.
Loading that last source meant first discovering that it was mostly not me. Of 17,995 records marked as written by the user, 17,165 were tool output. About 359 were sentences a human had typed, and a system that learns my voice from the rest learns a shell's voice.
So there are two indexes rather than one with a flag on it. Everything goes into a knowledge index; only the 3,315 chunks that are me writing in my own voice go into the second. A query that forgets a filter fails open and still looks perfectly normal.
A question runs against a dense index and a keyword index at the same time, and the two result lists are fused with reciprocal rank fusion. On real questions over this corpus, the two methods returned zero overlapping results.
That number is the reason hybrid retrieval is here at all. It is the difference between a technique chosen because it is fashionable and one chosen because the alternative was demonstrably missing answers.
The wait is the part I could not engineer away. A retrieval pass and a model call sit between a question and its answer, and no amount of streaming hides the first token.
12 questions, sorted by the failure they catch rather than the topic they cover. The two that matter most: it invents a position rather than admitting it has none, and it presents material written for me as my own thinking.
5 questions, two-sided on purpose. Two where the settled statement has to win, three about arriving at it where the early drafts are the right answer. A weight that gets one side right and the other wrong is worse than no weight.
Every passage that reaches the model carries who wrote it and when, so every answer is traceable to the passage it came from. When the archive is silent it says so rather than filling the gap.
Both harnesses use fixed questions, because a question that moves between runs measures nothing. Neither of them tests the agent: nothing here measures whether cancelling that meeting was the right call, and I do not yet know how I would.
A limit that lives in the prompt is a limit the model can be talked out of, and it only has to happen once. Growing this means adding an action in code, with its own ceiling and its own test, rather than widening a sentence.
The two halves stay separable the same way. An AST test fails the build if the agent package ever imports the brain package, so the thing that acts and the thing that remembers cannot quietly grow into each other.
26 cents is caching, not the model being cheap. Of the tokens it has read, 4.6 million were cache reads against 31,549 fresh ones - the prompt prefix is stable by design, so almost nothing is paid for twice.
The retrieval half costs nothing per question. The embedder runs on this machine's own CPU, and only the assembled passages are ever sent anywhere - about 6,000 tokens, which is also the whole of what leaves the laptop.
The results of a live run. Explore the UI to see what the agent and my AI brain thought and how they collaborated to solve a problem.