Skip to content

feat(acp): add read tool and delegate filesystem I/O to ACP clients#7668

Merged
codefromthecrypt merged 2 commits intomainfrom
adrian/acp-fs-delegation
Mar 11, 2026
Merged

feat(acp): add read tool and delegate filesystem I/O to ACP clients#7668
codefromthecrypt merged 2 commits intomainfrom
adrian/acp-fs-delegation

Conversation

@codefromthecrypt
Copy link
Collaborator

@codefromthecrypt codefromthecrypt commented Mar 5, 2026

Summary

ACP file system methods (fs/read_text_file and fs/write_text_file) let agents delegate file I/O to the editor instead of hitting disk directly. Reads can return unsaved editor state, and writes let the editor track modifications (Zed shows a native diff). The client advertises support via clientCapabilities.fs during initialize.

When ACP fs capabilities are present, an AcpTools decorator wraps DeveloperClient and intercepts the three filesystem tools (read, write, edit), delegating I/O to the client. All other tools (shell, tree, etc.) pass through to the inner client untouched. Non-ACP sessions use the developer extension directly with fs-err for local I/O.

AcpTools injects the read tool only when the client advertises fs.readTextFile. Non-ACP sessions have no read tool — the model uses shell for reads, matching the existing developer extension design. This follows the "tool not offered" pattern used by claude-agent-acp, fast-agent, and mistral-vibe.

File tools now self-report their locations via CallToolResult.meta with a tool_locations key, replacing post-hoc argument extraction for read/write/edit. Shell tool location extraction remains as a fallback.

The ACP-wrapped developer extension now preserves its instructions in system prompts (previously dropped by add_client passing None for server_info).

Type of Change

  • Feature
  • Tests

AI Assistance

  • This PR was created or reviewed with AI assistance

Testing

Base Case (no ACP):
No ACP client, so DeveloperClient handles I/O directly via fs-err. Output contains test-write-content-67890.

$ just release-binary
$ echo test-read-content-12345 > /tmp/test_acp_fs.txt
$ RUST_LOG=debug target/release/goose run \
  --with-builtin developer \
  -t "Use the write tool to write 'test-write-content-67890' to /tmp/test_acp_write.txt"

    __( O)>  ● new session · tetrate gpt-5-nano
   \____)    20260311_16 · /Users/codefromthecrypt/oss/goose-goosed
     L L     goose is ready

  ▸ write
    path /tmp/test_acp_write.txt
    content: test-write-content-67890

Created /tmp/test_acp_write.txt (1 lines)Done. Wrote to /tmp/test_acp_write.txt: test-write-content-67890

Zed

Clear logs and session/thread state:

$ pkill -f goose && rm -rf ~/.local/state/goose/logs ~/.local/share/goose/sessions ~/Library/Logs/Zed/ ~/Library/Application\ Support/Zed/threads/threads.db

Add to ~/.config/zed/settings.json:

"agent_servers": {
  "goose": {
    "type": "custom",
    "command": "/Users/codefromthecrypt/oss/goose-goosed/target/release/goose",
    "args": ["acp", "--with-builtin", "developer"],
    "env": {
      "RUST_LOG": "debug"
    }
  }
}

Read delegation:

Make a file called test.txt and save it empty. Then add "marry had a little dog" to its buffer without saving.

Prompt in Zed:

what is the buffer state of @test.txt?

Verify the ACP interactions in Goose. Zed has no telemetry or logs about ACP:

$ grep -h read_text_file ~/.local/state/goose/logs/cli/*/*.log
{"timestamp":"2026-03-11T09:24:57.752099Z","level":"DEBUG","fields":{"message":"initialize request","args":"InitializeRequest { protocol_version: ProtocolVersion(1), client_capabilities: ClientCapabilities { fs: FileSystemCapability { read_text_file: true, write_text_file: true, meta: None }, terminal: true, meta: Some({\"terminal_output\": Bool(true), \"terminal-auth\": Bool(true)}) }, client_info: Some(Implementation { name: \"zed\", title: Some(\"Zed\"), version: \"0.226.5+stable.197.07dae3b7020b0ad79ed91e18c750a16952432866\", meta: None }), meta: None }"},"target":"goose_acp::server","span":{"name":"goose-acp","name":"connection"},"spans":[{"name":"goose-acp","name":"connection"}]}
{"timestamp":"2026-03-11T09:25:20.122818Z","level":"DEBUG","fields":{"message":"outgoing_protocol_actor","message":"Request { method: \"fs/read_text_file\", params: Some(Object({\"sessionId\": String(\"20260311_1\"), \"path\": String(\"/Users/codefromthecrypt/test.txt\"), \"line\": Number(1), \"limit\": Number(10)})), response_tx: Sender { complete: false } }"},"target":"sacp::jsonrpc::outgoing_actor","span":{"name":"goose-acp","name":"connection"},"spans":[{"name":"goose-acp","name":"connection"}]}

Write delegation + diff view:

Prompt in Zed:

Change it to "marry had a little lambda"

Verify the ACP interactions in Goose. Zed has no telemetry or logs about ACP:

$ grep -h write_text_file ~/.local/state/goose/logs/cli/*/*.log
{"timestamp":"2026-03-11T09:24:57.752099Z","level":"DEBUG","fields":{"message":"initialize request","args":"InitializeRequest { protocol_version: ProtocolVersion(1), client_capabilities: ClientCapabilities { fs: FileSystemCapability { read_text_file: true, write_text_file: true, meta: None }, terminal: true, meta: Some({\"terminal_output\": Bool(true), \"terminal-auth\": Bool(true)}) }, client_info: Some(Implementation { name: \"zed\", title: Some(\"Zed\"), version: \"0.226.5+stable.197.07dae3b7020b0ad79ed91e18c750a16952432866\", meta: None }), meta: None }"},"target":"goose_acp::server","span":{"name":"goose-acp","name":"connection"},"spans":[{"name":"goose-acp","name":"connection"}]}
{"timestamp":"2026-03-11T09:26:11.858091Z","level":"DEBUG","fields":{"message":"outgoing_protocol_actor","message":"Request { method: \"fs/write_text_file\", params: Some(Object({\"sessionId\": String(\"20260311_1\"), \"path\": String(\"/Users/codefromthecrypt/test.txt\"), \"content\": String(\"marry had a little lambda\")})), response_tx: Sender { complete: false } }"},"target":"sacp::jsonrpc::outgoing_actor","span":{"name":"goose-acp","name":"connection"},"spans":[{"name":"goose-acp","name":"connection"}]}

Related Issues

Fixes #7451
Replaces #6940
Uses design from #7388
RFD about symmetric file caps (only both true/both false in practice, but no guidance): agentclientprotocol/agent-client-protocol#662

Screenshots

read diff edit

@codefromthecrypt
Copy link
Collaborator Author

investigating how to adapt this to the same style as #7668 cc @jamadeo or if the diff is so much it is simpler to redo and copy the tests.

@codefromthecrypt codefromthecrypt changed the title feat(acp): add Fs trait for filesystem delegation feat(acp): add read tool and delegate filesystem I/O to ACP clients Mar 5, 2026
@codefromthecrypt codefromthecrypt requested review from DOsinga and jamadeo and removed request for DOsinga March 5, 2026 08:05
@codefromthecrypt codefromthecrypt marked this pull request as ready for review March 5, 2026 08:06
@codefromthecrypt
Copy link
Collaborator Author

@jamadeo so thanks very much for your idea on #7388 It is very elegant and I took it, but it is your credit the good part anyway ;)

The main change besides test backfill etc, IMHO, is that this is narrowed to fs-only, so that we don't need to update AcpTools when new developer tools are added.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90c3dabc8f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5073bc5a42

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f598194348

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff9fb9d226

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f1fd9312c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

pub async fn run_fs_read_text_file_true<C: Connection>() {
let temp_dir = tempfile::tempdir().unwrap();
let config_yaml = format!(
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions:\n developer:\n enabled: true\n type: platform\n name: developer\n description: Developer\n display_name: Developer\n bundled: true\n available_tools: []\n"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this satisfies copilot which rightly pointed out you can add developer explicitly in the config yaml, without splitting this into two tests in a file that will already get long. Other paths use the arg syntax.

Note: in the experimental acp-server we hard-code developer as always here, but this is technically possible to set in goose acp

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe0bae23e8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@codefromthecrypt codefromthecrypt force-pushed the adrian/acp-fs-delegation branch from fe0bae2 to 62a00ee Compare March 11, 2026 01:22
@codefromthecrypt
Copy link
Collaborator Author

rebased as there wasa a lot of drift.. still need to adjust for feedback but no time left today

When the ACP client declares FileSystemCapability (read_text_file
and/or write_text_file), the server wraps the developer extension
with AcpTools that routes read/write/edit tool calls through the
client instead of using local disk. This works regardless of whether
developer is registered via CLI builtins or config.yaml.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
@codefromthecrypt codefromthecrypt force-pushed the adrian/acp-fs-delegation branch from 62a00ee to 0ecef10 Compare March 11, 2026 03:40
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ecef1085d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Signed-off-by: Adrian Cole <adrian@tetrate.io>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 23654aaa7d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +77 to 79
pub(crate) fn get_tools() -> Vec<Tool> {
vec![
Tool::new(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Advertise the new read tool in developer tool list

call_tool now handles "read", but DeveloperClient::get_tools() still only returns write/edit/shell/tree, so the model never sees read in normal (non-ACP) sessions and in ACP sessions without fs_read delegation. That makes the headline feature effectively unreachable unless callers hard-code an undiscoverable tool name, which breaks the expected parity between CLI and ACP tool availability.

Useful? React with 👍 / 👎.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes codex that's the point!

This could be a case where a comment is useful -- if the model is confused, a human might be too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

@jamadeo jamadeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say merge sooner rather than later and we can always follow up on having the ACP tools themselves emit edit locations etc.

Comment on lines +77 to 79
pub(crate) fn get_tools() -> Vec<Tool> {
vec![
Tool::new(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes codex that's the point!

This could be a case where a comment is useful -- if the model is confused, a human might be too.

@codefromthecrypt codefromthecrypt added this pull request to the merge queue Mar 11, 2026
Merged via the queue into main with commit cb4d99d Mar 11, 2026
21 checks passed
@codefromthecrypt codefromthecrypt deleted the adrian/acp-fs-delegation branch March 11, 2026 13:31
lifeizhou-ap added a commit that referenced this pull request Mar 12, 2026
* main: (270 commits)
  test(acp): align provider and server test parity (#7822)
  fix(acp): register MCP extensions when resuming a session (#7806)
  fix(goose): load .gitignore in prompt_manager for hint file filtering (#7795)
  fix: remap max_completion_tokens to max_tokens for OpenAI-compatible providers (#7765)
  fix(openai): preserve Responses API tool call/output linkage (#7759)
  chore(deps): bump @hono/node-server from 1.19.9 to 1.19.11 in /evals/open-model-gym/mcp-harness (#7687)
  fix: return ContextLengthExceeded when prompt exceeds effective KV cache size (#7815)
  feat: MCP Roots support (#7790)
  fix(google): use `includeThoughts/part.thought` for thinking handling (#7593)
  refactor: simplify tokenizer initialization — remove unnecessary Result wrapper (#7744)
  Fix model selector showing wrong model in tabs (#7784)
  Stop collecting goosed stderr after startup (#7814)
  fix: avoid word splitting by space for windows shell commands (#7781) (#7810)
  Simplify and make it not break on linux (#7813)
  Add preferred microphone selection  (#7805)
  Remove dependency on posthog-rs (#7811)
  feat: load hints in nested subdirs (#7772)
  feat(acp): add read tool and delegate filesystem I/O to ACP clients (#7668)
  Support secret interpolation in streamable HTTP extension URLs (#7782)
  More logging for command injection classifier model training (#7779)
  ...
@jamadeo jamadeo mentioned this pull request Mar 12, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delegate developer extension file I/O through ACP fs methods

2 participants