Commit log

ea847f2 fix: make thinking on/off toggle work for deepseek provider

Click to expand commit body
* Ref: https://github.com/charmbracelet/catwalk/pull/271
* Docs: https://api-docs.deepseek.com/guides/thinking_mode

Andrey Nering created

b0c3eb9 chore(deps): update fantasy and catwalk

Andrey Nering created

9114254 chore(legal): @pablodz has signed the CLA

Charm created

6f91b0c fix(tools): switch bufio scanner for reader (#2884)

Click to expand commit body
* fix(tools): switch bufio scanner for reader

* chore(tests): update golden files

Kieran Klukas created

65f30a1 perf(chat): skip re-parsing the rendered chat when nothing has changed

Click to expand commit body
Each frame the chat list is turned into a string with ANSI color codes
that we then have to parse back into cells before drawing. When the
chat list output is the same as the previous frame, we now reuse the
cells we already produced and skip the parsing step.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

0490a8a fix(bedrock): honor reasoning_effort for Anthropic-on-Bedrock models (#2887)

Click to expand commit body
Bedrock routes through Fantasy's Anthropic implementation with a
different display name, so provider options must still be filed under
anthropic.Name for the language model to pick them up. Previously the
bedrock provider type was missing from getProviderOptions entirely, so
reasoning_effort and think were silently dropped.

Co-authored-by: JJ Bot <john.jansen+bot@me.com>

John Jansen and JJ Bot created

1c7ccfd perf(chat): reuse the rendered prefix of a streaming reply

Click to expand commit body
While a model is streaming a reply, we used to re-render the entire
message text every time a new chunk arrived. Now we keep the rendered
output of the parts that are clearly finished and only render the
trailing piece on each update. The check for what counts as a finished
part is conservative on purpose, so anything risky (open code blocks,
lists, tables, html blocks, link references) still falls back to a
full render. The visible output is the same.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

77b6c38 perf(chat): only render the chat lines that fit on screen

Click to expand commit body
Previously the chat list pulled the entire rendered output of every
on-screen item into a buffer and then trimmed it down to the viewport
height at the end. For very tall items, like a long reasoning block,
that meant building a buffer with thousands of lines just to throw
most of them away every frame. The list now stops collecting lines
as soon as the viewport is full, so per-frame work is bounded by the
visible window. Output is unchanged.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

6b101f3 perf(chat): skip re-rendering chat list items that have not changed

Click to expand commit body
The chat list now remembers what each item rendered last frame and
reuses it when nothing about that item has changed. Once a message
turn is fully done, its rendered output is reused verbatim on every
subsequent frame for as long as it stays unchanged. Resizing the
window, focusing or selecting an item, dragging a selection over it,
toggling a thinking block, and any other state change still triggers
a fresh render. The visible output is identical to before; the work
to produce it is much less.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

295a62d fix(ui): calculation bug that would cause modified files to wrap

Christian Rocha created

e0a8e39 chore(legal): @johnjansen has signed the CLA

Charm created

303b153 feat(oauth): add logout command (#2838)

Kieran Klukas created

cc7d651 fix(config): use large model for small if not configured (#2873)

Kieran Klukas created

959bf7e feat(tools): create an allow list for MCP tools (#2800)

Bruno Krugel created

b223e24 feat(logs): add a log line for dropped events

Kieran Klukas created

0585f49 fix(pubsub): raise default per-subscriber buffer (64 -> 4096)

Click to expand commit body
There still seems to be a TUI-sync issue on upstream/main where
the assistant cuts off mid-sentence on screen even though the
DB has the full response.  Two recent PRs probably get most of
the way to fixing it: #2840 reordered the agent's
TypeAgentFinished notification past the activeRequests cleanup,
and #2836 made channelBufferSize actually honored.  In
power-user cases the default (64) is still too small, though.

A streaming turn calls messages.Update on every OnTextDelta /
OnReasoningDelta callback, and the TUI's glamour re-render
periodically stalls the Update loop for tens to hundreds of
milliseconds at a time.  64 slots fill before drain catches up
and the non-blocking publish in broker.go silently drops the
rest.

This diff adopts a pretty aggressive fix -- 64 -> 4096 covers a
long turn at typical SSE rates even under pathological View()
stalls.  Cost is a few MB of ring-buffer allocation across all
brokers, comfortably inside any modern dev machine's budget;
users on tighter memory targets can still tune via
NewBrokerWithOptions.

Drive-by cleanup: maxEvents (struct field + NewBrokerWithOptions
param) is set to 1000 by default but never read anywhere in
tree -- it's bufferSize, not maxEvents, that actually bounds the
queue.  Drop maxEvents on the theory that misleading dead code
is worse than no code.

💘 Generated with Crush

Assisted-by: Claude Opus 4.7 via Crush <crush@charm.land>

Sven Olsen created

a19dd58 fix(dns): fix tmux dns resolver

Kieran Klukas created

61ee2d2 fix(db): use connection pool to avoid corrupted writes

Kieran Klukas created

02b783a fix(permission): fix publish-before-lock race and use O(1) session permission lookups

Click to expand commit body
Move notification publish inside requestMu lock to prevent inconsistent
UI state, and replace the sessionPermissions slice with csync.Map
for constant-time persistent permission lookups.

💘 Generated with Crush

Assisted-by: DeepSeek V4 Pro via Crush <crush@charm.land>

Kieran Klukas created

43b986c perf(chat): show only the tail of long reasoning blocks when expanded

Click to expand commit body
When a reasoning block is expanded, show only the most recent few hundred
lines by default with a hint that more lines are hidden, instead of
rendering the entire thing. Clicking again shows the full block.
This keeps the UI responsive when models produce very long reasoning.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

0485adc chore(tests): update golden files

Kieran Klukas created

9b8b888 fix(prompts): don't include ripgrep and gh prompts in testing

Kieran Klukas created

0c1014e feat(prompts): extend templating system to more prompts

Kieran Klukas created

5ad8bee feat(prompts): template prompts and add github and ripgrep info

Click to expand commit body
Co-authored-by: Tai Groot <tai@taigrr.com>

Kieran Klukas and Tai Groot created

8370edb perf(chat): cache the parts of an assistant message separately

Click to expand commit body
Each assistant message has up to three sections — thinking, response, and
errors — and previously a new streamed token re-rendered all of them. Now
each section is cached on its own, so streaming a response no longer
re-renders the (often long) thinking block above it.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

609cc10 chore(legal): @jan-xyz has signed the CLA

Charm created

3497b74 Merge pull request #2885 from charmbracelet/harden-directory-bounds

Click to expand commit body
chore: harden directory bounds

Christian Rocha created

a7932c5 test(config): tests for the data directory paths

Click to expand commit body
Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

651abb4 chore(golden): rerecord vhs

Kieran Klukas created

efb3b03 feat(prompts): remove long prompt option

Kieran Klukas created

e112368 fix(config): scope crush.json discovery to the current repo

Click to expand commit body
The upward search for crush.json had no boundary and would walk
all the way to the filesystem root, which meant a stray crush.json
placed high in the tree could be picked up by every project beneath
it. This applies the same project boundary used for .crush discovery.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

e2e0bc0 fix(config): scope .crush discovery to the current repo

Click to expand commit body
When Crush starts up it looks for an existing .crush directory by
walking from the working directory toward the filesystem root. In
layouts with several worktrees of the same project under a common
parent, that walk could end up putting crush.db files in the project
root in worktrees.

This stops the walk at the git working tree root, when one can be
detected, and otherwise at the working directory itself. Each project
should now get its own .crush as expected.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

79b2d61 feat(fsext): stop upward lookup at a boundary directory

Click to expand commit body
Add variants of the upward filesystem search that stop at a
caller-supplied boundary directory instead of walking all the way up
to the filesystem root or to $HOME. Callers that want to avoid adopting
matches from outside their project can now express that boundary
explicitly. Existing callers and behavior are unchanged.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

6938ded perf: batch streaming message updates

Click to expand commit body
Group rapid streaming updates into one save and one notification per short
window instead of one per token. Important updates like finishes, tool
calls, and errors still go through immediately. Cuts database writes and
UI redraws by orders of magnitude during long responses.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

7b34700 chore: auto-update files

Charm created

c853a93 fix(config): always resolve the data directory to an absolute path (#2883)

Click to expand commit body
Co-authored-by: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

771117c perf(chat): cache the prefixed render of chat messages

Click to expand commit body
Avoid rebuilding the focus and selection prefix for every line of every
message on every frame. Each item now keeps the prefixed output cached
and only rebuilds it when something actually changes.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

dd1be0e refactor(server): derive per-host cache dir from parsed host URL

Click to expand commit body
Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

2dba83a test(server): regression for the client/server spawn race

Click to expand commit body
Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

d41c118 fix(server): serialize concurrent server spawns with a per-host lock

Click to expand commit body
When two clients started up at the same time they would both try to
spawn a server and one would lose the bind race, leaving a confusing
log behind. Take an exclusive file lock around the spawn-and-wait
sequence, re-check health after acquiring the lock, and skip the spawn
entirely if a peer client has already brought the server up. The lock
is released as soon as the new server is ready.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

d17d61c fix(server): spawn after stale shutdown + handle socket errors

Click to expand commit body
Two related gaps in the client startup path. After a version mismatch we
were shutting the old server down and then never starting a new one,
leaving the next caller to time out against a missing socket. And any
unexpected error from inspecting the socket path (something other than
"not found") was silently ignored, so we'd fall straight into the same
timeout. Both paths now converge on "needs (re)start" and we try to
clean up any stale file in the way before spawning.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

bf5dd26 fix(paste): normalize windows newlines

Kieran Klukas created

a1a4806 v0.67.0

Andrey Nering created

2235a49 fix: limit view size checks to returned content (#2785)

Greg Slepak created

24da509 fix: properly follow the `Assisted-by` header spec (#2871)

Click to expand commit body
We were not using the correct format. According to the SPEC it should be:

    Assisted-by: AGENT_NAME:MODEL_VERSION

So now it'll look like this:

    Assisted-by: Crush:kimi-k2.6

See:

https://docs.kernel.org/process/coding-assistants.html#attribution

Andrey Nering created

8021114 fix(server): keep the spawned server alive after the parent exits

Click to expand commit body
The parent process was creating the detached server via a context-bound
command, so when the parent exited or its context was cancelled the
runtime would also kill the brand new server we had just spawned. Drop
the context binding and rely on the existing platform-specific detach
to give the server a life of its own.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

9b366c3 fix(server): probe readiness over HTTP instead of statting the socket

Click to expand commit body
Cold starts of CRUSH_CLIENT_SERVER=1 frequently failed with a stat error
because the spawned server creates the socket file as the last step of
initialization, well after the parent had given up. Replace the stat
polling with a real HTTP probe against /v1/health, treat any 2xx as
ready, and make the total budget overridable via CRUSH_SERVER_READY_TIMEOUT.
Drop the now-redundant CreateWorkspace retry loop.

Co-Authored-By: Charm Crush <crush@charm.land>

Christian Rocha and Charm Crush created

1d42341 docs(hooks): clarify relative paths

Kieran Klukas created

61a9fce fix(config): individual errors on json parse

Kieran Klukas created

3b0d5de chore: auto-update files

Charm created