While a sign-in waits, the server screen in /mcp now reads "Didn't open?
Open the sign-in page." with the label linking the whole address, as the
transcript does since the sign-in links change. A long address no longer
fills the panel. An address that can't be a link target, or a screen too
narrow for the label, still shows the whole address. The transcript and
the screen share the label from menu.sign_in_link_label.
- An MCP tool call over HTTP after the server dropped an idle connection now goes out on a new connection, instead of failing with "the server went away" on every call until fx restarts.
- Renewing an MCP login after the sign-in server dropped an idle connection now goes through, instead of failing with "the sign-in server didn't answer" until fx restarts.
- A connection the server closed cleanly while idle is replaced before the call is sent, so the call no longer fails once with "the tool may have run".
- Connections unused for more than a minute are replaced instead of reused, so a call after the network silently dropped one no longer waits out its timeout.
- A request whose send fails goes out once more on a new connection. A request that was fully sent is still never sent twice.
The repeated-login driver read the sign-in address the transcript printed.
The transcript now links it, so the driver records the shell's output and
reads each link's target instead.
A typed /mcp login and the Vercel sign-in picker printed the whole sign-in
address. Both now show a few underlined words whose OSC 8 link is the
address: "Open the sign-in page" for MCP and "Authorize with Vercel", the
way Codex and Grok already link theirs. Notices underline a link on every
row it wraps onto. An address that can't be a link target is still printed
so it can be copied.
- `/effort` opens a menu of the current model's reasoning effort levels with the one in use marked. ↑↓ moves, Enter applies the highlighted level, and Esc closes it.
- `/effort <level>` applies a level without the menu, and `/effort default` goes back to the model's default.
- Tab after `/effort` opens a level column under the prompt, as Tab after `/model` opens the model column. ↑↓ previews the level in the status line, typing filters the list, Tab fills in the highlighted level, and Enter applies it.
- A new level is saved like a level chosen in `/settings`, and fx prints `Reasoning effort set to <level> for <model>`.
- During a response, the line reads `Next turn will use reasoning effort <level> for <model>`. The running turn keeps its level.
- A model without levels, a level the model doesn't offer, or a malformed level prints a notice and leaves the effort unchanged. If the model list is still loading, the notice asks to try again.
- In a short terminal, the menu leaves the end of the conversation in view and scrolls.
- `/model` still asks for the effort after a model is chosen.
- `/help` lists `/effort` with the model commands.
The SignIn model and its driver still had every reload replace the host and
end the sign-in. A reload now keeps a sign-in when it leaves that server
alone and ends it when it removes or changes the server; the host swap
remains for reloads the loader can't apply in place. KeptSignInGoesOn checks
the first, with a planted bug for the old behavior.
- The model can ask up to 20 questions in one ask_user_question call, so a related set of questions opens as one prompt instead of several prompts of 4.
- The tool schema and description tell the model the new limit.
- A call with more than 20 questions is rejected with "provide 1 to 20 questions", and no prompt opens.
- Resumed sessions show every answer from a batch of up to 20 questions.
Running /permissions with no arguments printed the mode, configured
rules, session grants, and saved rules to the transcript. It now opens a
read-only panel in the footer, like /status, and prints nothing. Each
configured rule, session grant, and saved rule is a bullet, and saved
rules show the ID that /permissions revoke takes. The panel updates when
an approval adds a grant. Subcommands such as /permissions auto and
/permissions remember still confirm in the transcript.
The /status panel becomes a shared info panel that both commands use.
Tests that ran /permissions only to put text in the transcript now run
/allowlist.
wasm32 has no 64-bit atomics, so the SDK's WASM builds failed to compile
the catalog's generation counter. Bindings only compare it for equality,
so 32 bits is enough.
With FX_RECORD set, fx prints a recording notice under the banner, so a
12-row terminal has no room left for the banner above the panel. The
tests now check that the last row of the transcript stays in view.
An /mcp add, remove, approve, or reject used to build a new MCP host and
restart every server. The runtime now applies the change in place through
Engine.reload: servers with the same config keep their process, connection,
sign-in, and calls; removed or changed servers stop and their calls end;
a changed or re-added server starts once its own old process has exited.
The engine copies each server's environment and compares it by content, so
reading the same config again no longer looks like a change.
In a short terminal the panel could take every row but three and cover
the turn in progress. Closing it redrew the rows it had covered, which a
terminal could already have scrolled into history, so they showed twice.
Output written while the panel was open could lose them instead.
The panel now gets the rows an inline picker gets, which leave the end of
the transcript in view, and scrolls the rest with the arrow keys. The E2E
reader scrolls a panel that does not fit to read every line.
- /status opens a panel in the footer instead of writing a notice to the transcript. Esc or Enter closes it and leaves nothing behind.
- The panel's first line shows the open session's ID and whether it is saved yet, so it can be resumed with fx --resume <id>. A shell that can't save sessions shows none.
- The open panel updates when a running turn saves the session or finishes.
- When the panel doesn't fit, the arrow keys scroll it and the hint says so. Long values such as the workspace path wrap instead of being cut off.
- When profile settings can't be read, the panel shows a Settings line and leaves out auth, instead of printing an error with no status.
- A fork made before the first prompt now counts as saved: /status shows it as saved, and the exit line prints its resume command.
- When a stdio MCP server replies with more than 16 MiB, the model is told the reply was too large and fx restarted the server, instead of "the server went away".
- When an HTTP MCP server replies with more than 16 MiB, fx ends the call at once and tells the model the reply was too large, instead of "the server went away".
- fx no longer resumes an HTTP stream (2025 protocol) to fetch an oversized reply again. Before, it downloaded the same reply up to two more times.
- fx no longer requests an oversized tool list again from an HTTP server on the 2026 protocol.
- The debug trace logs each dropped reply with the server, transport, and reason.
- /mcp logout in a shell now also revokes the login another terminal saved after the shell started. Before, that login stayed valid at the server.
- After another terminal logs out of an MCP server, a shell that still holds the login revokes it the next time it would renew it, instead of renewing it and saving it back.
On a Remove or Reject asked on its row, left chooses yes and right
chooses no; the chosen answer is bright. Enter on no goes back like Esc,
and a new question starts on yes. An approval's own screen keeps its
keys.
Remove and Reject now end their question with a bright "yes" for Enter
and a dim "no" for Esc, on the same row. The hint line keeps the server
screen's hints instead of switching to the answers.
The question replaces the choice's row on the server's screen, so it
shows where Enter was pressed. The hint line only says how to answer.
The row draws the name terminal safe, so the hint line no longer needs
its own guard for names that aren't plain ASCII.
Terminals disagree on how wide a glyph with VS15 or VS16 is: Ghostty draws
U+26A1 U+FE0E in one cell, while fx and tmux use two. Cells painted after
it landed one column off, so clearing the status line's MCP notice left
its first character behind in Ghostty.
The diff now moves to an absolute column after such a glyph and erases a
two-cell one before drawing it, so later cells and repaints land where the
grid puts them.