Where I recall the evolution of my tooling over the last few years.
The following text reveals the parts of the journey that stuck; there were numerous not-so-successful experiments on the way there, many tools I tried and ultimately did not adopt or stopped using very quickly, and which I choose to not include here.
Pre-history: 2022-2023
In the early times, GitHub released “copilot” (unrelated to the modern Microsoft brand), an API which could be integrated in a text editor (e.g. VSCode), and which ran LLM inference from the position of the cursor in a text editor. Based on the lines of text before the cursor, especially explanatory comments, it was able to guess your intent. You could then use tab completion to accept the suggested code.
I recall it did feel half like magic, half gimmicky. It was helpful for boilerplate, but not too good when caring about making code readable.
Copilot at the time had good support in Emacs, the only text editor I use:
(use-package copilot :quelpa (copilot :fetcher github :repo "copilot-emacs/copilot.el" :branch "main" :files ("dist" "*.el"))) (add-hook 'prog-mode-hook 'copilot-mode) (define-key copilot-completion-map (kbd "<tab>") 'copilot-accept-completion) (define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion)
In the grand scheme of things, copilot barely helped me. The first product I launched in 2024 after I adopted copilot ( https://breaktheice.social/ ) was implemented entirely without it.
Early history: 2024-2025
At the end of 2023, LLMs had become slightly more capable and the Cursor editor became extremely popular throughout 2024. With social pressure from friends, I explored Cursor at the end of 2024 then took a subscription in early 2025. At the time, it included unlimited inference with SOTA models as part of its “Auto” mode, a pretty good deal compared to 2026 and later.
What brought me to Cursor was the advanced contextual inference (“tab completion”) and local prompt based inference (“command K mode”). What made me stay after that was the “agent mode” it also included. Note that the term “agent mode” at the time referred to the “chat based programming” right side pane in the Cursor IDE, and is unrelated to headless agent-driven programming that became popular later.
However, I never liked IDEs; I am way more productive with keyboard
and a vertically scrolling terminal than with a mouse and 2D navigation.
So when Cursor released its cursor-agent CLI tool, I started using
that instead and never looked back.
What ultimately drove me away from Cursor was when its “Auto” mode became metered. At the time, there were alternative harnesses for the terminal and so switching was seamless.
Changelog instructions
It is while using Cursor that I founded the most important building block of my agent instructions, which is now included in all my projects: tracking the user input and choices made in a changelog alongside the code.
This comes in addition to tracking / updating work done in issue trackers. I also do it for projects that are not only about code (e.g. data transforms, static web files, Home Assistant experiments, etc.).
Why:
- it’s necessary to ensure I can hand over work started by one agent (e.g. Anthropic’s) to another one (e.g. Deepseek) and back again.
- it helps track the separation between my input and the decisions made by the agent. This also helps agents performing later changes to track back the rationale of choices, and stay coherent across projects. (Note that I since extended my coverage of this goal by also introducing specification libraries, not described here.)
First version of this instruction snippet:
During each agent conversation, create and maintain a changelog file to track changes, decisions, and progress. ### File Creation - Create changelog file in `changelog/` subdirectory - Name format: `YYYYMMDD-topic.md` (e.g., `20241220-api-integration.md`) - Auto-generate topic based on first message content - Use descriptive, kebab-case topics ### File Structure Each changelog file must contain: ```markdown # Changelog: [Topic] ## Specification Summary [Brief description of what was requested/accomplished] ## Files Modified - [List of files that were created, modified, or deleted] ## Test Strategy [Description of how changes were or should be tested] ## Obstacles & Solutions [If obstacles were encountered, document them here with potential solutions] ## Conversation Notes [Key decisions, direction changes, or important notes from the conversation] ``` ### Maintenance - Update the changelog file throughout the conversation - Add new sections as the conversation evolves - Document any changes in direction or scope - Include file paths, code snippets, and decisions made
This evolved several times afterwards. As of Q3 2026, here’s what I am currently using:
When a task will lead to a change, you must always create, update maintain a changelog file that tracks the specifications, changes, decisions, and progress. Update the file before and throughout a task to: - Track specifications and choices from the user - Maintain awareness of ongoing tasks and implementation decisions - Reference previous conversations through changelog files when relevant - Track project evolution and architectural decisions over time When launching a sub-agent to perform work on your behalf, remind them to create/update a changelog file as well. ### Formatting the changelog file The file is placed in the `changelog/` directory with the naming pattern: - **Format:** `YYYYMMDDhhmm-topic.md` (generate the timestamp using the shell command `date +%Y%m%d%H%M`) - **Topic generation:** Auto-generate from the user's initial request - **Example:** `202508141342-claude-md-improvements.md` The changelog file must include: 1. **Task Specification**: Clear description of the original request and scope 2. **High-Level Decisions**: Major architectural, technical, or strategic decisions made 3. **Requirements Changes**: Track when and how requirements are modified mid-conversation 4. **Files Modified**: List of all files created, modified, or deleted (no code diffs, just summaries) 5. **Rationales and Alternatives**: Why certain approaches were chosen over others 6. **Obstacles and Solutions**: Problems encountered and brief (1-line) solutions 7. **Current Status**: Progress tracking and next steps
The result is a repository under the changelog/ directory that I can consult whenever I need to look back at what happened, why it happened, the options we’ve considered and not adopted (and why), etc. even months later. It also helps me gauge the periods of time I have been active on a project (I use this for journaling and work timesheets).
You can find an example project where I’ve used this system here: https://github.com/knz/spkrd/tree/master/changelog
Also by ensuring I use the same changelog system across all my projects, it’s very easy to switch my focus from one to another because I can then use the same mindset and reading habits to revisit recent changes and decisions.
There’s been many other “rule files” and “skills” I tried throughout the entire period, but none of them have given me as much leverage as this one. I just don’t understand how other people are able to work on anything significant without an analogous system.
Headless Cursor
For context, most of my development occurs on a development server I access remotely over SSH and/or mosh.
As I wrote above, I prefer working from a terminal; while Cursor does
support connecting to a remote Cursor server over the network, toward
the end of my Cursor relationship in 2025 I had started using the CLI
harness cursor-agent exclusively.
Note
Why SSH and not a graphical remote desktop? See above: I have always been way more productive in a terminal. Also, remote graphical desktops suck when accessing from a spotty connection in a train or a plane.)
Note
Why remotely and not using a laptop? Laptops get lost or stolen, batteries get empty while traveling and without a charger, system upgrades can malfunction, hard drives can fail. With enough years of technical work (twenty+ in my case) all these things tend to happen eventually, whereas a properly administered always-on remote server remains rock solid and always available. Additionally, the development server also contains more compute cores and RAM, and runs faster, than a reasonably weighted laptop.
My first experience with multi-agent development was running
cursor-agent manually in multiple tmux
panes/windows. This was straightforward enough, and soon I wanted each agent
to spawn separate sub-agents to work on tasks and review (for context
size management), before sub-agent orchestration became a native feature.
For me, it was very important that sub-agents would let me intervene. At the time, LLM inference tended to get stuck in loops, so I wanted to retain the ability to steer it while it worked on tasks. My idea was thus to have agents create their own tmux panes/windows and launch sub-agents in them, while I could also interact with the tmux panes myself.
For this, I used tmux-cli. Although
this tool was originally built for Claude Code, at the time I was not
using Claude, and it worked fine with cursor-agent. I used the
following instructions:
## Implementation Strategy Using tmux-cli and cursor-agent ### Workflow Design 1. **Launch separate panes** for spec work and implementation work 2. **Use focused AI agents** with constrained context per phase 3. **Review cycles** with separate review agent after each major phase 4. **Iterative clarification** - handle questions autonomously when confident ### tmux-cli Usage Pattern ```bash # Launch shell pane for spec work tmux-cli launch "zsh" # Returns pane ID (e.g., 2) # Send cursor-agent command with focused prompt tmux-cli send "cursor-agent <task>" --pane=2 # Wait for completion tmux-cli wait_idle --pane=2 --idle-time=3.0 # Capture output to review tmux-cli capture --pane=2 # Launch separate review pane tmux-cli launch "zsh" # Returns pane ID (e.g., 3) tmux-cli send "cursor-agent review <spec>" --pane=3
This was slow, but workable. I used this configuration a lot for a couple of months in 2025, until sub-agent orchestration became sufficiently good. I still use it sometimes when I request an agent to drive an interactive demo to show me something.
Sound indicators
The point of headless agents is to let them do their thing while I focus on other work. I also strongly dislike switching back and forth to check whether an agent has completed a task and/or needs my input.
For this, I am using sound notifications. One small chirping sound for progress (silence means something got stuck), and separate distinct sounds for success, failure, and need more inpout.
This is a mechanism I had already been using since pre-2023 for local
development, via this script in ~/bin/x:
#! /bin/sh # Run the command and play a melody depending on its final status. "$@" s=$? melody="" case $s in 0) melody=f16g16 ;; 130) : interrupted - no sound ;; *) if [ $s -lt 128 ]; then melody=o1c. # error else melody=o2ec # signal fi ;; esac echo $melody >/dev/speaker exit $s
(This relies on the speaker(4)
driver and could be used as prefix, for example x make or x
./dev.sh build. I still use this too.).
I initially ported the x principle to Cursor hook configurations,
as early as mid-2024, then later using Claude’s settings.json. The
sound was initially played through speaker(4) directly, and later
I switched to a client/server architecture via spkrd/spkrc: when I am traveling, I want to
receive the sound notifications on my local terminal for status
updates happening on the remote server.
Example Claude Code config:
{
"hooks": {
"PostToolUse": [{"hooks": [
{
"type": "command",
"command": "spkrc c32",
"async": true
}
]}],
"Stop": [{"hooks": [
{
"type": "command",
"command": "spkrc f16g16",
"async": true
}
]}],
"StopFailure": [{"hooks": [
{
"type": "command",
"command": "spkrc o2ec",
"async": true
}
]}],
"Notification": [{"hooks": [
{
"type": "command",
"command": "spkrc o3f16e16f16",
"async": true
}
]}],
...
Token metering at a glance
When I started using Claude Code, I also had to start caring about token usage. Claude code’s own usage reporting is very limited (or at least was, from the beginning up to the time of this writing).
So I was an early adopter of ccstatusline-usage, some time in 2025. In Claude’s settings file:
"statusLine": {
"type": "command",
"command": "bunx -y ccstatusline-usage@latest",
"padding": 0
},
I still depend heavily on this.
Mobile tracking and control
With more and more tasks offloaded to headless agents, I find myself more and more frequently able to run errands away from a desk while the agents are working on long tasks.
A long task however still needs my input sometimes, for example to clarify a design decision or to make a strategic choice.
For this type of incidental participation, I became interested to monitor and control my headless agents as well as the other terminal sessions they control with tmux from a phone.
For this, I have adopted ccgram at the start of 2026. It supports reporting results, showing me input dialogs from agents, and running terminal commands from a Telegram multi-channel group chat. The reason why I find this better than, say, a mobile SSH client to access the agent’s CLI directly is that ccgram also supports transferring files, for example when I need to exchange product screenshots with the agent, and also shows me progress from each tmux pane in separate Telegram channels.
Ccgram is still part of my workflow today.
Tmux status indicators
As the number of agent panes in my tmux session grew, it became cumbersome to switch from one another to check on their progress. By Spring of 2026, I had started to like ccgram giving me a visual summary of all my agent sessions side-by-side on my phone, and I wanted something similar for my desktop terminal.
This is what led me to tmux-agent-switcher, which I am still using to this day.
Although its main advertised feature is a pop-up overview menu, the feature I end up relying on is the small icon that it maintains next to each window title in tmux’s status bar, which indicates the agent’s current status (running/blocked). This allows me to always know which pane to go to, without having to explore them all, when a sound notification tells me something needs my attention.
Cross-system orchestration
Medio 2026, I started to feel pressure from multiple simultanously growing desires / needs:
- I became more fluent in “token economics” and attentive to the progress made by open weight models. Increasingly frequently, I found myself wanted to orchestrate complex tasks with sub-tasks using one model and other sub-tasks using another. Opencode and Pi can help with this, but I actually would like to coordinate tasks across multiple harnesses side by side, not just different models.
- I have become fluent at steering long-running tasks and thus more comfortable at doing so while running errands / traveling. Sadly, the Telegram network introduces a big latency (up to seconds) to ccgram updates, and my brain hates that unnecessary friction. Also, the Telegram client is very “airy” and I found myself often wanting a higher text density on screen than what Telegram allows.
- I more frequently work on separate unrelated projects simultaneously and so would appreciate a visual separation between projects, i.e. per-project aggregation of agent sessions. Doing this with a single tmux session is very cumbersome, and coordinating multiple tmux sessions on a single screen is also unwieldy.
- Also increasingly frequently, I am running agents on multiple systems besides my main development servers, and wanted a single screen interface to orchestrate them all.
After trying to address each area of pressure with its own additional layer of tooling, I discovered Paseo, which I am still using to this day.
What I especially like about Paseo (besides it addressing all the pain points above) is that it extends my tmux/agent setup and does not aim to replace them. It both can drive tmux-based agents, and let me drive paseo-launched agents from my tmux CLI.
It also provides a “tool” based Paseo interface to individual agent harnesses: this is what makes it possible for a Claude Code agent to seamlessly delegate a sub-task to a GLM agent over OpenRouter, or vice-versa, with Paseo reporting task progress for each of them uniformly.
Task and next-step tracking
Very early through this journey, I realized that I was not interested to use the built-in task tracking (“todo”) facility of some harnesses, mostly because I frequently stop work in one tool and resume it in another.
Additionally, I do not wish to depend on a network service (e.g. Linear or Github issues) since many projects do not have an online presence at all and I do not wish to pay the overhead of setting up an online system for projects that otherwise do not require internet connections at all.
This led me early on to rely on file-based task tracking: in addition to the changelog files already discussed above, I set up workflows that forced my agent to write plans / steps to files on disk, and track progress by updating these files. I figured through experimentation that using markdown files for tracking work is a skill that all agent technologies understand and agree on quite readily, with little steering.
I used plan files in this way from mid-2024 to summer 2026, with great success, and continue to do so for small independent projects.
However, lately I have started to work on cross-project tasks, as well as longer-horizon projects where the work happens over multiple weeks and git worktrees. File-based task tracking, in this context, becomes cumbersome: which directory should the files be stored in? If they are part of the git history, how to synchronize them across worktrees?
After a lengthy research process (approx. a month) with tons of experiments using different tools, I adopted Kata as a local issue tracker. It has the smoothest CLI surface when used from multiple competing harnesses, stores its state in SQLite and thus integrates well with my existing backup workflow, and also contains a built-in, lightweight web viewer.
Tried them, and did not make sense (for me)
voice input. Writing always gets me to results much faster than speaking into a microphone.
“memory systems” where agents automatically choose where and how to persist information across tasks. My changelog system, supported by my own project management infrastructure (including a spec library, task tracking etc) gives me both more precision about provenance (is this information mine or the result of inference?) and also works better to update my own understanding of the work over time.
OpenClaw and similar - the security model makes no sense. 😱
integrating the agents with other specialized tools via MCPs for development (e.g. Notion, Linear, Figma). I tried this and it did not bring joy, nor benefits compared to plain text files on disk and driving tools with a CLI interface (e.g. Github via
gh, or thekatatracking tool).(Meanwhile I’m using MCPs successfully to import data or operate/actionate external systems in LLM-supported control systems, i.e. for non-development tasks.)
Looking at the future
In the current cambrian explosion in available tooling, the strategy I chose to remain calm, sort through the noise and develop my skill and toolset can be summarized to three points:
- I care for open source technology and will always bias my choice towards an open source solution when one exists. This is both an ethical consideration (I want to promote social structures where people help each other without a mandatory monetary transaction), and a practical one: I need to safeguard my ability to modify my tools when they are defective, incomplete, or become abandoned by their maintainer. My technology use spans years, so the latter tends to always happen eventually.
- I apply a degree of distrust towards technology supported by large-ish corporations and especially that supported by venture capital. These tend to evolve erratically over time, as corporate goals shift, and also tend to enshittify under VC pressure towards ROI. While I avoid being religious about this—I would feel foolish to completely ignore SOTA technology on this ground alone—it guides me towards always ensuring that I do not come to depend on corporate-funded software for long-term productivity habits. This is why, for example, I actively maintain my ability to use different LLMs and different harnesses, and switching between them.
- Knowledge of the Lindy effect continues to serve me well. For example, I choose to continue using Emacs to review my code and maintain my git history, because the Lindy effect teaches me it will likely remain a good tool for the job many years into the future, far beyond the lifetime of other tooling fads. I sometimes look with sadness at coworkers who had to switch and re-learn between text editors and IDEs over the years, when Emacs has served me well for 25 years and is likely to continue to evolve just as long. The same principle invites me to stick to tmux and tmux-compatible tooling for agent-assisted engineering.
One thing I do not yet have a solution for, and which I am exploring with low priority, is a way to ask a committee of models for non-technical feedback on certain choices (design, strategy), as a running meta-commentary while I am working on other projects. For example, I would welcome comments about days where I do not balance communication tasks with implementation tasks as much as I had intended, or when I spend too much time on a task that is not a high-priority in my current project. For this, I would need a model to get access to all the surfaces that I direct my attention to through the day, across multiple platforms. So far I know, this technology does not exist yet, and the security controls it would need give me some anxiety.
References
Tools and services mentioned above, in order of appearance:
- GitHub Copilot — editor completion from an LLM, integrated in VSCode and other editors.
- Visual Studio Code — the editor Copilot was first integrated with.
- copilot.el — the unofficial Copilot plugin for Emacs used in the configuration above.
- GNU Emacs — my text editor since 25 years, still used for code review and git history work.
- Cursor — the LLM-enabled IDE I subscribed to in early 2025, with its “tab completion”, “command K” and “agent mode” features.
- cursor-agent — Cursor’s CLI harness, which I used exclusively toward the end of my Cursor period.
- Claude Code
— Anthropic’s CLI harness, source of the
settings.jsonhook and status line examples above. - DeepSeek — one of the alternative model providers I hand work over to.
- GLM / Z.ai — open weight model family used for delegated sub-tasks.
- OpenRouter — model routing service used to reach models across providers.
- opencode — open source terminal harness with multi-provider support.
- Pi — minimal, extensible terminal coding agent harness.
- OpenClaw — local-first personal assistant framework; tried and rejected on security-model grounds.
- mosh — roaming, latency-tolerant remote shell used to reach the development server.
- tmux — terminal multiplexer, the substrate for all the agent panes described here.
- tmux-cli — lets an agent launch and drive sub-agents in separate tmux panes that I can also type into.
- speaker(4) — FreeBSD console speaker driver, used for status melodies.
- spkrd / spkrc — my client/server port of the same idea, so remote agents can chirp on my local terminal. Its changelog directory is a public example of the changelog system described above.
- ccstatusline-usage — token and cost metering in the Claude Code status line.
- ccgram — monitor and control headless agents and their tmux panes from Telegram.
- tmux-agent-switcher — per-window agent status icons in the tmux status bar, plus an overview pop-up.
- Paseo — cross-system, cross-harness agent orchestration that extends rather than replaces a tmux setup.
- Kata — local, SQLite-backed issue tracker with a CLI surface usable from several harnesses at once.
- GitHub CLI (gh) — how I drive GitHub, in preference to an MCP integration.
- Model Context Protocol — the MCP integrations referred to above; useful to me for control and data tasks, not for development.
Comments
Interested to discuss? Leave your comments below.