releases

What changed

What each version added and what it fixed. The app tells you itself when a new one is out, so the only thing to do here is read.

codemeRelease notes v1.5.2 · 2026-11-02

1.5.2 2026-11-02 current

A release that fixes the window slowing down and holding a lot of memory in a repository with thousands of changed files. A sleeping agent now wakes when its tab is clicked.

Git

  • The Git panel stays fast with thousands of changed files. It draws only the rows on screen, so typing a commit message with six thousand changes no longer stalls on every letter, and the panel no longer holds a lot of memory. The file lists of commits, comparisons, pull requests and reviews do the same.
  • A large diff no longer stops the window. The first 3000 lines show at once and “Show 3000 more lines” opens the rest. A change that is not shown in full has no stage or discard button.
  • The branch menu opens at once in a repository with thousands of branches. It shows 300 and the search finds the rest. The branch you are on shows wherever it sorts.

Agent

  • A sleeping agent wakes when you click its tab. It used to wake on the first key, and until then the tab looked like a bare shell. Closing the tab with × or opening its menu does not wake it.

The window

  • The window is no longer redrawn whole every second. It was, even when the list of terminal sessions had not changed. The file tree is not redrawn either when nothing changed.

1.5.1 2026-10-30

A release that fixes Codex and Claude tabs coming back as a shell after a restart, slow worktree switches, and the right side of the window being cut off in full screen. It also closes a few ways unsaved edits could be lost.

Agent

  • After a restart, Codex and Claude tabs no longer come back as a shell. Several Codex tabs in one folder each return to their own conversation, and a tab whose conversation cannot be told shows the list of conversations instead of a bare shell.
  • Hold Option and drag to select text in an agent’s screen.
  • A sleeping agent wakes as it was. A Claude started by hand with flags woke up without them, and while waking an agent could be announced as finished or a team Claude tab could turn into a plain one.
  • An agent row’s tooltip no longer shows fragments of its screen.

The window

  • Switching worktrees is faster. The sidebar no longer runs git on every worktree every four seconds, and work waiting on git no longer holds a switch up. Hover “switch” in the status bar to see where the time went.
  • The right side of the window is no longer cut off in full screen. Entering full screen on a monitor of another resolution made the window wider than the screen.
  • Unsaved edits are no longer lost. Switching to the preview or to another worktree saves first, and stops rather than overwrite a file that changed on disk meanwhile. “Close others” leaves tabs with unsaved edits open.
  • The worktree order you drag stays. It came undone when another worktree was opened, or one was created or removed.
  • Coming back to a worktree, the tabs behind the front one keep their place too. A document tab that was not in front went back to the top.

Git

  • The merge panel keeps the answers you picked. Resolving another file or staging anything used to start it over.
  • After a fetch, the commits to pull show at once. Also fixed: the Git bar showing the worktree just left right after a switch, and the file tree not showing new files after a switch.

1.5.0 2026-10-26

A release for running agents across many worktrees at once. Resting Codex and agents in other worktrees now fall asleep and give their memory back, and after a restart Claude and Codex tabs come back to the conversation they were in. My work opens on a to-do list, agents whose conversation has grown long are pointed out, and changed images can be seen before and after.

Agent

  • After a restart, Claude and Codex tabs come back to their own conversation. A Claude tab sometimes came back as a bare shell, and a Codex tab came back on the folder’s newest conversation. Each tab now remembers its conversation and resumes that one.
  • Agents whose conversation has grown long are pointed out. Every turn sends the whole conversation again, so the longer it is the more tokens each turn costs. A long one gets its token count on the agent’s row, and once per conversation a note suggests /compact or /clear.
  • Claude and Codex scroll less. A light push on the trackpad could move dozens of lines. Scrolling now follows how far your hand moved, and “Scroll speed in agents” in settings (1 to 10, 5 by default) adjusts it.
  • A file link in the terminal no longer opens a file other than the one it names. A link whose text and address disagree is not opened.

Memory

  • A resting Codex falls asleep too. Until now only Claude did. The next key typed into its tab wakes it on the same conversation.
  • Agents in worktrees not on screen fall asleep after five minutes of rest. The worktree on screen keeps fifteen. “Put idle agents in other worktrees to sleep” in settings changes it, and a working agent is never put to sleep anywhere. A Claude started by hand in a tab now falls asleep too.

The window

  • My work opens on a to-do list. Your pull requests that failed or had changes requested, reviews waiting on you, what is due this week, and your tickets in progress, in that order. The old view is the Statistics tab, and “What My work opens on” in settings picks the first view.
  • Changed images show before and after in Git changes. Where a single “binary” line used to be, the picture before and after sit side by side — staged, unstaged and in history.
  • The HTML preview no longer draws a page with a dark theme on white. The page follows the window’s theme, and a button above the preview picks light or dark.

Usage meter

  • Codex usage matches the real numbers. The meter invented a five-hour window that did not exist, and did not show a limit being reset or credits being added.
  • Usage counts every token. Only the last 8 MB of a long log was read, so it counted a tenth to four tenths of the real number.

1.4.2 2026-10-23

A release for moving between many worktrees. A resting Claude left on screen now falls asleep, Claude’s screen no longer occasionally breaks after a worktree switch, file links in the terminal and images in Markdown open, and tabs can be pinned.

The window

  • Tabs can be pinned. Right-click a tab and choose “Pin tab”. Pinned tabs gather at the front of the strip, wear a pin instead of ×, and are not closed by a middle click, Cmd-W or “Close others”. “Close tab” in the menu still closes one.
  • Scroll positions survive a worktree switch. Markdown previews, editors, diffs and CSV tables were back at the top after a trip to another worktree.
  • Images in a Markdown document show in its preview. Paths are read relative to the document’s folder, and a leading / from the workspace. Images from web addresses are still not loaded.

Agent

  • File links Claude prints open the file. The blue underlined links in the terminal (file://) did nothing. A line number takes you to that line, a file outside the workspace opens read-only, and web links open in the browser.
  • Claude’s screen no longer breaks after a worktree switch. The fullscreen renderer ("tui": "fullscreen") draws only what changed, so a screen restored from saved output could keep fragments of two frames. After restoring, Claude is now asked to draw the whole screen again.

Memory

  • A resting Claude falls asleep even when it is on screen. Fullscreen Claude is sent a terminal signal whenever the pointer passes over it or the window changes focus, and redraws a little in reply; the app counted both as activity, so fifteen minutes never passed. One Claude stayed awake for most of a day. Now only keys a person types and the agent’s own output count, and the pointer passing over a sleeping Claude no longer wakes it.

1.4.1 2026-10-21

A release that fixes the window freezing in 1.4.0. While an agent was running a command, terminals could stop taking keys, Claude and Codex in a new tab could fail to start, and switching to another worktree could do nothing.

The window

  • Terminals and worktree switching no longer freeze. To tell a dev server from other commands an agent started, 1.4.0 read the open ports (lsof) while holding the lock every terminal shares. On a Mac running security software that took seconds, and keystrokes, agent starts and worktree switches all waited on it. Those reads now happen only outside the lock, and only when something needs them.

1.4.0 2026-10-21

A release for keeping an agent in each of several worktrees. “Needs you” now appears only when an agent is really asking, a finished turn reads “done”, and a turn whose commands are still running reads “working”. A Claude that is only waiting falls asleep and gives its memory back, and a key typed into its tab wakes it into the same conversation. Each worktree card shows the memory that worktree holds.

Agent

  • “Needs you” appears only when the agent asks. A Claude started from this app carries the app’s hooks, so it reads “needs you” only for a question such as a permission prompt, and “done” when its turn ends. Reading thirty seconds of quiet as a question was why every finished turn said “needs you”. ~/.claude/settings.json is not touched.
  • Codex’s [!] is read. Codex titles its terminal [ ! ] Action Required while an approval or a question is on screen; that is now the only time it reads “needs you”, and the notification comes at once. A Codex that goes quiet without the mark reads “done”.
  • Background commands read as “working”. While a test run or a build the agent started is still going, the row no longer turns to “needs you” just because the agent stopped writing. A dev server listening on a port does not count as work.
  • Once seen, it settles to “done”. After you open the tab, a quiet agent no longer comes back as “needs you”. A question the agent asked itself stays until it is answered, since looking at it does not answer it.
  • After a restart, each tab returns to its own conversation. Two Claude tabs in one worktree both came back on the folder’s newest conversation. Each tab now remembers its own.
  • If you added the hooks yourself, add the matcher. A Notification hook in ~/.claude/settings.json with no matcher also shows “needs you” a minute after a turn ends. Add "matcher": "permission_prompt|elicitation_dialog|elicitation_url_dialog|agent_needs_input" to it, or remove the hook if you only run Claude from this app.

Memory

  • Idle Claude agents go to sleep. A Claude that has finished its turn, is running nothing and has been left alone for 15 minutes has its process ended to give its memory back. The tab and its screen stay, the row reads “asleep”, and a key typed into the tab wakes it into the same conversation (that key is not typed). Change the time under “Put idle agents to sleep” in Settings; 0 keeps every agent awake. Working and asking agents are never touched, and there is no limit on how many run at once.
  • See what each worktree holds in memory on its card. It adds up the agents, their MCP servers and any dev server left running in its terminals. The status bar’s memory is the app’s own process, which never counted any of them.

The window

  • Clicking a worktree card no longer leaves it following the mouse. When the window was busy switching and missed the button being released, the next movement became a drag with no button held.

1.3.0 2026-10-16

A release about AWS Kiro, Korean encodings and file icons. Kiro’s CLI opens in a tab like Claude and Codex, and the credits it used are shown. EUC-KR (CP949) files can now be searched, opened and edited, and read as Korean in diffs and merge conflicts. Icons in the file tree and tabs become the Material icons familiar from VS Code. Also fixed: discarding or unstaging a hunk could remove the wrong lines, and characters typed while a save was in progress were marked as saved.

Agent

  • Open Kiro in a tab. AWS Kiro sits next to Claude and Codex in the + menu, and its tabs and sidebar rows carry Kiro’s mark. Reopening the app picks up the last conversation in that folder.
  • Queue work for Kiro. Pick Kiro under “Queue work for agents” and it starts on the prompt; left unwatched, it runs once with --no-interactive and exits.
  • See the credits Kiro used. The usage chip shows today’s credits, and its card the credits and requests of the last 7 and 30 days — as Kiro recorded them in its session files on this machine. Classic mode, which records no credits, is counted in requests.

The editor

  • Open and save EUC-KR files. CP949 files saved by Korean Windows tools were refused as “not valid UTF-8”. They now open as Korean and are saved back as EUC-KR. The editor header shows EUC-KR, and a character EUC-KR cannot hold, such as an emoji, stops the save and leaves the file as it was.
  • Set an encoding per folder or extension. Write legacy/ → euc-kr under “File encodings” in Settings, and files with no Korean in them yet, and new files, are saved as EUC-KR too. A file that already has Korean in it stays in the encoding it is in.
  • Characters typed during a save are no longer marked as saved. Characters typed right after ⌘S were not on disk, yet the tab lost its dot, so closing the tab or quitting lost them without asking.
  • ⌘S over “changed on disk” tells you first. It silently overwrote what an agent or another editor had written. Now the first ⌘S stops, and pressing it again overwrites.
  • A formatter that prints nothing no longer empties the file. A formatter that printed nothing for a path it ignores could leave the file saved empty.
  • Saving a file with a byte-order mark no longer shows “changed on disk”. The editor read its own save as an outside change.
  • Renames by the language server are kept in Local History. A rename across many files left no copy to go back to, and a single EUC-KR file among them made the whole rename fail.

Search

  • Find in Project starts from your selection. ⇧⌘F ignored the word selected in the editor, and an old search from a right-click stayed in the box. With nothing selected it starts from the word under the cursor, and with several lines selected it opens empty.
  • EUC-KR files are searched and replaced in. Files that were not UTF-8 dropped out of searches without a word. Replace writes them back as EUC-KR.
  • Files the search could not read are listed under the results. It shows how many files were over 2MB, and how many look like they contain the query but are in an encoding it cannot read; hover to see their names.
  • Results in a file mid-merge no longer appear three times. A conflicted file was searched three times, so when the replacement contained the query, Replace All changed the same place three times.
  • $ in a regex matches in files with Windows line endings. foo$ missed CRLF files entirely.
  • Links pointing outside the project are not followed. The contents of an outside file that a symbolic link in the repository pointed at showed up in results.
  • Clearing the query clears the results. Clearing it mid-search left the previous results and Replace All under an empty box. Files in folders with Korean names no longer sink down in Go to File either.

The file tree

  • File icons become Material icons. The icons from VS Code’s Material Icon Theme appear in the file tree, tabs, search, Git and Local History. Folders differ by name too, such as src, docs and node_modules. .env gets the settings gear, .svg the same icon as other pictures, and test files keep their language’s icon. The previous icons can be chosen with workbench.iconTheme in Settings.
  • Choose your own file icons. Write Cargo.toml → rust or *.properties → java under “Your own file icons” in Settings. For a folder, end the name with /.
  • Java and Kotlin packages get the package icon. Folders such as com and domain inside a source root show as packages, as in IntelliJ.

Git

  • Discarding or unstaging a hunk no longer removes the wrong lines. With an unpicked hunk above it and a similar block nearby, it removed a committed line instead of the one just added.
  • Staging is refused if the file changed since it was shown. If an agent changed the file in between, a change nobody had looked at got staged. Unstaging some lines of a newly added file no longer always fails either.
  • Korean reads correctly in diffs and merge conflicts. The merge panel garbled even UTF-8 Korean, and diffs showed EUC-KR Korean as ���. The bytes written to the file are the same as before.
  • Pull requests touching EUC-KR files open. The whole pull request failed to open with “stream did not contain valid UTF-8”.

Local history

  • Two versions kept at the same moment no longer collapse into one. Keeping a file twice within 1ms lost the first. EUC-KR files changed by an agent are now kept too.

The window

  • Less slowdown in a small window. The blur over narrow panels was recalculated with every line of terminal output and every keystroke, and the tab strip, diffs and status bar redrew needlessly whenever the window was resized. Narrow panels now show a translucent cover instead.

1.2.4 2026-10-15

A release that widens the debugger and History. JavaScript and TypeScript debug on top of Node, and the ▶ in the editor margin starts a single test under the debugger. In History, pick a range to find the commit that broke it (git bisect), and tag commits and keep tags in step with the remote. Folder icons now follow what the folder holds. Also fixed: saving after renaming an open file brought the old file back, and typing in terminals stalled every few seconds.

The debugger

  • Debug JavaScript and TypeScript. Nothing to install beyond Node. TypeScript runs as written on Node 22.6 or later, which strips the types, so lines match the file; output from tsc or a bundler stops on the original .ts line by following its source map. Conditional and hit-count breakpoints and logpoints work too.
  • Attach to a running Node, and debug npm scripts as they are. A script from this project started with node --inspect shows up in the Debug panel as an “Attach to …” row. Scripts in package.json become rows too, and tools such as npm, nodemon and vite are passed over to attach to the project’s own code. When nodemon restarts it, the debugger attaches to the new process.
  • Debug a single test. ⌥-click the ▶ in the editor margin, or choose “Debug the test here” from the menu. It works for vitest, jest, pytest, Go and cargo tests, and for JUnit tests under Gradle and Maven — JUnit attaches to the JVM the build starts, so the test runs exactly as it does in the build.
  • Go modules in a subfolder can be debugged. With go.mod one level down, debugging failed with “cannot find main module”. A Go program that ran to the end no longer leaves __debug_bin behind in its package.
  • Opening a Java file no longer adds files to the project. The language server wrote .project, .classpath and .settings/ next to pom.xml, leaving the worktree dirty. Two Java projects in folders of the same name can now be open at once.
  • Debugger ports no longer pose as servers. While debugging, the ports opened by the Node inspector, debugpy and the Java debugger showed on the worktree card as if they were that worktree’s servers.

History

  • Find the commit that broke it. Pick two commits as a range in History and choose “Find the commit that broke it…”. A strip above the list shows the commit being checked and the steps left; answer good, bad or can’t tell, or have a command run in the terminal to find it all the way. A worktree in the middle of this shows “bisecting” on its card.
  • Tag a commit, push the tag, delete it. Selecting a commit adds a “Tag…” menu. Writing a message makes it an annotated tag. Deleting removes it from the remote first — a tag deleted only here comes back with the next fetch.
  • Compare tags with the remote. “Tags…” at the top of the panel shows tags not yet pushed, tags only on the remote, and tags that point at different commits on each side, and pushes, fetches or deletes them from the remote in one go. It never force-overwrites a tag that already exists.
  • A range with a merge commit in it is refused before revert or cherry-pick. It used to stop halfway with “failed”, and Continue silently skipped the merge. Now it tells you to choose the parent in the terminal, as in -m 1.
  • The list no longer goes blank when it reloads while scrolled down. It happened after a search, a pull or a commit from the terminal.

Git

  • Once every merge conflict is resolved, the commit message is already filled in. It uses the message git prepared, such as “Merge branch …”. Before, the commit button stayed disabled until you made up a summary.
  • “Both” in a merge no longer writes a line twice when both sides added it. If both sides added the same import, the result has it once.
  • Answers in the merge panel no longer land in the wrong place when the file changes underneath. Resolving one conflict elsewhere shifted the remaining answers by one. Now the panel reloads and says why. A resolution is not written to a file with unsaved changes in an editor — the next save brought the conflict markers back.
  • An invalid new branch name is reported inside the dialog. The dialog closed, taking what you typed with it, and git’s fatal error appeared across the top of the window. A name that already exists is handled the same way.
  • The ↑ in the toolbar clears as soon as you push. After pushing from the commit panel it kept saying “↑3” for nearly 15 seconds. The git marks in the file tree no longer lag by a few seconds either.

The editor and files

  • Renaming an open file takes its tab along. The tab stayed on the old path, and saving brought the old file back next to the new one. Renaming a folder moves the tabs inside it too, and if any have unsaved changes you are asked to save first.
  • ⌘S no longer undoes a rename made with F2. Open tabs kept the old text and wrote it back on save.
  • “Changed on disk” goes away once the file matches the editor again. After an outside edit was undone, it still asked you to reload a file where reloading would change nothing.
  • A file that was deleted and came back no longer stays “Deleted on disk”. It happened to files a checkout removed for a moment. Also fixed: the tab of a deleted file raised a “file watch error” banner every time the app reopened, and stayed empty even after the file returned.
  • Opening a file you peeked at with ⌘-hover shows what is on disk. If the file changed after the hover, the old contents from the hover opened, and saving wrote them over the new ones.
  • Read-only files are not saved over. They used to be overwritten.
  • Local History works for a deleted file. Opening it to recover a file an agent had deleted said the file was already like that.

The file tree

  • Folder icons follow what the folder holds. Source, test, docs, config, asset and script folders each get their own colour, and generated folders such as node_modules and dist are dimmed. Set workbench.iconTheme to monochrome in Settings to take the colour out of icons.
  • Renaming that only changes case works. readme.md → README.md was refused as “already exists”. Also fixed: pasting a folder into a link that points back at it copied without end, and a link pointing outside the workspace could not be deleted or renamed.

Search

  • $1_id in a regex replace no longer becomes an empty string. Letters right after $1 were read as part of the group’s name, so the matches were erased and it reported “N replaced”.
  • No more identical-looking result rows in pairs. Two matches on one line show their column numbers, and files that share a name show their paths.
  • Files too large to keep an undo copy of are not replaced in. If a replace would touch a file over 1MB, it says so and writes nothing.

Terminal

  • Typing in terminals no longer stalls every few seconds. While the sidebar read the session list, keystrokes in every terminal waited. It was longer in windows with a dev server running.
  • You can type straight after pressing the new-terminal button. The keyboard stayed on the button, so letters went nowhere and Space and Enter opened more terminals.

Worktrees

  • Worktrees created as ../name or ~/name open. The worktree was created but the window looked for it in the wrong place, and ~ made a folder named ~ inside the repository.
  • A window opened on a subfolder no longer stays behind in a deleted worktree. “Clean up finished worktrees” no longer ends agents working in that subfolder either. A locked worktree is refused before its terminals are closed.

And the rest

  • “Check for Updates…” answers the moment you click it. It shows “Checking for updates…” first and ends with an error if there is no answer within 20 seconds. When a proxy or security software held the connection, it looked as if nothing happened.
  • Number fields in Settings save once you have finished typing. Typing 999 into the font size saved the 9 on the way, leaving 9px text. Now the value is clamped to its range and saved on Enter or when you leave the field, and an empty field goes back to the default.
  • SQLite BLOB values no longer look empty. The table and the row editor show them as BLOB with their size in bytes.
  • A language server that restarts knows the open files. After a language server died and came back, hover, completion and go-to-definition had no answer. With rustup but no rust-analyzer component, it now says the server is not installed instead of “the server stopped”.

1.2.3 2026-10-12

A release that brings Find to previews. ⌘F now searches Markdown, HTML, PDF and CSV previews, and CSV and TSV files show as tables. The Docker tab lets you choose the runtime that starts the daemon, and the docker context. Deleting a branch now deletes it from origin too. And Return no longer submits a field when it is only finishing Korean composition.

Preview

  • ⌘F finds in previews. In Markdown, HTML, PDF and CSV previews every match is highlighted, the current one stands out, and a count like “2/5” says where you are. In HTML it works after clicking into the page too, and finds only text you can see. Inside the PDF viewer ⌘F belongs to the viewer, so use the Find button at the top of the preview.
  • CSV and TSV show as tables. The first row stays put as the header, and numeric columns are right-aligned. The delimiter — comma, semicolon, tab or bar — is chosen from the file. Hundreds of thousands of rows open at once, and Find searches the whole file.
  • Large Markdown no longer freezes the window. A document over 600KB is shown as text first, with a “Render anyway” button. Over 1MB it is shown as text only. The same goes for PR descriptions and ticket descriptions.
  • Saving no longer sends HTML and image previews back to the top. Every change to the file lost your place. With Find open, saving no longer drags you to the match either.
  • PDFs follow the panel’s width. Dragging the divider left the pages at their first width, and a PDF rewritten while another tab was showing came back drawn the size of a stamp.

The Docker tab

  • Choose the runtime that starts the daemon. “Start Docker” only ever opened the one app the docker command pointed at. Now Docker Desktop, Rancher Desktop, OrbStack, Podman, colima and Lima each get a button when they are on this Mac — colima one per profile, Lima one per instance.
  • Switch the docker context from the tab. With two or more contexts a picker appears. When you have started another runtime and docker is still looking at the old socket, switch it here. If DOCKER_HOST or DOCKER_CONTEXT is set, the picker is locked and says which variable is the reason.
  • A runtime that fails to start says why. After a launcher failed straight away, the panel stayed on “Starting” and no other button could be pressed.

Branch

  • Deleting a branch deletes it from origin too. Delete in the branch menu removed only the local branch and left the one on origin, and a branch already deleted locally failed with “branch not found”. The confirmation now says where it will delete from, and does exactly that. A branch not merged into the default branch asks once more.

Worktrees

  • Deleting a worktree also ends the terminals of a window opened on a subfolder of it. In a window opened on a monorepo subfolder, terminals and dev servers kept running in the deleted folder, holding their ports. A worktree removed with git worktree remove in a terminal is cleaned up the same way, as long as the app is running.

Korean input

  • Return that finishes Korean composition no longer submits the field. In fields such as a branch name, a worktree path, a file rename or the search palette, the Return meant to confirm the last character submitted straight away — dropping the last syllable or closing the dialog.
  • Korean being composed in the terminal is no longer clipped on the left. It showed most at the Claude Code prompt, and the character was drawn whole only once it was confirmed.

1.2.2 2026-10-07

A release for running several worktrees side by side. Worktree cards in the rail show the ports their servers hold, the CI of the branch’s PR, and the files that will collide with another worktree or the default branch. If you turn it on, a new worktree’s ports are moved so they do not clash. The Ports panel groups other worktrees’ servers on their own. Also fixed: a single file named constructor breaking the whole file tree, and files an agent deleted staying in the list.

The worktree rail

  • Cards show the ports their worktree’s servers hold. With dev servers running in several worktrees, finding out which one started a server meant opening them one by one. A badge like :5173 now sits in the card’s corner, and “Open localhost:5173” in the card’s ⋯ menu and context menu opens it. A server with many workers still gets one badge.
  • Cards show the CI result of the PR opened from their branch. “✓ CI”, “✕ CI” or “… CI” sits next to the local check mark. Only your own PRs in the same repository count, and it uses the board My work has already read. GitHub PRs only, for now.
  • Collisions between worktrees are flagged ahead of time. When files would conflict if merged into the default branch (origin/main) now, or another worktree is changing the same files, the card gets a one-line warning with the file list in its tooltip. It is measured every minute and when you return to the window. The conflict check needs git 2.38 or later.
  • Task rows always have an icon. Programs not in the table get a terminal icon, and macOS’s Python is recognized. More Python, Go, Java and Ruby tools, and tools that run on Node, are recognized too.
  • A quiet dev server row no longer turns into “Done”. Rows for programs other than agents switched to “✓ Done” once output stopped, so a server still serving looked finished. They now read “Running”.

New worktree

  • A new worktree can get its own ports. With “Give a new worktree its own ports” turned on in Settings, the ports in config files carried into a new worktree — .env, YAML, TOML and the like — move by one offset so they do not clash with other worktrees. localhost addresses naming those ports, API URLs and CORS origins included, move with them; shared services such as databases and Redis are left alone. Committed files are not edited — the lines still naming the old ports are listed instead. Off by default.
  • Links pointing into another worktree are carried too. Creating a worktree from one whose node_modules/ was a link failed with “points outside the worktree”.
  • Files are carried into folders that already exist. When git had just created a folder such as .vscode, everything meant to go inside it was skipped. Files are now placed one by one, and files already there are left alone.
  • No more false “Already in the new worktree: .env”. With the default settings it appeared in red every time a worktree was created.
  • A window opened on a monorepo subfolder carries files into the same subfolder. They went to the new worktree’s top level, where the app does not look for them.
  • Branch names in Korean get their own paths. Two branches like feat/ followed by different Korean words mapped to the same path, and a name made only of Korean quietly disabled Create.
  • Pressing twice or cancelling while a worktree is being created no longer tangles things. A second Create put “already exists” on top of the success, and after Cancel the window still switched to the new worktree a few seconds later. The buttons now pause while creating, and Cancel comes back after eight seconds.

The Ports panel

  • Other worktrees’ servers are grouped by worktree. “This project” meant only the worktree currently open, so a server started in another worktree went under “Other ports on this machine” alongside other repositories’ servers. When another worktree holds a port you had remembered, the panel says which one.
  • Ports that are not this project’s have no Restart. Restart on the row of another project’s server, or of a program like Claude Code, stopped it and typed its command into this project’s terminal. Stop is still there.
  • A process whose folder cannot be read no longer takes over a remembered port. Another worktree’s container showed up through docker-proxy as this worktree’s server, and Restart stopped it.
  • Restart starts the server from the folder it was started in. Restarting yarn --cwd apps/web dev looked for apps/web/apps/web, and typing into a shell sitting in another folder could start a different package.
  • Deleting a worktree forgets the ports it remembered. A worktree later created at the same path inherited the old rows.

The file tree

  • Names like constructor and __proto__ no longer break the window. A file or folder with such a name broke the whole file tree or Files panel, and so did a diff or Markdown code block using it as a language.
  • Deleted files no longer come back to the list. When changes arrived in quick succession, an earlier read could finish last and draw the old list. Files an agent had deleted often stayed until the next change.
  • A folder deleted and recreated is still followed. After switching branches or rebuilding an output folder, its changes stopped showing. Folders you had expanded below it open again too.
  • Makefile, Dockerfile and .env.local get their icons in tabs, the Git panel and search too. Places that received a full path lost the name-based icon.

And the rest

  • Service names replace the word “forge” in Korean. For example, a Jira description that cannot be edited here now says “Edit in Jira”.
  • tcsh and csh tabs count as idle shells. The rail showed them as running programs.

1.2.1 2026-10-01

A bug-fix release. First in line were the paths where merely opening someone else’s repository made things happen — the repository’s settings file could change your terminal shell and the server your tokens are sent to, and the DB and Build panels ran code the repository chose as soon as they opened. Several ways of losing work while saving are fixed, and so is a whole-project Jira board showing other people’s tickets as “mine”. Signing in to Bitbucket or Jira anew requires this version.

Security

  • A repository’s settings file can no longer choose your terminal shell or server addresses. .codeme/settings.json inside a repository is layered over your own settings. Pointing the terminal shell at a script shipped in the repository ran that script the first time a terminal opened, and changing the GitHub, Forgejo, Bitbucket or Jira address sent your tokens to that server on the next board refresh. The shell, server addresses, OAuth clients and account emails are now read from your own settings only; when a project settings file sets them, you are told they are ignored. Things a project should decide, like tab size, still follow the project.
  • The DB panel no longer runs code from a repository’s .env. If an H2 URL in .env carried a setting like INIT=RUNSCRIPT, opening the panel connected to it and ran it. H2 URL settings are now limited to how the file is opened, and connections found in .env or in containers are not opened until you click them. Only connections you saved yourself open on their own.
  • The Build panel no longer runs ./gradlew as soon as it opens. Reading the task list means running the repository’s wrapper and build scripts, so merely opening the panel on a fresh clone ran them. If you have never picked a task from that runner on this machine, the panel now waits for “Load tasks”.
  • Preview pages can no longer read files in your home folder. The exception that serves files next to a file opened from outside applied to every preview page, so opening a single ~/notes.txt let a repository’s HTML page read the JSON in your home folder — credentials like ~/.docker/config.json included. Only an HTML, Markdown or SVG page opened from outside counts now, and folders whose names start with a dot are never served, even below it.
  • Bitbucket and Jira sign-in now finishes only when you approve it in a browser on the computer running the app. If someone else approved the consent link of a sign-in another person had started, the approver’s token could end up with whoever started it. The token is now handed over only once the approving browser comes back to the app. Older versions of the app therefore cannot sign in to these two anew and are told to update. Existing sign-ins keep working.
  • Redirects to a different port drop the token. As long as the host matched, the authorization header was kept even when the port changed.
  • Finding a favicon no longer requests the page’s address a second time. When the address in a browser tab was a sign-in, confirmation or password-reset link, the icon lookup could use up the one-time link first. It now looks on the site’s front page.

The editor

  • “Save and quit” no longer writes files you did not edit. It wrote every open editor, so a file an agent had changed was overwritten with the old text still in the editor, and files deleted from the tree came back. Restarting for an update did the same. Only files with unsaved edits are written now.
  • Text typed while the formatter runs is no longer dropped from the save. The formatted result overwrote it. If the buffer changed in the meantime, it is saved as it is now, unformatted.
  • “Save and close” waits for the save to finish. When saving failed — a read-only file, a full disk — the tab closed anyway and the edits were gone.
  • Saving can no longer leave a file empty or cut short. A full disk, or the app quitting mid-write, could leave the file empty. Files are now written alongside and swapped in, keeping permissions and symbolic links. A byte-order mark at the start of the file is kept, too.
  • Find and replace leaves files with unsaved edits alone. It changed them on disk, and the next save quietly undid the change. It now refuses when such a file is involved, records local history before replacing, and tells open editors.
  • Updating the table of contents no longer deletes part of the document. In a README that shows the <!-- toc --> marker inside a code block, everything from that block to the real contents was deleted. Only a marker pair outside code blocks with nothing but a list between them counts now. ## C# no longer becomes “C”, and three identical headings no longer share a link.
  • rustfmt no longer fails on code like async fn. The project’s Rust edition was not passed, so it read the file as 2015.

Git

  • Staging only the lines added after a file’s unterminated last line no longer corrupts it. Adding lines to JSON ending in } and selecting only the new ones staged }new glued together. Such a selection is now refused, asking you to include the last-line change too.
  • Discarding a hunk never throws away a change you did not see. If an agent edited further up while the confirmation was open, the numbering shifted and a different hunk was discarded. A hunk is now discarded only if it is still the one you saw; otherwise you are asked to look again.
  • Discarding or staging one hunk no longer takes the file’s mode change with it. Discarding a single hunk of a script you had chmod +x’d also removed the executable bit. The mode change goes along only when every change is selected.
  • Pushing no longer changes what a branch tracks. Every push reset the upstream to origin, so a branch in a fork that followed upstream switched remotes after a single push. A branch already tracking one of the same name is left as it is.

PR review

  • Line comments no longer land on the wrong line. If the author pushed while you were writing, comments attached to different code, or a line fell out of range and the whole review was rejected. Comments now attach to the commit the panel drew, and GitHub or Forgejo shows them as outdated if those lines have since changed.
  • Another user’s fork with a same-named branch no longer blocks your PR. On Forgejo only the branch name was compared, so it said the PR already existed.

My work

  • “Assigned to me” filters by assignee. With a whole-project JQL such as project = APP, every ticket counted as yours, so the toggle hid nothing on the Jira side. Other people’s and unassigned tickets now gather under “Someone else’s” at the bottom, and “Waiting on me” and review-request notifications are for PRs only.
  • Same-named sprints in two projects are no longer merged. Two projects each with a Sprint 12 showed as one choice, and it looked in progress even when one had closed. The dashboard’s current-sprint bar did the same. One sprint spanning several projects, and GitHub or Forgejo milestones given the same name in each repository, are still grouped as one.
  • Jira descriptions that saving would damage are not opened for editing. Fixing one typo erased mentions, attached images, dates, panels and link cards. Such descriptions now show “Edit on the forge” and why.
  • Jira checklists survive a save. With an empty item, or a checklist directly under a bullet, the following items became bullets and lost their done state.

Agent

  • “Message several agents” no longer types into a shell. Tabs whose agent had exited and left a shell in front were listed — checked by default — and each line of the message ran as a shell command. Only tabs with an agent in front are listed now, and this is checked again on send. Multiple lines go as one message.
  • Queued prompts are quoted correctly in fish. A prompt containing a single quote could end there, with the rest run as a command. Arguments to “Run this file” had the same problem.
  • After a restart, two Claude tabs in one worktree no longer resume the same conversation. Restoring picked up “the latest conversation in this folder”, so both tabs wrote to one conversation. Only the first tab per worktree resumes now; the others return to a shell so you can pick a conversation.
  • Saved layouts survive moving between versions. Tabs this version could not read (a tab kind from a newer version) were erased when another layout was saved. They are now kept and written back, and a file that cannot be read at all is moved aside before anything overwrites it.
  • Cleaning up finished worktrees no longer stops agents in the ones it keeps. When git refused to remove a worktree with uncommitted changes, its agents and shells had already been stopped. Worktrees with changes, or with something other than a shell running, are now left out first, with the reason.

Terminal

  • Claude Code installed with npm is recognized. Since the npm package started installing a native binary, its tab showed a terminal icon and dropped out of the rail and the “waiting for you” marker.
  • Swiping sideways on a trackpad no longer scrolls Claude down.
  • Text like 196m no longer appears instead of a colour. It happened when a redraw boundary fell in the middle of a colour code while Claude was printing heavily.
  • Switching tabs quickly right after opening a layout no longer leaves a broken screen. It could leave a fragmented screen with no scrollback.

The browser tab

  • The page no longer flickers on every link you follow.
  • A tab opened before its dev server was up now gets its favicon once the server starts. It used to stay a globe until the app restarted, and a different project on the same address showed the first one’s icon.
  • In a split window, the focus outline is no longer hidden by the page except along the top.

Local history

  • Edits you make between agent turns are no longer lost. The baseline was taken when a turn ended, so if the next turn overwrote what you had changed in between, it was kept nowhere. It is now also taken when a turn starts.
  • One failure no longer stops it. After a single failure — say, while an agent was running git commit — that worktree recorded nothing until restart.
  • Paths are right when you open a subfolder of a repository. Opening app/ resolved files as app/app/y.rs. The Agent changes panel is fixed along with it.
  • Local history opened as a tab shows new entries as they are recorded.

Panel

  • The Ports panel no longer claims processes from other folders. Remembered ports were matched by number alone, so something like macOS’s ControlCenter showed as this project’s, and Restart stopped it.
  • Stopping a port no longer stops whatever launched the server. Stopping a server an agent had started with npm run dev & could stop the agent too.
  • Docker “Remove” asks for confirmation.

1.2.0 2026-09-30

Web pages open in a tab. Keep the dev server beside the code, with the developer tools docked in that same tab. Boards in My work are drawn one per project, each with its own Jira columns. PR review opens Bitbucket Cloud pull requests too (read-only), and a comment can be handed straight to the agent on that branch. Local history is a tab now, and keeps the files an agent changed. Claude’s screen no longer breaks when you switch worktrees, and scrolling inside Claude no longer drags.

The browser tab

  • Web pages open in a tab. From the tab strip’s + menu, the globe button at the top, or “Open” in the Ports panel — and 3000 in the address bar is enough for localhost:3000. A page that asks for a new window gets a new tab in the same group, and reopening a layout comes back to the page you were on.
  • The developer tools dock inside the tab. A page’s right-click menu follows Chrome’s order — open a link in a new tab, copy its address, search for the selection, inspect.
  • App shortcuts work while you are on a page. Reload, back, forward, the address bar and the developer tools take Chrome’s keys.
  • The tab’s icon is the site’s own favicon.
  • When a menu or a notification overlaps. The page sits above everything the window draws, so a menu or dialog opened over it hides it for a moment, with the page’s title in its place. While a notification is up in the bottom-right corner, the page shortens to stop above it. Downloads do not work yet.

Local history

  • Opens as a tab. The toolbar button, the shortcut and the + menu all open a tab you can keep beside the editor to compare with. One file’s history is still a dialog, as before.
  • Files an agent changed are kept too. Only files saved in this window’s editor used to be kept, so some files were there and others were not. Now each time an agent finishes a turn, the earlier contents of the files that turn changed are kept — deleted files included.

My work

  • Boards are split by project. With more than one project on screen the board fell back to three columns — To do, In progress, Done — so “In review” and “In progress” landed in one. Now each project gets its own board, and a Jira project uses the columns configured for it. A card can only be moved within its own project’s board. The project name and the column names stay pinned at the top as you scroll.
  • The list groups by project too. Inside “Waiting on you” and “Yours”, each project gets a subheading.
  • Filters say what they hold. The project filter shows tickets and pull requests under their own headings, and the sprint filter puts the project in front of each name (SkillDB · Sprint 12). “The sprint running now” is now “Active sprint”.
  • Tables and checklists in a Jira description look like tables and checklists. A table used to come out one cell per line, and a checklist as run-together text with no boxes. Editing and saving keeps them as tables and checklists.
  • A pull request’s details go across to PR review with “View files”.
  • Bitbucket Cloud now lists other people’s pull requests too. Only the ones you wrote used to arrive. Open pull requests are read from the recently updated repositories you can write to.
  • The board no longer shifts when you switch worktrees. Coming back used to pass through the dashboard and the default columns before settling. It now comes back as you left it.

PR review

  • Bitbucket Cloud pull requests can be read. The diff of each file and the line comments already on it are shown. Send comments and approvals from Bitbucket for now.
  • Hand comments to the agent. When an agent is running in the worktree that has the pull request’s branch, each thread gets “Send to agent” and the header gets “All comments to the agent”. The file, line and comment are pasted as a quote and nothing is sent — you write what to do about it.
  • The file list can be resized and grouped into folders. The same folders / one-row-per-file choice is in agent changes, history and compare, and the choice is remembered.
  • The top-right buttons are tidied up. Back to the list is a left arrow, and unified / split uses the same buttons as every other diff.

History and worktrees

  • Tidy an agent’s commits. In history, pick a range of commits to squash, reword or drop. Commits that are already pushed ask first, and it will not run over a merge commit or in a worktree with uncommitted changes.
  • Finished worktrees are marked. Worktrees whose branch was merged or whose remote branch is gone are marked in the sidebar and can be cleaned up in one go. A worktree with uncommitted changes is not removed. A branch merged by squash is recognised only once its remote branch is deleted.
  • Discarding a file with brackets in its name no longer deletes other files. git read paths like pages/[id].tsx as patterns, so discarding that untracked file also deleted pages/d.tsx. Paths are now passed literally.
  • “Put aside” in the Git panel is now “Stashed”. It is git stash.

Terminal

  • Claude’s screen no longer breaks when you switch worktrees. While another worktree was showing, the terminal stopped taking output, and on return it redrew the saved output. That copy had its beginning cut off, so old fragments stayed at the top of Claude’s screen with blank rows under them. The terminal now keeps taking output while hidden, so there is nothing to redraw.
  • Scrolling inside Claude no longer drags. One trackpad swipe sent Claude about sixty scroll signals a second, and its redraws queued up behind each other. The signals are now batched.
  • Claude no longer flashes during long output. The one flash per terminal when returning to a worktree is fixed too.
  • A terminal that glitched once no longer stays blurry and slow. The GPU renderer is now held only by terminals in the visible worktree, and taken again when a terminal is shown.
  • Claude Code installed with npm is recognised as an agent. Installed with npm i -g on Homebrew’s Node, its tab did not recognise Claude and drew a terminal icon.
  • Switching projects no longer pushes Claude’s screen down or cuts it off. The shell prompt landing on top of the conversation after /exit is fixed too.

diff

  • Additions and deletions are a clear green and a clear red. They used to be light mixes of the theme’s colours, and in the default dark theme both came out a similar brown. Changed lines in the editor use the same colours.
  • Resizing the window no longer lets the old side of a split diff spill over the new side.

The window

  • The tab + menu is split into four groups. Git, Run and debug, Services, Work — fifteen panels used to sit under one heading.
  • Long paths wrap in dialogs. In the remove-worktree confirmation a long path pushed out past the dialog and cut off its buttons.

The editor

  • Markdown table alignment and table of contents. “Line up this table” in the context menu aligns columns counting Hangul as two columns wide, and “Insert or update the table of contents” writes or refreshes a contents list with the same anchors GitHub uses.

The debugger

  • lldb-dap is found even when it is not on PATH. The one inside Xcode and the one in Homebrew’s llvm were both reported as “not installed”. There was nothing to install.

The file tree

  • Worktree folders inside a project have their own icon. You can tell another checkout from this project’s files without reading the name.

1.1.2 2026-09-29

The divider in a side-by-side diff can now be dragged, and every panel that shows a diff has a zoom button. The rest are bug fixes. The most important: pressing “Stage hunk” right after switching files in the Git panel could stage the wrong lines. Two things 1.1.1 said it fixed but hadn’t — the last day of a sprint, and usage after a refresh — are now fixed properly.

Terminal

  • Switching projects no longer leaves an agent’s screen blank. When a terminal is shown again it clears the screen and redraws the output it saved. But it also cleared the screen when there was nothing to redraw — right after “Clear screen”, or just after a full-screen program exited. The process was still alive, but only the status line was left, and an agent waiting for input does not redraw by itself, so it stayed blank. Now the screen is cleared only when there is something to draw.
  • Hangul being typed shows in the right place. A syllable being composed sat 3px to the right and jumped left the moment it was finished — in Claude it looked like text leaning left, in a shell like text slowly drifting. The GPU renderer and the composition box placed characters by different rules; the box now uses the same rule. Windows drawing without a GPU never had the problem and are left as they were.

Git

  • “Stage hunk” pressed right after switching files no longer applies to another file. Until the new file’s diff arrived, the previous file’s hunks stayed on screen under the new file’s name. The button works by hunk number, so pressing it in that gap staged the new file by the old file’s numbers. Clicking a file and staging its first hunk straight away is common, so this was not rare. Now choosing another file empties the panel first and waits for the new diff.
  • Files created inside a new folder no longer show up as a nameless empty row. git reports a folder holding only new files as one line, like features/, and the changes tree drew it as a folder with one nameless file. The count said “1” however many files were inside, and you could neither open them nor stage just one. Now each file is listed on its own. Discarding only some of them no longer leaves an empty folder behind either. Another repository inside the worktree is still one row, but it now shows its name, like lib/.

diff

  • Drag the divider of a side-by-side diff. The two columns were always half and half, so in a diff with short lines on one side and long ones on the other you had to scroll sideways to see the code and back again. Where you put it stays when you open another file.
  • History, Review, Compare and Git all have a zoom button now. It does the same as “Show in a dialog” on the tab menu. It does not appear when there is no text to show, such as for a binary file.

The window

  • Scrollbars are down from 15px to 8px and match the window’s colours. Beside the narrow sidebar the grey scrollbar took up far too much room. It grows along with the text when you make the text larger.
  • The file tree shows placeholders instead of a blank while it is first read. The empty list used to look like a repository with no files. Grey rows the height of the real ones now appear first. If the read failed, dismissing the error no longer brings the grey rows back.

My work

  • The card no longer disappears on the last day of a sprint. 1.1.1 said the card stays on the last day, but the end time was counted in UTC, so a sprint ending on Friday morning was treated as over for all of Friday in Korea. It is now counted in your own time zone. And while the card hid, “Do this next” just below it kept treating the finished sprint as “This sprint” when ranking; it now uses the same rule.

Usage

  • A failed refresh no longer drops to “~0% left”. 1.1.1 made the chip say “Reading…” until the next one-minute check answered, but that check did not actually ask the server again — it returned the failure just stored. Now it really asks. Pressing again while it says “Reading…” no longer cancels the wait either.

The debugger

  • A debug start waiting on a cargo build can be stopped. When the terminal or rust-analyzer held the build lock, the panel sat on “Starting…” with no way out. There is now a stop button beside it, and pressing it stops rustc too. Changing folders or quitting the app also stops the build.

Local history

  • The history list is up to date after a restore. After restoring a file picked from the list and coming back, the version count and times were the old ones. The list is now read again every time you come back. The history of a file whose name ends in a space no longer goes missing from the list either.

1.1.1 2026-09-28

The debugger that arrived yesterday had nothing to offer a Rust project. This app is written in Rust, so the first people to find that out were the ones who wrote it — an empty panel saying “add a configuration to a folder named after another editor”. Two things were wrong at once, and both are fixed.

The debugger

  • Rust asks cargo what to run. Opening the panel runs cargo metadata --no-deps, which lists this workspace's bins and test binaries; pressing Debug runs cargo build|test --no-run --message-format=json, which says where it put the executable it has just written. The grounds on which 1.1.0 gave Rust nothing were “guessing at a path under target/ is how a debugger starts the wrong program”, and that is true — so this satisfies the objection rather than overruling it. Nothing is guessed at. Reading the path out of cargo was always the only way anything was going to find a name like target/debug/deps/dap-8f3c1a4e7b2d0c19. The build happens when somebody presses Debug rather than when the picker draws itself, and a compile that fails arrives as the sentence rustc wrote.
  • The configuration file is .codeme/launch.json. 1.1.0 said the answer was .vscode/launch.json. Reading that file is right — a repository that has already told one editor how to start its server should not have to tell this window again, and that is the same rule the formatter, the linter and the test runner are chosen by. Reading somebody else's file is the courtesy; requiring it was the mistake, because it came to asking somebody to make a folder named after another editor in order to configure this one. So the file the empty panel and the error name is inside the .codeme/ this window already keeps, and .vscode/launch.json is still read wherever there is one. Where the same name is in both, this window's file wins — so a repository moving its configurations across never sees one row twice.
  • C and C++ still have the configuration file and nothing else. A Makefile has no cargo to ask, and compile_commands.json says how a translation unit is compiled, not which of the binaries in the tree is the program. Go and Python are answered by the open file, Java and Rust by the project's own build, and those two are what is left.

Local history

  • The files that have history, in one place. Keeping the previous contents on every save has been here since 1.0, but the only way to see them was the editor with that file open, or the file tree — and nobody has eleven file names in mind the moment an agent has just rewritten eleven files. There is a button on the toolbar now, and it lists the files that have history as the folders they are in. Picking one is the versions, the diff and the restore, as before.
  • And the reason the store could not answer that question is fixed too. A folder in the store is named by a hash of the path — paths have slashes in them, and that choice is what stops the day somebody has both a file and a folder called a from costing one of them entirely — and a hash does not read backwards. So the path is now written down beside the copies. History kept before that is not in the list, and is not lost either: open the file and it is there as it always was, and the next save puts it in the list.

My work

  • A sprint nobody closed no longer holds the top of the dashboard. Jira keeps a sprint active until somebody closes it, and nobody closes it on the Friday. So a plan that had been over for six days was still “the cycle in progress”, and the place that says how long there is was saying “6 days past” — the one sentence that section must never say. A cycle whose end has gone past now stands down from it. The last day stays: that is the day the bar is read most. No row is hidden by this — they are in the queue, and the cycle is still one option in the filter over it.

Terminal

  • Claude Code installed natively is recognised as an agent too. A tab names what is running in front by its executable's file name, and Claude Code's install script names that file after its version, as in versions/2.1.283. So from the day it moved off Homebrew, the tab was running 2.1.283 rather than an agent — no icon, no work row, no “your turn”. A number inside a versions folder is now read as the name of the folder above it.

Usage

  • Usage just after a refresh no longer reads “~0% left”. Refreshing the Claude card drops the server figure it had, since the sign-in may have changed, and asks again — and when that one ask was slow or refused, the chip fell to the estimate counted on this Mac: a measurement of something else, shown as the answer to the click. Now the chip says “Reading…” until the server figure arrives, and uses whatever the next minute’s read brings back.

1.1.0 2026-09-27

There is one reason the number left 1.0 — the debugger. It was the empty line beside the language servers, and the largest thing this window could not do. Along the way the language servers learned four questions that leave the open file, a local history that remembers the thirty minutes between commits arrived, and so did git's ways of undoing a commit and of setting work aside. And two places that were quietly corrupting files that are not UTF-8 are fixed.

The debugger

  • Go, Python, C/C++, Rust — and Java — are debugged in this window. DAP is LSP's sibling — same author, same pipe, same Content-Length framing — so the transport is the one the language servers already use. What it does not inherit is the shape of the conversation. LSP is a set of questions independent of one another; DAP begins with an order: launch is sent and not waited on until the adapter says “now tell me your breakpoints”, then the breakpoints go, and only then does the answer to launch arrive. A client that waits for that answer first deadlocks — delve and debugpy are both that kind of adapter.
  • The adapters are only the ones already on PATH. dlv dap, the debugpy inside the project's own virtualenv, and lldb-dap, which comes with LLVM 17+ — already beside the clang that builds a C project, and what a Rust binary is debugged with too. Bundling nothing and installing nothing is the same rule the language servers were held to. There that rule brought seven languages at once; here it does not go as far, because most debug adapters ship as VS Code extensions, and a .vsix is a program on nobody's PATH.
  • What to run is answered by .vscode/launch.json. Not as a VS Code-compatible gesture but because it is the project's own file, which is the same rule that picks the formatter, the linter and the test runner. JSONC — comments and a trailing comma — is read too: VS Code's own default template is mostly comments, so a strict parser fails on the commonest case. With no file the open one answers, but only for Go and Python: what lldb-dap runs is a binary that has to be built first, and guessing at a path under target/ is how a debugger starts the wrong program.
  • Java's debugger lives inside the language server. java-debug is not a program but an Eclipse JDT plugin, so it is reached by carrying one jar into jdtls and then asking the language server to “open a debug session and tell me the port”. This window already runs jdtls. That makes “what should I run” the best answer of the six languages — with no launch.json and no guessing, the main class comes out of the Maven or Gradle build the language server has already read, and the classpath (a hundred jars in a real project) arrives the same way. The jar is something a person fetches once from Maven Central, and the places looked in are ~/.m2 and mason — another editor's install folder is deliberately left alone.
  • TypeScript and Node are not supported. And the window says so. js-debug exists only inside a .vsix, so fetching it would make it this app's first downloaded binary — version pinning, signature checking and the whole update story would become ours. Rather than draw a button that does nothing, it is written down that this does not work.
  • A breakpoint says more than a line now — conditions, hit counts and logpoints. A breakpoint that is only a line is ninety times out of a hundred; the other ten are the ones that burn an afternoon: the loop that is wrong only on the five hundredth pass, the function called from forty places where one is the problem. By hand that means stopping four hundred and ninety-nine times, so what people actually do is edit the program — adding and removing a print in the file the debugger is already looking at. All three are evaluated by the debugger: i > 500 is Python in a Python file and Go in a Go file, and if this window checked the syntax it would be a second and worse compiler.
  • The gutter tells them apart by shape, not colour — circle, diamond, arrow. Colour alone cannot be read by somebody who is colour-blind and is erased by the next theme, and what separates them here is not decoration: a logpoint never stops and a conditional usually does not, so somebody reading it wrong is waiting for a halt that is not coming.
  • Exception breakpoints, and what they turned up. setExceptionBreakpoints was being sent an empty filter list, and an empty list is not “no opinion” — it is off. debugpy arrives with uncaught already on, so a program dying on an uncaught exception ran all the way through under the debugger and printed its traceback: the same result as running it without one. What the adapter arrives with is now sent back as it came, and the list and its wording are the adapter's. It is remembered per adapter, so from the second run they can be ticked before starting.
  • Breakpoints outlive the window. They were in memory only, so closing the app lost all of them — the kind of thing you notice on the second run rather than the first. They are kept beside the layout and keyed the same way. They are not kept inside the folder: a breakpoint is where you are looking, not something to commit. When the file makes no sense — missing, half-written by a crash, copied from another machine — all three get the same answer: start with no breakpoints.
  • The debug panel opens with ⌘⇧D, and containers moved to Ctrl⌥D. The container list had borrowed that key, and the grounds for borrowing it were written in the code — in VS Code it is Run and Debug, and “this app does not have that”. It does now. And the rule that a window shortcut must carry a modifier gained a function-key exception: that rule is about typing (d gets pressed in the middle of a word) and F5 does not make a letter — which is exactly why two products spend the function row on the debugger.
  • The file you stopped in no longer covers the debugger. The debug panel is a tab in the same split tree as everything else, so stopping and opening that file into the same group hid the stack, the variables and the watches completely. Pressing the tab to get back made the stopped line disappear instead — two halves of one answer, taking turns. With only one group it does nothing: splitting somebody's window because their program stopped is worse than what it was fixing.

Language servers

  • The language server does the highlighting now, not a regular expression. The editor's tokenizer paints Board the same whether it is a struct, a variable or a macro — it is reading letters. The server has already worked that out, and in Rust that is exactly half of what a reader wants to tell apart. Legends differ from server to server, so the core maps the server's indices onto this window's list, and a kind this window has no colour for is dropped rather than painted as the nearest thing — that would be a lie about the code, and the tokenizer's guess is better than a lie. With no server, or one still indexing, an already-painted file is left as it is.
  • Four questions that leave the open file. Go to symbol — finding the Board somewhere in a hundred thousand lines by text gives you the two hundred lines that mention it, while the server's index gives you the one struct (a repository holding both Rust and Python has two indices, so every live server is asked). Go to implementation — going to the definition from a trait method lands on the trait, when what you wanted was the four types that implement it. Go to type definition — in let rows = read()?; what you wanted was Vec<Row>, not read. Show callers — one level only: “what reaches this, and is it what I think” is answered at the first level nine times in ten.

Local history

  • The thirty minutes between commits are remembered. git answers “what was this file at that commit”, and has nothing to say about the thirty minutes between two of them — which is the span this window deals in: an agent rewrites eleven files, the formatter runs on every save, a rename touches forty. Nowhere in the window answered “what was this function twenty minutes ago”. A copy of what was there is kept just before each save, and the diff uses your own git (git diff --no-index). Files over 1MB and saves that changed nothing are not kept, and at fifty per file or 64MB in all the oldest go first.
  • It opens from the tree's right-click too. With the editor header as the only door, seeing what changed means opening the file first — and the moment this is wanted is the opposite: the agent has changed eleven files and the interesting one is the one you have not opened. It sits right beside “Show changes”, because it is the same question asked of a different span (that one since the last commit, this one over the last half hour) and the two read better together.
  • A restore is refused while there are unsaved edits. What is kept is what was on disk, and if the buffer has run ahead of that, its text is nowhere. After a restore every editor re-reads from disk — so what you were working on would be absent from the disk, from the store and from the buffer alike. That is the exact opposite of why this feature exists. One save puts the previous contents into the store, so saving and then restoring loses nothing.

git

  • Two ways to undo a commit — revert and reset. The history panel had every commit in it and no way to undo one of them. The difference between the two is the whole of the menu: revert adds to history and reset rewrites it. That is why the former is the one that is safe on a branch somebody has already pulled, and why it stands first. The three reset rows each say what they take with them — leave the changes staged, leave them as edits, or take them. The last is the only action in this panel that gives nothing back, so it asks first, and that dialog points at revert by name again.
  • Setting work aside — a third answer to discarding it. The dialog said “this worktree has 3 uncommitted changes. They will all be lost”, and put “Cancel” and “Discard and delete” underneath it. It described the loss down to the count, and then offered one button that takes it. The answer people want — keep the work and clear the checkout — was nowhere in the window. Taking untracked files along is the default here: leaving them makes git worktree remove refuse, so half the work moves and the second step fails, scattering it across two places. They come back from the commit panel — a stash you cannot see is a stash you have lost — and the ones made in a terminal appear there too.
  • Resolving a conflict corrupted files that are not UTF-8, in full. The merge panel rewrites the whole file, so every byte it could not decode was destroyed on the spot — in the worktree, in the file about to be committed, without a word. Put one cp949 file into conflict and choose “ours” and an 11-byte file comes out at 19 bytes with every Korean character a question mark. Three paths read it and all three were decoding. All three had to be fixed: fixing only the file keeps the bytes but loses the ancestor column of the three-way view, and that column is the whole reason a three-way editor beats a two-way one.
  • Staging a hunk did the same thing to the index. A patch is not text. Read a diff as a string and every byte that will not decode becomes a replacement character, which goes back out as three bytes. Stage one cp949 .properties by hunk and the index gets the broken bytes while the worktree keeps the original — so the file looks modified forever and the commit carries the broken side. Three more on the same path: a file with no newline on its last line went out a byte longer, staging a hunk of a new untracked file quietly did nothing at all, and a diff that cannot be cut into hunks (binary, mode-only) was answered as a success.
  • A filename with a quote in it was not a path, and renamed files vanished from the review list. core.quotePath=false covers only half of it — regardless of that setting, ", \ and newlines always come out wrapped in quotes, and such names are legal on every system this window runs on. Taken as they arrive they are not paths: every button on the q"uote.txt row pointed at a file that does not exist, and in a commit diff it was quieter still — a section whose name could not be read is thrown away, so the file simply dropped out of the list. Renames were the same kind of thing. --numstat writes a moved file as src/{a => b}/f.rs, which is not a path, so it was drawn as a deleted file under a name that never existed, while the file that went and the file that arrived were both missing from the list.
  • Commit, pull, abort and stash-restore were not telling the rest of the window. The history list, the editor gutter, the change marks in the file tree and the counts in the sidebar each draw their own copy. The one way of telling them was being sent from six places and left out of four — and the four were all things that move the worktree. The “Commit” button told nobody while “Commit and push” told everyone: a history panel open beside it went on showing the state before the commit you had just made.

Notifications and My work

  • A gate going red reaches you in another app. What a supervisor actually wants the moment an agent stops is the one question “is it green”, and the answer reached a single card inside the window. That window spends the whole time four agents are working behind another app. Half of this is what it does not say — green is not news (a machine interrupting you to report that it did not interrupt you), and a cancelled gate and a gate you ran by pressing the button are things that person is already watching. The sentence starts with the worktree's name, and the line under it is the command of the step that decided and how many failed — cargo test --workspace is something you can go and run again, and “Tests” is not.
  • A pull request of yours going red, or getting an answer, reaches you too. What notifications answered until now was one side of the queue — somebody waiting on me. Whether my own pull request had gone red, whether changes had been requested, whether it was approved and could now be merged, could be learned only by opening the panel, and the panel polls only while its tab is on screen. For somebody running four agents this side happens more often — four branches means four sets of checks. It watches edges, not state: a branch that has been red since yesterday is not announced again every five minutes, two branches already red when the app starts are both silent, and silence is not a change of mind — a value the payload did not mention overwriting a remembered red makes the next poll read it as a new one.
  • The ticket → worktree → pull request loop closes on its last square. A worktree is made from a ticket and its branch name comes from there too, but the description of the pull request opened on that branch was empty. Nothing needed writing down — the branch is the link: run the rule that made the name from the ticket backwards over the board and it is found again. Closes #42 is used only in the one case where it actually works — an issue on a git forge in the same repository. Written on a pull request in another repository, or against a Jira key, it reads as a promise and keeps nothing. And once the pull request is out, moving the ticket is only offered: which column an open request belongs in is a decision the team wrote into its workflow, and picking one would be the window inventing a process.
  • A 403 said “this is not a token problem” and threw the reason away. To somebody who does not think they are signed in, that sentence reads as a contradiction and leaves nothing to be done about it. Which 403 it is lives only in the body — the token not carrying that scope, SAML being on for the organisation, a burst limit. Every other status code was reading the body; only 403 discarded it. What it carries now is only what the body stated: the body of a 403 is often an HTML page from a proxy in front of the forge, and <!DOCTYPE html> under a 170px column is worse than nothing at all.
  • One forge refusing put the same row up three times. The banner is one row per forge, and what was being handed to it was one row per query. GitHub asks three and Forgejo asks three, so when the forge rather than the token refuses, the identical row stood three times, each with its own two buttons. And because that 403 is telling the truth, signing in does not make it go away — three rows come back on every poll.
  • One poll without a network left the queue empty. There is a rule that when every source asked comes back with nothing but excuses, the remembered rows are served with an age on them — but the notification thread uses the same cache from outside that rule. So one poll landing in a moment with no network puts an empty board into the cache, and the next person to open the panel gets it: no rows, four excuses, no remembered rows and no age. Nor is it brief — the cache lasts two minutes and the panel does not ask again for five.

And the rest

  • The PDF that was an empty panel on Linux is drawn by the window itself. WebKitGTK has no built-in PDF viewer, and <object type="application/pdf"> draws nothing — no error and no fallback. An empty panel appears where the document should be and the window says nothing about it. The decision is made on capability rather than on the platform's name: navigator.pdfViewerEnabled is the standard property that answers exactly this question, so on the day a webview gains a viewer it stops using the bundled one by itself. The viewer is a separate chunk that arrives only when a PDF is opened (129KB gzipped), and a page drops its bitmap once it is far from view — drawing all of a 500-page document turns half a gigabyte into bitmaps for the sake of the two pages you are looking at.
  • Duplicating a folder turned symbolic links into their contents. The one line that asks whether something is a directory follows the link. Duplicate a folder holding a pnpm node_modules — almost entirely links into the shared store — and the whole store is copied, and where a link points outside the workspace you get a copy of somewhere this module carefully leaves alone everywhere else. A link pointing at an ancestor has no end: the kernel stops at forty levels, but not before the attempt has left 122 directories behind and failed. And a broken link read as “that name is free”, so the copy was written through it — asking for notes copy.md produced elsewhere.txt.
  • Two turns in the same second counted usage twice. A resumed session writes the earlier turns out again into a new file, so every turn from before the resume is on disk twice — but the side that removes duplicates compares only adjacent pairs, and the sort was ordering by a different key. With one turn a second the two copies really do end up side by side, which made it look like it worked. With two a second it does not — a second holding 300 tokens comes out as 600, and that second goes in twice to today's total, to the open five-hour block, to the weekly sum and to the split per worktree. A turn moving quickly through tools makes two responses in a second all day long. The story panel had one of the same bug, and drew the whole of such a second twice.
  • A value going into a sentence's blank was read as a substitution pattern. JavaScript's string replace turns $& and $' inside the replacement into the text around the match. So a branch called fix-$&, or a search pattern somebody typed, split the sentence and landed it in the middle of its own value — git allows $ in a branch name, and the search box is somewhere a person can type anything. Every place that takes what a person typed, a path, a branch, a command from a config file or something another program said has been moved over.
  • The sign-in limit was counting a window that does not exist. It called itself “ten an hour” and counted over an hour, while the sweep at the top of the same function had just deleted every row older than ten minutes — so by counting time there is nothing older than ten minutes left to count. The real limit was ten per ten minutes, and the sentence describing it was out by a factor of six. It counts the window that exists, and the name now says what is true: how many sign-ins one address can have open at once.

1.0.21 2026-09-24

The queue this window led with last time had nothing to press — one shortcut was the only way in, and on a Mac that shortcut logged you out. That is where this round started, and from there the window was read file by file, the hardest things to undo first. And the heights and corners of its controls, which had drifted apart, are now two numbers and one ladder.

The queue

  • There is a button for the queue now — on the start tab. It led the last release, and the only place in the whole window that opened it was a shortcut. No button, no menu item, no command palette entry: only somebody who had read the release notes could press it. The action row on the start tab is the one place in this window where each action prints its own shortcut beside it, so the button and the key are learned together.
  • That shortcut logged the Mac out. ⌥⇧⌘Q is the chord macOS spends system-wide on Log Out immediately, and it is the one that does not ask. The window never saw the key, so the symptom did not read as “the shortcut does not work” — it read as “this app restarts my computer”. The letter stayed and the row moved: Ctrl⌥Q. Binding the same chord by hand in settings is refused now, and the refusal says what happens instead rather than why it cannot.
  • “Delete them anyway” deleted worktrees nobody had named. Keeping one way takes the worktrees and branches back from the finished others, and that list was taken before the ways still running were cancelled. So a way mid-turn was not among the first press's targets, and was not in the refusal a person reads either — and by the second press it had stopped, which made it one. An hour of uncommitted work could go that way. The second press now reaches only the trees the first one named.
  • The checks judged by the plan of the project next door. The gate strip reads the plan once, when it mounts, and changing worktrees does not mount it again. Moving from a project that declares no checks to one that does took the strip, the verdict and the “check” button away altogether. It follows the worktree that is open now.
  • One byte of non-UTF-8 from a linter and the checks never finished. The side reading the output did not drop a few lines there — it stopped reading. The child goes on writing, the pipe fills, the child blocks, and the gate never comes back for as long as the window lives: no verdict, no next item, and nothing to say why. One linter printing a file name the way the locale spells it is enough.

What was nearly lost

  • One checkbox erased every comment in the settings file. The parser takes comments on purpose — people leave notes in their settings. The writing side, though, printed the parsed values back whole. So changing one value in the settings menu erased the comments and the blank lines and turned the key order alphabetical: a file somebody had grouped and annotated came back as a flat list because of one click somewhere else entirely. The value is spliced into the file's own text now, and nothing outside the place that changed is touched.
  • One unreadable layout took every saved layout with it. The rule was “a tree this build can no longer read is dropped one entry at a time”, and the loader was all-or-nothing. A failure on the first entry emptied the list, and the next layout saved was written over that empty list — the rest gone for good. Entries are read one at a time now, and only the ones that cannot be read are dropped.
  • “Stage” and “discard” on a newly created file had never once worked. An untracked file has no diff from git, so the window makes one up — and that fragment had no file name on it. git does not take a patch without a header, and both those buttons and the per-line checkboxes go down that road. The mode line went on too: stage a script without its executable bit and the undo warns.
  • A conflicted file was numbered from line zero. The diff for an unmerged path is the combined form, one column per parent, so its header is different. Failing to read it was swallowed quietly and read as zero, and staging from there sent an empty range. A header that cannot be read is not a hunk any more — a conflict is not staged, it is resolved, and that door is already in the panel.
  • Closing a terminal signalled somebody else's process group. A group whose pid has been reused and now belongs to somebody else is not to be touched again — that is the rule, and the code read that case as “still alive”. After spending the full two seconds of grace, the last loop, which runs unconditionally, kills that group. It is the only mistake this window can make that lands outside it.

Your work, and signing in

  • A Jira signed in to through the browser left the board empty forever. The address a request goes to and the address a link points at are not the same, and they part company in exactly one case: a cloud Jira. The board's only Jira query was going to the address meant for links, where a perfectly good token is refused. What the screen said was “the token was rejected”.
  • One unreachable forge left the others' boards on last night's answer. Failures pile up per query, and that count was being held against the number of forges. With GitHub alone down, two sources produce three failures, which reads as “nothing was learned” — and the other forge, which had honestly answered that it was empty, keeps yesterday instead of today.
  • Starting with no network turned everything that had piled up into notifications. “Already seen” is per source; “seeded” was one flag for the whole window. So the first poll marked even the sources that never answered as seen, and a window started offline seeds every one of them empty — the first poll that gets through reads every review request already standing as new. A failed poll seeds nothing now. An empty set is a claim that there is nothing here, and a failure has never made that claim.
  • On a machine signed in to a company GitHub, a github.com pull request went to the company address. The side that reads the remote looked at the literal github.com before the configured host. In the default setup both answer the same, so that line only ever fired where it was wrong.
  • While the sign-in window was open, any program could kill that thread. The two characters after a % in the address that comes back were being sliced out of a string — and a byte no browser would send has become a three-byte replacement character by then, so a slice landing mid-character is a panic rather than an error. In front of the very check this socket exists to make. The slice is over bytes now, and a % that is not followed by characters is passed through as it is.
  • A refusal the provider had already named was waited out for ten minutes. A sentence for a person to read beats an error code — that is deliberate — but an empty sentence beat it too. So “the user refused” came back erased, and the dialog spent the whole deadline as though nothing had answered.
  • A paragraph of D-Bus error sat in the sign-in row of “your work”. The reason column is the middle of a three-column row, so it is about 170 pixels, and what goes in it is whatever the platform credential store said — a thing with no upper bound on its length. An English paragraph sat down in the middle of a Korean sentence, and two of the four forges stood three times the height of the others. The words stay — that is the part a person searches the web with, and no dictionary can hold it. It has only stopped being inside the sentence: it has a line of its own with an ellipsis, and all of it is one hover away. Row height 110px → 60px.
  • The “git was not found” banner never appeared on a Mac. A Mac without the Command Line Tools still has git on the PATH — Apple's stub, which starts fine, prints nothing, and exits non-zero. The exit code was not being read, so that empty string was remembered as the version for the life of the process. Instead of the banner, what a person saw was worktrees, history and commits failing one at a time in git's own words — on a machine the window had just called fine.

Where “pick one” stood with nothing to pick

  • The compare panel draws “there is nothing different” as an answer. That is the state this tab opens into most often — two branches just cut, two agents that have not committed yet — and the screen was one grey sentence in the top left of an empty column, beside a pane saying “pick a file” where there was no file to pick. The right-hand side now carries a green check and says which two worktrees the answer is about, and it offers one place to go from there: if A…B is empty the next question is always whether A did something, so the button compares the other way round.
  • The same place turned up three more times. A commit that changed no files (history), a worktree with a baseline set and nothing written yet (review — the state anybody watching an agent sees most), and a database with no tables. An empty list is not something missing, it is the answer; and an answer drawn as an instruction is one nobody can follow.

How the window looks

  • Five names that had never been declared were being read by twenty-eight lines. Point at a name CSS does not have and there is no fallback — the declaration itself becomes invalid, and the browser says nothing about it. So the window looked almost right: a background that quietly goes transparent reads as flat design, and text that should be dim and stays at full brightness reads as a decision. What was really there was a recall palette with no paper under it, the panel below showing through; a queue input box printing what you typed in the grey kept for labels; and a device code, printed large to be copied out by eye, drawn in a font where l and 1 are the same stroke.
  • Controls standing in one row came in nine heights. Asked Chromium for the real pixels, they ran from 20.5 to 32, and an input box stood 4px taller than the button right beside it. Even the rule whose own comment said “these stand in the same row, so they stand at the same height” was out of line with that row. There are two now — 28, and 24 for the rows that are deliberately tight. The corners went with them: fourteen values became six rungs chosen by the size of the thing, and there is no raw-pixel corner left in this stylesheet.
  • Fifteen small tinted boxes had no height. With only colour and padding, a box takes the line box of wherever it was used as its height — so the same chip stood at a different key in every panel (nine of them, measured) and sat off-centre in any row with a glyph in it. The text looking stuck to the top went with it: a line box is as tall as the font's ascent and descent, and those two are not symmetrical about the letters — TAG and main have nothing below the baseline. The amount differs per font, so rather than writing a number down the engine trims it from the real metrics.
  • Three spinners did not turn, and one was not drawn at all. The rotation was written wherever a spinner is seen rather than on the glyph, so anywhere that was not remembered drew a stopped arc — which reads as a broken glyph, not as progress. The gate's running line was worse than that: an empty element whose class no rule in this stylesheet had ever heard of, so nothing was drawn. The one line in the window that says “wait” showed nothing at all while you waited.
  • Three lists belonged to the engine rather than to the window. The two worktrees in compare and the agent and the mode in the queue were native <select>s. A closed box takes styling and an open list does not, so in a dark window that one thing opens bright, with a different typeface, a different row height and the engine's own arrow.
  • Four button labels narrated rather than named. All four are ordinary imperatives in English; only in Korean did they become sentences, and three of them sat in one dialog — a feature written in one sitting acquires a voice of its own, and noticing it means opening the other hundred-odd labels alongside it. They are names now: “stop reading it”, “keep only this one”, “leave them”, “delete them anyway”.
  • Forty rules that drew nothing. Every one of them is a place where a rename moved the markup and left the rule behind. Dead CSS is not harmless — it reads as alive in review, and it gets fixed. One rule that both the corner cleanup and the height cleanup just above took care over had not matched an element since that box was renamed.

And the rest

  • The file palette started a git process for every keystroke. Each search rebuilt the list of candidates, and that read the index and walked the working tree every time — to be handed the same answer. In a repository of 20,000 files one keystroke cost 26.6ms, three quarters of it that one call. The list is shared for a second now: longer than the gap between keystrokes, shorter than the gap between glances. 7.8ms — 3.4×.
  • A relative path in .env pointed somewhere else entirely. Something like file:./dev.db is written relative to the project, and it was being resolved from wherever the app was launched. sqlite makes a new empty database there, and the panel reports that it has no tables. The same place was also stripping every leading slash off sqlite:////var/lib/app.db, turning an absolute path into a relative one.
  • One unclaimed traceback line took the line numbers off every failure below it. Failed cases and printed lines are paired in order, and when the file names did not match, that line was left at the head of the list — so the next failure, and the one after that, were compared against the same line and all came out wrong. One failure raised inside a helper or a fixture near the top, and nothing below it in the panel can go to a line.
  • Four on the site and the server. UPDATE_DISABLED=false was turning updates off — it was read by whether it was set rather than by what it said, and after that every app gets a 204, the same answer as “you are already up to date”. A blank line with one space in it was not counted as blank, so a single comment could push every other one off the screen; addresses run together with commas counted as one link, so “two links at most” never once caught the shape a link farm actually uses; and a row that said it lived ten minutes was living a day.

1.0.20 2026-09-23

Two of the jobs the person supervising was doing move into the window. When an agent hands the turn back, the checks the project declares for itself are run over that worktree for you; and a queue that takes work while you are away gives each item its own branch, its own worktree and its own agent. And eleven fixes.

Checks

  • When an agent stops, the checks run right there. The question the person supervising has at that moment is “does it pass”, and the answer meant going out to a terminal, remembering what this project runs, running it, and reading the end of it — per worktree, per turn. The plan comes from evidence only: the typecheck and lint scripts package.json declares, and the test suites already found, and only where the tool is really there. Cheapest first — four minutes of a suite on a tree that does not typecheck knows nothing tsc did not say in four seconds — it stops at the first failure, and a step that never ran stays “skipped”. So that nothing reports a green it did not look at.
  • The verdict stands in the corner of the card and above the review panel. A green or a red and the name of the step that decided it go on the card (the tooltip carries the command it actually ran), and the one-line strip above the review panel opens onto the failed step, the failed tests and the tail of the output. Pressing “reviewed” forgets the verdict along with it — a green for a tree whose baseline has moved is a mark about work already signed off. It is off by default: running a test suite on somebody's machine without a click is a decision the owner of that battery makes. The “check” button runs the same plan there and then.

Handing work over

  • Ctrl⌥Q — put work in, and each item gets its own branch, worktree and agent. Starting one has been handwork: make the worktree, open a terminal, type the agent's name, paste the prompt. Five tickets is that dance five times, and it can only be danced at the keyboard. What you read in the morning is a list of greens, reds and “it asked something”. Work that went wrong is not quietly retried — what is known goes on the row and the queue moves on. Unattended work that retries by itself is work nobody can account for in the morning.
  • Each item chooses between “run once and finish” and “leave it open and watch”. An interactive agent has no moment that means “done”, so the end has to be inferred from silence. Agents have a non-interactive mode of their own (claude -p, codex exec), and there finishing the work and the process exiting are the same event — there is nothing to infer. What that costs is a conversation to step into and carry on. Which one is right differs per item, so it is a choice made there rather than a setting.
  • One prompt thrown down several ways, and only the winning way is kept. Two agents given the same instruction do not do the same thing, so the question actually worth asking is which answer is better. Give a number of ways and the whole round is laid out at once; the comparison is drawn by the compare panel that was already here. Pressing “go with this one” leaves that way alone and takes the worktrees and branches back from the finished others — a way still running is not a loser, it is an agent mid-turn. A tree with uncommitted changes is left where it is on the first request, with the paths and the reason handed back; the second button is the person's answer.
  • The example in the arguments box differs by agent. A flag borrowed from one agent is a command that fails on another — -p over there is not --print but --profile. Only the chosen agent's example is shown, and an agent we do not know leaves the line empty.

Terminal

  • An agent's /clear left the screen black. What you are looking at after a clear is the screen the agent repainted, and the window was running one more erase over the top of it — an erase that keeps only the row the cursor is on, so what is left is one line of the input box and everything just drawn above it is gone. The only thing here that wants erasing is the conversation that has scrolled out of sight.
  • A composing Hangul syllable shifted a few pixels the moment it was committed. Hangul is in none of the monospace families on the list, so it falls through to the system fallback — and the syllable being composed and the one already committed were each choosing that fallback separately. A machine with more than one Hangul face can answer those two lookups differently.

My work

  • An expired token brought the Keychain dialog back every minute. A blob that could not be read had a backoff; only an expired one had none. A token going stale while the app runs is worth one more ask, but that entry goes on saying the same thing until the CLI logs in again — so “one more” never ended, and a dialog came up on every turn of the meter, once a minute.
  • The order of the conversations you can reopen, and the “N hours ago” on them, were wrong. One more place was reading a time with an offset on it as though it were UTC. The same instant becomes a different number depending on the offset, and that number is what this list is sorted by — a conversation whose last word was a week ago sits second in the list.

And the rest

  • The commit graph stayed as it was after a fetch from origin. Every git panel listens for the signal that the repository has moved; history alone did not, so the commits that had just come down were not in it, and nothing on screen said the list was stale.
  • A container publishing a port range dropped out of the database list altogether. docker draws a range as 8000-8002→8000-8002/tcp, and giving up on that one line — the one that is not a number — took the container itself out of the list. One compose service that opens a debug port range alongside, and its database is simply not there.
  • A failing test line had no “open it”. A stack frame with no place written on it — (Unknown Source), the point a lambda is called from — made the search give up wholesale, without so much as looking at the real frame below it. On exactly the failures that are hardest to read.
  • The class name arrived where the test name belongs. The report was searched for name as a substring, and that is also the tail of classname. In a report from a tool that writes the class first, twenty cases in one file all become one same name, and “run only this one” aims at the wrong thing.
  • Pressing + on a repository row opened that row's overflow menu. The layer that appears and disappears on hover takes up no width and sat in the same place, so what you saw was the + and what took the click was the menu above it. One of the same family — a hidden layer taking clicks while invisible — is blocked along with it.
  • Dragging one row while a worktree was briefly gone erased that worktree's place. A path that has stopped existing is ignored rather than removed — that is the rule, and only the reading side was keeping it. A worktree removed and made again under the same name lost the place it had been carefully given and went to the bottom.
  • A tab was erased from what you sent, running two words together. The range that strips control characters ended at the tab. A line copied from a spreadsheet or from code arrives as one lump with every gap gone, and the length check passes just the same.

1.0.19 2026-09-22

Four ways the window died or stalled, and three places doing the same work more than once. No new features: this is the round where what was already here does what it said it would.

Where the window died or stalled

  • One number from a language server took the whole window down. An LSP frame carries the length of its body, and that many bytes are set aside before it is read. The number was believed as it arrived — a frame claiming a terabyte was a single request for a terabyte, and the end of that is a crash.
  • A large file an agent wrote brought the review panel down. A newly created file has no other side to compare against, so all of it is drawn — and nothing bounded that. One 120MB generated file took the window with it on its way to saying “2,419,791 lines added”.
  • A long glob in search's include or exclude box stalled the window. The search box itself had every limit; the two beside it had none. Each * is a fresh choice about how much to swallow, and at twenty characters the combinations pass what anybody will wait for.
  • A symlink inside a worktree was followed out of it. The rule was always “resolve, then check”, so a link pointing outside should be refused exactly as ../../etc/passwd is. It was being kept only for links whose target already existed.

Speed

  • One refresh walked the worktree four times. The totals in the header and the file list below look like different questions and are the same git status. Nowhere in the window asks for one without the other, and they were each running their own.
  • One git process per file an agent wrote. Two numbers — lines added, lines removed — were being taken out of a fully parsed diff, and an untracked file spawned one more process before that.
  • Search's file gate stopped being a gate when the comments were Korean. Before walking a file line by line it is scanned once for “is it even in here” — and that scan waved Korean through. The step that exists to save the rest saved nothing.

My work

  • A change made in the settings menu never reached the board. The panel's own “not using this one” always worked; the same change made through the settings menu did nothing at all, because the two-minute cache answered ahead of it.
  • The branch name suggested for a ticket was one git refused. The place that tidies those names promised to leave something git check-ref-format accepts. Asked directly, git refused seven shapes of it.
  • A worktree deleted and made again was measured from the old review point. A worktree's path follows its branch name, so making one again for the same branch lands it in the same place — where the previous baseline was still sitting, pointing “reviewed” at the wrong moment.
  • A review point was being marked in a folder that is not a repository. Open a folder with no git in it, start an agent, and not a git repository arrived as a red banner — a failure report for something nobody asked for, about a folder that had opened perfectly well.

Preview

  • A page in a subfolder got neither its styles nor its scripts. The address handed to the frame escaped the path separators too, so the whole path arrived as one segment. The page still opened — but the browser then resolved shared/styles.css against the root and the folder was gone. A page sitting at the root happened to be right, which is why this stayed hidden.

And the rest

  • The copy button did nothing. Both on the notice card and in the terminal menu. Where the WebView has no clipboard the press became neither a success nor a failure but silence — nothing copied, nothing said, so the button gets pressed again by somebody who cannot tell it is broken.
  • Usage read a timestamp wrongly and put the tokens in the wrong window. A time carrying a zone offset was being read as UTC.
  • A browser sign-in checked things in the wrong order when it came back refused. The state check stood in front of the code and not in front of the refusal.
  • “Not a repository” stood there every time a folder of repositories was opened. The rows below already said it, and the line invented a fault where there is none.

1.0.18 2026-09-21

Read a pull request you were asked to review here, answer on the line, and send it. Search the commits in the history. And the terminal breaking up along the bottom after hours of use — which turned out to be caused by the code 1.0.9 added to fix the same symptom.

A forge you had signed into asking you to sign in again is this version too. The token was there and had merely expired, and the renewal that brings one back was being skipped in two places.

Review

  • Pull requests you were asked to review, in the app. Read what changed, comment on the line itself, and send it with an approval or a request for changes. What this panel is worth is the trip to the browser it saves. Drafts survive a tab change — one of ten things fixed alongside it, and the one that lost typed comments.

My work

  • A forge you had signed into answering “the token was refused — sign in again”. Three forges refusing at once points here rather than at any server. The token was stored and had only expired, and the renewal that revives one was skipped in two places: a two-minute cache answered ahead of the request that was allowed to renew, and coming back to the window counted as a timer firing. Coming back to a window is a person.
  • Two things the account row at the bottom was saying that were not true. It read “signed in” for a forge that was refusing the token — the credential store holding one and the forge accepting it are different facts — and it counted forges turned off with “not using this one”. The question that row answers is “what is being read right now”. A refused forge now dims its mark and offers “sign in again” in the menu.
  • The row limit is each forge's own now. One number was going out as four different parameters, and their ceilings differ — raising it had Bitbucket answering 400. And a page that came back full says so. A list cut at its limit reads as the whole list, and a project whose tickets all fell past the cut cannot even be picked in the filter, which makes it look like a project that does not exist.
  • Jira signs in with a token. The browser button is gone — our Atlassian app is still in development, so that button opened a browser only to show a refusal. The token box beside it works as it did. And when a browser sign-in does finish, the window comes to the front by itself.
  • The dashboard says what the plan is and what is stuck. What you meant to do today, and what has stopped moving, without opening Jira for either. The ticket detail was rebuilt to read like an issue tracker's own detail screen.
  • A board's columns are read from that project's board. “In review” was folding into “In progress”: column names differ from project to project, and reading one project's board with another's names piles the tickets of a column that does not exist into the one next to it.

History

  • Search the commits. Typing in the box does not filter the rows on screen — it reads the whole history again, because what is on screen is the newest few hundred commits and the one you are looking for is usually older than that. A row comes back if any of the sha, the author, the subject or a ref pointing at it matches. Ctrl/Cmd+F opens it, Esc clears it.

Terminal

  • Characters breaking up along the bottom after hours of use. It was our own code, and it was the code 1.0.9 added to fix the same symptom. Back then the terminal addon could not manage its glyph pages, so we bounded them for it; the addon now merges four pages into one when it reaches its limit — and a merge fires the same signal we were counting. So we were throwing the whole glyph cache away every ten seconds, and the line that pays for that first is the one redrawn most often: the bottom line of a full-screen program.

Editor

  • Error: Model not found when holding Cmd over an import. Cmd+click was fine — it opens a tab — but holding the key and only hovering makes Monaco draw a preview of the definition, and to do that it looks for that file's model and threw when there was none. If the file happened to be open already it worked quietly, which is why it worked about as often as it failed. The underline splitting into @one, ui, field is fixed with it.

Worktrees and tabs

  • The rows under a session say what is running. node is the name of a runtime, not the name of a thing. A row now reads pnpm dev — what was actually started — with :5173 at the right where it is serving one. The tab says node:5173 too, and so does the row in the ports panel.
  • What the agent is doing is one row. That space used to hold cargo, then head, then ugrep — the stages of one pipeline, changing every time the list was read — and before them the six MCP servers the agent starts for itself. One row now, named the way a person would name the command: by its first stage.
  • The amber ring around a waiting worktree is gone. The open worktree is drawn with an edge too, so the moment an agent in another checkout asked something there were two ringed cards and “which one am I in” stopped having a glanceable answer. The edge belongs to selection — “this one needs you” is already said inside the card by the activity badge and the agent row, and those can also say which agent asked what.
  • git and cargo have marks now. A git push over a slow link, or a cargo test, are among the longest-lived rows here — and they were the ones with an empty glyph slot beside them, which reads as “unknown program”.
  • Python wears Python's mark. Anything with no mark of its own gets the terminal glyph instead: the spark means “an agent we have no drawing for”, and on python3 that is simply untrue. The project list has a faint rule between projects now.

Preview

  • An outside page could not read the stylesheet next to it. It drew without its styles, so a page with nothing wrong with it looked broken.
  • Ctrl/Cmd+R reloads the preview.

And the rest

  • The usage meter says the same numbers as /usage. One unlucky read of the Keychain — locked, just after waking from sleep — was filed as “there is no token” and kept for good, so the meter dropped to this machine's own estimate and stayed there until the app was quit.
  • Switching project draws its progress under the header. That row is where the thing being replaced is named — the repository, the branch, the remote — and where the switcher that starts most switches lives. A switch that lands quickly draws nothing at all: two pixels appearing and vanishing inside three frames reads as the window twitching rather than as work.
  • Every row in the branch list is the same target. The branch you are on is not offered a delete button, and the row was growing into the space it would have taken. And Pull and Push now say in a tooltip what they will do — how many commits, and with which remote.

1.0.17 2026-09-18

Two things 1.0.16 only half fixed: the list under a session filled with what the agent had started for its own use, and Codex's list of conversations to pick up still disagreeing with codex resume.

Agent

  • Only what somebody ran shows under a session. An agent starts its own MCP servers and a caffeinate to hold the mac awake, and each of them became a row: npm node node npm uv caffeinate — the six-row cap, filled, identically under every session, telling you nothing. What separates the two is who started it. Machinery an agent wires up for itself hangs directly off the agent; what an agent runs it runs the way a person would, through a shell, one level further down. A row is now something a shell started.
  • Codex's conversation list now matches codex resume. Three things were off. The names — Codex keeps what it calls a conversation in an index of its own rather than in the transcript, and reading only the transcript left a column of opening sentences where the picker shows titles. The order — by the last thing said rather than by when the file was last touched, because Codex goes on appending settings and bookkeeping to a transcript after the conversation has stopped. What was missing — every conversation started from the editor. What Codex leaves out of its picker is the ones a program drove (codex exec), not the ones you had in an editor.

1.0.16 2026-09-18

Fixes for what 1.0.15 turned up: a newly created file reported as having no changes, the list of conversations to pick up disagreeing with /resume, and a terminal breaking up along the bottom after a trip between worktrees.

git

  • A new file shows as entirely added. git diff compares the index with the working tree, and a file git has never seen is in neither — so it answered with nothing and the pane drew “no changes” over a file that is entirely new. Every new file in a change list read that way, and because they all read the same way, moving between them looked like the pane had stopped responding.

Agent

  • The list of conversations to pick up now matches /resume. Titles are read in the order the agent itself uses them — the session's name, a name set with /rename, the title it wrote for itself, the summary, and only then the first prompt. Reading the last of those alone left eight of twelve rows with a different name. A subagent's transcript is left out: its name is not a session id, so the row could not be opened. And the order is by the last thing said rather than by when the file was last touched, which is why a conversation whose last word was a week old sat near the top.
  • One background job is one row. A single npm run dev is npm, the node it starts, and that node's workers, which came out as npm node node node. The list has also moved under the session, rather than up against the right of the row.
  • The warn ring goes out once the agent is working again. The ring means “this one needs you”, and it stayed on after the agent had been answered and gone back to work — the badge beside it said “working” while the ring said otherwise, which is one card saying two things.

Terminal

  • A terminal breaking up along the bottom after moving between worktrees. Coming back measured the width the screen would be redrawn at, but never told the program running in the terminal about it. So the program went on drawing for the old width and its status line landed in the wrong columns — and since the size never changed as far as the terminal was concerned, nothing corrected it.

1.0.15 2026-09-18

Ctrl/Cmd+click an import and the file opens — a tsconfig alias or something inside node_modules, with nothing to install. Also fixed: an alert coming back after you had dealt with it, a session reported as “working” while it was asking you something, and a folded panel unfolding after a trip to another project.

The editor

  • Press an import and the file opens. Ctrl/Cmd+click the path in import { DatePicker } from '@one/ui/date-picker', or press F12. Until now nothing happened at all: the TypeScript inside the window knows only the file that is open, so it could not find even the file next to it. It now reads paths and baseUrl from tsconfig.json (inherited ones included), a package's exports and types, and node_modules, for itself.
  • With typescript-language-server installed, more works. Ctrl/Cmd+click on a function name, find references, rename, type errors. What a name refers to is something only a language server can tell you. It is used when installed and reported as missing when not. The project's own node_modules/.bin is looked at first, so putting it in package.json covers the whole team.

Alerts and state

  • An alert you have seen does not come back. Going to the session and reading it did not count as dealing with it unless you typed a reply, so the same alert returned thirty seconds later. Reading it now counts too. The next alert comes after the agent has finished another turn.
  • A session that is asking you something is no longer reported as working. The agent does signal “your turn”, and the next line of output erased that signal. With nothing left to go on the session read as “working” for five minutes and “done” after that. The signal now holds until you answer.
  • You can see what a session is running in the background. A dev server, watcher or build the agent started is listed one level under the session.
  • “Idle” is now “no agent”. The number counts terminals with no agent in front, which includes a shell you are typing in. “Idle” reads as “useless”, which made the clean up beside it look broken for leaving them alone.

The window

  • A folded panel stays folded after a trip to another project. Folds were stored once for the whole window, so opening another project cleared them. They are now stored per project.
  • A menu row takes a press anywhere along it. It used to answer only over the words, and the submenu arrow has moved to the end of the row. The list of conversations to pick up now shows when each was last used.
  • The node icon is the same everywhere. The tab strip, the worktree rail and the ports list were each drawing the same process differently. The ports list now carries an icon for what is using the port.
  • A terminal that stopped drawing below the cursor, and would not scroll. Nothing redrew after the graphics context was swapped, so the rows below stayed as the previous picture and the scroll range kept its old value.
  • A folder that is not a repository is not labelled as one. The line is shown only when there are repositories inside it for the line to head.

1.0.14 2026-09-18

Hover an agent in the + menu to see the conversations from that worktree, and press one to carry on. Also fixed, in what the window was reporting wrongly: a finished turn called “working” for five more minutes, a removed worktree left in the list, a mouse cursor frozen after one drag, and a keychain password asked for after sleep.

Agent

  • Pick up a past conversation. Hover claude or codex in the + menu and the last ten conversations from this worktree are listed; press one and the agent starts there. Pressing the agent's own name still starts a fresh one — that is what choosing an agent from a menu means, and two new tabs must not land on the same conversation. The Start tab carries the five most recent under “Pick up where you left off”.
  • A finished turn is no longer called “working” for five more minutes. The screen read done with a question waiting for you while the rail called that worktree busy. The agent does say when it has finished, but the word was buried by the next line of output and the window went back to judging by the clock. Now the word closes the turn.
  • The lights on a card make sense again. The accent ring that meant “working” is gone — that colour is what this rail spends on the worktree that is open, so every card with an agent in it looked selected. The warn colour for “waiting on you” stays, and now it lights once, until you answer. It used to go out on every line the agent printed and come back after, which read as a question you had already dealt with asking again.

Worktrees and projects

  • The worktree you have open can be removed. It used to be refused with “open another one first”, an errand whose answer was always the same. The window now steps across to the repository's own checkout first and then removes it — the panels and the file tree are reading that directory, so it has to stop being the open one before it stops existing.
  • A removed worktree no longer stays in the list. Removing and re-reading are two calls, and a read that set off before the removal answers with the row that is about to go — arriving late and putting it back. So the card stayed, pressing it errored on a directory that was gone, and only then did it disappear. A card pressed in that gap could also register itself as a project named after the branch; that came from the same place and is closed too.
  • A folder that is not a repository opens too. Adding one and finding it is not a repository left nothing to press, so going to another project meant never getting back to it. The line saying there are no worktrees stays, and the folder itself now has a row under it — the file tree, the editor and a terminal need no repository.
  • Two sidebars show the project icon too, and say which projects are pinned. The icon was drawn in the one-rail list and the switcher only, so the same project looked like two different things depending on the arrangement; pinning was in the menu and changed nothing on the row.

Terminal

  • The syllable you are typing in Korean is visible again. The first jamo showed and everything after it stayed hidden until it committed. The text was being drawn all along — into a box the window was hiding on every keystroke.
  • Moving between worktrees no longer leaves the bottom of an agent's screen out of step. Coming back replays the previous screen, and it was written at one width and then re-wrapped to another, which cut the last frame — the agent's input box. The replay now happens at the width it is going to keep.
  • Re-entering a terminal whose process had exited no longer prints escape sequences as text. The replayed screen carries the questions the program asked the terminal while it was alive; the terminal answered them again, and the answers landed on screen.

The window

  • One drag no longer freezes the mouse cursor for the whole window. It stayed an arrow over buttons and over panel dividers alike. The pointer was not given back when the drag ended, so the whole document was drawing that element's cursor.
  • The tick in Git changes moves on the click. Staging is one git call, but the box waited for the whole refresh behind it and kept its old state, which made the click look like it had missed. Buttons that go over the network — push — now spin while they are going.
  • Waking from sleep no longer asks for your keychain password. A refresh running in the background renewed an expired token, which writes to the credential store, and writing to a locked keychain is that dialog. Renewing now happens when you open the board or press refresh — nothing is lost by waiting.

My work

  • The queue is already there when the window opens. The board is kept on disk, so there is no empty screen while the forges are asked again.
  • A pull request row says whether it is green and whether it is approved. What it is waiting on is readable without opening it.
  • A ticket can be pasted straight into that worktree's agent. One trip fewer through opening the ticket, copying it and carrying it to a terminal.

1.0.13 2026-09-17

Where the build file is not at the top of the repository but in a folder like services/api, the tests panel listed gradlew test but could not run it. Fixed. The build panel can be moved through from the keyboard, counts warnings apart from errors, and remembers the last task you ran. The rail marks a worktree that is working. Tables an agent drew in the terminal printed over themselves because emoji width was measured wrongly; that is fixed too.

Building and testing

  • A Gradle or Maven build one level down actually runs. In the arrangement where nothing declares a build at the top of the repository and services/api does, the test panel listed gradlew test and then answered “no suite” when you pressed Run. Saying a thing is there and then saying it is not is the kind of failure that leaves you no way to find out what is wrong. A suite and the build panel spelled the same folder two different ways; there is one spelling now.
  • A module runs with the wrapper at the top of the repository. This came out of the same place. There is no gradlew beside a module — a repository of several modules keeps one wrapper at the top — and failing to find it we fell through quietly to whatever Gradle this computer has on its PATH. That is exactly the version difference the wrapper exists to prevent. “Why does it work in CI and not here” turns on this one line.
  • The build panel's task list and problem list work from the keyboard. The only gesture either list had was the double click, which is the one gesture a keyboard cannot make: starting a build and going to a compile error were both mouse-only. The arrows, Home, End, PageUp and PageDown move now, and Return runs a task or opens a problem. Moving the selection does neither — arrowing down a list must not start a build. It is the rule the file tree, the git panel, the history and the test panel already follow.
  • Warnings are counted apart from errors. They went into one chip, in the error colour. A build that succeeded with twelve deprecation warnings wore a red “12 problems” right beside its green Built — the panel arguing with itself about a build that was fine.
  • It comes back pointed at the task you last ran. The Run button means “again”, and it did within a session — but reopening the window left the task empty and the button greyed out, so the one you ran eleven times yesterday had to be found in the list again. Remembered per runner, and dropped when the build script no longer has it.

Terminal

  • Switching project and coming back no longer leaves pieces of the old screen behind. Half a line that had scrolled away long ago would be sitting in the middle of an otherwise fresh screen. A terminal repaints only the cells that changed, and that is only sound if it has been on screen the whole time in between. Changing project takes the terminal out of the page altogether and puts it back, so the rows that changed while it was gone were simply never drawn and the old pixels stayed. This was already guarded for a tab that is not on top; the larger version of the same thing was missed.
  • Tables drawn by an agent no longer print over themselves. A table's right-hand border would be drawn a column early with the previous one left standing behind it, or Korean would appear in the middle of a file path. The terminal had not lost its place: it was measuring emoji as one column wide. A program drawing a screen counts how many columns its own text takes and moves the cursor by that much, so a count that is off by one puts every frame after it off by one too. Korean was right all along, which is why the terminal looked fine most of the time and broke now and then — the broken lines always had an emoji on them. Widths come from Unicode 15 now, and characters assembled out of several pieces, like family emoji and flags, come out right with them.

The window

  • A worktree that is mid-turn lights up. The “3 running” on a project row is the number of sessions with an agent up, deliberately: a number that changes while you read it cannot be read. But the only thing answering “and is it doing anything” was one dot beside it, summed over the whole project — so which of three worktrees was busy could only be learned by unfolding the project and reading each card. The card says it now. A card whose agent is waiting on you has been amber for a while; mid-turn joins it as a blue outline — quieter, and with no motion, because waiting is something you have to act on and running is not. The arrangement that stacks each project's worktrees separately had no light at all, not even for waiting; it lights up too.
  • Worktree cards are a line shorter. Token spend had a line to itself, which made the card four lines deep with the fourth spent on a single number — six worktrees meant six lines for six numbers. It has moved to the right-hand end of the branch line. It shares that corner with the change counts, but the two are told apart by colour and weight: the counts are coloured and bold, the spend is muted and carries its own icon. Reading right to left, the side further from the branch is the working tree and the side nearer it is what that cost.

Smaller things

  • The guide now matches what the window actually does. Its shortcut table taught a key for the history that is not bound to it (that key is Replace in Files), and the build, problems, ports and compare-worktrees panels appeared neither in the table nor in the prose. The My work section described the world before browser sign-in, and the install section spoke only about Macs.
  • Bitbucket's “Sign in with a browser” no longer just says server-error. The site's database was not finished being set up, and what reached the screen was a line of code a reader could do nothing with. It now says the sign-in broker is not configured and falls back to the other way in, which is right underneath it: the box you paste a token into. And codes do not reach people any more — a refusal is turned into a sentence, and only what the dictionary has never heard of keeps its name, in brackets.

1.0.12 2026-09-17

Turning on “My work” meant making a token and pasting it in; you now sign in through the browser. GitHub, Forgejo and Gitea do not go through our server at all; for Bitbucket and Jira the site is involved only at the moment a token is exchanged. In the terminal: characters that went missing one at a time after a few hours, and Korean text that was invisible while being composed. A drag-selection in the Markdown preview no longer disappears. Expanding an unpushed commit lists its files right underneath, and pressing one shows the diff in the right-hand pane. The rail's project list scrolls when there are many.

Signing in

  • You sign in at the forge instead of pasting a token. Turning on My work meant going to the forge's settings, making a token, reading up on which permissions to tick, and copying it back here. It is one button now. The four forges ask different things of us, so there are three ways in — GitHub has you type a code into the browser once, and Forgejo and Gitea come back to an address on this computer. Bitbucket and Jira allow neither, so the site stands in for the single exchange that needs it. The token box has not gone anywhere — a self-hosted instance we have no registration with still shows you exactly that.
  • An expired token renews itself. A token granted through the browser has a lifetime — two hours, for Bitbucket. Rather than writing down when it expires, we renew once when a call is refused and ask again. Writing it down means keeping that moment true on a machine that slept and woke, and the forge already knows when its own token ran out.
  • Jira no longer asks for the address first. Atlassian's consent screen belongs to the account rather than to a site, and which site you approved is something we ask about after signing in. Yet an empty address field meant no button at all — a value the sign-in can answer for you was standing in front of the sign-in. The address of the site you approved is now written by the sign-in itself. Where an account has more than one Jira, the one whose name matches is used, and failing that the first.
  • A pasted token is not overwritten by a renewal token left behind. If you signed in through the browser once and then pasted a token for a different account, the old renewal token still in the store came back to life at the first refusal and swapped out what you had just pasted. Signing in now clears the matching entry along with it.
  • Signing in through the browser is no longer refused where you once used a Bitbucket app password. A filled-in account field is what makes credentials of the older kind, and signing in through the browser was not clearing it. A perfectly good token comes back as refused. And the sign-in window now says that it expires in ten minutes — it used to fail without a word to anyone who spent longer than that looking for a password.

Git

  • Pressing a file in an unsent commit shows its diff in the pane on the right. The changed-files list right beside it fills that pane from the same gesture, while a row in this list was a label you could not press. When two lists of the same shape answer differently inside one panel, which of them is the rule has to be learned afresh every time. Unfolding the row already fetches the whole patch, so nothing more is asked for. It is read-only — no staging and no discarding. Those are decisions about what the next commit will carry, and they mean nothing about a change already committed. The header carries that commit's short sha, which is the one thing saying this pane is not showing you the working tree.
  • Unfolding an unsent commit puts its files directly underneath it. The commit row sat in the left half and the file list in the right, with the row floating halfway down that list. The rule that makes every list item in this panel a single-line row had reached in here, where an item is not a row but a row plus a list. The same cause lit up the commit and the sibling files whenever you pointed at one file, and the indent was declared but never once reached the screen, so the files were drawn on the same left edge as the commit. Both are fixed with it.
  • The file list in History now says how many files and how much. They are the first two things anyone asks of a commit somebody else wrote — how many files is this, and how big. Added and removed lines go on the right, where the rows keep their own numbers, in the colours the rows use. With no files at all there is no header: that is the place where "still loading" and "none" have to stay apart, and a header reading 0 only repeats what the list below already says.
  • The more button in the changed-files list sits in the middle of its row. This button is taller than the row it sits on. Taking the top-aligned value written for the rail's two-line cards puts its centre 3px below the row's and leaves the bottom of it hanging outside. It was visibly out of line with the status dots on the rows either side.
  • Pressing a changed file opens the diff in one place only. In 1.0.11, pressing a file in the Git panel also opened a diff tab in the work area, and because the diff pane inside the panel stayed where it was, one press opened the same diff twice. That change was meant to come paired with "the two-column diff inside the panel goes unused", and that half of it was never done. So it is reverted — the diff opens inside the panel, and where the pane is too narrow you drag the split wider.

Terminal

  • Characters no longer drop out of a terminal left running for hours. Lines do not disappear; a character's place goes blank, and it shows first on the line redrawn most often — the status line at the foot of a full-screen program. Every character is drawn once per combination of glyph, colour and style and kept in a texture, and once that texture passes the number this machine's graphics can read at once, whatever spilled over is not drawn. A day of diffs and syntax highlighting is thousands of them. What has been gathered is now emptied before that number is reached. Emptying costs no more than redrawing the characters on screen right now, which is the price changing the font size by one step, and watching every character come back, was already paying. Changing theme empties it too — a gathered character keeps the colour it was drawn in, so the window had a new palette while the characters already on it stayed the old one.
  • The syllable you are composing is visible as you type Korean. Typing ㅎ showed nothing, and the character before only appeared once you began the next syllable. There is one box that the syllable being composed is drawn into and two parties drawing into it, and after one of them stood down the other went on hiding that box at every render. A terminal renders every time a character echoes, so the syllable being composed was never on screen long enough to see. Between "draw it" and "hide it" there is now "leave it alone".

Preview

  • A selection dragged across a Markdown document stays. It was fixed once in 1.0.11, and that was half of it. How links, inline code and tables are drawn was being built anew on every render, so every time the document was redrawn those nodes were replaced wholesale. A selection lives on the nodes, so it dies with them — and almost any selection worth copying out of a README passes through a link or a fragment of code. Redrawing is certain to happen, besides: the file watch reports even a touch that changed no content, and a drag takes a second or two.
  • A link that starts at the root, like /docs/x.md, opens the file it names. It is the form GitHub asks for in a README, so every repository has them, and it was being joined onto the folder of the document you were reading — opening nothing, or opening a file nobody asked for. A ../../../ climbing out of the repository was not refused but trimmed, and resolved quietly to the file of that name at the root. The side that works out which files to watch knew both rules and only the side that resolves the links you press did not, so the rules now live in one place and both read them there.

The window

  • A rail with many projects scrolls. Put forty in and it cuts off at twenty-seven, and eight turns of the wheel moved it not one pixel — because there was no scrolling box there. Nor does the cut show: the rail lets overflow stay visible so that tooltips are not sliced in half, so the rows that overflowed simply ran out of the window. The switcher list in the one-rail layout, which swallowed rows the same way in a short window with three sections unfolded, is fixed with it.
  • The sign that a project is opening has moved to the foot of the window. It used to be on the bottom edge of the card you pressed. A switch starts from five places, four of them places your eyes leave the moment you press, and those 2px were inside a rail that can scroll or be folded away. That a switch is under way is a fact about the window, not about one card, and browsers and editors all put it at the foot of theirs. Which one you pressed is still said by the card.
  • A worktree's spend has moved below the commit line. A number about money an agent spent was wedged between a branch and what that branch did. The letters in the corner are about the working tree and this one is about the plan, which puts it at the bottom of the card.
  • Closing the app with keep-awake on no longer leaves the machine awake. What holds sleep off is a separate process the app starts, and a child process does not die with its parent. So every time the app was closed with the switch on, one was left behind holding sleep off forever, and the switch in the next app to open says — truthfully — that sleep is allowed, about a process it did not start. One on this machine had been alive for 136 hours. The process is now told whose it is, so the operating system clears it away when the app goes — a guarantee that covers crashes and force quits as well.

Smaller things

  • The privacy policy has been brought in line with signing in through the browser. "Tokens are not transmitted to us — there is no server to receive them" is no longer true of signing in to Bitbucket or Jira. Rather than deleting the sentence, we wrote down what passes through and for how long: encrypted, held for ten minutes, and deleted on the spot once the app that began the sign-in has collected it.

1.0.11 2026-09-16

One instruction can go to several agents at once, you can search across sessions for which one said something, and each worktree's card shows what it has spent. There is a panel that compares two worktrees side by side, and a commit can be copied to the worktree next to it. A folder holding repositories now nests them in the project list — a folder with six repositories is not seven rows. Switching worktrees and projects is faster, and says that it is switching.

Agent

  • The same instruction goes to several agents at once. When there is an agent in each of four worktrees and three of them need the same thing said to them — "run the tests", "pull main", "stop and write up what you have so far" — that meant going into three terminals and typing it three times, and the third agent heard it a minute after the first. Idle sessions are ticked by default, and a session that is mid-turn says on its own row why it is not. A shell that is not an agent does not appear in the list at all: one line typed into four prompts at once is four commands nobody read. If it reached only some of them the dialog stays open and says which sessions did not hear it. ⌘+Alt+Shift+A.
  • Which session said that is now a thing you can look up. Find in a terminal asks "where in this panel". When there are five agents across four worktrees, three of them not even drawn right now, and one of them said it an hour ago, the only way through was to open them one at a time and press find five times. The scrollback of every live session is crossed in one go, and pressing a row takes you to that session — opening its worktree first if it is somewhere else. Text inside the boxes an agent draws is found too. ⌘+Alt+Shift+F.
  • A card says how much this branch has spent. The meter in the status bar answers "how much is left", which is a question about this machine's plan and has one answer. Somebody running four agents at once holds a different question — "what did this branch cost" — and it is answered by reading the working directory every session records, and counting tokens per worktree. A nested worktree is counted against the nearest one. A worktree that only ever ran Codex reports nothing rather than zero: a 0 sitting there reads as "this one was free".
  • An agent updating Claude is not announced as finished. "Finished" goes out when an agent is not seen in two observations running, and those two are two seconds. An update takes far longer than that, and what stands in front for the duration is the installer. What separates the two cases is not how long but what is in front — an agent that really has finished leaves its shell behind. So it counts as finished only once the prompt is back.
  • Sessions left in a worktree that is gone are recognised as something to reclaim. The worktree was deleted and the shells that ran inside it are still alive. A layout file outlives the worktree it describes and nothing deletes it, so while that file was there it went on vouching for the sessions, and once even it was gone the answer was "cannot read" and they were left alone. A directory that is gone is a directory no tab can be reopened in, which makes those sessions unreachable from anywhere — and that is knowing, not not knowing.

Projects

  • A folder of repositories holds them in the list. A folder picker often stops one level above the repository, and a project that came in that way had "cannot read" written on its row — the folder opened perfectly well and merely had no repository in it, yet it was handed the same sentence as a drive that is no longer mounted. Such a folder now offers the repositories inside it, and pressing one opens it. And the one you open does not get its own entry in the list: it stays under the folder, because somebody adding a folder of six repositories meant that this is one project. Two levels down are searched, nothing inside a repository that has been found is searched, and a list cut short by the limit says that it was cut short.
  • One repository inside a folder can be promoted to a project of its own. One folder is the right answer for most of what is in it and the wrong answer for the one you are in every day. Until now the only way to say so was to take the folder out of the list, which took the other five with it. A promoted repository gets its own row, drops out from under the folder, and the way back is Unpin on that row.
  • Two ways the list of repositories found inside a folder went missing are fixed. First, if the project list moved for some unrelated reason while a folder was being scanned, the answer still in flight was thrown away — and since that folder was already recorded as asked, it was never asked again. Second, a pinned repository was drawn a second time under the folder above it, which put the "you are here" mark on three rows at once.

Worktrees

  • A worktree made in another terminal now shows up. The window knew about its own git commands and nothing watches the trees, so in the two-rail layout the list read when a project was first opened stayed that way until the app was restarted — a worktree made in the terminal next door never appeared at all. The open projects are now read again when the window comes to the front, because making one in a terminal and coming over here is the gesture. A terminal inside the window never takes focus away from it, so the project row has a refresh button too.
  • Two worktrees can be set side by side. Where Review says what the agent in this tree changed, this panel says how that differs from the tree next door — two branches cut from the same point with an agent on each for an hour: which one got further, and what did that one do that this one did not. The baseline is where they parted. Comparing only the two tips calls every commit the mainline picked up in between a difference between the two, which is not what anybody meant. One direction is asked at a time, and the other is one button away. Ctrl+Alt+C.
  • A new worktree starts with every ignored file already in it. The old defaults, .env* and application-local.yml, were a guess made in advance, and you find out the guess was wrong an hour later as "the app will not start". The line is not length but file against directory — the first are small, machine-specific settings, all of which you want; the second are node_modules and target, big and reproducible, none of which you want. git already draws that line, so this follows it. The sweep has a 64 MB ceiling and reports what it left behind along with the reason: a file named in the settings was asked for by a person and is carried whatever its size.
  • A delete that cannot happen says why instead of hiding. Creating a worktree opens it straight away, and the menu of an open worktree left "Delete worktree…" out altogether. So the card you had just made had exactly one item in its menu, and at that point "not allowed here" and "not a feature" are the same thing. The row is always drawn now, greyed out when it cannot be done, with what to do first attached to it.
  • "Discard changes and delete" reached the two-rail layout. Its confirm dialog told you there were uncommitted changes and that git would refuse, and then offered a single button that walked into that refusal — so a dirty worktree simply could not be deleted in this layout. Whether the same thing was possible depended on which layout you happened to be using.
  • A card's ⋯ no longer sits on top of M, S and !. The overlap was exactly one badge wide, so the rightmost one ended up under the icon. The gradient behind it was there to prevent that, but it was built for the branch name — dim, body weight — and these glyphs have a colour and a weight of their own and did not fade. Every card has a menu now, so the corner is kept clear in advance.

Git

  • A commit can be copied to the worktree next door. Keeping several branches open at once is what this app is laid out for, and about an hour in comes "that commit belongs on the other branch". Until now that was a trip out to a terminal. The worktrees of one repository share an object database, so a commit visible in any history can be copied into any worktree. Pick several and they go oldest first — out of order they conflict purely because of the order — and the original sha is left in the message. It says copy rather than move because the original stays where it is.
  • Pressing a changed file opens the diff somewhere you can read it. This panel is built as two columns, list on the left and diff on the right, and that design assumes room. Wedged into a narrow pane the two columns collapse and the diff is on screen without a single readable line. The way to open a diff tab in the work area already existed; it just was not wired to the git panel. The diff column inside the panel stays — that is where per-hunk staging lives — and the tab opens somewhere that does not cover the list that asked for it. Arrowing through the list opens nothing.

The window

  • A switch says it has started. Press a worktree or a project and the window canonicalises the path, restores the arrangement, re-arms the watches and goes looking for the repository, and for all of that every pixel on screen still belongs to the checkout being left. So the press did nothing at all for as long as the core took, which is indistinguishable from a click that missed. The card or row you pressed now draws a progress sweep. And when two switches overlap, the older answer arriving last was applied over the newer one — one checkout's arrangement under the other's root — which is fixed with it.
  • Switching got faster. The file tree was repainted once for every folder it restored. Each folder had its own turn at walking the whole tree, and the walk cost more each time because the tree had grown. A set is now read together and written down once. And a single switch that spawned git four times to learn three paths spawns it twice — what costs here is not the work but starting git, and on a machine running real-time scanning every one of those is inspected before it runs.
  • Restored folders are watched too. A folder earned a watch when somebody opened it, and when the cascade folded it away — reopening a checkout was neither. So a folder that came back open came back dead: a file an agent wrote in it did not appear until the row was closed and opened again. That is precisely the fault watching was added to prevent, and it was landing on the folders somebody had already shown they cared about by leaving them open.
  • A selection does not vanish while you drag across the preview. The panel follows the open file, and the way it answered was to throw the rendered document away whole and build it again from text that arrived a moment later. When nobody has written to the file, the text that comes back is the text that was already there, which makes the whole thing a demolition with nothing on the other side of it — and a selection lives in the nodes that were demolished. It kept happening because the watcher counted a change of metadata alone as a change: anything an indexer, a backup or a security agent walking the tree touched. Both ends are fixed.
  • ⌥+← and → skip by word in the rename box. Every text field on macOS does this and the file tree's rename box alone did nothing. The window was not swallowing the keys — the webview was not acting on them — so it is answered directly, the same road the terminal went down with the same symptom. A word is letters and digits: what goes in this box is a file name, and on this machine a name written in Korean is as common as report-draft.md.
  • Pressing Esc in the rename box no longer drops you out of full screen. When the webview passes on an Esc nobody used, macOS reads it as leave full screen, so the window already had a rule that prevents that default. The rule stood at the end of the way up, though, so anything that stopped the event earlier finished ahead of it. The tree's rename box does exactly that — it has to, or the tree's arrow keys would move the cursor under the letters you are typing — so the box was not at fault and the window's rule was failing the "unconditionally" it had promised. It now answers on the way down instead.
  • A checkbox in a dialog no longer eats the whole row. The rule that fills a text box across the row was catching the checkboxes inside it too, so the "carry local files" field of the new-worktree dialog became a 340px square with its own label pushed off to the right. The bottom border of the buttons being shaved off when a dialog hit its height limit is fixed as well — a button row with no bottom to it reads as a dialog cut off by the window rather than as more form to scroll.
  • The icon and the text on the add-project screen have space between them. That gap shipped in 1.0.10 and was declared, but it was dead. A general rule above it carried higher specificity, so it won no matter which one was written last. Undoing the fix leaves code that reads exactly the same, so there is now a check on it.
  • A due date showing a day late at UTC+12 and beyond is fixed. A due date is stored as noon UTC of that day, and noon was chosen so that reading the instant in local time still gives the right date. That holds from UTC-11 to UTC+11. In Auckland noon UTC is already the next morning, so every due date came out a day late, and the countdown beside it counted to that wrong date.

Terminal

  • Find still works after a panel is remounted. A terminal instance survives its panel being remounted, but the key handler carries the one belonging to the component that first created it. So the call that opens the find box was aimed at a component no longer on screen, and with nothing drawn and no error raised that tab's find was dead for good. What 1.0.10 added — opening a saved layout, folding and unfolding a pane — is exactly what remounts a panel for ordinary reasons, which is why it showed up then. The handler now only names the tab, and whichever panel is mounted opens its own box.
  • ①②③ coming out small is fixed. It came in with the 1.0.10 fix for them being cut off, and that fix rested on a wrong premise. A font on macOS does have these glyphs at one cell wide — SF Mono. Its family name starts with a dot, though, so an ordinary lookup skips it, a full-width CJK font drew them instead, and squeezing that to the cell took the width alone down to 62% and left them thin. The family is now called for by name. The squeezing stays as a net for machines without such a font.

Build

  • Gradle and Maven are found in projects whose build file is not at the root. Runners were looked for in one place, the project root, so a repository with services/api/build.gradle one level down was told this project declares no build. That was untrue, and it read as the feature being absent. Two levels down are searched now. When the root declares a build, nothing below it is read — a Gradle multi-project build has settings.gradle at the top and a build.gradle in every module, those modules belong to that build, and the root already reaches them as :api:test. Because the search runs only where the old answer was empty, no project that works today is changed by it. A module with no wrapper beside it uses the gradlew above it: one wrapper per repository is the ordinary arrangement, and missing it means falling through to the version difference the wrapper exists to prevent.
  • The terminal's PATH is inherited on Linux too. PATH is how the window finds every tool it runs, and what an app launched from a file manager is given is not the one a person wrote in their shell. macOS already asked a login shell for it; Linux did not, on the assumption that a desktop environment hands over the person's own environment. That is half true — what a session manager passes on does not include ~/.bashrc, and ~/.bashrc is exactly where sdkman, nvm and mise write their line. It is why a Gradle installed with sdkman was invisible. The asking now has a deadline as well: it happens before the window opens, so one rc file that never answers must not become a window that never opens.
  • A build list that cannot be read says why. The failure was swallowed, which left the panel showing its loading skeleton — not an error and not an empty panel, but a screen that looks like it is still working, which is the one outcome nobody can act on or even name. The core's own words are shown now. And where there are several modules, the picker shows the path of each build file rather than the program: every module of one repository runs the same gradlew, so the path is the only thing that tells them apart.

Smaller things

  • Opening a folder no longer re-reads the folder above it in full every time you move worktree. It held the lock on the project list while it did, so everything else in the window that touches the list queued behind it. What was read is remembered — but "not there" is never served from memory: a repository you cloned in a terminal a moment ago is not in a listing read before that.
  • The privacy policy said the opposite of what the app does, and now does not. The summary table read "automatic update check — none" and the body was just as firm about not checking, while the app checks for an update every 30 minutes. Rather than delete the "none", it now says what goes out: a version number, the operating system and the kind of CPU, and nothing that points at the person.

1.0.10 2026-09-15

A pane can be folded down to a handle and opened again, and an arrangement you like can be named and recalled in another project. A project can be added by address — cloned from a Git URL, or created as a new repository in an empty folder. A branch can be switched from the card in the rail, and branches and commits show when they last changed. After /clear in Claude, scrolling up still showed the conversation it had thrown away; one line of hook in your settings fixes that. Saving a file in a monorepo did not run the formatter; fixed.

Projects

  • A project can be added by address. Add project was a folder picker and nothing else, so a repository you had not cloned yet meant a trip out to a terminal and back — type git clone, then come back and find that folder again in the picker. One dialog now holds three ways in: browse for a folder, clone from a Git URL, or start an empty one with a repository in it. While it downloads you see the numbers git is counting, it can be stopped, and a clone that is stopped or fails clears away the half-written folder itself.
  • Nothing asks you for a password. There is no terminal behind this window to answer one, so a prompt would leave the progress line sitting where it stopped. The asking is turned off instead and git fails straight away in its own words — an ssh key, a credential helper and a token in the address all still work.

The window

  • A pane folds down to a handle, and opens again. A split is right at a desk and wrong on a laptop, and the window made you choose once. A folded pane stays where it was — its size, its open tabs, the terminal still running inside it — and all it hands over is its width. The button is pinned to the right end of the tab strip, and the mark draws the shape the window takes rather than the gesture.
  • A layout can be named, saved, and opened in another project. Layouts were already kept per workspace, but there was no way to carry one to a different checkout: a new project or a new worktree always opened as one of the four built-in presets. Save the shape of the window under a name now, and pick that name anywhere.
  • A saved layout is renamed in its own row. Changing a name meant saving the same arrangement under the new one and deleting the old — and in between, the menu had the same arrangement in it twice. The list is where the names are read, so it is where they are changed.
  • How thin a pane can go no longer follows the size of the screen. The floor was a twentieth of the row, so the wider the screen the more width a pane insisted on — and a wide screen is exactly where you want to squeeze one thin. It is pixels now.
  • A pane too narrow to read is frosted over rather than shown cut off. Below the width that holds one whole tab and the fold button together, what is drawn underneath is fragments rather than words. It is blurred instead, and clears when the width comes back.
  • The active tab of a group without focus is a step quieter. A window split four ways lit four accent underlines at once. Which tab a group is showing stays as it was — that is true whether or not you are typing into it — and only the underline and the label come down.
  • Changing sections in settings starts the body at the top. The box remembered the previous section's scroll, and because section headings stick to the top it did not read as leftover scroll but as a section that simply begins in the middle. The same goes for changing the search or the filters.
  • The sleep switch says which way it currently is. One control was saying two opposite things at once — the icon was a state (a moon or a sun) and the words were an action ("Keep awake") — so what was actually on depended on which half you read.

Terminal

  • A /clear in Claude can clear the scrollback with it. This was not the window's doing: Claude Code's renderer erases the visible lines and leaves the scrollback alone — and those bytes are the same ones it writes for an ordinary repaint, so nothing in the window can tell the two apart. So the agent is given a way to say it dropped the conversation: one line of hook under SessionStart in ~/.claude/settings.json, and the window empties both its record and the screen at that moment. Same contract as the waiting·done words the rail already listens for — the hook sees source is clear and writes cleared to $CODEME_AGENT_SIGNAL. Without it nothing changes. The cleared conversation that was still kept whole inside the app, and re-sent on every later view, goes with the same line.
  • Clearing the screen has a shortcut — Ctrl+Alt+K. It lived only in the right-click menu, where opening the menu costs more than the thing it does.
  • ①②③ are drawn whole. The numbers an agent puts on its choices came out as pieces of a circle and could not be read as numbers. No font was missing — Unicode calls these one cell wide and no monospace font on macOS has them, so the substitute font drew them at its own width, and a renderer that bakes glyphs to cell size cut off whatever did not fit. They are squeezed to the cell now.

Worktrees

  • A branch moves from the card itself — through the ⋯ menu or a right click. The one checkout the window could switch was the open one, so moving another worktree in the rail meant opening it → switching → coming back. Keeping several worktrees is exactly what removes that round trip. And the ⋯ menu no longer hangs only on the cards you are allowed to delete.
  • A branch says when it was last committed to. The list was sorted newest first from the start and never showed the date it was sorted by — with an order and no numbers, a reader has to take the order on trust. Both the branch switcher and the branch list you pick from when creating a worktree.
  • A history row says how long ago it landed. There was no time on it at all, and the exact date lived in the tooltip — which made "when did this go in" a question you answered by hovering forty rows. The commit detail now says it the same way.

Git

  • An unsent commit opens to show what it changed. The row had a sha, a subject and a name on it, and not the other half of "what am I about to send" — the half nobody is holding in their head. The files are read once, when a commit is opened, and kept by sha: drawing the list reads no patches.

Smaller things

  • Formatters and linters are looked for where the file is, not only at the root. With the config in apps/admin/.prettierrc and the install hoisted to the root — the most common shape there is — saving did nothing at all, because the decision looked only at the root and answered "no formatter".
  • My work's dashboard no longer breaks the work down by who pushed it.

1.0.9 2026-09-14

Korean, Japanese and Chinese reach the terminal. The shell this window starts was given no locale, so a character came apart into its pieces, or the shell answered with something like (arg: 8). And the worktree that said it was working when nobody had asked it anything, the notification that kept repeating, and the sixty-nine tooltips that did nothing at all on macOS.

Terminal

  • Your input method reaches the shell. An app opened from the Dock or the Finder inherits no locale variables — a terminal app sets its own, and nothing sets one on this path. So the shell ran without a locale, and a line editor in that state reads the bytes of a single character as so many separate key chords. The middle byte of a Korean syllable becoming Meta-8 is where (arg: 8) came from, and it is the same place the missing letters went. The locale is now filled in from your system settings, as UTF-8, and only when it is empty — a value you set yourself is left alone.

Agent

  • A turn you interrupted stops saying it is working. An agent you cut off never gets to say it has finished — Claude Code sends that signal when it completes a response and not when a person stops it. So one interruption left the tab working until the agent itself was quit. Now Ctrl+C closes the turn, and a turn that has printed nothing for five minutes stops being called one.
  • A session you are looking at is not announced in the corner. Every permission prompt raised the same sentence in a toast — and if that terminal is on screen and being read, the middle of the window is already saying it in more detail. Notifications from the OS are untouched: those weigh whether the window is behind something and whether you are at the machine at all.

The window

  • Tooltips appear on macOS. The kind left to the browser is not drawn by this window's web view, and sixty-nine of them were still written that way — every one a place where nothing happened. A truncated file path and a branch name were among them. A control you cannot press now says why.
  • A tooltip no longer covers the thing it explains. Pushed back from the edge of the window, it used to come to rest on top of its own control. The side is chosen first now, and the nudge that follows only moves it along the other axis.
  • The theme list in settings scrolls. What closes such a list was listening to the list's own scrolling, so one notch of the wheel shut it. Every dropdown in the window was in that state; the short ones, which never scroll, were hiding it.
  • Reveal in the file tree points at the file actually in front of you.

Review

  • The mark that agent changes are measured from is set from this worktree's sessions alone. Opening this window while an agent ran in another project set the mark then and there, and everything already written was folded inside it and gone from the list.
  • A directory git cannot answer for is not read as "no commits yet". Read that way, every tracked file in the repository comes up as something an agent wrote. Such a place now says what actually happened.

Smaller things

  • A rating is saved with the comment it came with. They travelled separately, so a comment that landed and a rating that failed left a star nobody counted — and whoever wrote it wrote it again. They go together now, in one statement.

1.0.8 2026-09-14

Commits you have made but not pushed are listed, the branch list includes branches a colleague pushed, and “My work” can show more than one project at once. On the Mac the red button closes the window rather than quitting the app. Also fixed: a diff that stayed selected after one press and release, a terminal search mark that was hard to see, and the wording on the sleep switch.

Git

  • What you have committed and not pushed is a list. Its own group under the changed files, a subject, a short sha and an author on each row. Until now the only thing that said you were in that state was a number on a button: the moment you commit, the change leaves the list above and there is nothing left to look at until it is pushed — a state you can be in for a day.
  • Branches that only a remote has are in the list too. Working on a branch somebody else pushed used to mean leaving the window, creating the local branch by hand and coming back. Now you pick it where you are, and the tracking branch is made as you do. Opening the menu fetches once, so something pushed a minute ago is there.
  • Fixed: in a diff, one press and release, and lines kept being picked. There was a way for the release to go unheard, and after that every line the pointer crossed was picked with nothing held down.

My work

  • Two projects at once, or three. Two of your four are this week's, and the only way to see those two together was to turn the filter off and read past the rest — a filter you had to stop using to use. Picking none of them means all of them.

The window

  • On macOS the red button closes the window. The app stays in the Dock and the agents keep running — the sessions are held by the app rather than by the window, so the window you open again is the one that left. The way out is ⌘+Q, and that is where the question is asked.
  • One window, not two. Launching it again brings the window you already have to the front. With two, the same Claude session wore a different number in each, and one worktree was being watched by two processes with two sets of language servers.

Smaller things

  • What you find in a terminal is now visible. The mark was the same faint colour as a selection, which is a value measured for a block of text whose position you already know. It uses the theme's own yellow now, chosen by measuring it against that theme's paper.
  • The sleep switch says what pressing it will do. It reads one thing when sleep is allowed and the other when it is blocked, and either way the words are true of the press. And it says so when it fails to take hold — it used to light up and quietly let go.
  • A checkout you unpacked to review something is no longer remembered as a project. Unpacking a pull request for review makes a whole repository in a temporary folder, and opening it put a project named after a commit hash in the list. Once the folder was swept away, that row could be neither read nor opened, and only removed by hand. Opening one still works; it is only not written down. Rows already there go on the next launch.
  • The weekly figure on the usage chip, top right, is spelled out rather than abbreviated to one letter in Korean.

1.0.7 2026-09-13

Inlay hints, highlighting of the same name, the signature inside the brackets, and quick fixes beside an error; Python gets a language server for the first time. Git can stage by line rather than by hunk, terminal output can be searched, and a Linux AppImage is now published. Seven requests that came in over Slack are here too — a pane that runs Gradle and Maven, a file tree that folds empty folders into one row, and a tests tab that looks into sub-packages.

The build window

  • Gradle and Maven run in the window. The task list on the left, the compile errors on the right. The handful a build is actually started with — build, bootRun, test, clean — come first, and a double-click runs that task. There is one reason not to step out to the terminal: of the four hundred lines a failed build prints, three are the compile error, and the next command pushes them off the screen.
  • An error line becomes a row that goes to that file at that line. The file:line that javac and the Kotlin compiler speak is read out into a list. The rest of the output is shown as it came, untouched.
  • The wrapper comes first. If the project has a gradlew or an mvnw, the build runs with that, and the window says which one it is running — the answer to “why is it different only here” is usually there. The progress bar does not claim a proportion. The percentage Gradle prints is the share of tasks that have started, not the time that is left, and drawing a bar from it would be the window inventing a number the build itself does not have.

The file tree

  • A chain of folders each holding one folder folds into a single row. Open a Spring project and the top six rows of the tree were all empty folders — src / main / java / com / mz / service pointed at one place with six rows and six steps of indentation. It is one row now: java/com.mz.service. The names are joined with dots only inside a Java or Kotlin source root — dots in any tree at all would make src/components read as a package. It can be turned off in settings.
  • The tree goes back to the file you are looking at. The tree scrolls once, when the cursor moves — the rule that keeps it from jumping to the top while you type a name into a folder five hundred rows down. But the window naming the same file again was caught by that rule too, so once you had scrolled the tree elsewhere while reading, the mark was all that was left and there was no way back to a row that is off the screen.
  • The target button in the file header takes the tree to the file you are looking at (Ctrl+Alt+E). “Follow the tab, or do not” is a setting; this is the one-off that setting cannot give you — where, right now, this file is.
  • “Copy relative path” tries once more in a WebView that refuses the permission. It used to end there as an error.

Tests

  • Tests in sub-packages are found too. Only the workspace root was looked at before, so the vitest declared in apps/desktop/package.json was not visible at all. With a single suggestion the runner picker is not drawn either, which left nothing on the screen to say what would run. Now cargo test and Vitest · apps/desktop stand side by side, and each suite runs inside its own package.
  • You can see what is there before you run it. “List tests” asks the runner itself, and a double-click on a row runs that one alone. It is a button because the question is not cheap — vitest loads every test file, and cargo and go compile the test binary first. None of that happens merely because you opened the panel.

Worktrees

  • A new worktree starts with its .env in hand. A worktree is a clean checkout of the tracked files, so none of the local configuration it takes to start the app is in it — git ignores those files on purpose, so no git command will ever bring them along, and you end up copying them by hand every time. The list of what to carry over at creation is in settings.
  • Configuration files are copied, and a name ending in / means a directory and is linked. Changing the port per worktree is the ordinary thing to do, so configuration has to be a copy; node_modules cannot be duplicated a few gigabytes at a time per worktree, so that side is a link. A file that is already there is not overwritten, and you are told what was skipped.

Usage

  • The weekly limit is on the chip itself. Only what was left of the session was visible before, with the weekly figure inside the hover card. The weekly limit is the one that blocks days rather than hours, and a number you have to go and find is a number you learn after it has already blocked you. The headline is still the session; the weekly one stands beside it as W 69%. The ~ on an estimate and the rule for turning red hold for the weekly one too.
  • Refreshing after switching Claude accounts reads the new account’s limits. The periodic poll cannot open the keychain a second time, so it was holding the previous account’s numbers.

Tabs and dragging

  • Dropping a tab on the edge of a panel splits it that way. Dropping it in the middle moves it into that group. The operations themselves were already there, in the right-click menu and nowhere else — a handle has been put on the gesture side that every other editor has.
  • You can see which side a tab is going to. A line used to be drawn inside the tab, which read as “this tab”, and between two neighbouring tabs the right-hand line of the left tab and the left-hand line of the right tab were the same mark to the eye. A bar stands in the gap now.
  • A drag selected files in blue just by passing over them, changed the cursor at every surface it crossed, and moved the focus. Fixed. Being able to drop a tab into the body is what first sent a drag across the middle of the window, and all three showed up there at once.

The sidebar

  • A silence inside one turn read as “done”. Fixed. An agent row went working → done → needs you → working over the course of a single turn. Nothing about the session changed; only the clock moved. The judgement is made once, in one place, now, and the rail, the tab marks, the project chip, the tray menu and the menu bar badge all read that one.

Language servers

  • Python has a language server. Until now a Python file had no go-to-definition, no completion and no error marks — the client advertised one promise it could not keep, pyright believed it, asked, got no answer, and quietly withdrew. The rule that nothing is advertised unless it is implemented dates from that afternoon.
  • Inlay hints — what is not in the file but the server knows, drawn inside the line. The inferred type, the parameter name in front of an argument. Not characters that get saved: notes the server asked to have drawn.
  • Put the cursor on a name and its other uses light up. The server's answer rather than a text match, so a local count and another function's count are not mixed together. Where it is read and where it is written are marked differently.
  • Open a bracket and it shows what goes in it. The argument being typed is the one in bold, and it moves along as you type.
  • A lamp appears beside an error. Press it to apply a fix the server knows, and Ctrl+Shift+O goes to a symbol inside the file.
  • Take the name and the import comes with it. Type as far as HashMa, choose it, and use std::collections::HashMap; lands at the top of the file. An edit somewhere the cursor is not, which is exactly why it could never have ridden along with the text being completed.
  • A completion goes in over the range the server named, and a snippet gets the stops you tab between. The range used to be guessed from the word beside the cursor, which is right for an identifier and wrong for anything with punctuation in it.

The editor

  • Which symbol the cursor is inside is written beside the file's name, and scrolling into the middle of a long function pins that name to the top of the view. Press it to go there.
  • Path completion, matching tags, Vim keys. A file path completes inside quotes, and editing an opening tag changes the closing one with it.
  • The right-click menu is translated. The window was, but the one place the editor draws its own menu had stayed in English.
  • The ▶ beside a test is visible. It was there and could not be seen — the margin it lives in was zero wide, so the feature worked and said nothing.

The problems list

  • Problems in files you have not opened are collected too. It used to speak only about open files, which is half an answer to “is anything broken right now”. How much it is holding, and the ceiling it cannot pass, are in the status bar's memory card.

Git

  • Staging goes by line, not by hunk. Drag the line numbers and only the lines you picked go into the index — “stage all of this file except the dbg! I left on line 40” is an ordinary thing to want, and the hunk that line is in usually holds four other changes you do mean. Taking lines back out works the same way.
  • The last commit can be amended. A typo in the subject and a file you forgot are one piece of work, not a reason to stack a second commit on top of the first.
  • Inside a changed line, the part that actually moved is the part that is marked. A line with one character altered used to be red and green end to end, and finding what changed was left to your eyes.
  • Git that happens outside the window reaches the panel. Type git add in the terminal below, or let the agent in the next tab commit, and the change list follows. It used to go on showing a diff that was no longer true, with buttons that acted on it.

My work

  • The sprint and the project you picked are still picked next time. The filters were there before, but the choice was not kept: reopening the panel put it back on everything, with the rows somebody had deliberately narrowed away in front of them again. The first screen is still everything — nothing is hidden from somebody who has not touched it.
  • The sprint running now stands above the names as an option of its own. Pick Sprint 12 and the choice is right until the Friday it closes; on the Monday it is a name the board no longer has, and the list quietly goes back to everything. This one is still right on that Monday, because what is kept is the intent and not the name.
  • What this window is open on is in the same place. It reads the remote of the repository the window has open and keeps that repository's pull requests. It does not catch Jira tickets — a ticket's project is not something a checkout's path can tell you — so it stands beside the names rather than replacing them.
  • And the choice is kept per project. “Which of my Jira projects is this” has a different answer in every repository, and one value for the machine would make the choice taken in one wrong in the next. The worktrees of one repository share it — moving between a feature worktree and the main one is not a change of project.

Terminal

  • The output can be searched. A long line folded across two rows is joined back into the line that was printed before it is searched, so a narrow panel loses no matches.

Tests

  • The JVM is first class. Gradle and Maven tests run from the tests tab, and a ▶ stands beside every @Test.
  • pytest is the fifth runner.
  • Run the test you are reading, from where you are reading it. Press the ▶ beside its name and that one test runs.

Linux

  • An AppImage is in the release pipeline. On Linux the file a person downloads and the file the updater installs are the same thing, so the same bytes go up twice under two names.

And the rest

  • Text in a narrow panel used to stack one character per line. Korean may break anywhere, so in a narrow column it wrapped by character rather than by word.
  • In a narrow window the toolbar's three segments were drawn on top of one another. The repository, the branch and the remote now give ground together and in proportion.
  • A refusal a tool wrote across several lines was collapsed into one. Git's advice arrived as a single sentence with every word in it and no order that meant anything.
  • A session's number is on its tab and in its notifications. Two agents waiting in one worktree used to be two rows of the same sentence.
  • Opening a folder that is already open keeps the arrangement it has. The preview redraws when a file the page pulled in changes, not only when the page itself does.
  • The sleep switch was named for the state it was in. Turned off it read "let it sleep", which is what a button says when pressing it will do that — and pressing it did the opposite. On or off it now carries one name, keep awake, with a sun or a moon for which way it is set.
  • The switch now goes out when the thing holding the machine awake dies. That process is the assertion, so the guarantee goes with it; before, the light stayed on over nothing. On a Linux machine without the tool at all, no switch is offered.

1.0.6 2026-09-11

Ten changes have piled up since 1.0.5. A stopped merge is settled from the file list rather than from a banner. My work signs in from behind a corporate network, where all four sources used to fail; the terminal’s /clear takes the scrollback with it; and the notification that came straight back the moment you answered has stopped doing that. Agents have a number you can say out loud, and the app asks for a new version every 30 minutes instead of every six hours.

Merge conflicts

  • Conflicted files stand in their own group at the top of the left-hand list. A banner above used to lay out their names and hold the only way through to the 3-way editor, while the list right underneath had the same files again and could do nothing with them. “Resolve” is now where the file is — Return and a double-click open the same thing.
  • Conflict rows have no checkbox. Checking an unresolved path folds the three stages git was holding into one, and unchecking it did not bring them back — something you could do and could not undo was sitting on a control that looks undoable. That action has a name now instead: “Mark resolved”, in the row menu.
  • If you settled the whole merge outside the app, “Mark all resolved” on the group’s title row finishes it in one go. Unlike the single row, it asks first — this is the side that skips the very work the group exists for.
  • A stopped merge is visible from the other tab too. The “Changes” tab carries a !3. The files themselves stay where they can be fixed, and only the fact that the merge stopped is left on the tab you would press to get to them.
  • In a narrow column the “Files the merge stopped on” banner stacked its label one letter per line and pushed the abort button off the right edge — the one banner read by somebody already stuck was the hardest of them to read. That banner is gone.

The list of changes

  • Changed files can be read as folders. A flat list reads at a three-file change and stops reading at ten — every row opens with the same forty characters, and the part that differs is off the right edge. A folder holding one folder folds into a single row. Whichever view you pick is remembered.
  • A folder row’s checkbox stages everything beneath it in one go, and a folder wears the strongest state below it — a folder holding one conflict looks conflicted.
  • Letters inside a path came out the wrong way round. Fixed. .gitignore drew as gitignore. and /home/me/app as home/me/app/ — a path that does not exist, in the one list you read in order to find a file. Five places: the commit list, diff headings, the changed files in a review, project rows and the project switcher.

My work

  • Signing in works from behind a corporate network. A network that inspects TLS re-signs every certificate with its own CA, and that CA is installed in the keychain — not in the list the app carried compiled into its binary. So all four sources, Forgejo and GitHub and Bitbucket and Jira, died at once with UnknownIssuer. The app now asks the machine about certificates. An in-house self-signed certificate comes along with that: if the Mac trusts it, the app trusts it.
  • A 403 no longer reads as “sign in again”. On Bitbucket a 403 can be a rate limit, or the front end taking a burst for a robot, and a perfectly good token was being thrown away over it. Only a 401 is about the token now.
  • A read asks a second time. Where a single connection dropped somewhere along the way was the whole of a failure, it now waits 400ms, then 800ms, and tries up to three times. Writes — a transition, a comment, opening a PR — are not retried: sending a read twice costs one read, but sending a POST twice opens two PRs.

Terminal

  • Claude Code’s /clear clears the scrollback with it. Scroll up after clearing and the conversation from before was still sitting there — the shell’s own clear was fine, and only this was not. The full repaint it sends is large enough to open a window in which frames are dropped, and the instruction at the very end of it, clear the screen and the scrollback together, was being dropped in that window.

Notices

  • Answering brought the same notification straight back. Fixed. Nothing that decided the session was waiting changes at the instant you press Return, so for an observation or two the session read as both “answered” and “still waiting” at once. What arms the next notification is now seeing the agent take the turn back.
  • “It has finished” repeated itself — fixed in the same place. A moment in which what is in the foreground briefly cannot be known read as the session ending, and the next flicker could say the same thing again. It now has to be true twice running to be announced, and an ending announced once is not announced again until you type something into that session.
  • The notification card is 420px wide now. A worktree name only had to be a little long for “is waiting in …” to be pushed onto a line of its own, and the card grew downward instead of sideways.

Agent

  • Every session has a number you can say out loud. “The third one is asking” was not a sentence you could say — the sidebar and the menu bar were already telling you the state, but neither could tell you which session it belonged to. The number appears in three places: the sidebar row, the menu bar row and the notification headline. Five notifications that all read the same on a locked screen are not notifications.
  • A number stays with a session until it dies. An agent that exits does not hand it back — to the person who was watching, that tab is still number 3.
  • The tooltip on a sidebar row now carries the session id in full. It is what claude --resume and a bug report both want, and there was nowhere in the window to read it.

Updates

  • The app asks for a new version every 30 minutes. It was six hours — the reasoning being that a release is made by a person, so nothing about it is urgent. That was half right: a release that unblocks somebody is urgent, and six hours is how long a window you left open stays blocked. One check costs 0.3 seconds and no body at all when you are already up to date.
  • This one only takes effect from the next release onward. On 1.0.5 or earlier you are on the six-hour cycle until you have received this one.

1.0.5 2026-09-11

Seven changes have piled up since 1.0.4. The theme is one setting now, and the text a light one used to hide is readable. The settings screen puts each name and its control on the first line and cut the descriptions in half, and the four readings in the status bar grew detail cards you can open. Fourteen places that drew an empty slot while you waited now draw the shape of what is about to land.

Theme

  • The window’s brightness and the code theme are one setting. Split in two, choosing a light theme left the window dark, and the control that would have fixed that was another row which said nothing about any of this. Choosing a theme now changes the window and the code together.
  • “Follow the system” is now a light theme you name. Choose nothing for when the Mac is light and the theme you chose above simply is the theme — there is no state left in which that setting does nothing at all.
  • A terminal under a light theme is readable. The “bright” colours were always pushed toward white, which on white paper is exactly backwards, and bright white was white text on a white background — half of an agent’s output was invisible.
  • Under the stock dark and light themes, diffs and rendered code blocks were all one shade of ink. Fixed. Only the editor knew those colours, and everything derived from them was handed nothing.
  • codeme-light is new — the window’s own light palette said in sixteen colours, the way codeme-dark already said the dark one. Settings you already had are carried over for you; there is nothing to open and fix.

Settings

  • A name and the control that changes it share the first line. They used to sit at the two ends of the row with three or four lines of description between them, and at the width the dialog actually opens at, the middle column was four words wide.
  • Descriptions are a sentence or two. Forty-five of them came to 10,787 characters and the longest ran to 800 — “Theme” alone took seven lines, so one of the three settings on that card was all you could see. The longest is now 209.
  • Failure messages come in the window’s language. The list read by someone who has just been told their settings file is wrong was handing them the core’s English verbatim.

The status bar

  • Press a reading and a detail card opens. All four are summaries of something, and a tooltip is one sentence — so boot 240ms · paint 610ms · interactive 1300ms was crushed into a single line, or was not there at all.
  • There is something to do inside the card. The terminal card has a “Tidy up” that ends the idle sessions, and the buffer card has the control that raises the limit — the one thing a person watching that number climb can do was three clicks deep in a dialog.

Notices

  • A notice you clicked does not come back. Opening the tab from the notice was itself what cleared the “waiting” mark, so the same turn — still unanswered — climbed back onto the wire. It is announced once now, and stays down until a person actually answers.
  • The notice card has a copy button. What lands in one is usually a sentence from the tool itself, and the next thing anyone does with it is paste it into a search box or to another person.

While you wait

  • Fourteen places that drew a grey … or nothing at all now draw the shape of what is about to arrive.
  • The four panels that put a diff on the right (Changes, git, History, Review) folded that half into one line every time you picked a file and then filled it again — the very act those panels exist for was the one that made the window jump.
  • The new worktree dialog looked like nothing had happened when you pressed the button, and covered the screen a moment later. The shape of a dialog now stands there first.

Ports

  • “Other ports on this machine” reads as a section. Nothing marked it off from the list above it, and twelve identically shaped rows ran on like a wall.
  • What is under it is grouped by program. Four nodes and one postgres are two things, not five.
  • In a narrow panel the address was drawn on top of the buttons. Fixed.

The editor and files

  • In the find widget, the placeholder was centred, the tooltips were clipped, and the whole thing rose through the “Go to file” palette. All three are fixed, and all three had a different cause.
  • Deleting a file that merely shares a name with the one you have open no longer says “deleted from disk”. With README.md open, deleting docs/README.md reported the file that is still perfectly there as gone.
  • Dropping a file in from Finder used to stop working, quietly, after a tab or a split changed. Fixed — and the listeners[eventId].handlerId banner that came out of the same place goes with it.

Tests

  • You can see what is running while it runs. The runner’s name, the time elapsed and how many lines it has printed come together on one line, and a thin bar beneath says the thing is alive — a runner that has printed nothing and a dead one look identical otherwise.
  • A line repeated in a row is folded. When a jsdom suite prints Not implemented: … on every test, four hundred copies of one sentence arrive — technically output, and in practice a wall.

The menu bar

  • The glyph’s strokes are heavier. The window frame was thinner than the system icons it sits beside, which made it read as blurred.
  • The mark shrank when an agent started asking. Fixed — the only thing added when the state changes now is the clock badge.

1.0.4 2026-09-05

Thirty-four changes have piled up since 1.0.3. The last running thing the window could not see now has a ports panel, keyboard shortcuts can be changed in the settings, and an update no longer stops your session. Terminals open with the same shell as every other terminal on the machine, and the file tree, the preview and the database panel each got a layer better.

Ports

  • Open ports are a list — everything on the machine, this project’s first. Containers had a list and agents had a sidebar; a dev server was visible only for as long as the terminal tab that started it stayed open.
  • You can have the port back. It stops the whole process group, and waits until it is really gone. Kill only node and npm is left behind printing an error, and the next run races whatever still holds the socket.
  • You can have the server back too. The command that started it is remembered, and restarting types that line into a terminal. The server’s output is the thing you actually want, and that belongs in a terminal.
  • What is remembered is not the command line of the process holding the port but the line a person actually typed. npm run dev is a shell, npm and node, and node is the one holding the port — retyping its command line runs the tool inside the script rather than the script somebody wrote.

Shortcuts

  • Shortcuts can be changed in the settings. The two keymaps are a fine starting point, but which key is wrong differs by person — a chord the window manager eats first, a keyboard with no right Alt, three fingers on one hand.
  • There is no notation to memorise. Click the field, press the keys you want, and that is what gets recorded. Writing Mod-Shift-] by hand was the easiest way to end up with a shortcut that does nothing.
  • A clash is named before you save. If a command already answers to that chord it says which one, and saving lets your choice win — the row that lost says who took it.

Updates

  • Downloading and restarting are separate now. One button used to download, install and restart, which made the price of an update everything running in that window. Terminals and agents keep going while it downloads.
  • “Later” is a real answer. What has been downloaded is applied on the way out, so even if you never press “restart now”, the next launch is the new version.
  • Check for updates and send feedback are in the app menu too. The menu bar item can be turned off, and some machines have none at all — and then there was nowhere left to check for an update from.
  • The notice names the version and links to this page.

Changes

  • What you have touched can be thrown away. There was a way into the index and back out of it and no way to undo, so undoing meant leaving for a terminal and typing git restore. A row's menu gets “Discard changes”, the header gets “Discard all changes”, and a hunk header gets “Discard this hunk”.
  • Throwing away cannot be undone, so it asks first — counting what is about to go. A commit can bring back a tracked file; a file git has never seen is gone for good.

Search

  • There is a regular-expression switch. The default does not change by one character — a box that quietly reads what you typed as a pattern raises errors about something you never wrote. With the switch on, a ( is a group you opened, and a message about it is an answer rather than a complaint.
  • Turning it on cannot hang the window. The engine is linear in the length of the input, so a pattern that would have stopped a backtracking one halfway through the project is, here, just a pattern with no matches.

Terminal

  • The shell opens as a login shell. The bash-3.2$ prompt was only the symptom anyone noticed; what was missing were the aliases, the exports and the version manager shims that live in ~/.bash_profile and ~/.zprofile — present in every other terminal on the same machine.
  • Enter no longer goes missing while you type Korean. The timer meant to release a composition whose end was lost rewound on every following syllable, so the terminal kept swallowing Enter until you took your hands off the keys for ten seconds.
  • Text no longer comes back folded into two columns when you return to a tab that was hidden. Fitting the terminal while its width was zero produced a two-column terminal, and it stayed one.
  • Closing a terminal now waits for what was running inside it to finish. It was killed 100 ms later no matter what, which cut an agent off midway through tidying up its own session — so a terminal you had closed stayed a running task in another app.

The file tree

  • The folders you had open survive a switch. Changing project or worktree — even coming back to where you had just been — used to collapse the tree all the way to its root.
  • A folder that disappeared arrives as news, not as a banner. When an agent ran rm -rf, or a branch switch took a directory away, No such file or directory (os error 2) appeared without anyone having touched the tree — and without saying which path.

Preview

  • Four backgrounds to choose between — the panel’s own colour, a checkerboard, light, dark. A PNG leaves whatever it did not paint transparent and the tab background fills those parts, which is why a black icon was a black square under a dark theme. The checkerboard shows which parts are transparent at all.
  • Edit is gone from files it cannot open. On an image, a PDF or a binary it only ever answered that the file is not valid UTF-8, and a button whose one outcome is an error is worse than no button — it reads as something you are meant to press.

Databases

  • The table list is drawn like the file tree. Listing public.users and auth.users one per line was printing directories by full path — the same half said forty times, and the half you actually compare stuck on the end. It now folds and unfolds, and the arrow keys move through it.
  • Refresh shows that it was pressed. When the list came straight back, nothing looked like it had happened at all.

Code intelligence

  • Kotlin and Java get hovers and completion. Highlighting already worked; what was missing was a row in the table of servers.
  • A JVM language server is no longer cut off while it starts. The handshake shared the ten seconds a hover gets, and a cold cache measured 9.72 s — a coin flip, and losing it cost not an empty tooltip but the whole language, treated as having no server at all.

The window

  • The macOS input source badge is turned off for this app. Between the file filter, the search palette, the commit box and the terminals it appeared on nearly every click, and it said what the keys you had just pressed already said. A setting turns it back on, and it takes effect on the next launch.
  • The app icon has its margin back. The plate filled the canvas edge to edge, so Finder drew it larger than the apps beside it and the shadow had nowhere to fall.
  • A turn waiting on you is announced once. If you go and look and the same turn asks again, the first thing you learn is that going and looking means nothing.
  • Every failure message is the same card. One place had the card and the sixteen others still had a red line, and saying “read this” in two ways teaches one of them as the one to skip.
  • Rows fill the panel to its edge. In a wide panel a Docker container row ended at 208 px of 620 — the row is a button, and a button’s width: auto shrinks to fit its contents whatever its display says.
  • The menu bar icons follow the conventions of an IDE now, at a size to match. The waiting state fits inside the same size, so the mark does not jump when an agent starts asking.
  • A list in the settings that clicks fell straight through is fixed. It opened, its rows lit under the pointer, and pressing one did nothing — the way a dialog stops you clicking what is behind it was reaching the list as well.

My work

  • In a wide window whole columns sat empty. At three columns the third one stayed blank, and very wide the first row filled less than a third of the width. Fixed.
  • Cards in a row now end at the same height. A ragged bottom edge does not read as “this one has less to say”; it reads as a grid that failed to line up.
  • While a ticket’s description loads, the placeholder is the shape of the paragraphs about to land. Fifteen lines arriving on top of a one-line “loading…” pushed everything below it down by a screen.

1.0.3 2026-08-29

Fifteen changes have piled up since 1.0.2. Most of them are the My work panel; the rest fix places where the window tried to tell you something and could not.

My work — the dashboard

  • The seven stacked strips are now a card grid that takes its columns from the width. Standing beside an editor, that is seven screens of scrolling you no longer do.
  • Right now — the whole queue as one ring, with the total in the middle. It is the number you used to get by adding two tiles together.
  • The next two weeks — one cell per day. A list of due dates cannot answer “is next week flat, and are five of them piled on Thursday?”
  • Where it is stuck — the columns crossed with age. Forgotten before anyone started it is a backlog; forgotten while somebody is on it is a standup question.
  • By who raised it — half the queue is review requests, and that is a question about people.
  • Hovering a chart opens a second layer. It shows the make-up, the share and the ticket names as rows rather than as a sentence, and the same thing stays on every element as an aria-label.

My work — tickets

  • Ticket detail is two columns now, the way Jira draws it: prose (title, description, conversation) and fields (status, assignee, priority, dates) are read differently.
  • The comment thread is read and written here. A two-line description with the decision down in the comments is the ordinary shape of a ticket, and until now those two lines were all that was shown.
  • Title, description, priority, labels and due date can be edited, and only the changed fields are sent. A form that submits every visible field turns fixing one typo into a write that also reverts somebody else’s edit.
  • The list carries an issue type mark — bug, story, task, epic, subtask. A type a project made for itself keeps its own name and gets a neutral mark.
  • The “this sprint” toggle is now a cycle dropdown. The backlog and past sprints are visible too.

The window

  • The message under the header is now a card like the toasts. A red rule had nothing about it that read as a notice, so the one thing saying why the button you just pressed did nothing was the thing you looked past.
  • File marks are the language’s own — a logo where there is one, a letter tile where there is not.
  • A file from outside the workspace opens when you drop it in, read-only.
  • Long lines leaked out of the diff, and side-by-side cut them off outright. Both fixed.
  • “Needs attention” was announced several times over before a turn had even ended. Fixed.

1.0.2 2026-08-15

Twenty-three changes piled up since 1.0.1. It is also the build where the app updating itself actually happens for the first time — the verifying key is compiled into the binary, so 1.0.0 could not ride this channel, and 1.0.1 → 1.0.2 is that first leg.

Terminal

  • While Korean was being composed, old output turned up behind the input line. Fixed.
  • Shift+Enter submitted instead of breaking the line, and Cmd+←/→ sent no bytes at all. The terminal encodes both itself now.
  • Paste went in twice. Fixed.
  • Right-click has a menu — copy, select all, paste, clear the screen, split the group.
  • Scrollback now defaults to 1MB. An agent that redraws its screen spends most of its bytes on colour and cursor moves, so 256KB was far shorter than it sounded.

Where the window froze

  • Re-reading scrollback, pasting, taking a review baseline — everything that waited on the thread that draws the window has been taken off it. The four-pane layout that came out with three panes went with it.

My work

  • Sprints arrived. A row says which cycle it is in, and the bar grows a toggle only when a cycle is actually running.
  • Bitbucket Cloud loads again. Atlassian removed the endpoint it used on 2025-02-20, and signing in had answered 404 ever since.

Opening it for the first time

  • The three steps are laid out where you are. Working out what to press first in an empty window is no longer the state you start in.

Smaller things

  • The notices at the bottom right were redrawn, and the settings gathered into cards.
  • Dark-theme text colour is set from a target contrast rather than from the floor.
  • “Check for Updates” is in the menu bar.
  • finished is out of the default notifications — waiting had already arrived when the agent handed the turn back, and the process going away is the same news one beat later, so one thing was being announced twice.

1.0.1 2026-07-18

The first build anyone could actually get. 1.0.0 was built too, signed and notarised, but its release files sat in a private repository and answered 404 to anybody without a token.

  • The download address hands over a file now. Installers go out to a public repository.
  • The in-app updater is in the app from this build on. The verifying key is compiled into the binary, so 1.0.0 cannot ride this channel.
  • The icon has a plate behind it.
  • “Go to file” opens onto a list of files. The empty screen went to text search.

How an update arrives

The app checks for a new version itself. When there is one the window asks in a banner, and the download and the restart both happen <strong>after you press</strong> — it does not fetch on its own and it does not restart on its own. “Check for Updates” in the menu bar asks right now.

  • What comes down is one signed file. The verifying key is inside the app, and a signature that does not match is not installed.
  • Version numbers only go forward. A build that went out wrong is not rolled back; it is fixed and goes out under the next number.
  • On 1.0.0 you cannot ride this channel — take it from Download and install over the old one. Installing over the top is a valid update from any version.

The version you are on is in About, in the menu bar. If that number matches the one at the top of this page, you are current.

Have not tried it yet

There is one app to install, and the agent CLI you already use stays exactly as it is.