## Stack
Part 3 of the split. #64047 and #64194 are merged. This PR targets
`main`, which has been merged into the branch without rewriting history;
the already-merged output-limit and counting changes are preserved.
## Summary
Expose Copilot's actual prompt, combined-context, and output limits
through the shared model interface. Preserve `max_token_count()` as the
existing context capacity; add `max_input_tokens()` for independent
prompt limits, defaulting to context capacity for other providers.
Existing total-display and telemetry callers keep using
`max_token_count()` without fallback expressions. The values come from
the provider's model feed, not hard-coded model tables. Missing prompt
metadata falls back to context capacity; missing output metadata remains
unknown.
Use the independent prompt limit when deciding when to auto-compact,
while retaining the combined window for total usage display and
telemetry. For example, a 90k prompt limit within a 200k context window
is not treated as 200k input and does not lose a second output
reservation.
The existing split-display ring and tooltip use the same usable input
capacity. This PR does not enable split display for Copilot, so it does
not introduce a visible Copilot input-limit display. No counting
endpoints, consent changes, or Delta changes are included.
## Validation
- After the review follow-up, all 47 selected Copilot and agent
compaction tests passed. Local testing used the existing
`gpui_platform/runtime_shaders` feature because the Apple Metal compiler
is unavailable.
- Scoped script/clippy passed for copilot_chat, agent, and agent_ui.
- Formatting and whitespace checks passed.
- Fixtures cover unequal prompt/context/output limits, absent/zero
metadata, and existing compaction workflows.
- Reviewed the complete diff against current main: only the input-limit
API, Copilot metadata, its compaction/display consumers, and tests
remain. The live tooltip workflow was not exercised.
- No live provider calls were made.
Downstream Delta integration must use `max_input_tokens()` for input
admission when updating its Zed dependency; that pin update remains
separate.
## Review follow-up
- Added a real Thread regression with 200k context, 90k input, and
16,384 output: compaction changes from inactive at 80,999 tokens to
active at 81,000; total displayed capacity remains 200k.
- Changed the split input ring to use the same capacity as its tooltip.
This does not enable split display for Copilot.
- All 47 selected tests passed locally, along with scoped Clippy,
formatting, and whitespace checks. Temporarily restoring the incorrect
context-limit call made the new regression fail; that mutation was
removed.
Release Notes:
- Fixed auto-compaction thresholds for GitHub Copilot models with a
prompt limit below their context window.
## Stack
Part 2 of the split. #64047 is merged, and this PR now targets `main`.
Current main was merged into this branch without rewriting history. The
diff contains only counting/consent work and the required README review
acknowledgment (8 files, +837/-80). The Copilot metadata sibling #64195
does not depend on this PR.
## Summary
Add optional provider-backed input counting for direct Anthropic, direct
OpenAI Responses, and hosted Anthropic/OpenAI models. Preserve
structured input and reuse provider conversion, authentication refresh,
and client request limiting. Unsupported providers return `None`;
provider and malformed-response errors remain visible.
Keep the existing hosted data-retention consent rule common to counting,
native compaction, and generation. Counting never sends input before
consent. The matched Cloud endpoint support is merged; its deployment
remains a prerequisite for downstream callers.
This PR does not change Copilot prompt/context metadata, compaction
thresholds, or tooltips. No chunking or paid tests are introduced.
## Validation
- After resolving the main merge: 226 tests passed across anthropic,
open_ai, language_models, and language_models_cloud. Main’s consolidated
output-limit tests and renamed serialization test are preserved.
- Scoped script/clippy passed for anthropic, open_ai, language_models,
and language_models_cloud.
- Formatting and whitespace checks passed.
- Coverage includes images, structured request fields, authenticated
hosted requests, unsupported providers, error propagation, and consent
rejection before HTTP.
- No live provider calls were made.
Release Notes:
- Fixed data-retention consent checks for hosted counting and compaction
requests.
## Stack
- This PR: output-limit plumbing, based on `main`.
- #64194: provider input counting and consent, based on this branch.
- #64195: Copilot metadata and consumers, independently based on this
branch.
After this PR lands, rebase/retarget both children onto `main` as
needed, especially after a squash merge. At split time, a synthetic
merge of the two child heads exactly matched the saved pre-split source
tree. PR1 has since consolidated overlapping tests without changing
production code.
## Summary
Part 1 of a three-PR split: add optional per-request
`max_output_tokens`, forward it through provider payloads, and clamp it
against known output limits. Unset requests preserve existing defaults.
Unknown Copilot output metadata is not treated as a zero-token maximum
when forwarding a cap.
This PR also supplies the combined-window and native-capability
interfaces used by downstream budget calculations. It does not add
input-token counting, data-retention consent integration, or change
Copilot prompt/context metadata, compaction thresholds, or tooltips.
Those changes are split into two child PRs based on this branch.
The net diff is 24 files, +438/-55. Forward narrowing commits preserve
the original review history; there was no force-push.
## Test consolidation
Eight overlapping standalone tests have been folded into existing
conversion tests, preserving coverage of unset limits, explicit limits,
clamping, and serialized payloads. Four distinct tests remain separate:
request serialization compatibility, Copilot wire formats, DeepSeek
conversion (no existing conversion suite), and hosted OpenAI
normal-completion HTTP behavior. This cleanup changes no production Rust
code.
## Validation
- Latest run: 269 tests passed across anthropic, google_ai, open_ai,
language_models, copilot_chat, and language_models_cloud.
- Five extended existing tests failed when cap selection was temporarily
broken and passed after restoration. No mutations remain.
- Latest scoped script/clippy, formatting, and whitespace checks passed.
Earlier split validation:
- 229 tests passed across language_model_core, anthropic, open_ai,
copilot_chat, and language_models_cloud.
- Scoped script/clippy passed for copilot_chat, language_models_cloud,
language_models, agent, and agent_ui.
- Formatting and whitespace checks passed.
- Permanent tests cover payload propagation, absent/explicit limits,
unknown output metadata, direct and hosted native-compaction caps, and
hosted OpenAI clamping.
- No live provider requests were made for the split.
## Review notes
The separately identified fixed/non-interleaved thinking-budget versus
smaller output-cap concern remains open in this PR; it must not be
hidden in the counting or metadata PRs. The README acknowledgment is
retained for human review.
Downstream applications using input counting must consume the counting
child PR as well, not repin to this branch alone.
Release Notes:
- N/A
Fixes the `edit_file` tool failing to resolve `old_text` fragments that
only cover part of a longer line. The streaming matcher compared the
query against whole trimmed buffer lines, so an exact substring like
`keyboard WASD, voxel-based` inside a much longer line failed the fuzzy
similarity threshold and the edit was rejected with "did not match any
content".
Supersedes #60615 — thanks to @ziimakc for the report, reproduction, and
initial investigation there. This PR takes a different approach based on
review feedback on that PR.
## Approach
- `StreamingFuzzyMatcher::push()` is unchanged: it still fuzzy-matches
completed lines incrementally so the UI can reveal the likely edit
location while `old_text` streams in.
- `finish()` now first searches the buffer for the complete raw query as
an exact byte substring (rope-native, overlap-aware KMP; no copy of the
buffer). Exact matches take precedence; fuzzy matching remains the
fallback for indentation drift, typos, and inserted/omitted lines.
- Exact matches are capped at two occurrences — enough to prove
ambiguity — and ambiguous or overlapping matches are rejected with the
existing "matched multiple locations" error instead of silently editing
one.
- The matcher now returns match candidates with their line alignment and
exact/fuzzy provenance in one result, and the edit pipeline uses that to
reindent correctly: for an exact mid-line match the first replacement
line keeps the retained prefix (zero delta) while subsequent lines get
the contextual indentation.
- The streaming parser now preserves the trailing newline of finalized
`old_text` (it still strips it from `new_text` to avoid duplicate line
endings, per #52661), so `"foo\n"` can disambiguate a standalone `foo`
line from `foo suffix`.
## Notes
- Exact-search cost is O(buffer + query) at finalization only; the
buffer is never copied into a `String` (the main concern with the
original PR).
- New regression tests cover mid-line fragments, exact-over-fuzzy
precedence, overlapping-match ambiguity, multiline replacement
indentation (spaces and tabs), trailing-newline disambiguation, and
newline-only edits.
Closes https://github.com/zed-industries/zed/issues/59369
Release Notes:
- Fixed agent edits failing when the text to replace is only part of a
line
## Summary
- Open relative file links with GitHub-style line fragments at the
referenced line
- Support line navigation from agent responses and Markdown previews
- Preserve decoded-first path resolution with literal percent-escape
fallback
## Testing
- cargo test -q -p util test_source_line_from_fragment -- --nocapture
- cargo test -q -p acp_thread test_hyperlink_percent_escapes_are_decoded
-- --nocapture
- cargo test -q -p agent_ui test_open_link -- --nocapture
- cargo test -q -p markdown_preview -- --nocapture
- cargo fmt --all -- --check
Release Notes:
- Improved relative file links with line numbers to open at the
referenced line.
The `edit_file` tool re-indents `new_text` by computing a single indent
delta from the first line of `old_text` versus the matched buffer line,
then applying that delta to every line of the replacement. When a model
omits the leading indentation on only the first line of
`old_text`/`new_text` (a common pattern when copying from mid-line
context), the delta computed from the first line was wrongly applied to
the remaining, already-correctly-indented lines, doubling their
indentation.
This PR:
- Tracks the `(query_row, buffer_row)` line pairs aligned by the
streaming fuzzy matcher so the indent of each `old_text` line can be
compared against the buffer line it actually matched.
- Computes a separate indent delta for the lines after the first: when
those lines agree on a consistent delta, it's used for the rest of the
replacement; otherwise the previous uniform behavior is preserved.
- Keeps `query_lines`/line pairs in sync when `finish()` extends a match
with a trailing incomplete line.
- Adds an end-to-end regression test reproducing the issue, plus unit
tests for the new re-indentation logic.
Closes https://github.com/zed-industries/zed/issues/60302
Release Notes:
- Fixed the agent's `edit_file` tool corrupting indentation when a
replacement omitted leading whitespace on only its first line.
Summary:
- Add a shell-level startup handshake owned by the terminal.
- Send a split startup marker through the shell and run the configured
init command after the marker is observed, preventing local echo from
satisfying the handshake.
- Keep display-only/restored terminal behavior unchanged while
preserving startup output when shells fail or users type first.
Tests:
- `cargo test -p terminal test_init_command_startup_marker --
--nocapture`
- `cargo test -p terminal write_init_command_after_startup --
--nocapture`
- `cargo test -p agent_ui init_command -- --nocapture`
- `./script/clippy -p terminal -p agent_ui`
Closes AI-426
Release Notes:
- Fixed terminal init commands sometimes appearing or running
incorrectly when using custom shells
---------
Co-authored-by: Anant Goel <anant@zed.dev>
Follow-ups to the recently-landed agent terminal sandboxing work.
- Make the persistent "Allow Unsandboxed Terminal Commands" setting
(`allow_unsandboxed`) the single off-switch for the agent terminal
sandbox: when enabled, the sandboxed terminal tool isn't exposed and the
system prompt omits the sandbox section, so the model uses the plain
`terminal` tool (and on Windows, WSL sandbox setup is skipped). This
removes the dead, unwired `disabled` setting that was meant to do the
same thing but had no UI, writer, or docs. Per-command and per-thread
`unsandboxed: true` grants are unchanged.
- Expand the blocklist of Windows-specific environment variables that
aren't forwarded into the WSL sandbox (system locations, `HOME`/profile
paths, host/session identity, CPU descriptors, etc.) so they can't
shadow or break Linux commands. It stays a blocklist, so portable
variables like `LANG` still reach the command.
Release Notes:
- N/A
The agent panel's `grep` tool output previously rendered file paths and
line numbers as plain markdown text, so search results weren't clickable
(unlike `find_path`, which emits `ResourceLink` content blocks).
This PR makes `grep` results clickable in the same way `find_path` does:
- `grep` now streams a `ResourceLink` content block per match
(`crates/foo/bar.rs#L12-15` → `file:///abs/path#L12-15`) followed by the
code snippet, via `event_stream.update_fields`, and sets `locations` on
the tool call.
- `render_resource_link` in `agent_ui` now splits an optional `#L...`
fragment off `file://` URIs before resolving the project-relative path,
so labels render as `path#L12-15` instead of falling back to the raw
absolute URI. Clicking opens the file at the matched line (handled by
the existing `MentionUri` selection parsing).
- The model-facing text output of the tool is unchanged.
Closes AI-401
Release Notes:
- Improved the agent panel so that file search results from the agent's
`grep` tool are clickable and open the file at the matched line.
Summary
- Adds Windows agent terminal sandboxing by routing commands through WSL
and Bubblewrap.
- Supports native Windows and WSL project paths, including elevated
write grants for WSL paths.
- Shows a confirmation prompt to turn off sandboxing when WSL sandbox
setup is unavailable.
This builds on the work in the sandbox-linux branch.
Closes AI-376
Release Notes:
- Added Windows terminal sandboxing for agent commands when sandboxing
is enabled.
---------
Co-authored-by: cameron <cameron.studdstreet@gmail.com>
Co-authored-by: Richard Feldman <oss@rtfeldman.com>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
Adds a dedicated Sandbox settings page under the AI settings, letting
users review and manage the elevated terminal sandbox permissions that
are always allowed without prompting.
The page exposes:
- Network: an "Allow All Domains" toggle and an editable list of allowed
domains (exact domains or leading-`*.` subdomain wildcards), with
validation.
- Filesystem: an "Allow All Filesystem Writes" toggle and an editable
list of writable paths.
- Sandbox: an "Allow Unsandboxed Terminal Commands" toggle.
This replaces the single "Allow Unsandboxed Terminal Commands" setting
item with the new page, and updates the agent panel's settings shortcut
to open it. "Allow always" sandbox grants now persist to settings only
and are no longer also cached as an in-memory thread grant.
Closes AI-413
Release Notes:
- Added a settings page for managing the agent terminal sandbox
permissions (allowed domains, writable paths, and unsandboxed command
execution).
## Summary
- Adds an `agent.terminal_init_command` setting for Terminal Threads.
- Runs the configured command automatically when creating a new Terminal
Thread, while skipping restored terminal threads.
- Documents the setting and exposes it in the AI settings page.
Closes https://github.com/zed-industries/zed/issues/58697
Closes AI-337
Release Notes:
- Added a setting to automatically run a command when opening a new
terminal thread in the agent panel.
---------
Co-authored-by: Anant Goel <anant@zed.dev>
Include the changed paths in `UpdatedEntries` events emitted by remote
worktrees.
Previously a remote worktree emitted `Event::UpdatedEntries` with an
empty changeset (`Arc::default()`), discarding the changed paths. The
changeset now carries the real added/updated/removed paths, resolving
removed entries against the previous snapshot.
Release Notes:
- Fixed file change events not reporting changed paths in remote
projects
When a setting was reset to its default while its input field was
focused, the field kept showing the old value. The reconciliation that
syncs the editor with the current setting value now handles cleared
(null/empty) defaults and reconciles focused fields when they have no
unsaved edits, so the field clears as expected.
Release Notes:
- Fixed settings input fields not clearing when a setting was reset to
its default while the field was focused
Follow-up to #58996. The "Remove Worktree from Window" button captured
the row index at render time and re-resolved it against the picker's
matches at click time. Matches are rebuilt asynchronously (initial
worktree list load, post-delete refresh, query changes), so the index
could drift between the rendered frame and the click being processed,
closing the workspace of a different worktree than the one the user
clicked.
This changes the click handler to capture the worktree's path — a stable
identity — instead of its index, adds the same `deleting_worktree_paths`
click-time guard the neighboring handlers use, and constructs the button
only when it will actually be shown.
Scoped to the code added in #58996; the same stale-index pattern in the
delete and open-in-new-window handlers is left for a later change.
Release Notes:
- Fixed an issue where the worktree picker's "Remove Worktree from
Window" button could act on the wrong worktree if the list updated at
the moment of the click.
## Summary
- Show the command being approved in sandbox permission prompts even
when no specific write paths are requested
- Keep the existing network and write-path details alongside the command
## Validation
- rustfmt crates/agent_ui/src/conversation_view/thread_view.rs
- cargo check -p agent_ui
Release Notes:
- Improved sandbox permission prompts to show the command being
approved.
Summary:
- Include terminal command text in sandbox authorization metadata.
- Render the command in sandbox permission prompts, including prompts to
run outside the sandbox.
- Keep write-path details visible alongside the command when both are
present.
Tests:
- cargo test -p agent sandbox
- cargo check -p agent_ui
Release Notes:
- Improved agent sandbox permission prompts to show the command being
requested.
Closes AI-394
When the kernel isn't running — e.g. Python isn't installed, ipykernel
is missing, or the kernel failed to launch — clicking run on a notebook
cell would unconditionally enter the executing state and silently drop
the execute request. The cell then spun forever with no logs and no way
to cancel (the stop button only works on a running kernel).
This change makes `execute_cell` attempt to send the execute request
first, and only mark the cell as executing when the send succeeds. On
failure it:
- Renders the failure (including the original kernel launch error) as an
error output on the cell, reusing the same `ErrorView` used for Python
tracebacks
- Logs the reason at the moment run is clicked, instead of only once at
notebook open
- No longer swallows `try_send` errors when the kernel process has died
Also adds the first unit test for the notebook editor, which exercises
the production path end to end: a real `.ipynb` parsed via
`NotebookItem::try_open`, a kernelspec pointing at a nonexistent
interpreter selected through `ReplStore::set_active_kernelspec`, a real
failed process spawn, and assertions through the production save path
(`to_nbformat_cell`). Verified red/green: the test fails against the
previous behavior.
Note for future notebook tests: `NotebookEditor` renders a continuously
animating kernel status icon, so rendering it as a root view in a GPUI
test makes `run_until_parked` spin forever. The test creates the editor
inside an empty window instead.
Release Notes:
- N/A
After prompting an agent, no response was received and only a spinner
was shown. After updating and reopening Zed, the thread still appeared
in the sidebar but failed to restore with `Failed to Launch` / `no
thread found with ID: SessionId(...)`, and the original prompt was lost.
## Root cause
A native agent thread is tracked by two independent persistence layers:
- **Sidebar metadata** (`ThreadMetadataStore`) and the **serialized
agent panel** record the thread's `session_id` through fast, separate
write paths.
- **Thread content** (`ThreadsDatabase`) is written by a per-session
async task (`NativeAgent::save_thread`) that can still be in flight when
the process exits.
When a graceful quit or update restart raced that async content save,
the metadata/serialized session id was persisted but the content row was
not. On restore, the metadata gate passes, then `load_thread` finds no
content row and hard-fails with `no thread found with ID`.
## Fix
Register an `on_app_quit` handler on `NativeAgent` that synchronously
commits every newly created non-empty thread's content to
`ThreadsDatabase` during shutdown, keeping the two stores consistent
across a graceful quit/restart (the auto-updater's path).
Closes AI-374
Release Notes:
- Fixed agent threads failing to restore after quitting or updating Zed
while a response was still in progress
Fixes the agent panel silently reverting all pending subagent file
changes when an earlier message is edited and regenerated.
`ThreadView::regenerate` decides whether to auto-keep pending edits from
earlier prompts (behavior introduced in #43347) by scanning the parent
thread's entries for diffs. Subagent edits never appear there — they are
only forwarded to the parent's action log via the linked-log mechanism —
so the auto-keep step was skipped and `rewind`'s unscoped
`reject_all_edits` reverted all of them on disk, without confirmation.
The fix treats any earlier subagent tool call as potentially having
edits, so they get auto-kept just like direct edits from earlier
prompts. Keeping all edits is a no-op when the subagent made none. Edits
produced by the prompt being regenerated are still auto-rejected,
consistent with existing behavior.
Also adds a regression test
(`test_regenerate_keeps_pending_subagent_edits`) that reproduces the
full flow — subagent edit forwarded through a linked action log,
follow-up prompt, regenerate — and fails with the exact reported data
loss without the fix.
Closes AI-386
Closes https://github.com/zed-industries/zed/issues/58932
Release Notes:
- Fixed pending subagent file changes being discarded when editing an
earlier message in the agent panel.
Closes AI-344
Closes AI-342
Moves agent skills management out of the agent panel and into the
settings UI. The skill creator (previously its own crate) now lives in
`settings_ui` as a settings page, alongside the skills setup page. The
agent panel's ellipsis menu now links to the settings page instead of
hosting skill management directly.
Release Notes:
- Improved agent skills management by moving it into the settings UI
---------
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
The settings UI previously required selecting a settings scope (User /
project) before entering a sub-page; the scope picker disappeared once
inside. This makes the scope switchable from within sub-pages.
- The scope segment of the sub-page breadcrumb (e.g. "User / AI / Agent
Configuration / Skills") is now a dropdown listing all scopes the
sub-page supports (filtered by the sub-page's file mask, intersected
across the sub-page stack). Selecting a scope re-renders the sub-page in
place — e.g. the Skills page swaps between global and project-local
skills.
- The sub-page stack is preserved across scope changes when every
sub-page in it is valid in the new scope; otherwise it falls back to the
regular navigation behavior.
- Sub-pages that only support one scope (Tool Permissions, Configure
Providers, Feature Flags) keep the static label.
- Entering a sub-page now clears the settings search bar so sub-pages
show all their items (settings deep links that prefill the search are
unaffected).
Closes AI-343
Release Notes:
- Improved the settings window: sub-pages such as Skills and
per-language settings now have a scope picker in the breadcrumb, so you
can switch between User and project settings without leaving the page.
---------
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
When a pending tool call awaiting permission contains tall content (e.g.
a full plan in Claude Code plan mode) and the inline prompt is scrolled
out of view, the floating awaiting-permission row embeds that content
and can grow to consume the entire panel, squeezing the conversation
list to zero height. `ListState::item_is_above_viewport` /
`item_is_below_viewport` returned `None` for a zero-height viewport, so
the row's visibility decision oscillated from frame to frame, flickering
between the conversation and the permission prompt and making the thread
unusable.
This PR fixes the root cause and hardens the UI:
- `gpui`: `item_is_above_viewport` / `item_is_below_viewport` now answer
definitively from the last layout bounds even when the viewport is
zero-height, so callers that size sibling UI based on these queries
can't oscillate. Adds a regression test.
- `agent_ui`: adds a `Floating` tool call layout used by the
awaiting-permission row that caps the embedded tool call content with a
scrollable max height, so the row can never crowd the conversation list
out of view while keeping the permission buttons visible. Adds an
integration test that drives real window draws and asserts the row's
visibility is stable across frames.
Closes AI-372
Closes https://github.com/zed-industries/zed/issues/58564
Release Notes:
- Fixed the agent panel flickering and becoming unusable when a
permission prompt with tall content (such as a plan awaiting approval)
was scrolled out of view.
Removing the `Rule` variant from `MentionUri` in #58080 broke
deserialization of any thread saved before the rules-to-skills
migration. Loading one failed with `unknown variant `Rule``, making
those threads inaccessible.
This restores access without bringing back the rules feature:
- Reintroduce a backward-compatible `Rule` mention variant so legacy
threads deserialize again.
- Preserve the original rule `id` through save/load so a thread re-saved
by a newer build still loads on older Zed versions (and synthesize a
valid placeholder when the id is missing).
- Clicking a legacy rule mention now opens the skill the rule was
migrated into, and shows a notification linking the Skills docs. On
remote/collab projects the migrated file lives on the local machine, so
it opens as a read-only buffer. If no matching skill exists, it does
nothing.
Closes https://github.com/zed-industries/zed/issues/58498
Closes AI-371
Release Notes:
- Fixed old threads that mention Rules being inaccessible after Rules
were migrated to Skills
Edits targeting the agent skills directory (project `.agents/skills/`
and global `~/.agents/skills/`) always prompt regardless of permission
settings, because they route through `authorize_always_prompt` which
never consults the persisted `always_allow` rules.
The permission prompt still rendered an "Always allow" button, though.
Clicking it wrote an `always_allow` rule into settings that was then
silently ignored on the next skills edit, so users were re-prompted
every time despite having chosen "always allow" — exactly the confusion
reported in AI-346.
This keeps the always-prompt behavior intact and just hides the
misleading "Always allow" / "Always deny" options for skills, leaving
once-only Allow/Deny. Applies to all mutating skills tools: `edit_file`,
`write_file`, `copy_path`, `move_path`, `delete_path`, and
`create_directory`.
Implementation:
- New `ToolPermissionScope::AgentSkills`, set via
`ToolPermissionContext::for_agent_skills()`.
- `build_permission_options` returns flat once-only Allow/Deny for that
scope (mirrors the existing `SymlinkTarget` handling).
- Wired into both authorization entry points (`authorize_file_edit` and
`authorize_with_sensitive_settings`).
- Tests assert no `AllowAlways` option is offered for each affected
tool.
Settings-file prompts (`.zed/settings.json`, global config) are
intentionally left unchanged.
Closes AI-346
Release Notes:
- Removed the misleading "Always allow" button from agent permission
prompts for edits to the agent skills directory, since those edits
always require confirmation.
Summary:
- Allow agent tool-call locations outside visible worktrees to resolve
as local buffers.
- Fall back to opening absolute paths from the tool-call click handler.
Tests:
- cargo test -p acp_thread
test_tool_call_location_resolves_external_file
- cargo check -p agent_ui
Closes AI-362
Release Notes:
- Fixed opening agent-created files outside the current project, such as
global skill files.
Adds granular, per-path write permissions to the agent's sandboxed
`terminal` tool.
Previously a command could only request unrestricted filesystem writes
(`allow_fs_write: true`) as an all-or-nothing escape hatch. Now the
model can request write access to specific paths via `fs_write_paths`,
and each granted directory covers its whole subtree. The broad escape
hatch is still available as `allow_fs_write_all: true` for cases where
the paths can't be enumerated up front.
Approval prompts now let the user grant a write request either just for
that command or for the rest of the conversation. Conversation grants
are tracked in memory (never persisted) using pure subtree containment,
so later commands writing under an already-granted path run without
prompting again.
Closes AI-335
Release Notes:
- Improved the agent's terminal sandbox so commands can request write
access to specific paths instead of all-or-nothing filesystem access,
with the option to grant access for a single command or the rest of the
conversation.
---------
Co-authored-by: Anant Goel <anantdgoel@gmail.com>
Co-authored-by: Richard Feldman <oss@rtfeldman.com>
Closes https://github.com/zed-industries/zed/issues/57992
Closes AI-349
## Summary
- Run rules-to-skills migration during agent UI init instead of waiting
for feature flags in production.
- Add a command palette action to rerun the migration manually.
- Make AGENTS.md migration appends idempotent to avoid duplicated
default-rule prompts.
Release Notes:
- Added a manual way to trigger the Rules to Skills migration
Project-local skills now load through project buffers so remote
workspaces can resolve them consistently with other project files.
Validation:
- cargo check -p agent_skills -p agent
- cargo test -p agent_skills
- cargo test -p agent skills
Closes AI-329
Closes https://github.com/zed-industries/zed/issues/57877
Release Notes:
- Improved project skills support in remote workspaces.
---------
Co-authored-by: Cole Miller <cole@zed.dev>
Adds a progress indicator to the worktree picker so users get visual
feedback while a worktree deletion is in progress, which can take
several seconds.
Closes AI-239
Release Notes:
- Added progress feedback in the worktree picker while deleting a
worktree
Extends the same `~/.agents/skills` special case that
`create_directory`, `edit_file`, and `write_file` already use to the
path tools, so the agent can copy or move skills into and out of the
global skills folder and delete individual skills or skill resources
beneath it.
- `copy_path` now allows source and/or destination to be a descendant of
`~/.agents/skills`, going through `fs::copy_recursive` directly when one
side is outside the project.
- `move_path` now allows source and/or destination to be a descendant of
`~/.agents/skills`, going through `fs.rename` directly when one side is
outside the project. Moving the `~/.agents/skills` root itself is
rejected.
- `delete_path` now allows deleting any file or directory beneath
`~/.agents/skills`, going through `fs.remove_dir` / `fs.remove_file`
directly. Deleting the `~/.agents/skills` root itself is rejected.
- All three tools still always prompt for approval on agent-skill paths,
even when default tool permissions are set to allow.
- Added shared helpers in `tool_permissions.rs` for resolving global
skill descendants and rejecting operations on the skills root where
needed.
- Added tests covering copying and moving skills in both directions,
deleting a global skill directory/file, and rejecting deletion of the
skills root.
Release Notes:
- Agent can now copy or move skills into and out of `~/.agents/skills`
and delete individual skills, with an explicit confirmation prompt for
each operation
The Skill Creator window previously couldn't be resized — its minimum
size was set to the same dimensions as its initial size, so users
couldn't make it smaller or shorter. Its contents also didn't scroll, so
on smaller windows the Skill Content editor would be squeezed below its
usable size.
This change:
- Lowers the window's minimum size to 500×420 so it can be resized in
both directions.
- Wraps the form body in a scrollable container with a vertical
scrollbar.
- Replaces `flex_1 + min_h_0` on the form fields and Skill Content
wrapper with `flex_grow + flex_shrink_0`. Combined with the existing
`min_h(160)` on the body editor, this means:
- When there's extra vertical space, the Skill Content editor grows to
fill it.
- When the window is short, the form keeps its content at natural size
and the outer container scrolls instead of crushing the editor.
Closes AI-315
Release Notes:
- Made the Skill Creator window resizable and its contents scrollable
when the window is smaller than the form.
Summary
- Display the full path for global skill files in the agent edits
summary when they do not have a project-relative file name.
Closes AI-320
Validation
- cargo check -p agent_ui --lib
Release Notes:
- Fixed global skill edits appearing without a file path in the agent
changes summary.
Summary
- Allow write_file and edit_file to create or modify files under
~/.agents/skills.
- Keep the global skills exception constrained to that directory and
preserve existing project-path behavior.
- Document global skill file editing support in the built-in
create-skill instructions.
Tests
- cargo fmt -p agent
- cargo test -p agent global_skill_file
- cargo test -p agent
test_create_directory_allows_global_skill_directory
Release Notes:
- Fixed agent file editing for global skills
---------
Co-authored-by: Richard Feldman <oss@rtfeldman.com>
Summary:
- Added a rename action for agent threads in the sidebar.
- Persisted renamed thread titles and kept open thread views in sync.
Release Notes:
- Improved agent threads by allowing them to be renamed directly from
the sidebar.
---------
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
The threads sidebar rebuilds its `Vec<ListEntry>` from scratch on events
that touch thread/sidebar state (status changes, title generation, new
live info, sending a message, etc.). It previously called
`ListState::reset` after every rebuild, which rewrote every list item to
`Unmeasured`. On the next render frame, the sticky project header had no
measured bounds for the next project header.
The sticky project header uses `ListState::bounds_for_item` for the next
project header to compute how far it should be pushed off screen. When
those measurements were missing, it temporarily fell back to `top_offset
= 0`, snapped fully into view for one frame, then popped back once the
list was remeasured.
Fix: preserve list measurements for entries whose identity and layout
shape did not change. `EntryShape` captures each entry's identity plus
height-affecting project-header flags. `update_entries` snapshots the
old shapes, rebuilds contents, then splices only the changed shape range
into `ListState`. Unchanged items keep their measured bounds, so the
sticky header remains in its pushed-off position across same-shape
updates.
This also adds a regression test that renders a two-project sidebar,
scrolls into the sticky-header push-off state, performs a same-shape
thread metadata update, and verifies the next header's measured bounds
are preserved.
Closes AI-196
Release Notes:
- Fixed the project section header flickering in the agent threads
sidebar when sending a message while the header was partially scrolled
off screen.
Summary:
- Added a rename action for agent threads in the sidebar.
- Persisted renamed thread titles and kept open thread views in sync.
Release Notes:
- Improved agent threads by allowing them to be renamed directly from
the sidebar.
Format `read_file` tool output in `cat -n` style: each line is prefixed
with its line number right-aligned in a 6-character field, followed by a
single tab, followed by the line's original content (newlines preserved,
including CRLF). Numbering reflects the actual file lines, so a ranged
read starting at line 42 emits `42` for its first line, not `1`.
For large files, content returned by `get_buffer_content_or_outline` is
**not** prefixed:
- The symbol outline path already conveys structure via its `[L100-150]`
annotations.
- The truncated first-1KB fallback (used when a file exceeds
`AUTO_OUTLINE_SIZE` and has no parseable outline) is wrapped in a
synthetic `# First 1KB of …` header, so its lines don't correspond to
real file line numbers.
Both cases are reported via `BufferContent::is_synthetic` (renamed from
`is_outline`).
Also updates the `edit_file` tool's input doc to describe the prefix
format and tell the model to strip it before constructing `old_text` /
`new_text`, preserving the original indentation that appears after the
tab.
Updates how we render `read_file` tool call outputs in the UI
(screenshots included in comments below).
Also fixes an existing bug where `read_file` tool call outputs would not
re-render their content code block when an older thread was restored
(the tool's `replay` hook was missing).
Closes AI-226
Release Notes:
- Improved how `read_file` tool output renders in the agent panel, with
a line-number gutter, and fixed it not re-rendering on restored threads
---------
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
## Summary
- Hide deleted skills immediately in Settings while deletion completes
- Refresh the skill index after creating a skill so Settings updates
without reopening
Closes AI-299
Release Notes:
- Fixed skill management so newly created and deleted skills update in
Settings immediately.
When the agent mentions a file path inside `backticks` (e.g. ``
`src/main.rs` `` or `` `src/main.rs:42` ``), the rendered code span now
becomes a clickable link in the agent panel. Clicking opens the
referenced file in the workspace, jumping to the right line and column
when present.
## How it works
- **Shared path resolution.** Extracted `OpenTarget` and the
workspace/worktree resolution logic out of
`terminal_view::terminal_path_like_target` into a new
`workspace::path_link` module so both the terminal and the agent panel
can use the same code. Includes a `sanitize_path_text` helper ported
from the terminal's URL/punctuation handling. Pure refactor — terminal
behavior is unchanged.
- **`markdown` crate hook.** Added
`MarkdownElement::on_code_span_link(callback)`. When the callback
returns `Some(url)` for a given code span's contents, the existing
`push_link` machinery wires up cmd-hover, hit testing, and the existing
`on_url_click` callback. When it returns `None`, the code span renders
as before. The hook is opt-in, so `markdown` stays workspace-agnostic.
- **Agent panel wiring.** `render_agent_markdown` constructs an
`AgentCodeSpanResolver` that snapshots the project's visible worktree
entries plus their file extensions. `try_resolve` does a cheap
synchronous heuristic check (path must contain `/`/`\` or end in an
extension present in the workspace, can't be a URL, can't be all digits,
etc.) and then looks the candidate up in the per-worktree
`HashSet<Arc<RelPath>>`. On a hit it returns a `MentionUri::File` or
`MentionUri::Selection` URI, which the existing `thread_view::open_link`
already knows how to open at the right line.
## Edge cases handled
- Code spans inside fenced code blocks stay plain (gated on
`builder.code_block_stack.is_empty()`, matching how regular markdown
links behave).
- Trailing prose punctuation (`` `src/main.rs.` ``) is stripped before
lookup.
- Identifiers like `` `String` ``, `` `await` ``, `` `npm run dev` ``
stay plain — they don't pass the path-like heuristic.
- Cross-platform path separators handled via the per-worktree
`PathStyle`.
## Tests
- `crates/markdown` — unit test asserting code spans become links when
the callback returns `Some`, and stay plain when it doesn't.
- `crates/agent_ui` — unit test for `AgentCodeSpanResolver::try_resolve`
covering hits with and without a `:line` suffix, misses, identifiers,
and trailing punctuation.
- Existing `terminal_view` tests cover the moved resolution code
(unchanged behavior).
## Notes
- There's currently a temporary `log::info!` in
`AgentCodeSpanResolver::try_resolve` that reports per-call worktree-walk
timing and a cumulative total. Kept in for now to verify the feature
isn't being called excessively during streaming renders. Can be removed
before merge.
- Resolution is sync-only against worktree entries; absolute paths
outside the workspace are not resolved (would require an async re-render
path).
Closes AI-277
Release Notes:
- Made file paths in `backticks` clickable in the agent panel; clicking
opens the referenced file at the given line when present.
Clicking a built-in skill mention while connected to a remote project
(SSH or collab) caused Zed to abort with `called create_local_buffer on
a remote project`.
## Root cause
`agent_ui::ui::mention_crease::open_skill_file` was calling
`Project::create_local_buffer` to display the embedded read-only content
of a built-in skill:
```rust
let buffer = project.update(cx, |project, cx| {
project.create_local_buffer(content, None, false, cx)
});
```
`Project::create_local_buffer` has an explicit panic guard for remote
projects, so any user who clicked a built-in skill mention while in an
SSH or collab project would crash Zed.
## Fix
The buffer is purely a display surface for binary-embedded skill content
— it has no on-disk backing, isn't searchable, and never needs to be
tracked by the project's buffer store. Build it directly with
`language::Buffer::local(content, cx)` instead, matching the pattern
used elsewhere in `agent_ui` (`thread_view.rs`, `message_editor.rs`,
`inline_assistant.rs`, etc.). This works for both local and remote
projects.
## Repro (before fix)
1. Connect Zed to a remote (SSH) project.
2. In the agent panel, click on a built-in skill mention (e.g. one
referencing `create-skill`).
3. Zed aborts with SIGABRT.
After the fix, the mention opens a read-only editor with the embedded
markdown content, identical behavior to local projects.
Release Notes:
- Fixed a crash when clicking a built-in skill mention in the agent
panel while connected to a remote project
When `read_file` returns a file outline instead of full contents, the
result is now wrapped in a plain fenced code block rather than tagging
it with the file's path.
Previously, the outline was wrapped in a fenced block tagged with the
file path (e.g. `` ```crates/agent/src/tools/read_file_tool.rs ``).
Because the tag contains a slash, the markdown parser routed it through
`CodeBlockKind::FencedSrc`, resolved the file's language by path, and
ran the language's tree-sitter parser against the outline on every
paint. The outline is structural (e.g. `fn foo [L10-20]`), not actual
source for the file's language, so the parse was both expensive and
produced incorrect highlighting.
Because GPUI rebuilds the visible element tree on every window paint,
anything that triggers a repaint (cursor blink in the focused message
editor, animations, the turn timer, etc.) would re-run the tree-sitter
parse on the entire outline, throttling the frame rate while the tool
call was expanded.
This change adds an `is_outline_response` flag in `ReadFileTool::run`
and, when set, passes an empty tag to `MarkdownCodeBlock` so the
renderer sees `CodeBlockKind::Fenced` (no language). Plain monospace
formatting is preserved; the path tag is still used for the non-outline
(full file) case.
Adds two regression tests: one asserting the outline path uses an
untagged fenced block, and one asserting the full-file path keeps the
path tag (so the next person fixing this doesn't accidentally strip the
tag everywhere).
Also includes a small markdown-rendering follow-up:
`MarkdownElementBuilder::push_text` was recomputing the base text style
(cloning `base_text_style` and walking the style stack) twice per
highlighted token. For a code block with hundreds of highlight tokens,
that's hundreds of redundant `TextStyle` clones per paint. The style
stack does not change while runs are being attributed, so the style is
now computed once outside the loop and reused.
Closes AI-234
Release Notes:
- Improved scrolling smoothness in the agent panel when a `read_file`
tool call with a large file outline is expanded.
Replaces the legacy Rules creation UI with a focused "New Skill"
creation window when the `SkillsFeatureFlag` is on.
The new `skills_library` crate provides a single-skill form with:
- Name, Description, and Body fields (placeholders double as labels)
- Live validation matching the SKILL.md spec (name: 1–64 lowercase +
digits + hyphens, no leading/trailing hyphen; description: non-empty,
≤1024 chars)
- A scope dropdown listing every local worktree in the originating
workspace plus "Global"
- An Optional Parameters card with the `disable-model-invocation`
checkbox
- Save writes `<scope>/.agents/skills/<name>/SKILL.md` via
`serde_yaml_ng` (YAML-safe escaping), refuses to overwrite existing
skills, shows a success toast in the originating workspace, then closes
the window
The "Rules" entry in the agent panel triple-dot menu is renamed to
"Skills" when the flag is on. The existing `cmd-alt-l` keyboard shortcut
still works: `AgentPanel::deploy_rules_library` reroutes to
`deploy_skills_library` when the flag is on, so any persisted keymaps
and the menu's automatic shortcut lookup keep functioning without
changes to the default keymap files.
The old `rules_library` crate is intentionally left in place for this PR
— once the flag rolls out and the few remaining `OpenRulesLibrary {
prompt_to_select }` call sites (in thread_view link handlers and
@-mention crease) are migrated to an "open existing skill" flow, a
follow-up can delete the crate entirely.
15 unit tests cover the validation rules, frontmatter formatting
(including YAML-special-character round-tripping), and disk write
behavior (creates directory, refuses overwrite).
Closes AI-247
Release Notes:
- Added a new Skills creation UI that replaces the old Rules library
when the Skills feature flag is enabled.
---------
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Replaces the `@rule` autocomplete entry in the agent chat input with
`@skill`, since Zed Rules are being deprecated in favor of Skills.
Behavior matches the old `@rule` flow: selecting a skill inserts a Skill
mention crease that loads the skill file as context, and the entry only
appears when there are available skills.
The underlying `MentionUri::Rule` parsing/handling is left in place so
previously saved rule mentions still load correctly — only the
autocomplete surface area was migrated.
Release Notes:
- Replaced the `@rule` autocomplete entry with `@skill` in the agent
chat input.
Hides the legacy Rules surfaces when the `skills` feature flag is
enabled, since Rules are surfaced through the Skills UI in that case:
- The **Rules** entry in the agent panel's ellipsis (triple-dot)
dropdown menu is hidden.
- The `assistant: open rules library` command palette action is hidden.
The `@rules` autocomplete in the chat input is intentionally left alone
for now.
### Implementation notes
`cx.has_flag::<SkillsFeatureFlag>()` reads from a global feature-flag
store that is populated asynchronously from the server:
- **Command palette**: `update_command_palette_filter` is already re-run
via `cx.on_flags_ready` once flags arrive, so the filter is reapplied
with the correct value. No new wiring needed.
- **Dropdown menu**: the popover's menu closure runs on every open, so
the latest flag value is reflected at click time.
Release Notes:
- N/A