diff --git a/Cargo.lock b/Cargo.lock
index 85dcffe..76d2a3b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6,29 +6,34 @@ version = 4
 name = "agent-client-protocol"
 version = "0.10.4"
 dependencies = [
+ "agent-client-protocol-derive",
  "agent-client-protocol-schema",
+ "agent-client-protocol-test",
  "anyhow",
- "async-broadcast",
- "async-trait",
- "derive_more",
- "env_logger",
+ "boxfnonce",
+ "clap",
+ "expect-test",
  "futures",
- "futures-util",
- "log",
- "piper",
- "pretty_assertions",
- "rustyline",
+ "futures-concurrency",
+ "jsonrpcmsg",
+ "rmcp",
+ "rustc-hash",
+ "schemars",
  "serde",
  "serde_json",
+ "shell-words",
+ "thiserror",
  "tokio",
  "tokio-util",
+ "tracing",
+ "uuid",
 ]
 
 [[package]]
 name = "agent-client-protocol-conductor"
-version = "0.1.0"
+version = "0.11.0"
 dependencies = [
- "agent-client-protocol-core",
+ "agent-client-protocol",
  "agent-client-protocol-schema",
  "agent-client-protocol-test",
  "agent-client-protocol-tokio",
@@ -63,10 +68,10 @@ dependencies = [
 
 [[package]]
 name = "agent-client-protocol-cookbook"
-version = "0.1.0"
+version = "0.11.0"
 dependencies = [
+ "agent-client-protocol",
  "agent-client-protocol-conductor",
- "agent-client-protocol-core",
  "agent-client-protocol-rmcp",
  "agent-client-protocol-tokio",
  "rmcp",
@@ -77,36 +82,9 @@ dependencies = [
  "tracing",
 ]
 
-[[package]]
-name = "agent-client-protocol-core"
-version = "0.1.0"
-dependencies = [
- "agent-client-protocol-derive",
- "agent-client-protocol-schema",
- "agent-client-protocol-test",
- "anyhow",
- "boxfnonce",
- "clap",
- "expect-test",
- "futures",
- "futures-concurrency",
- "jsonrpcmsg",
- "rmcp",
- "rustc-hash",
- "schemars",
- "serde",
- "serde_json",
- "shell-words",
- "thiserror",
- "tokio",
- "tokio-util",
- "tracing",
- "uuid",
-]
-
 [[package]]
 name = "agent-client-protocol-derive"
-version = "0.1.0"
+version = "0.11.0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -115,9 +93,9 @@ dependencies = [
 
 [[package]]
 name = "agent-client-protocol-rmcp"
-version = "0.1.0"
+version = "0.11.0"
 dependencies = [
- "agent-client-protocol-core",
+ "agent-client-protocol",
  "futures",
  "futures-concurrency",
  "rmcp",
@@ -145,9 +123,9 @@ dependencies = [
 
 [[package]]
 name = "agent-client-protocol-test"
-version = "0.1.0"
+version = "0.11.0"
 dependencies = [
- "agent-client-protocol-core",
+ "agent-client-protocol",
  "agent-client-protocol-tokio",
  "agent-client-protocol-yopo",
  "anyhow",
@@ -165,9 +143,9 @@ dependencies = [
 
 [[package]]
 name = "agent-client-protocol-tokio"
-version = "0.1.0"
+version = "0.11.0"
 dependencies = [
- "agent-client-protocol-core",
+ "agent-client-protocol",
  "agent-client-protocol-test",
  "expect-test",
  "futures",
@@ -180,7 +158,7 @@ dependencies = [
 
 [[package]]
 name = "agent-client-protocol-trace-viewer"
-version = "0.1.0"
+version = "0.11.0"
 dependencies = [
  "anyhow",
  "axum",
@@ -195,9 +173,9 @@ dependencies = [
 
 [[package]]
 name = "agent-client-protocol-yopo"
-version = "0.1.0"
+version = "0.11.0"
 dependencies = [
- "agent-client-protocol-core",
+ "agent-client-protocol",
  "agent-client-protocol-tokio",
  "clap",
  "tokio",
@@ -259,7 +237,7 @@ version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
 dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys",
 ]
 
 [[package]]
@@ -270,7 +248,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
 dependencies = [
  "anstyle",
  "once_cell_polyfill",
- "windows-sys 0.61.2",
+ "windows-sys",
 ]
 
 [[package]]
@@ -279,18 +257,6 @@ version = "1.0.102"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
 
-[[package]]
-name = "async-broadcast"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
-dependencies = [
- "event-listener",
- "event-listener-strategy",
- "futures-core",
- "pin-project-lite",
-]
-
 [[package]]
 name = "async-stream"
 version = "0.3.6"
@@ -494,30 +460,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
 
-[[package]]
-name = "clipboard-win"
-version = "5.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
-dependencies = [
- "error-code",
-]
-
 [[package]]
 name = "colorchoice"
 version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
 
-[[package]]
-name = "concurrent-queue"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
-dependencies = [
- "crossbeam-utils",
-]
-
 [[package]]
 name = "convert_case"
 version = "0.10.0"
@@ -614,12 +562,6 @@ dependencies = [
  "unicode-xid",
 ]
 
-[[package]]
-name = "diff"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
-
 [[package]]
 name = "displaydoc"
 version = "0.2.5"
@@ -643,35 +585,6 @@ version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
 
-[[package]]
-name = "endian-type"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
-
-[[package]]
-name = "env_filter"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef"
-dependencies = [
- "log",
- "regex",
-]
-
-[[package]]
-name = "env_logger"
-version = "0.11.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a"
-dependencies = [
- "anstream",
- "anstyle",
- "env_filter",
- "jiff",
- "log",
-]
-
 [[package]]
 name = "equivalent"
 version = "1.0.2"
@@ -685,34 +598,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
 dependencies = [
  "libc",
- "windows-sys 0.61.2",
-]
-
-[[package]]
-name = "error-code"
-version = "3.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
-
-[[package]]
-name = "event-listener"
-version = "5.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
-dependencies = [
- "concurrent-queue",
- "parking",
- "pin-project-lite",
-]
-
-[[package]]
-name = "event-listener-strategy"
-version = "0.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
-dependencies = [
- "event-listener",
- "pin-project-lite",
+ "windows-sys",
 ]
 
 [[package]]
@@ -731,17 +617,6 @@ version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
-[[package]]
-name = "fd-lock"
-version = "4.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
-dependencies = [
- "cfg-if",
- "rustix",
- "windows-sys 0.59.0",
-]
-
 [[package]]
 name = "find-msvc-tools"
 version = "0.1.9"
@@ -917,15 +792,6 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
-[[package]]
-name = "home"
-version = "0.5.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
-dependencies = [
- "windows-sys 0.61.2",
-]
-
 [[package]]
 name = "http"
 version = "1.4.0"
@@ -1218,30 +1084,6 @@ version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
 
-[[package]]
-name = "jiff"
-version = "0.2.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359"
-dependencies = [
- "jiff-static",
- "log",
- "portable-atomic",
- "portable-atomic-util",
- "serde_core",
-]
-
-[[package]]
-name = "jiff-static"
-version = "0.2.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
 [[package]]
 name = "js-sys"
 version = "0.3.94"
@@ -1282,12 +1124,6 @@ version = "0.2.183"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
 
-[[package]]
-name = "linux-raw-sys"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
-
 [[package]]
 name = "litemap"
 version = "0.8.1"
@@ -1354,28 +1190,7 @@ checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
 dependencies = [
  "libc",
  "wasi",
- "windows-sys 0.61.2",
-]
-
-[[package]]
-name = "nibble_vec"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
-name = "nix"
-version = "0.30.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
-dependencies = [
- "bitflags",
- "cfg-if",
- "cfg_aliases",
- "libc",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1396,7 +1211,7 @@ version = "0.50.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
 dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1510,32 +1325,6 @@ version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
 
-[[package]]
-name = "piper"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
-dependencies = [
- "atomic-waker",
- "fastrand",
- "futures-io",
-]
-
-[[package]]
-name = "portable-atomic"
-version = "1.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
-
-[[package]]
-name = "portable-atomic-util"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3"
-dependencies = [
- "portable-atomic",
-]
-
 [[package]]
 name = "potential_utf"
 version = "0.1.4"
@@ -1551,16 +1340,6 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
 
-[[package]]
-name = "pretty_assertions"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
-dependencies = [
- "diff",
- "yansi",
-]
-
 [[package]]
 name = "prettyplease"
 version = "0.2.37"
@@ -1588,7 +1367,7 @@ checksum = "2e842efad9119158434d193c6682e2ebee4b44d6ad801d7b349623b3f57cdf55"
 dependencies = [
  "futures",
  "indexmap",
- "nix 0.31.2",
+ "nix",
  "tokio",
  "tracing",
  "windows",
@@ -1609,16 +1388,6 @@ version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
 
-[[package]]
-name = "radix_trie"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
-dependencies = [
- "endian-type",
- "nibble_vec",
-]
-
 [[package]]
 name = "redox_syscall"
 version = "0.5.18"
@@ -1766,47 +1535,12 @@ dependencies = [
  "semver",
 ]
 
-[[package]]
-name = "rustix"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
-dependencies = [
- "bitflags",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.61.2",
-]
-
 [[package]]
 name = "rustversion"
 version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
 
-[[package]]
-name = "rustyline"
-version = "17.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e902948a25149d50edc1a8e0141aad50f54e22ba83ff988cf8f7c9ef07f50564"
-dependencies = [
- "bitflags",
- "cfg-if",
- "clipboard-win",
- "fd-lock",
- "home",
- "libc",
- "log",
- "memchr",
- "nix 0.30.1",
- "radix_trie",
- "unicode-segmentation",
- "unicode-width",
- "utf8parse",
- "windows-sys 0.60.2",
-]
-
 [[package]]
 name = "ryu"
 version = "1.0.23"
@@ -1978,7 +1712,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
 dependencies = [
  "libc",
- "windows-sys 0.61.2",
+ "windows-sys",
 ]
 
 [[package]]
@@ -2151,7 +1885,7 @@ dependencies = [
  "signal-hook-registry",
  "socket2",
  "tokio-macros",
- "windows-sys 0.61.2",
+ "windows-sys",
 ]
 
 [[package]]
@@ -2357,12 +2091,6 @@ version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
 
-[[package]]
-name = "unicode-width"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
-
 [[package]]
 name = "unicode-xid"
 version = "0.2.6"
@@ -2665,24 +2393,6 @@ dependencies = [
  "windows-link",
 ]
 
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.60.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
-dependencies = [
- "windows-targets 0.53.5",
-]
-
 [[package]]
 name = "windows-sys"
 version = "0.61.2"
@@ -2692,39 +2402,6 @@ dependencies = [
  "windows-link",
 ]
 
-[[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm 0.52.6",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.53.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
-dependencies = [
- "windows-link",
- "windows_aarch64_gnullvm 0.53.1",
- "windows_aarch64_msvc 0.53.1",
- "windows_i686_gnu 0.53.1",
- "windows_i686_gnullvm 0.53.1",
- "windows_i686_msvc 0.53.1",
- "windows_x86_64_gnu 0.53.1",
- "windows_x86_64_gnullvm 0.53.1",
- "windows_x86_64_msvc 0.53.1",
-]
-
 [[package]]
 name = "windows-threading"
 version = "0.2.1"
@@ -2734,102 +2411,6 @@ dependencies = [
  "windows-link",
 ]
 
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
-
 [[package]]
 name = "wit-bindgen"
 version = "0.51.0"
@@ -2924,12 +2505,6 @@ version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
 
-[[package]]
-name = "yansi"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
-
 [[package]]
 name = "yoke"
 version = "0.8.1"
diff --git a/Cargo.toml b/Cargo.toml
index c7958e0..15abe75 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,7 +3,6 @@ members = [
     "src/agent-client-protocol",
     "src/agent-client-protocol-conductor",
     "src/agent-client-protocol-cookbook",
-    "src/agent-client-protocol-core",
     "src/agent-client-protocol-derive",
     "src/agent-client-protocol-rmcp",
     "src/agent-client-protocol-test",
@@ -22,14 +21,14 @@ homepage = "https://github.com/agentclientprotocol/rust-sdk"
 
 [workspace.dependencies]
 # Internal crates
-agent-client-protocol-conductor = { path = "src/agent-client-protocol-conductor", version = "0.1.0" }
-agent-client-protocol-core = { path = "src/agent-client-protocol-core", version = "0.1.0" }
-agent-client-protocol-derive = { path = "src/agent-client-protocol-derive", version = "0.1.0" }
-agent-client-protocol-rmcp = { path = "src/agent-client-protocol-rmcp", version = "0.1.0" }
-agent-client-protocol-test = { path = "src/agent-client-protocol-test", version = "0.1.0" }
-agent-client-protocol-tokio = { path = "src/agent-client-protocol-tokio", version = "0.1.0" }
-agent-client-protocol-trace-viewer = { path = "src/agent-client-protocol-trace-viewer", version = "0.1.0" }
-yopo = { package = "agent-client-protocol-yopo", path = "src/yopo", version = "0.1.0" }
+agent-client-protocol = { path = "src/agent-client-protocol", version = "0.10.4" }
+agent-client-protocol-conductor = { path = "src/agent-client-protocol-conductor", version = "0.11.0" }
+agent-client-protocol-derive = { path = "src/agent-client-protocol-derive", version = "0.11.0" }
+agent-client-protocol-rmcp = { path = "src/agent-client-protocol-rmcp", version = "0.11.0" }
+agent-client-protocol-test = { path = "src/agent-client-protocol-test", version = "0.11.0" }
+agent-client-protocol-tokio = { path = "src/agent-client-protocol-tokio", version = "0.11.0" }
+agent-client-protocol-trace-viewer = { path = "src/agent-client-protocol-trace-viewer", version = "0.11.0" }
+yopo = { package = "agent-client-protocol-yopo", path = "src/yopo", version = "0.11.0" }
 
 # Core async runtime
 tokio = { version = "1.48", features = ["full"] }
diff --git a/src/agent-client-protocol-conductor/Cargo.toml b/src/agent-client-protocol-conductor/Cargo.toml
index d3da12d..5f35da6 100644
--- a/src/agent-client-protocol-conductor/Cargo.toml
+++ b/src/agent-client-protocol-conductor/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "agent-client-protocol-conductor"
-version = "0.1.0"
+version = "0.11.0"
 edition.workspace = true
 authors.workspace = true
 license.workspace = true
@@ -18,7 +18,7 @@ path = "src/main.rs"
 test-support = []
 
 [dependencies]
-agent-client-protocol-core.workspace = true
+agent-client-protocol.workspace = true
 agent-client-protocol-schema.workspace = true
 agent-client-protocol-tokio.workspace = true
 agent-client-protocol-trace-viewer.workspace = true
diff --git a/src/agent-client-protocol-conductor/README.md b/src/agent-client-protocol-conductor/README.md
index 8b3e62c..f94965b 100644
--- a/src/agent-client-protocol-conductor/README.md
+++ b/src/agent-client-protocol-conductor/README.md
@@ -64,7 +64,7 @@ Binary will be at `target/release/agent-client-protocol-conductor`.
 
 ## Related Crates
 
-- **[agent-client-protocol-core](../agent-client-protocol-core/)** — Core ACP protocol types and traits
+- **[agent-client-protocol](../agent-client-protocol/)** — Core ACP protocol types and traits
 - **[agent-client-protocol-tokio](../agent-client-protocol-tokio/)** — Tokio utilities for process spawning
 - **[agent-client-protocol-trace-viewer](../agent-client-protocol-trace-viewer/)** — Interactive trace visualization
 
diff --git a/src/agent-client-protocol-conductor/src/conductor.rs b/src/agent-client-protocol-conductor/src/conductor.rs
index 9ca1641..4bc2557 100644
--- a/src/agent-client-protocol-conductor/src/conductor.rs
+++ b/src/agent-client-protocol-conductor/src/conductor.rs
@@ -112,19 +112,19 @@
 
 use std::{collections::HashMap, sync::Arc};
 
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     Agent, BoxFuture, Client, Conductor, ConnectTo, Dispatch, DynConnectTo, Error, JsonRpcMessage,
     Proxy, Role, RunWithConnectionTo, role::HasPeer, util::MatchDispatch,
 };
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     Builder, ConnectionTo, JsonRpcNotification, JsonRpcRequest, SentRequest, UntypedMessage,
 };
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     HandleDispatchFrom,
     schema::{InitializeProxyRequest, InitializeRequest, NewSessionRequest},
     util::MatchDispatchFrom,
 };
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     Handled,
     schema::{
         McpConnectRequest, McpConnectResponse, McpDisconnectNotification, McpOverAcpMessage,
@@ -226,12 +226,12 @@ impl<Host: ConductorHostRole> ConductorImpl<Host> {
     pub async fn run(
         self,
         transport: impl ConnectTo<Host>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         let (conductor_tx, conductor_rx) = mpsc::channel(128 /* chosen arbitrarily */);
 
         // Set up tracing if enabled - spawn writer task and get handle
         let trace_handle;
-        let trace_future: BoxFuture<'static, Result<(), agent_client_protocol_core::Error>>;
+        let trace_future: BoxFuture<'static, Result<(), agent_client_protocol::Error>>;
         if let Some((h, f)) = self.trace_writer.map(super::trace::TraceWriter::spawn) {
             trace_handle = Some(h);
             trace_future = Box::pin(f);
@@ -248,7 +248,7 @@ impl<Host: ConductorHostRole> ConductorImpl<Host> {
             bridge_connections: HashMap::default(),
             mcp_bridge_mode: self.mcp_bridge_mode,
             proxies: Vec::default(),
-            successor: Arc::new(agent_client_protocol_core::util::internal_error(
+            successor: Arc::new(agent_client_protocol::util::internal_error(
                 "successor not initialized",
             )),
             trace_handle,
@@ -272,27 +272,27 @@ impl<Host: ConductorHostRole> ConductorImpl<Host> {
     async fn incoming_message_from_client(
         conductor_tx: &mut mpsc::Sender<ConductorMessage>,
         message: Dispatch,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         conductor_tx
             .send(ConductorMessage::LeftToRight {
                 target_component_index: 0,
                 message,
             })
             .await
-            .map_err(agent_client_protocol_core::util::internal_error)
+            .map_err(agent_client_protocol::util::internal_error)
     }
 
     async fn incoming_message_from_agent(
         conductor_tx: &mut mpsc::Sender<ConductorMessage>,
         message: Dispatch,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         conductor_tx
             .send(ConductorMessage::RightToLeft {
                 source_component_index: SourceComponentIndex::Successor,
                 message,
             })
             .await
-            .map_err(agent_client_protocol_core::util::internal_error)
+            .map_err(agent_client_protocol::util::internal_error)
     }
 }
 
@@ -300,7 +300,7 @@ impl<Host: ConductorHostRole> ConnectTo<Host::Counterpart> for ConductorImpl<Hos
     async fn connect_to(
         self,
         client: impl ConnectTo<Host>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         self.run(client).await
     }
 }
@@ -316,9 +316,8 @@ impl<Host: ConductorHostRole> HandleDispatchFrom<Host::Counterpart>
     async fn handle_dispatch_from(
         &mut self,
         message: Dispatch,
-        connection: agent_client_protocol_core::ConnectionTo<Host::Counterpart>,
-    ) -> Result<agent_client_protocol_core::Handled<Dispatch>, agent_client_protocol_core::Error>
-    {
+        connection: agent_client_protocol::ConnectionTo<Host::Counterpart>,
+    ) -> Result<agent_client_protocol::Handled<Dispatch>, agent_client_protocol::Error> {
         self.host
             .handle_dispatch(message, connection, &mut self.conductor_tx)
             .await
@@ -397,7 +396,7 @@ where
     async fn run_with_connection_to(
         mut self,
         connection: ConnectionTo<Host::Counterpart>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         // Components are now spawned lazily in forward_initialize_request
         // when the first Initialize request is received.
 
@@ -446,7 +445,7 @@ where
         &mut self,
         client: ConnectionTo<Host::Counterpart>,
         message: ConductorMessage,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         tracing::debug!(?message, "handle_conductor_message");
 
         match message {
@@ -502,7 +501,7 @@ where
                                     connection,
                                 })
                                 .await
-                                .map_err(|_| agent_client_protocol_core::Error::internal_error()),
+                                .map_err(|_| agent_client_protocol::Error::internal_error()),
                             Err(_) => {
                                 // Error occurred, just drop the connection.
                                 Ok(())
@@ -582,7 +581,7 @@ where
         client: ConnectionTo<Host::Counterpart>,
         source_component_index: SourceComponentIndex,
         message: Dispatch<Req, N>,
-    ) -> Result<(), agent_client_protocol_core::Error>
+    ) -> Result<(), agent_client_protocol::Error>
     where
         Req::Response: Send,
     {
@@ -635,7 +634,7 @@ where
         client: ConnectionTo<Host::Counterpart>,
         source_component_index: usize,
         notification: N,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         tracing::debug!(
             source_component_index,
             proxies_len = self.proxies.len(),
@@ -665,7 +664,7 @@ where
         target_component_index: usize,
         message: Dispatch,
         client: ConnectionTo<Host::Counterpart>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         tracing::trace!(
             target_component_index,
             ?message,
@@ -739,7 +738,7 @@ where
         &mut self,
         client: ConnectionTo<Host::Counterpart>,
         proxy_components: Vec<DynConnectTo<Conductor>>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         assert!(self.proxies.is_empty());
 
         let num_proxies = proxy_components.len();
@@ -838,7 +837,7 @@ where
                                     message: dispatch.map(|r, cx| (r.message, cx), |n| n.message),
                                 })
                                 .await
-                                .map_err(agent_client_protocol_core::util::internal_error)
+                                .map_err(agent_client_protocol::util::internal_error)
                         })
                         .await
                         .otherwise(async |dispatch| {
@@ -865,11 +864,11 @@ where
                             conductor_tx
                                 .send(message)
                                 .await
-                                .map_err(agent_client_protocol_core::util::internal_error)
+                                .map_err(agent_client_protocol::util::internal_error)
                         })
                         .await
                 },
-                agent_client_protocol_core::on_receive_dispatch!(),
+                agent_client_protocol::on_receive_dispatch!(),
             )
     }
 
@@ -877,13 +876,13 @@ where
         &mut self,
         target_component_index: usize,
         message: Dispatch,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         tracing::debug!(?message, "forward_message_to_proxy");
 
         MatchDispatch::new(message)
             .if_request(async |_request: InitializeProxyRequest, responder| {
                 responder.respond_with_error(
-                    agent_client_protocol_core::Error::invalid_request()
+                    agent_client_protocol::Error::invalid_request()
                         .data("initialize/proxy requests are only sent by the conductor"),
                 )
             })
@@ -924,7 +923,7 @@ where
         MatchDispatch::new(message)
             .if_request(async |_request: InitializeProxyRequest, responder| {
                 responder.respond_with_error(
-                    agent_client_protocol_core::Error::invalid_request()
+                    agent_client_protocol::Error::invalid_request()
                         .data("initialize/proxy requests are only sent by the conductor"),
                 )
             })
@@ -958,7 +957,7 @@ where
                     self.bridge_connections
                         .get_mut(&connection_id)
                         .ok_or_else(|| {
-                            agent_client_protocol_core::util::internal_error(format!(
+                            agent_client_protocol::util::internal_error(format!(
                                 "unknown connection id: {connection_id}"
                             ))
                         })?
@@ -976,7 +975,7 @@ where
                 self.bridge_connections
                     .get_mut(&connection_id)
                     .ok_or_else(|| {
-                        agent_client_protocol_core::util::internal_error(format!(
+                        agent_client_protocol::util::internal_error(format!(
                             "unknown connection id: {connection_id}"
                         ))
                     })?
@@ -1056,10 +1055,7 @@ pub trait InstantiateProxies: Send {
         req: InitializeRequest,
     ) -> futures::future::BoxFuture<
         'static,
-        Result<
-            (InitializeRequest, Vec<DynConnectTo<Conductor>>),
-            agent_client_protocol_core::Error,
-        >,
+        Result<(InitializeRequest, Vec<DynConnectTo<Conductor>>), agent_client_protocol::Error>,
     >;
 }
 
@@ -1075,10 +1071,7 @@ where
         req: InitializeRequest,
     ) -> futures::future::BoxFuture<
         'static,
-        Result<
-            (InitializeRequest, Vec<DynConnectTo<Conductor>>),
-            agent_client_protocol_core::Error,
-        >,
+        Result<(InitializeRequest, Vec<DynConnectTo<Conductor>>), agent_client_protocol::Error>,
     > {
         Box::pin(async move {
             let components: Vec<DynConnectTo<Conductor>> =
@@ -1095,7 +1088,7 @@ where
     Fut: std::future::Future<
             Output = Result<
                 (InitializeRequest, Vec<DynConnectTo<Conductor>>),
-                agent_client_protocol_core::Error,
+                agent_client_protocol::Error,
             >,
         > + Send
         + 'static,
@@ -1105,10 +1098,7 @@ where
         req: InitializeRequest,
     ) -> futures::future::BoxFuture<
         'static,
-        Result<
-            (InitializeRequest, Vec<DynConnectTo<Conductor>>),
-            agent_client_protocol_core::Error,
-        >,
+        Result<(InitializeRequest, Vec<DynConnectTo<Conductor>>), agent_client_protocol::Error>,
     > {
         Box::pin(async move { (*self)(req).await })
     }
@@ -1135,7 +1125,7 @@ pub trait InstantiateProxiesAndAgent: Send {
                 Vec<DynConnectTo<Conductor>>,
                 DynConnectTo<Client>,
             ),
-            agent_client_protocol_core::Error,
+            agent_client_protocol::Error,
         >,
     >;
 }
@@ -1156,7 +1146,7 @@ impl<A: ConnectTo<Client> + 'static> InstantiateProxiesAndAgent for AgentOnly<A>
                 Vec<DynConnectTo<Conductor>>,
                 DynConnectTo<Client>,
             ),
-            agent_client_protocol_core::Error,
+            agent_client_protocol::Error,
         >,
     > {
         Box::pin(async move { Ok((req, Vec::new(), DynConnectTo::new(self.0))) })
@@ -1218,7 +1208,7 @@ impl InstantiateProxiesAndAgent for ProxiesAndAgent {
                 Vec<DynConnectTo<Conductor>>,
                 DynConnectTo<Client>,
             ),
-            agent_client_protocol_core::Error,
+            agent_client_protocol::Error,
         >,
     > {
         Box::pin(async move { Ok((req, self.proxies, self.agent)) })
@@ -1236,7 +1226,7 @@ where
                     Vec<DynConnectTo<Conductor>>,
                     DynConnectTo<Client>,
                 ),
-                agent_client_protocol_core::Error,
+                agent_client_protocol::Error,
             >,
         > + Send
         + 'static,
@@ -1252,7 +1242,7 @@ where
                 Vec<DynConnectTo<Conductor>>,
                 DynConnectTo<Client>,
             ),
-            agent_client_protocol_core::Error,
+            agent_client_protocol::Error,
         >,
     > {
         Box::pin(async move { (*self)(req).await })
@@ -1350,7 +1340,7 @@ pub trait ConductorHostRole: Role<Counterpart: HasPeer<Client>> {
         connection: ConnectionTo<Self::Counterpart>,
         instantiator: Self::Instantiator,
         responder: &mut ConductorResponder<Self>,
-    ) -> impl Future<Output = Result<Dispatch, agent_client_protocol_core::Error>> + Send;
+    ) -> impl Future<Output = Result<Dispatch, agent_client_protocol::Error>> + Send;
 
     /// Handle an incoming message from the client or conductor, depending on `Self`
     fn handle_dispatch(
@@ -1358,7 +1348,7 @@ pub trait ConductorHostRole: Role<Counterpart: HasPeer<Client>> {
         message: Dispatch,
         connection: ConnectionTo<Self::Counterpart>,
         conductor_tx: &mut mpsc::Sender<ConductorMessage>,
-    ) -> impl Future<Output = Result<Handled<Dispatch>, agent_client_protocol_core::Error>> + Send;
+    ) -> impl Future<Output = Result<Handled<Dispatch>, agent_client_protocol::Error>> + Send;
 }
 
 /// Conductor acting as an agent
@@ -1371,7 +1361,7 @@ impl ConductorHostRole for Agent {
         client_connection: ConnectionTo<Client>,
         instantiator: Self::Instantiator,
         responder: &mut ConductorResponder<Self>,
-    ) -> Result<Dispatch, agent_client_protocol_core::Error> {
+    ) -> Result<Dispatch, agent_client_protocol::Error> {
         let invalid_request = || Error::invalid_request().data("expected `initialize` request");
 
         // Not yet initialized - expect an initialize request.
@@ -1417,10 +1407,10 @@ impl ConductorHostRole for Agent {
                                     message: dispatch,
                                 })
                                 .await
-                                .map_err(agent_client_protocol_core::util::internal_error)
+                                .map_err(agent_client_protocol::util::internal_error)
                         }
                     },
-                    agent_client_protocol_core::on_receive_dispatch!(),
+                    agent_client_protocol::on_receive_dispatch!(),
                 ),
             agent_component,
         )?;
@@ -1440,7 +1430,7 @@ impl ConductorHostRole for Agent {
         message: Dispatch,
         client_connection: ConnectionTo<Client>,
         conductor_tx: &mut mpsc::Sender<ConductorMessage>,
-    ) -> Result<Handled<Dispatch>, agent_client_protocol_core::Error> {
+    ) -> Result<Handled<Dispatch>, agent_client_protocol::Error> {
         tracing::debug!(
             method = ?message.method(),
             "ConductorToClient::handle_dispatch"
@@ -1469,7 +1459,7 @@ impl ConductorHostRole for Proxy {
         client_connection: ConnectionTo<Conductor>,
         instantiator: Self::Instantiator,
         responder: &mut ConductorResponder<Self>,
-    ) -> Result<Dispatch, agent_client_protocol_core::Error> {
+    ) -> Result<Dispatch, agent_client_protocol::Error> {
         let invalid_request = || Error::invalid_request().data("expected `initialize` request");
 
         // Not yet initialized - expect an InitializeProxy request.
@@ -1514,7 +1504,7 @@ impl ConductorHostRole for Proxy {
         message: Dispatch,
         client_connection: ConnectionTo<Conductor>,
         conductor_tx: &mut mpsc::Sender<ConductorMessage>,
-    ) -> Result<Handled<Dispatch>, agent_client_protocol_core::Error> {
+    ) -> Result<Handled<Dispatch>, agent_client_protocol::Error> {
         tracing::debug!(
             method = ?message.method(),
             ?message,
@@ -1557,16 +1547,16 @@ pub trait ConductorSuccessor<Host: ConductorHostRole>: Send + Sync + 'static {
         message: Dispatch,
         connection_to_conductor: ConnectionTo<Host::Counterpart>,
         responder: &'a mut ConductorResponder<Host>,
-    ) -> BoxFuture<'a, Result<(), agent_client_protocol_core::Error>>;
+    ) -> BoxFuture<'a, Result<(), agent_client_protocol::Error>>;
 }
 
-impl<Host: ConductorHostRole> ConductorSuccessor<Host> for agent_client_protocol_core::Error {
+impl<Host: ConductorHostRole> ConductorSuccessor<Host> for agent_client_protocol::Error {
     fn send_message<'a>(
         &self,
         #[expect(unused_variables)] message: Dispatch,
         #[expect(unused_variables)] connection_to_conductor: ConnectionTo<Host::Counterpart>,
         #[expect(unused_variables)] responder: &'a mut ConductorResponder<Host>,
-    ) -> BoxFuture<'a, Result<(), agent_client_protocol_core::Error>> {
+    ) -> BoxFuture<'a, Result<(), agent_client_protocol::Error>> {
         let error = self.clone();
         Box::pin(std::future::ready(Err(error)))
     }
@@ -1590,7 +1580,7 @@ impl ConductorSuccessor<Proxy> for GrandSuccessor {
         message: Dispatch,
         connection: ConnectionTo<Conductor>,
         _responder: &'a mut ConductorResponder<Proxy>,
-    ) -> BoxFuture<'a, Result<(), agent_client_protocol_core::Error>> {
+    ) -> BoxFuture<'a, Result<(), agent_client_protocol::Error>> {
         Box::pin(async move {
             debug!("Proxy mode: forwarding successor message to conductor's successor");
             connection.send_proxied_message_to(Agent, message)
@@ -1607,7 +1597,7 @@ impl ConductorSuccessor<Agent> for ConnectionTo<Agent> {
         message: Dispatch,
         connection: ConnectionTo<Client>,
         responder: &'a mut ConductorResponder<Agent>,
-    ) -> BoxFuture<'a, Result<(), agent_client_protocol_core::Error>> {
+    ) -> BoxFuture<'a, Result<(), agent_client_protocol::Error>> {
         let connection_to_agent = self.clone();
         Box::pin(async move {
             debug!("Proxy mode: forwarding successor message to conductor's successor");
diff --git a/src/agent-client-protocol-conductor/src/conductor/mcp_bridge.rs b/src/agent-client-protocol-conductor/src/conductor/mcp_bridge.rs
index 4e9dae5..ed4b07a 100644
--- a/src/agent-client-protocol-conductor/src/conductor/mcp_bridge.rs
+++ b/src/agent-client-protocol-conductor/src/conductor/mcp_bridge.rs
@@ -5,8 +5,8 @@ pub mod stdio;
 use std::collections::HashMap;
 use std::path::PathBuf;
 
-use agent_client_protocol_core::schema::{McpServer, McpServerHttp, McpServerStdio};
-use agent_client_protocol_core::{ConnectionTo, Dispatch, Role};
+use agent_client_protocol::schema::{McpServer, McpServerHttp, McpServerStdio};
+use agent_client_protocol::{ConnectionTo, Dispatch, Role};
 use futures::{SinkExt, channel::mpsc};
 use tokio::net::TcpListener;
 use tracing::info;
@@ -40,14 +40,11 @@ impl McpBridgeConnection {
         Self { to_mcp_client_tx }
     }
 
-    pub async fn send(
-        &mut self,
-        message: Dispatch,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    pub async fn send(&mut self, message: Dispatch) -> Result<(), agent_client_protocol::Error> {
         self.to_mcp_client_tx
             .send(message)
             .await
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     }
 }
 
@@ -66,8 +63,8 @@ impl McpBridgeListeners {
         mcp_server: &mut McpServer,
         conductor_tx: &mpsc::Sender<ConductorMessage>,
         mcp_bridge_mode: &crate::McpBridgeMode,
-    ) -> Result<(), agent_client_protocol_core::Error> {
-        use agent_client_protocol_core::schema::McpServer;
+    ) -> Result<(), agent_client_protocol::Error> {
+        use agent_client_protocol::schema::McpServer;
 
         let McpServer::Http(http) = mcp_server else {
             return Ok(());
@@ -78,7 +75,7 @@ impl McpBridgeListeners {
         }
 
         if !http.headers.is_empty() {
-            return Err(agent_client_protocol_core::Error::internal_error());
+            return Err(agent_client_protocol::Error::internal_error());
         }
 
         let name = &http.name;
diff --git a/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/actor.rs b/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/actor.rs
index 2c15ad9..557e08c 100644
--- a/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/actor.rs
+++ b/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/actor.rs
@@ -1,4 +1,4 @@
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     ConnectTo, Dispatch, DynConnectTo, role::mcp, schema::McpDisconnectNotification,
 };
 use futures::{SinkExt as _, StreamExt as _, channel::mpsc};
@@ -34,7 +34,7 @@ impl McpBridgeConnectionActor {
         }
     }
 
-    pub async fn run(self, connection_id: String) -> Result<(), agent_client_protocol_core::Error> {
+    pub async fn run(self, connection_id: String) -> Result<(), agent_client_protocol::Error> {
         info!(connection_id, "MCP bridge connected");
 
         let McpBridgeConnectionActor {
@@ -51,17 +51,17 @@ impl McpBridgeConnectionActor {
                 {
                     let mut conductor_tx = conductor_tx.clone();
                     let connection_id = connection_id.clone();
-                    async move |message: agent_client_protocol_core::Dispatch, _cx| {
+                    async move |message: agent_client_protocol::Dispatch, _cx| {
                         conductor_tx
                             .send(ConductorMessage::McpClientToMcpServer {
                                 connection_id: connection_id.clone(),
                                 message,
                             })
                             .await
-                            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+                            .map_err(|_| agent_client_protocol::Error::internal_error())
                     }
                 },
-                agent_client_protocol_core::on_receive_dispatch!(),
+                agent_client_protocol::on_receive_dispatch!(),
             )
             // When we receive messages from the conductor, forward them to the MCP client
             .connect_with(transport, async move |mcp_connection_to_client| {
@@ -81,7 +81,7 @@ impl McpBridgeConnectionActor {
                 },
             })
             .await
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())?;
+            .map_err(|_| agent_client_protocol::Error::internal_error())?;
 
         result
     }
diff --git a/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/http.rs b/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/http.rs
index 2b90998..9ea579d 100644
--- a/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/http.rs
+++ b/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/http.rs
@@ -1,4 +1,4 @@
-use agent_client_protocol_core::{BoxFuture, Channel, ConnectTo, jsonrpcmsg::Message, role::mcp};
+use agent_client_protocol::{BoxFuture, Channel, ConnectTo, jsonrpcmsg::Message, role::mcp};
 use axum::{
     Router,
     extract::State,
@@ -27,7 +27,7 @@ pub async fn run_http_listener(
     tcp_listener: TcpListener,
     acp_url: String,
     mut conductor_tx: mpsc::Sender<ConductorMessage>,
-) -> Result<(), agent_client_protocol_core::Error> {
+) -> Result<(), agent_client_protocol::Error> {
     let (to_mcp_client_tx, to_mcp_client_rx) = mpsc::channel(128);
 
     // When we send this message to the conductor,
@@ -45,7 +45,7 @@ pub async fn run_http_listener(
             connection: McpBridgeConnection::new(to_mcp_client_tx),
         })
         .await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?;
+        .map_err(|_| agent_client_protocol::Error::internal_error())?;
 
     Ok(())
 }
@@ -66,7 +66,7 @@ impl ConnectTo<mcp::Client> for HttpMcpBridge {
     async fn connect_to(
         self,
         client: impl ConnectTo<mcp::Server>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         let (channel, serve_self) = self.into_channel_and_future();
         match futures::future::select(pin!(client.connect_to(channel)), serve_self).await {
             Either::Left((result, _)) | Either::Right((result, _)) => result,
@@ -77,7 +77,7 @@ impl ConnectTo<mcp::Client> for HttpMcpBridge {
         self,
     ) -> (
         Channel,
-        BoxFuture<'static, Result<(), agent_client_protocol_core::Error>>,
+        BoxFuture<'static, Result<(), agent_client_protocol::Error>>,
     )
     where
         Self: Sized,
@@ -90,11 +90,11 @@ impl ConnectTo<mcp::Client> for HttpMcpBridge {
 /// Error type that we use to respond to malformed HTTP requests.
 #[derive(Debug, thiserror::Error)]
 #[error(transparent)]
-struct HttpError(#[from] agent_client_protocol_core::Error);
+struct HttpError(#[from] agent_client_protocol::Error);
 
 impl From<axum::Error> for HttpError {
     fn from(error: axum::Error) -> Self {
-        HttpError(agent_client_protocol_core::util::internal_error(error))
+        HttpError(agent_client_protocol::util::internal_error(error))
     }
 }
 
@@ -107,10 +107,7 @@ impl IntoResponse for HttpError {
 
 /// Run a webserver listening on `listener` for HTTP requests at `/`
 /// and communicating those requests over `channel` to the JSON-RPC server.
-async fn run(
-    listener: TcpListener,
-    channel: Channel,
-) -> Result<(), agent_client_protocol_core::Error> {
+async fn run(listener: TcpListener, channel: Channel) -> Result<(), agent_client_protocol::Error> {
     let (registration_tx, registration_rx) = mpsc::unbounded();
 
     let state = BridgeState { registration_tx };
@@ -135,7 +132,7 @@ async fn run(
 
         axum::serve(listener, app)
             .await
-            .map_err(agent_client_protocol_core::util::internal_error)
+            .map_err(agent_client_protocol::util::internal_error)
     }
     .race(RunningServer::new().run(channel, registration_rx))
     .await
@@ -153,27 +150,27 @@ enum HttpMessage {
     /// A JSON-RPC request (has an id, expects a response via the channel)
     Request {
         http_request_id: uuid::Uuid,
-        request: agent_client_protocol_core::jsonrpcmsg::Request,
-        response_tx: mpsc::UnboundedSender<agent_client_protocol_core::jsonrpcmsg::Message>,
+        request: agent_client_protocol::jsonrpcmsg::Request,
+        response_tx: mpsc::UnboundedSender<agent_client_protocol::jsonrpcmsg::Message>,
     },
     /// A JSON-RPC notification (no id, no response expected)
     Notification {
         http_request_id: uuid::Uuid,
-        request: agent_client_protocol_core::jsonrpcmsg::Request,
+        request: agent_client_protocol::jsonrpcmsg::Request,
     },
     /// A JSON-RPC response from the client
     Response {
         http_request_id: uuid::Uuid,
-        response: agent_client_protocol_core::jsonrpcmsg::Response,
+        response: agent_client_protocol::jsonrpcmsg::Response,
     },
     /// A GET request to open an SSE stream for server-initiated messages
     Get {
         http_request_id: uuid::Uuid,
-        response_tx: mpsc::UnboundedSender<agent_client_protocol_core::jsonrpcmsg::Message>,
+        response_tx: mpsc::UnboundedSender<agent_client_protocol::jsonrpcmsg::Message>,
     },
 }
 
-/// Clone of `agent_client_protocol_core::jsonrpcmsg::Id` since for unfathomable reasons that does not impl Hash
+/// Clone of `agent_client_protocol::jsonrpcmsg::Id` since for unfathomable reasons that does not impl Hash
 #[derive(Eq, PartialEq, PartialOrd, Ord, Hash, Debug, Clone)]
 enum JsonRpcId {
     /// String identifier
@@ -184,12 +181,12 @@ enum JsonRpcId {
     Null,
 }
 
-impl From<agent_client_protocol_core::jsonrpcmsg::Id> for JsonRpcId {
-    fn from(id: agent_client_protocol_core::jsonrpcmsg::Id) -> Self {
+impl From<agent_client_protocol::jsonrpcmsg::Id> for JsonRpcId {
+    fn from(id: agent_client_protocol::jsonrpcmsg::Id) -> Self {
         match id {
-            agent_client_protocol_core::jsonrpcmsg::Id::String(s) => JsonRpcId::String(s),
-            agent_client_protocol_core::jsonrpcmsg::Id::Number(n) => JsonRpcId::Number(n),
-            agent_client_protocol_core::jsonrpcmsg::Id::Null => JsonRpcId::Null,
+            agent_client_protocol::jsonrpcmsg::Id::String(s) => JsonRpcId::String(s),
+            agent_client_protocol::jsonrpcmsg::Id::Number(n) => JsonRpcId::Number(n),
+            agent_client_protocol::jsonrpcmsg::Id::Null => JsonRpcId::Null,
         }
     }
 }
@@ -197,7 +194,7 @@ impl From<agent_client_protocol_core::jsonrpcmsg::Id> for JsonRpcId {
 struct RunningServer {
     waiting_sessions: FxHashMap<JsonRpcId, RegisteredSession>,
     general_sessions: Vec<RegisteredSession>,
-    message_deque: VecDeque<agent_client_protocol_core::jsonrpcmsg::Message>,
+    message_deque: VecDeque<agent_client_protocol::jsonrpcmsg::Message>,
 }
 
 impl RunningServer {
@@ -219,15 +216,12 @@ impl RunningServer {
         mut self,
         mut channel: Channel,
         http_rx: mpsc::UnboundedReceiver<HttpMessage>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         #[derive(Debug)]
         enum MultiplexMessage {
             FromHttpToChannel(HttpMessage),
             FromChannelToHttp(
-                Result<
-                    agent_client_protocol_core::jsonrpcmsg::Message,
-                    agent_client_protocol_core::Error,
-                >,
+                Result<agent_client_protocol::jsonrpcmsg::Message, agent_client_protocol::Error>,
             ),
         }
 
@@ -245,9 +239,9 @@ impl RunningServer {
 
                 MultiplexMessage::FromChannelToHttp(message) => {
                     let message = message.unwrap_or_else(|err| {
-                        agent_client_protocol_core::jsonrpcmsg::Message::Response(
-                            agent_client_protocol_core::jsonrpcmsg::Response::error(
-                                agent_client_protocol_core::util::into_jsonrpc_error(err),
+                        agent_client_protocol::jsonrpcmsg::Message::Response(
+                            agent_client_protocol::jsonrpcmsg::Response::error(
+                                agent_client_protocol::util::into_jsonrpc_error(err),
                                 None,
                             ),
                         )
@@ -274,12 +268,9 @@ impl RunningServer {
         &mut self,
         message: HttpMessage,
         channel_tx: &mut mpsc::UnboundedSender<
-            Result<
-                agent_client_protocol_core::jsonrpcmsg::Message,
-                agent_client_protocol_core::Error,
-            >,
+            Result<agent_client_protocol::jsonrpcmsg::Message, agent_client_protocol::Error>,
         >,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         match message {
             HttpMessage::Request {
                 http_request_id,
@@ -292,7 +283,7 @@ impl RunningServer {
                 // Send to the JSON-RPC server
                 channel_tx
                     .unbounded_send(Ok(Message::Request(request)))
-                    .map_err(agent_client_protocol_core::util::internal_error)?;
+                    .map_err(agent_client_protocol::util::internal_error)?;
 
                 // Register to receive the response
                 let session = RegisteredSession::new(response_tx);
@@ -314,7 +305,7 @@ impl RunningServer {
                 // Just forward to the server, no response tracking needed
                 channel_tx
                     .unbounded_send(Ok(Message::Request(request)))
-                    .map_err(agent_client_protocol_core::util::internal_error)?;
+                    .map_err(agent_client_protocol::util::internal_error)?;
             }
 
             HttpMessage::Response {
@@ -325,7 +316,7 @@ impl RunningServer {
                 // Forward to the server
                 channel_tx
                     .unbounded_send(Ok(Message::Response(response)))
-                    .map_err(agent_client_protocol_core::util::internal_error)?;
+                    .map_err(agent_client_protocol::util::internal_error)?;
             }
 
             HttpMessage::Get {
@@ -389,8 +380,8 @@ impl RunningServer {
     /// If there is no place to send it, returns `Some(message)`.
     fn try_dispatch_jsonrpc_message(
         &mut self,
-        mut message: agent_client_protocol_core::jsonrpcmsg::Message,
-    ) -> Option<agent_client_protocol_core::jsonrpcmsg::Message> {
+        mut message: agent_client_protocol::jsonrpcmsg::Message,
+    ) -> Option<agent_client_protocol::jsonrpcmsg::Message> {
         // Extract the id of the message we are replying to, if any
         let message_id = match &message {
             Message::Response(response) => response.id.as_ref().map(|v| v.clone().into()),
@@ -467,13 +458,11 @@ impl RunningServer {
 
 struct RegisteredSession {
     id: uuid::Uuid,
-    outgoing_tx: mpsc::UnboundedSender<agent_client_protocol_core::jsonrpcmsg::Message>,
+    outgoing_tx: mpsc::UnboundedSender<agent_client_protocol::jsonrpcmsg::Message>,
 }
 
 impl RegisteredSession {
-    fn new(
-        outgoing_tx: mpsc::UnboundedSender<agent_client_protocol_core::jsonrpcmsg::Message>,
-    ) -> Self {
+    fn new(outgoing_tx: mpsc::UnboundedSender<agent_client_protocol::jsonrpcmsg::Message>) -> Self {
         Self {
             id: uuid::Uuid::new_v4(),
             outgoing_tx,
@@ -491,8 +480,8 @@ async fn handle_post(
     let http_request_id = uuid::Uuid::new_v4();
 
     // Parse incoming JSON-RPC message
-    let message: agent_client_protocol_core::jsonrpcmsg::Message =
-        serde_json::from_str(&body).map_err(agent_client_protocol_core::util::parse_error)?;
+    let message: agent_client_protocol::jsonrpcmsg::Message =
+        serde_json::from_str(&body).map_err(agent_client_protocol::util::parse_error)?;
 
     match message {
         Message::Request(request) if request.id.is_some() => {
@@ -506,7 +495,7 @@ async fn handle_post(
                     request,
                     response_tx: tx,
                 })
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             let stream = async_stream::stream! {
                 while let Some(message) = rx.next().await {
@@ -530,7 +519,7 @@ async fn handle_post(
                     http_request_id,
                     request,
                 })
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
             Ok(StatusCode::ACCEPTED.into_response())
         }
 
@@ -543,7 +532,7 @@ async fn handle_post(
                     http_request_id,
                     response,
                 })
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
             Ok(StatusCode::ACCEPTED.into_response())
         }
     }
@@ -564,7 +553,7 @@ async fn handle_get(
             http_request_id,
             response_tx: tx,
         })
-        .map_err(agent_client_protocol_core::util::internal_error)?;
+        .map_err(agent_client_protocol::util::internal_error)?;
 
     let stream = async_stream::stream! {
         while let Some(message) = rx.next().await {
diff --git a/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/stdio.rs b/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/stdio.rs
index 3b15c64..fd85ee4 100644
--- a/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/stdio.rs
+++ b/src/agent-client-protocol-conductor/src/conductor/mcp_bridge/stdio.rs
@@ -1,4 +1,4 @@
-use agent_client_protocol_core::Dispatch;
+use agent_client_protocol::Dispatch;
 use futures::{SinkExt, channel::mpsc};
 use tokio::net::{TcpListener, TcpStream};
 use tokio_util::compat::{TokioAsyncReadCompatExt as _, TokioAsyncWriteCompatExt as _};
@@ -16,13 +16,13 @@ pub async fn run_tcp_listener(
     tcp_listener: TcpListener,
     acp_url: String,
     mut conductor_tx: mpsc::Sender<ConductorMessage>,
-) -> Result<(), agent_client_protocol_core::Error> {
+) -> Result<(), agent_client_protocol::Error> {
     // Accept connections
     loop {
         let (stream, _addr) = tcp_listener
             .accept()
             .await
-            .map_err(agent_client_protocol_core::Error::into_internal_error)?;
+            .map_err(agent_client_protocol::Error::into_internal_error)?;
 
         let (to_mcp_client_tx, to_mcp_client_rx) = mpsc::channel(128);
 
@@ -33,7 +33,7 @@ pub async fn run_tcp_listener(
                 connection: McpBridgeConnection::new(to_mcp_client_tx),
             })
             .await
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())?;
+            .map_err(|_| agent_client_protocol::Error::internal_error())?;
     }
 }
 
@@ -48,7 +48,7 @@ fn make_stdio_actor(
     // The bridge will send MCP requests (tools/call, etc.) to the conductor
     // The conductor can also send responses back
     let transport =
-        agent_client_protocol_core::ByteStreams::new(write_half.compat_write(), read_half.compat());
+        agent_client_protocol::ByteStreams::new(write_half.compat_write(), read_half.compat());
 
     McpBridgeConnectionActor::new(transport, conductor_tx, to_mcp_client_rx)
 }
diff --git a/src/agent-client-protocol-conductor/src/lib.rs b/src/agent-client-protocol-conductor/src/lib.rs
index f1ecba0..1878c73 100644
--- a/src/agent-client-protocol-conductor/src/lib.rs
+++ b/src/agent-client-protocol-conductor/src/lib.rs
@@ -71,7 +71,7 @@
 //! ## Related Crates
 //!
 //! - **[agent-client-protocol-proxy](https://crates.io/crates/agent-client-protocol-proxy)** - Framework for building proxy components
-//! - **[agent-client-protocol-core](https://crates.io/crates/agent-client-protocol-core)** - Core ACP SDK
+//! - **[agent-client-protocol](https://crates.io/crates/agent-client-protocol)** - Core ACP SDK
 //! - **[agent-client-protocol-tokio](https://crates.io/crates/agent-client-protocol-tokio)** - Tokio utilities for process spawning
 
 use std::path::PathBuf;
@@ -91,7 +91,7 @@ pub use self::conductor::*;
 
 use clap::{Parser, Subcommand};
 
-use agent_client_protocol_core::{Client, Conductor, DynConnectTo, schema::InitializeRequest};
+use agent_client_protocol::{Client, Conductor, DynConnectTo, schema::InitializeRequest};
 use agent_client_protocol_tokio::{AcpAgent, Stdio};
 use tracing::Instrument;
 use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
@@ -111,10 +111,7 @@ impl InstantiateProxies for CommandLineComponents {
         req: InitializeRequest,
     ) -> futures::future::BoxFuture<
         'static,
-        Result<
-            (InitializeRequest, Vec<DynConnectTo<Conductor>>),
-            agent_client_protocol_core::Error,
-        >,
+        Result<(InitializeRequest, Vec<DynConnectTo<Conductor>>), agent_client_protocol::Error>,
     > {
         Box::pin(async move {
             let proxies = self.0.into_iter().map(DynConnectTo::new).collect();
@@ -135,7 +132,7 @@ impl InstantiateProxiesAndAgent for CommandLineComponents {
                 Vec<DynConnectTo<Conductor>>,
                 DynConnectTo<Client>,
             ),
-            agent_client_protocol_core::Error,
+            agent_client_protocol::Error,
         >,
     > {
         Box::pin(async move {
@@ -153,7 +150,7 @@ impl InstantiateProxiesAndAgent for CommandLineComponents {
                 }
             }
 
-            Err(agent_client_protocol_core::util::internal_error(
+            Err(agent_client_protocol::util::internal_error(
                 "no agent component in list",
             ))
         })
@@ -329,7 +326,7 @@ impl ConductorArgs {
         self,
         debug_logger: Option<&debug_logger::DebugLogger>,
         trace_writer: Option<trace::TraceWriter>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         match self.command {
             ConductorCommand::Agent { name, components } => {
                 initialize_conductor(
@@ -366,7 +363,7 @@ async fn initialize_conductor<Host: ConductorHostRole>(
         CommandLineComponents,
         crate::McpBridgeMode,
     ) -> ConductorImpl<Host>,
-) -> Result<(), agent_client_protocol_core::Error> {
+) -> Result<(), agent_client_protocol::Error> {
     // Parse agents and optionally wrap with debug callbacks
     let providers: Vec<AcpAgent> = components
         .into_iter()
@@ -378,7 +375,7 @@ async fn initialize_conductor<Host: ConductorHostRole>(
             }
             Ok(agent)
         })
-        .collect::<Result<Vec<_>, agent_client_protocol_core::Error>>()?;
+        .collect::<Result<Vec<_>, agent_client_protocol::Error>>()?;
 
     // Create Stdio component with optional debug logging
     let stdio = if let Some(logger) = debug_logger {
diff --git a/src/agent-client-protocol-conductor/src/mcp_bridge.rs b/src/agent-client-protocol-conductor/src/mcp_bridge.rs
index d6b3ca0..9d60825 100644
--- a/src/agent-client-protocol-conductor/src/mcp_bridge.rs
+++ b/src/agent-client-protocol-conductor/src/mcp_bridge.rs
@@ -15,7 +15,7 @@ use tokio::net::TcpStream;
 ///
 /// Reads MCP JSON-RPC messages from stdin, forwards to TCP connection.
 /// Reads responses from TCP, writes to stdout.
-pub async fn run_mcp_bridge(port: u16) -> Result<(), agent_client_protocol_core::Error> {
+pub async fn run_mcp_bridge(port: u16) -> Result<(), agent_client_protocol::Error> {
     tracing::info!("MCP bridge starting, connecting to localhost:{}", port);
 
     // Connect to the main conductor via TCP
@@ -92,7 +92,7 @@ pub async fn run_mcp_bridge(port: u16) -> Result<(), agent_client_protocol_core:
 }
 
 /// Connect to TCP port with retry logic
-async fn connect_with_retry(port: u16) -> Result<TcpStream, agent_client_protocol_core::Error> {
+async fn connect_with_retry(port: u16) -> Result<TcpStream, agent_client_protocol::Error> {
     let max_retries = 10;
     let mut retry_delay_ms = 50;
 
@@ -113,7 +113,7 @@ async fn connect_with_retry(port: u16) -> Result<TcpStream, agent_client_protoco
                 retry_delay_ms = (retry_delay_ms * 2).min(1000); // Exponential backoff, max 1s
             }
             Err(e) => {
-                return Err(agent_client_protocol_core::Error::into_internal_error(e));
+                return Err(agent_client_protocol::Error::into_internal_error(e));
             }
         }
     }
diff --git a/src/agent-client-protocol-conductor/src/snoop.rs b/src/agent-client-protocol-conductor/src/snoop.rs
index 455fd32..2c61c04 100644
--- a/src/agent-client-protocol-conductor/src/snoop.rs
+++ b/src/agent-client-protocol-conductor/src/snoop.rs
@@ -1,33 +1,25 @@
-use agent_client_protocol_core::{Channel, ConnectTo, DynConnectTo, Role, jsonrpcmsg};
+use agent_client_protocol::{Channel, ConnectTo, DynConnectTo, Role, jsonrpcmsg};
 use futures::StreamExt;
 use futures_concurrency::future::TryJoin;
 
 pub struct SnooperComponent<R: Role> {
     base_component: DynConnectTo<R>,
     incoming_message: Box<
-        dyn FnMut(&jsonrpcmsg::Message) -> Result<(), agent_client_protocol_core::Error>
-            + Send
-            + Sync,
+        dyn FnMut(&jsonrpcmsg::Message) -> Result<(), agent_client_protocol::Error> + Send + Sync,
     >,
     outgoing_message: Box<
-        dyn FnMut(&jsonrpcmsg::Message) -> Result<(), agent_client_protocol_core::Error>
-            + Send
-            + Sync,
+        dyn FnMut(&jsonrpcmsg::Message) -> Result<(), agent_client_protocol::Error> + Send + Sync,
     >,
 }
 
 impl<R: Role> SnooperComponent<R> {
     pub fn new(
         base_component: impl ConnectTo<R>,
-        incoming_message: impl FnMut(
-            &jsonrpcmsg::Message,
-        ) -> Result<(), agent_client_protocol_core::Error>
+        incoming_message: impl FnMut(&jsonrpcmsg::Message) -> Result<(), agent_client_protocol::Error>
         + Send
         + Sync
         + 'static,
-        outgoing_message: impl FnMut(
-            &jsonrpcmsg::Message,
-        ) -> Result<(), agent_client_protocol_core::Error>
+        outgoing_message: impl FnMut(&jsonrpcmsg::Message) -> Result<(), agent_client_protocol::Error>
         + Send
         + Sync
         + 'static,
@@ -44,7 +36,7 @@ impl<R: Role> ConnectTo<R> for SnooperComponent<R> {
     async fn connect_to(
         mut self,
         client: impl ConnectTo<R::Counterpart>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         let (client_a, mut client_b) = Channel::duplex();
 
         let client_future = client.connect_to(client_a);
@@ -62,7 +54,7 @@ impl<R: Role> ConnectTo<R> for SnooperComponent<R> {
                 base_channel
                     .tx
                     .unbounded_send(msg)
-                    .map_err(agent_client_protocol_core::util::internal_error)?;
+                    .map_err(agent_client_protocol::util::internal_error)?;
             }
             Ok(())
         };
@@ -78,7 +70,7 @@ impl<R: Role> ConnectTo<R> for SnooperComponent<R> {
                 client_b
                     .tx
                     .unbounded_send(msg)
-                    .map_err(agent_client_protocol_core::util::internal_error)?;
+                    .map_err(agent_client_protocol::util::internal_error)?;
             }
             Ok(())
         };
diff --git a/src/agent-client-protocol-conductor/src/trace.rs b/src/agent-client-protocol-conductor/src/trace.rs
index 2573ca9..7b10ba4 100644
--- a/src/agent-client-protocol-conductor/src/trace.rs
+++ b/src/agent-client-protocol-conductor/src/trace.rs
@@ -9,8 +9,8 @@ use std::io::{BufWriter, Write};
 use std::path::Path;
 use std::time::Instant;
 
-use agent_client_protocol_core::schema::{McpOverAcpMessage, SuccessorMessage};
-use agent_client_protocol_core::{DynConnectTo, JsonRpcMessage, Role, UntypedMessage, jsonrpcmsg};
+use agent_client_protocol::schema::{McpOverAcpMessage, SuccessorMessage};
+use agent_client_protocol::{DynConnectTo, JsonRpcMessage, Role, UntypedMessage, jsonrpcmsg};
 use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
 
@@ -388,7 +388,7 @@ impl TraceWriter {
         mut self: TraceWriter,
     ) -> (
         TraceHandle,
-        impl std::future::Future<Output = Result<(), agent_client_protocol_core::Error>>,
+        impl std::future::Future<Output = Result<(), agent_client_protocol::Error>>,
     ) {
         use futures::StreamExt;
 
@@ -421,7 +421,7 @@ impl TraceHandle {
         successor_index: ComponentIndex,
         incoming: Incoming,
         message: &jsonrpcmsg::Message,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         self.tx
             .unbounded_send(TracedMessage {
                 component_index,
@@ -429,7 +429,7 @@ impl TraceHandle {
                 incoming,
                 message: message.clone(),
             })
-            .map_err(agent_client_protocol_core::util::internal_error)
+            .map_err(agent_client_protocol::util::internal_error)
     }
 
     /// Create a tracing bridge that wraps a proxy component.
@@ -450,7 +450,7 @@ impl TraceHandle {
         &self,
         proxy_index: ComponentIndex,
         successor_index: ComponentIndex,
-        proxy: impl agent_client_protocol_core::ConnectTo<R>,
+        proxy: impl agent_client_protocol::ConnectTo<R>,
     ) -> DynConnectTo<R> {
         DynConnectTo::new(SnooperComponent::new(
             proxy,
diff --git a/src/agent-client-protocol-conductor/tests/arrow_proxy_eliza.rs b/src/agent-client-protocol-conductor/tests/arrow_proxy_eliza.rs
index 5f6328d..1b465a8 100644
--- a/src/agent-client-protocol-conductor/tests/arrow_proxy_eliza.rs
+++ b/src/agent-client-protocol-conductor/tests/arrow_proxy_eliza.rs
@@ -15,8 +15,8 @@ use tokio::io::duplex;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 
 #[tokio::test]
-async fn test_conductor_with_arrow_proxy_and_test_agent()
--> Result<(), agent_client_protocol_core::Error> {
+async fn test_conductor_with_arrow_proxy_and_test_agent() -> Result<(), agent_client_protocol::Error>
+{
     // Create the component chain: arrow_proxy -> test_agent
     // Uses pre-built binaries to avoid cargo run races during `cargo test --all`
     let arrow_proxy_agent =
@@ -34,7 +34,7 @@ async fn test_conductor_with_arrow_proxy_and_test_agent()
             ProxiesAndAgent::new(test_agent).proxy(arrow_proxy_agent),
             McpBridgeMode::default(),
         )
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -44,7 +44,7 @@ async fn test_conductor_with_arrow_proxy_and_test_agent()
     // Wait for editor to complete and get the result
     let result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
         let result = yopo::prompt(
-            agent_client_protocol_core::ByteStreams::new(
+            agent_client_protocol::ByteStreams::new(
                 editor_write.compat_write(),
                 editor_read.compat(),
             ),
@@ -59,7 +59,7 @@ async fn test_conductor_with_arrow_proxy_and_test_agent()
             "Expected response to start with '>' from arrow proxy, got: {result}"
         );
 
-        Ok::<String, agent_client_protocol_core::Error>(result)
+        Ok::<String, agent_client_protocol::Error>(result)
     })
     .await
     .expect("Test timed out")
diff --git a/src/agent-client-protocol-conductor/tests/empty_conductor_eliza.rs b/src/agent-client-protocol-conductor/tests/empty_conductor_eliza.rs
index 495faf4..c1f87a8 100644
--- a/src/agent-client-protocol-conductor/tests/empty_conductor_eliza.rs
+++ b/src/agent-client-protocol-conductor/tests/empty_conductor_eliza.rs
@@ -6,8 +6,8 @@
 //! 3. Messages flow correctly through the empty conductor to the agent
 //! 4. The full chain works end-to-end
 
+use agent_client_protocol::{Conductor, ConnectTo, Proxy};
 use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::{Conductor, ConnectTo, Proxy};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use tokio::io::duplex;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
@@ -20,9 +20,9 @@ impl ConnectTo<Conductor> for MockEmptyConductor {
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         // Create an empty conductor with no components - it should act as a passthrough
-        let empty_components: Vec<agent_client_protocol_core::DynConnectTo<Conductor>> = vec![];
+        let empty_components: Vec<agent_client_protocol::DynConnectTo<Conductor>> = vec![];
         ConnectTo::<Conductor>::connect_to(
             ConductorImpl::new_proxy(
                 "empty-conductor".to_string(),
@@ -37,7 +37,7 @@ impl ConnectTo<Conductor> for MockEmptyConductor {
 
 #[tokio::test]
 async fn test_conductor_with_empty_conductor_and_test_agent()
--> Result<(), agent_client_protocol_core::Error> {
+-> Result<(), agent_client_protocol::Error> {
     // Initialize tracing for debugging
     drop(
         tracing_subscriber::fmt()
@@ -59,7 +59,7 @@ async fn test_conductor_with_empty_conductor_and_test_agent()
             ProxiesAndAgent::new(Testy::new()).proxy(MockEmptyConductor),
             McpBridgeMode::default(),
         )
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -69,7 +69,7 @@ async fn test_conductor_with_empty_conductor_and_test_agent()
     // Wait for editor to complete and get the result
     let result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
         let result = yopo::prompt(
-            agent_client_protocol_core::ByteStreams::new(
+            agent_client_protocol::ByteStreams::new(
                 editor_write.compat_write(),
                 editor_read.compat(),
             ),
@@ -85,7 +85,7 @@ async fn test_conductor_with_empty_conductor_and_test_agent()
         "#]]
         .assert_debug_eq(&result);
 
-        Ok::<String, agent_client_protocol_core::Error>(result)
+        Ok::<String, agent_client_protocol::Error>(result)
     })
     .await
     .expect("Test timed out")
diff --git a/src/agent-client-protocol-conductor/tests/initialization_sequence.rs b/src/agent-client-protocol-conductor/tests/initialization_sequence.rs
index 004c7ad..dcf0a5a 100644
--- a/src/agent-client-protocol-conductor/tests/initialization_sequence.rs
+++ b/src/agent-client-protocol-conductor/tests/initialization_sequence.rs
@@ -5,12 +5,12 @@
 //! 2. Multi-component chains: proxies receive `InitializeProxyRequest`
 //! 3. Last component (agent) receives `InitializeRequest`
 
-use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::schema::{
+use agent_client_protocol::schema::{
     AgentCapabilities, InitializeProxyRequest, InitializeRequest, InitializeResponse,
     ProtocolVersion,
 };
-use agent_client_protocol_core::{Agent, Client, Conductor, ConnectTo, DynConnectTo, Proxy};
+use agent_client_protocol::{Agent, Client, Conductor, ConnectTo, DynConnectTo, Proxy};
+use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
 use agent_client_protocol_test::testy::Testy;
 use std::sync::Arc;
 use std::sync::Mutex;
@@ -19,16 +19,16 @@ use tokio::io::duplex;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 
 /// Test helper to receive a JSON-RPC response
-async fn recv<T: agent_client_protocol_core::JsonRpcResponse + Send>(
-    response: agent_client_protocol_core::SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+async fn recv<T: agent_client_protocol::JsonRpcResponse + Send>(
+    response: agent_client_protocol::SentRequest<T>,
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 /// Tracks what type of initialization request was received
@@ -74,7 +74,7 @@ impl ConnectTo<Conductor> for InitComponent {
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         let config = self.config;
         let config2 = Arc::clone(&config);
 
@@ -89,13 +89,13 @@ impl ConnectTo<Conductor> for InitComponent {
                         Some(InitRequestType::InitializeProxy);
 
                     // Forward InitializeRequest (not InitializeProxyRequest) to successor
-                    cx.send_request_to(agent_client_protocol_core::Agent, request.initialize)
+                    cx.send_request_to(agent_client_protocol::Agent, request.initialize)
                         .on_receiving_result(async move |response| {
                             let response: InitializeResponse = response?;
                             responder.respond(response)
                         })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             // Handle InitializeRequest (we're the agent)
             .on_receive_request_from(
@@ -110,7 +110,7 @@ impl ConnectTo<Conductor> for InitComponent {
 
                     responder.respond(response)
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             .connect_to(client)
             .await
@@ -120,17 +120,17 @@ impl ConnectTo<Conductor> for InitComponent {
 async fn run_test_with_components(
     proxies: Vec<InitComponent>,
     editor_task: impl AsyncFnOnce(
-        agent_client_protocol_core::ConnectionTo<Agent>,
-    ) -> Result<(), agent_client_protocol_core::Error>,
-) -> Result<(), agent_client_protocol_core::Error> {
+        agent_client_protocol::ConnectionTo<Agent>,
+    ) -> Result<(), agent_client_protocol::Error>,
+) -> Result<(), agent_client_protocol::Error> {
     // Set up editor <-> conductor communication
     let (editor_out, conductor_in) = duplex(1024);
     let (conductor_out, editor_in) = duplex(1024);
 
     let transport =
-        agent_client_protocol_core::ByteStreams::new(editor_out.compat_write(), editor_in.compat());
+        agent_client_protocol::ByteStreams::new(editor_out.compat_write(), editor_in.compat());
 
-    agent_client_protocol_core::Client
+    agent_client_protocol::Client
         .builder()
         .name("editor-to-connector")
         .with_spawned(|_cx| async move {
@@ -139,7 +139,7 @@ async fn run_test_with_components(
                 ProxiesAndAgent::new(Testy::new()).proxies(proxies),
                 McpBridgeMode::default(),
             )
-            .run(agent_client_protocol_core::ByteStreams::new(
+            .run(agent_client_protocol::ByteStreams::new(
                 conductor_out.compat_write(),
                 conductor_in.compat(),
             ))
@@ -150,8 +150,8 @@ async fn run_test_with_components(
 }
 
 #[tokio::test]
-async fn test_single_component_gets_initialize_request()
--> Result<(), agent_client_protocol_core::Error> {
+async fn test_single_component_gets_initialize_request() -> Result<(), agent_client_protocol::Error>
+{
     // Single component (agent) should receive InitializeRequest - we use ElizaAgent
     // which properly handles InitializeRequest
     run_test_with_components(vec![], async |connection_to_editor| {
@@ -165,7 +165,7 @@ async fn test_single_component_gets_initialize_request()
             "Initialize should succeed: {init_response:?}"
         );
 
-        Ok::<(), agent_client_protocol_core::Error>(())
+        Ok::<(), agent_client_protocol::Error>(())
     })
     .await?;
 
@@ -174,7 +174,7 @@ async fn test_single_component_gets_initialize_request()
 
 #[tokio::test]
 async fn test_two_components_proxy_gets_initialize_proxy()
--> Result<(), agent_client_protocol_core::Error> {
+-> Result<(), agent_client_protocol::Error> {
     // First component (proxy) gets InitializeProxyRequest
     // Second component (agent, ElizaAgent) gets InitializeRequest
     let component1 = InitConfig::new();
@@ -192,7 +192,7 @@ async fn test_two_components_proxy_gets_initialize_proxy()
                 "Initialize should succeed: {init_response:?}"
             );
 
-            Ok::<(), agent_client_protocol_core::Error>(())
+            Ok::<(), agent_client_protocol::Error>(())
         },
     )
     .await?;
@@ -211,7 +211,7 @@ async fn test_two_components_proxy_gets_initialize_proxy()
 
 #[tokio::test]
 async fn test_three_components_all_proxies_get_initialize_proxy()
--> Result<(), agent_client_protocol_core::Error> {
+-> Result<(), agent_client_protocol::Error> {
     // First two components (proxies) get InitializeProxyRequest
     // Third component (agent, ElizaAgent) gets InitializeRequest
     let component1 = InitConfig::new();
@@ -233,7 +233,7 @@ async fn test_three_components_all_proxies_get_initialize_proxy()
                 "Initialize should succeed: {init_response:?}"
             );
 
-            Ok::<(), agent_client_protocol_core::Error>(())
+            Ok::<(), agent_client_protocol::Error>(())
         },
     )
     .await?;
@@ -263,7 +263,7 @@ impl ConnectTo<Conductor> for BadProxy {
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         Proxy
             .builder()
             .name("bad-proxy")
@@ -277,7 +277,7 @@ impl ConnectTo<Conductor> for BadProxy {
                             responder.respond(response)
                         })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             .connect_to(client)
             .await
@@ -289,16 +289,16 @@ async fn run_bad_proxy_test(
     proxies: Vec<DynConnectTo<Conductor>>,
     agent: DynConnectTo<Client>,
     editor_task: impl AsyncFnOnce(
-        agent_client_protocol_core::ConnectionTo<Agent>,
-    ) -> Result<(), agent_client_protocol_core::Error>,
-) -> Result<(), agent_client_protocol_core::Error> {
+        agent_client_protocol::ConnectionTo<Agent>,
+    ) -> Result<(), agent_client_protocol::Error>,
+) -> Result<(), agent_client_protocol::Error> {
     let (editor_out, conductor_in) = duplex(1024);
     let (conductor_out, editor_in) = duplex(1024);
 
     let transport =
-        agent_client_protocol_core::ByteStreams::new(editor_out.compat_write(), editor_in.compat());
+        agent_client_protocol::ByteStreams::new(editor_out.compat_write(), editor_in.compat());
 
-    agent_client_protocol_core::Client
+    agent_client_protocol::Client
         .builder()
         .name("editor-to-connector")
         .with_spawned(|_cx| async move {
@@ -307,7 +307,7 @@ async fn run_bad_proxy_test(
                 ProxiesAndAgent::new(agent).proxies(proxies),
                 McpBridgeMode::default(),
             )
-            .run(agent_client_protocol_core::ByteStreams::new(
+            .run(agent_client_protocol::ByteStreams::new(
                 conductor_out.compat_write(),
                 conductor_in.compat(),
             ))
@@ -319,7 +319,7 @@ async fn run_bad_proxy_test(
 
 #[tokio::test]
 async fn test_conductor_rejects_initialize_proxy_forwarded_to_agent()
--> Result<(), agent_client_protocol_core::Error> {
+-> Result<(), agent_client_protocol::Error> {
     // BadProxy incorrectly forwards InitializeProxyRequest to the agent.
     // The conductor should reject this with an error.
     let result = run_bad_proxy_test(
@@ -338,7 +338,7 @@ async fn test_conductor_rejects_initialize_proxy_forwarded_to_agent()
                 );
             }
 
-            Ok::<(), agent_client_protocol_core::Error>(())
+            Ok::<(), agent_client_protocol::Error>(())
         },
     )
     .await;
@@ -358,7 +358,7 @@ async fn test_conductor_rejects_initialize_proxy_forwarded_to_agent()
 
 #[tokio::test]
 async fn test_conductor_rejects_initialize_proxy_forwarded_to_proxy()
--> Result<(), agent_client_protocol_core::Error> {
+-> Result<(), agent_client_protocol::Error> {
     // BadProxy incorrectly forwards InitializeProxyRequest to another proxy.
     // The conductor should reject this with an error.
     let result = run_bad_proxy_test(
@@ -381,7 +381,7 @@ async fn test_conductor_rejects_initialize_proxy_forwarded_to_proxy()
                 );
             }
 
-            Ok::<(), agent_client_protocol_core::Error>(())
+            Ok::<(), agent_client_protocol::Error>(())
         },
     )
     .await;
diff --git a/src/agent-client-protocol-conductor/tests/mcp-integration.rs b/src/agent-client-protocol-conductor/tests/mcp-integration.rs
index 2ab5407..174f0b9 100644
--- a/src/agent-client-protocol-conductor/tests/mcp-integration.rs
+++ b/src/agent-client-protocol-conductor/tests/mcp-integration.rs
@@ -7,12 +7,12 @@
 
 mod mcp_integration;
 
-use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::Agent;
-use agent_client_protocol_core::schema::{
+use agent_client_protocol::Agent;
+use agent_client_protocol::schema::{
     ContentBlock, InitializeRequest, NewSessionRequest, PromptRequest, ProtocolVersion,
     SessionNotification, TextContent,
 };
+use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
 use agent_client_protocol_test::test_binaries;
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use futures::{SinkExt, StreamExt, channel::mpsc};
@@ -21,16 +21,16 @@ use tokio::io::duplex;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 
 /// Test helper to receive a JSON-RPC response
-async fn recv<T: agent_client_protocol_core::JsonRpcResponse + Send>(
-    response: agent_client_protocol_core::SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+async fn recv<T: agent_client_protocol::JsonRpcResponse + Send>(
+    response: agent_client_protocol::SentRequest<T>,
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 fn conductor_command() -> Vec<String> {
@@ -42,9 +42,9 @@ async fn run_test_with_mode(
     mode: McpBridgeMode,
     components: ProxiesAndAgent,
     editor_task: impl AsyncFnOnce(
-        agent_client_protocol_core::ConnectionTo<Agent>,
-    ) -> Result<(), agent_client_protocol_core::Error>,
-) -> Result<(), agent_client_protocol_core::Error> {
+        agent_client_protocol::ConnectionTo<Agent>,
+    ) -> Result<(), agent_client_protocol::Error>,
+) -> Result<(), agent_client_protocol::Error> {
     // Initialize tracing for debug output
     drop(
         tracing_subscriber::fmt()
@@ -58,14 +58,14 @@ async fn run_test_with_mode(
     let (conductor_out, editor_in) = duplex(1024);
 
     let transport =
-        agent_client_protocol_core::ByteStreams::new(editor_out.compat_write(), editor_in.compat());
+        agent_client_protocol::ByteStreams::new(editor_out.compat_write(), editor_in.compat());
 
-    agent_client_protocol_core::Client
+    agent_client_protocol::Client
         .builder()
         .name("editor-to-connector")
         .with_spawned(|_cx| async move {
             ConductorImpl::new_agent("conductor".to_string(), components, mode)
-                .run(agent_client_protocol_core::ByteStreams::new(
+                .run(agent_client_protocol::ByteStreams::new(
                     conductor_out.compat_write(),
                     conductor_in.compat(),
                 ))
@@ -77,7 +77,7 @@ async fn run_test_with_mode(
 
 /// Test that proxy-provided MCP tools work with stdio bridge mode
 #[tokio::test]
-async fn test_proxy_provides_mcp_tools_stdio() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_proxy_provides_mcp_tools_stdio() -> Result<(), agent_client_protocol::Error> {
     run_test_with_mode(
         McpBridgeMode::Stdio {
             conductor_command: conductor_command(),
@@ -121,7 +121,7 @@ async fn test_proxy_provides_mcp_tools_stdio() -> Result<(), agent_client_protoc
 
 /// Test that proxy-provided MCP tools work with HTTP bridge mode
 #[tokio::test]
-async fn test_proxy_provides_mcp_tools_http() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_proxy_provides_mcp_tools_http() -> Result<(), agent_client_protocol::Error> {
     run_test_with_mode(
         McpBridgeMode::Http,
         ProxiesAndAgent::new(Testy::new()).proxy(mcp_integration::proxy::ProxyComponent),
@@ -162,7 +162,7 @@ async fn test_proxy_provides_mcp_tools_http() -> Result<(), agent_client_protoco
 }
 
 #[tokio::test]
-async fn test_agent_handles_prompt() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_agent_handles_prompt() -> Result<(), agent_client_protocol::Error> {
     // Initialize tracing for debug output
     drop(
         tracing_subscriber::fmt()
@@ -185,7 +185,7 @@ async fn test_agent_handles_prompt() -> Result<(), agent_client_protocol_core::E
             ProxiesAndAgent::new(Testy::new()).proxy(mcp_integration::proxy::ProxyComponent),
             McpBridgeMode::default(),
         )
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -193,25 +193,25 @@ async fn test_agent_handles_prompt() -> Result<(), agent_client_protocol_core::E
     });
 
     // Run the client
-    let result = agent_client_protocol_core::Client
+    let result = agent_client_protocol::Client
         .builder()
         .name("editor-to-connector")
         .on_receive_notification(
             {
                 let mut log_tx = log_tx.clone();
                 async move |notification: SessionNotification,
-                            _cx: agent_client_protocol_core::ConnectionTo<Agent>| {
+                            _cx: agent_client_protocol::ConnectionTo<Agent>| {
                     // Log the notification in debug format
                     log_tx
                         .send(format!("{notification:?}"))
                         .await
-                        .map_err(|_| agent_client_protocol_core::Error::internal_error())
+                        .map_err(|_| agent_client_protocol::Error::internal_error())
                 }
             },
-            agent_client_protocol_core::on_receive_notification!(),
+            agent_client_protocol::on_receive_notification!(),
         )
         .connect_with(
-            agent_client_protocol_core::ByteStreams::new(
+            agent_client_protocol::ByteStreams::new(
                 client_write.compat_write(),
                 client_read.compat(),
             ),
@@ -247,7 +247,7 @@ async fn test_agent_handles_prompt() -> Result<(), agent_client_protocol_core::E
                 log_tx
                     .send(format!("{prompt_response:?}"))
                     .await
-                    .map_err(|_| agent_client_protocol_core::Error::internal_error())?;
+                    .map_err(|_| agent_client_protocol::Error::internal_error())?;
 
                 Ok(())
             },
diff --git a/src/agent-client-protocol-conductor/tests/mcp_integration/proxy.rs b/src/agent-client-protocol-conductor/tests/mcp_integration/proxy.rs
index 6daaa75..1359cf1 100644
--- a/src/agent-client-protocol-conductor/tests/mcp_integration/proxy.rs
+++ b/src/agent-client-protocol-conductor/tests/mcp_integration/proxy.rs
@@ -1,7 +1,7 @@
 //! Proxy component that provides MCP tools
 
-use agent_client_protocol_core::mcp_server::McpServer;
-use agent_client_protocol_core::{Conductor, ConnectTo, Proxy};
+use agent_client_protocol::mcp_server::McpServer;
+use agent_client_protocol::{Conductor, ConnectTo, Proxy};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 
@@ -25,7 +25,7 @@ impl ConnectTo<Conductor> for ProxyComponent {
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         let test_server = McpServer::builder("test")
             .instructions("A simple test MCP server with an echo tool")
             .tool_fn_mut(
@@ -36,11 +36,11 @@ impl ConnectTo<Conductor> for ProxyComponent {
                         result: format!("Echo: {}", params.message),
                     })
                 },
-                agent_client_protocol_core::tool_fn_mut!(),
+                agent_client_protocol::tool_fn_mut!(),
             )
             .build();
 
-        agent_client_protocol_core::Proxy
+        agent_client_protocol::Proxy
             .builder()
             .name("proxy-component")
             .with_mcp_server(test_server)
diff --git a/src/agent-client-protocol-conductor/tests/mcp_server_handler_chain.rs b/src/agent-client-protocol-conductor/tests/mcp_server_handler_chain.rs
index 3ddd232..c2b1f9c 100644
--- a/src/agent-client-protocol-conductor/tests/mcp_server_handler_chain.rs
+++ b/src/agent-client-protocol-conductor/tests/mcp_server_handler_chain.rs
@@ -5,13 +5,13 @@
 //! `Handled::No`, which prevented downstream `.on_receive_request_from()` handlers
 //! from being invoked.
 
-use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::mcp_server::McpServer;
-use agent_client_protocol_core::schema::{
+use agent_client_protocol::mcp_server::McpServer;
+use agent_client_protocol::schema::{
     AgentCapabilities, InitializeRequest, InitializeResponse, NewSessionRequest,
     NewSessionResponse, ProtocolVersion, SessionId,
 };
-use agent_client_protocol_core::{Agent, Client, Conductor, ConnectTo, DynConnectTo, Proxy};
+use agent_client_protocol::{Agent, Client, Conductor, ConnectTo, DynConnectTo, Proxy};
+use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
@@ -34,16 +34,16 @@ struct EchoOutput {
 }
 
 /// Test helper to receive a JSON-RPC response
-async fn recv<T: agent_client_protocol_core::JsonRpcResponse + Send>(
-    response: agent_client_protocol_core::SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+async fn recv<T: agent_client_protocol::JsonRpcResponse + Send>(
+    response: agent_client_protocol::SentRequest<T>,
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 /// Tracks whether the NewSessionRequest handler was invoked
@@ -73,7 +73,7 @@ impl ConnectTo<Conductor> for ProxyWithMcpAndHandler {
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         let config = Arc::clone(&self.config);
 
         // Create an MCP server with a simple tool
@@ -87,11 +87,11 @@ impl ConnectTo<Conductor> for ProxyWithMcpAndHandler {
                         result: format!("Echo: {}", params.message),
                     })
                 },
-                agent_client_protocol_core::tool_fn_mut!(),
+                agent_client_protocol::tool_fn_mut!(),
             )
             .build();
 
-        agent_client_protocol_core::Proxy
+        agent_client_protocol::Proxy
             .builder()
             .name("proxy-with-mcp-and-handler")
             // Add the MCP server
@@ -112,7 +112,7 @@ impl ConnectTo<Conductor> for ProxyWithMcpAndHandler {
                             responder.respond(response)
                         })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             .connect_to(client)
             .await
@@ -126,7 +126,7 @@ impl ConnectTo<Client> for SimpleAgent {
     async fn connect_to(
         self,
         client: impl ConnectTo<Agent>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         Agent
             .builder()
             .name("simple-agent")
@@ -137,7 +137,7 @@ impl ConnectTo<Client> for SimpleAgent {
                             .agent_capabilities(AgentCapabilities::new()),
                     )
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             .on_receive_request(
                 async |_request: NewSessionRequest, responder, _cx| {
@@ -145,7 +145,7 @@ impl ConnectTo<Client> for SimpleAgent {
                         uuid::Uuid::new_v4().to_string(),
                     )))
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             .connect_to(client)
             .await
@@ -156,16 +156,16 @@ async fn run_test(
     proxies: Vec<DynConnectTo<Conductor>>,
     agent: DynConnectTo<Client>,
     editor_task: impl AsyncFnOnce(
-        agent_client_protocol_core::ConnectionTo<Agent>,
-    ) -> Result<(), agent_client_protocol_core::Error>,
-) -> Result<(), agent_client_protocol_core::Error> {
+        agent_client_protocol::ConnectionTo<Agent>,
+    ) -> Result<(), agent_client_protocol::Error>,
+) -> Result<(), agent_client_protocol::Error> {
     let (editor_out, conductor_in) = duplex(1024);
     let (conductor_out, editor_in) = duplex(1024);
 
     let transport =
-        agent_client_protocol_core::ByteStreams::new(editor_out.compat_write(), editor_in.compat());
+        agent_client_protocol::ByteStreams::new(editor_out.compat_write(), editor_in.compat());
 
-    agent_client_protocol_core::Client
+    agent_client_protocol::Client
         .builder()
         .name("editor-to-conductor")
         .with_spawned(|_cx| async move {
@@ -174,7 +174,7 @@ async fn run_test(
                 ProxiesAndAgent::new(agent).proxies(proxies),
                 McpBridgeMode::default(),
             )
-            .run(agent_client_protocol_core::ByteStreams::new(
+            .run(agent_client_protocol::ByteStreams::new(
                 conductor_out.compat_write(),
                 conductor_in.compat(),
             ))
@@ -187,7 +187,7 @@ async fn run_test(
 /// Regression test: NewSessionRequest handler should be invoked even when MCP server is present
 #[tokio::test]
 async fn test_new_session_handler_invoked_with_mcp_server()
--> Result<(), agent_client_protocol_core::Error> {
+-> Result<(), agent_client_protocol::Error> {
     let handler_config = HandlerConfig::new();
     let handler_config_clone = Arc::clone(&handler_config);
 
@@ -214,7 +214,7 @@ async fn test_new_session_handler_invoked_with_mcp_server()
             "Should receive a valid session ID"
         );
 
-        Ok::<(), agent_client_protocol_core::Error>(())
+        Ok::<(), agent_client_protocol::Error>(())
     })
     .await?;
 
diff --git a/src/agent-client-protocol-conductor/tests/nested_arrow_proxy.rs b/src/agent-client-protocol-conductor/tests/nested_arrow_proxy.rs
index 3bb91ed..42a7ac2 100644
--- a/src/agent-client-protocol-conductor/tests/nested_arrow_proxy.rs
+++ b/src/agent-client-protocol-conductor/tests/nested_arrow_proxy.rs
@@ -22,8 +22,8 @@ use tokio::io::duplex;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 
 #[tokio::test]
-async fn test_conductor_with_two_external_arrow_proxies()
--> Result<(), agent_client_protocol_core::Error> {
+async fn test_conductor_with_two_external_arrow_proxies() -> Result<(), agent_client_protocol::Error>
+{
     // Create the component chain: arrow_proxy1 -> arrow_proxy2 -> test_agent
     // Uses pre-built binaries to avoid cargo run races during `cargo test --all`
     let arrow_proxy1 = AcpAgent::from_args([arrow_proxy_example().to_string_lossy().to_string()])?;
@@ -43,7 +43,7 @@ async fn test_conductor_with_two_external_arrow_proxies()
                 .proxy(arrow_proxy2),
             McpBridgeMode::default(),
         )
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -53,7 +53,7 @@ async fn test_conductor_with_two_external_arrow_proxies()
     // Wait for editor to complete and get the result
     let result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
         let result = yopo::prompt(
-            agent_client_protocol_core::ByteStreams::new(
+            agent_client_protocol::ByteStreams::new(
                 editor_write.compat_write(),
                 editor_read.compat(),
             ),
@@ -66,7 +66,7 @@ async fn test_conductor_with_two_external_arrow_proxies()
         "#]]
         .assert_debug_eq(&result);
 
-        Ok::<String, agent_client_protocol_core::Error>(result)
+        Ok::<String, agent_client_protocol::Error>(result)
     })
     .await
     .expect("Test timed out")
diff --git a/src/agent-client-protocol-conductor/tests/nested_conductor.rs b/src/agent-client-protocol-conductor/tests/nested_conductor.rs
index 1a53620..2d03436 100644
--- a/src/agent-client-protocol-conductor/tests/nested_conductor.rs
+++ b/src/agent-client-protocol-conductor/tests/nested_conductor.rs
@@ -19,8 +19,8 @@
 //!
 //! Run `just prep-tests` before running these tests.
 
+use agent_client_protocol::{Conductor, ConnectTo, DynConnectTo};
 use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::{Conductor, ConnectTo, DynConnectTo};
 use agent_client_protocol_test::arrow_proxy::run_arrow_proxy;
 use agent_client_protocol_test::test_binaries::{arrow_proxy_example, conductor_binary, testy};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
@@ -35,8 +35,8 @@ struct MockArrowProxy;
 impl ConnectTo<Conductor> for MockArrowProxy {
     async fn connect_to(
         self,
-        client: impl ConnectTo<agent_client_protocol_core::Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+        client: impl ConnectTo<agent_client_protocol::Proxy>,
+    ) -> Result<(), agent_client_protocol::Error> {
         run_arrow_proxy(client).await
     }
 }
@@ -56,8 +56,8 @@ impl MockInnerConductor {
 impl ConnectTo<Conductor> for MockInnerConductor {
     async fn connect_to(
         self,
-        client: impl ConnectTo<agent_client_protocol_core::Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+        client: impl ConnectTo<agent_client_protocol::Proxy>,
+    ) -> Result<(), agent_client_protocol::Error> {
         // Create mock arrow proxy components for the inner conductor
         // This conductor is ONLY proxies - no actual agent
         // Use Serve::serve instead of .run() to get the Serve<Conductor> impl
@@ -79,8 +79,7 @@ impl ConnectTo<Conductor> for MockInnerConductor {
 }
 
 #[tokio::test]
-async fn test_nested_conductor_with_arrow_proxies() -> Result<(), agent_client_protocol_core::Error>
-{
+async fn test_nested_conductor_with_arrow_proxies() -> Result<(), agent_client_protocol::Error> {
     // Create the nested component chain using mock components
     // Inner conductor will manage: arrow_proxy1 -> arrow_proxy2 -> eliza
     // Outer conductor will manage: inner_conductor only
@@ -96,7 +95,7 @@ async fn test_nested_conductor_with_arrow_proxies() -> Result<(), agent_client_p
             ProxiesAndAgent::new(Testy::new()).proxy(MockInnerConductor::new(2)),
             McpBridgeMode::default(),
         )
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -106,7 +105,7 @@ async fn test_nested_conductor_with_arrow_proxies() -> Result<(), agent_client_p
     // Wait for editor to complete and get the result
     let result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
         let result = yopo::prompt(
-            agent_client_protocol_core::ByteStreams::new(
+            agent_client_protocol::ByteStreams::new(
                 editor_write.compat_write(),
                 editor_read.compat(),
             ),
@@ -121,7 +120,7 @@ async fn test_nested_conductor_with_arrow_proxies() -> Result<(), agent_client_p
         "#]]
         .assert_debug_eq(&result);
 
-        Ok::<String, agent_client_protocol_core::Error>(result)
+        Ok::<String, agent_client_protocol::Error>(result)
     })
     .await
     .expect("Test timed out")
@@ -139,7 +138,7 @@ async fn test_nested_conductor_with_arrow_proxies() -> Result<(), agent_client_p
 
 #[tokio::test]
 async fn test_nested_conductor_with_external_arrow_proxies()
--> Result<(), agent_client_protocol_core::Error> {
+-> Result<(), agent_client_protocol::Error> {
     // Create the nested component chain using external processes
     // Inner conductor spawned as a separate process with two arrow proxies
     // Outer conductor manages: inner_conductor -> test agent (both as external processes)
@@ -165,7 +164,7 @@ async fn test_nested_conductor_with_external_arrow_proxies()
             ProxiesAndAgent::new(agent).proxy(inner_conductor),
             McpBridgeMode::default(),
         )
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -175,7 +174,7 @@ async fn test_nested_conductor_with_external_arrow_proxies()
     // Wait for editor to complete and get the result
     let result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
         let result = yopo::prompt(
-            agent_client_protocol_core::ByteStreams::new(
+            agent_client_protocol::ByteStreams::new(
                 editor_write.compat_write(),
                 editor_read.compat(),
             ),
@@ -190,7 +189,7 @@ async fn test_nested_conductor_with_external_arrow_proxies()
         "#]]
         .assert_debug_eq(&result);
 
-        Ok::<String, agent_client_protocol_core::Error>(result)
+        Ok::<String, agent_client_protocol::Error>(result)
     })
     .await
     .expect("Test timed out")
diff --git a/src/agent-client-protocol-conductor/tests/scoped_mcp_server.rs b/src/agent-client-protocol-conductor/tests/scoped_mcp_server.rs
index dc2836a..adb1f07 100644
--- a/src/agent-client-protocol-conductor/tests/scoped_mcp_server.rs
+++ b/src/agent-client-protocol-conductor/tests/scoped_mcp_server.rs
@@ -4,9 +4,9 @@
 //! can capture references to stack-local data (like a Vec) and push to it
 //! when the tool is invoked.
 
+use agent_client_protocol::mcp_server::McpServer;
+use agent_client_protocol::{Agent, Conductor, ConnectTo, Proxy, Role, RunWithConnectionTo};
 use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::mcp_server::McpServer;
-use agent_client_protocol_core::{Agent, Conductor, ConnectTo, Proxy, Role, RunWithConnectionTo};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -17,7 +17,7 @@ use std::sync::Mutex;
 /// This validates the scoped lifetime feature - the tool closure captures
 /// a reference to `collected_values` which lives on the stack.
 #[tokio::test]
-async fn test_scoped_mcp_server_through_proxy() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_scoped_mcp_server_through_proxy() -> Result<(), agent_client_protocol::Error> {
     let conductor = ConductorImpl::new_agent(
         "conductor".to_string(),
         ProxiesAndAgent::new(Testy::new()).proxy(ScopedProxy),
@@ -48,9 +48,9 @@ async fn test_scoped_mcp_server_through_proxy() -> Result<(), agent_client_proto
 /// The MCP server captures a reference to stack-local data that lives for
 /// the duration of the session.
 #[tokio::test]
-async fn test_scoped_mcp_server_through_session() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_scoped_mcp_server_through_session() -> Result<(), agent_client_protocol::Error> {
     // Run the client
-    agent_client_protocol_core::Client.builder()
+    agent_client_protocol::Client.builder()
         .connect_with(
             ConductorImpl::new_agent(
                 "conductor".to_string(),
@@ -59,8 +59,8 @@ async fn test_scoped_mcp_server_through_session() -> Result<(), agent_client_pro
             ),
             async |cx| {
                 // Initialize first
-                cx.send_request(agent_client_protocol_core::schema::InitializeRequest::new(
-                    agent_client_protocol_core::schema::ProtocolVersion::LATEST,
+                cx.send_request(agent_client_protocol::schema::InitializeRequest::new(
+                    agent_client_protocol::schema::ProtocolVersion::LATEST,
                 ))
                 .block_task()
                 .await?;
@@ -113,7 +113,7 @@ fn make_mcp_server<Counterpart: Role>(
                 values.extend(input.elements);
                 Ok(values.len())
             },
-            agent_client_protocol_core::tool_fn_mut!(),
+            agent_client_protocol::tool_fn_mut!(),
         )
         .tool_fn_mut(
             "get",
@@ -122,7 +122,7 @@ fn make_mcp_server<Counterpart: Role>(
                 let values = values.lock().expect("not poisoned");
                 Ok(values.clone())
             },
-            agent_client_protocol_core::tool_fn_mut!(),
+            agent_client_protocol::tool_fn_mut!(),
         )
         .build()
 }
@@ -131,12 +131,12 @@ impl ConnectTo<Conductor> for ScopedProxy {
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         // Stack-local data that the MCP tool will push to
         let values: Mutex<Vec<String>> = Mutex::new(Vec::new());
 
         // Build the MCP server that captures a reference to collected_values
-        let mcp_server = make_mcp_server::<agent_client_protocol_core::Conductor>(&values);
+        let mcp_server = make_mcp_server::<agent_client_protocol::Conductor>(&values);
 
         Proxy
             .builder()
diff --git a/src/agent-client-protocol-conductor/tests/standalone_mcp_server.rs b/src/agent-client-protocol-conductor/tests/standalone_mcp_server.rs
index 77a7b90..4501c97 100644
--- a/src/agent-client-protocol-conductor/tests/standalone_mcp_server.rs
+++ b/src/agent-client-protocol-conductor/tests/standalone_mcp_server.rs
@@ -3,7 +3,7 @@
 //! These tests verify that `McpServer` can be used directly with MCP clients
 //! via the `Component<McpServerToClient>` implementation.
 
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     ByteStreams, ConnectTo, RunWithConnectionTo, mcp_server::McpServer, role::mcp, util::run_until,
 };
 use rmcp::{ClientHandler, ServiceExt, model::ClientInfo};
@@ -38,7 +38,7 @@ fn create_test_server() -> McpServer<mcp::Client, impl RunWithConnectionTo<mcp::
             "echo",
             "Echo a message back",
             async |input: EchoInput, _cx| Ok(format!("Echo: {}", input.message)),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .tool_fn(
             "add",
@@ -48,7 +48,7 @@ fn create_test_server() -> McpServer<mcp::Client, impl RunWithConnectionTo<mcp::
                     result: input.a + input.b,
                 })
             },
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .build()
 }
@@ -64,7 +64,7 @@ impl ClientHandler for MinimalClientHandler {
 }
 
 #[tokio::test]
-async fn test_standalone_server_list_tools() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_standalone_server_list_tools() -> Result<(), agent_client_protocol::Error> {
     // Create duplex streams for communication
     let (server_stream, client_stream) = tokio::io::duplex(8192);
     let (server_read, server_write) = tokio::io::split(server_stream);
@@ -83,13 +83,13 @@ async fn test_standalone_server_list_tools() -> Result<(), agent_client_protocol
             let client = MinimalClientHandler
                 .serve((server_read, server_write))
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             // List tools
             let tools_result = client
                 .list_tools(None)
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             // Verify we got both tools
             assert_eq!(tools_result.tools.len(), 2);
@@ -103,7 +103,7 @@ async fn test_standalone_server_list_tools() -> Result<(), agent_client_protocol
             client
                 .cancel()
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
             Ok(())
         },
     )
@@ -111,7 +111,7 @@ async fn test_standalone_server_list_tools() -> Result<(), agent_client_protocol
 }
 
 #[tokio::test]
-async fn test_standalone_server_call_echo_tool() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_standalone_server_call_echo_tool() -> Result<(), agent_client_protocol::Error> {
     let (server_stream, client_stream) = tokio::io::duplex(8192);
     let (server_read, server_write) = tokio::io::split(server_stream);
     let (client_read, client_write) = tokio::io::split(client_stream);
@@ -125,7 +125,7 @@ async fn test_standalone_server_call_echo_tool() -> Result<(), agent_client_prot
             let client = MinimalClientHandler
                 .serve((server_read, server_write))
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             // Call the echo tool
             let result = client
@@ -138,7 +138,7 @@ async fn test_standalone_server_call_echo_tool() -> Result<(), agent_client_prot
                     ),
                 )
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             // Verify the result
             let text = result
@@ -153,7 +153,7 @@ async fn test_standalone_server_call_echo_tool() -> Result<(), agent_client_prot
             client
                 .cancel()
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
             Ok(())
         },
     )
@@ -161,7 +161,7 @@ async fn test_standalone_server_call_echo_tool() -> Result<(), agent_client_prot
 }
 
 #[tokio::test]
-async fn test_standalone_server_call_add_tool() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_standalone_server_call_add_tool() -> Result<(), agent_client_protocol::Error> {
     let (server_stream, client_stream) = tokio::io::duplex(8192);
     let (server_read, server_write) = tokio::io::split(server_stream);
     let (client_read, client_write) = tokio::io::split(client_stream);
@@ -175,7 +175,7 @@ async fn test_standalone_server_call_add_tool() -> Result<(), agent_client_proto
             let client = MinimalClientHandler
                 .serve((server_read, server_write))
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             // Call the add tool
             let result = client
@@ -188,7 +188,7 @@ async fn test_standalone_server_call_add_tool() -> Result<(), agent_client_proto
                     ),
                 )
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             // The add tool returns structured output (AddOutput)
             // Check that we get the expected result
@@ -206,7 +206,7 @@ async fn test_standalone_server_call_add_tool() -> Result<(), agent_client_proto
             client
                 .cancel()
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
             Ok(())
         },
     )
@@ -214,7 +214,7 @@ async fn test_standalone_server_call_add_tool() -> Result<(), agent_client_proto
 }
 
 #[tokio::test]
-async fn test_standalone_server_tool_not_found() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_standalone_server_tool_not_found() -> Result<(), agent_client_protocol::Error> {
     let (server_stream, client_stream) = tokio::io::duplex(8192);
     let (server_read, server_write) = tokio::io::split(server_stream);
     let (client_read, client_write) = tokio::io::split(client_stream);
@@ -228,7 +228,7 @@ async fn test_standalone_server_tool_not_found() -> Result<(), agent_client_prot
             let client = MinimalClientHandler
                 .serve((server_read, server_write))
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             // Call a non-existent tool
             let result = client
@@ -241,7 +241,7 @@ async fn test_standalone_server_tool_not_found() -> Result<(), agent_client_prot
             client
                 .cancel()
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
             Ok(())
         },
     )
@@ -249,8 +249,7 @@ async fn test_standalone_server_tool_not_found() -> Result<(), agent_client_prot
 }
 
 #[tokio::test]
-async fn test_standalone_server_with_disabled_tools()
--> Result<(), agent_client_protocol_core::Error> {
+async fn test_standalone_server_with_disabled_tools() -> Result<(), agent_client_protocol::Error> {
     let (server_stream, client_stream) = tokio::io::duplex(8192);
     let (server_read, server_write) = tokio::io::split(server_stream);
     let (client_read, client_write) = tokio::io::split(client_stream);
@@ -261,7 +260,7 @@ async fn test_standalone_server_with_disabled_tools()
             "echo",
             "Echo a message",
             async |input: EchoInput, _cx| Ok(format!("Echo: {}", input.message)),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .tool_fn(
             "add",
@@ -271,7 +270,7 @@ async fn test_standalone_server_with_disabled_tools()
                     result: input.a + input.b,
                 })
             },
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .disable_tool("echo")?
         .build();
@@ -284,13 +283,13 @@ async fn test_standalone_server_with_disabled_tools()
             let client = MinimalClientHandler
                 .serve((server_read, server_write))
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
 
             // List tools - should only show "add"
             let tools_result = client
                 .list_tools(None)
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
             assert_eq!(tools_result.tools.len(), 1);
             assert_eq!(tools_result.tools[0].name.as_ref(), "add");
 
@@ -311,7 +310,7 @@ async fn test_standalone_server_with_disabled_tools()
             client
                 .cancel()
                 .await
-                .map_err(agent_client_protocol_core::util::internal_error)?;
+                .map_err(agent_client_protocol::util::internal_error)?;
             Ok(())
         },
     )
diff --git a/src/agent-client-protocol-conductor/tests/test_mcp_tool_output_types.rs b/src/agent-client-protocol-conductor/tests/test_mcp_tool_output_types.rs
index 54c3846..5b65118 100644
--- a/src/agent-client-protocol-conductor/tests/test_mcp_tool_output_types.rs
+++ b/src/agent-client-protocol-conductor/tests/test_mcp_tool_output_types.rs
@@ -3,9 +3,9 @@
 //! MCP structured output requires JSON objects. This test verifies behavior
 //! when tools return non-object types like bare strings or integers.
 
+use agent_client_protocol::mcp_server::McpServer;
+use agent_client_protocol::{Conductor, ConnectTo, DynConnectTo, Proxy, RunWithConnectionTo};
 use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::mcp_server::McpServer;
-use agent_client_protocol_core::{Conductor, ConnectTo, DynConnectTo, Proxy, RunWithConnectionTo};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -22,13 +22,13 @@ fn create_test_proxy() -> DynConnectTo<Conductor> {
             "return_string",
             "Returns a bare string",
             async |_input: EmptyInput, _context| Ok("hello world".to_string()),
-            agent_client_protocol_core::tool_fn_mut!(),
+            agent_client_protocol::tool_fn_mut!(),
         )
         .tool_fn_mut(
             "return_integer",
             "Returns a bare integer",
             async |_input: EmptyInput, _context| Ok(42i32),
-            agent_client_protocol_core::tool_fn_mut!(),
+            agent_client_protocol::tool_fn_mut!(),
         )
         .build();
 
@@ -45,8 +45,8 @@ impl<R: RunWithConnectionTo<Conductor> + 'static + Send> ConnectTo<Conductor>
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
-        agent_client_protocol_core::Proxy
+    ) -> Result<(), agent_client_protocol::Error> {
+        agent_client_protocol::Proxy
             .builder()
             .name("test-proxy")
             .with_mcp_server(self.mcp_server)
@@ -56,7 +56,7 @@ impl<R: RunWithConnectionTo<Conductor> + 'static + Send> ConnectTo<Conductor>
 }
 
 #[tokio::test]
-async fn test_tool_returning_string() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_tool_returning_string() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
@@ -82,7 +82,7 @@ async fn test_tool_returning_string() -> Result<(), agent_client_protocol_core::
 }
 
 #[tokio::test]
-async fn test_tool_returning_integer() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_tool_returning_integer() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
diff --git a/src/agent-client-protocol-conductor/tests/test_session_id_in_mcp_tools.rs b/src/agent-client-protocol-conductor/tests/test_session_id_in_mcp_tools.rs
index dc464fb..27682fa 100644
--- a/src/agent-client-protocol-conductor/tests/test_session_id_in_mcp_tools.rs
+++ b/src/agent-client-protocol-conductor/tests/test_session_id_in_mcp_tools.rs
@@ -8,10 +8,10 @@
 //! 5. The tool returns the session_id in its response
 //! 6. We verify the session_ids match
 
+use agent_client_protocol::RunWithConnectionTo;
+use agent_client_protocol::mcp_server::McpServer;
+use agent_client_protocol::{Conductor, ConnectTo, DynConnectTo, Proxy};
 use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::RunWithConnectionTo;
-use agent_client_protocol_core::mcp_server::McpServer;
-use agent_client_protocol_core::{Conductor, ConnectTo, DynConnectTo, Proxy};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -39,7 +39,7 @@ fn create_echo_proxy() -> DynConnectTo<Conductor> {
                     acp_url: context.acp_url(),
                 })
             },
-            agent_client_protocol_core::tool_fn_mut!(),
+            agent_client_protocol::tool_fn_mut!(),
         )
         .build();
 
@@ -57,8 +57,8 @@ impl<R: RunWithConnectionTo<Conductor> + 'static + Send> ConnectTo<Conductor>
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
-        agent_client_protocol_core::Proxy
+    ) -> Result<(), agent_client_protocol::Error> {
+        agent_client_protocol::Proxy
             .builder()
             .name("echo-proxy")
             .with_mcp_server(self.mcp_server)
@@ -68,7 +68,7 @@ impl<R: RunWithConnectionTo<Conductor> + 'static + Send> ConnectTo<Conductor>
 }
 
 #[tokio::test]
-async fn test_list_tools_from_mcp_server() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_list_tools_from_mcp_server() -> Result<(), agent_client_protocol::Error> {
     use expect_test::expect;
 
     let result = yopo::prompt(
@@ -94,7 +94,7 @@ async fn test_list_tools_from_mcp_server() -> Result<(), agent_client_protocol_c
 }
 
 #[tokio::test]
-async fn test_session_id_delivered_to_mcp_tools() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_session_id_delivered_to_mcp_tools() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
diff --git a/src/agent-client-protocol-conductor/tests/test_tool_enable_disable.rs b/src/agent-client-protocol-conductor/tests/test_tool_enable_disable.rs
index 60d8ac1..cb1b865 100644
--- a/src/agent-client-protocol-conductor/tests/test_tool_enable_disable.rs
+++ b/src/agent-client-protocol-conductor/tests/test_tool_enable_disable.rs
@@ -3,9 +3,9 @@
 //! These tests verify that `disable_tool`, `enable_tool`, `disable_all_tools`,
 //! and `enable_all_tools` correctly filter which tools are visible and callable.
 
+use agent_client_protocol::mcp_server::McpServer;
+use agent_client_protocol::{Conductor, ConnectTo, DynConnectTo, Proxy, RunWithConnectionTo};
 use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::mcp_server::McpServer;
-use agent_client_protocol_core::{Conductor, ConnectTo, DynConnectTo, Proxy, RunWithConnectionTo};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -27,27 +27,27 @@ struct GreetInput {
 struct EmptyInput {}
 
 /// Create a proxy with multiple tools, some disabled via deny-list
-fn create_proxy_with_disabled_tool()
--> Result<DynConnectTo<Conductor>, agent_client_protocol_core::Error> {
+fn create_proxy_with_disabled_tool() -> Result<DynConnectTo<Conductor>, agent_client_protocol::Error>
+{
     let mcp_server = McpServer::builder("test_server".to_string())
         .instructions("Test MCP server with some disabled tools")
         .tool_fn(
             "echo",
             "Echo a message back",
             async |input: EchoInput, _context| Ok(format!("Echo: {}", input.message)),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .tool_fn(
             "greet",
             "Greet someone by name",
             async |input: GreetInput, _context| Ok(format!("Hello, {}!", input.name)),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .tool_fn(
             "secret",
             "A secret tool that should be disabled",
             async |_input: EmptyInput, _context| Ok("This is secret!".to_string()),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .disable_tool("secret")?
         .build();
@@ -56,27 +56,26 @@ fn create_proxy_with_disabled_tool()
 }
 
 /// Create a proxy where all tools are disabled except specific ones (allow-list)
-fn create_proxy_with_allowlist()
--> Result<DynConnectTo<Conductor>, agent_client_protocol_core::Error> {
+fn create_proxy_with_allowlist() -> Result<DynConnectTo<Conductor>, agent_client_protocol::Error> {
     let mcp_server = McpServer::builder("allowlist_server".to_string())
         .instructions("Test MCP server with allow-list")
         .tool_fn(
             "echo",
             "Echo a message back",
             async |input: EchoInput, _context| Ok(format!("Echo: {}", input.message)),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .tool_fn(
             "greet",
             "Greet someone by name",
             async |input: GreetInput, _context| Ok(format!("Hello, {}!", input.name)),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .tool_fn(
             "secret",
             "A secret tool",
             async |_input: EmptyInput, _context| Ok("This is secret!".to_string()),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .disable_all_tools()
         .enable_tool("echo")?
@@ -93,8 +92,8 @@ impl<R: RunWithConnectionTo<Conductor> + 'static + Send> ConnectTo<Conductor> fo
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
-        agent_client_protocol_core::Proxy
+    ) -> Result<(), agent_client_protocol::Error> {
+        agent_client_protocol::Proxy
             .builder()
             .name("test-proxy")
             .with_mcp_server(self.mcp_server)
@@ -108,7 +107,7 @@ impl<R: RunWithConnectionTo<Conductor> + 'static + Send> ConnectTo<Conductor> fo
 // ============================================================================
 
 #[tokio::test]
-async fn test_list_tools_excludes_disabled() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_list_tools_excludes_disabled() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
@@ -134,7 +133,7 @@ async fn test_list_tools_excludes_disabled() -> Result<(), agent_client_protocol
 }
 
 #[tokio::test]
-async fn test_enabled_tool_can_be_called() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_enabled_tool_can_be_called() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
@@ -159,7 +158,7 @@ async fn test_enabled_tool_can_be_called() -> Result<(), agent_client_protocol_c
 }
 
 #[tokio::test]
-async fn test_disabled_tool_returns_not_found() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_disabled_tool_returns_not_found() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
@@ -189,8 +188,7 @@ async fn test_disabled_tool_returns_not_found() -> Result<(), agent_client_proto
 // ============================================================================
 
 #[tokio::test]
-async fn test_allowlist_only_shows_enabled_tools() -> Result<(), agent_client_protocol_core::Error>
-{
+async fn test_allowlist_only_shows_enabled_tools() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
@@ -219,7 +217,7 @@ async fn test_allowlist_only_shows_enabled_tools() -> Result<(), agent_client_pr
 }
 
 #[tokio::test]
-async fn test_allowlist_enabled_tool_works() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_allowlist_enabled_tool_works() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
@@ -245,7 +243,7 @@ async fn test_allowlist_enabled_tool_works() -> Result<(), agent_client_protocol
 
 #[tokio::test]
 async fn test_allowlist_non_enabled_tool_returns_not_found()
--> Result<(), agent_client_protocol_core::Error> {
+-> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
diff --git a/src/agent-client-protocol-conductor/tests/test_tool_fn.rs b/src/agent-client-protocol-conductor/tests/test_tool_fn.rs
index e74fd7e..b0fbb43 100644
--- a/src/agent-client-protocol-conductor/tests/test_tool_fn.rs
+++ b/src/agent-client-protocol-conductor/tests/test_tool_fn.rs
@@ -3,9 +3,9 @@
 //! This test verifies that `tool_fn` works correctly for stateless tools
 //! that don't need mutable state.
 
+use agent_client_protocol::mcp_server::McpServer;
+use agent_client_protocol::{Conductor, ConnectTo, DynConnectTo, Proxy, RunWithConnectionTo};
 use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::mcp_server::McpServer;
-use agent_client_protocol_core::{Conductor, ConnectTo, DynConnectTo, Proxy, RunWithConnectionTo};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -25,7 +25,7 @@ fn create_greet_proxy() -> DynConnectTo<Conductor> {
             "greet",
             "Greet someone by name",
             async |input: GreetInput, _context| Ok(format!("Hello, {}!", input.name)),
-            agent_client_protocol_core::tool_fn!(),
+            agent_client_protocol::tool_fn!(),
         )
         .build();
 
@@ -43,7 +43,7 @@ impl<R: RunWithConnectionTo<Conductor> + 'static + Send> ConnectTo<Conductor>
     async fn connect_to(
         self,
         client: impl ConnectTo<Proxy>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         Proxy
             .builder()
             .name("greet-proxy")
@@ -54,7 +54,7 @@ impl<R: RunWithConnectionTo<Conductor> + 'static + Send> ConnectTo<Conductor>
 }
 
 #[tokio::test]
-async fn test_tool_fn_greet() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_tool_fn_greet() -> Result<(), agent_client_protocol::Error> {
     let result = yopo::prompt(
         ConductorImpl::new_agent(
             "test-conductor".to_string(),
diff --git a/src/agent-client-protocol-conductor/tests/test_util.rs b/src/agent-client-protocol-conductor/tests/test_util.rs
index cde9f65..af519e1 100644
--- a/src/agent-client-protocol-conductor/tests/test_util.rs
+++ b/src/agent-client-protocol-conductor/tests/test_util.rs
@@ -8,9 +8,11 @@ pub fn init_test_tracing() {
 
     drop(
         fmt()
-            .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| {
-                EnvFilter::new("trace,agent_client_protocol_core::jsonrpc=trace")
-            }))
+            .with_env_filter(
+                EnvFilter::try_from_default_env().unwrap_or_else(|_| {
+                    EnvFilter::new("trace,agent_client_protocol::jsonrpc=trace")
+                }),
+            )
             .with_test_writer()
             .try_init(),
     );
diff --git a/src/agent-client-protocol-conductor/tests/trace_client_mcp_server.rs b/src/agent-client-protocol-conductor/tests/trace_client_mcp_server.rs
index 77527c1..753f91c 100644
--- a/src/agent-client-protocol-conductor/tests/trace_client_mcp_server.rs
+++ b/src/agent-client-protocol-conductor/tests/trace_client_mcp_server.rs
@@ -9,11 +9,11 @@
 //! Unlike trace_mcp_tool_call.rs which tests proxy-hosted MCP servers, this test
 //! verifies that MCP requests travel all the way back to the client.
 
+use agent_client_protocol::mcp_server::McpServer;
+use agent_client_protocol::schema::{InitializeRequest, ProtocolVersion};
+use agent_client_protocol::{Client, Role, RunWithConnectionTo};
 use agent_client_protocol_conductor::trace::TraceEvent;
 use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::mcp_server::McpServer;
-use agent_client_protocol_core::schema::{InitializeRequest, ProtocolVersion};
-use agent_client_protocol_core::{Client, Role, RunWithConnectionTo};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use expect_test::expect;
 use futures::StreamExt;
@@ -211,13 +211,13 @@ fn make_echo_mcp_server<R: Role>(
                     call_number: *count,
                 })
             },
-            agent_client_protocol_core::tool_fn_mut!(),
+            agent_client_protocol::tool_fn_mut!(),
         )
         .build()
 }
 
 #[tokio::test]
-async fn test_trace_client_mcp_server() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_trace_client_mcp_server() -> Result<(), agent_client_protocol::Error> {
     // Create channel for collecting trace events
     let (trace_tx, trace_rx) = mpsc::unbounded();
 
@@ -233,7 +233,7 @@ async fn test_trace_client_mcp_server() -> Result<(), agent_client_protocol_core
             McpBridgeMode::default(),
         )
         .trace_to(trace_tx)
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -242,11 +242,11 @@ async fn test_trace_client_mcp_server() -> Result<(), agent_client_protocol_core
 
     // Run the client with a client-hosted MCP server
     let test_result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
-        agent_client_protocol_core::Client
+        agent_client_protocol::Client
             .builder()
             .name("test-client")
             .connect_with(
-                agent_client_protocol_core::ByteStreams::new(
+                agent_client_protocol::ByteStreams::new(
                     client_write.compat_write(),
                     client_read.compat(),
                 ),
diff --git a/src/agent-client-protocol-conductor/tests/trace_generation.rs b/src/agent-client-protocol-conductor/tests/trace_generation.rs
index 6b93d22..3c2a284 100644
--- a/src/agent-client-protocol-conductor/tests/trace_generation.rs
+++ b/src/agent-client-protocol-conductor/tests/trace_generation.rs
@@ -15,7 +15,7 @@ use tokio::io::duplex;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 
 #[tokio::test]
-async fn test_trace_generation() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_trace_generation() -> Result<(), agent_client_protocol::Error> {
     // Enable tracing if RUST_LOG is set
     drop(
         tracing_subscriber::fmt()
@@ -47,7 +47,7 @@ async fn test_trace_generation() -> Result<(), agent_client_protocol_core::Error
         )
         .trace_to_path(&trace_path_clone)
         .expect("Failed to create trace writer")
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -57,7 +57,7 @@ async fn test_trace_generation() -> Result<(), agent_client_protocol_core::Error
     // Run a simple prompt through the conductor
     let result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
         let result = yopo::prompt(
-            agent_client_protocol_core::ByteStreams::new(
+            agent_client_protocol::ByteStreams::new(
                 editor_write.compat_write(),
                 editor_read.compat(),
             ),
@@ -65,7 +65,7 @@ async fn test_trace_generation() -> Result<(), agent_client_protocol_core::Error
         )
         .await?;
 
-        Ok::<String, agent_client_protocol_core::Error>(result)
+        Ok::<String, agent_client_protocol::Error>(result)
     })
     .await
     .expect("Test timed out")
diff --git a/src/agent-client-protocol-conductor/tests/trace_mcp_tool_call.rs b/src/agent-client-protocol-conductor/tests/trace_mcp_tool_call.rs
index f2ea4af..f8ffc4c 100644
--- a/src/agent-client-protocol-conductor/tests/trace_mcp_tool_call.rs
+++ b/src/agent-client-protocol-conductor/tests/trace_mcp_tool_call.rs
@@ -10,12 +10,12 @@
 
 mod mcp_integration;
 
-use agent_client_protocol_conductor::trace::TraceEvent;
-use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
-use agent_client_protocol_core::schema::{
+use agent_client_protocol::schema::{
     ContentBlock, InitializeRequest, NewSessionRequest, PromptRequest, ProtocolVersion,
     SessionNotification, TextContent,
 };
+use agent_client_protocol_conductor::trace::TraceEvent;
+use agent_client_protocol_conductor::{ConductorImpl, McpBridgeMode, ProxiesAndAgent};
 use agent_client_protocol_test::testy::{Testy, TestyCommand};
 use expect_test::expect;
 use futures::channel::mpsc;
@@ -183,20 +183,20 @@ impl EventNormalizer {
 }
 
 /// Test helper to receive a JSON-RPC response
-async fn recv<T: agent_client_protocol_core::JsonRpcResponse + Send>(
-    response: agent_client_protocol_core::SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+async fn recv<T: agent_client_protocol::JsonRpcResponse + Send>(
+    response: agent_client_protocol::SentRequest<T>,
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 #[tokio::test]
-async fn test_trace_mcp_tool_call() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_trace_mcp_tool_call() -> Result<(), agent_client_protocol::Error> {
     // Create channel for collecting trace events
     let (trace_tx, trace_rx) = mpsc::unbounded();
 
@@ -218,7 +218,7 @@ async fn test_trace_mcp_tool_call() -> Result<(), agent_client_protocol_core::Er
             McpBridgeMode::default(),
         )
         .trace_to(trace_tx)
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -227,7 +227,7 @@ async fn test_trace_mcp_tool_call() -> Result<(), agent_client_protocol_core::Er
 
     // Run the client interaction
     let test_result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
-        agent_client_protocol_core::Client
+        agent_client_protocol::Client
             .builder()
             .name("test-client")
             .on_receive_notification(
@@ -237,13 +237,13 @@ async fn test_trace_mcp_tool_call() -> Result<(), agent_client_protocol_core::Er
                         notif_tx
                             .send(notification)
                             .await
-                            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+                            .map_err(|_| agent_client_protocol::Error::internal_error())
                     }
                 },
-                agent_client_protocol_core::on_receive_notification!(),
+                agent_client_protocol::on_receive_notification!(),
             )
             .connect_with(
-                agent_client_protocol_core::ByteStreams::new(
+                agent_client_protocol::ByteStreams::new(
                     client_write.compat_write(),
                     client_read.compat(),
                 ),
diff --git a/src/agent-client-protocol-conductor/tests/trace_snapshot.rs b/src/agent-client-protocol-conductor/tests/trace_snapshot.rs
index 5c90706..f59c0f3 100644
--- a/src/agent-client-protocol-conductor/tests/trace_snapshot.rs
+++ b/src/agent-client-protocol-conductor/tests/trace_snapshot.rs
@@ -128,7 +128,7 @@ impl EventNormalizer {
 }
 
 #[tokio::test]
-async fn test_trace_snapshot() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_trace_snapshot() -> Result<(), agent_client_protocol::Error> {
     // Create channel for collecting trace events
     let (tx, rx) = mpsc::unbounded();
 
@@ -150,7 +150,7 @@ async fn test_trace_snapshot() -> Result<(), agent_client_protocol_core::Error>
             McpBridgeMode::default(),
         )
         .trace_to(tx)
-        .run(agent_client_protocol_core::ByteStreams::new(
+        .run(agent_client_protocol::ByteStreams::new(
             conductor_write.compat_write(),
             conductor_read.compat(),
         ))
@@ -160,7 +160,7 @@ async fn test_trace_snapshot() -> Result<(), agent_client_protocol_core::Error>
     // Run a simple prompt through the conductor
     let result = tokio::time::timeout(std::time::Duration::from_secs(30), async move {
         yopo::prompt(
-            agent_client_protocol_core::ByteStreams::new(
+            agent_client_protocol::ByteStreams::new(
                 editor_write.compat_write(),
                 editor_read.compat(),
             ),
diff --git a/src/agent-client-protocol-cookbook/Cargo.toml b/src/agent-client-protocol-cookbook/Cargo.toml
index ef2a3aa..2bdfdf4 100644
--- a/src/agent-client-protocol-cookbook/Cargo.toml
+++ b/src/agent-client-protocol-cookbook/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "agent-client-protocol-cookbook"
-version = "0.1.0"
+version = "0.11.0"
 edition.workspace = true
 authors.workspace = true
 license.workspace = true
@@ -12,7 +12,7 @@ categories = ["development-tools"]
 
 [dependencies]
 agent-client-protocol-conductor.workspace = true
-agent-client-protocol-core.workspace = true
+agent-client-protocol.workspace = true
 agent-client-protocol-rmcp.workspace = true
 agent-client-protocol-tokio.workspace = true
 rmcp.workspace = true
diff --git a/src/agent-client-protocol-cookbook/src/lib.rs b/src/agent-client-protocol-cookbook/src/lib.rs
index fc3be1f..9308d7c 100644
--- a/src/agent-client-protocol-cookbook/src/lib.rs
+++ b/src/agent-client-protocol-cookbook/src/lib.rs
@@ -6,13 +6,13 @@
 //! - **Proxies** - Sit between client and agent to add capabilities (like MCP tools)
 //! - **Agents** - Respond to prompts with AI-powered responses
 //!
-//! See the [`agent_client_protocol_core::concepts`] module for detailed explanations of
+//! See the [`agent_client_protocol::concepts`] module for detailed explanations of
 //! the concepts behind the API.
 //!
 //! # Building Clients
 //!
 //! A client connects to an agent, sends requests, and handles responses. Use
-//! [`Client.builder()`](agent_client_protocol_core::Client) to build connections.
+//! [`Client.builder()`](agent_client_protocol::Client) to build connections.
 //!
 //! - [`one_shot_prompt`] - Send a single prompt and get a response (simplest pattern)
 //! - [`connecting_as_client`] - More details on connection setup and permission handling
@@ -20,7 +20,7 @@
 //! # Building Proxies
 //!
 //! A proxy sits between client and agent, intercepting and optionally modifying
-//! messages. The most common use case is adding MCP tools. Use [`Proxy.builder()`](agent_client_protocol_core::Proxy)
+//! messages. The most common use case is adding MCP tools. Use [`Proxy.builder()`](agent_client_protocol::Proxy)
 //! to build proxy connections.
 //!
 //! **Important:** Proxies don't run standalone—they need the [`agent-client-protocol-conductor`] to
@@ -37,18 +37,18 @@
 //!
 //! # Building Agents
 //!
-//! An agent receives prompts and generates responses. Use [`Agent.builder()`](agent_client_protocol_core::Agent)
+//! An agent receives prompts and generates responses. Use [`Agent.builder()`](agent_client_protocol::Agent)
 //! to build agent connections.
 //!
 //! - [`building_an_agent`] - Handle initialization, sessions, and prompts
 //! - [`reusable_components`] - Package your agent as a [`ConnectTo`]
 //! - [`custom_message_handlers`] - Fine-grained control over message routing
 //!
-//! [`agent_client_protocol_core::concepts`]: agent_client_protocol_core::concepts
-//! [`Client`]: agent_client_protocol_core::Client
-//! [`Agent`]: agent_client_protocol_core::Agent
-//! [`Proxy`]: agent_client_protocol_core::Proxy
-//! [`ConnectTo`]: agent_client_protocol_core::ConnectTo
+//! [`agent_client_protocol::concepts`]: agent_client_protocol::concepts
+//! [`Client`]: agent_client_protocol::Client
+//! [`Agent`]: agent_client_protocol::Agent
+//! [`Proxy`]: agent_client_protocol::Proxy
+//! [`ConnectTo`]: agent_client_protocol::ConnectTo
 
 pub mod one_shot_prompt {
     //! Pattern: You Only Prompt Once.
@@ -60,13 +60,13 @@ pub mod one_shot_prompt {
     //! # Example
     //!
     //! ```
-    //! use agent_client_protocol_core::{Client, Agent, ConnectTo};
-    //! use agent_client_protocol_core::schema::{InitializeRequest, ProtocolVersion};
+    //! use agent_client_protocol::{Client, Agent, ConnectTo};
+    //! use agent_client_protocol::schema::{InitializeRequest, ProtocolVersion};
     //!
     //! async fn ask_agent(
     //!     transport: impl ConnectTo<Client> + 'static,
     //!     prompt: &str,
-    //! ) -> Result<String, agent_client_protocol_core::Error> {
+    //! ) -> Result<String, agent_client_protocol::Error> {
     //!     Client.builder()
     //!         .name("my-client")
     //!         .connect_with(transport, async |connection| {
@@ -105,16 +105,16 @@ pub mod one_shot_prompt {
     //! commands or writing files. See [`connecting_as_client`] for how to handle
     //! [`RequestPermissionRequest`] messages.
     //!
-    //! [`connect_with`]: agent_client_protocol_core::Builder::connect_with
-    //! [`send_request`]: agent_client_protocol_core::ConnectionTo::send_request
-    //! [`block_task`]: agent_client_protocol_core::SentRequest::block_task
-    //! [`build_session_cwd`]: agent_client_protocol_core::ConnectionTo::build_session_cwd
-    //! [`start_session`]: agent_client_protocol_core::SessionBuilder::start_session
-    //! [`ActiveSession`]: agent_client_protocol_core::ActiveSession
-    //! [`send_prompt`]: agent_client_protocol_core::ActiveSession::send_prompt
-    //! [`read_to_string`]: agent_client_protocol_core::ActiveSession::read_to_string
+    //! [`connect_with`]: agent_client_protocol::Builder::connect_with
+    //! [`send_request`]: agent_client_protocol::ConnectionTo::send_request
+    //! [`block_task`]: agent_client_protocol::SentRequest::block_task
+    //! [`build_session_cwd`]: agent_client_protocol::ConnectionTo::build_session_cwd
+    //! [`start_session`]: agent_client_protocol::SessionBuilder::start_session
+    //! [`ActiveSession`]: agent_client_protocol::ActiveSession
+    //! [`send_prompt`]: agent_client_protocol::ActiveSession::send_prompt
+    //! [`read_to_string`]: agent_client_protocol::ActiveSession::read_to_string
     //! [`connecting_as_client`]: super::connecting_as_client
-    //! [`RequestPermissionRequest`]: agent_client_protocol_core::schema::RequestPermissionRequest
+    //! [`RequestPermissionRequest`]: agent_client_protocol::schema::RequestPermissionRequest
 }
 
 pub mod connecting_as_client {
@@ -127,10 +127,10 @@ pub mod connecting_as_client {
     //! # Basic Example
     //!
     //! ```
-    //! use agent_client_protocol_core::{Client, Agent, ConnectTo};
-    //! use agent_client_protocol_core::schema::{InitializeRequest, ProtocolVersion};
+    //! use agent_client_protocol::{Client, Agent, ConnectTo};
+    //! use agent_client_protocol::schema::{InitializeRequest, ProtocolVersion};
     //!
-    //! async fn connect_to_agent(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+    //! async fn connect_to_agent(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
     //!     Client.builder()
     //!         .name("my-client")
     //!         .connect_with(transport, async |connection| {
@@ -182,7 +182,7 @@ pub mod connecting_as_client {
     //!             },
     //!             meta: None,
     //!         })
-    //!     }, agent_client_protocol_core::on_receive_request!())
+    //!     }, agent_client_protocol::on_receive_request!())
     //!     .connect_with(transport, async |connection| { /* ... */ })
     //!     .await
     //! ```
@@ -193,16 +193,16 @@ pub mod connecting_as_client {
     //! as a spawned task, not on the event loop. The event loop continues processing
     //! messages (including the response you're waiting for) while your task blocks.
     //!
-    //! [`connect_with`]: agent_client_protocol_core::Builder::connect_with
-    //! [`block_task`]: agent_client_protocol_core::SentRequest::block_task
-    //! [`build_session`]: agent_client_protocol_core::ConnectionTo::build_session
-    //! [`SessionBuilder`]: agent_client_protocol_core::SessionBuilder
-    //! [`send_prompt`]: agent_client_protocol_core::ActiveSession::send_prompt
-    //! [`read_update`]: agent_client_protocol_core::ActiveSession::read_update
-    //! [`read_to_string`]: agent_client_protocol_core::ActiveSession::read_to_string
-    //! [`with_mcp_server`]: agent_client_protocol_core::SessionBuilder::with_mcp_server
-    //! [`RequestPermissionRequest`]: agent_client_protocol_core::schema::RequestPermissionRequest
-    //! [`on_receive_request`]: agent_client_protocol_core::Builder::on_receive_request
+    //! [`connect_with`]: agent_client_protocol::Builder::connect_with
+    //! [`block_task`]: agent_client_protocol::SentRequest::block_task
+    //! [`build_session`]: agent_client_protocol::ConnectionTo::build_session
+    //! [`SessionBuilder`]: agent_client_protocol::SessionBuilder
+    //! [`send_prompt`]: agent_client_protocol::ActiveSession::send_prompt
+    //! [`read_update`]: agent_client_protocol::ActiveSession::read_update
+    //! [`read_to_string`]: agent_client_protocol::ActiveSession::read_to_string
+    //! [`with_mcp_server`]: agent_client_protocol::SessionBuilder::with_mcp_server
+    //! [`RequestPermissionRequest`]: agent_client_protocol::schema::RequestPermissionRequest
+    //! [`on_receive_request`]: agent_client_protocol::Builder::on_receive_request
 }
 
 pub mod building_an_agent {
@@ -214,19 +214,19 @@ pub mod building_an_agent {
     //! 2. Handle [`NewSessionRequest`] to create sessions
     //! 3. Handle [`PromptRequest`] to process prompts
     //!
-    //! Use [`Agent.builder()`](agent_client_protocol_core::Agent) to build agent connections.
+    //! Use [`Agent.builder()`](agent_client_protocol::Agent) to build agent connections.
     //!
     //! # Minimal Example
     //!
     //! ```
-    //! use agent_client_protocol_core::{Agent, Client, ConnectTo, Dispatch, ConnectionTo};
-    //! use agent_client_protocol_core::schema::{
+    //! use agent_client_protocol::{Agent, Client, ConnectTo, Dispatch, ConnectionTo};
+    //! use agent_client_protocol::schema::{
     //!     InitializeRequest, InitializeResponse, AgentCapabilities,
     //!     NewSessionRequest, NewSessionResponse, SessionId,
     //!     PromptRequest, PromptResponse, StopReason,
     //! };
     //!
-    //! async fn run_agent(transport: impl ConnectTo<Agent>) -> Result<(), agent_client_protocol_core::Error> {
+    //! async fn run_agent(transport: impl ConnectTo<Agent>) -> Result<(), agent_client_protocol::Error> {
     //!     Agent.builder()
     //!         .name("my-agent")
     //!         // Handle initialization
@@ -235,11 +235,11 @@ pub mod building_an_agent {
     //!                 InitializeResponse::new(req.protocol_version)
     //!                     .agent_capabilities(AgentCapabilities::new())
     //!             )
-    //!         }, agent_client_protocol_core::on_receive_request!())
+    //!         }, agent_client_protocol::on_receive_request!())
     //!         // Handle session creation
     //!         .on_receive_request(async |req: NewSessionRequest, responder, _connection| {
     //!             responder.respond(NewSessionResponse::new(SessionId::new("session-1")))
-    //!         }, agent_client_protocol_core::on_receive_request!())
+    //!         }, agent_client_protocol::on_receive_request!())
     //!         // Handle prompts
     //!         .on_receive_request(async |req: PromptRequest, responder, connection| {
     //!             // Send streaming updates via notifications
@@ -247,11 +247,11 @@ pub mod building_an_agent {
     //!
     //!             // Return final response
     //!             responder.respond(PromptResponse::new(StopReason::EndTurn))
-    //!         }, agent_client_protocol_core::on_receive_request!())
+    //!         }, agent_client_protocol::on_receive_request!())
     //!         // Reject unknown messages
     //!         .on_receive_dispatch(async |message: Dispatch, connection: ConnectionTo<Client>| {
-    //!             message.respond_with_error(agent_client_protocol_core::Error::method_not_found(), connection)
-    //!         }, agent_client_protocol_core::on_receive_dispatch!())
+    //!             message.respond_with_error(agent_client_protocol::Error::method_not_found(), connection)
+    //!         }, agent_client_protocol::on_receive_dispatch!())
     //!         .connect_to(transport)
     //!         .await
     //! }
@@ -287,7 +287,7 @@ pub mod building_an_agent {
     //!         stop_reason: StopReason::EndTurn,
     //!         meta: None,
     //!     })
-    //! }, agent_client_protocol_core::on_receive_request!())
+    //! }, agent_client_protocol::on_receive_request!())
     //! ```
     //!
     //! # Requesting Permissions
@@ -321,13 +321,13 @@ pub mod building_an_agent {
     //! For agents that will be composed with proxies, implement [`ConnectTo`].
     //! See [`reusable_components`] for the pattern.
     //!
-    //! [`InitializeRequest`]: agent_client_protocol_core::schema::InitializeRequest
-    //! [`NewSessionRequest`]: agent_client_protocol_core::schema::NewSessionRequest
-    //! [`PromptRequest`]: agent_client_protocol_core::schema::PromptRequest
-    //! [`SessionNotification`]: agent_client_protocol_core::schema::SessionNotification
-    //! [`RequestPermissionRequest`]: agent_client_protocol_core::schema::RequestPermissionRequest
-    //! [`Agent`]: agent_client_protocol_core::Agent
-    //! [`ConnectTo`]: agent_client_protocol_core::ConnectTo
+    //! [`InitializeRequest`]: agent_client_protocol::schema::InitializeRequest
+    //! [`NewSessionRequest`]: agent_client_protocol::schema::NewSessionRequest
+    //! [`PromptRequest`]: agent_client_protocol::schema::PromptRequest
+    //! [`SessionNotification`]: agent_client_protocol::schema::SessionNotification
+    //! [`RequestPermissionRequest`]: agent_client_protocol::schema::RequestPermissionRequest
+    //! [`Agent`]: agent_client_protocol::Agent
+    //! [`ConnectTo`]: agent_client_protocol::ConnectTo
     //! [`reusable_components`]: super::reusable_components
 }
 
@@ -341,8 +341,8 @@ pub mod reusable_components {
     //! # Example
     //!
     //! ```
-    //! use agent_client_protocol_core::{ConnectTo, Agent, Client};
-    //! use agent_client_protocol_core::schema::{
+    //! use agent_client_protocol::{ConnectTo, Agent, Client};
+    //! use agent_client_protocol::schema::{
     //!     InitializeRequest, InitializeResponse, AgentCapabilities,
     //! };
     //!
@@ -351,7 +351,7 @@ pub mod reusable_components {
     //! }
     //!
     //! impl ConnectTo<Client> for MyAgent {
-    //!     async fn connect_to(self, client: impl ConnectTo<Agent>) -> Result<(), agent_client_protocol_core::Error> {
+    //!     async fn connect_to(self, client: impl ConnectTo<Agent>) -> Result<(), agent_client_protocol::Error> {
     //!         Agent.builder()
     //!             .name(&self.name)
     //!             .on_receive_request(async move |req: InitializeRequest, responder, _connection| {
@@ -359,7 +359,7 @@ pub mod reusable_components {
     //!                     InitializeResponse::new(req.protocol_version)
     //!                         .agent_capabilities(AgentCapabilities::new())
     //!                 )
-    //!             }, agent_client_protocol_core::on_receive_request!())
+    //!             }, agent_client_protocol::on_receive_request!())
     //!             .connect_to(client)
     //!             .await
     //!     }
@@ -376,9 +376,9 @@ pub mod reusable_components {
     //! - Use [`ConnectionTo::spawn`] to offload work to a background task
     //! - Use [`on_receiving_result`] to schedule work when a response arrives
     //!
-    //! [`ConnectTo`]: agent_client_protocol_core::ConnectTo
-    //! [`ConnectionTo::spawn`]: agent_client_protocol_core::ConnectionTo::spawn
-    //! [`on_receiving_result`]: agent_client_protocol_core::SentRequest::on_receiving_result
+    //! [`ConnectTo`]: agent_client_protocol::ConnectTo
+    //! [`ConnectionTo::spawn`]: agent_client_protocol::ConnectionTo::spawn
+    //! [`on_receiving_result`]: agent_client_protocol::SentRequest::on_receiving_result
     //! [`agent-client-protocol-conductor`]: https://crates.io/crates/agent-client-protocol-conductor
 }
 
@@ -396,9 +396,9 @@ pub mod custom_message_handlers {
     //! # Example
     //!
     //! ```
-    //! use agent_client_protocol_core::{HandleDispatchFrom, Dispatch, Handled, ConnectionTo, UntypedRole};
-    //! use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, AgentCapabilities};
-    //! use agent_client_protocol_core::util::MatchDispatch;
+    //! use agent_client_protocol::{HandleDispatchFrom, Dispatch, Handled, ConnectionTo, UntypedRole};
+    //! use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, AgentCapabilities};
+    //! use agent_client_protocol::util::MatchDispatch;
     //!
     //! struct MyHandler;
     //!
@@ -407,7 +407,7 @@ pub mod custom_message_handlers {
     //!         &mut self,
     //!         message: Dispatch,
     //!         _connection: ConnectionTo<UntypedRole>,
-    //!     ) -> Result<Handled<Dispatch>, agent_client_protocol_core::Error> {
+    //!     ) -> Result<Handled<Dispatch>, agent_client_protocol::Error> {
     //!         MatchDispatch::new(message)
     //!             .if_request(async |req: InitializeRequest, responder| {
     //!                 responder.respond(
@@ -431,9 +431,9 @@ pub mod custom_message_handlers {
     //! - [`MatchDispatchFrom`] - Use in proxies where messages come from different
     //!   peers (`Client` vs `Agent`) and may need different handling
     //!
-    //! [`HandleDispatchFrom`]: agent_client_protocol_core::HandleDispatchFrom
-    //! [`MatchDispatch`]: agent_client_protocol_core::util::MatchDispatch
-    //! [`MatchDispatchFrom`]: agent_client_protocol_core::util::MatchDispatchFrom
+    //! [`HandleDispatchFrom`]: agent_client_protocol::HandleDispatchFrom
+    //! [`MatchDispatch`]: agent_client_protocol::util::MatchDispatch
+    //! [`MatchDispatchFrom`]: agent_client_protocol::util::MatchDispatchFrom
 }
 
 pub mod global_mcp_server {
@@ -454,8 +454,8 @@ pub mod global_mcp_server {
     //! The simplest way to create an MCP server is with [`McpServer::builder`]:
     //!
     //! ```
-    //! use agent_client_protocol_core::mcp_server::McpServer;
-    //! use agent_client_protocol_core::{ConnectTo, RunWithConnectionTo, Proxy, Conductor};
+    //! use agent_client_protocol::mcp_server::McpServer;
+    //! use agent_client_protocol::{ConnectTo, RunWithConnectionTo, Proxy, Conductor};
     //! use schemars::JsonSchema;
     //! use serde::{Deserialize, Serialize};
     //!
@@ -471,7 +471,7 @@ pub mod global_mcp_server {
     //!         async |params: EchoParams, _cx| {
     //!             Ok(EchoOutput { echoed: params.message })
     //!         },
-    //!         agent_client_protocol_core::tool_fn!())
+    //!         agent_client_protocol::tool_fn!())
     //!     .build();
     //!
     //! // The proxy component is generic over the MCP server's responder type
@@ -480,7 +480,7 @@ pub mod global_mcp_server {
     //! }
     //!
     //! impl<R: RunWithConnectionTo<Conductor> + Send + 'static> ConnectTo<Conductor> for MyProxy<R> {
-    //!     async fn connect_to(self, conductor: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+    //!     async fn connect_to(self, conductor: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
     //!         Proxy.builder()
     //!             .with_mcp_server(self.mcp_server)
     //!             .connect_to(conductor)
@@ -501,8 +501,8 @@ pub mod global_mcp_server {
     //! use rmcp::handler::server::router::tool::ToolRouter;
     //! use rmcp::handler::server::wrapper::Parameters;
     //! use rmcp::model::*;
-    //! use agent_client_protocol_core::mcp_server::McpServer;
-    //! use agent_client_protocol_core::Conductor;
+    //! use agent_client_protocol::mcp_server::McpServer;
+    //! use agent_client_protocol::Conductor;
     //! use agent_client_protocol_rmcp::McpServerExt;
     //! use serde::{Deserialize, Serialize};
     //!
@@ -556,9 +556,9 @@ pub mod global_mcp_server {
     //! 2. Passes the modified request through to the next handler
     //! 3. Handles incoming MCP protocol messages (tool calls, etc.) for its URL
     //!
-    //! [`McpServer::builder`]: agent_client_protocol_core::mcp_server::McpServer::builder
+    //! [`McpServer::builder`]: agent_client_protocol::mcp_server::McpServer::builder
     //! [`McpServer::from_rmcp`]: agent_client_protocol_rmcp::McpServerExt::from_rmcp
-    //! [`with_mcp_server`]: agent_client_protocol_core::Builder::with_mcp_server
+    //! [`with_mcp_server`]: agent_client_protocol::Builder::with_mcp_server
 }
 
 pub mod per_session_mcp_server {
@@ -580,11 +580,11 @@ pub mod per_session_mcp_server {
     //! run code after the session is established:
     //!
     //! ```
-    //! use agent_client_protocol_core::mcp_server::McpServer;
-    //! use agent_client_protocol_core::schema::NewSessionRequest;
-    //! use agent_client_protocol_core::{Client, Proxy, Conductor, ConnectTo};
+    //! use agent_client_protocol::mcp_server::McpServer;
+    //! use agent_client_protocol::schema::NewSessionRequest;
+    //! use agent_client_protocol::{Client, Proxy, Conductor, ConnectTo};
     //!
-    //! async fn run_proxy(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+    //! async fn run_proxy(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
     //!     Proxy.builder()
     //!         .on_receive_request_from(Client, async move |request: NewSessionRequest, responder, connection| {
     //!             // Extract session context from the request
@@ -596,7 +596,7 @@ pub mod per_session_mcp_server {
     //!                     async move |_params: (), _cx| {
     //!                         Ok(workspace_path.display().to_string())
     //!                     }
-    //!                 }, agent_client_protocol_core::tool_fn!())
+    //!                 }, agent_client_protocol::tool_fn!())
     //!                 .build();
     //!
     //!             // Build the session and run code after it starts
@@ -613,7 +613,7 @@ pub mod per_session_mcp_server {
     //!                     tracing::info!(%session_id, "Session started");
     //!                     Ok(())
     //!                 })
-    //!         }, agent_client_protocol_core::on_receive_request!())
+    //!         }, agent_client_protocol::on_receive_request!())
     //!         .connect_to(transport)
     //!         .await
     //! }
@@ -638,17 +638,17 @@ pub mod per_session_mcp_server {
     //! blocking is safe), use [`block_task`] + [`start_session_proxy`]:
     //!
     //! ```
-    //! # use agent_client_protocol_core::mcp_server::McpServer;
-    //! # use agent_client_protocol_core::schema::NewSessionRequest;
-    //! # use agent_client_protocol_core::{Client, Proxy, Conductor, ConnectTo};
-    //! # async fn run_proxy(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+    //! # use agent_client_protocol::mcp_server::McpServer;
+    //! # use agent_client_protocol::schema::NewSessionRequest;
+    //! # use agent_client_protocol::{Client, Proxy, Conductor, ConnectTo};
+    //! # async fn run_proxy(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
     //!     Proxy.builder()
     //!         .on_receive_request_from(Client, async |request: NewSessionRequest, responder, connection| {
     //!             let cwd = request.cwd.clone();
     //!             let mcp_server = McpServer::builder("tools")
     //!                 .tool_fn("get_cwd", "Returns working directory", {
     //!                     async move |_params: (), _cx| Ok(cwd.display().to_string())
-    //!                 }, agent_client_protocol_core::tool_fn!())
+    //!                 }, agent_client_protocol::tool_fn!())
     //!                 .build();
     //!
     //!             let session_id = connection.build_session_from(request)
@@ -659,7 +659,7 @@ pub mod per_session_mcp_server {
     //!
     //!             tracing::info!(%session_id, "Session started");
     //!             Ok(())
-    //!         }, agent_client_protocol_core::on_receive_request!())
+    //!         }, agent_client_protocol::on_receive_request!())
     //!         .connect_to(transport)
     //!         .await
     //! # }
@@ -668,13 +668,13 @@ pub mod per_session_mcp_server {
     //! For patterns where you need to interact with the session before proxying,
     //! use [`start_session`] + [`proxy_remaining_messages`] instead.
     //!
-    //! [`start_session`]: agent_client_protocol_core::SessionBuilder::start_session
-    //! [`proxy_remaining_messages`]: agent_client_protocol_core::ActiveSession::proxy_remaining_messages
+    //! [`start_session`]: agent_client_protocol::SessionBuilder::start_session
+    //! [`proxy_remaining_messages`]: agent_client_protocol::ActiveSession::proxy_remaining_messages
     //!
-    //! [`NewSessionRequest`]: agent_client_protocol_core::schema::NewSessionRequest
-    //! [`on_proxy_session_start`]: agent_client_protocol_core::SessionBuilder::on_proxy_session_start
-    //! [`block_task`]: agent_client_protocol_core::SessionBuilder::block_task
-    //! [`start_session_proxy`]: agent_client_protocol_core::SessionBuilder::start_session_proxy
+    //! [`NewSessionRequest`]: agent_client_protocol::schema::NewSessionRequest
+    //! [`on_proxy_session_start`]: agent_client_protocol::SessionBuilder::on_proxy_session_start
+    //! [`block_task`]: agent_client_protocol::SessionBuilder::block_task
+    //! [`start_session_proxy`]: agent_client_protocol::SessionBuilder::start_session_proxy
 }
 
 pub mod filtering_tools {
@@ -693,22 +693,22 @@ pub mod filtering_tools {
     //! hide specific tools:
     //!
     //! ```
-    //! use agent_client_protocol_core::mcp_server::McpServer;
-    //! use agent_client_protocol_core::{Conductor, RunWithConnectionTo};
+    //! use agent_client_protocol::mcp_server::McpServer;
+    //! use agent_client_protocol::{Conductor, RunWithConnectionTo};
     //! use schemars::JsonSchema;
     //! use serde::Deserialize;
     //!
     //! #[derive(Debug, Deserialize, JsonSchema)]
     //! struct Params {}
     //!
-    //! fn build_server(enable_admin: bool) -> Result<McpServer<Conductor, impl RunWithConnectionTo<Conductor>>, agent_client_protocol_core::Error> {
+    //! fn build_server(enable_admin: bool) -> Result<McpServer<Conductor, impl RunWithConnectionTo<Conductor>>, agent_client_protocol::Error> {
     //!     let mut builder = McpServer::builder("my-server")
     //!         .tool_fn("echo", "Echo a message",
     //!             async |_p: Params, _cx| Ok("echoed"),
-    //!             agent_client_protocol_core::tool_fn!())
+    //!             agent_client_protocol::tool_fn!())
     //!         .tool_fn("admin", "Admin-only tool",
     //!             async |_p: Params, _cx| Ok("admin action"),
-    //!             agent_client_protocol_core::tool_fn!());
+    //!             agent_client_protocol::tool_fn!());
     //!
     //!     // Conditionally disable the admin tool
     //!     if !enable_admin {
@@ -729,25 +729,25 @@ pub mod filtering_tools {
     //! allow-list where only explicitly enabled tools are available:
     //!
     //! ```
-    //! use agent_client_protocol_core::mcp_server::McpServer;
-    //! use agent_client_protocol_core::{Conductor, RunWithConnectionTo};
+    //! use agent_client_protocol::mcp_server::McpServer;
+    //! use agent_client_protocol::{Conductor, RunWithConnectionTo};
     //! use schemars::JsonSchema;
     //! use serde::Deserialize;
     //!
     //! #[derive(Debug, Deserialize, JsonSchema)]
     //! struct Params {}
     //!
-    //! fn build_restricted_server() -> Result<McpServer<Conductor, impl RunWithConnectionTo<Conductor>>, agent_client_protocol_core::Error> {
+    //! fn build_restricted_server() -> Result<McpServer<Conductor, impl RunWithConnectionTo<Conductor>>, agent_client_protocol::Error> {
     //!     McpServer::builder("restricted-server")
     //!         .tool_fn("safe", "Safe operation",
     //!             async |_p: Params, _cx| Ok("safe"),
-    //!             agent_client_protocol_core::tool_fn!())
+    //!             agent_client_protocol::tool_fn!())
     //!         .tool_fn("dangerous", "Dangerous operation",
     //!             async |_p: Params, _cx| Ok("danger!"),
-    //!             agent_client_protocol_core::tool_fn!())
+    //!             agent_client_protocol::tool_fn!())
     //!         .tool_fn("experimental", "Experimental feature",
     //!             async |_p: Params, _cx| Ok("experimental"),
-    //!             agent_client_protocol_core::tool_fn!())
+    //!             agent_client_protocol::tool_fn!())
     //!         // Start with all tools disabled
     //!         .disable_all_tools()
     //!         // Only enable the safe tool
@@ -762,8 +762,8 @@ pub mod filtering_tools {
     //! if the tool name doesn't match any registered tool. This helps catch typos:
     //!
     //! ```
-    //! use agent_client_protocol_core::mcp_server::McpServer;
-    //! use agent_client_protocol_core::Conductor;
+    //! use agent_client_protocol::mcp_server::McpServer;
+    //! use agent_client_protocol::Conductor;
     //!
     //! // This will error because "ech" is not a registered tool
     //! let result = McpServer::<Conductor, _>::builder("server")
@@ -775,9 +775,9 @@ pub mod filtering_tools {
     //! Calling enable/disable on an already enabled/disabled tool is not an error -
     //! the operations are idempotent.
     //!
-    //! [`disable_tool`]: agent_client_protocol_core::mcp_server::McpServerBuilder::disable_tool
-    //! [`enable_tool`]: agent_client_protocol_core::mcp_server::McpServerBuilder::enable_tool
-    //! [`disable_all_tools`]: agent_client_protocol_core::mcp_server::McpServerBuilder::disable_all_tools
+    //! [`disable_tool`]: agent_client_protocol::mcp_server::McpServerBuilder::disable_tool
+    //! [`enable_tool`]: agent_client_protocol::mcp_server::McpServerBuilder::enable_tool
+    //! [`disable_all_tools`]: agent_client_protocol::mcp_server::McpServerBuilder::disable_all_tools
 }
 
 pub mod running_proxies_with_conductor {
@@ -850,6 +850,6 @@ pub mod running_proxies_with_conductor {
     //! running with the conductor.
     //!
     //! [`agent-client-protocol-conductor`]: https://crates.io/crates/agent-client-protocol-conductor
-    //! [`SuccessorMessage`]: agent_client_protocol_core::schema::SuccessorMessage
+    //! [`SuccessorMessage`]: agent_client_protocol::schema::SuccessorMessage
     //! [`agent-client-protocol-conductor` tests]: https://github.com/anthropics/acp-rust-sdk/tree/main/src/agent-client-protocol-conductor/tests
 }
diff --git a/src/agent-client-protocol-core/CHANGELOG.md b/src/agent-client-protocol-core/CHANGELOG.md
deleted file mode 100644
index c19d951..0000000
--- a/src/agent-client-protocol-core/CHANGELOG.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
diff --git a/src/agent-client-protocol-core/Cargo.toml b/src/agent-client-protocol-core/Cargo.toml
deleted file mode 100644
index 376bb6a..0000000
--- a/src/agent-client-protocol-core/Cargo.toml
+++ /dev/null
@@ -1,68 +0,0 @@
-[package]
-name = "agent-client-protocol-core"
-version = "0.1.0"
-edition.workspace = true
-authors.workspace = true
-license.workspace = true
-repository.workspace = true
-homepage.workspace = true
-description = "Core protocol types and traits for the Agent Client Protocol"
-keywords = ["acp", "agent", "protocol", "ai"]
-categories = ["development-tools"]
-
-[features]
-default = []
-
-# Forward unstable features from agent-client-protocol-schema.
-# Enable these to get support for the corresponding unstable ACP methods.
-unstable = [
-    "unstable_auth_methods",
-    "unstable_boolean_config",
-    "unstable_logout",
-    "unstable_message_id",
-    "unstable_session_additional_directories",
-    "unstable_session_close",
-    "unstable_session_fork",
-    "unstable_session_model",
-    "unstable_session_resume",
-    "unstable_session_usage",
-]
-unstable_auth_methods = ["agent-client-protocol-schema/unstable_auth_methods"]
-unstable_boolean_config = ["agent-client-protocol-schema/unstable_boolean_config"]
-unstable_logout = ["agent-client-protocol-schema/unstable_logout"]
-unstable_message_id = ["agent-client-protocol-schema/unstable_message_id"]
-unstable_session_additional_directories = ["agent-client-protocol-schema/unstable_session_additional_directories"]
-unstable_session_close = ["agent-client-protocol-schema/unstable_session_close"]
-unstable_session_fork = ["agent-client-protocol-schema/unstable_session_fork"]
-unstable_session_model = ["agent-client-protocol-schema/unstable_session_model"]
-unstable_session_resume = ["agent-client-protocol-schema/unstable_session_resume"]
-unstable_session_usage = ["agent-client-protocol-schema/unstable_session_usage"]
-
-[dependencies]
-agent-client-protocol-schema.workspace = true
-agent-client-protocol-derive.workspace = true
-anyhow.workspace = true
-boxfnonce.workspace = true
-futures.workspace = true
-futures-concurrency.workspace = true
-rustc-hash.workspace = true
-jsonrpcmsg.workspace = true
-rmcp = { workspace = true, features = ["server"] }
-schemars.workspace = true
-serde.workspace = true
-serde_json.workspace = true
-thiserror.workspace = true
-tokio.workspace = true
-tokio-util.workspace = true
-tracing.workspace = true
-uuid.workspace = true
-
-[dev-dependencies]
-agent-client-protocol-test.workspace = true
-clap.workspace = true
-expect-test.workspace = true
-shell-words.workspace = true
-tokio.workspace = true
-
-[lints]
-workspace = true
diff --git a/src/agent-client-protocol-core/README.md b/src/agent-client-protocol-core/README.md
deleted file mode 100644
index a33a37d..0000000
--- a/src/agent-client-protocol-core/README.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# agent-client-protocol-core
-
-Core protocol types and traits for the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/).
-
-ACP is a protocol for communication between AI agents and their clients (IDEs, CLIs, etc.),
-enabling features like tool use, permission requests, and streaming responses.
-
-## What can you build with this crate?
-
-- **Clients** that talk to ACP agents (like building your own Claude Code interface)
-- **Proxies** that add capabilities to existing agents (like adding custom tools via MCP)
-- **Agents** that respond to prompts with AI-powered responses
-
-## Quick Start: Connecting to an Agent
-
-The most common use case is connecting to an existing ACP agent as a client:
-
-```rust
-use agent_client_protocol_core::{Client, Agent, ConnectTo};
-use agent_client_protocol_core::schema::{InitializeRequest, ProtocolVersion};
-
-Client.builder()
-    .name("my-client")
-    .connect_with(transport, async |cx| {
-        // Initialize the connection
-        cx.send_request(InitializeRequest::new(ProtocolVersion::V1))
-            .block_task()
-            .await?;
-
-        Ok(())
-    })
-    .await?;
-```
-
-## Learning More
-
-See the [crate documentation](https://docs.rs/agent-client-protocol-core) for:
-
-- **[Cookbook](https://docs.rs/agent-client-protocol-core/latest/agent_client_protocol_core/cookbook/)** — Patterns for building clients, proxies, and agents
-- **[Examples](https://github.com/agentclientprotocol/rust-sdk/tree/main/src/agent-client-protocol-core/examples)** — Working code you can run
-
-## Related Crates
-
-- **[agent-client-protocol-tokio](../agent-client-protocol-tokio/)** — Tokio utilities for spawning agent processes
-- **[agent-client-protocol-derive](../agent-client-protocol-derive/)** — Derive macros for JSON-RPC traits
-- **[agent-client-protocol-trace-viewer](../agent-client-protocol-trace-viewer/)** — Interactive trace visualization
-
-## License
-
-Apache-2.0
diff --git a/src/agent-client-protocol-core/src/lib.rs b/src/agent-client-protocol-core/src/lib.rs
deleted file mode 100644
index 9175751..0000000
--- a/src/agent-client-protocol-core/src/lib.rs
+++ /dev/null
@@ -1,210 +0,0 @@
-#![deny(missing_docs)]
-
-//! # agent-client-protocol-core -- the Symposium Agent Client Protocol (ACP) SDK
-//!
-//! **agent-client-protocol-core** is a Rust SDK for building [Agent-Client Protocol (ACP)][acp] applications.
-//! ACP is a protocol for communication between AI agents and their clients (IDEs, CLIs, etc.),
-//! enabling features like tool use, permission requests, and streaming responses.
-//!
-//! [acp]: https://agentclientprotocol.com/
-//!
-//! ## What can you build with agent-client-protocol-core?
-//!
-//! - **Clients** that talk to ACP agents (like building your own Claude Code interface)
-//! - **Proxies** that add capabilities to existing agents (like adding custom tools via MCP)
-//! - **Agents** that respond to prompts with AI-powered responses
-//!
-//! ## Quick Start: Connecting to an Agent
-//!
-//! The most common use case is connecting to an existing ACP agent as a client.
-//! Here's a minimal example that initializes a connection, creates a session,
-//! and sends a prompt:
-//!
-//! ```no_run
-//! use agent_client_protocol_core::Client;
-//! use agent_client_protocol_core::schema::{InitializeRequest, ProtocolVersion};
-//!
-//! # async fn run(transport: impl agent_client_protocol_core::ConnectTo<agent_client_protocol_core::Client>) -> agent_client_protocol_core::Result<()> {
-//! Client.builder()
-//!     .name("my-client")
-//!     .connect_with(transport, async |cx| {
-//!         // Step 1: Initialize the connection
-//!         cx.send_request(InitializeRequest::new(ProtocolVersion::V1))
-//!             .block_task().await?;
-//!
-//!         // Step 2: Create a session and send a prompt
-//!         cx.build_session_cwd()?
-//!             .block_task()
-//!             .run_until(async |mut session| {
-//!                 session.send_prompt("What is 2 + 2?")?;
-//!                 let response = session.read_to_string().await?;
-//!                 println!("{}", response);
-//!                 Ok(())
-//!             })
-//!             .await
-//!     })
-//!     .await
-//! # }
-//! ```
-//!
-//! For a complete working example, see [`yolo_one_shot_client.rs`][yolo].
-//!
-//! [yolo]: https://github.com/agentclientprotocol/rust-sdk/blob/main/src/agent-client-protocol-core/examples/yolo_one_shot_client.rs
-//!
-//! ## Cookbook
-//!
-//! The [`agent_client_protocol_cookbook`] crate contains practical guides and examples:
-//!
-//! - Connecting as a client
-//! - Global MCP server
-//! - Per-session MCP server with workspace context
-//! - Building agents and reusable components
-//! - Running proxies with the conductor
-//!
-//! [`agent_client_protocol_cookbook`]: https://docs.rs/agent-client-protocol-cookbook
-//!
-//! ## Core Concepts
-//!
-//! The [`concepts`] module provides detailed explanations of how agent-client-protocol-core works,
-//! including connections, sessions, callbacks, ordering guarantees, and more.
-//!
-//! ## Related Crates
-//!
-//! - [`agent-client-protocol-tokio`] - Tokio utilities for spawning agent processes
-//! - [`agent-client-protocol-conductor`] - Binary for running proxy chains
-//!
-//! [`agent-client-protocol-tokio`]: https://crates.io/crates/agent-client-protocol-tokio
-//! [`agent-client-protocol-conductor`]: https://crates.io/crates/agent-client-protocol-conductor
-
-/// Capability management for the `_meta.symposium` object
-mod capabilities;
-/// Component abstraction for agents and proxies
-pub mod component;
-/// Core concepts for understanding and using agent-client-protocol-core
-pub mod concepts;
-/// Cookbook of common patterns for building ACP components
-pub mod cookbook;
-/// JSON-RPC handler types for building custom message handlers
-pub mod handler;
-/// JSON-RPC connection and handler infrastructure
-mod jsonrpc;
-/// MCP server support for providing MCP tools over ACP
-pub mod mcp_server;
-/// Role types for ACP connections
-pub mod role;
-/// ACP protocol schema types - all message types, requests, responses, and supporting types
-pub mod schema;
-/// Utility functions and types
-pub mod util;
-
-pub use capabilities::*;
-
-/// JSON-RPC message types.
-///
-/// This module re-exports types from the `jsonrpcmsg` crate that are transitively
-/// reachable through the public API (e.g., via [`Channel`]).
-///
-/// Users of the `agent-client-protocol-core` crate can use these types without adding a direct dependency
-/// on `jsonrpcmsg`.
-pub mod jsonrpcmsg {
-    pub use jsonrpcmsg::{Error, Id, Message, Params, Request, Response};
-}
-
-pub use jsonrpc::{
-    Builder, ByteStreams, Channel, ConnectionTo, Dispatch, HandleDispatchFrom, Handled,
-    IntoHandled, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, Lines,
-    NullHandler, Responder, ResponseRouter, SentRequest, UntypedMessage,
-    run::{ChainRun, NullRun, RunWithConnectionTo},
-};
-
-pub use role::{
-    Role, RoleId, UntypedRole,
-    acp::{Agent, Client, Conductor, Proxy},
-};
-
-pub use component::{ConnectTo, DynConnectTo};
-
-// Re-export BoxFuture for implementing Component traits
-pub use futures::future::BoxFuture;
-
-// Re-export the six primary message enum types at the root
-pub use schema::{
-    AgentNotification, AgentRequest, AgentResponse, ClientNotification, ClientRequest,
-    ClientResponse,
-};
-
-// Re-export commonly used infrastructure types for convenience
-pub use schema::{Error, ErrorCode, Result};
-
-// Re-export derive macros for custom JSON-RPC types
-pub use agent_client_protocol_derive::{JsonRpcNotification, JsonRpcRequest, JsonRpcResponse};
-
-mod session;
-pub use session::*;
-
-/// This is a hack that must be given as the final argument of
-/// [`McpServerBuilder::tool_fn`](`crate::mcp_server::McpServerBuilder::tool_fn`) when defining tools.
-/// Look away, lest ye be blinded by its vileness!
-///
-/// Fine, if you MUST know, it's a horrific workaround for not having
-/// [return-type notation](https://github.com/rust-lang/rust/issues/109417)
-/// and for [this !@$#!%! bug](https://github.com/rust-lang/rust/issues/110338).
-/// Trust me, the need for it hurts me more than it hurts you. --nikomatsakis
-#[macro_export]
-macro_rules! tool_fn_mut {
-    () => {
-        |func, params, context| Box::pin(func(params, context))
-    };
-}
-
-/// This is a hack that must be given as the final argument of
-/// [`McpServerBuilder::tool_fn`](`crate::mcp_server::McpServerBuilder::tool_fn`) when defining stateless concurrent tools.
-/// See [`tool_fn_mut!`] for the gory details.
-#[macro_export]
-macro_rules! tool_fn {
-    () => {
-        |func, params, context| Box::pin(func(params, context))
-    };
-}
-
-/// This macro is used for the value of the `to_future_hack` parameter of
-/// [`Builder::on_receive_request`] and [`Builder::on_receive_request_from`].
-///
-/// It expands to `|f, req, responder, cx| Box::pin(f(req, responder, cx))`.
-///
-/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
-/// is stabilized.
-#[macro_export]
-macro_rules! on_receive_request {
-    () => {
-        |f: &mut _, req, responder, cx| Box::pin(f(req, responder, cx))
-    };
-}
-
-/// This macro is used for the value of the `to_future_hack` parameter of
-/// [`Builder::on_receive_notification`] and [`Builder::on_receive_notification_from`].
-///
-/// It expands to `|f, notif, cx| Box::pin(f(notif, cx))`.
-///
-/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
-/// is stabilized.
-#[macro_export]
-macro_rules! on_receive_notification {
-    () => {
-        |f: &mut _, notif, cx| Box::pin(f(notif, cx))
-    };
-}
-
-/// This macro is used for the value of the `to_future_hack` parameter of
-/// [`Builder::on_receive_dispatch`] and [`Builder::on_receive_dispatch_from`].
-///
-/// It expands to `|f, dispatch, cx| Box::pin(f(dispatch, cx))`.
-///
-/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
-/// is stabilized.
-#[macro_export]
-macro_rules! on_receive_dispatch {
-    () => {
-        |f: &mut _, dispatch, cx| Box::pin(f(dispatch, cx))
-    };
-}
diff --git a/src/agent-client-protocol-derive/Cargo.toml b/src/agent-client-protocol-derive/Cargo.toml
index 597e553..976d3fe 100644
--- a/src/agent-client-protocol-derive/Cargo.toml
+++ b/src/agent-client-protocol-derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "agent-client-protocol-derive"
-version = "0.1.0"
+version = "0.11.0"
 edition.workspace = true
 authors.workspace = true
 license.workspace = true
diff --git a/src/agent-client-protocol-derive/src/lib.rs b/src/agent-client-protocol-derive/src/lib.rs
index 9275858..325ed57 100644
--- a/src/agent-client-protocol-derive/src/lib.rs
+++ b/src/agent-client-protocol-derive/src/lib.rs
@@ -46,7 +46,7 @@ use syn::{DeriveInput, Expr, Lit, Path, Type, parse_macro_input};
 /// # Attributes
 ///
 /// - `#[request(method = "method_name", response = ResponseType)]`
-/// - `#[request(method = "method_name", response = ResponseType, crate = crate)]` - for use within the `agent_client_protocol_core` crate
+/// - `#[request(method = "method_name", response = ResponseType, crate = crate)]` - for use within the `agent_client_protocol` crate
 ///
 /// # Example
 ///
@@ -106,7 +106,7 @@ pub fn derive_json_rpc_request(input: TokenStream) -> TokenStream {
 /// # Attributes
 ///
 /// - `#[notification(method = "method_name")]`
-/// - `#[notification(method = "method_name", crate = crate)]` - for use within the `agent_client_protocol_core` crate
+/// - `#[notification(method = "method_name", crate = crate)]` - for use within the `agent_client_protocol` crate
 ///
 /// # Example
 ///
@@ -163,7 +163,7 @@ pub fn derive_json_rpc_notification(input: TokenStream) -> TokenStream {
 ///
 /// # Attributes
 ///
-/// - `#[response(crate = crate)]` - for use within the `agent_client_protocol_core` crate
+/// - `#[response(crate = crate)]` - for use within the `agent_client_protocol` crate
 ///
 /// # Example
 ///
@@ -199,7 +199,7 @@ pub fn derive_json_rpc_response_payload(input: TokenStream) -> TokenStream {
 }
 
 fn default_crate_path() -> Path {
-    syn::parse_quote!(agent_client_protocol_core)
+    syn::parse_quote!(agent_client_protocol)
 }
 
 fn parse_request_attrs(input: &DeriveInput) -> syn::Result<(String, Type, Path)> {
diff --git a/src/agent-client-protocol-rmcp/Cargo.toml b/src/agent-client-protocol-rmcp/Cargo.toml
index 48c9efe..1550958 100644
--- a/src/agent-client-protocol-rmcp/Cargo.toml
+++ b/src/agent-client-protocol-rmcp/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "agent-client-protocol-rmcp"
-version = "0.1.0"
+version = "0.11.0"
 edition.workspace = true
 authors.workspace = true
 license.workspace = true
@@ -11,7 +11,7 @@ keywords = ["acp", "agent", "proxy", "mcp", "rmcp"]
 categories = ["development-tools"]
 
 [dependencies]
-agent-client-protocol-core.workspace = true
+agent-client-protocol.workspace = true
 futures.workspace = true
 futures-concurrency.workspace = true
 rmcp.workspace = true
diff --git a/src/agent-client-protocol-rmcp/README.md b/src/agent-client-protocol-rmcp/README.md
index c4fb9c5..7c2738a 100644
--- a/src/agent-client-protocol-rmcp/README.md
+++ b/src/agent-client-protocol-rmcp/README.md
@@ -4,14 +4,14 @@
 
 ## Overview
 
-This crate bridges [rmcp](https://docs.rs/rmcp)-based MCP server implementations with the ACP MCP server framework from `agent-client-protocol-core`. It lets you use any rmcp service as an MCP server in an ACP proxy.
+This crate bridges [rmcp](https://docs.rs/rmcp)-based MCP server implementations with the ACP MCP server framework from `agent-client-protocol`. It lets you use any rmcp service as an MCP server in an ACP proxy.
 
 ## Usage
 
 Use the `McpServerExt` trait to create an MCP server from an rmcp service:
 
 ```rust
-use agent_client_protocol_core::mcp_server::McpServer;
+use agent_client_protocol::mcp_server::McpServer;
 use agent_client_protocol_rmcp::McpServerExt;
 
 let server = McpServer::from_rmcp("my-server", MyRmcpService::new);
@@ -25,15 +25,15 @@ Proxy.builder()
 
 ## Why a Separate Crate?
 
-This crate is separate from `agent-client-protocol-core` to avoid coupling the core protocol crate to the `rmcp` dependency. This allows:
+This crate is separate from `agent-client-protocol` to avoid coupling the core protocol crate to the `rmcp` dependency. This allows:
 
-- `agent-client-protocol-core` to remain focused on the ACP protocol
+- `agent-client-protocol` to remain focused on the ACP protocol
 - `agent-client-protocol-rmcp` to track `rmcp` updates independently
 - Breaking changes in `rmcp` only require updating this crate
 
 ## Related Crates
 
-- **[agent-client-protocol-core](../agent-client-protocol-core/)** — Core ACP protocol types and traits
+- **[agent-client-protocol](../agent-client-protocol/)** — Core ACP protocol types and traits
 - **[agent-client-protocol-tokio](../agent-client-protocol-tokio/)** — Tokio utilities for spawning agent processes
 
 ## License
diff --git a/src/agent-client-protocol-rmcp/examples/with_mcp_server.rs b/src/agent-client-protocol-rmcp/examples/with_mcp_server.rs
index 7b8139c..68856da 100644
--- a/src/agent-client-protocol-rmcp/examples/with_mcp_server.rs
+++ b/src/agent-client-protocol-rmcp/examples/with_mcp_server.rs
@@ -8,7 +8,7 @@
 //! cargo run --example with_mcp_server
 //! ```
 
-use agent_client_protocol_core::{Proxy, mcp_server::McpServer};
+use agent_client_protocol::{Proxy, mcp_server::McpServer};
 use agent_client_protocol_rmcp::McpServerExt;
 use rmcp::{
     ErrorData as McpError, ServerHandler,
@@ -93,7 +93,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
         // Register the MCP server as a handler
         .with_mcp_server(mcp_server)
         // Start serving
-        .connect_to(agent_client_protocol_core::ByteStreams::new(
+        .connect_to(agent_client_protocol::ByteStreams::new(
             tokio::io::stdout().compat_write(),
             tokio::io::stdin().compat(),
         ))
diff --git a/src/agent-client-protocol-rmcp/src/lib.rs b/src/agent-client-protocol-rmcp/src/lib.rs
index 4b436c9..7faf143 100644
--- a/src/agent-client-protocol-rmcp/src/lib.rs
+++ b/src/agent-client-protocol-rmcp/src/lib.rs
@@ -8,7 +8,7 @@
 //! Create an MCP server from an rmcp service using the extension trait:
 //!
 //! ```ignore
-//! use agent_client_protocol_core::mcp_server::McpServer;
+//! use agent_client_protocol::mcp_server::McpServer;
 //! use agent_client_protocol_rmcp::McpServerExt;
 //!
 //! let server = McpServer::from_rmcp("my-server", MyRmcpService::new);
@@ -20,9 +20,9 @@
 //!     .await?;
 //! ```
 
-use agent_client_protocol_core::mcp_server::{McpConnectionTo, McpServer, McpServerConnect};
-use agent_client_protocol_core::role::{self, HasPeer};
-use agent_client_protocol_core::{Agent, ByteStreams, ConnectTo, DynConnectTo, NullRun, Role};
+use agent_client_protocol::mcp_server::{McpConnectionTo, McpServer, McpServerConnect};
+use agent_client_protocol::role::{self, HasPeer};
+use agent_client_protocol::{Agent, ByteStreams, ConnectTo, DynConnectTo, NullRun, Role};
 use futures_concurrency::future::TryJoin as _;
 use rmcp::ServiceExt;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
@@ -94,7 +94,7 @@ where
     async fn connect_to(
         self,
         client: impl ConnectTo<role::mcp::Server>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         // Create tokio byte streams that rmcp expects
         let (mcp_server_stream, mcp_client_stream) = tokio::io::duplex(8192);
         let (mcp_server_read, mcp_server_write) = tokio::io::split(mcp_server_stream);
@@ -117,14 +117,14 @@ where
                 .service
                 .serve((mcp_server_read, mcp_server_write))
                 .await
-                .map_err(agent_client_protocol_core::Error::into_internal_error)?;
+                .map_err(agent_client_protocol::Error::into_internal_error)?;
 
             // Wait for the server to finish
             running_server
                 .waiting()
                 .await
                 .map(|_quit_reason| ())
-                .map_err(agent_client_protocol_core::Error::into_internal_error)
+                .map_err(agent_client_protocol::Error::into_internal_error)
         };
 
         (bytes_to_acp, bytes_to_rmcp).try_join().await?;
diff --git a/src/agent-client-protocol-test/Cargo.toml b/src/agent-client-protocol-test/Cargo.toml
index e404df6..2ea2fde 100644
--- a/src/agent-client-protocol-test/Cargo.toml
+++ b/src/agent-client-protocol-test/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "agent-client-protocol-test"
-version = "0.1.0"
+version = "0.11.0"
 edition.workspace = true
 authors.workspace = true
 license.workspace = true
@@ -18,7 +18,7 @@ name = "testy"
 path = "src/bin/testy.rs"
 
 [dependencies]
-agent-client-protocol-core.workspace = true
+agent-client-protocol.workspace = true
 agent-client-protocol-tokio.workspace = true
 yopo.workspace = true
 anyhow.workspace = true
diff --git a/src/agent-client-protocol-test/examples/arrow_proxy.rs b/src/agent-client-protocol-test/examples/arrow_proxy.rs
index 3b7b2bb..bd425f8 100644
--- a/src/agent-client-protocol-test/examples/arrow_proxy.rs
+++ b/src/agent-client-protocol-test/examples/arrow_proxy.rs
@@ -20,7 +20,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let stdout = tokio::io::stdout().compat_write();
 
     // Run the arrow proxy
-    run_arrow_proxy(agent_client_protocol_core::ByteStreams::new(stdout, stdin)).await?;
+    run_arrow_proxy(agent_client_protocol::ByteStreams::new(stdout, stdin)).await?;
 
     Ok(())
 }
diff --git a/src/agent-client-protocol-test/src/arrow_proxy.rs b/src/agent-client-protocol-test/src/arrow_proxy.rs
index 5a95767..6a006b9 100644
--- a/src/agent-client-protocol-test/src/arrow_proxy.rs
+++ b/src/agent-client-protocol-test/src/arrow_proxy.rs
@@ -3,10 +3,10 @@
 //! This proxy demonstrates basic proxy functionality by intercepting
 //! `session/update` notifications and prepending `>` to the content.
 
-use agent_client_protocol_core::schema::{
+use agent_client_protocol::schema::{
     ContentBlock, ContentChunk, SessionNotification, SessionUpdate,
 };
-use agent_client_protocol_core::{Agent, Client, ConnectTo, Proxy};
+use agent_client_protocol::{Agent, Client, ConnectTo, Proxy};
 
 /// Run the arrow proxy that adds `>` to each session update.
 ///
@@ -15,7 +15,7 @@ use agent_client_protocol_core::{Agent, Client, ConnectTo, Proxy};
 /// * `transport` - Component to the predecessor (conductor or another proxy)
 pub async fn run_arrow_proxy(
     transport: impl ConnectTo<Proxy> + 'static,
-) -> Result<(), agent_client_protocol_core::Error> {
+) -> Result<(), agent_client_protocol::Error> {
     Proxy
         .builder()
         .name("arrow-proxy")
@@ -40,7 +40,7 @@ pub async fn run_arrow_proxy(
                 cx.send_notification_to(Client, notification)?;
                 Ok(())
             },
-            agent_client_protocol_core::on_receive_notification!(),
+            agent_client_protocol::on_receive_notification!(),
         )
         .connect_to(transport)
         .await
diff --git a/src/agent-client-protocol-test/src/bin/testy.rs b/src/agent-client-protocol-test/src/bin/testy.rs
index 72834f9..76b67dd 100644
--- a/src/agent-client-protocol-test/src/bin/testy.rs
+++ b/src/agent-client-protocol-test/src/bin/testy.rs
@@ -1,4 +1,4 @@
-use agent_client_protocol_core::ConnectTo;
+use agent_client_protocol::ConnectTo;
 use agent_client_protocol_test::testy::Testy;
 
 #[tokio::main]
diff --git a/src/agent-client-protocol-test/src/lib.rs b/src/agent-client-protocol-test/src/lib.rs
index 8833d68..166c797 100644
--- a/src/agent-client-protocol-test/src/lib.rs
+++ b/src/agent-client-protocol-test/src/lib.rs
@@ -1,4 +1,4 @@
-use agent_client_protocol_core::*;
+use agent_client_protocol::*;
 use serde::{Deserialize, Serialize};
 
 pub mod arrow_proxy;
@@ -129,7 +129,7 @@ macro_rules! impl_jr_message {
                 if !Self::matches_method(method) {
                     return Err(crate::Error::method_not_found());
                 }
-                agent_client_protocol_core::util::json_cast_params(params)
+                agent_client_protocol::util::json_cast_params(params)
             }
         }
     };
diff --git a/src/agent-client-protocol-test/src/testy.rs b/src/agent-client-protocol-test/src/testy.rs
index 3e3d5ea..d882fdf 100644
--- a/src/agent-client-protocol-test/src/testy.rs
+++ b/src/agent-client-protocol-test/src/testy.rs
@@ -2,12 +2,12 @@
 //!
 //! The agent accepts JSON-serialized [`TestyCommand`] values as prompt text.
 
-use agent_client_protocol_core::schema::{
+use agent_client_protocol::schema::{
     AgentCapabilities, ContentBlock, ContentChunk, InitializeRequest, InitializeResponse,
     McpServer, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse, SessionId,
     SessionNotification, SessionUpdate, StopReason, TextContent,
 };
-use agent_client_protocol_core::{Agent, Client, ConnectTo, ConnectionTo, Responder};
+use agent_client_protocol::{Agent, Client, ConnectTo, ConnectionTo, Responder};
 use anyhow::Result;
 use serde::{Deserialize, Serialize};
 use std::collections::HashMap;
@@ -88,7 +88,7 @@ impl Testy {
         request: PromptRequest,
         responder: Responder<PromptResponse>,
         connection: ConnectionTo<Client>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         let session_id = request.session_id.clone();
         let input_text = extract_text_from_prompt(&request.prompt);
 
@@ -258,7 +258,7 @@ impl ConnectTo<Client> for Testy {
     async fn connect_to(
         self,
         client: impl ConnectTo<Agent>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         Agent
             .builder()
             .name("test-agent")
@@ -269,7 +269,7 @@ impl ConnectTo<Client> for Testy {
                             .agent_capabilities(AgentCapabilities::new()),
                     )
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             .on_receive_request(
                 {
@@ -280,7 +280,7 @@ impl ConnectTo<Client> for Testy {
                         responder.respond(NewSessionResponse::new(session_id))
                     }
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             .on_receive_request(
                 {
@@ -293,7 +293,7 @@ impl ConnectTo<Client> for Testy {
                         })
                     }
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             )
             .connect_to(client)
             .await
diff --git a/src/agent-client-protocol-tokio/Cargo.toml b/src/agent-client-protocol-tokio/Cargo.toml
index be67f97..92b6c89 100644
--- a/src/agent-client-protocol-tokio/Cargo.toml
+++ b/src/agent-client-protocol-tokio/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "agent-client-protocol-tokio"
-version = "0.1.0"
+version = "0.11.0"
 edition.workspace = true
 authors.workspace = true
 license.workspace = true
@@ -11,7 +11,7 @@ keywords = ["acp", "agent", "protocol", "ai", "tokio"]
 categories = ["development-tools"]
 
 [dependencies]
-agent-client-protocol-core.workspace = true
+agent-client-protocol.workspace = true
 futures.workspace = true
 serde.workspace = true
 serde_json.workspace = true
diff --git a/src/agent-client-protocol-tokio/README.md b/src/agent-client-protocol-tokio/README.md
index 146f230..850a9e6 100644
--- a/src/agent-client-protocol-tokio/README.md
+++ b/src/agent-client-protocol-tokio/README.md
@@ -14,7 +14,7 @@ This crate provides helpers for spawning and connecting to ACP agents using the
 The main use case is spawning an agent process and connecting to it:
 
 ```rust
-use agent_client_protocol_core::{Client, ConnectTo};
+use agent_client_protocol::{Client, ConnectTo};
 use agent_client_protocol_tokio::AcpAgent;
 use std::str::FromStr;
 
@@ -47,11 +47,11 @@ Use `agent-client-protocol-tokio` when you need to:
 - Build tools that orchestrate multiple agents
 
 If you're implementing an agent that listens on stdin/stdout, you only need the core
-[`agent-client-protocol-core`](../agent-client-protocol-core/) crate.
+[`agent-client-protocol`](../agent-client-protocol/) crate.
 
 ## Related Crates
 
-- **[agent-client-protocol-core](../agent-client-protocol-core/)** — Core ACP protocol types and traits
+- **[agent-client-protocol](../agent-client-protocol/)** — Core ACP protocol types and traits
 - **[agent-client-protocol-derive](../agent-client-protocol-derive/)** — Derive macros for JSON-RPC traits
 - **[agent-client-protocol-trace-viewer](../agent-client-protocol-trace-viewer/)** — Interactive trace visualization
 
diff --git a/src/agent-client-protocol-tokio/src/acp_agent.rs b/src/agent-client-protocol-tokio/src/acp_agent.rs
index 1139ae2..acdfea4 100644
--- a/src/agent-client-protocol-tokio/src/acp_agent.rs
+++ b/src/agent-client-protocol-tokio/src/acp_agent.rs
@@ -1,13 +1,13 @@
 //! Utilities for connecting to ACP agents and proxies.
 //!
-//! This module provides [`AcpAgent`], a convenient wrapper around [`agent_client_protocol_core::schema::McpServer`]
+//! This module provides [`AcpAgent`], a convenient wrapper around [`agent_client_protocol::schema::McpServer`]
 //! that can be parsed from either a command string or JSON configuration.
 
 use std::path::PathBuf;
 use std::str::FromStr;
 use std::sync::Arc;
 
-use agent_client_protocol_core::{Client, Conductor, Role};
+use agent_client_protocol::{Client, Conductor, Role};
 use tokio::process::Child;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 
@@ -24,12 +24,12 @@ pub enum LineDirection {
 
 /// A component representing an external ACP agent running in a separate process.
 ///
-/// `AcpAgent` implements the [`agent_client_protocol_core::ConnectTo`] trait for spawning and communicating with
+/// `AcpAgent` implements the [`agent_client_protocol::ConnectTo`] trait for spawning and communicating with
 /// external agents or proxies via stdio. It handles process spawning, stream setup, and
 /// byte stream serialization automatically. This is the primary way to connect to agents
 /// that run as separate executables.
 ///
-/// This is a wrapper around [`agent_client_protocol_core::schema::McpServer`] that provides convenient parsing
+/// This is a wrapper around [`agent_client_protocol::schema::McpServer`] that provides convenient parsing
 /// from command-line strings or JSON configurations.
 ///
 /// # Use Cases
@@ -57,7 +57,7 @@ pub enum LineDirection {
 ///
 /// Use as a component to connect to an external agent:
 /// ```ignore
-/// use agent_client_protocol_core::{Client, Builder};
+/// use agent_client_protocol::{Client, Builder};
 /// use agent_client_protocol_tokio::AcpAgent;
 /// use std::str::FromStr;
 ///
@@ -79,7 +79,7 @@ pub enum LineDirection {
 ///
 /// [`agent_client_protocol_conductor::Conductor`]: https://docs.rs/agent-client-protocol-conductor/latest/agent_client_protocol_conductor/struct.Conductor.html
 pub struct AcpAgent {
-    server: agent_client_protocol_core::schema::McpServer,
+    server: agent_client_protocol::schema::McpServer,
     debug_callback: Option<Arc<dyn Fn(&str, LineDirection) + Send + Sync + 'static>>,
 }
 
@@ -96,9 +96,9 @@ impl std::fmt::Debug for AcpAgent {
 }
 
 impl AcpAgent {
-    /// Create a new `AcpAgent` from an [`agent_client_protocol_core::schema::McpServer`] configuration.
+    /// Create a new `AcpAgent` from an [`agent_client_protocol::schema::McpServer`] configuration.
     #[must_use]
-    pub fn new(server: agent_client_protocol_core::schema::McpServer) -> Self {
+    pub fn new(server: agent_client_protocol::schema::McpServer) -> Self {
         Self {
             server,
             debug_callback: None,
@@ -127,15 +127,15 @@ impl AcpAgent {
             .expect("valid bash command")
     }
 
-    /// Get the underlying [`agent_client_protocol_core::schema::McpServer`] configuration.
+    /// Get the underlying [`agent_client_protocol::schema::McpServer`] configuration.
     #[must_use]
-    pub fn server(&self) -> &agent_client_protocol_core::schema::McpServer {
+    pub fn server(&self) -> &agent_client_protocol::schema::McpServer {
         &self.server
     }
 
-    /// Convert into the underlying [`agent_client_protocol_core::schema::McpServer`] configuration.
+    /// Convert into the underlying [`agent_client_protocol::schema::McpServer`] configuration.
     #[must_use]
-    pub fn into_server(self) -> agent_client_protocol_core::schema::McpServer {
+    pub fn into_server(self) -> agent_client_protocol::schema::McpServer {
         self.server
     }
 
@@ -175,10 +175,10 @@ impl AcpAgent {
             tokio::process::ChildStderr,
             Child,
         ),
-        agent_client_protocol_core::Error,
+        agent_client_protocol::Error,
     > {
         match &self.server {
-            agent_client_protocol_core::schema::McpServer::Stdio(stdio) => {
+            agent_client_protocol::schema::McpServer::Stdio(stdio) => {
                 let mut cmd = tokio::process::Command::new(&stdio.command);
                 cmd.args(&stdio.args);
                 for env_var in &stdio.env {
@@ -190,31 +190,31 @@ impl AcpAgent {
 
                 let mut child = cmd
                     .spawn()
-                    .map_err(agent_client_protocol_core::Error::into_internal_error)?;
+                    .map_err(agent_client_protocol::Error::into_internal_error)?;
 
                 let child_stdin = child.stdin.take().ok_or_else(|| {
-                    agent_client_protocol_core::util::internal_error("Failed to open stdin")
+                    agent_client_protocol::util::internal_error("Failed to open stdin")
                 })?;
                 let child_stdout = child.stdout.take().ok_or_else(|| {
-                    agent_client_protocol_core::util::internal_error("Failed to open stdout")
+                    agent_client_protocol::util::internal_error("Failed to open stdout")
                 })?;
                 let child_stderr = child.stderr.take().ok_or_else(|| {
-                    agent_client_protocol_core::util::internal_error("Failed to open stderr")
+                    agent_client_protocol::util::internal_error("Failed to open stderr")
                 })?;
 
                 Ok((child_stdin, child_stdout, child_stderr, child))
             }
-            agent_client_protocol_core::schema::McpServer::Http(_) => {
-                Err(agent_client_protocol_core::util::internal_error(
+            agent_client_protocol::schema::McpServer::Http(_) => {
+                Err(agent_client_protocol::util::internal_error(
                     "HTTP transport not yet supported by AcpAgent",
                 ))
             }
-            agent_client_protocol_core::schema::McpServer::Sse(_) => {
-                Err(agent_client_protocol_core::util::internal_error(
+            agent_client_protocol::schema::McpServer::Sse(_) => {
+                Err(agent_client_protocol::util::internal_error(
                     "SSE transport not yet supported by AcpAgent",
                 ))
             }
-            _ => Err(agent_client_protocol_core::util::internal_error(
+            _ => Err(agent_client_protocol::util::internal_error(
                 "Unknown MCP server transport type",
             )),
         }
@@ -243,12 +243,12 @@ impl Drop for ChildGuard {
 async fn monitor_child(
     child: Child,
     stderr_rx: tokio::sync::oneshot::Receiver<String>,
-) -> Result<(), agent_client_protocol_core::Error> {
+) -> Result<(), agent_client_protocol::Error> {
     let mut guard = ChildGuard(child);
 
     // Wait for the child to exit
     let status = guard.wait().await.map_err(|e| {
-        agent_client_protocol_core::util::internal_error(format!("Failed to wait for process: {e}"))
+        agent_client_protocol::util::internal_error(format!("Failed to wait for process: {e}"))
     })?;
 
     if status.success() {
@@ -263,7 +263,7 @@ async fn monitor_child(
             format!("Process exited with {status}: {stderr}")
         };
 
-        Err(agent_client_protocol_core::util::internal_error(message))
+        Err(agent_client_protocol::util::internal_error(message))
     }
 }
 
@@ -274,13 +274,13 @@ impl AcpAgentCounterpartRole for Client {}
 
 impl AcpAgentCounterpartRole for Conductor {}
 
-impl<Counterpart: AcpAgentCounterpartRole> agent_client_protocol_core::ConnectTo<Counterpart>
+impl<Counterpart: AcpAgentCounterpartRole> agent_client_protocol::ConnectTo<Counterpart>
     for AcpAgent
 {
     async fn connect_to(
         self,
-        client: impl agent_client_protocol_core::ConnectTo<Counterpart::Counterpart>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+        client: impl agent_client_protocol::ConnectTo<Counterpart::Counterpart>,
+    ) -> Result<(), agent_client_protocol::Error> {
         use futures::AsyncBufReadExt;
         use futures::AsyncWriteExt;
         use futures::StreamExt;
@@ -359,8 +359,8 @@ impl<Counterpart: AcpAgentCounterpartRole> agent_client_protocol_core::ConnectTo
 
         // Race the protocol against child process exit
         // If the child exits early (e.g., with an error), we return that error
-        let protocol_future = agent_client_protocol_core::ConnectTo::<Counterpart>::connect_to(
-            agent_client_protocol_core::Lines::new(outgoing_sink, incoming_lines),
+        let protocol_future = agent_client_protocol::ConnectTo::<Counterpart>::connect_to(
+            agent_client_protocol::Lines::new(outgoing_sink, incoming_lines),
             client,
         );
 
@@ -389,7 +389,7 @@ impl AcpAgent {
     ///     "my-crate",
     /// ]).unwrap();
     /// ```
-    pub fn from_args<I, T>(args: I) -> Result<Self, agent_client_protocol_core::Error>
+    pub fn from_args<I, T>(args: I) -> Result<Self, agent_client_protocol::Error>
     where
         I: IntoIterator<Item = T>,
         T: ToString,
@@ -397,7 +397,7 @@ impl AcpAgent {
         let args: Vec<String> = args.into_iter().map(|s| s.to_string()).collect();
 
         if args.is_empty() {
-            return Err(agent_client_protocol_core::util::internal_error(
+            return Err(agent_client_protocol::util::internal_error(
                 "Arguments cannot be empty",
             ));
         }
@@ -408,9 +408,7 @@ impl AcpAgent {
         // Parse leading FOO=bar arguments as environment variables
         for (i, arg) in args.iter().enumerate() {
             if let Some((name, value)) = parse_env_var(arg) {
-                env.push(agent_client_protocol_core::schema::EnvVariable::new(
-                    name, value,
-                ));
+                env.push(agent_client_protocol::schema::EnvVariable::new(name, value));
                 command_idx = i + 1;
             } else {
                 break;
@@ -418,7 +416,7 @@ impl AcpAgent {
         }
 
         if command_idx >= args.len() {
-            return Err(agent_client_protocol_core::util::internal_error(
+            return Err(agent_client_protocol::util::internal_error(
                 "No command found (only environment variables provided)",
             ));
         }
@@ -434,8 +432,8 @@ impl AcpAgent {
             .to_string();
 
         Ok(AcpAgent {
-            server: agent_client_protocol_core::schema::McpServer::Stdio(
-                agent_client_protocol_core::schema::McpServerStdio::new(name, command)
+            server: agent_client_protocol::schema::McpServer::Stdio(
+                agent_client_protocol::schema::McpServerStdio::new(name, command)
                     .args(cmd_args)
                     .env(env),
             ),
@@ -471,16 +469,16 @@ fn parse_env_var(s: &str) -> Option<(String, String)> {
 }
 
 impl FromStr for AcpAgent {
-    type Err = agent_client_protocol_core::Error;
+    type Err = agent_client_protocol::Error;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         let trimmed = s.trim();
 
         // If it starts with '{', try to parse as JSON
         if trimmed.starts_with('{') {
-            let server: agent_client_protocol_core::schema::McpServer =
-                serde_json::from_str(trimmed).map_err(|e| {
-                    agent_client_protocol_core::util::internal_error(format!(
+            let server: agent_client_protocol::schema::McpServer = serde_json::from_str(trimmed)
+                .map_err(|e| {
+                    agent_client_protocol::util::internal_error(format!(
                         "Failed to parse JSON: {e}"
                     ))
                 })?;
@@ -492,9 +490,7 @@ impl FromStr for AcpAgent {
 
         // Otherwise, parse as a command string
         let parts = shell_words::split(trimmed).map_err(|e| {
-            agent_client_protocol_core::util::internal_error(format!(
-                "Failed to parse command: {e}"
-            ))
+            agent_client_protocol::util::internal_error(format!("Failed to parse command: {e}"))
         })?;
 
         Self::from_args(parts)
@@ -509,7 +505,7 @@ mod tests {
     fn test_parse_simple_command() {
         let agent = AcpAgent::from_str("python agent.py").unwrap();
         match agent.server {
-            agent_client_protocol_core::schema::McpServer::Stdio(stdio) => {
+            agent_client_protocol::schema::McpServer::Stdio(stdio) => {
                 assert_eq!(stdio.name, "python");
                 assert_eq!(stdio.command, PathBuf::from("python"));
                 assert_eq!(stdio.args, vec!["agent.py"]);
@@ -523,7 +519,7 @@ mod tests {
     fn test_parse_command_with_args() {
         let agent = AcpAgent::from_str("node server.js --port 8080 --verbose").unwrap();
         match agent.server {
-            agent_client_protocol_core::schema::McpServer::Stdio(stdio) => {
+            agent_client_protocol::schema::McpServer::Stdio(stdio) => {
                 assert_eq!(stdio.name, "node");
                 assert_eq!(stdio.command, PathBuf::from("node"));
                 assert_eq!(stdio.args, vec!["server.js", "--port", "8080", "--verbose"]);
@@ -537,7 +533,7 @@ mod tests {
     fn test_parse_command_with_quotes() {
         let agent = AcpAgent::from_str(r#"python "my agent.py" --name "Test Agent""#).unwrap();
         match agent.server {
-            agent_client_protocol_core::schema::McpServer::Stdio(stdio) => {
+            agent_client_protocol::schema::McpServer::Stdio(stdio) => {
                 assert_eq!(stdio.name, "python");
                 assert_eq!(stdio.command, PathBuf::from("python"));
                 assert_eq!(stdio.args, vec!["my agent.py", "--name", "Test Agent"]);
@@ -558,7 +554,7 @@ mod tests {
         }"#;
         let agent = AcpAgent::from_str(json).unwrap();
         match agent.server {
-            agent_client_protocol_core::schema::McpServer::Stdio(stdio) => {
+            agent_client_protocol::schema::McpServer::Stdio(stdio) => {
                 assert_eq!(stdio.name, "my-agent");
                 assert_eq!(stdio.command, PathBuf::from("/usr/bin/python"));
                 assert_eq!(stdio.args, vec!["agent.py", "--verbose"]);
@@ -578,7 +574,7 @@ mod tests {
         }"#;
         let agent = AcpAgent::from_str(json).unwrap();
         match agent.server {
-            agent_client_protocol_core::schema::McpServer::Http(http) => {
+            agent_client_protocol::schema::McpServer::Http(http) => {
                 assert_eq!(http.name, "remote-agent");
                 assert_eq!(http.url, "https://example.com/agent");
                 assert!(http.headers.is_empty());
diff --git a/src/agent-client-protocol-tokio/src/lib.rs b/src/agent-client-protocol-tokio/src/lib.rs
index 5936e0c..0f2075c 100644
--- a/src/agent-client-protocol-tokio/src/lib.rs
+++ b/src/agent-client-protocol-tokio/src/lib.rs
@@ -7,7 +7,7 @@
 mod acp_agent;
 
 pub use acp_agent::{AcpAgent, LineDirection};
-use agent_client_protocol_core::{ByteStreams, ConnectTo, Role};
+use agent_client_protocol::{ByteStreams, ConnectTo, Role};
 use std::sync::Arc;
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 
@@ -49,7 +49,7 @@ impl<Counterpart: Role> ConnectTo<Counterpart> for Stdio {
     async fn connect_to(
         self,
         client: impl ConnectTo<Counterpart::Counterpart>,
-    ) -> Result<(), agent_client_protocol_core::Error> {
+    ) -> Result<(), agent_client_protocol::Error> {
         if let Some(callback) = self.debug_callback {
             use futures::AsyncBufReadExt;
             use futures::AsyncWriteExt;
@@ -85,7 +85,7 @@ impl<Counterpart: Role> ConnectTo<Counterpart> for Stdio {
                 as std::pin::Pin<Box<dyn futures::Sink<String, Error = std::io::Error> + Send>>;
 
             ConnectTo::<Counterpart>::connect_to(
-                agent_client_protocol_core::Lines::new(outgoing_sink, incoming_lines),
+                agent_client_protocol::Lines::new(outgoing_sink, incoming_lines),
                 client,
             )
             .await
diff --git a/src/agent-client-protocol-tokio/tests/debug_logging.rs b/src/agent-client-protocol-tokio/tests/debug_logging.rs
index 277d212..893255c 100644
--- a/src/agent-client-protocol-tokio/tests/debug_logging.rs
+++ b/src/agent-client-protocol-tokio/tests/debug_logging.rs
@@ -1,22 +1,22 @@
 //! Integration test for AcpAgent debug logging
 
-use agent_client_protocol_core::schema::InitializeRequest;
-use agent_client_protocol_core::{Client, ConnectTo};
+use agent_client_protocol::schema::InitializeRequest;
+use agent_client_protocol::{Client, ConnectTo};
 use agent_client_protocol_test::test_binaries::testy;
 use agent_client_protocol_tokio::LineDirection;
 use std::sync::{Arc, Mutex};
 
 /// Test helper to receive a JSON-RPC response
-async fn recv<T: agent_client_protocol_core::JsonRpcResponse + Send>(
-    response: agent_client_protocol_core::SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+async fn recv<T: agent_client_protocol::JsonRpcResponse + Send>(
+    response: agent_client_protocol::SentRequest<T>,
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 #[tokio::test]
@@ -58,7 +58,7 @@ async fn test_acp_agent_debug_callback() -> Result<(), Box<dyn std::error::Error
     let (agent_out, client_in) = duplex(1024);
 
     let transport =
-        agent_client_protocol_core::ByteStreams::new(client_out.compat_write(), client_in.compat());
+        agent_client_protocol::ByteStreams::new(client_out.compat_write(), client_in.compat());
 
     Client
         .builder()
@@ -66,7 +66,7 @@ async fn test_acp_agent_debug_callback() -> Result<(), Box<dyn std::error::Error
         .with_spawned(|_cx| async move {
             ConnectTo::<Client>::connect_to(
                 agent,
-                agent_client_protocol_core::ByteStreams::new(
+                agent_client_protocol::ByteStreams::new(
                     agent_out.compat_write(),
                     agent_in.compat(),
                 ),
@@ -76,7 +76,7 @@ async fn test_acp_agent_debug_callback() -> Result<(), Box<dyn std::error::Error
         .connect_with(transport, async |connection_to_client| {
             // Send an initialize request
             let _init_response = recv(connection_to_client.send_request(InitializeRequest::new(
-                agent_client_protocol_core::schema::ProtocolVersion::LATEST,
+                agent_client_protocol::schema::ProtocolVersion::LATEST,
             )))
             .await?;
 
diff --git a/src/agent-client-protocol-trace-viewer/Cargo.toml b/src/agent-client-protocol-trace-viewer/Cargo.toml
index 9b2c23a..390c7a0 100644
--- a/src/agent-client-protocol-trace-viewer/Cargo.toml
+++ b/src/agent-client-protocol-trace-viewer/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "agent-client-protocol-trace-viewer"
-version = "0.1.0"
+version = "0.11.0"
 edition.workspace = true
 authors.workspace = true
 license.workspace = true
diff --git a/src/agent-client-protocol/Cargo.toml b/src/agent-client-protocol/Cargo.toml
index 30f19ab..48406fc 100644
--- a/src/agent-client-protocol/Cargo.toml
+++ b/src/agent-client-protocol/Cargo.toml
@@ -1,67 +1,68 @@
 [package]
 name = "agent-client-protocol"
-authors = ["Zed <hi@zed.dev>"]
 version = "0.10.4"
-edition = "2024"
-license = "Apache-2.0"
-description = "A protocol for standardizing communication between code editors and AI coding agents"
-repository = "https://github.com/agentclientprotocol/rust-sdk"
-homepage = "https://github.com/agentclientprotocol/rust-sdk"
-documentation = "https://docs.rs/agent-client-protocol"
-readme = "README.md"
-keywords = ["agent", "client", "protocol", "ai", "editor"]
-categories = ["development-tools", "api-bindings"]
+edition.workspace = true
+authors.workspace = true
+license.workspace = true
+repository.workspace = true
+homepage.workspace = true
+description = "Core protocol types and traits for the Agent Client Protocol"
+keywords = ["acp", "agent", "protocol", "ai"]
+categories = ["development-tools"]
 
 [features]
+default = []
+
+# Forward unstable features from agent-client-protocol-schema.
+# Enable these to get support for the corresponding unstable ACP methods.
 unstable = [
     "unstable_auth_methods",
-    "unstable_cancel_request",
-    "unstable_elicitation",
+    "unstable_boolean_config",
     "unstable_logout",
-    "unstable_nes",
+    "unstable_message_id",
     "unstable_session_additional_directories",
-    "unstable_session_fork",
     "unstable_session_close",
+    "unstable_session_fork",
     "unstable_session_model",
     "unstable_session_resume",
     "unstable_session_usage",
-    "unstable_message_id",
-    "unstable_boolean_config",
 ]
 unstable_auth_methods = ["agent-client-protocol-schema/unstable_auth_methods"]
-unstable_cancel_request = ["agent-client-protocol-schema/unstable_cancel_request"]
-unstable_elicitation = ["agent-client-protocol-schema/unstable_elicitation"]
+unstable_boolean_config = ["agent-client-protocol-schema/unstable_boolean_config"]
 unstable_logout = ["agent-client-protocol-schema/unstable_logout"]
-unstable_nes = ["agent-client-protocol-schema/unstable_nes"]
+unstable_message_id = ["agent-client-protocol-schema/unstable_message_id"]
 unstable_session_additional_directories = ["agent-client-protocol-schema/unstable_session_additional_directories"]
+unstable_session_close = ["agent-client-protocol-schema/unstable_session_close"]
 unstable_session_fork = ["agent-client-protocol-schema/unstable_session_fork"]
 unstable_session_model = ["agent-client-protocol-schema/unstable_session_model"]
 unstable_session_resume = ["agent-client-protocol-schema/unstable_session_resume"]
 unstable_session_usage = ["agent-client-protocol-schema/unstable_session_usage"]
-unstable_session_close = ["agent-client-protocol-schema/unstable_session_close"]
-unstable_message_id = ["agent-client-protocol-schema/unstable_message_id"]
-unstable_boolean_config = ["agent-client-protocol-schema/unstable_boolean_config"]
-
 
 [dependencies]
 agent-client-protocol-schema.workspace = true
+agent-client-protocol-derive.workspace = true
 anyhow.workspace = true
-async-broadcast.workspace = true
-async-trait.workspace = true
-derive_more.workspace = true
+boxfnonce.workspace = true
 futures.workspace = true
-log.workspace = true
+futures-concurrency.workspace = true
+rustc-hash.workspace = true
+jsonrpcmsg.workspace = true
+rmcp = { workspace = true, features = ["server"] }
+schemars.workspace = true
 serde.workspace = true
 serde_json.workspace = true
+thiserror.workspace = true
+tokio.workspace = true
+tokio-util.workspace = true
+tracing.workspace = true
+uuid.workspace = true
 
 [dev-dependencies]
-env_logger.workspace = true
-futures-util.workspace = true
-piper.workspace = true
-pretty_assertions.workspace = true
-rustyline.workspace = true
+agent-client-protocol-test.workspace = true
+clap.workspace = true
+expect-test.workspace = true
+shell-words.workspace = true
 tokio.workspace = true
-tokio-util.workspace = true
 
 [lints]
 workspace = true
diff --git a/src/agent-client-protocol/README.md b/src/agent-client-protocol/README.md
index ef510fd..1f6b12a 100644
--- a/src/agent-client-protocol/README.md
+++ b/src/agent-client-protocol/README.md
@@ -2,27 +2,52 @@
   <img alt="Agent Client Protocol" src="https://zed.dev/img/acp/banner-dark.webp">
 </a>
 
-# Agent Client Protocol
+# agent-client-protocol
 
-The Agent Client Protocol (ACP) standardizes communication between _code editors_ (interactive programs for viewing and editing source code) and _coding agents_ (programs that use generative AI to autonomously modify code).
+Core protocol types and traits for the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/).
 
-Learn more at [agentclientprotocol.com](https://agentclientprotocol.com/).
+ACP is a protocol for communication between AI agents and their clients (IDEs, CLIs, etc.),
+enabling features like tool use, permission requests, and streaming responses.
 
-## Integrations
+## What can you build with this crate?
 
-- [Schema](./schema/schema.json)
-- [Agents](https://agentclientprotocol.com/overview/agents)
-- [Clients](https://agentclientprotocol.com/overview/clients)
-- Official Libraries
-  - **Kotlin**: [`acp-kotlin`](https://github.com/agentclientprotocol/kotlin-sdk) - Supports JVM, other targets are in progress, see [samples](https://github.com/agentclientprotocol/kotlin-sdk/tree/master/samples/kotlin-acp-client-sample/src/main/kotlin/com/agentclientprotocol/samples)
-  - **Python**: [`python-sdk`](https://github.com/agentclientprotocol/python-sdk) - See [examples](https://github.com/agentclientprotocol/python-sdk/tree/main/examples)
-  - **Rust**: [`agent-client-protocol`](https://crates.io/crates/agent-client-protocol) - See [examples/agent.rs](https://github.com/agentclientprotocol/rust-sdk/blob/main/examples/agent.rs) and [examples/client.rs](https://github.com/agentclientprotocol/rust-sdk/blob/main/examples/client.rs)
-  - **TypeScript**: [`@agentclientprotocol/sdk`](https://www.npmjs.com/package/@agentclientprotocol/sdk) - See [examples/](https://github.com/agentclientprotocol/typescript-sdk/tree/main/src/examples)
-- [Community Libraries](https://agentclientprotocol.com/libraries/community)
+- **Clients** that talk to ACP agents (like building your own Claude Code interface)
+- **Proxies** that add capabilities to existing agents (like adding custom tools via MCP)
+- **Agents** that respond to prompts with AI-powered responses
 
-## Contributing
+## Quick Start: Connecting to an Agent
 
-ACP is a protocol intended for broad adoption across the ecosystem; we follow a structured process to ensure changes are well-considered. Read the [Contributing Guide](./CONTRIBUTING.md) for more information.
+The most common use case is connecting to an existing ACP agent as a client:
+
+```rust
+use agent_client_protocol::{Client, Agent, ConnectTo};
+use agent_client_protocol::schema::{InitializeRequest, ProtocolVersion};
+
+Client.builder()
+    .name("my-client")
+    .connect_with(transport, async |cx| {
+        // Initialize the connection
+        cx.send_request(InitializeRequest::new(ProtocolVersion::V1))
+            .block_task()
+            .await?;
+
+        Ok(())
+    })
+    .await?;
+```
+
+## Learning More
+
+See the [crate documentation](https://docs.rs/agent-client-protocol) for:
+
+- **[Cookbook](https://docs.rs/agent-client-protocol/latest/agent_client_protocol/cookbook/)** — Patterns for building clients, proxies, and agents
+- **[Examples](https://github.com/agentclientprotocol/rust-sdk/tree/main/src/agent-client-protocol/examples)** — Working code you can run
+
+## Related Crates
+
+- **[agent-client-protocol-tokio](../agent-client-protocol-tokio/)** — Tokio utilities for spawning agent processes
+- **[agent-client-protocol-derive](../agent-client-protocol-derive/)** — Derive macros for JSON-RPC traits
+- **[agent-client-protocol-trace-viewer](../agent-client-protocol-trace-viewer/)** — Interactive trace visualization
 
 ## Contribution Policy
 
diff --git a/src/agent-client-protocol/examples/agent.rs b/src/agent-client-protocol/examples/agent.rs
deleted file mode 100644
index 7eb32ba..0000000
--- a/src/agent-client-protocol/examples/agent.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-//! A simple ACP agent server for educational purposes.
-//!
-//! The agent communicates with clients over stdio. To run it with logging:
-//!
-//! ```bash
-//! RUST_LOG=info cargo run --example agent
-//! ```
-//!
-//! To connect it to the example client from this crate:
-//!
-//! ```bash
-//! cargo build --example agent && cargo run --example client -- target/debug/examples/agent
-//! ```
-
-use std::cell::Cell;
-
-use agent_client_protocol::{self as acp, Client as _};
-use serde_json::json;
-use tokio::sync::{mpsc, oneshot};
-use tokio_util::compat::{TokioAsyncReadCompatExt as _, TokioAsyncWriteCompatExt as _};
-
-struct ExampleAgent {
-    session_update_tx: mpsc::UnboundedSender<(acp::SessionNotification, oneshot::Sender<()>)>,
-    next_session_id: Cell<u64>,
-}
-
-impl ExampleAgent {
-    fn new(
-        session_update_tx: mpsc::UnboundedSender<(acp::SessionNotification, oneshot::Sender<()>)>,
-    ) -> Self {
-        Self {
-            session_update_tx,
-            next_session_id: Cell::new(0),
-        }
-    }
-}
-
-#[async_trait::async_trait(?Send)]
-impl acp::Agent for ExampleAgent {
-    async fn initialize(
-        &self,
-        arguments: acp::InitializeRequest,
-    ) -> Result<acp::InitializeResponse, acp::Error> {
-        log::info!("Received initialize request {arguments:?}");
-        Ok(acp::InitializeResponse::new(acp::ProtocolVersion::V1)
-            .agent_info(acp::Implementation::new("example-agent", "0.1.0").title("Example Agent")))
-    }
-
-    async fn authenticate(
-        &self,
-        arguments: acp::AuthenticateRequest,
-    ) -> Result<acp::AuthenticateResponse, acp::Error> {
-        log::info!("Received authenticate request {arguments:?}");
-        Ok(acp::AuthenticateResponse::default())
-    }
-
-    async fn new_session(
-        &self,
-        arguments: acp::NewSessionRequest,
-    ) -> Result<acp::NewSessionResponse, acp::Error> {
-        log::info!("Received new session request {arguments:?}");
-        let session_id = self.next_session_id.get();
-        self.next_session_id.set(session_id + 1);
-        Ok(acp::NewSessionResponse::new(session_id.to_string()))
-    }
-
-    async fn load_session(
-        &self,
-        arguments: acp::LoadSessionRequest,
-    ) -> Result<acp::LoadSessionResponse, acp::Error> {
-        log::info!("Received load session request {arguments:?}");
-        Ok(acp::LoadSessionResponse::new())
-    }
-
-    async fn prompt(
-        &self,
-        arguments: acp::PromptRequest,
-    ) -> Result<acp::PromptResponse, acp::Error> {
-        log::info!("Received prompt request {arguments:?}");
-        for content in ["Client sent: ".into()].into_iter().chain(arguments.prompt) {
-            let (tx, rx) = oneshot::channel();
-            self.session_update_tx
-                .send((
-                    acp::SessionNotification::new(
-                        arguments.session_id.clone(),
-                        acp::SessionUpdate::AgentMessageChunk(acp::ContentChunk::new(content)),
-                    ),
-                    tx,
-                ))
-                .map_err(|_| acp::Error::internal_error())?;
-            rx.await.map_err(|_| acp::Error::internal_error())?;
-        }
-        Ok(acp::PromptResponse::new(acp::StopReason::EndTurn))
-    }
-
-    async fn cancel(&self, args: acp::CancelNotification) -> Result<(), acp::Error> {
-        log::info!("Received cancel request {args:?}");
-        Ok(())
-    }
-
-    async fn set_session_mode(
-        &self,
-        args: acp::SetSessionModeRequest,
-    ) -> Result<acp::SetSessionModeResponse, acp::Error> {
-        log::info!("Received set session mode request {args:?}");
-        Ok(acp::SetSessionModeResponse::default())
-    }
-
-    #[cfg(feature = "unstable_session_model")]
-    async fn set_session_model(
-        &self,
-        args: acp::SetSessionModelRequest,
-    ) -> Result<acp::SetSessionModelResponse, acp::Error> {
-        log::info!("Received select model request {args:?}");
-        Ok(acp::SetSessionModelResponse::default())
-    }
-
-    async fn set_session_config_option(
-        &self,
-        args: acp::SetSessionConfigOptionRequest,
-    ) -> Result<acp::SetSessionConfigOptionResponse, acp::Error> {
-        log::info!("Received set session config option request {args:?}");
-        #[cfg(feature = "unstable_boolean_config")]
-        let value = args
-            .value
-            .as_value_id()
-            .ok_or(acp::Error::invalid_params())?
-            .clone();
-        #[cfg(not(feature = "unstable_boolean_config"))]
-        let value: acp::SessionConfigValueId = args.value.into();
-        let option = acp::SessionConfigOption::select(
-            args.config_id,
-            "Example Option",
-            value,
-            vec![
-                acp::SessionConfigSelectOption::new("option1", "Option 1"),
-                acp::SessionConfigSelectOption::new("option2", "Option 2"),
-            ],
-        );
-        Ok(acp::SetSessionConfigOptionResponse::new(vec![option]))
-    }
-
-    async fn ext_method(&self, args: acp::ExtRequest) -> Result<acp::ExtResponse, acp::Error> {
-        log::info!(
-            "Received extension method call: method={}, params={:?}",
-            args.method,
-            args.params
-        );
-        Ok(acp::ExtResponse::new(
-            serde_json::value::to_raw_value(&json!({"example": "response"}))?.into(),
-        ))
-    }
-
-    async fn ext_notification(&self, args: acp::ExtNotification) -> Result<(), acp::Error> {
-        log::info!(
-            "Received extension notification: method={}, params={:?}",
-            args.method,
-            args.params
-        );
-        Ok(())
-    }
-}
-
-#[tokio::main(flavor = "current_thread")]
-async fn main() -> acp::Result<()> {
-    env_logger::init();
-
-    let outgoing = tokio::io::stdout().compat_write();
-    let incoming = tokio::io::stdin().compat();
-
-    // The AgentSideConnection will spawn futures onto our Tokio runtime.
-    // LocalSet and spawn_local are used because the futures from the
-    // agent-client-protocol crate are not Send.
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async move {
-            let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
-            // Start up the ExampleAgent connected to stdio.
-            let (conn, handle_io) =
-                acp::AgentSideConnection::new(ExampleAgent::new(tx), outgoing, incoming, |fut| {
-                    tokio::task::spawn_local(fut);
-                });
-            // Kick off a background task to send the ExampleAgent's session notifications to the client.
-            tokio::task::spawn_local(async move {
-                while let Some((session_notification, tx)) = rx.recv().await {
-                    let result = conn.session_notification(session_notification).await;
-                    if let Err(e) = result {
-                        log::error!("{e}");
-                        break;
-                    }
-                    tx.send(()).ok();
-                }
-            });
-            // Run until stdin/stdout are closed.
-            handle_io.await
-        })
-        .await
-}
diff --git a/src/agent-client-protocol/examples/client.rs b/src/agent-client-protocol/examples/client.rs
deleted file mode 100644
index 34736ae..0000000
--- a/src/agent-client-protocol/examples/client.rs
+++ /dev/null
@@ -1,173 +0,0 @@
-//! A simple ACP client for educational purposes.
-//!
-//! The client starts an agent as a subprocess and communicates with it over stdio. Run the client like this:
-//!
-//! ```bash
-//! cargo run --example client -- path/to/agent --agent-arg
-//! ```
-//!
-//! To connect it to the example agent from this crate:
-//!
-//! ```bash
-//! cargo build --example agent && cargo run --example client -- target/debug/examples/agent
-//! ```
-
-use agent_client_protocol::{self as acp, Agent as _};
-use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
-
-struct ExampleClient {}
-
-#[async_trait::async_trait(?Send)]
-impl acp::Client for ExampleClient {
-    async fn request_permission(
-        &self,
-        _args: acp::RequestPermissionRequest,
-    ) -> acp::Result<acp::RequestPermissionResponse> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn write_text_file(
-        &self,
-        _args: acp::WriteTextFileRequest,
-    ) -> acp::Result<acp::WriteTextFileResponse> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn read_text_file(
-        &self,
-        _args: acp::ReadTextFileRequest,
-    ) -> acp::Result<acp::ReadTextFileResponse> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn create_terminal(
-        &self,
-        _args: acp::CreateTerminalRequest,
-    ) -> Result<acp::CreateTerminalResponse, acp::Error> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn terminal_output(
-        &self,
-        _args: acp::TerminalOutputRequest,
-    ) -> acp::Result<acp::TerminalOutputResponse> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn release_terminal(
-        &self,
-        _args: acp::ReleaseTerminalRequest,
-    ) -> acp::Result<acp::ReleaseTerminalResponse> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn wait_for_terminal_exit(
-        &self,
-        _args: acp::WaitForTerminalExitRequest,
-    ) -> acp::Result<acp::WaitForTerminalExitResponse> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn kill_terminal(
-        &self,
-        _args: acp::KillTerminalRequest,
-    ) -> acp::Result<acp::KillTerminalResponse> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn session_notification(
-        &self,
-        args: acp::SessionNotification,
-    ) -> acp::Result<(), acp::Error> {
-        if let acp::SessionUpdate::AgentMessageChunk(acp::ContentChunk { content, .. }) =
-            args.update
-        {
-            let text = match content {
-                acp::ContentBlock::Text(text_content) => text_content.text,
-                acp::ContentBlock::Image(_) => "<image>".into(),
-                acp::ContentBlock::Audio(_) => "<audio>".into(),
-                acp::ContentBlock::ResourceLink(resource_link) => resource_link.uri,
-                acp::ContentBlock::Resource(_) => "<resource>".into(),
-                _ => "Unknown chunk".into(),
-            };
-            println!("| Agent: {text}");
-        }
-        Ok(())
-    }
-
-    async fn ext_method(&self, _args: acp::ExtRequest) -> acp::Result<acp::ExtResponse> {
-        Err(acp::Error::method_not_found())
-    }
-
-    async fn ext_notification(&self, _args: acp::ExtNotification) -> acp::Result<()> {
-        Err(acp::Error::method_not_found())
-    }
-}
-
-#[tokio::main(flavor = "current_thread")]
-async fn main() -> anyhow::Result<()> {
-    env_logger::init();
-
-    let command = std::env::args().collect::<Vec<_>>();
-    let (outgoing, incoming, child) = match command.as_slice() {
-        [_, program, args @ ..] => {
-            let mut child = tokio::process::Command::new(program)
-                .args(args.iter())
-                .stdin(std::process::Stdio::piped())
-                .stdout(std::process::Stdio::piped())
-                .kill_on_drop(true)
-                .spawn()?;
-            (
-                child.stdin.take().unwrap().compat_write(),
-                child.stdout.take().unwrap().compat(),
-                child,
-            )
-        }
-        _ => anyhow::bail!("Usage: client AGENT_PROGRAM AGENT_ARG..."),
-    };
-
-    // The ClientSideConnection will spawn futures onto our Tokio runtime.
-    // LocalSet and spawn_local are used because the futures from the
-    // agent-client-protocol crate are not Send.
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async move {
-            // Set up the ExampleClient connected to the agent's stdio.
-            let (conn, handle_io) =
-                acp::ClientSideConnection::new(ExampleClient {}, outgoing, incoming, |fut| {
-                    tokio::task::spawn_local(fut);
-                });
-
-            // Handle I/O in the background.
-            tokio::task::spawn_local(handle_io);
-
-            // Connect to the agent and set up a session.
-            conn.initialize(
-                acp::InitializeRequest::new(acp::ProtocolVersion::V1).client_info(
-                    acp::Implementation::new("example-client", "0.1.0").title("Example Client"),
-                ),
-            )
-            .await?;
-            let response = conn
-                .new_session(acp::NewSessionRequest::new(std::env::current_dir()?))
-                .await?;
-
-            // Send prompts to the agent until stdin is closed.
-            let mut rl = rustyline::DefaultEditor::new()?;
-            while let Ok(line) = rl.readline("> ") {
-                let result = conn
-                    .prompt(acp::PromptRequest::new(
-                        response.session_id.clone(),
-                        vec![line.into()],
-                    ))
-                    .await;
-                if let Err(e) = result {
-                    log::error!("{e}");
-                }
-            }
-
-            drop(child);
-            Ok(())
-        })
-        .await
-}
diff --git a/src/agent-client-protocol-core/examples/simple_agent.rs b/src/agent-client-protocol/examples/simple_agent.rs
similarity index 61%
rename from src/agent-client-protocol-core/examples/simple_agent.rs
rename to src/agent-client-protocol/examples/simple_agent.rs
index 939f1da..de380b1 100644
--- a/src/agent-client-protocol-core/examples/simple_agent.rs
+++ b/src/agent-client-protocol/examples/simple_agent.rs
@@ -1,7 +1,5 @@
-use agent_client_protocol_core::schema::{
-    AgentCapabilities, InitializeRequest, InitializeResponse,
-};
-use agent_client_protocol_core::{Agent, Client, ConnectionTo, Dispatch, Result};
+use agent_client_protocol::schema::{AgentCapabilities, InitializeRequest, InitializeResponse};
+use agent_client_protocol::{Agent, Client, ConnectionTo, Dispatch, Result};
 use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 
 #[tokio::main]
@@ -17,19 +15,16 @@ async fn main() -> Result<()> {
                         .agent_capabilities(AgentCapabilities::new()),
                 )
             },
-            agent_client_protocol_core::on_receive_request!(),
+            agent_client_protocol::on_receive_request!(),
         )
         .on_receive_dispatch(
             async move |message: Dispatch, cx: ConnectionTo<Client>| {
                 // Respond to any other message with an error
-                message.respond_with_error(
-                    agent_client_protocol_core::util::internal_error("TODO"),
-                    cx,
-                )
+                message.respond_with_error(agent_client_protocol::util::internal_error("TODO"), cx)
             },
-            agent_client_protocol_core::on_receive_dispatch!(),
+            agent_client_protocol::on_receive_dispatch!(),
         )
-        .connect_to(agent_client_protocol_core::ByteStreams::new(
+        .connect_to(agent_client_protocol::ByteStreams::new(
             tokio::io::stdout().compat_write(),
             tokio::io::stdin().compat(),
         ))
diff --git a/src/agent-client-protocol-core/examples/yolo_one_shot_client.rs b/src/agent-client-protocol/examples/yolo_one_shot_client.rs
similarity index 93%
rename from src/agent-client-protocol-core/examples/yolo_one_shot_client.rs
rename to src/agent-client-protocol/examples/yolo_one_shot_client.rs
index 109da71..fcf019c 100644
--- a/src/agent-client-protocol-core/examples/yolo_one_shot_client.rs
+++ b/src/agent-client-protocol/examples/yolo_one_shot_client.rs
@@ -11,12 +11,12 @@
 //! cargo run --example yolo_one_shot_client -- --command "python my_agent.py" "What is 2+2?"
 //! ```
 
-use agent_client_protocol_core::schema::{
+use agent_client_protocol::schema::{
     ContentBlock, InitializeRequest, NewSessionRequest, PromptRequest, ProtocolVersion,
     RequestPermissionOutcome, RequestPermissionRequest, RequestPermissionResponse,
     SelectedPermissionOutcome, SessionNotification, TextContent,
 };
-use agent_client_protocol_core::{Agent, Client, ConnectionTo};
+use agent_client_protocol::{Agent, Client, ConnectionTo};
 use clap::Parser;
 use std::path::PathBuf;
 use tokio::process::Child;
@@ -82,10 +82,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let (child_stdin, child_stdout, mut child) = spawn_agent_process(command, args)?;
 
     // Create transport and connection
-    let transport = agent_client_protocol_core::ByteStreams::new(
-        child_stdin.compat_write(),
-        child_stdout.compat(),
-    );
+    let transport =
+        agent_client_protocol::ByteStreams::new(child_stdin.compat_write(), child_stdout.compat());
 
     // Run the client
     Client
@@ -96,7 +94,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
                 println!("{:?}", notification.update);
                 Ok(())
             },
-            agent_client_protocol_core::on_receive_notification!(),
+            agent_client_protocol::on_receive_notification!(),
         )
         .on_receive_request(
             async move |request: RequestPermissionRequest, responder, _connection| {
@@ -114,7 +112,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
                     ))
                 }
             },
-            agent_client_protocol_core::on_receive_request!(),
+            agent_client_protocol::on_receive_request!(),
         )
         .connect_with(transport, |connection: ConnectionTo<Agent>| async move {
             // Initialize the agent
diff --git a/src/agent-client-protocol-core/src/acp.rs b/src/agent-client-protocol/src/acp.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/acp.rs
rename to src/agent-client-protocol/src/acp.rs
diff --git a/src/agent-client-protocol/src/agent.rs b/src/agent-client-protocol/src/agent.rs
deleted file mode 100644
index dd163e1..0000000
--- a/src/agent-client-protocol/src/agent.rs
+++ /dev/null
@@ -1,372 +0,0 @@
-use std::{rc::Rc, sync::Arc};
-
-use agent_client_protocol_schema::{
-    AuthenticateRequest, AuthenticateResponse, CancelNotification, Error, ExtNotification,
-    ExtRequest, ExtResponse, InitializeRequest, InitializeResponse, ListSessionsRequest,
-    ListSessionsResponse, LoadSessionRequest, LoadSessionResponse, NewSessionRequest,
-    NewSessionResponse, PromptRequest, PromptResponse, Result, SetSessionConfigOptionRequest,
-    SetSessionConfigOptionResponse, SetSessionModeRequest, SetSessionModeResponse,
-};
-#[cfg(feature = "unstable_session_close")]
-use agent_client_protocol_schema::{CloseSessionRequest, CloseSessionResponse};
-#[cfg(feature = "unstable_session_fork")]
-use agent_client_protocol_schema::{ForkSessionRequest, ForkSessionResponse};
-#[cfg(feature = "unstable_logout")]
-use agent_client_protocol_schema::{LogoutRequest, LogoutResponse};
-#[cfg(feature = "unstable_session_resume")]
-use agent_client_protocol_schema::{ResumeSessionRequest, ResumeSessionResponse};
-#[cfg(feature = "unstable_session_model")]
-use agent_client_protocol_schema::{SetSessionModelRequest, SetSessionModelResponse};
-use serde_json::value::RawValue;
-
-/// Defines the interface that all ACP-compliant agents must implement.
-///
-/// Agents are programs that use generative AI to autonomously modify code. They handle
-/// requests from clients and execute tasks using language models and tools.
-#[async_trait::async_trait(?Send)]
-pub trait Agent {
-    /// Establishes the connection with a client and negotiates protocol capabilities.
-    ///
-    /// This method is called once at the beginning of the connection to:
-    /// - Negotiate the protocol version to use
-    /// - Exchange capability information between client and agent
-    /// - Determine available authentication methods
-    ///
-    /// The agent should respond with its supported protocol version and capabilities.
-    ///
-    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
-    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse>;
-
-    /// Authenticates the client using the specified authentication method.
-    ///
-    /// Called when the agent requires authentication before allowing session creation.
-    /// The client provides the authentication method ID that was advertised during initialization.
-    ///
-    /// After successful authentication, the client can proceed to create sessions with
-    /// `new_session` without receiving an `auth_required` error.
-    ///
-    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
-    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse>;
-
-    /// **UNSTABLE**
-    ///
-    /// This capability is not part of the spec yet, and may be removed or changed at any point.
-    ///
-    /// Logs out of the current authenticated state.
-    ///
-    /// After a successful logout, all new sessions will require authentication.
-    /// There is no guarantee about the behavior of already running sessions.
-    ///
-    /// Only available if the Agent supports the `auth.logout` capability.
-    #[cfg(feature = "unstable_logout")]
-    async fn logout(&self, _args: LogoutRequest) -> Result<LogoutResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Creates a new conversation session with the agent.
-    ///
-    /// Sessions represent independent conversation contexts with their own history and state.
-    ///
-    /// The agent should:
-    /// - Create a new session context
-    /// - Connect to any specified MCP servers
-    /// - Return a unique session ID for future requests
-    ///
-    /// May return an `auth_required` error if the agent requires authentication.
-    ///
-    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
-    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse>;
-
-    /// Processes a user prompt within a session.
-    ///
-    /// This method handles the whole lifecycle of a prompt:
-    /// - Receives user messages with optional context (files, images, etc.)
-    /// - Processes the prompt using language models
-    /// - Reports language model content and tool calls to the Clients
-    /// - Requests permission to run tools
-    /// - Executes any requested tool calls
-    /// - Returns when the turn is complete with a stop reason
-    ///
-    /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
-    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse>;
-
-    /// Cancels ongoing operations for a session.
-    ///
-    /// This is a notification sent by the client to cancel an ongoing prompt turn.
-    ///
-    /// Upon receiving this notification, the Agent SHOULD:
-    /// - Stop all language model requests as soon as possible
-    /// - Abort all tool call invocations in progress
-    /// - Send any pending `session/update` notifications
-    /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
-    ///
-    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
-    async fn cancel(&self, args: CancelNotification) -> Result<()>;
-
-    /// Loads an existing session to resume a previous conversation.
-    ///
-    /// This method is only available if the agent advertises the `loadSession` capability.
-    ///
-    /// The agent should:
-    /// - Restore the session context and conversation history
-    /// - Connect to the specified MCP servers
-    /// - Stream the entire conversation history back to the client via notifications
-    ///
-    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
-    async fn load_session(&self, _args: LoadSessionRequest) -> Result<LoadSessionResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Sets the current mode for a session.
-    ///
-    /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
-    /// that affect system prompts, tool availability, and permission behaviors.
-    ///
-    /// The mode must be one of the modes advertised in `availableModes` during session
-    /// creation or loading. Agents may also change modes autonomously and notify the
-    /// client via `current_mode_update` notifications.
-    ///
-    /// This method can be called at any time during a session, whether the Agent is
-    /// idle or actively generating a response.
-    ///
-    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
-    async fn set_session_mode(
-        &self,
-        _args: SetSessionModeRequest,
-    ) -> Result<SetSessionModeResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// **UNSTABLE**
-    ///
-    /// This capability is not part of the spec yet, and may be removed or changed at any point.
-    ///
-    /// Select a model for a given session.
-    #[cfg(feature = "unstable_session_model")]
-    async fn set_session_model(
-        &self,
-        _args: SetSessionModelRequest,
-    ) -> Result<SetSessionModelResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Sets the current value for a session configuration option.
-    ///
-    /// Configuration options allow agents to expose arbitrary selectors (like model choice,
-    /// reasoning level, etc.) that clients can display and modify.
-    ///
-    /// The response returns the full list of configuration options with their current values,
-    /// as changing one option may affect others.
-    async fn set_session_config_option(
-        &self,
-        _args: SetSessionConfigOptionRequest,
-    ) -> Result<SetSessionConfigOptionResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// **UNSTABLE**
-    ///
-    /// This capability is not part of the spec yet, and may be removed or changed at any point.
-    ///
-    /// Lists existing sessions known to the agent.
-    ///
-    /// Only available if the Agent supports the `sessionCapabilities.list` capability.
-    async fn list_sessions(&self, _args: ListSessionsRequest) -> Result<ListSessionsResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// **UNSTABLE**
-    ///
-    /// This capability is not part of the spec yet, and may be removed or changed at any point.
-    ///
-    /// Forks an existing session, creating a new session with the same conversation history.
-    ///
-    /// Only available if the Agent supports the `sessionCapabilities.fork` capability.
-    #[cfg(feature = "unstable_session_fork")]
-    async fn fork_session(&self, _args: ForkSessionRequest) -> Result<ForkSessionResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// **UNSTABLE**
-    ///
-    /// This capability is not part of the spec yet, and may be removed or changed at any point.
-    ///
-    /// Resumes an existing session without replaying message history.
-    ///
-    /// This is similar to `load_session`, except it does not return previous messages.
-    /// Useful for agents that support continuing conversations but don't store full history.
-    ///
-    /// Only available if the Agent supports the `sessionCapabilities.resume` capability.
-    #[cfg(feature = "unstable_session_resume")]
-    async fn resume_session(&self, _args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// **UNSTABLE**
-    ///
-    /// This capability is not part of the spec yet, and may be removed or changed at any point.
-    ///
-    /// Closes an active session, freeing up any resources associated with it.
-    ///
-    /// The agent must cancel any ongoing work (as if `session/cancel` was called)
-    /// and then free up any resources associated with the session.
-    ///
-    /// Only available if the Agent supports the `session.close` capability.
-    #[cfg(feature = "unstable_session_close")]
-    async fn close_session(&self, _args: CloseSessionRequest) -> Result<CloseSessionResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Handles extension method requests from the client.
-    ///
-    /// Extension methods provide a way to add custom functionality while maintaining
-    /// protocol compatibility.
-    ///
-    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
-    async fn ext_method(&self, _args: ExtRequest) -> Result<ExtResponse> {
-        Ok(ExtResponse::new(RawValue::NULL.to_owned().into()))
-    }
-
-    /// Handles extension notifications from the client.
-    ///
-    /// Extension notifications provide a way to send one-way messages for custom functionality
-    /// while maintaining protocol compatibility.
-    ///
-    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
-    async fn ext_notification(&self, _args: ExtNotification) -> Result<()> {
-        Ok(())
-    }
-}
-
-#[async_trait::async_trait(?Send)]
-impl<T: Agent> Agent for Rc<T> {
-    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse> {
-        self.as_ref().initialize(args).await
-    }
-    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse> {
-        self.as_ref().authenticate(args).await
-    }
-    #[cfg(feature = "unstable_logout")]
-    async fn logout(&self, args: LogoutRequest) -> Result<LogoutResponse> {
-        self.as_ref().logout(args).await
-    }
-    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse> {
-        self.as_ref().new_session(args).await
-    }
-    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse> {
-        self.as_ref().load_session(args).await
-    }
-    async fn set_session_mode(
-        &self,
-        args: SetSessionModeRequest,
-    ) -> Result<SetSessionModeResponse> {
-        self.as_ref().set_session_mode(args).await
-    }
-    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse> {
-        self.as_ref().prompt(args).await
-    }
-    async fn cancel(&self, args: CancelNotification) -> Result<()> {
-        self.as_ref().cancel(args).await
-    }
-    #[cfg(feature = "unstable_session_model")]
-    async fn set_session_model(
-        &self,
-        args: SetSessionModelRequest,
-    ) -> Result<SetSessionModelResponse> {
-        self.as_ref().set_session_model(args).await
-    }
-    async fn set_session_config_option(
-        &self,
-        args: SetSessionConfigOptionRequest,
-    ) -> Result<SetSessionConfigOptionResponse> {
-        self.as_ref().set_session_config_option(args).await
-    }
-
-    async fn list_sessions(&self, args: ListSessionsRequest) -> Result<ListSessionsResponse> {
-        self.as_ref().list_sessions(args).await
-    }
-    #[cfg(feature = "unstable_session_fork")]
-    async fn fork_session(&self, args: ForkSessionRequest) -> Result<ForkSessionResponse> {
-        self.as_ref().fork_session(args).await
-    }
-    #[cfg(feature = "unstable_session_resume")]
-    async fn resume_session(&self, args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
-        self.as_ref().resume_session(args).await
-    }
-    #[cfg(feature = "unstable_session_close")]
-    async fn close_session(&self, args: CloseSessionRequest) -> Result<CloseSessionResponse> {
-        self.as_ref().close_session(args).await
-    }
-    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
-        self.as_ref().ext_method(args).await
-    }
-    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
-        self.as_ref().ext_notification(args).await
-    }
-}
-
-#[async_trait::async_trait(?Send)]
-impl<T: Agent> Agent for Arc<T> {
-    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse> {
-        self.as_ref().initialize(args).await
-    }
-    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse> {
-        self.as_ref().authenticate(args).await
-    }
-    #[cfg(feature = "unstable_logout")]
-    async fn logout(&self, args: LogoutRequest) -> Result<LogoutResponse> {
-        self.as_ref().logout(args).await
-    }
-    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse> {
-        self.as_ref().new_session(args).await
-    }
-    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse> {
-        self.as_ref().load_session(args).await
-    }
-    async fn set_session_mode(
-        &self,
-        args: SetSessionModeRequest,
-    ) -> Result<SetSessionModeResponse> {
-        self.as_ref().set_session_mode(args).await
-    }
-    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse> {
-        self.as_ref().prompt(args).await
-    }
-    async fn cancel(&self, args: CancelNotification) -> Result<()> {
-        self.as_ref().cancel(args).await
-    }
-    #[cfg(feature = "unstable_session_model")]
-    async fn set_session_model(
-        &self,
-        args: SetSessionModelRequest,
-    ) -> Result<SetSessionModelResponse> {
-        self.as_ref().set_session_model(args).await
-    }
-    async fn set_session_config_option(
-        &self,
-        args: SetSessionConfigOptionRequest,
-    ) -> Result<SetSessionConfigOptionResponse> {
-        self.as_ref().set_session_config_option(args).await
-    }
-    async fn list_sessions(&self, args: ListSessionsRequest) -> Result<ListSessionsResponse> {
-        self.as_ref().list_sessions(args).await
-    }
-    #[cfg(feature = "unstable_session_fork")]
-    async fn fork_session(&self, args: ForkSessionRequest) -> Result<ForkSessionResponse> {
-        self.as_ref().fork_session(args).await
-    }
-    #[cfg(feature = "unstable_session_resume")]
-    async fn resume_session(&self, args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
-        self.as_ref().resume_session(args).await
-    }
-    #[cfg(feature = "unstable_session_close")]
-    async fn close_session(&self, args: CloseSessionRequest) -> Result<CloseSessionResponse> {
-        self.as_ref().close_session(args).await
-    }
-    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
-        self.as_ref().ext_method(args).await
-    }
-    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
-        self.as_ref().ext_notification(args).await
-    }
-}
diff --git a/src/agent-client-protocol-core/src/capabilities.rs b/src/agent-client-protocol/src/capabilities.rs
similarity index 97%
rename from src/agent-client-protocol-core/src/capabilities.rs
rename to src/agent-client-protocol/src/capabilities.rs
index ee3eff8..36c6f98 100644
--- a/src/agent-client-protocol-core/src/capabilities.rs
+++ b/src/agent-client-protocol/src/capabilities.rs
@@ -6,8 +6,8 @@
 //! # Example
 //!
 //! ```rust,no_run
-//! use agent_client_protocol_core::{MetaCapabilityExt, McpAcpTransport};
-//! # use agent_client_protocol_core::schema::InitializeResponse;
+//! use agent_client_protocol::{MetaCapabilityExt, McpAcpTransport};
+//! # use agent_client_protocol::schema::InitializeResponse;
 //! # let init_response: InitializeResponse = unimplemented!();
 //!
 //! let response = init_response.add_meta_capability(McpAcpTransport);
diff --git a/src/agent-client-protocol/src/client.rs b/src/agent-client-protocol/src/client.rs
deleted file mode 100644
index c60493f..0000000
--- a/src/agent-client-protocol/src/client.rs
+++ /dev/null
@@ -1,260 +0,0 @@
-use std::{rc::Rc, sync::Arc};
-
-use agent_client_protocol_schema::{
-    CreateTerminalRequest, CreateTerminalResponse, Error, ExtNotification, ExtRequest, ExtResponse,
-    KillTerminalRequest, KillTerminalResponse, ReadTextFileRequest, ReadTextFileResponse,
-    ReleaseTerminalRequest, ReleaseTerminalResponse, RequestPermissionRequest,
-    RequestPermissionResponse, Result, SessionNotification, TerminalOutputRequest,
-    TerminalOutputResponse, WaitForTerminalExitRequest, WaitForTerminalExitResponse,
-    WriteTextFileRequest, WriteTextFileResponse,
-};
-use serde_json::value::RawValue;
-
-/// Defines the interface that ACP-compliant clients must implement.
-///
-/// Clients are typically code editors (IDEs, text editors) that provide the interface
-/// between users and AI agents. They manage the environment, handle user interactions,
-/// and control access to resources.
-#[async_trait::async_trait(?Send)]
-pub trait Client {
-    /// Requests permission from the user for a tool call operation.
-    ///
-    /// Called by the agent when it needs user authorization before executing
-    /// a potentially sensitive operation. The client should present the options
-    /// to the user and return their decision.
-    ///
-    /// If the client cancels the prompt turn via `session/cancel`, it MUST
-    /// respond to this request with `RequestPermissionOutcome::Cancelled`.
-    ///
-    /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
-    async fn request_permission(
-        &self,
-        args: RequestPermissionRequest,
-    ) -> Result<RequestPermissionResponse>;
-
-    /// Handles session update notifications from the agent.
-    ///
-    /// This is a notification endpoint (no response expected) that receives
-    /// real-time updates about session progress, including message chunks,
-    /// tool calls, and execution plans.
-    ///
-    /// Note: Clients SHOULD continue accepting tool call updates even after
-    /// sending a `session/cancel` notification, as the agent may send final
-    /// updates before responding with the cancelled stop reason.
-    ///
-    /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
-    async fn session_notification(&self, args: SessionNotification) -> Result<()>;
-
-    /// Writes content to a text file in the client's file system.
-    ///
-    /// Only available if the client advertises the `fs.writeTextFile` capability.
-    /// Allows the agent to create or modify files within the client's environment.
-    ///
-    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
-    async fn write_text_file(&self, _args: WriteTextFileRequest) -> Result<WriteTextFileResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Reads content from a text file in the client's file system.
-    ///
-    /// Only available if the client advertises the `fs.readTextFile` capability.
-    /// Allows the agent to access file contents within the client's environment.
-    ///
-    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
-    async fn read_text_file(&self, _args: ReadTextFileRequest) -> Result<ReadTextFileResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Executes a command in a new terminal
-    ///
-    /// Only available if the `terminal` Client capability is set to `true`.
-    ///
-    /// Returns a `TerminalId` that can be used with other terminal methods
-    /// to get the current output, wait for exit, and kill the command.
-    ///
-    /// The `TerminalId` can also be used to embed the terminal in a tool call
-    /// by using the `ToolCallContent::Terminal` variant.
-    ///
-    /// The Agent is responsible for releasing the terminal by using the `terminal/release`
-    /// method.
-    ///
-    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
-    async fn create_terminal(
-        &self,
-        _args: CreateTerminalRequest,
-    ) -> Result<CreateTerminalResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Gets the terminal output and exit status
-    ///
-    /// Returns the current content in the terminal without waiting for the command to exit.
-    /// If the command has already exited, the exit status is included.
-    ///
-    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
-    async fn terminal_output(
-        &self,
-        _args: TerminalOutputRequest,
-    ) -> Result<TerminalOutputResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Releases a terminal
-    ///
-    /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
-    /// to wait for the command to exit before releasing the terminal.
-    ///
-    /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
-    /// but tool calls that already contain it, continue to display its output.
-    ///
-    /// The `terminal/kill` method can be used to terminate the command without releasing
-    /// the terminal, allowing the Agent to call `terminal/output` and other methods.
-    ///
-    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
-    async fn release_terminal(
-        &self,
-        _args: ReleaseTerminalRequest,
-    ) -> Result<ReleaseTerminalResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Waits for the terminal command to exit and return its exit status
-    ///
-    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
-    async fn wait_for_terminal_exit(
-        &self,
-        _args: WaitForTerminalExitRequest,
-    ) -> Result<WaitForTerminalExitResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Kills the terminal command without releasing the terminal
-    ///
-    /// While `terminal/release` will also kill the command, this method will keep
-    /// the `TerminalId` valid so it can be used with other methods.
-    ///
-    /// This method can be helpful when implementing command timeouts which terminate
-    /// the command as soon as elapsed, and then get the final output so it can be sent
-    /// to the model.
-    ///
-    /// Note: `terminal/release` when `TerminalId` is no longer needed.
-    ///
-    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
-    async fn kill_terminal(&self, _args: KillTerminalRequest) -> Result<KillTerminalResponse> {
-        Err(Error::method_not_found())
-    }
-
-    /// Handles extension method requests from the agent.
-    ///
-    /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
-    /// Extension methods provide a way to add custom functionality while maintaining
-    /// protocol compatibility.
-    ///
-    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
-    async fn ext_method(&self, _args: ExtRequest) -> Result<ExtResponse> {
-        Ok(ExtResponse::new(RawValue::NULL.to_owned().into()))
-    }
-
-    /// Handles extension notifications from the agent.
-    ///
-    /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
-    /// Extension notifications provide a way to send one-way messages for custom functionality
-    /// while maintaining protocol compatibility.
-    ///
-    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
-    async fn ext_notification(&self, _args: ExtNotification) -> Result<()> {
-        Ok(())
-    }
-}
-
-#[async_trait::async_trait(?Send)]
-impl<T: Client> Client for Rc<T> {
-    async fn request_permission(
-        &self,
-        args: RequestPermissionRequest,
-    ) -> Result<RequestPermissionResponse> {
-        self.as_ref().request_permission(args).await
-    }
-    async fn write_text_file(&self, args: WriteTextFileRequest) -> Result<WriteTextFileResponse> {
-        self.as_ref().write_text_file(args).await
-    }
-    async fn read_text_file(&self, args: ReadTextFileRequest) -> Result<ReadTextFileResponse> {
-        self.as_ref().read_text_file(args).await
-    }
-    async fn session_notification(&self, args: SessionNotification) -> Result<()> {
-        self.as_ref().session_notification(args).await
-    }
-    async fn create_terminal(&self, args: CreateTerminalRequest) -> Result<CreateTerminalResponse> {
-        self.as_ref().create_terminal(args).await
-    }
-    async fn terminal_output(&self, args: TerminalOutputRequest) -> Result<TerminalOutputResponse> {
-        self.as_ref().terminal_output(args).await
-    }
-    async fn release_terminal(
-        &self,
-        args: ReleaseTerminalRequest,
-    ) -> Result<ReleaseTerminalResponse> {
-        self.as_ref().release_terminal(args).await
-    }
-    async fn wait_for_terminal_exit(
-        &self,
-        args: WaitForTerminalExitRequest,
-    ) -> Result<WaitForTerminalExitResponse> {
-        self.as_ref().wait_for_terminal_exit(args).await
-    }
-    async fn kill_terminal(&self, args: KillTerminalRequest) -> Result<KillTerminalResponse> {
-        self.as_ref().kill_terminal(args).await
-    }
-    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
-        self.as_ref().ext_method(args).await
-    }
-    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
-        self.as_ref().ext_notification(args).await
-    }
-}
-
-#[async_trait::async_trait(?Send)]
-impl<T: Client> Client for Arc<T> {
-    async fn request_permission(
-        &self,
-        args: RequestPermissionRequest,
-    ) -> Result<RequestPermissionResponse> {
-        self.as_ref().request_permission(args).await
-    }
-    async fn write_text_file(&self, args: WriteTextFileRequest) -> Result<WriteTextFileResponse> {
-        self.as_ref().write_text_file(args).await
-    }
-    async fn read_text_file(&self, args: ReadTextFileRequest) -> Result<ReadTextFileResponse> {
-        self.as_ref().read_text_file(args).await
-    }
-    async fn session_notification(&self, args: SessionNotification) -> Result<()> {
-        self.as_ref().session_notification(args).await
-    }
-    async fn create_terminal(&self, args: CreateTerminalRequest) -> Result<CreateTerminalResponse> {
-        self.as_ref().create_terminal(args).await
-    }
-    async fn terminal_output(&self, args: TerminalOutputRequest) -> Result<TerminalOutputResponse> {
-        self.as_ref().terminal_output(args).await
-    }
-    async fn release_terminal(
-        &self,
-        args: ReleaseTerminalRequest,
-    ) -> Result<ReleaseTerminalResponse> {
-        self.as_ref().release_terminal(args).await
-    }
-    async fn wait_for_terminal_exit(
-        &self,
-        args: WaitForTerminalExitRequest,
-    ) -> Result<WaitForTerminalExitResponse> {
-        self.as_ref().wait_for_terminal_exit(args).await
-    }
-    async fn kill_terminal(&self, args: KillTerminalRequest) -> Result<KillTerminalResponse> {
-        self.as_ref().kill_terminal(args).await
-    }
-    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
-        self.as_ref().ext_method(args).await
-    }
-    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
-        self.as_ref().ext_notification(args).await
-    }
-}
diff --git a/src/agent-client-protocol-core/src/component.rs b/src/agent-client-protocol/src/component.rs
similarity index 97%
rename from src/agent-client-protocol-core/src/component.rs
rename to src/agent-client-protocol/src/component.rs
index f86bc2e..b3c0304 100644
--- a/src/agent-client-protocol-core/src/component.rs
+++ b/src/agent-client-protocol/src/component.rs
@@ -11,7 +11,7 @@
 //! To implement a component, implement the `connect_to` method:
 //!
 //! ```rust,ignore
-//! use agent_client_protocol_core::{Agent, Client, Connect, Result};
+//! use agent_client_protocol::{Agent, Client, Connect, Result};
 //!
 //! struct MyAgent {
 //!     // configuration fields
@@ -68,7 +68,7 @@ use crate::{Channel, Result, role::Role};
 /// # Implementation Example
 ///
 /// ```rust,ignore
-/// use agent_client_protocol_core::{Agent, Result, Serve, role::Client};
+/// use agent_client_protocol::{Agent, Result, Serve, role::Client};
 ///
 /// struct MyAgent {
 ///     config: AgentConfig,
@@ -94,7 +94,7 @@ use crate::{Channel, Result, role::Role};
 /// For storing different component types in the same collection, use [`DynConnectTo`]:
 ///
 /// ```rust,ignore
-/// use agent_client_protocol_core::Client;
+/// use agent_client_protocol::Client;
 ///
 /// let components: Vec<DynConnectTo<Client>> = vec![
 ///     DynConnectTo::new(proxy1),
@@ -205,7 +205,7 @@ impl<C: ConnectTo<R>, R: Role> ErasedConnectTo<R> for C {
 /// # Examples
 ///
 /// ```rust,ignore
-/// use agent_client_protocol_core::{DynConnectTo, Client};
+/// use agent_client_protocol::{DynConnectTo, Client};
 ///
 /// let components: Vec<DynConnectTo<Client>> = vec![
 ///     DynConnectTo::new(Proxy1),
diff --git a/src/agent-client-protocol-core/src/concepts/acp_basics.rs b/src/agent-client-protocol/src/concepts/acp_basics.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/concepts/acp_basics.rs
rename to src/agent-client-protocol/src/concepts/acp_basics.rs
diff --git a/src/agent-client-protocol-core/src/concepts/callbacks.rs b/src/agent-client-protocol/src/concepts/callbacks.rs
similarity index 79%
rename from src/agent-client-protocol-core/src/concepts/callbacks.rs
rename to src/agent-client-protocol/src/concepts/callbacks.rs
index 231c117..df71883 100644
--- a/src/agent-client-protocol-core/src/concepts/callbacks.rs
+++ b/src/agent-client-protocol/src/concepts/callbacks.rs
@@ -8,9 +8,9 @@
 //! Use `on_receive_request` to handle incoming requests that expect a response:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::{ValidateRequest, ValidateResponse};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! Client.builder()
 //!     .on_receive_request(async |req: ValidateRequest, responder, cx| {
 //!         // Process the request
@@ -18,7 +18,7 @@
 //!
 //!         // Send the response
 //!         responder.respond(ValidateResponse { is_valid, error: None })
-//!     }, agent_client_protocol_core::on_receive_request!())
+//!     }, agent_client_protocol::on_receive_request!())
 //!     .connect_with(transport, async |cx| { Ok(()) })
 //!     .await?;
 //! # Ok(())
@@ -36,14 +36,14 @@
 //! a response:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::StatusUpdate;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! Client.builder()
 //!     .on_receive_notification(async |notif: StatusUpdate, cx| {
 //!         println!("Status: {}", notif.message);
 //!         Ok(())
-//!     }, agent_client_protocol_core::on_receive_notification!())
+//!     }, agent_client_protocol::on_receive_notification!())
 //! #   .connect_with(transport, async |_| Ok(())).await?;
 //! # Ok(())
 //! # }
@@ -54,15 +54,15 @@
 //! The [`Responder`] lets you send a response to the request:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::{MyRequest, MyResponse};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder()
 //! #   .on_receive_request(async |req: MyRequest, responder, cx| {
 //! // Send a successful response
 //! responder.respond(MyResponse { status: "ok".into() })?;
 //! # Ok(())
-//! #   }, agent_client_protocol_core::on_receive_request!())
+//! #   }, agent_client_protocol::on_receive_request!())
 //! #   .connect_with(transport, async |_| Ok(())).await?;
 //! # Ok(())
 //! # }
@@ -71,14 +71,14 @@
 //! Or send an error:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::{MyRequest, MyResponse};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder()
 //! #   .on_receive_request(async |req: MyRequest, responder, cx| {
-//! responder.respond_with_error(agent_client_protocol_core::Error::invalid_params())?;
+//! responder.respond_with_error(agent_client_protocol::Error::invalid_params())?;
 //! # Ok(())
-//! #   }, agent_client_protocol_core::on_receive_request!())
+//! #   }, agent_client_protocol::on_receive_request!())
 //! #   .connect_with(transport, async |_| Ok(())).await?;
 //! # Ok(())
 //! # }
@@ -93,18 +93,18 @@
 //! handles the message:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::{ValidateRequest, ValidateResponse, ExecuteRequest, ExecuteResponse};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! Client.builder()
 //!     .on_receive_request(async |req: ValidateRequest, responder, cx| {
 //!         // Handle validation requests
 //!         responder.respond(ValidateResponse { is_valid: true, error: None })
-//!     }, agent_client_protocol_core::on_receive_request!())
+//!     }, agent_client_protocol::on_receive_request!())
 //!     .on_receive_request(async |req: ExecuteRequest, responder, cx| {
 //!         // Handle execution requests
 //!         responder.respond(ExecuteResponse { result: "done".into() })
-//!     }, agent_client_protocol_core::on_receive_request!())
+//!     }, agent_client_protocol::on_receive_request!())
 //! #   .connect_with(transport, async |_| Ok(())).await?;
 //! # Ok(())
 //! # }
diff --git a/src/agent-client-protocol-core/src/concepts/connections.rs b/src/agent-client-protocol/src/concepts/connections.rs
similarity index 87%
rename from src/agent-client-protocol-core/src/concepts/connections.rs
rename to src/agent-client-protocol/src/concepts/connections.rs
index a4c9006..8c05fe7 100644
--- a/src/agent-client-protocol-core/src/concepts/connections.rs
+++ b/src/agent-client-protocol/src/concepts/connections.rs
@@ -21,8 +21,8 @@
 //! The builder lets you configure handlers, then connect to a transport:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! Client.builder()
 //!     .name("my-client")
 //!     .connect_with(transport, async |cx| {
@@ -40,10 +40,10 @@
 //! lets you interact with the remote peer:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # use agent_client_protocol_core::schema::{InitializeRequest, ProtocolVersion};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::schema::{InitializeRequest, ProtocolVersion};
 //! # use agent_client_protocol_test::StatusUpdate;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! // Send a request and wait for the response
 //! let response = cx.send_request(InitializeRequest::new(ProtocolVersion::V1))
@@ -68,9 +68,9 @@
 //! Use `block_task()` when you need the response before continuing:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::MyRequest;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! let response = cx.send_request(MyRequest {})
 //!     .block_task()
@@ -87,9 +87,9 @@
 //! Use `on_receiving_result()` when you want to handle the response asynchronously:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::MyRequest;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! cx.send_request(MyRequest {})
 //!     .on_receiving_result(async |result| {
diff --git a/src/agent-client-protocol-core/src/concepts/error_handling.rs b/src/agent-client-protocol/src/concepts/error_handling.rs
similarity index 80%
rename from src/agent-client-protocol-core/src/concepts/error_handling.rs
rename to src/agent-client-protocol/src/concepts/error_handling.rs
index f1cc0b9..e2d84ba 100644
--- a/src/agent-client-protocol-core/src/concepts/error_handling.rs
+++ b/src/agent-client-protocol/src/concepts/error_handling.rs
@@ -1,12 +1,12 @@
-//! Error handling patterns in agent-client-protocol-core.
+//! Error handling patterns in agent-client-protocol.
 //!
-//! This chapter explains how errors work in agent-client-protocol-core callbacks and the difference
+//! This chapter explains how errors work in agent-client-protocol callbacks and the difference
 //! between *protocol errors* (sent to the peer) and *connection errors* (which
 //! shut down the connection).
 //!
 //! # Callback Return Types
 //!
-//! Almost all agent-client-protocol-core callbacks return `Result<_, crate::Error>`. What happens
+//! Almost all agent-client-protocol callbacks return `Result<_, crate::Error>`. What happens
 //! when you return an `Err` depends on the context:
 //!
 //! **Returning `Err` from a callback shuts down the connection.**
@@ -22,21 +22,21 @@
 //! use the request context's `respond` method:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::{ValidateRequest, ValidateResponse};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! Client.builder()
 //!     .on_receive_request(async |request: ValidateRequest, responder, _cx| {
 //!         if request.data.is_empty() {
 //!             // Send error to peer, keep connection alive
-//!             responder.respond_with_error(agent_client_protocol_core::Error::invalid_params())?;
+//!             responder.respond_with_error(agent_client_protocol::Error::invalid_params())?;
 //!             return Ok(());
 //!         }
 //!
 //!         // Process valid request...
 //!         responder.respond(ValidateResponse { is_valid: true, error: None })?;
 //!         Ok(())
-//!     }, agent_client_protocol_core::on_receive_request!())
+//!     }, agent_client_protocol::on_receive_request!())
 //! #   .connect_with(transport, async |_| Ok(())).await?;
 //! # Ok(())
 //! # }
@@ -46,10 +46,10 @@
 //! [`send_error_notification`][crate::ConnectionTo::send_error_notification]:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
-//! cx.send_error_notification(agent_client_protocol_core::Error::internal_error()
+//! cx.send_error_notification(agent_client_protocol::Error::internal_error()
 //!     .data("Something went wrong"))?;
 //! # Ok(())
 //! # }).await?;
@@ -60,17 +60,17 @@
 //! # The `into_internal_error` Helper
 //!
 //! When working with external libraries that return their own error types,
-//! you need to convert them to `agent_client_protocol_core::Error`. The
+//! you need to convert them to `agent_client_protocol::Error`. The
 //! [`Error::into_internal_error`][crate::Error::into_internal_error] method
 //! provides a convenient way to do this:
 //!
 //! ```
-//! use agent_client_protocol_core::Error;
+//! use agent_client_protocol::Error;
 //!
-//! # fn example() -> Result<(), agent_client_protocol_core::Error> {
+//! # fn example() -> Result<(), agent_client_protocol::Error> {
 //! # let data = "hello";
 //! # let path = "/tmp/test.txt";
-//! // Convert any error type to agent_client_protocol_core::Error
+//! // Convert any error type to agent_client_protocol::Error
 //! let value = serde_json::to_value(&data)
 //!     .map_err(Error::into_internal_error)?;
 //!
@@ -99,7 +99,7 @@
 //! You can add context with `.data()`:
 //!
 //! ```
-//! let error = agent_client_protocol_core::Error::invalid_params()
+//! let error = agent_client_protocol::Error::invalid_params()
 //!     .data(serde_json::json!({
 //!         "field": "timeout",
 //!         "reason": "must be positive"
diff --git a/src/agent-client-protocol-core/src/concepts/mod.rs b/src/agent-client-protocol/src/concepts/mod.rs
similarity index 92%
rename from src/agent-client-protocol-core/src/concepts/mod.rs
rename to src/agent-client-protocol/src/concepts/mod.rs
index 5c32b48..01b77ef 100644
--- a/src/agent-client-protocol-core/src/concepts/mod.rs
+++ b/src/agent-client-protocol/src/concepts/mod.rs
@@ -1,7 +1,7 @@
-//! Core concepts for understanding and using agent-client-protocol-core.
+//! Core concepts for understanding and using agent-client-protocol.
 //!
 //! This module provides detailed explanations of the key concepts you need
-//! to work effectively with the agent-client-protocol-core SDK. Read these in order for a progressive
+//! to work effectively with the agent-client-protocol SDK. Read these in order for a progressive
 //! introduction, or jump to specific topics as needed.
 //!
 //! # Table of Contents
diff --git a/src/agent-client-protocol-core/src/concepts/ordering.rs b/src/agent-client-protocol/src/concepts/ordering.rs
similarity index 93%
rename from src/agent-client-protocol-core/src/concepts/ordering.rs
rename to src/agent-client-protocol/src/concepts/ordering.rs
index 602b844..bc27f9b 100644
--- a/src/agent-client-protocol-core/src/concepts/ordering.rs
+++ b/src/agent-client-protocol/src/concepts/ordering.rs
@@ -1,6 +1,6 @@
 //! Message ordering, concurrency, and the dispatch loop.
 //!
-//! Understanding how agent-client-protocol-core processes messages is key to writing correct code.
+//! Understanding how agent-client-protocol processes messages is key to writing correct code.
 //! This chapter explains the dispatch loop and the ordering guarantees you
 //! can rely on.
 //!
@@ -58,9 +58,9 @@
 //! Use this in spawned tasks where you need to wait for the response:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::MyRequest;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! cx.spawn({
 //!     let cx = cx.clone();
@@ -87,9 +87,9 @@
 //! Use this when you need ordering guarantees:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::MyRequest;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! cx.send_request(MyRequest {})
 //!     .on_receiving_result(async |result| {
@@ -132,8 +132,8 @@
 //! so awaiting them won't cause deadlocks:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! cx.build_session_cwd()?
 //!     .block_task()
diff --git a/src/agent-client-protocol-core/src/concepts/peers.rs b/src/agent-client-protocol/src/concepts/peers.rs
similarity index 86%
rename from src/agent-client-protocol-core/src/concepts/peers.rs
rename to src/agent-client-protocol/src/concepts/peers.rs
index 93d8204..29978ff 100644
--- a/src/agent-client-protocol-core/src/concepts/peers.rs
+++ b/src/agent-client-protocol/src/concepts/peers.rs
@@ -16,9 +16,9 @@
 //! So when you write:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # use agent_client_protocol_core::schema::{InitializeRequest, ProtocolVersion};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::schema::{InitializeRequest, ProtocolVersion};
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! // As a client
 //! cx.send_request(InitializeRequest::new(ProtocolVersion::V1));
@@ -45,9 +45,9 @@
 //! For simple role types, the explicit form is equivalent:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
 //! # use agent_client_protocol_test::MyRequest;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! # let req = MyRequest {};
 //! // These are equivalent for Client:
@@ -70,16 +70,16 @@
 //! When writing proxy code, you need to specify which direction:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Proxy, Client, Agent, Conductor, ConnectTo};
+//! # use agent_client_protocol::{Proxy, Client, Agent, Conductor, ConnectTo};
 //! # use agent_client_protocol_test::MyRequest;
-//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
 //! Proxy.builder()
 //!     // Receive a request from the client
 //!     .on_receive_request_from(Client, async |req: MyRequest, responder, cx| {
 //!         // Forward it to the agent
 //!         cx.send_request_to(Agent, req)
 //!             .forward_response_to(responder)
-//!     }, agent_client_protocol_core::on_receive_request!())
+//!     }, agent_client_protocol::on_receive_request!())
 //!     .connect_to(transport)
 //!     .await?;
 //! # Ok(())
diff --git a/src/agent-client-protocol-core/src/concepts/proxies.rs b/src/agent-client-protocol/src/concepts/proxies.rs
similarity index 84%
rename from src/agent-client-protocol-core/src/concepts/proxies.rs
rename to src/agent-client-protocol/src/concepts/proxies.rs
index c8857df..9b985aa 100644
--- a/src/agent-client-protocol-core/src/concepts/proxies.rs
+++ b/src/agent-client-protocol/src/concepts/proxies.rs
@@ -20,8 +20,8 @@
 //! This means a minimal proxy that does nothing is just:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Proxy, Conductor, ConnectTo};
-//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Proxy, Conductor, ConnectTo};
+//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
 //! Proxy.builder()
 //!     .connect_to(transport)
 //!     .await?;
@@ -36,9 +36,9 @@
 //! To intercept specific messages, use `on_receive_*_from` with explicit peers:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Proxy, Client, Agent, Conductor, ConnectTo};
+//! # use agent_client_protocol::{Proxy, Client, Agent, Conductor, ConnectTo};
 //! # use agent_client_protocol_test::ProcessRequest;
-//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
 //! Proxy.builder()
 //!     // Intercept requests from the client
 //!     .on_receive_request_from(Client, async |req: ProcessRequest, responder, cx| {
@@ -50,7 +50,7 @@
 //!         // Forward to agent and relay the response back
 //!         cx.send_request_to(Agent, modified)
 //!             .forward_response_to(responder)
-//!     }, agent_client_protocol_core::on_receive_request!())
+//!     }, agent_client_protocol::on_receive_request!())
 //!     .connect_to(transport)
 //!     .await?;
 //! # Ok(())
@@ -67,9 +67,9 @@
 //! ## Global MCP Server
 //!
 //! ```
-//! # use agent_client_protocol_core::{Proxy, Conductor, ConnectTo};
-//! # use agent_client_protocol_core::mcp_server::McpServer;
-//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Proxy, Conductor, ConnectTo};
+//! # use agent_client_protocol::mcp_server::McpServer;
+//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
 //! # let my_mcp_server = McpServer::<Conductor, _>::builder("tools").build();
 //! Proxy.builder()
 //!     .with_mcp_server(my_mcp_server)
@@ -82,10 +82,10 @@
 //! ## Per-Session MCP Server
 //!
 //! ```
-//! # use agent_client_protocol_core::{Proxy, Client, Conductor, ConnectTo};
-//! # use agent_client_protocol_core::schema::NewSessionRequest;
-//! # use agent_client_protocol_core::mcp_server::McpServer;
-//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Proxy, Client, Conductor, ConnectTo};
+//! # use agent_client_protocol::schema::NewSessionRequest;
+//! # use agent_client_protocol::mcp_server::McpServer;
+//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
 //! Proxy.builder()
 //!     .on_receive_request_from(Client, async |req: NewSessionRequest, responder, cx| {
 //!         let my_mcp_server = McpServer::<Conductor, _>::builder("tools").build();
@@ -95,7 +95,7 @@
 //!                 // Session started with MCP server attached
 //!                 Ok(())
 //!             })
-//!     }, agent_client_protocol_core::on_receive_request!())
+//!     }, agent_client_protocol::on_receive_request!())
 //!     .connect_to(transport)
 //!     .await?;
 //! # Ok(())
diff --git a/src/agent-client-protocol-core/src/concepts/sessions.rs b/src/agent-client-protocol/src/concepts/sessions.rs
similarity index 82%
rename from src/agent-client-protocol-core/src/concepts/sessions.rs
rename to src/agent-client-protocol/src/concepts/sessions.rs
index dd0f8bd..142350a 100644
--- a/src/agent-client-protocol-core/src/concepts/sessions.rs
+++ b/src/agent-client-protocol/src/concepts/sessions.rs
@@ -9,8 +9,8 @@
 //! Use the session builder to create a new session:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! cx.build_session_cwd()?          // Use current working directory
 //!     .block_task()                // Mark as blocking
@@ -28,8 +28,8 @@
 //! Or specify a custom working directory:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! cx.build_session("/path/to/project")
 //!     .block_task()
@@ -47,8 +47,8 @@
 //! with the agent:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # Client.builder().connect_with(transport, async |cx| {
 //! # cx.build_session_cwd()?.block_task()
 //! .run_until(async |mut session| {
@@ -78,9 +78,9 @@
 //! tools to the agent:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # use agent_client_protocol_core::mcp_server::McpServer;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::mcp_server::McpServer;
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! # let my_mcp_server = McpServer::<Agent, _>::builder("tools").build();
 //! # Client.builder().connect_with(transport, async |cx| {
 //! cx.build_session_cwd()?
@@ -102,9 +102,9 @@
 //! use `on_session_start` instead of `block_task().run_until()`:
 //!
 //! ```
-//! # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-//! # use agent_client_protocol_core::schema::NewSessionRequest;
-//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+//! # use agent_client_protocol::{Client, Agent, ConnectTo};
+//! # use agent_client_protocol::schema::NewSessionRequest;
+//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 //! Client.builder()
 //!     .on_receive_request(async |req: NewSessionRequest, responder, cx| {
 //!         cx.build_session_from(req)
@@ -113,7 +113,7 @@
 //!                 Ok(())
 //!             })?;
 //!         Ok(())
-//!     }, agent_client_protocol_core::on_receive_request!())
+//!     }, agent_client_protocol::on_receive_request!())
 //! #   .connect_with(transport, async |_| Ok(())).await?;
 //! # Ok(())
 //! # }
diff --git a/src/agent-client-protocol-core/src/cookbook.rs b/src/agent-client-protocol/src/cookbook.rs
similarity index 94%
rename from src/agent-client-protocol-core/src/cookbook.rs
rename to src/agent-client-protocol/src/cookbook.rs
index 689cb83..d4bad8b 100644
--- a/src/agent-client-protocol-core/src/cookbook.rs
+++ b/src/agent-client-protocol/src/cookbook.rs
@@ -1,7 +1,7 @@
 //! Cookbook of common patterns for building ACP components.
 //!
 //! This module has moved to the [`agent_client_protocol_cookbook`] crate, which provides
-//! more comprehensive examples with full access to the entire agent-client-protocol-core ecosystem.
+//! more comprehensive examples with full access to the entire agent-client-protocol ecosystem.
 //!
 //! See [`agent_client_protocol_cookbook`] for:
 //!
diff --git a/src/agent-client-protocol-core/src/handler.rs b/src/agent-client-protocol/src/handler.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/handler.rs
rename to src/agent-client-protocol/src/handler.rs
diff --git a/src/agent-client-protocol-core/src/jsonrpc.rs b/src/agent-client-protocol/src/jsonrpc.rs
similarity index 94%
rename from src/agent-client-protocol-core/src/jsonrpc.rs
rename to src/agent-client-protocol/src/jsonrpc.rs
index e6ac431..6062dce 100644
--- a/src/agent-client-protocol-core/src/jsonrpc.rs
+++ b/src/agent-client-protocol/src/jsonrpc.rs
@@ -107,21 +107,21 @@ use crate::{Agent, Client, ConnectTo, RoleId};
 /// Most users register handlers using the builder methods on [`Builder`]:
 ///
 /// ```
-/// # use agent_client_protocol_core::{Agent, Client, ConnectTo};
-/// # use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, AgentCapabilities};
+/// # use agent_client_protocol::{Agent, Client, ConnectTo};
+/// # use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, AgentCapabilities};
 /// # use agent_client_protocol_test::StatusUpdate;
-/// # async fn example(transport: impl ConnectTo<Agent>) -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example(transport: impl ConnectTo<Agent>) -> Result<(), agent_client_protocol::Error> {
 /// Agent.builder()
 ///     .on_receive_request(async |req: InitializeRequest, responder, cx| {
 ///         responder.respond(
 ///             InitializeResponse::new(req.protocol_version)
 ///                 .agent_capabilities(AgentCapabilities::new()),
 ///         )
-///     }, agent_client_protocol_core::on_receive_request!())
+///     }, agent_client_protocol::on_receive_request!())
 ///     .on_receive_notification(async |notif: StatusUpdate, cx| {
 ///         // Process notification
 ///         Ok(())
-///     }, agent_client_protocol_core::on_receive_notification!())
+///     }, agent_client_protocol::on_receive_notification!())
 ///     .connect_to(transport)
 ///     .await?;
 /// # Ok(())
@@ -167,9 +167,9 @@ use crate::{Agent, Client, ConnectTo, RoleId};
 /// to run work concurrently:
 ///
 /// ```
-/// # use agent_client_protocol_core::{Client, Agent, ConnectTo};
+/// # use agent_client_protocol::{Client, Agent, ConnectTo};
 /// # use agent_client_protocol_test::{expensive_operation, ProcessComplete};
-/// # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
 /// # Client.builder().connect_with(transport, async |cx| {
 /// cx.spawn({
 ///     let connection = cx.clone();
@@ -268,18 +268,18 @@ where
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, SessionNotification};
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, SessionNotification};
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// connection
 ///     .on_receive_request(async |req: InitializeRequest, responder, cx| {
 ///         // Handle only InitializeRequest messages
 ///         responder.respond(InitializeResponse::make())
-///     }, agent_client_protocol_core::on_receive_request!())
+///     }, agent_client_protocol::on_receive_request!())
 ///     .on_receive_notification(async |notif: SessionNotification, cx| {
 ///         // Handle only SessionUpdate notifications
 ///         Ok(())
-///     }, agent_client_protocol_core::on_receive_notification!())
+///     }, agent_client_protocol::on_receive_notification!())
 /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
 /// # Ok(())
 /// # }
@@ -292,9 +292,9 @@ where
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # use agent_client_protocol_core::{JsonRpcRequest, JsonRpcMessage, UntypedMessage};
-/// # use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, PromptRequest, PromptResponse};
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::{JsonRpcRequest, JsonRpcMessage, UntypedMessage};
+/// # use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, PromptRequest, PromptResponse};
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// // Define an enum for multiple request types
 /// #[derive(Debug, Clone)]
@@ -307,8 +307,8 @@ where
 /// # impl JsonRpcMessage for MyRequests {
 /// #     fn matches_method(_method: &str) -> bool { false }
 /// #     fn method(&self) -> &str { "myRequests" }
-/// #     fn to_untyped_message(&self) -> Result<UntypedMessage, agent_client_protocol_core::Error> { todo!() }
-/// #     fn parse_message(_method: &str, _params: &impl serde::Serialize) -> Result<Self, agent_client_protocol_core::Error> { Err(agent_client_protocol_core::Error::method_not_found()) }
+/// #     fn to_untyped_message(&self) -> Result<UntypedMessage, agent_client_protocol::Error> { todo!() }
+/// #     fn parse_message(_method: &str, _params: &impl serde::Serialize) -> Result<Self, agent_client_protocol::Error> { Err(agent_client_protocol::Error::method_not_found()) }
 /// # }
 /// impl JsonRpcRequest for MyRequests { type Response = serde_json::Value; }
 ///
@@ -318,7 +318,7 @@ where
 ///         MyRequests::Initialize(init) => { responder.respond(serde_json::json!({})) }
 ///         MyRequests::Prompt(prompt) => { responder.respond(serde_json::json!({})) }
 ///     }
-/// }, agent_client_protocol_core::on_receive_request!())
+/// }, agent_client_protocol::on_receive_request!())
 /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
 /// # Ok(())
 /// # }
@@ -330,9 +330,9 @@ where
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # use agent_client_protocol_core::Dispatch;
-/// # use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, SessionNotification};
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::Dispatch;
+/// # use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, SessionNotification};
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// // on_receive_dispatch receives Dispatch which can be either a request or notification
 /// connection.on_receive_dispatch(async |msg: Dispatch<InitializeRequest, SessionNotification>, _cx| {
@@ -348,7 +348,7 @@ where
 ///             router.respond_with_result(result)
 ///         }
 ///     }
-/// }, agent_client_protocol_core::on_receive_dispatch!())
+/// }, agent_client_protocol::on_receive_dispatch!())
 /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
 /// # Ok(())
 /// # }
@@ -370,23 +370,23 @@ where
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # use agent_client_protocol_core::{Dispatch, UntypedMessage};
-/// # use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, PromptRequest, PromptResponse};
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::{Dispatch, UntypedMessage};
+/// # use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, PromptRequest, PromptResponse};
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// connection
 ///     .on_receive_request(async |req: InitializeRequest, responder, cx| {
 ///         // This runs first for InitializeRequest
 ///         responder.respond(InitializeResponse::make())
-///     }, agent_client_protocol_core::on_receive_request!())
+///     }, agent_client_protocol::on_receive_request!())
 ///     .on_receive_request(async |req: PromptRequest, responder, cx| {
 ///         // This runs first for PromptRequest
 ///         responder.respond(PromptResponse::make())
-///     }, agent_client_protocol_core::on_receive_request!())
+///     }, agent_client_protocol::on_receive_request!())
 ///     .on_receive_dispatch(async |msg: Dispatch, cx| {
 ///         // This runs for any message not handled above
-///         msg.respond_with_error(agent_client_protocol_core::util::internal_error("unknown method"), cx)
-///     }, agent_client_protocol_core::on_receive_dispatch!())
+///         msg.respond_with_error(agent_client_protocol::util::internal_error("unknown method"), cx)
+///     }, agent_client_protocol::on_receive_dispatch!())
 /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
 /// # Ok(())
 /// # }
@@ -407,7 +407,7 @@ where
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// connection.on_receive_request(async |req: AnalyzeRequest, responder, cx| {
 ///     // Clone cx for the spawned task
@@ -422,7 +422,7 @@ where
 ///
 ///     // Respond immediately without blocking
 ///     responder.respond(AnalysisStarted { job_id: 42 })
-/// }, agent_client_protocol_core::on_receive_request!())
+/// }, agent_client_protocol::on_receive_request!())
 /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
 /// # Ok(())
 /// # }
@@ -459,12 +459,12 @@ where
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// connection
 ///     .on_receive_request(async |req: MyRequest, responder, cx| {
 ///         responder.respond(MyResponse { status: "ok".into() })
-///     }, agent_client_protocol_core::on_receive_request!())
+///     }, agent_client_protocol::on_receive_request!())
 ///     .connect_to(MockTransport)  // Runs until connection closes or error occurs
 ///     .await?;
 /// # Ok(())
@@ -481,13 +481,13 @@ where
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # use agent_client_protocol_core::schema::InitializeRequest;
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::schema::InitializeRequest;
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// connection
 ///     .on_receive_request(async |req: MyRequest, responder, cx| {
 ///         responder.respond(MyResponse { status: "ok".into() })
-///     }, agent_client_protocol_core::on_receive_request!())
+///     }, agent_client_protocol::on_receive_request!())
 ///     .connect_with(MockTransport, async |cx| {
 ///         // You can send requests to the other side
 ///         let response = cx.send_request(InitializeRequest::make())
@@ -510,12 +510,12 @@ where
 /// # Example: Complete Agent
 ///
 /// ```no_run
-/// # use agent_client_protocol_core::UntypedRole;
-/// # use agent_client_protocol_core::{Builder};
-/// # use agent_client_protocol_core::ByteStreams;
-/// # use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, PromptRequest, PromptResponse, SessionNotification};
+/// # use agent_client_protocol::UntypedRole;
+/// # use agent_client_protocol::{Builder};
+/// # use agent_client_protocol::ByteStreams;
+/// # use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, PromptRequest, PromptResponse, SessionNotification};
 /// # use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// let transport = ByteStreams::new(
 ///     tokio::io::stdout().compat_write(),
 ///     tokio::io::stdin().compat(),
@@ -526,7 +526,7 @@ where
 ///     .on_receive_request(async |init: InitializeRequest, responder, cx| {
 ///         let response: InitializeResponse = todo!();
 ///         responder.respond(response)
-///     }, agent_client_protocol_core::on_receive_request!())
+///     }, agent_client_protocol::on_receive_request!())
 ///     .on_receive_request(async |prompt: PromptRequest, responder, cx| {
 ///         // You can send notifications while processing a request
 ///         let notif: SessionNotification = todo!();
@@ -535,7 +535,7 @@ where
 ///         // Then respond to the request
 ///         let response: PromptResponse = todo!();
 ///         responder.respond(response)
-///     }, agent_client_protocol_core::on_receive_request!())
+///     }, agent_client_protocol::on_receive_request!())
 ///     .connect_to(transport)
 ///     .await?;
 /// # Ok(())
@@ -689,8 +689,8 @@ impl<
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # use agent_client_protocol_core::Dispatch;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # use agent_client_protocol::Dispatch;
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// # let connection = mock_connection();
     /// connection.on_receive_dispatch(async |message: Dispatch<MyRequest, StatusUpdate>, _cx| {
     ///     match message {
@@ -707,7 +707,7 @@ impl<
     ///             router.respond_with_result(result)
     ///         }
     ///     }
-    /// }, agent_client_protocol_core::on_receive_dispatch!())
+    /// }, agent_client_protocol::on_receive_dispatch!())
     /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
     /// # Ok(())
     /// # }
@@ -768,10 +768,10 @@ impl<
     /// # Example
     ///
     /// ```ignore
-    /// # use agent_client_protocol_core::UntypedRole;
-    /// # use agent_client_protocol_core::{Builder};
-    /// # use agent_client_protocol_core::schema::{PromptRequest, PromptResponse, SessionNotification};
-    /// # fn example<R: agent_client_protocol_core::Role>(connection: Builder<R, impl agent_client_protocol_core::HandleMessageAs<R>>) {
+    /// # use agent_client_protocol::UntypedRole;
+    /// # use agent_client_protocol::{Builder};
+    /// # use agent_client_protocol::schema::{PromptRequest, PromptResponse, SessionNotification};
+    /// # fn example<R: agent_client_protocol::Role>(connection: Builder<R, impl agent_client_protocol::HandleMessageAs<R>>) {
     /// connection.on_receive_request(async |request: PromptRequest, responder, cx| {
     ///     // Send a notification while processing
     ///     let notif: SessionNotification = todo!();
@@ -783,7 +783,7 @@ impl<
     ///     // Send the response
     ///     let response: PromptResponse = todo!();
     ///     responder.respond(response)
-    /// }, agent_client_protocol_core::on_receive_request!());
+    /// }, agent_client_protocol::on_receive_request!());
     /// # }
     /// ```
     ///
@@ -843,7 +843,7 @@ impl<
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// # let connection = mock_connection();
     /// connection.on_receive_notification(async |notif: SessionUpdate, cx| {
     ///     // Process the notification
@@ -855,7 +855,7 @@ impl<
     ///     })?;
     ///
     ///     Ok(())
-    /// }, agent_client_protocol_core::on_receive_notification!())
+    /// }, agent_client_protocol::on_receive_notification!())
     /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
     /// # Ok(())
     /// # }
@@ -959,8 +959,8 @@ impl<
     /// # Example
     ///
     /// ```ignore
-    /// use agent_client_protocol_core::Agent;
-    /// use agent_client_protocol_core::schema::InitializeRequest;
+    /// use agent_client_protocol::Agent;
+    /// use agent_client_protocol::schema::InitializeRequest;
     ///
     /// // Conductor receiving from agent direction - messages will be unwrapped from SuccessorMessage
     /// connection.on_receive_request_from(Agent, async |req: InitializeRequest, responder, cx| {
@@ -1075,12 +1075,12 @@ impl<
     /// # Example: Byte Stream Transport
     ///
     /// ```no_run
-    /// # use agent_client_protocol_core::UntypedRole;
-    /// # use agent_client_protocol_core::{Builder};
-    /// # use agent_client_protocol_core::ByteStreams;
+    /// # use agent_client_protocol::UntypedRole;
+    /// # use agent_client_protocol::{Builder};
+    /// # use agent_client_protocol::ByteStreams;
     /// # use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
     /// # use agent_client_protocol_test::*;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// let transport = ByteStreams::new(
     ///     tokio::io::stdout().compat_write(),
     ///     tokio::io::stdin().compat(),
@@ -1089,7 +1089,7 @@ impl<
     /// UntypedRole.builder()
     ///     .on_receive_request(async |req: MyRequest, responder, cx| {
     ///         responder.respond(MyResponse { status: "ok".into() })
-    ///     }, agent_client_protocol_core::on_receive_request!())
+    ///     }, agent_client_protocol::on_receive_request!())
     ///     .connect_to(transport)
     ///     .await?;
     /// # Ok(())
@@ -1119,13 +1119,13 @@ impl<
     /// # Example
     ///
     /// ```no_run
-    /// # use agent_client_protocol_core::UntypedRole;
-    /// # use agent_client_protocol_core::{Builder};
-    /// # use agent_client_protocol_core::ByteStreams;
-    /// # use agent_client_protocol_core::schema::InitializeRequest;
+    /// # use agent_client_protocol::UntypedRole;
+    /// # use agent_client_protocol::{Builder};
+    /// # use agent_client_protocol::ByteStreams;
+    /// # use agent_client_protocol::schema::InitializeRequest;
     /// # use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
     /// # use agent_client_protocol_test::*;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// let transport = ByteStreams::new(
     ///     tokio::io::stdout().compat_write(),
     ///     tokio::io::stdin().compat(),
@@ -1135,7 +1135,7 @@ impl<
     ///     .on_receive_request(async |req: MyRequest, responder, cx| {
     ///         // Handle incoming requests in the background
     ///         responder.respond(MyResponse { status: "ok".into() })
-    ///     }, agent_client_protocol_core::on_receive_request!())
+    ///     }, agent_client_protocol::on_receive_request!())
     ///     .connect_with(transport, async |cx| {
     ///         // Initialize the protocol
     ///         let init_response = cx.send_request(InitializeRequest::make())
@@ -1471,7 +1471,7 @@ impl<Counterpart: Role> ConnectionTo<Counterpart> {
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// # let connection = mock_connection();
     /// connection.on_receive_request(async |req: ProcessRequest, responder, cx| {
     ///     // Clone cx for the spawned task
@@ -1486,7 +1486,7 @@ impl<Counterpart: Role> ConnectionTo<Counterpart> {
     ///
     ///     // Respond immediately
     ///     responder.respond(ProcessResponse { result: "started".into() })
-    /// }, agent_client_protocol_core::on_receive_request!())
+    /// }, agent_client_protocol::on_receive_request!())
     /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
     /// # Ok(())
     /// # }
@@ -1522,15 +1522,15 @@ impl<Counterpart: Role> ConnectionTo<Counterpart> {
     /// # Example: Proxying to a backend connection
     ///
     /// ```
-    /// # use agent_client_protocol_core::UntypedRole;
-    /// # use agent_client_protocol_core::{Builder, ConnectionTo};
+    /// # use agent_client_protocol::UntypedRole;
+    /// # use agent_client_protocol::{Builder, ConnectionTo};
     /// # use agent_client_protocol_test::*;
-    /// # async fn example(cx: ConnectionTo<UntypedRole>) -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example(cx: ConnectionTo<UntypedRole>) -> Result<(), agent_client_protocol::Error> {
     /// // Set up a backend connection builder
     /// let backend = UntypedRole.builder()
     ///     .on_receive_request(async |req: MyRequest, responder, _cx| {
     ///         responder.respond(MyResponse { status: "ok".into() })
-    ///     }, agent_client_protocol_core::on_receive_request!());
+    ///     }, agent_client_protocol::on_receive_request!());
     ///
     /// // Spawn it and get a context to send requests to it
     /// let backend_connection = cx.spawn_connection(backend, MockTransport)?;
@@ -1615,7 +1615,7 @@ impl<Counterpart: Role> ConnectionTo<Counterpart> {
     ///
     /// ```compile_fail
     /// # use agent_client_protocol_test::*;
-    /// # async fn example(cx: agent_client_protocol_core::ConnectionTo<agent_client_protocol_core::UntypedRole>) -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example(cx: agent_client_protocol::ConnectionTo<agent_client_protocol::UntypedRole>) -> Result<(), agent_client_protocol::Error> {
     /// // ❌ This doesn't compile - prevents blocking the event loop
     /// let response = cx.send_request(MyRequest {}).await?;
     /// # Ok(())
@@ -1624,7 +1624,7 @@ impl<Counterpart: Role> ConnectionTo<Counterpart> {
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # async fn example(cx: agent_client_protocol_core::ConnectionTo<agent_client_protocol_core::UntypedRole>) -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example(cx: agent_client_protocol::ConnectionTo<agent_client_protocol::UntypedRole>) -> Result<(), agent_client_protocol::Error> {
     /// // ✅ Option 1: Schedule callback (safe in handlers)
     /// cx.send_request(MyRequest {})
     ///     .on_receiving_result(async |result| {
@@ -1735,7 +1735,7 @@ impl<Counterpart: Role> ConnectionTo<Counterpart> {
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # async fn example(cx: agent_client_protocol_core::ConnectionTo<agent_client_protocol_core::Agent>) -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example(cx: agent_client_protocol::ConnectionTo<agent_client_protocol::Agent>) -> Result<(), agent_client_protocol::Error> {
     /// cx.send_notification(StatusUpdate {
     ///     message: "Processing...".into(),
     /// })?;
@@ -1861,7 +1861,7 @@ impl<R: Role> Drop for DynamicHandlerRegistration<R> {
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// connection.on_receive_request(async |req: ProcessRequest, responder, cx| {
 ///     // Send a notification while processing
@@ -1874,7 +1874,7 @@ impl<R: Role> Drop for DynamicHandlerRegistration<R> {
 ///
 ///     // Respond to the request
 ///     responder.respond(ProcessResponse { result })
-/// }, agent_client_protocol_core::on_receive_request!())
+/// }, agent_client_protocol::on_receive_request!())
 /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
 /// # Ok(())
 /// # }
@@ -2201,7 +2201,7 @@ pub trait JsonRpcMessage: 'static + Debug + Sized + Send + Clone {
 /// Use `#[derive(JsonRpcResponse)]` to automatically implement this trait:
 ///
 /// ```ignore
-/// use agent_client_protocol_core::JsonRpcResponse;
+/// use agent_client_protocol::JsonRpcResponse;
 /// use serde::{Serialize, Deserialize};
 ///
 /// #[derive(Debug, Serialize, Deserialize, JsonRpcResponse)]
@@ -2235,7 +2235,7 @@ impl JsonRpcResponse for serde_json::Value {
 /// Use `#[derive(JsonRpcNotification)]` to automatically implement both `JsonRpcMessage` and `JsonRpcNotification`:
 ///
 /// ```ignore
-/// use agent_client_protocol_core::JsonRpcNotification;
+/// use agent_client_protocol::JsonRpcNotification;
 /// use serde::{Serialize, Deserialize};
 ///
 /// #[derive(Debug, Clone, Serialize, Deserialize, JsonRpcNotification)]
@@ -2253,7 +2253,7 @@ pub trait JsonRpcNotification: JsonRpcMessage {}
 /// Use `#[derive(JsonRpcRequest)]` to automatically implement both `JsonRpcMessage` and `JsonRpcRequest`:
 ///
 /// ```ignore
-/// use agent_client_protocol_core::{JsonRpcRequest, JsonRpcResponse};
+/// use agent_client_protocol::{JsonRpcRequest, JsonRpcResponse};
 /// use serde::{Serialize, Deserialize};
 ///
 /// #[derive(Debug, Clone, Serialize, Deserialize, JsonRpcRequest)]
@@ -2700,7 +2700,7 @@ impl JsonRpcNotification for UntypedMessage {}
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # async fn example(cx: agent_client_protocol_core::ConnectionTo<agent_client_protocol_core::UntypedRole>) -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example(cx: agent_client_protocol::ConnectionTo<agent_client_protocol::UntypedRole>) -> Result<(), agent_client_protocol::Error> {
 /// cx.send_request(MyRequest {})
 ///     .on_receiving_result(async |result| {
 ///         match result {
@@ -2725,7 +2725,7 @@ impl JsonRpcNotification for UntypedMessage {}
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # async fn example(cx: agent_client_protocol_core::ConnectionTo<agent_client_protocol_core::UntypedRole>) -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example(cx: agent_client_protocol::ConnectionTo<agent_client_protocol::UntypedRole>) -> Result<(), agent_client_protocol::Error> {
 /// // ✅ Safe: Spawned task runs concurrently
 /// cx.spawn({
 ///     let cx = cx.clone();
@@ -2743,7 +2743,7 @@ impl JsonRpcNotification for UntypedMessage {}
 ///
 /// ```no_run
 /// # use agent_client_protocol_test::*;
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// # let connection = mock_connection();
 /// // ❌ NEVER do this in a handler - blocks the event loop!
 /// connection.on_receive_request(async |req: MyRequest, responder, cx| {
@@ -2751,7 +2751,7 @@ impl JsonRpcNotification for UntypedMessage {}
 ///         .block_task()  // This will deadlock!
 ///         .await?;
 ///     responder.respond(response)
-/// }, agent_client_protocol_core::on_receive_request!())
+/// }, agent_client_protocol::on_receive_request!())
 /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
 /// # Ok(())
 /// # }
@@ -2834,15 +2834,15 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     /// # Example: Proxying requests
     ///
     /// ```
-    /// # use agent_client_protocol_core::UntypedRole;
-    /// # use agent_client_protocol_core::{Builder, ConnectionTo};
+    /// # use agent_client_protocol::UntypedRole;
+    /// # use agent_client_protocol::{Builder, ConnectionTo};
     /// # use agent_client_protocol_test::*;
-    /// # async fn example(cx: ConnectionTo<UntypedRole>) -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example(cx: ConnectionTo<UntypedRole>) -> Result<(), agent_client_protocol::Error> {
     /// // Set up backend connection builder
     /// let backend = UntypedRole.builder()
     ///     .on_receive_request(async |req: MyRequest, responder, cx| {
     ///         responder.respond(MyResponse { status: "ok".into() })
-    ///     }, agent_client_protocol_core::on_receive_request!());
+    ///     }, agent_client_protocol::on_receive_request!());
     ///
     /// // Spawn backend and get a context to send to it
     /// let backend_connection = cx.spawn_connection(backend, MockTransport)?;
@@ -2857,7 +2857,7 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///                 .forward_response_to(responder)?;
     ///             Ok(())
     ///         }
-    ///     }, agent_client_protocol_core::on_receive_request!());
+    ///     }, agent_client_protocol::on_receive_request!());
     /// # Ok(())
     /// # }
     /// ```
@@ -2893,7 +2893,7 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// # let connection = mock_connection();
     /// connection.on_receive_request(async |req: MyRequest, responder, cx| {
     ///     // Spawn a task to handle the request
@@ -2912,7 +2912,7 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///
     ///     // Respond immediately
     ///     responder.respond(MyResponse { status: "ok".into() })
-    /// }, agent_client_protocol_core::on_receive_request!())
+    /// }, agent_client_protocol::on_receive_request!())
     /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
     /// # Ok(())
     /// # }
@@ -2922,7 +2922,7 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// # let connection = mock_connection();
     /// connection.on_receive_request(async |req: MyRequest, responder, cx| {
     ///     // ❌ DEADLOCK: Handler blocks event loop, which can't process the response
@@ -2931,7 +2931,7 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///         .await?;
     ///
     ///     responder.respond(MyResponse { status: response.value })
-    /// }, agent_client_protocol_core::on_receive_request!())
+    /// }, agent_client_protocol::on_receive_request!())
     /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
     /// # Ok(())
     /// # }
@@ -2996,7 +2996,7 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// # let connection = mock_connection();
     /// connection.on_receive_request(async |req: ValidateRequest, responder, cx| {
     ///     // Send initial request
@@ -3007,12 +3007,12 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///                 // Respond to original request
     ///                 responder.respond(ValidateResponse { is_valid: true, error: None })
     ///             } else {
-    ///                 responder.respond_with_error(agent_client_protocol_core::util::internal_error("validation failed"))
+    ///                 responder.respond_with_error(agent_client_protocol::util::internal_error("validation failed"))
     ///             }
     ///         })?;
     ///
     ///     Ok(())
-    /// }, agent_client_protocol_core::on_receive_request!())
+    /// }, agent_client_protocol::on_receive_request!())
     /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
     /// # Ok(())
     /// # }
@@ -3057,7 +3057,7 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///
     /// ```no_run
     /// # use agent_client_protocol_test::*;
-    /// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+    /// # async fn example() -> Result<(), agent_client_protocol::Error> {
     /// # let connection = mock_connection();
     /// connection.on_receive_request(async |req: MyRequest, responder, cx| {
     ///     // Send a request and schedule a callback for the response
@@ -3082,7 +3082,7 @@ impl<T: JsonRpcResponse> SentRequest<T> {
     ///
     ///     // Handler continues immediately without waiting
     ///     responder.respond(MyResponse { status: "processing".into() })
-    /// }, agent_client_protocol_core::on_receive_request!())
+    /// }, agent_client_protocol::on_receive_request!())
     /// # .connect_to(agent_client_protocol_test::MockTransport).await?;
     /// # Ok(())
     /// # }
@@ -3256,18 +3256,18 @@ where
 /// Connecting to an agent via stdio:
 ///
 /// ```no_run
-/// use agent_client_protocol_core::UntypedRole;
-/// # use agent_client_protocol_core::{ByteStreams};
+/// use agent_client_protocol::UntypedRole;
+/// # use agent_client_protocol::{ByteStreams};
 /// use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 ///
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// let component = ByteStreams::new(
 ///     tokio::io::stdout().compat_write(),
 ///     tokio::io::stdin().compat(),
 /// );
 ///
 /// // Use as a component in a connection
-/// agent_client_protocol_core::UntypedRole.builder()
+/// agent_client_protocol::UntypedRole.builder()
 ///     .name("my-client")
 ///     .connect_to(component)
 ///     .await?;
@@ -3342,9 +3342,9 @@ where
 /// # Example
 ///
 /// ```no_run
-/// # use agent_client_protocol_core::UntypedRole;
-/// # use agent_client_protocol_core::{Channel, Builder};
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::UntypedRole;
+/// # use agent_client_protocol::{Channel, Builder};
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// // Create a pair of connected channels
 /// let (channel_a, channel_b) = Channel::duplex();
 ///
diff --git a/src/agent-client-protocol-core/src/jsonrpc/connection.rs b/src/agent-client-protocol/src/jsonrpc/connection.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/jsonrpc/connection.rs
rename to src/agent-client-protocol/src/jsonrpc/connection.rs
diff --git a/src/agent-client-protocol-core/src/jsonrpc/dynamic_handler.rs b/src/agent-client-protocol/src/jsonrpc/dynamic_handler.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/jsonrpc/dynamic_handler.rs
rename to src/agent-client-protocol/src/jsonrpc/dynamic_handler.rs
diff --git a/src/agent-client-protocol-core/src/jsonrpc/handlers.rs b/src/agent-client-protocol/src/jsonrpc/handlers.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/jsonrpc/handlers.rs
rename to src/agent-client-protocol/src/jsonrpc/handlers.rs
diff --git a/src/agent-client-protocol-core/src/jsonrpc/incoming_actor.rs b/src/agent-client-protocol/src/jsonrpc/incoming_actor.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/jsonrpc/incoming_actor.rs
rename to src/agent-client-protocol/src/jsonrpc/incoming_actor.rs
diff --git a/src/agent-client-protocol-core/src/jsonrpc/outgoing_actor.rs b/src/agent-client-protocol/src/jsonrpc/outgoing_actor.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/jsonrpc/outgoing_actor.rs
rename to src/agent-client-protocol/src/jsonrpc/outgoing_actor.rs
diff --git a/src/agent-client-protocol-core/src/jsonrpc/run.rs b/src/agent-client-protocol/src/jsonrpc/run.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/jsonrpc/run.rs
rename to src/agent-client-protocol/src/jsonrpc/run.rs
diff --git a/src/agent-client-protocol-core/src/jsonrpc/task_actor.rs b/src/agent-client-protocol/src/jsonrpc/task_actor.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/jsonrpc/task_actor.rs
rename to src/agent-client-protocol/src/jsonrpc/task_actor.rs
diff --git a/src/agent-client-protocol-core/src/jsonrpc/transport_actor.rs b/src/agent-client-protocol/src/jsonrpc/transport_actor.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/jsonrpc/transport_actor.rs
rename to src/agent-client-protocol/src/jsonrpc/transport_actor.rs
diff --git a/src/agent-client-protocol/src/lib.rs b/src/agent-client-protocol/src/lib.rs
index 010515a..91254ed 100644
--- a/src/agent-client-protocol/src/lib.rs
+++ b/src/agent-client-protocol/src/lib.rs
@@ -1,723 +1,210 @@
-use futures::{AsyncRead, AsyncWrite, future::LocalBoxFuture};
-use rpc::RpcConnection;
-
-mod agent;
-mod client;
-mod rpc;
-#[cfg(test)]
-mod rpc_tests;
-mod stream_broadcast;
-
-pub use agent::*;
-pub use agent_client_protocol_schema::*;
-pub use client::*;
-pub use rpc::*;
-pub use stream_broadcast::{
-    StreamMessage, StreamMessageContent, StreamMessageDirection, StreamReceiver,
-};
-
-// Client to Agent
-
-/// A client-side connection to an agent.
+#![deny(missing_docs)]
+
+//! # agent-client-protocol -- the Symposium Agent Client Protocol (ACP) SDK
+//!
+//! **agent-client-protocol** is a Rust SDK for building [Agent-Client Protocol (ACP)][acp] applications.
+//! ACP is a protocol for communication between AI agents and their clients (IDEs, CLIs, etc.),
+//! enabling features like tool use, permission requests, and streaming responses.
+//!
+//! [acp]: https://agentclientprotocol.com/
+//!
+//! ## What can you build with agent-client-protocol?
+//!
+//! - **Clients** that talk to ACP agents (like building your own Claude Code interface)
+//! - **Proxies** that add capabilities to existing agents (like adding custom tools via MCP)
+//! - **Agents** that respond to prompts with AI-powered responses
+//!
+//! ## Quick Start: Connecting to an Agent
+//!
+//! The most common use case is connecting to an existing ACP agent as a client.
+//! Here's a minimal example that initializes a connection, creates a session,
+//! and sends a prompt:
+//!
+//! ```no_run
+//! use agent_client_protocol::Client;
+//! use agent_client_protocol::schema::{InitializeRequest, ProtocolVersion};
+//!
+//! # async fn run(transport: impl agent_client_protocol::ConnectTo<agent_client_protocol::Client>) -> agent_client_protocol::Result<()> {
+//! Client.builder()
+//!     .name("my-client")
+//!     .connect_with(transport, async |cx| {
+//!         // Step 1: Initialize the connection
+//!         cx.send_request(InitializeRequest::new(ProtocolVersion::V1))
+//!             .block_task().await?;
+//!
+//!         // Step 2: Create a session and send a prompt
+//!         cx.build_session_cwd()?
+//!             .block_task()
+//!             .run_until(async |mut session| {
+//!                 session.send_prompt("What is 2 + 2?")?;
+//!                 let response = session.read_to_string().await?;
+//!                 println!("{}", response);
+//!                 Ok(())
+//!             })
+//!             .await
+//!     })
+//!     .await
+//! # }
+//! ```
+//!
+//! For a complete working example, see [`yolo_one_shot_client.rs`][yolo].
+//!
+//! [yolo]: https://github.com/agentclientprotocol/rust-sdk/blob/main/src/agent-client-protocol/examples/yolo_one_shot_client.rs
+//!
+//! ## Cookbook
+//!
+//! The [`agent_client_protocol_cookbook`] crate contains practical guides and examples:
+//!
+//! - Connecting as a client
+//! - Global MCP server
+//! - Per-session MCP server with workspace context
+//! - Building agents and reusable components
+//! - Running proxies with the conductor
+//!
+//! [`agent_client_protocol_cookbook`]: https://docs.rs/agent-client-protocol-cookbook
+//!
+//! ## Core Concepts
+//!
+//! The [`concepts`] module provides detailed explanations of how agent-client-protocol works,
+//! including connections, sessions, callbacks, ordering guarantees, and more.
+//!
+//! ## Related Crates
+//!
+//! - [`agent-client-protocol-tokio`] - Tokio utilities for spawning agent processes
+//! - [`agent-client-protocol-conductor`] - Binary for running proxy chains
+//!
+//! [`agent-client-protocol-tokio`]: https://crates.io/crates/agent-client-protocol-tokio
+//! [`agent-client-protocol-conductor`]: https://crates.io/crates/agent-client-protocol-conductor
+
+/// Capability management for the `_meta.symposium` object
+mod capabilities;
+/// Component abstraction for agents and proxies
+pub mod component;
+/// Core concepts for understanding and using agent-client-protocol
+pub mod concepts;
+/// Cookbook of common patterns for building ACP components
+pub mod cookbook;
+/// JSON-RPC handler types for building custom message handlers
+pub mod handler;
+/// JSON-RPC connection and handler infrastructure
+mod jsonrpc;
+/// MCP server support for providing MCP tools over ACP
+pub mod mcp_server;
+/// Role types for ACP connections
+pub mod role;
+/// ACP protocol schema types - all message types, requests, responses, and supporting types
+pub mod schema;
+/// Utility functions and types
+pub mod util;
+
+pub use capabilities::*;
+
+/// JSON-RPC message types.
 ///
-/// This struct provides the client's view of an ACP connection, allowing
-/// clients (such as code editors) to communicate with agents. It implements
-/// the [`Agent`] trait to provide methods for initializing sessions, sending
-/// prompts, and managing the agent lifecycle.
+/// This module re-exports types from the `jsonrpcmsg` crate that are transitively
+/// reachable through the public API (e.g., via [`Channel`]).
 ///
-/// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
-#[derive(Debug)]
-pub struct ClientSideConnection {
-    conn: RpcConnection<ClientSide, AgentSide>,
+/// Users of the `agent-client-protocol` crate can use these types without adding a direct dependency
+/// on `jsonrpcmsg`.
+pub mod jsonrpcmsg {
+    pub use jsonrpcmsg::{Error, Id, Message, Params, Request, Response};
 }
 
-impl ClientSideConnection {
-    /// Creates a new client-side connection to an agent.
-    ///
-    /// This establishes the communication channel between a client and agent
-    /// following the ACP specification.
-    ///
-    /// # Arguments
-    ///
-    /// * `client` - A handler that implements the [`Client`] trait to process incoming agent requests
-    /// * `outgoing_bytes` - The stream for sending data to the agent (typically stdout)
-    /// * `incoming_bytes` - The stream for receiving data from the agent (typically stdin)
-    /// * `spawn` - A function to spawn async tasks (e.g., `tokio::spawn`)
-    ///
-    /// # Returns
-    ///
-    /// Returns a tuple containing:
-    /// - The connection instance for making requests to the agent
-    /// - An I/O future that must be spawned to handle the underlying communication
-    ///
-    /// See protocol docs: [Communication Model](https://agentclientprotocol.com/protocol/overview#communication-model)
-    pub fn new(
-        client: impl MessageHandler<ClientSide> + 'static,
-        outgoing_bytes: impl Unpin + AsyncWrite,
-        incoming_bytes: impl Unpin + AsyncRead,
-        spawn: impl Fn(LocalBoxFuture<'static, ()>) + 'static,
-    ) -> (Self, impl Future<Output = Result<()>>) {
-        let (conn, io_task) = RpcConnection::new(client, outgoing_bytes, incoming_bytes, spawn);
-        (Self { conn }, io_task)
-    }
-
-    /// Subscribe to receive stream updates from the agent.
-    ///
-    /// This allows the client to receive real-time notifications about
-    /// agent activities, such as tool calls, content updates, and progress reports.
-    ///
-    /// # Returns
-    ///
-    /// A [`StreamReceiver`] that can be used to receive stream messages.
-    pub fn subscribe(&self) -> StreamReceiver {
-        self.conn.subscribe()
-    }
-}
-
-#[async_trait::async_trait(?Send)]
-impl Agent for ClientSideConnection {
-    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.initialize,
-                Some(ClientRequest::InitializeRequest(args)),
-            )?
-            .await
-    }
-
-    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse> {
-        self.conn
-            .request::<Option<_>>(
-                AGENT_METHOD_NAMES.authenticate,
-                Some(ClientRequest::AuthenticateRequest(args)),
-            )?
-            .await
-            .map(Option::unwrap_or_default)
-    }
-
-    #[cfg(feature = "unstable_logout")]
-    async fn logout(&self, args: LogoutRequest) -> Result<LogoutResponse> {
-        self.conn
-            .request::<Option<_>>(
-                AGENT_METHOD_NAMES.logout,
-                Some(ClientRequest::LogoutRequest(args)),
-            )?
-            .await
-            .map(Option::unwrap_or_default)
-    }
-
-    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.session_new,
-                Some(ClientRequest::NewSessionRequest(args)),
-            )?
-            .await
-    }
-
-    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse> {
-        self.conn
-            .request::<Option<_>>(
-                AGENT_METHOD_NAMES.session_load,
-                Some(ClientRequest::LoadSessionRequest(args)),
-            )?
-            .await
-            .map(Option::unwrap_or_default)
-    }
-
-    async fn set_session_mode(
-        &self,
-        args: SetSessionModeRequest,
-    ) -> Result<SetSessionModeResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.session_set_mode,
-                Some(ClientRequest::SetSessionModeRequest(args)),
-            )?
-            .await
-    }
-
-    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.session_prompt,
-                Some(ClientRequest::PromptRequest(args)),
-            )?
-            .await
-    }
-
-    async fn cancel(&self, args: CancelNotification) -> Result<()> {
-        self.conn.notify(
-            AGENT_METHOD_NAMES.session_cancel,
-            Some(ClientNotification::CancelNotification(args)),
-        )
-    }
-
-    #[cfg(feature = "unstable_session_model")]
-    async fn set_session_model(
-        &self,
-        args: SetSessionModelRequest,
-    ) -> Result<SetSessionModelResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.session_set_model,
-                Some(ClientRequest::SetSessionModelRequest(args)),
-            )?
-            .await
-    }
+pub use jsonrpc::{
+    Builder, ByteStreams, Channel, ConnectionTo, Dispatch, HandleDispatchFrom, Handled,
+    IntoHandled, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, Lines,
+    NullHandler, Responder, ResponseRouter, SentRequest, UntypedMessage,
+    run::{ChainRun, NullRun, RunWithConnectionTo},
+};
 
-    async fn list_sessions(&self, args: ListSessionsRequest) -> Result<ListSessionsResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.session_list,
-                Some(ClientRequest::ListSessionsRequest(args)),
-            )?
-            .await
-    }
+pub use role::{
+    Role, RoleId, UntypedRole,
+    acp::{Agent, Client, Conductor, Proxy},
+};
 
-    #[cfg(feature = "unstable_session_fork")]
-    async fn fork_session(&self, args: ForkSessionRequest) -> Result<ForkSessionResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.session_fork,
-                Some(ClientRequest::ForkSessionRequest(args)),
-            )?
-            .await
-    }
+pub use component::{ConnectTo, DynConnectTo};
 
-    #[cfg(feature = "unstable_session_resume")]
-    async fn resume_session(&self, args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.session_resume,
-                Some(ClientRequest::ResumeSessionRequest(args)),
-            )?
-            .await
-    }
+// Re-export BoxFuture for implementing Component traits
+pub use futures::future::BoxFuture;
 
-    #[cfg(feature = "unstable_session_close")]
-    async fn close_session(&self, args: CloseSessionRequest) -> Result<CloseSessionResponse> {
-        self.conn
-            .request::<Option<_>>(
-                AGENT_METHOD_NAMES.session_close,
-                Some(ClientRequest::CloseSessionRequest(args)),
-            )?
-            .await
-            .map(Option::unwrap_or_default)
-    }
+// Re-export the six primary message enum types at the root
+pub use schema::{
+    AgentNotification, AgentRequest, AgentResponse, ClientNotification, ClientRequest,
+    ClientResponse,
+};
 
-    async fn set_session_config_option(
-        &self,
-        args: SetSessionConfigOptionRequest,
-    ) -> Result<SetSessionConfigOptionResponse> {
-        self.conn
-            .request(
-                AGENT_METHOD_NAMES.session_set_config_option,
-                Some(ClientRequest::SetSessionConfigOptionRequest(args)),
-            )?
-            .await
-    }
+// Re-export commonly used infrastructure types for convenience
+pub use schema::{Error, ErrorCode, Result};
 
-    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
-        self.conn
-            .request(
-                format!("_{}", args.method),
-                Some(ClientRequest::ExtMethodRequest(args)),
-            )?
-            .await
-    }
+// Re-export derive macros for custom JSON-RPC types
+pub use agent_client_protocol_derive::{JsonRpcNotification, JsonRpcRequest, JsonRpcResponse};
 
-    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
-        self.conn.notify(
-            format!("_{}", args.method),
-            Some(ClientNotification::ExtNotification(args)),
-        )
-    }
-}
+mod session;
+pub use session::*;
 
-/// Marker type representing the client side of an ACP connection.
+/// This is a hack that must be given as the final argument of
+/// [`McpServerBuilder::tool_fn`](`crate::mcp_server::McpServerBuilder::tool_fn`) when defining tools.
+/// Look away, lest ye be blinded by its vileness!
 ///
-/// This type is used by the RPC layer to determine which messages
-/// are incoming vs outgoing from the client's perspective.
-///
-/// See protocol docs: [Communication Model](https://agentclientprotocol.com/protocol/overview#communication-model)
-#[derive(Clone, Debug)]
-pub struct ClientSide;
-
-impl Side for ClientSide {
-    type InNotification = AgentNotification;
-    type InRequest = AgentRequest;
-    type OutResponse = ClientResponse;
-
-    fn decode_request(method: &str, params: Option<&RawValue>) -> Result<AgentRequest> {
-        let params = params.ok_or_else(Error::invalid_params)?;
-
-        match method {
-            m if m == CLIENT_METHOD_NAMES.session_request_permission => {
-                serde_json::from_str(params.get())
-                    .map(AgentRequest::RequestPermissionRequest)
-                    .map_err(Into::into)
-            }
-            m if m == CLIENT_METHOD_NAMES.fs_write_text_file => serde_json::from_str(params.get())
-                .map(AgentRequest::WriteTextFileRequest)
-                .map_err(Into::into),
-            m if m == CLIENT_METHOD_NAMES.fs_read_text_file => serde_json::from_str(params.get())
-                .map(AgentRequest::ReadTextFileRequest)
-                .map_err(Into::into),
-            m if m == CLIENT_METHOD_NAMES.terminal_create => serde_json::from_str(params.get())
-                .map(AgentRequest::CreateTerminalRequest)
-                .map_err(Into::into),
-            m if m == CLIENT_METHOD_NAMES.terminal_output => serde_json::from_str(params.get())
-                .map(AgentRequest::TerminalOutputRequest)
-                .map_err(Into::into),
-            m if m == CLIENT_METHOD_NAMES.terminal_kill => serde_json::from_str(params.get())
-                .map(AgentRequest::KillTerminalRequest)
-                .map_err(Into::into),
-            m if m == CLIENT_METHOD_NAMES.terminal_release => serde_json::from_str(params.get())
-                .map(AgentRequest::ReleaseTerminalRequest)
-                .map_err(Into::into),
-            m if m == CLIENT_METHOD_NAMES.terminal_wait_for_exit => {
-                serde_json::from_str(params.get())
-                    .map(AgentRequest::WaitForTerminalExitRequest)
-                    .map_err(Into::into)
-            }
-            _ => {
-                if let Some(custom_method) = method.strip_prefix('_') {
-                    Ok(AgentRequest::ExtMethodRequest(ExtRequest::new(
-                        custom_method,
-                        params.to_owned().into(),
-                    )))
-                } else {
-                    Err(Error::method_not_found())
-                }
-            }
-        }
-    }
-
-    fn decode_notification(method: &str, params: Option<&RawValue>) -> Result<AgentNotification> {
-        let params = params.ok_or_else(Error::invalid_params)?;
-
-        match method {
-            m if m == CLIENT_METHOD_NAMES.session_update => serde_json::from_str(params.get())
-                .map(AgentNotification::SessionNotification)
-                .map_err(Into::into),
-            _ => {
-                if let Some(custom_method) = method.strip_prefix('_') {
-                    Ok(AgentNotification::ExtNotification(ExtNotification::new(
-                        custom_method,
-                        RawValue::from_string(params.get().to_string())?.into(),
-                    )))
-                } else {
-                    Err(Error::method_not_found())
-                }
-            }
-        }
-    }
+/// Fine, if you MUST know, it's a horrific workaround for not having
+/// [return-type notation](https://github.com/rust-lang/rust/issues/109417)
+/// and for [this !@$#!%! bug](https://github.com/rust-lang/rust/issues/110338).
+/// Trust me, the need for it hurts me more than it hurts you. --nikomatsakis
+#[macro_export]
+macro_rules! tool_fn_mut {
+    () => {
+        |func, params, context| Box::pin(func(params, context))
+    };
 }
 
-impl<T: Client> MessageHandler<ClientSide> for T {
-    async fn handle_request(&self, request: AgentRequest) -> Result<ClientResponse> {
-        match request {
-            AgentRequest::RequestPermissionRequest(args) => {
-                let response = self.request_permission(args).await?;
-                Ok(ClientResponse::RequestPermissionResponse(response))
-            }
-            AgentRequest::WriteTextFileRequest(args) => {
-                let response = self.write_text_file(args).await?;
-                Ok(ClientResponse::WriteTextFileResponse(response))
-            }
-            AgentRequest::ReadTextFileRequest(args) => {
-                let response = self.read_text_file(args).await?;
-                Ok(ClientResponse::ReadTextFileResponse(response))
-            }
-            AgentRequest::CreateTerminalRequest(args) => {
-                let response = self.create_terminal(args).await?;
-                Ok(ClientResponse::CreateTerminalResponse(response))
-            }
-            AgentRequest::TerminalOutputRequest(args) => {
-                let response = self.terminal_output(args).await?;
-                Ok(ClientResponse::TerminalOutputResponse(response))
-            }
-            AgentRequest::ReleaseTerminalRequest(args) => {
-                let response = self.release_terminal(args).await?;
-                Ok(ClientResponse::ReleaseTerminalResponse(response))
-            }
-            AgentRequest::WaitForTerminalExitRequest(args) => {
-                let response = self.wait_for_terminal_exit(args).await?;
-                Ok(ClientResponse::WaitForTerminalExitResponse(response))
-            }
-            AgentRequest::KillTerminalRequest(args) => {
-                let response = self.kill_terminal(args).await?;
-                Ok(ClientResponse::KillTerminalResponse(response))
-            }
-            AgentRequest::ExtMethodRequest(args) => {
-                let response = self.ext_method(args).await?;
-                Ok(ClientResponse::ExtMethodResponse(response))
-            }
-            _ => Err(Error::method_not_found()),
-        }
-    }
-
-    async fn handle_notification(&self, notification: AgentNotification) -> Result<()> {
-        match notification {
-            AgentNotification::SessionNotification(args) => {
-                self.session_notification(args).await?;
-            }
-            AgentNotification::ExtNotification(args) => {
-                self.ext_notification(args).await?;
-            }
-            // Ignore unknown notifications
-            _ => {}
-        }
-        Ok(())
-    }
+/// This is a hack that must be given as the final argument of
+/// [`McpServerBuilder::tool_fn`](`crate::mcp_server::McpServerBuilder::tool_fn`) when defining stateless concurrent tools.
+/// See [`tool_fn_mut!`] for the gory details.
+#[macro_export]
+macro_rules! tool_fn {
+    () => {
+        |func, params, context| Box::pin(func(params, context))
+    };
 }
 
-// Agent to Client
-
-/// An agent-side connection to a client.
+/// This macro is used for the value of the `to_future_hack` parameter of
+/// [`Builder::on_receive_request`] and [`Builder::on_receive_request_from`].
 ///
-/// This struct provides the agent's view of an ACP connection, allowing
-/// agents to communicate with clients. It implements the [`Client`] trait
-/// to provide methods for requesting permissions, accessing the file system,
-/// and sending session updates.
+/// It expands to `|f, req, responder, cx| Box::pin(f(req, responder, cx))`.
 ///
-/// See protocol docs: [Agent](https://agentclientprotocol.com/protocol/overview#agent)
-#[derive(Debug)]
-pub struct AgentSideConnection {
-    conn: RpcConnection<AgentSide, ClientSide>,
+/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
+/// is stabilized.
+#[macro_export]
+macro_rules! on_receive_request {
+    () => {
+        |f: &mut _, req, responder, cx| Box::pin(f(req, responder, cx))
+    };
 }
 
-impl AgentSideConnection {
-    /// Creates a new agent-side connection to a client.
-    ///
-    /// This establishes the communication channel from the agent's perspective
-    /// following the ACP specification.
-    ///
-    /// # Arguments
-    ///
-    /// * `agent` - A handler that implements the [`Agent`] trait to process incoming client requests
-    /// * `outgoing_bytes` - The stream for sending data to the client (typically stdout)
-    /// * `incoming_bytes` - The stream for receiving data from the client (typically stdin)
-    /// * `spawn` - A function to spawn async tasks (e.g., `tokio::spawn`)
-    ///
-    /// # Returns
-    ///
-    /// Returns a tuple containing:
-    /// - The connection instance for making requests to the client
-    /// - An I/O future that must be spawned to handle the underlying communication
-    ///
-    /// See protocol docs: [Communication Model](https://agentclientprotocol.com/protocol/overview#communication-model)
-    pub fn new(
-        agent: impl MessageHandler<AgentSide> + 'static,
-        outgoing_bytes: impl Unpin + AsyncWrite,
-        incoming_bytes: impl Unpin + AsyncRead,
-        spawn: impl Fn(LocalBoxFuture<'static, ()>) + 'static,
-    ) -> (Self, impl Future<Output = Result<()>>) {
-        let (conn, io_task) = RpcConnection::new(agent, outgoing_bytes, incoming_bytes, spawn);
-        (Self { conn }, io_task)
-    }
-
-    /// Subscribe to receive stream updates from the client.
-    ///
-    /// This allows the agent to receive real-time notifications about
-    /// client activities and cancellation requests.
-    ///
-    /// # Returns
-    ///
-    /// A [`StreamReceiver`] that can be used to receive stream messages.
-    pub fn subscribe(&self) -> StreamReceiver {
-        self.conn.subscribe()
-    }
-}
-
-#[async_trait::async_trait(?Send)]
-impl Client for AgentSideConnection {
-    async fn request_permission(
-        &self,
-        args: RequestPermissionRequest,
-    ) -> Result<RequestPermissionResponse> {
-        self.conn
-            .request(
-                CLIENT_METHOD_NAMES.session_request_permission,
-                Some(AgentRequest::RequestPermissionRequest(args)),
-            )?
-            .await
-    }
-
-    async fn write_text_file(&self, args: WriteTextFileRequest) -> Result<WriteTextFileResponse> {
-        self.conn
-            .request::<Option<_>>(
-                CLIENT_METHOD_NAMES.fs_write_text_file,
-                Some(AgentRequest::WriteTextFileRequest(args)),
-            )?
-            .await
-            .map(Option::unwrap_or_default)
-    }
-
-    async fn read_text_file(&self, args: ReadTextFileRequest) -> Result<ReadTextFileResponse> {
-        self.conn
-            .request(
-                CLIENT_METHOD_NAMES.fs_read_text_file,
-                Some(AgentRequest::ReadTextFileRequest(args)),
-            )?
-            .await
-    }
-
-    async fn create_terminal(&self, args: CreateTerminalRequest) -> Result<CreateTerminalResponse> {
-        self.conn
-            .request(
-                CLIENT_METHOD_NAMES.terminal_create,
-                Some(AgentRequest::CreateTerminalRequest(args)),
-            )?
-            .await
-    }
-
-    async fn terminal_output(&self, args: TerminalOutputRequest) -> Result<TerminalOutputResponse> {
-        self.conn
-            .request(
-                CLIENT_METHOD_NAMES.terminal_output,
-                Some(AgentRequest::TerminalOutputRequest(args)),
-            )?
-            .await
-    }
-
-    async fn release_terminal(
-        &self,
-        args: ReleaseTerminalRequest,
-    ) -> Result<ReleaseTerminalResponse> {
-        self.conn
-            .request::<Option<_>>(
-                CLIENT_METHOD_NAMES.terminal_release,
-                Some(AgentRequest::ReleaseTerminalRequest(args)),
-            )?
-            .await
-            .map(Option::unwrap_or_default)
-    }
-
-    async fn wait_for_terminal_exit(
-        &self,
-        args: WaitForTerminalExitRequest,
-    ) -> Result<WaitForTerminalExitResponse> {
-        self.conn
-            .request(
-                CLIENT_METHOD_NAMES.terminal_wait_for_exit,
-                Some(AgentRequest::WaitForTerminalExitRequest(args)),
-            )?
-            .await
-    }
-
-    async fn kill_terminal(&self, args: KillTerminalRequest) -> Result<KillTerminalResponse> {
-        self.conn
-            .request::<Option<_>>(
-                CLIENT_METHOD_NAMES.terminal_kill,
-                Some(AgentRequest::KillTerminalRequest(args)),
-            )?
-            .await
-            .map(Option::unwrap_or_default)
-    }
-
-    async fn session_notification(&self, args: SessionNotification) -> Result<()> {
-        self.conn.notify(
-            CLIENT_METHOD_NAMES.session_update,
-            Some(AgentNotification::SessionNotification(args)),
-        )
-    }
-
-    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
-        self.conn
-            .request(
-                format!("_{}", args.method),
-                Some(AgentRequest::ExtMethodRequest(args)),
-            )?
-            .await
-    }
-
-    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
-        self.conn.notify(
-            format!("_{}", args.method),
-            Some(AgentNotification::ExtNotification(args)),
-        )
-    }
-}
-
-/// Marker type representing the agent side of an ACP connection.
+/// This macro is used for the value of the `to_future_hack` parameter of
+/// [`Builder::on_receive_notification`] and [`Builder::on_receive_notification_from`].
 ///
-/// This type is used by the RPC layer to determine which messages
-/// are incoming vs outgoing from the agent's perspective.
+/// It expands to `|f, notif, cx| Box::pin(f(notif, cx))`.
 ///
-/// See protocol docs: [Communication Model](https://agentclientprotocol.com/protocol/overview#communication-model)
-#[derive(Clone, Debug)]
-pub struct AgentSide;
-
-impl Side for AgentSide {
-    type InRequest = ClientRequest;
-    type InNotification = ClientNotification;
-    type OutResponse = AgentResponse;
-
-    fn decode_request(method: &str, params: Option<&RawValue>) -> Result<ClientRequest> {
-        let params = params.ok_or_else(Error::invalid_params)?;
-
-        match method {
-            m if m == AGENT_METHOD_NAMES.initialize => serde_json::from_str(params.get())
-                .map(ClientRequest::InitializeRequest)
-                .map_err(Into::into),
-            m if m == AGENT_METHOD_NAMES.authenticate => serde_json::from_str(params.get())
-                .map(ClientRequest::AuthenticateRequest)
-                .map_err(Into::into),
-            #[cfg(feature = "unstable_logout")]
-            m if m == AGENT_METHOD_NAMES.logout => serde_json::from_str(params.get())
-                .map(ClientRequest::LogoutRequest)
-                .map_err(Into::into),
-            m if m == AGENT_METHOD_NAMES.session_new => serde_json::from_str(params.get())
-                .map(ClientRequest::NewSessionRequest)
-                .map_err(Into::into),
-            m if m == AGENT_METHOD_NAMES.session_load => serde_json::from_str(params.get())
-                .map(ClientRequest::LoadSessionRequest)
-                .map_err(Into::into),
-            m if m == AGENT_METHOD_NAMES.session_set_mode => serde_json::from_str(params.get())
-                .map(ClientRequest::SetSessionModeRequest)
-                .map_err(Into::into),
-            #[cfg(feature = "unstable_session_model")]
-            m if m == AGENT_METHOD_NAMES.session_set_model => serde_json::from_str(params.get())
-                .map(ClientRequest::SetSessionModelRequest)
-                .map_err(Into::into),
-            m if m == AGENT_METHOD_NAMES.session_list => serde_json::from_str(params.get())
-                .map(ClientRequest::ListSessionsRequest)
-                .map_err(Into::into),
-            #[cfg(feature = "unstable_session_fork")]
-            m if m == AGENT_METHOD_NAMES.session_fork => serde_json::from_str(params.get())
-                .map(ClientRequest::ForkSessionRequest)
-                .map_err(Into::into),
-            #[cfg(feature = "unstable_session_resume")]
-            m if m == AGENT_METHOD_NAMES.session_resume => serde_json::from_str(params.get())
-                .map(ClientRequest::ResumeSessionRequest)
-                .map_err(Into::into),
-            #[cfg(feature = "unstable_session_close")]
-            m if m == AGENT_METHOD_NAMES.session_close => serde_json::from_str(params.get())
-                .map(ClientRequest::CloseSessionRequest)
-                .map_err(Into::into),
-            m if m == AGENT_METHOD_NAMES.session_set_config_option => {
-                serde_json::from_str(params.get())
-                    .map(ClientRequest::SetSessionConfigOptionRequest)
-                    .map_err(Into::into)
-            }
-            m if m == AGENT_METHOD_NAMES.session_prompt => serde_json::from_str(params.get())
-                .map(ClientRequest::PromptRequest)
-                .map_err(Into::into),
-            _ => {
-                if let Some(custom_method) = method.strip_prefix('_') {
-                    Ok(ClientRequest::ExtMethodRequest(ExtRequest::new(
-                        custom_method,
-                        params.to_owned().into(),
-                    )))
-                } else {
-                    Err(Error::method_not_found())
-                }
-            }
-        }
-    }
-
-    fn decode_notification(method: &str, params: Option<&RawValue>) -> Result<ClientNotification> {
-        let params = params.ok_or_else(Error::invalid_params)?;
-
-        match method {
-            m if m == AGENT_METHOD_NAMES.session_cancel => serde_json::from_str(params.get())
-                .map(ClientNotification::CancelNotification)
-                .map_err(Into::into),
-            _ => {
-                if let Some(custom_method) = method.strip_prefix('_') {
-                    Ok(ClientNotification::ExtNotification(ExtNotification::new(
-                        custom_method,
-                        RawValue::from_string(params.get().to_string())?.into(),
-                    )))
-                } else {
-                    Err(Error::method_not_found())
-                }
-            }
-        }
-    }
+/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
+/// is stabilized.
+#[macro_export]
+macro_rules! on_receive_notification {
+    () => {
+        |f: &mut _, notif, cx| Box::pin(f(notif, cx))
+    };
 }
 
-impl<T: Agent> MessageHandler<AgentSide> for T {
-    async fn handle_request(&self, request: ClientRequest) -> Result<AgentResponse> {
-        match request {
-            ClientRequest::InitializeRequest(args) => {
-                let response = self.initialize(args).await?;
-                Ok(AgentResponse::InitializeResponse(response))
-            }
-            ClientRequest::AuthenticateRequest(args) => {
-                let response = self.authenticate(args).await?;
-                Ok(AgentResponse::AuthenticateResponse(response))
-            }
-            #[cfg(feature = "unstable_logout")]
-            ClientRequest::LogoutRequest(args) => {
-                let response = self.logout(args).await?;
-                Ok(AgentResponse::LogoutResponse(response))
-            }
-            ClientRequest::NewSessionRequest(args) => {
-                let response = self.new_session(args).await?;
-                Ok(AgentResponse::NewSessionResponse(response))
-            }
-            ClientRequest::LoadSessionRequest(args) => {
-                let response = self.load_session(args).await?;
-                Ok(AgentResponse::LoadSessionResponse(response))
-            }
-            ClientRequest::PromptRequest(args) => {
-                let response = self.prompt(args).await?;
-                Ok(AgentResponse::PromptResponse(response))
-            }
-            ClientRequest::SetSessionModeRequest(args) => {
-                let response = self.set_session_mode(args).await?;
-                Ok(AgentResponse::SetSessionModeResponse(response))
-            }
-            #[cfg(feature = "unstable_session_model")]
-            ClientRequest::SetSessionModelRequest(args) => {
-                let response = self.set_session_model(args).await?;
-                Ok(AgentResponse::SetSessionModelResponse(response))
-            }
-            ClientRequest::ListSessionsRequest(args) => {
-                let response = self.list_sessions(args).await?;
-                Ok(AgentResponse::ListSessionsResponse(response))
-            }
-            #[cfg(feature = "unstable_session_fork")]
-            ClientRequest::ForkSessionRequest(args) => {
-                let response = self.fork_session(args).await?;
-                Ok(AgentResponse::ForkSessionResponse(response))
-            }
-            #[cfg(feature = "unstable_session_resume")]
-            ClientRequest::ResumeSessionRequest(args) => {
-                let response = self.resume_session(args).await?;
-                Ok(AgentResponse::ResumeSessionResponse(response))
-            }
-            #[cfg(feature = "unstable_session_close")]
-            ClientRequest::CloseSessionRequest(args) => {
-                let response = self.close_session(args).await?;
-                Ok(AgentResponse::CloseSessionResponse(response))
-            }
-            ClientRequest::SetSessionConfigOptionRequest(args) => {
-                let response = self.set_session_config_option(args).await?;
-                Ok(AgentResponse::SetSessionConfigOptionResponse(response))
-            }
-            ClientRequest::ExtMethodRequest(args) => {
-                let response = self.ext_method(args).await?;
-                Ok(AgentResponse::ExtMethodResponse(response))
-            }
-            _ => Err(Error::method_not_found()),
-        }
-    }
-
-    async fn handle_notification(&self, notification: ClientNotification) -> Result<()> {
-        match notification {
-            ClientNotification::CancelNotification(args) => {
-                self.cancel(args).await?;
-            }
-            ClientNotification::ExtNotification(args) => {
-                self.ext_notification(args).await?;
-            }
-            // Ignore unknown notifications
-            _ => {}
-        }
-        Ok(())
-    }
+/// This macro is used for the value of the `to_future_hack` parameter of
+/// [`Builder::on_receive_dispatch`] and [`Builder::on_receive_dispatch_from`].
+///
+/// It expands to `|f, dispatch, cx| Box::pin(f(dispatch, cx))`.
+///
+/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
+/// is stabilized.
+#[macro_export]
+macro_rules! on_receive_dispatch {
+    () => {
+        |f: &mut _, dispatch, cx| Box::pin(f(dispatch, cx))
+    };
 }
diff --git a/src/agent-client-protocol-core/src/mcp_server/active_session.rs b/src/agent-client-protocol/src/mcp_server/active_session.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/mcp_server/active_session.rs
rename to src/agent-client-protocol/src/mcp_server/active_session.rs
diff --git a/src/agent-client-protocol-core/src/mcp_server/builder.rs b/src/agent-client-protocol/src/mcp_server/builder.rs
similarity index 99%
rename from src/agent-client-protocol-core/src/mcp_server/builder.rs
rename to src/agent-client-protocol/src/mcp_server/builder.rs
index 6bd9891..368df5b 100644
--- a/src/agent-client-protocol-core/src/mcp_server/builder.rs
+++ b/src/agent-client-protocol/src/mcp_server/builder.rs
@@ -73,7 +73,7 @@ use crate::{
 ///         "greet",
 ///         "Greet someone by name",
 ///         async |input: GreetInput, _cx| Ok(format!("Hello, {}!", input.name)),
-///         agent_client_protocol_core::tool_fn!(),
+///         agent_client_protocol::tool_fn!(),
 ///     )
 ///     .build();
 /// ```
diff --git a/src/agent-client-protocol-core/src/mcp_server/connect.rs b/src/agent-client-protocol/src/mcp_server/connect.rs
similarity index 93%
rename from src/agent-client-protocol-core/src/mcp_server/connect.rs
rename to src/agent-client-protocol/src/mcp_server/connect.rs
index 7fa614b..7d625ec 100644
--- a/src/agent-client-protocol-core/src/mcp_server/connect.rs
+++ b/src/agent-client-protocol/src/mcp_server/connect.rs
@@ -15,8 +15,8 @@ use crate::{
 /// # Example
 ///
 /// ```rust,ignore
-/// use agent_client_protocol_core::mcp_server::{McpServerConnect, McpConnectionTo};
-/// use agent_client_protocol_core::{DynConnectTo, role::Role};
+/// use agent_client_protocol::mcp_server::{McpServerConnect, McpConnectionTo};
+/// use agent_client_protocol::{DynConnectTo, role::Role};
 ///
 /// struct MyMcpServer {
 ///     name: String,
diff --git a/src/agent-client-protocol-core/src/mcp_server/context.rs b/src/agent-client-protocol/src/mcp_server/context.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/mcp_server/context.rs
rename to src/agent-client-protocol/src/mcp_server/context.rs
diff --git a/src/agent-client-protocol-core/src/mcp_server/mod.rs b/src/agent-client-protocol/src/mcp_server/mod.rs
similarity index 86%
rename from src/agent-client-protocol-core/src/mcp_server/mod.rs
rename to src/agent-client-protocol/src/mcp_server/mod.rs
index 35c14f8..25f5416 100644
--- a/src/agent-client-protocol-core/src/mcp_server/mod.rs
+++ b/src/agent-client-protocol/src/mcp_server/mod.rs
@@ -6,7 +6,7 @@
 //! ## Quick Start
 //!
 //! ```rust,ignore
-//! use agent_client_protocol_core::mcp_server::{McpServer, McpTool};
+//! use agent_client_protocol::mcp_server::{McpServer, McpTool};
 //!
 //! // Create an MCP server with tools
 //! let server = McpServer::builder("my-server".to_string())
@@ -26,8 +26,8 @@
 //! You can implement [`McpServerConnect`](`crate::mcp_server::McpServerConnect`) to create custom MCP servers:
 //!
 //! ```rust,ignore
-//! use agent_client_protocol_core::mcp_server::{McpServer, McpServerConnect, McpContext};
-//! use agent_client_protocol_core::{DynComponent, JrLink};
+//! use agent_client_protocol::mcp_server::{McpServer, McpServerConnect, McpContext};
+//! use agent_client_protocol::{DynComponent, JrLink};
 //!
 //! struct MyCustomServer;
 //!
diff --git a/src/agent-client-protocol-core/src/mcp_server/responder.rs b/src/agent-client-protocol/src/mcp_server/responder.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/mcp_server/responder.rs
rename to src/agent-client-protocol/src/mcp_server/responder.rs
diff --git a/src/agent-client-protocol-core/src/mcp_server/server.rs b/src/agent-client-protocol/src/mcp_server/server.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/mcp_server/server.rs
rename to src/agent-client-protocol/src/mcp_server/server.rs
diff --git a/src/agent-client-protocol-core/src/mcp_server/tool.rs b/src/agent-client-protocol/src/mcp_server/tool.rs
similarity index 90%
rename from src/agent-client-protocol-core/src/mcp_server/tool.rs
rename to src/agent-client-protocol/src/mcp_server/tool.rs
index 5c26f04..1b2c450 100644
--- a/src/agent-client-protocol-core/src/mcp_server/tool.rs
+++ b/src/agent-client-protocol/src/mcp_server/tool.rs
@@ -16,7 +16,7 @@ use super::McpConnectionTo;
 /// # Example
 ///
 /// ```rust,ignore
-/// use agent_client_protocol_core::mcp_server::{McpTool, McpContext};
+/// use agent_client_protocol::mcp_server::{McpTool, McpContext};
 /// use schemars::JsonSchema;
 /// use serde::{Deserialize, Serialize};
 ///
@@ -32,7 +32,7 @@ use super::McpConnectionTo;
 ///
 /// struct EchoTool;
 ///
-/// impl<R: agent_client_protocol_core::role::Role> McpTool<R> for EchoTool {
+/// impl<R: agent_client_protocol::role::Role> McpTool<R> for EchoTool {
 ///     type Input = EchoInput;
 ///     type Output = EchoOutput;
 ///
@@ -48,7 +48,7 @@ use super::McpConnectionTo;
 ///         &self,
 ///         input: EchoInput,
 ///         _context: McpContext<R>,
-///     ) -> Result<EchoOutput, agent_client_protocol_core::Error> {
+///     ) -> Result<EchoOutput, agent_client_protocol::Error> {
 ///         Ok(EchoOutput {
 ///             echoed: format!("Echo: {}", input.message),
 ///         })
diff --git a/src/agent-client-protocol-core/src/role.rs b/src/agent-client-protocol/src/role.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/role.rs
rename to src/agent-client-protocol/src/role.rs
diff --git a/src/agent-client-protocol-core/src/role/acp.rs b/src/agent-client-protocol/src/role/acp.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/role/acp.rs
rename to src/agent-client-protocol/src/role/acp.rs
diff --git a/src/agent-client-protocol-core/src/role/mcp.rs b/src/agent-client-protocol/src/role/mcp.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/role/mcp.rs
rename to src/agent-client-protocol/src/role/mcp.rs
diff --git a/src/agent-client-protocol/src/rpc.rs b/src/agent-client-protocol/src/rpc.rs
deleted file mode 100644
index 42acdcc..0000000
--- a/src/agent-client-protocol/src/rpc.rs
+++ /dev/null
@@ -1,380 +0,0 @@
-use std::{
-    any::Any,
-    borrow::Cow,
-    collections::HashMap,
-    rc::Rc,
-    sync::{
-        Arc, Mutex,
-        atomic::{AtomicI64, Ordering},
-    },
-};
-
-use agent_client_protocol_schema::{
-    Error, JsonRpcMessage, Notification, OutgoingMessage, Request, RequestId, Response, Result,
-    Side,
-};
-use futures::{
-    AsyncBufReadExt as _, AsyncRead, AsyncWrite, AsyncWriteExt as _, FutureExt as _,
-    StreamExt as _,
-    channel::{
-        mpsc::{self, UnboundedReceiver, UnboundedSender},
-        oneshot,
-    },
-    future::LocalBoxFuture,
-    io::BufReader,
-    select_biased,
-};
-use serde::{Deserialize, de::DeserializeOwned};
-use serde_json::value::RawValue;
-
-use super::stream_broadcast::{StreamBroadcast, StreamReceiver, StreamSender};
-
-#[derive(Debug)]
-pub(crate) struct RpcConnection<Local: Side, Remote: Side> {
-    outgoing_tx: UnboundedSender<OutgoingMessage<Local, Remote>>,
-    pending_responses: Arc<Mutex<HashMap<RequestId, PendingResponse>>>,
-    next_id: AtomicI64,
-    broadcast: StreamBroadcast,
-}
-
-#[derive(Debug)]
-struct PendingResponse {
-    deserialize: fn(&serde_json::value::RawValue) -> Result<Box<dyn Any + Send>>,
-    respond: oneshot::Sender<Result<Box<dyn Any + Send>>>,
-}
-
-impl<Local, Remote> RpcConnection<Local, Remote>
-where
-    Local: Side + 'static,
-    Remote: Side + 'static,
-{
-    pub(crate) fn new<Handler>(
-        handler: Handler,
-        outgoing_bytes: impl Unpin + AsyncWrite,
-        incoming_bytes: impl Unpin + AsyncRead,
-        spawn: impl Fn(LocalBoxFuture<'static, ()>) + 'static,
-    ) -> (Self, impl futures::Future<Output = Result<()>>)
-    where
-        Handler: MessageHandler<Local> + 'static,
-    {
-        let (incoming_tx, incoming_rx) = mpsc::unbounded();
-        let (outgoing_tx, outgoing_rx) = mpsc::unbounded();
-
-        let pending_responses = Arc::new(Mutex::new(HashMap::default()));
-        let (broadcast_tx, broadcast) = StreamBroadcast::new();
-
-        let io_task = {
-            let pending_responses = pending_responses.clone();
-            async move {
-                let result = Self::handle_io(
-                    incoming_tx,
-                    outgoing_rx,
-                    outgoing_bytes,
-                    incoming_bytes,
-                    pending_responses.clone(),
-                    broadcast_tx,
-                )
-                .await;
-                pending_responses.lock().unwrap().clear();
-                result
-            }
-        };
-
-        Self::handle_incoming(outgoing_tx.clone(), incoming_rx, handler, spawn);
-
-        let this = Self {
-            outgoing_tx,
-            pending_responses,
-            next_id: AtomicI64::new(0),
-            broadcast,
-        };
-
-        (this, io_task)
-    }
-
-    pub(crate) fn subscribe(&self) -> StreamReceiver {
-        self.broadcast.receiver()
-    }
-
-    pub(crate) fn notify(
-        &self,
-        method: impl Into<Arc<str>>,
-        params: Option<Remote::InNotification>,
-    ) -> Result<()> {
-        self.outgoing_tx
-            .unbounded_send(OutgoingMessage::Notification(Notification {
-                method: method.into(),
-                params,
-            }))
-            .map_err(|_| Error::internal_error().data("failed to send notification"))
-    }
-
-    pub(crate) fn request<Out: DeserializeOwned + Send + 'static>(
-        &self,
-        method: impl Into<Arc<str>>,
-        params: Option<Remote::InRequest>,
-    ) -> Result<impl Future<Output = Result<Out>>> {
-        let (tx, rx) = oneshot::channel();
-        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
-        let id = RequestId::Number(id);
-        self.pending_responses.lock().unwrap().insert(
-            id.clone(),
-            PendingResponse {
-                deserialize: |value| {
-                    serde_json::from_str::<Out>(value.get())
-                        .map(|out| Box::new(out) as _)
-                        .map_err(|_| Error::internal_error().data("failed to deserialize response"))
-                },
-                respond: tx,
-            },
-        );
-
-        if self
-            .outgoing_tx
-            .unbounded_send(OutgoingMessage::Request(Request {
-                id: id.clone(),
-                method: method.into(),
-                params,
-            }))
-            .is_err()
-        {
-            self.pending_responses.lock().unwrap().remove(&id);
-            return Err(
-                Error::internal_error().data("connection closed before request could be sent")
-            );
-        }
-        Ok(async move {
-            let result = rx
-                .await
-                .map_err(|_| Error::internal_error().data("server shut down unexpectedly"))??
-                .downcast::<Out>()
-                .map_err(|_| Error::internal_error().data("failed to deserialize response"))?;
-
-            Ok(*result)
-        })
-    }
-
-    async fn handle_io(
-        incoming_tx: UnboundedSender<IncomingMessage<Local>>,
-        mut outgoing_rx: UnboundedReceiver<OutgoingMessage<Local, Remote>>,
-        mut outgoing_bytes: impl Unpin + AsyncWrite,
-        incoming_bytes: impl Unpin + AsyncRead,
-        pending_responses: Arc<Mutex<HashMap<RequestId, PendingResponse>>>,
-        broadcast: StreamSender,
-    ) -> Result<()> {
-        // TODO: Create nicer abstraction for broadcast
-        let mut input_reader = BufReader::new(incoming_bytes);
-        let mut outgoing_line = Vec::new();
-        let mut incoming_line = String::new();
-        loop {
-            select_biased! {
-                message = outgoing_rx.next() => {
-                    if let Some(message) = message {
-                        outgoing_line.clear();
-                        serde_json::to_writer(&mut outgoing_line, &JsonRpcMessage::wrap(&message)).map_err(Error::into_internal_error)?;
-                        log::trace!("send: {}", String::from_utf8_lossy(&outgoing_line));
-                        outgoing_line.push(b'\n');
-                        if let Err(e) = outgoing_bytes.write_all(&outgoing_line).await {
-                            log::error!("failed to send message to peer: {e}");
-                            break;
-                        }
-                        broadcast.outgoing(&message);
-                    } else {
-                        break;
-                    }
-                }
-                bytes_read = input_reader.read_line(&mut incoming_line).fuse() => {
-                    if bytes_read.map_err(Error::into_internal_error)? == 0 {
-                        break
-                    }
-                    log::trace!("recv: {}", &incoming_line);
-
-                    match serde_json::from_str::<RawIncomingMessage<'_>>(&incoming_line) {
-                        Ok(message) => {
-                            if let Some(id) = message.id {
-                                if let Some(method) = message.method {
-                                    // Request
-                                    match Local::decode_request(&method, message.params) {
-                                        Ok(request) => {
-                                            broadcast.incoming_request(id.clone(), &*method, &request);
-                                            if let Err(e) = incoming_tx.unbounded_send(IncomingMessage::Request { id, request }) {
-                                                log::warn!("failed to send request to handler, channel full: {e:?}");
-                                            }
-                                        }
-                                        Err(error) => {
-                                            outgoing_line.clear();
-                                            let error_response = OutgoingMessage::<Local, Remote>::Response(Response::Error {
-                                                id,
-                                                error,
-                                            });
-
-                                            serde_json::to_writer(&mut outgoing_line, &JsonRpcMessage::wrap(&error_response))?;
-                                            log::trace!("send: {}", String::from_utf8_lossy(&outgoing_line));
-                                            outgoing_line.push(b'\n');
-                                            if let Err(e) = outgoing_bytes.write_all(&outgoing_line).await {
-                                                log::error!("failed to send error response to peer: {e}");
-                                                break;
-                                            }
-                                            broadcast.outgoing(&error_response);
-                                        }
-                                    }
-                                } else if let Some(pending_response) = pending_responses.lock().unwrap().remove(&id) {
-                                    // Response
-                                    if let Some(result_value) = message.result {
-                                        broadcast.incoming_response(id, Ok(Some(result_value)));
-
-                                        let result = (pending_response.deserialize)(result_value);
-                                        pending_response.respond.send(result).ok();
-                                    } else if let Some(error) = message.error {
-                                        broadcast.incoming_response(id, Err(&error));
-
-                                        pending_response.respond.send(Err(error)).ok();
-                                    } else {
-                                        broadcast.incoming_response(id, Ok(None));
-
-                                        let result = (pending_response.deserialize)(RawValue::NULL);
-                                        pending_response.respond.send(result).ok();
-                                    }
-                                } else {
-                                    log::error!("received response for unknown request id: {id:?}");
-                                }
-                            } else if let Some(method) = message.method {
-                                // Notification
-                                match Local::decode_notification(&method, message.params) {
-                                    Ok(notification) => {
-                                        broadcast.incoming_notification(&*method, &notification);
-                                        if let Err(e) = incoming_tx.unbounded_send(IncomingMessage::Notification { notification }) {
-                                            log::warn!("failed to send notification to handler, channel full: {e:?}");
-                                        }
-                                    }
-                                    Err(err) => {
-                                        log::error!("failed to decode {:?}: {err}", message.params);
-                                    }
-                                }
-                            } else {
-                                log::error!("received message with neither id nor method");
-                            }
-                        }
-                        Err(error) => {
-                            log::error!("failed to parse incoming message: {error}. Raw: {incoming_line}");
-                        }
-                    }
-                    incoming_line.clear();
-                }
-            }
-        }
-        Ok(())
-    }
-
-    fn handle_incoming<Handler: MessageHandler<Local> + 'static>(
-        outgoing_tx: UnboundedSender<OutgoingMessage<Local, Remote>>,
-        mut incoming_rx: UnboundedReceiver<IncomingMessage<Local>>,
-        handler: Handler,
-        spawn: impl Fn(LocalBoxFuture<'static, ()>) + 'static,
-    ) {
-        let spawn = Rc::new(spawn);
-        let handler = Rc::new(handler);
-        spawn({
-            let spawn = spawn.clone();
-            async move {
-                while let Some(message) = incoming_rx.next().await {
-                    match message {
-                        IncomingMessage::Request { id, request } => {
-                            let outgoing_tx = outgoing_tx.clone();
-                            let handler = handler.clone();
-                            spawn(
-                                async move {
-                                    let result = handler.handle_request(request).await;
-                                    if let Err(e) = outgoing_tx.unbounded_send(
-                                        OutgoingMessage::Response(Response::new(id, result)),
-                                    ) {
-                                        log::error!("failed to send response to peer: {e:?}");
-                                    }
-                                }
-                                .boxed_local(),
-                            );
-                        }
-                        IncomingMessage::Notification { notification } => {
-                            let handler = handler.clone();
-                            spawn(
-                                async move {
-                                    if let Err(err) =
-                                        handler.handle_notification(notification).await
-                                    {
-                                        log::error!("failed to handle notification: {err:?}");
-                                    }
-                                }
-                                .boxed_local(),
-                            );
-                        }
-                    }
-                }
-            }
-            .boxed_local()
-        });
-    }
-}
-
-#[derive(Debug, Deserialize)]
-pub struct RawIncomingMessage<'a> {
-    id: Option<RequestId>,
-    #[serde(borrow)]
-    method: Option<Cow<'a, str>>,
-    #[serde(borrow)]
-    params: Option<&'a RawValue>,
-    #[serde(borrow)]
-    result: Option<&'a RawValue>,
-    error: Option<Error>,
-}
-
-#[derive(Debug)]
-pub enum IncomingMessage<Local: Side> {
-    Request {
-        id: RequestId,
-        request: Local::InRequest,
-    },
-    Notification {
-        notification: Local::InNotification,
-    },
-}
-
-pub trait MessageHandler<Local: Side> {
-    fn handle_request(
-        &self,
-        request: Local::InRequest,
-    ) -> impl Future<Output = Result<Local::OutResponse>>;
-
-    fn handle_notification(
-        &self,
-        notification: Local::InNotification,
-    ) -> impl Future<Output = Result<()>>;
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_raw_incoming_message_with_escaped_slash() {
-        // JSON with escaped forward slash in method name (valid per RFC 8259).
-        // Some JSON encoders (especially behind WebSocket proxies) produce
-        // `\/` instead of `/`.  The Cow<str> field in RawIncomingMessage ensures
-        // serde can allocate a new String when unescaping is required.
-        //
-        // Before the fix, this would fail because `&'a str` cannot hold an
-        // unescaped value that differs from the source bytes.
-        let json_str = r#"{"jsonrpc":"2.0","id":1,"method":"session\/update","params":{}}"#;
-        let parsed: RawIncomingMessage<'_> = serde_json::from_str(json_str).unwrap();
-        assert_eq!(parsed.method.unwrap(), "session/update");
-        assert_eq!(parsed.params.unwrap().to_string(), "{}");
-    }
-
-    #[test]
-    fn test_raw_incoming_message_without_escape() {
-        // Normal method name without escapes should still work (zero-copy borrow via Cow::Borrowed).
-        let json_str = r#"{"jsonrpc":"2.0","id":2,"method":"session/update","params":{}}"#;
-        let parsed: RawIncomingMessage<'_> = serde_json::from_str(json_str).unwrap();
-        assert_eq!(parsed.method.unwrap(), "session/update");
-        assert_eq!(parsed.params.unwrap().to_string(), "{}");
-    }
-}
diff --git a/src/agent-client-protocol/src/rpc_tests.rs b/src/agent-client-protocol/src/rpc_tests.rs
deleted file mode 100644
index 288f946..0000000
--- a/src/agent-client-protocol/src/rpc_tests.rs
+++ /dev/null
@@ -1,984 +0,0 @@
-use std::sync::{Arc, Mutex};
-
-use crate::*;
-
-#[derive(Clone)]
-struct TestClient {
-    permission_responses: Arc<Mutex<Vec<RequestPermissionOutcome>>>,
-    file_contents: Arc<Mutex<std::collections::HashMap<std::path::PathBuf, String>>>,
-    written_files: Arc<Mutex<Vec<(std::path::PathBuf, String)>>>,
-    session_notifications: Arc<Mutex<Vec<SessionNotification>>>,
-    extension_notifications: Arc<Mutex<Vec<(String, ExtNotification)>>>,
-}
-
-impl TestClient {
-    fn new() -> Self {
-        Self {
-            permission_responses: Arc::new(Mutex::new(Vec::new())),
-            file_contents: Arc::new(Mutex::new(std::collections::HashMap::new())),
-            written_files: Arc::new(Mutex::new(Vec::new())),
-            session_notifications: Arc::new(Mutex::new(Vec::new())),
-            extension_notifications: Arc::new(Mutex::new(Vec::new())),
-        }
-    }
-
-    fn add_permission_response(&self, outcome: RequestPermissionOutcome) {
-        self.permission_responses.lock().unwrap().push(outcome);
-    }
-
-    fn add_file_content(&self, path: std::path::PathBuf, content: String) {
-        self.file_contents.lock().unwrap().insert(path, content);
-    }
-}
-
-macro_rules! raw_json {
-    ($($json:tt)+) => {{
-        let response = serde_json::json!($($json)+);
-        serde_json::value::to_raw_value(&response).unwrap().into()
-    }};
-}
-
-#[async_trait::async_trait(?Send)]
-impl Client for TestClient {
-    async fn request_permission(
-        &self,
-        _arguments: RequestPermissionRequest,
-    ) -> Result<RequestPermissionResponse> {
-        let responses = self.permission_responses.clone();
-        let mut responses = responses.lock().unwrap();
-        let outcome = responses
-            .pop()
-            .unwrap_or(RequestPermissionOutcome::Cancelled);
-        Ok(RequestPermissionResponse::new(outcome))
-    }
-
-    async fn write_text_file(
-        &self,
-        arguments: WriteTextFileRequest,
-    ) -> Result<WriteTextFileResponse> {
-        self.written_files
-            .lock()
-            .unwrap()
-            .push((arguments.path, arguments.content));
-        Ok(WriteTextFileResponse::default())
-    }
-
-    async fn read_text_file(&self, arguments: ReadTextFileRequest) -> Result<ReadTextFileResponse> {
-        let contents = self.file_contents.lock().unwrap();
-        let content = contents
-            .get(&arguments.path)
-            .cloned()
-            .unwrap_or_else(|| "default content".to_string());
-        Ok(ReadTextFileResponse::new(content))
-    }
-
-    async fn session_notification(&self, args: SessionNotification) -> Result<()> {
-        self.session_notifications.lock().unwrap().push(args);
-        Ok(())
-    }
-
-    async fn create_terminal(
-        &self,
-        _args: CreateTerminalRequest,
-    ) -> Result<CreateTerminalResponse> {
-        unimplemented!()
-    }
-
-    async fn terminal_output(
-        &self,
-        _args: TerminalOutputRequest,
-    ) -> Result<TerminalOutputResponse> {
-        unimplemented!()
-    }
-
-    async fn kill_terminal(&self, _args: KillTerminalRequest) -> Result<KillTerminalResponse> {
-        unimplemented!()
-    }
-
-    async fn release_terminal(
-        &self,
-        _args: ReleaseTerminalRequest,
-    ) -> Result<ReleaseTerminalResponse> {
-        unimplemented!()
-    }
-
-    async fn wait_for_terminal_exit(
-        &self,
-        _args: WaitForTerminalExitRequest,
-    ) -> Result<WaitForTerminalExitResponse> {
-        unimplemented!()
-    }
-
-    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
-        match args.method.as_ref() {
-            "example.com/ping" => Ok(ExtResponse::new(raw_json!({
-                "response": "pong",
-                "params": args.params
-            }))),
-            _ => Err(Error::method_not_found()),
-        }
-    }
-
-    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
-        self.extension_notifications
-            .lock()
-            .unwrap()
-            .push((args.method.to_string(), args));
-        Ok(())
-    }
-}
-
-#[derive(Clone)]
-struct TestAgent {
-    sessions: Arc<Mutex<std::collections::HashMap<SessionId, std::path::PathBuf>>>,
-    prompts_received: Arc<Mutex<Vec<PromptReceived>>>,
-    cancellations_received: Arc<Mutex<Vec<SessionId>>>,
-    #[cfg(feature = "unstable_logout")]
-    logout_count: Arc<Mutex<u32>>,
-    extension_notifications: Arc<Mutex<Vec<(String, ExtNotification)>>>,
-}
-
-type PromptReceived = (SessionId, Vec<ContentBlock>);
-
-impl TestAgent {
-    fn new() -> Self {
-        Self {
-            sessions: Arc::new(Mutex::new(std::collections::HashMap::new())),
-            prompts_received: Arc::new(Mutex::new(Vec::new())),
-            cancellations_received: Arc::new(Mutex::new(Vec::new())),
-            #[cfg(feature = "unstable_logout")]
-            logout_count: Arc::new(Mutex::new(0)),
-            extension_notifications: Arc::new(Mutex::new(Vec::new())),
-        }
-    }
-}
-
-#[async_trait::async_trait(?Send)]
-impl Agent for TestAgent {
-    async fn initialize(&self, arguments: InitializeRequest) -> Result<InitializeResponse> {
-        #[cfg(feature = "unstable_logout")]
-        let mut capabilities = AgentCapabilities::new();
-        #[cfg(not(feature = "unstable_logout"))]
-        let capabilities = AgentCapabilities::new();
-        #[cfg(feature = "unstable_logout")]
-        {
-            capabilities.auth.logout =
-                Some(agent_client_protocol_schema::LogoutCapabilities::default());
-        }
-        Ok(InitializeResponse::new(arguments.protocol_version)
-            .agent_capabilities(capabilities)
-            .agent_info(Implementation::new("test-agent", "0.0.0").title("Test Agent")))
-    }
-
-    async fn authenticate(&self, _arguments: AuthenticateRequest) -> Result<AuthenticateResponse> {
-        Ok(AuthenticateResponse::default())
-    }
-
-    #[cfg(feature = "unstable_logout")]
-    async fn logout(
-        &self,
-        _arguments: agent_client_protocol_schema::LogoutRequest,
-    ) -> Result<agent_client_protocol_schema::LogoutResponse> {
-        *self.logout_count.lock().unwrap() += 1;
-        Ok(agent_client_protocol_schema::LogoutResponse::default())
-    }
-
-    async fn new_session(&self, arguments: NewSessionRequest) -> Result<NewSessionResponse> {
-        let session_id = SessionId::new("test-session-123");
-        self.sessions
-            .lock()
-            .unwrap()
-            .insert(session_id.clone(), arguments.cwd);
-        Ok(NewSessionResponse::new(session_id))
-    }
-
-    async fn load_session(&self, _: LoadSessionRequest) -> Result<LoadSessionResponse> {
-        Ok(LoadSessionResponse::new())
-    }
-
-    async fn set_session_mode(
-        &self,
-        _arguments: SetSessionModeRequest,
-    ) -> Result<SetSessionModeResponse> {
-        Ok(SetSessionModeResponse::new())
-    }
-
-    async fn prompt(&self, arguments: PromptRequest) -> Result<PromptResponse> {
-        self.prompts_received
-            .lock()
-            .unwrap()
-            .push((arguments.session_id, arguments.prompt));
-        Ok(PromptResponse::new(StopReason::EndTurn))
-    }
-
-    async fn cancel(&self, args: CancelNotification) -> Result<()> {
-        self.cancellations_received
-            .lock()
-            .unwrap()
-            .push(args.session_id);
-        Ok(())
-    }
-
-    #[cfg(feature = "unstable_session_model")]
-    async fn set_session_model(
-        &self,
-        args: agent_client_protocol_schema::SetSessionModelRequest,
-    ) -> Result<agent_client_protocol_schema::SetSessionModelResponse> {
-        log::info!("Received select model request {args:?}");
-        Ok(agent_client_protocol_schema::SetSessionModelResponse::default())
-    }
-
-    async fn list_sessions(
-        &self,
-        _args: agent_client_protocol_schema::ListSessionsRequest,
-    ) -> Result<agent_client_protocol_schema::ListSessionsResponse> {
-        let sessions = self.sessions.lock().unwrap();
-        let session_infos: Vec<_> = sessions
-            .iter()
-            .map(|(id, cwd)| {
-                agent_client_protocol_schema::SessionInfo::new(id.clone(), cwd.clone())
-            })
-            .collect();
-        Ok(agent_client_protocol_schema::ListSessionsResponse::new(
-            session_infos,
-        ))
-    }
-
-    #[cfg(feature = "unstable_session_fork")]
-    async fn fork_session(
-        &self,
-        args: agent_client_protocol_schema::ForkSessionRequest,
-    ) -> Result<agent_client_protocol_schema::ForkSessionResponse> {
-        let new_session_id = SessionId::new(format!("fork-of-{}", args.session_id.0));
-        self.sessions
-            .lock()
-            .unwrap()
-            .insert(new_session_id.clone(), args.cwd);
-        Ok(agent_client_protocol_schema::ForkSessionResponse::new(
-            new_session_id,
-        ))
-    }
-
-    #[cfg(feature = "unstable_session_resume")]
-    async fn resume_session(
-        &self,
-        args: agent_client_protocol_schema::ResumeSessionRequest,
-    ) -> Result<agent_client_protocol_schema::ResumeSessionResponse> {
-        // Check if session exists
-        if !self.sessions.lock().unwrap().contains_key(&args.session_id) {
-            return Err(Error::invalid_params());
-        }
-        Ok(agent_client_protocol_schema::ResumeSessionResponse::new())
-    }
-
-    async fn set_session_config_option(
-        &self,
-        args: agent_client_protocol_schema::SetSessionConfigOptionRequest,
-    ) -> Result<agent_client_protocol_schema::SetSessionConfigOptionResponse> {
-        #[cfg(feature = "unstable_boolean_config")]
-        let value = args
-            .value
-            .as_value_id()
-            .ok_or(agent_client_protocol_schema::Error::invalid_params())?
-            .clone();
-        #[cfg(not(feature = "unstable_boolean_config"))]
-        let value: agent_client_protocol_schema::SessionConfigValueId = args.value.into();
-        let option = agent_client_protocol_schema::SessionConfigOption::select(
-            args.config_id,
-            "Test Option",
-            value,
-            vec![
-                agent_client_protocol_schema::SessionConfigSelectOption::new("value1", "Value 1"),
-                agent_client_protocol_schema::SessionConfigSelectOption::new("value2", "Value 2"),
-            ],
-        );
-        Ok(agent_client_protocol_schema::SetSessionConfigOptionResponse::new(vec![option]))
-    }
-
-    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
-        match args.method.as_ref() {
-            "example.com/echo" => {
-                let response = serde_json::json!({
-                    "echo": args.params
-                });
-                Ok(ExtResponse::new(
-                    serde_json::value::to_raw_value(&response)?.into(),
-                ))
-            }
-            _ => Err(Error::method_not_found()),
-        }
-    }
-
-    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
-        self.extension_notifications
-            .lock()
-            .unwrap()
-            .push((args.method.to_string(), args));
-        Ok(())
-    }
-}
-
-// Helper function to create a bidirectional connection
-fn create_connection_pair(
-    client: &TestClient,
-    agent: &TestAgent,
-) -> (ClientSideConnection, AgentSideConnection) {
-    let (client_to_agent_rx, client_to_agent_tx) = piper::pipe(1024);
-    let (agent_to_client_rx, agent_to_client_tx) = piper::pipe(1024);
-
-    let (agent_conn, agent_io_task) = ClientSideConnection::new(
-        client.clone(),
-        client_to_agent_tx,
-        agent_to_client_rx,
-        |fut| {
-            tokio::task::spawn_local(fut);
-        },
-    );
-
-    let (client_conn, client_io_task) = AgentSideConnection::new(
-        agent.clone(),
-        agent_to_client_tx,
-        client_to_agent_rx,
-        |fut| {
-            tokio::task::spawn_local(fut);
-        },
-    );
-
-    // Spawn the IO tasks
-    tokio::task::spawn_local(agent_io_task);
-    tokio::task::spawn_local(client_io_task);
-
-    (agent_conn, client_conn)
-}
-
-#[tokio::test]
-async fn test_initialize() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
-
-            let result =
-                agent_conn
-                    .initialize(InitializeRequest::new(ProtocolVersion::LATEST).client_info(
-                        Implementation::new("test-client", "0.0.0").title("Test Client"),
-                    ))
-                    .await;
-
-            assert!(result.is_ok());
-            let response = result.unwrap();
-            assert_eq!(response.protocol_version, ProtocolVersion::LATEST);
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_basic_session_creation() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
-
-            agent_conn
-                .new_session(NewSessionRequest::new("/test"))
-                .await
-                .expect("new_session failed");
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_bidirectional_file_operations() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            // Add test file content
-            let test_path = std::path::PathBuf::from("/test/file.txt");
-            client.add_file_content(test_path.clone(), "Hello, World!".to_string());
-
-            let (_agent_conn, client_conn) = create_connection_pair(&client, &agent);
-
-            // Test reading a file
-            let session_id = SessionId::new("test-session");
-            let read_result = client_conn
-                .read_text_file(ReadTextFileRequest::new(session_id.clone(), &test_path))
-                .await
-                .expect("read_text_file failed");
-
-            assert_eq!(read_result.content, "Hello, World!");
-
-            // Test writing a file
-            let write_result = client_conn
-                .write_text_file(WriteTextFileRequest::new(
-                    session_id.clone(),
-                    &test_path,
-                    "Updated content",
-                ))
-                .await;
-
-            assert!(write_result.is_ok());
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_session_notifications() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (_agent_conn, client_conn) = create_connection_pair(&client, &agent);
-
-            let session_id = SessionId::new("test-session");
-            // Send various session updates
-            client_conn
-                .session_notification(SessionNotification::new(
-                    session_id.clone(),
-                    SessionUpdate::UserMessageChunk(ContentChunk::new("Hello from user".into())),
-                ))
-                .await
-                .expect("session_notification failed");
-
-            client_conn
-                .session_notification(SessionNotification::new(
-                    session_id.clone(),
-                    SessionUpdate::AgentMessageChunk(ContentChunk::new("Hello from agent".into())),
-                ))
-                .await
-                .expect("session_notification failed");
-
-            tokio::task::yield_now().await;
-
-            let notifications = client.session_notifications.lock().unwrap();
-            assert_eq!(notifications.len(), 2);
-            assert_eq!(notifications[0].session_id, session_id);
-            assert_eq!(notifications[1].session_id, session_id);
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_cancel_notification() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
-
-            let session_id = SessionId::new("test-session");
-            // Send cancel notification
-            agent_conn
-                .cancel(CancelNotification::new(session_id.clone()))
-                .await
-                .expect("cancel failed");
-
-            tokio::task::yield_now().await;
-
-            let cancelled = agent.cancellations_received.lock().unwrap();
-            assert_eq!(cancelled.len(), 1);
-            assert_eq!(cancelled[0], session_id);
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_concurrent_operations() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            // Add multiple file contents
-            for i in 0..5 {
-                let path = std::path::PathBuf::from(format!("/test/file{i}.txt"));
-                client.add_file_content(path, format!("Content {i}"));
-            }
-
-            let (_agent_conn, client_conn) = create_connection_pair(&client, &agent);
-
-            let session_id = SessionId::new("test-session");
-
-            // Launch multiple concurrent read operations
-            let mut read_futures = vec![];
-            for i in 0..5 {
-                let path = std::path::PathBuf::from(format!("/test/file{i}.txt"));
-                let future =
-                    client_conn.read_text_file(ReadTextFileRequest::new(session_id.clone(), path));
-                read_futures.push(future);
-            }
-
-            // Wait for all reads to complete
-            let results = futures::future::join_all(read_futures).await;
-
-            // Verify all reads succeeded
-            for (i, result) in results.into_iter().enumerate() {
-                let output = result.expect("read failed");
-                assert_eq!(output.content, format!("Content {i}"));
-            }
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_full_conversation_flow() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            // Set up permission to approve the tool call
-            client.add_permission_response(RequestPermissionOutcome::Selected(SelectedPermissionOutcome::new(PermissionOptionId::new("allow-once"))));
-
-            let (agent_conn, client_conn) = create_connection_pair(&client, &agent);
-            // 1. Start new session
-            let new_session_result = agent_conn
-                .new_session(NewSessionRequest::new("/test"))
-                .await
-                .expect("new_session failed");
-
-            let session_id = new_session_result.session_id;
-
-            // 2. Send user message
-            let user_prompt = vec!["Please analyze the file and summarize it".into()];
-
-            agent_conn
-                .prompt(PromptRequest::new(session_id.clone(), user_prompt))
-                .await
-                .expect("prompt failed");
-
-            // 3. Agent starts responding
-            client_conn
-                .session_notification(SessionNotification::new(session_id.clone(), SessionUpdate::AgentMessageChunk(ContentChunk::new("I'll analyze the file for you. ".into()))))
-                .await
-                .expect("session_notification failed");
-
-            // 4. Agent creates a tool call
-            let tool_call_id = ToolCallId::new("read-file-001");
-            client_conn
-                .session_notification(SessionNotification::new(session_id.clone(), SessionUpdate::ToolCall(ToolCall::new(tool_call_id.clone(), "Reading file").kind(ToolKind::Read).locations(vec![ToolCallLocation::new("/test/data.txt")]))))
-                .await
-                .expect("session_notification failed");
-
-            // 5. Agent requests permission for the tool call
-            let permission_result = client_conn
-                .request_permission(RequestPermissionRequest::new(session_id.clone(), ToolCallUpdate::new(tool_call_id.clone(), ToolCallUpdateFields::new().title("Read /test/data.txt").locations(vec![ToolCallLocation::new("/test/data.txt")])), vec![
-                        PermissionOption::new(PermissionOptionId::new("allow-once"), "Allow once", PermissionOptionKind::AllowOnce),
-                        PermissionOption::new(
-                            PermissionOptionId::new("reject-once"),
-                             "Reject",
-                             PermissionOptionKind::RejectOnce,
-                        ),
-                    ],
-                ))
-                .await
-                .expect("request_permission failed");
-
-            // Verify permission was granted
-            match permission_result.outcome {
-                RequestPermissionOutcome::Selected(SelectedPermissionOutcome { option_id, .. }) => {
-                    assert_eq!(option_id.0.as_ref(), "allow-once");
-                }
-                _ => panic!("Expected permission to be granted"),
-            }
-
-            // 6. Update tool call status
-            client_conn
-                .session_notification(SessionNotification::new(
-                     session_id.clone(),
-                     SessionUpdate::ToolCallUpdate(ToolCallUpdate::new(
-                         tool_call_id.clone(),
-                         ToolCallUpdateFields::new().status(ToolCallStatus::InProgress),
-                    ))))
-                .await
-                .expect("session_notification failed");
-
-            // 7. Tool call completes with content
-            client_conn
-                .session_notification(SessionNotification::new(
-                     session_id.clone(),
-                     SessionUpdate::ToolCallUpdate(ToolCallUpdate::new(tool_call_id.clone(), ToolCallUpdateFields::new().status(ToolCallStatus::Completed).content(vec!["File contents: Lorem ipsum dolor sit amet".into()])))))
-                .await
-                .expect("session_notification failed");
-
-            // 8. Agent sends more text after tool completion
-            client_conn
-                .session_notification(SessionNotification::new(
-                     session_id.clone(),
-                    SessionUpdate::AgentMessageChunk(ContentChunk::new("Based on the file contents, here's my summary: The file contains placeholder text commonly used in the printing industry.".into()))))
-                .await
-                .expect("session_notification failed");
-
-            for _ in 0..10 {
-                tokio::task::yield_now().await;
-            }
-
-            // Verify we received all the updates
-            let updates = client.session_notifications.lock().unwrap();
-            assert!(updates.len() >= 5); // At least 5 updates sent
-
-            // Verify the sequence of updates
-            let mut found_agent_message = false;
-            let mut found_tool_call = false;
-            let mut found_tool_update = false;
-            let mut found_final_message = false;
-
-            for notification in updates.iter() {
-                match &notification.update {
-                    SessionUpdate::AgentMessageChunk(ContentChunk { content : ContentBlock::Text(text), ..}) => {
-                        if text.text.contains("I'll analyze") {
-                            found_agent_message = true;
-                        } else if text.text.contains("Based on the file") {
-                            found_final_message = true;
-                        }
-                    }
-                    SessionUpdate::ToolCall(_) => {
-                        found_tool_call = true;
-                    }
-                    SessionUpdate::ToolCallUpdate(update) => {
-                        if let Some(ToolCallStatus::Completed) = update.fields.status {
-                            found_tool_update = true;
-                        }
-                    }
-                    _ => {}
-                }
-            }
-
-            assert!(found_agent_message, "Should have initial agent message");
-            assert!(found_tool_call, "Should have tool call");
-            assert!(found_tool_update, "Should have tool call completion");
-            assert!(found_final_message, "Should have final agent message");
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_extension_methods_and_notifications() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            // Store references to the client and agent to check notifications later
-            let client_ref = client.clone();
-            let agent_ref = agent.clone();
-
-            let (client_conn, agent_conn) = create_connection_pair(&client, &agent);
-            // Test agent calling client extension method
-            let params: Arc<_> = raw_json!({ "data": "test" });
-            let client_response = agent_conn
-                .ext_method(ExtRequest::new("example.com/ping", params))
-                .await
-                .unwrap();
-
-            assert_eq!(
-                serde_json::to_value(client_response).unwrap(),
-                serde_json::json!({
-                    "response": "pong",
-                    "params": {"data": "test"}
-                })
-            );
-
-            // Test client calling agent extension method
-            let params: Arc<_> = raw_json!({ "message": "hello" });
-            let agent_response = client_conn
-                .ext_method(ExtRequest::new("example.com/echo", params))
-                .await
-                .unwrap();
-
-            assert_eq!(
-                serde_json::to_value(agent_response).unwrap(),
-                serde_json::json!({
-                    "echo": {"message": "hello"}
-                })
-            );
-
-            // Test extension notifications
-            let params: Arc<_> = raw_json!({ "info": "client notification" });
-            agent_conn
-                .ext_notification(ExtNotification::new("example.com/client/notify", params))
-                .await
-                .unwrap();
-
-            let params: Arc<_> = raw_json!({ "info": "agent notification" });
-            client_conn
-                .ext_notification(ExtNotification::new("example.com/agent/notify", params))
-                .await
-                .unwrap();
-
-            // Yield to allow notifications to be processed
-            tokio::task::yield_now().await;
-
-            // Verify client received the notification
-            let client_notifications = client_ref.extension_notifications.lock().unwrap();
-            assert_eq!(client_notifications.len(), 1);
-            assert_eq!(client_notifications[0].0, "example.com/client/notify");
-            assert_eq!(
-                serde_json::to_value(&client_notifications[0].1).unwrap(),
-                serde_json::json!({"info": "client notification"})
-            );
-
-            // Verify agent received the notification
-            let agent_notifications = agent_ref.extension_notifications.lock().unwrap();
-            assert_eq!(agent_notifications.len(), 1);
-            assert_eq!(agent_notifications[0].0, "example.com/agent/notify");
-            assert_eq!(
-                serde_json::to_value(&agent_notifications[0].1).unwrap(),
-                serde_json::json!({"info": "agent notification"})
-            );
-        })
-        .await;
-}
-
-#[cfg(feature = "unstable_session_fork")]
-#[tokio::test]
-async fn test_fork_session() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
-
-            // First create a session
-            let new_session_response = agent_conn
-                .new_session(NewSessionRequest::new("/test"))
-                .await
-                .expect("new_session failed");
-
-            let original_session_id = new_session_response.session_id;
-
-            // Fork the session
-            let fork_response = agent_conn
-                .fork_session(agent_client_protocol_schema::ForkSessionRequest::new(
-                    original_session_id.clone(),
-                    "/test",
-                ))
-                .await
-                .expect("fork_session failed");
-
-            // Verify the forked session has a different ID
-            assert_ne!(fork_response.session_id, original_session_id);
-            assert_eq!(
-                fork_response.session_id.0.as_ref(),
-                format!("fork-of-{}", original_session_id.0)
-            );
-
-            // Verify the forked session was added to the agent's sessions
-            let sessions = agent.sessions.lock().unwrap();
-            assert!(sessions.contains_key(&fork_response.session_id));
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_list_sessions() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
-
-            // First create a session
-            let new_session_response = agent_conn
-                .new_session(NewSessionRequest::new("/test"))
-                .await
-                .expect("new_session failed");
-
-            // Verify the session was created
-            assert!(!new_session_response.session_id.0.is_empty());
-
-            // List sessions
-            let list_response = agent_conn
-                .list_sessions(agent_client_protocol_schema::ListSessionsRequest::new())
-                .await
-                .expect("list_sessions failed");
-
-            // Verify the response contains our session
-            assert_eq!(list_response.sessions.len(), 1);
-            assert_eq!(
-                list_response.sessions[0].session_id,
-                new_session_response.session_id
-            );
-            assert_eq!(
-                list_response.sessions[0].cwd,
-                std::path::PathBuf::from("/test")
-            );
-            assert!(list_response.next_cursor.is_none());
-        })
-        .await;
-}
-
-#[cfg(feature = "unstable_session_resume")]
-#[tokio::test]
-async fn test_resume_session() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
-
-            // First create a session
-            let new_session_response = agent_conn
-                .new_session(NewSessionRequest::new("/test"))
-                .await
-                .expect("new_session failed");
-
-            let session_id = new_session_response.session_id;
-
-            // Resume the session
-            let resume_response = agent_conn
-                .resume_session(agent_client_protocol_schema::ResumeSessionRequest::new(
-                    session_id.clone(),
-                    "/test",
-                ))
-                .await
-                .expect("resume_session failed");
-
-            // Verify we got a valid response (no modes by default in TestAgent)
-            assert!(resume_response.modes.is_none());
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_session_info_update() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (_agent_conn, client_conn) = create_connection_pair(&client, &agent);
-
-            let session_id = SessionId::new("test-session");
-
-            // Send a session info update notification
-            client_conn
-                .session_notification(SessionNotification::new(
-                    session_id.clone(),
-                    SessionUpdate::SessionInfoUpdate(
-                        agent_client_protocol_schema::SessionInfoUpdate::new()
-                            .title("Test Session Title")
-                            .updated_at("2025-01-15T12:00:00Z"),
-                    ),
-                ))
-                .await
-                .expect("session_notification failed");
-
-            tokio::task::yield_now().await;
-
-            // Verify client received the notification
-            let notifications = client.session_notifications.lock().unwrap();
-            assert_eq!(notifications.len(), 1);
-            assert_eq!(notifications[0].session_id, session_id);
-
-            if let SessionUpdate::SessionInfoUpdate(info_update) = &notifications[0].update {
-                assert_eq!(
-                    info_update.title,
-                    agent_client_protocol_schema::MaybeUndefined::Value(
-                        "Test Session Title".to_string()
-                    )
-                );
-                assert_eq!(
-                    info_update.updated_at,
-                    agent_client_protocol_schema::MaybeUndefined::Value(
-                        "2025-01-15T12:00:00Z".to_string()
-                    )
-                );
-            } else {
-                panic!("Expected SessionInfoUpdate variant");
-            }
-        })
-        .await;
-}
-
-#[cfg(feature = "unstable_logout")]
-#[tokio::test]
-async fn test_logout() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
-
-            let initialize_response =
-                agent_conn
-                    .initialize(InitializeRequest::new(ProtocolVersion::LATEST).client_info(
-                        Implementation::new("test-client", "0.0.0").title("Test Client"),
-                    ))
-                    .await
-                    .expect("initialize failed");
-
-            assert!(
-                initialize_response.agent_capabilities.auth.logout.is_some(),
-                "agent should advertise auth.logout capability"
-            );
-
-            let response = agent_conn
-                .logout(agent_client_protocol_schema::LogoutRequest::new())
-                .await
-                .expect("logout failed");
-
-            assert_eq!(
-                response,
-                agent_client_protocol_schema::LogoutResponse::default()
-            );
-            assert_eq!(*agent.logout_count.lock().unwrap(), 1);
-        })
-        .await;
-}
-
-#[tokio::test]
-async fn test_set_session_config_option() {
-    let local_set = tokio::task::LocalSet::new();
-    local_set
-        .run_until(async {
-            let client = TestClient::new();
-            let agent = TestAgent::new();
-
-            let (agent_conn, _client_conn) = create_connection_pair(&client, &agent);
-
-            // Set a config option
-            let response = agent_conn
-                .set_session_config_option(
-                    agent_client_protocol_schema::SetSessionConfigOptionRequest::new(
-                        "test-session",
-                        "mode",
-                        "value2",
-                    ),
-                )
-                .await
-                .expect("set_session_config_option failed");
-
-            // Verify we got config options back
-            assert_eq!(response.config_options.len(), 1);
-            assert_eq!(
-                response.config_options[0].id,
-                agent_client_protocol_schema::SessionConfigId::new("mode")
-            );
-        })
-        .await;
-}
diff --git a/src/agent-client-protocol-core/src/schema/agent_to_client/mod.rs b/src/agent-client-protocol/src/schema/agent_to_client/mod.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/agent_to_client/mod.rs
rename to src/agent-client-protocol/src/schema/agent_to_client/mod.rs
diff --git a/src/agent-client-protocol-core/src/schema/agent_to_client/notifications.rs b/src/agent-client-protocol/src/schema/agent_to_client/notifications.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/agent_to_client/notifications.rs
rename to src/agent-client-protocol/src/schema/agent_to_client/notifications.rs
diff --git a/src/agent-client-protocol-core/src/schema/agent_to_client/requests.rs b/src/agent-client-protocol/src/schema/agent_to_client/requests.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/agent_to_client/requests.rs
rename to src/agent-client-protocol/src/schema/agent_to_client/requests.rs
diff --git a/src/agent-client-protocol-core/src/schema/client_to_agent/mod.rs b/src/agent-client-protocol/src/schema/client_to_agent/mod.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/client_to_agent/mod.rs
rename to src/agent-client-protocol/src/schema/client_to_agent/mod.rs
diff --git a/src/agent-client-protocol-core/src/schema/client_to_agent/notifications.rs b/src/agent-client-protocol/src/schema/client_to_agent/notifications.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/client_to_agent/notifications.rs
rename to src/agent-client-protocol/src/schema/client_to_agent/notifications.rs
diff --git a/src/agent-client-protocol-core/src/schema/client_to_agent/requests.rs b/src/agent-client-protocol/src/schema/client_to_agent/requests.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/client_to_agent/requests.rs
rename to src/agent-client-protocol/src/schema/client_to_agent/requests.rs
diff --git a/src/agent-client-protocol-core/src/schema/enum_impls.rs b/src/agent-client-protocol/src/schema/enum_impls.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/enum_impls.rs
rename to src/agent-client-protocol/src/schema/enum_impls.rs
diff --git a/src/agent-client-protocol-core/src/schema/mod.rs b/src/agent-client-protocol/src/schema/mod.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/mod.rs
rename to src/agent-client-protocol/src/schema/mod.rs
diff --git a/src/agent-client-protocol-core/src/schema/proxy_protocol.rs b/src/agent-client-protocol/src/schema/proxy_protocol.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/schema/proxy_protocol.rs
rename to src/agent-client-protocol/src/schema/proxy_protocol.rs
diff --git a/src/agent-client-protocol-core/src/session.rs b/src/agent-client-protocol/src/session.rs
similarity index 98%
rename from src/agent-client-protocol-core/src/session.rs
rename to src/agent-client-protocol/src/session.rs
index 9908c00..4e6ed1d 100644
--- a/src/agent-client-protocol-core/src/session.rs
+++ b/src/agent-client-protocol/src/session.rs
@@ -183,9 +183,9 @@ where
     /// # Example
     ///
     /// ```
-    /// # use agent_client_protocol_core::{Client, Agent, ConnectTo};
-    /// # use agent_client_protocol_core::mcp_server::McpServer;
-    /// # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol_core::Error> {
+    /// # use agent_client_protocol::{Client, Agent, ConnectTo};
+    /// # use agent_client_protocol::mcp_server::McpServer;
+    /// # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
     /// # Client.builder().connect_with(transport, async |cx| {
     /// # let mcp = McpServer::<Agent, _>::builder("tools").build();
     /// cx.build_session_cwd()?
@@ -257,10 +257,10 @@ where
     /// # Example
     ///
     /// ```
-    /// # use agent_client_protocol_core::{Proxy, Client, Conductor, ConnectTo};
-    /// # use agent_client_protocol_core::schema::NewSessionRequest;
-    /// # use agent_client_protocol_core::mcp_server::McpServer;
-    /// # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol_core::Error> {
+    /// # use agent_client_protocol::{Proxy, Client, Conductor, ConnectTo};
+    /// # use agent_client_protocol::schema::NewSessionRequest;
+    /// # use agent_client_protocol::mcp_server::McpServer;
+    /// # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
     /// Proxy.builder()
     ///     .on_receive_request_from(Client, async |request: NewSessionRequest, responder, cx| {
     ///         let mcp = McpServer::<Conductor, _>::builder("tools").build();
@@ -270,7 +270,7 @@ where
     ///                 // Session started
     ///                 Ok(())
     ///             })
-    ///     }, agent_client_protocol_core::on_receive_request!())
+    ///     }, agent_client_protocol::on_receive_request!())
     ///     .connect_to(transport)
     ///     .await?;
     /// # Ok(())
diff --git a/src/agent-client-protocol/src/stream_broadcast.rs b/src/agent-client-protocol/src/stream_broadcast.rs
deleted file mode 100644
index 2966768..0000000
--- a/src/agent-client-protocol/src/stream_broadcast.rs
+++ /dev/null
@@ -1,300 +0,0 @@
-//! JSON-RPC Stream broadcasting for debugging and monitoring communication.
-//!
-//! This module provides functionality to observe the JSON-RPC message stream between
-//! clients and agents. It's primarily used for debugging, logging, and building
-//! development tools that need to monitor the protocol communication.
-
-use std::sync::Arc;
-
-use agent_client_protocol_schema::{
-    Error, Notification, OutgoingMessage, Request, RequestId, Response, Result, Side,
-};
-use derive_more::From;
-use serde::Serialize;
-use serde_json::value::RawValue;
-
-/// A message that flows through the RPC stream.
-///
-/// This represents any JSON-RPC message (request, response, or notification)
-/// along with its direction (incoming or outgoing).
-///
-/// Stream messages are used for observing and debugging the protocol communication
-/// without interfering with the actual message handling.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct StreamMessage {
-    /// The direction of the message relative to this side of the connection.
-    pub direction: StreamMessageDirection,
-    /// The actual content of the message.
-    pub message: StreamMessageContent,
-}
-
-/// The direction of a message in the RPC stream.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum StreamMessageDirection {
-    /// A message received from the other side of the connection.
-    Incoming,
-    /// A message sent to the other side of the connection.
-    Outgoing,
-}
-
-/// The content of a stream message.
-///
-/// This enum represents the three types of JSON-RPC messages:
-/// - Requests: Method calls that expect a response
-/// - Responses: Replies to previous requests
-/// - Notifications: One-way messages that don't expect a response
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum StreamMessageContent {
-    /// A JSON-RPC request message.
-    Request {
-        /// The unique identifier for this request.
-        id: RequestId,
-        /// The name of the method being called.
-        method: Arc<str>,
-        /// Optional parameters for the method.
-        params: Option<serde_json::Value>,
-    },
-    /// A JSON-RPC response message.
-    Response {
-        /// The ID of the request this response is for.
-        id: RequestId,
-        /// The result of the request (success or error).
-        result: Result<Option<serde_json::Value>>,
-    },
-    /// A JSON-RPC notification message.
-    Notification {
-        /// The name of the notification method.
-        method: Arc<str>,
-        /// Optional parameters for the notification.
-        params: Option<serde_json::Value>,
-    },
-}
-
-/// A receiver for observing the message stream.
-///
-/// This allows you to receive copies of all messages flowing through the connection,
-/// useful for debugging, logging, or building development tools.
-///
-/// # Example
-///
-/// ```no_run
-/// use agent_client_protocol::{StreamReceiver, StreamMessageDirection};
-///
-/// async fn monitor_messages(mut receiver: StreamReceiver) {
-///     while let Ok(message) = receiver.recv().await {
-///         match message.direction {
-///             StreamMessageDirection::Incoming => println!("← Received: {:?}", message.message),
-///             StreamMessageDirection::Outgoing => println!("→ Sent: {:?}", message.message),
-///         }
-///     }
-/// }
-/// ```
-#[derive(Debug, From)]
-pub struct StreamReceiver(async_broadcast::Receiver<StreamMessage>);
-
-impl StreamReceiver {
-    /// Receives the next message from the stream.
-    ///
-    /// This method will wait until a message is available or the sender is dropped.
-    ///
-    /// # Returns
-    ///
-    /// - `Ok(StreamMessage)` when a message is received
-    /// - `Err` when the sender is dropped or the receiver is lagged
-    pub async fn recv(&mut self) -> Result<StreamMessage> {
-        self.0
-            .recv()
-            .await
-            .map_err(|e| Error::internal_error().data(e.to_string()))
-    }
-}
-
-/// Internal sender for broadcasting stream messages.
-///
-/// This is used internally by the RPC system to broadcast messages to all receivers.
-/// You typically won't interact with this directly.
-#[derive(Clone, Debug, From)]
-pub(crate) struct StreamSender(async_broadcast::Sender<StreamMessage>);
-
-impl StreamSender {
-    /// Broadcasts an outgoing message to all receivers.
-    pub(crate) fn outgoing<L: Side, R: Side>(&self, message: &OutgoingMessage<L, R>) {
-        if self.0.receiver_count() == 0 {
-            return;
-        }
-
-        let message = StreamMessage {
-            direction: StreamMessageDirection::Outgoing,
-            message: match message {
-                OutgoingMessage::Request(Request { id, method, params }) => {
-                    StreamMessageContent::Request {
-                        id: id.clone(),
-                        method: method.clone(),
-                        params: serde_json::to_value(params).ok(),
-                    }
-                }
-                OutgoingMessage::Response(Response::Result { id, result }) => {
-                    StreamMessageContent::Response {
-                        id: id.clone(),
-                        result: Ok(serde_json::to_value(result).ok()),
-                    }
-                }
-                OutgoingMessage::Response(Response::Error { id, error }) => {
-                    StreamMessageContent::Response {
-                        id: id.clone(),
-                        result: Err(error.clone()),
-                    }
-                }
-                OutgoingMessage::Notification(Notification { method, params }) => {
-                    StreamMessageContent::Notification {
-                        method: method.clone(),
-                        params: serde_json::to_value(params).ok(),
-                    }
-                }
-            },
-        };
-
-        self.0.try_broadcast(message).ok();
-    }
-
-    /// Broadcasts an incoming request to all receivers.
-    pub(crate) fn incoming_request(
-        &self,
-        id: RequestId,
-        method: impl Into<Arc<str>>,
-        params: &impl Serialize,
-    ) {
-        if self.0.receiver_count() == 0 {
-            return;
-        }
-
-        let message = StreamMessage {
-            direction: StreamMessageDirection::Incoming,
-            message: StreamMessageContent::Request {
-                id,
-                method: method.into(),
-                params: serde_json::to_value(params).ok(),
-            },
-        };
-
-        self.0.try_broadcast(message).ok();
-    }
-
-    /// Broadcasts an incoming response to all receivers.
-    pub(crate) fn incoming_response(
-        &self,
-        id: RequestId,
-        result: Result<Option<&RawValue>, &Error>,
-    ) {
-        if self.0.receiver_count() == 0 {
-            return;
-        }
-
-        let result = match result {
-            Ok(Some(value)) => Ok(serde_json::from_str(value.get()).ok()),
-            Ok(None) => Ok(None),
-            Err(err) => Err(err.clone()),
-        };
-
-        let message = StreamMessage {
-            direction: StreamMessageDirection::Incoming,
-            message: StreamMessageContent::Response { id, result },
-        };
-
-        self.0.try_broadcast(message).ok();
-    }
-
-    /// Broadcasts an incoming notification to all receivers.
-    pub(crate) fn incoming_notification(
-        &self,
-        method: impl Into<Arc<str>>,
-        params: &impl Serialize,
-    ) {
-        if self.0.receiver_count() == 0 {
-            return;
-        }
-
-        let message = StreamMessage {
-            direction: StreamMessageDirection::Incoming,
-            message: StreamMessageContent::Notification {
-                method: method.into(),
-                params: serde_json::to_value(params).ok(),
-            },
-        };
-
-        self.0.try_broadcast(message).ok();
-    }
-}
-
-/// A broadcast for observing RPC message streams.
-///
-/// This is used internally by the RPC connection to allow multiple receivers
-/// to observe the message stream.
-#[derive(Debug, Clone)]
-pub(crate) struct StreamBroadcast {
-    receiver: async_broadcast::InactiveReceiver<StreamMessage>,
-}
-
-impl StreamBroadcast {
-    /// Creates a new broadcast.
-    ///
-    /// Returns a sender for broadcasting messages and the broadcast instance
-    /// for creating receivers.
-    pub(crate) fn new() -> (StreamSender, Self) {
-        let (sender, receiver) = async_broadcast::broadcast(1);
-        (
-            sender.into(),
-            Self {
-                receiver: receiver.deactivate(),
-            },
-        )
-    }
-
-    /// Creates a new receiver for observing the message stream.
-    ///
-    /// Each receiver will get its own copy of every message.
-    pub(crate) fn receiver(&self) -> StreamReceiver {
-        let was_empty = self.receiver.receiver_count() == 0;
-        let mut new_receiver = self.receiver.activate_cloned();
-        if was_empty {
-            // Grow capacity once we actually have a receiver
-            new_receiver.set_capacity(64);
-        }
-        new_receiver.into()
-    }
-}
-
-impl<Local: Side, Remote: Side> From<OutgoingMessage<Local, Remote>> for StreamMessage {
-    fn from(message: OutgoingMessage<Local, Remote>) -> Self {
-        Self {
-            direction: StreamMessageDirection::Outgoing,
-            message: match message {
-                OutgoingMessage::Request(Request { id, method, params }) => {
-                    StreamMessageContent::Request {
-                        id,
-                        method,
-                        params: serde_json::to_value(params).ok(),
-                    }
-                }
-                OutgoingMessage::Response(Response::Result { id, result }) => {
-                    StreamMessageContent::Response {
-                        id,
-                        result: Ok(serde_json::to_value(result).ok()),
-                    }
-                }
-                OutgoingMessage::Response(Response::Error { id, error }) => {
-                    StreamMessageContent::Response {
-                        id,
-                        result: Err(error),
-                    }
-                }
-                OutgoingMessage::Notification(Notification { method, params }) => {
-                    StreamMessageContent::Notification {
-                        method,
-                        params: serde_json::to_value(params).ok(),
-                    }
-                }
-            },
-        }
-    }
-}
diff --git a/src/agent-client-protocol-core/src/typed.rs b/src/agent-client-protocol/src/typed.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/typed.rs
rename to src/agent-client-protocol/src/typed.rs
diff --git a/src/agent-client-protocol-core/src/util.rs b/src/agent-client-protocol/src/util.rs
similarity index 100%
rename from src/agent-client-protocol-core/src/util.rs
rename to src/agent-client-protocol/src/util.rs
diff --git a/src/agent-client-protocol-core/src/util/typed.rs b/src/agent-client-protocol/src/util/typed.rs
similarity index 96%
rename from src/agent-client-protocol-core/src/util/typed.rs
rename to src/agent-client-protocol/src/util/typed.rs
index c94e8dd..16dfb49 100644
--- a/src/agent-client-protocol-core/src/util/typed.rs
+++ b/src/agent-client-protocol/src/util/typed.rs
@@ -38,12 +38,12 @@ use crate::{
 /// # Example
 ///
 /// ```
-/// # use agent_client_protocol_core::Dispatch;
-/// # use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, AgentCapabilities};
-/// # use agent_client_protocol_core::util::MatchDispatch;
-/// # async fn example(message: Dispatch) -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::Dispatch;
+/// # use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, AgentCapabilities};
+/// # use agent_client_protocol::util::MatchDispatch;
+/// # async fn example(message: Dispatch) -> Result<(), agent_client_protocol::Error> {
 /// MatchDispatch::new(message)
-///     .if_request(|req: InitializeRequest, responder: agent_client_protocol_core::Responder<InitializeResponse>| async move {
+///     .if_request(|req: InitializeRequest, responder: agent_client_protocol::Responder<InitializeResponse>| async move {
 ///         let response = InitializeResponse::new(req.protocol_version)
 ///             .agent_capabilities(AgentCapabilities::new());
 ///         responder.respond(response)
@@ -52,7 +52,7 @@ use crate::{
 ///     .otherwise(|message| async move {
 ///         match message {
 ///             Dispatch::Request(_, responder) => {
-///                 responder.respond_with_error(agent_client_protocol_core::util::internal_error("unknown method"))
+///                 responder.respond_with_error(agent_client_protocol::util::internal_error("unknown method"))
 ///             }
 ///             Dispatch::Notification(_) | Dispatch::Response(_, _) => Ok(()),
 ///         }
@@ -430,19 +430,19 @@ impl MatchDispatch {
 /// # Example
 ///
 /// ```
-/// # use agent_client_protocol_core::Dispatch;
-/// # use agent_client_protocol_core::schema::{InitializeRequest, InitializeResponse, PromptRequest, PromptResponse, AgentCapabilities, StopReason};
-/// # use agent_client_protocol_core::util::MatchDispatchFrom;
-/// # async fn example(message: Dispatch, cx: &agent_client_protocol_core::ConnectionTo<agent_client_protocol_core::Client>) -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::Dispatch;
+/// # use agent_client_protocol::schema::{InitializeRequest, InitializeResponse, PromptRequest, PromptResponse, AgentCapabilities, StopReason};
+/// # use agent_client_protocol::util::MatchDispatchFrom;
+/// # async fn example(message: Dispatch, cx: &agent_client_protocol::ConnectionTo<agent_client_protocol::Client>) -> Result<(), agent_client_protocol::Error> {
 /// MatchDispatchFrom::new(message, cx)
-///     .if_request(|req: InitializeRequest, responder: agent_client_protocol_core::Responder<InitializeResponse>| async move {
+///     .if_request(|req: InitializeRequest, responder: agent_client_protocol::Responder<InitializeResponse>| async move {
 ///         // Handle initialization
 ///         let response = InitializeResponse::new(req.protocol_version)
 ///             .agent_capabilities(AgentCapabilities::new());
 ///         responder.respond(response)
 ///     })
 ///     .await
-///     .if_request(|_req: PromptRequest, responder: agent_client_protocol_core::Responder<PromptResponse>| async move {
+///     .if_request(|_req: PromptRequest, responder: agent_client_protocol::Responder<PromptResponse>| async move {
 ///         // Handle prompts
 ///         responder.respond(PromptResponse::new(StopReason::EndTurn))
 ///     })
@@ -450,7 +450,7 @@ impl MatchDispatch {
 ///     .otherwise(|message| async move {
 ///         // Fallback for unrecognized messages
 ///         match message {
-///             Dispatch::Request(_, responder) => responder.respond_with_error(agent_client_protocol_core::util::internal_error("unknown method")),
+///             Dispatch::Request(_, responder) => responder.respond_with_error(agent_client_protocol::util::internal_error("unknown method")),
 ///             Dispatch::Notification(_) | Dispatch::Response(_, _) => Ok(()),
 ///         }
 ///     })
@@ -823,10 +823,10 @@ impl<Counterpart: Role> MatchDispatchFrom<Counterpart> {
 /// # Example
 ///
 /// ```
-/// # use agent_client_protocol_core::{UntypedMessage, ConnectionTo, Agent};
-/// # use agent_client_protocol_core::schema::SessionNotification;
-/// # use agent_client_protocol_core::util::TypeNotification;
-/// # async fn example(message: UntypedMessage, cx: &ConnectionTo<Agent>) -> Result<(), agent_client_protocol_core::Error> {
+/// # use agent_client_protocol::{UntypedMessage, ConnectionTo, Agent};
+/// # use agent_client_protocol::schema::SessionNotification;
+/// # use agent_client_protocol::util::TypeNotification;
+/// # async fn example(message: UntypedMessage, cx: &ConnectionTo<Agent>) -> Result<(), agent_client_protocol::Error> {
 /// TypeNotification::new(message, cx)
 ///     .handle_if(|notif: SessionNotification| async move {
 ///         // Handle session notifications
diff --git a/src/agent-client-protocol-core/tests/derive_macros.rs b/src/agent-client-protocol/tests/derive_macros.rs
similarity index 95%
rename from src/agent-client-protocol-core/tests/derive_macros.rs
rename to src/agent-client-protocol/tests/derive_macros.rs
index a71799d..720dbb4 100644
--- a/src/agent-client-protocol-core/tests/derive_macros.rs
+++ b/src/agent-client-protocol/tests/derive_macros.rs
@@ -1,8 +1,6 @@
 //! Tests for the JsonRpcRequest, JsonRpcNotification, and JsonRpcResponse derive macros.
 
-use agent_client_protocol_core::{
-    JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse,
-};
+use agent_client_protocol::{JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse};
 use serde::{Deserialize, Serialize};
 
 // ============================================================================
@@ -128,6 +126,6 @@ fn test_jr_response_payload_from_value() {
 
 #[test]
 fn test_jr_notification_is_marker() {
-    fn assert_notification<N: agent_client_protocol_core::JsonRpcNotification>() {}
+    fn assert_notification<N: agent_client_protocol::JsonRpcNotification>() {}
     assert_notification::<PingNotification>();
 }
diff --git a/src/agent-client-protocol-core/tests/jsonrpc_advanced.rs b/src/agent-client-protocol/tests/jsonrpc_advanced.rs
similarity index 82%
rename from src/agent-client-protocol-core/tests/jsonrpc_advanced.rs
rename to src/agent-client-protocol/tests/jsonrpc_advanced.rs
index cdec8e9..78de0d0 100644
--- a/src/agent-client-protocol-core/tests/jsonrpc_advanced.rs
+++ b/src/agent-client-protocol/tests/jsonrpc_advanced.rs
@@ -5,7 +5,7 @@
 //! - Request ID tracking and matching
 //! - Out-of-order response handling
 
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     ConnectionTo, JsonRpcMessage, JsonRpcRequest, JsonRpcResponse, Responder, SentRequest,
     role::UntypedRole,
 };
@@ -16,14 +16,14 @@ use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 /// Test helper to block and wait for a JSON-RPC response.
 async fn recv<T: JsonRpcResponse + Send>(
     response: SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 /// Helper to set up test streams for testing.
@@ -64,18 +64,18 @@ impl JsonRpcMessage for PingRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -89,18 +89,15 @@ struct PongResponse {
 }
 
 impl JsonRpcResponse for PongResponse {
-    fn into_json(
-        self,
-        _method: &str,
-    ) -> Result<serde_json::Value, agent_client_protocol_core::Error> {
-        serde_json::to_value(self).map_err(agent_client_protocol_core::Error::into_internal_error)
+    fn into_json(self, _method: &str) -> Result<serde_json::Value, agent_client_protocol::Error> {
+        serde_json::to_value(self).map_err(agent_client_protocol::Error::into_internal_error)
     }
 
     fn from_value(
         _method: &str,
         value: serde_json::Value,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(&value)
+    ) -> Result<Self, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(&value)
     }
 }
 
@@ -121,18 +118,18 @@ impl JsonRpcMessage for SlowRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -146,18 +143,15 @@ struct SlowResponse {
 }
 
 impl JsonRpcResponse for SlowResponse {
-    fn into_json(
-        self,
-        _method: &str,
-    ) -> Result<serde_json::Value, agent_client_protocol_core::Error> {
-        serde_json::to_value(self).map_err(agent_client_protocol_core::Error::into_internal_error)
+    fn into_json(self, _method: &str) -> Result<serde_json::Value, agent_client_protocol::Error> {
+        serde_json::to_value(self).map_err(agent_client_protocol::Error::into_internal_error)
     }
 
     fn from_value(
         _method: &str,
         value: serde_json::Value,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(&value)
+    ) -> Result<Self, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(&value)
     }
 }
 
@@ -177,7 +171,7 @@ async fn test_bidirectional_communication() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let side_a_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let side_a = UntypedRole.builder().on_receive_request(
                 async |request: PingRequest,
                        responder: Responder<PongResponse>,
@@ -186,11 +180,11 @@ async fn test_bidirectional_communication() {
                         value: request.value + 1,
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let side_b_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
 
             // Spawn side_a as server
             tokio::task::spawn_local(async move {
@@ -202,7 +196,7 @@ async fn test_bidirectional_communication() {
                 .builder()
                 .connect_with(
                     side_b_transport,
-                    async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> Result<(), agent_client_protocol::Error> {
                         let request = PingRequest { value: 10 };
                         let response_future = recv(cx.send_request(request));
                         let response: Result<PongResponse, _> = response_future.await;
@@ -236,7 +230,7 @@ async fn test_request_ids() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |request: PingRequest,
                        responder: Responder<PongResponse>,
@@ -245,11 +239,11 @@ async fn test_request_ids() {
                         value: request.value + 1,
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -259,7 +253,7 @@ async fn test_request_ids() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> Result<(), agent_client_protocol::Error> {
                         // Send multiple requests and verify responses match
                         let req1 = PingRequest { value: 1 };
                         let req2 = PingRequest { value: 2 };
@@ -303,7 +297,7 @@ async fn test_out_of_order_responses() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |request: SlowRequest,
                        responder: Responder<SlowResponse>,
@@ -312,11 +306,11 @@ async fn test_out_of_order_responses() {
                     tokio::time::sleep(tokio::time::Duration::from_millis(request.delay_ms)).await;
                     responder.respond(SlowResponse { id: request.id })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -326,7 +320,7 @@ async fn test_out_of_order_responses() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> Result<(), agent_client_protocol::Error> {
                         // Send requests with different delays
                         // Request 1: 100ms delay
                         // Request 2: 50ms delay
diff --git a/src/agent-client-protocol-core/tests/jsonrpc_connection_builder.rs b/src/agent-client-protocol/tests/jsonrpc_connection_builder.rs
similarity index 79%
rename from src/agent-client-protocol-core/tests/jsonrpc_connection_builder.rs
rename to src/agent-client-protocol/tests/jsonrpc_connection_builder.rs
index 8a093bf..b819bfa 100644
--- a/src/agent-client-protocol-core/tests/jsonrpc_connection_builder.rs
+++ b/src/agent-client-protocol/tests/jsonrpc_connection_builder.rs
@@ -9,7 +9,7 @@ use std::{
     time::Duration,
 };
 
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     ConnectTo, ConnectionTo, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse,
     Responder, SentRequest, role::UntypedRole, util::run_until,
 };
@@ -19,14 +19,14 @@ use tokio_util::compat::{TokioAsyncReadCompatExt as _, TokioAsyncWriteCompatExt
 /// Test helper to block and wait for a JSON-RPC response.
 async fn recv<T: JsonRpcResponse + Send>(
     response: SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 // ============================================================================
@@ -49,18 +49,18 @@ impl JsonRpcMessage for FooRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -74,18 +74,15 @@ struct FooResponse {
 }
 
 impl JsonRpcResponse for FooResponse {
-    fn into_json(
-        self,
-        _method: &str,
-    ) -> Result<serde_json::Value, agent_client_protocol_core::Error> {
-        serde_json::to_value(self).map_err(agent_client_protocol_core::Error::into_internal_error)
+    fn into_json(self, _method: &str) -> Result<serde_json::Value, agent_client_protocol::Error> {
+        serde_json::to_value(self).map_err(agent_client_protocol::Error::into_internal_error)
     }
 
     fn from_value(
         _method: &str,
         value: serde_json::Value,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(&value)
+    ) -> Result<Self, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(&value)
     }
 }
 
@@ -105,18 +102,18 @@ impl JsonRpcMessage for BarRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -130,18 +127,15 @@ struct BarResponse {
 }
 
 impl JsonRpcResponse for BarResponse {
-    fn into_json(
-        self,
-        _method: &str,
-    ) -> Result<serde_json::Value, agent_client_protocol_core::Error> {
-        serde_json::to_value(self).map_err(agent_client_protocol_core::Error::into_internal_error)
+    fn into_json(self, _method: &str) -> Result<serde_json::Value, agent_client_protocol::Error> {
+        serde_json::to_value(self).map_err(agent_client_protocol::Error::into_internal_error)
     }
 
     fn from_value(
         _method: &str,
         value: serde_json::Value,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(&value)
+    ) -> Result<Self, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(&value)
     }
 }
 
@@ -163,7 +157,7 @@ async fn test_multiple_handlers_different_methods() {
 
             // Chain both handlers
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole
                 .builder()
                 .on_receive_request(
@@ -174,7 +168,7 @@ async fn test_multiple_handlers_different_methods() {
                             result: format!("foo: {}", request.value),
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 )
                 .on_receive_request(
                     async |request: BarRequest,
@@ -184,10 +178,10 @@ async fn test_multiple_handlers_different_methods() {
                             result: format!("bar: {}", request.value),
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 );
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -199,15 +193,15 @@ async fn test_multiple_handlers_different_methods() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         // Test foo request
                         let foo_response = recv(cx.send_request(FooRequest {
                             value: "test1".to_string(),
                         }))
                         .await
                         .map_err(
-                            |e| -> agent_client_protocol_core::Error {
-                                agent_client_protocol_core::util::internal_error(format!(
+                            |e| -> agent_client_protocol::Error {
+                                agent_client_protocol::util::internal_error(format!(
                                     "Foo request failed: {e:?}"
                                 ))
                             },
@@ -220,8 +214,8 @@ async fn test_multiple_handlers_different_methods() {
                         }))
                         .await
                         .map_err(
-                            |e| -> agent_client_protocol_core::Error {
-                                agent_client_protocol_core::util::internal_error(format!(
+                            |e| -> agent_client_protocol::Error {
+                                agent_client_protocol::util::internal_error(format!(
                                     "Bar request failed: {e:?}"
                                 ))
                             },
@@ -258,18 +252,18 @@ impl JsonRpcMessage for TrackRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -299,7 +293,7 @@ async fn test_handler_priority_ordering() {
             let handled_clone1 = handled.clone();
             let handled_clone2 = handled.clone();
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole
                 .builder()
                 .on_receive_request(
@@ -311,7 +305,7 @@ async fn test_handler_priority_ordering() {
                             result: format!("handler1: {}", request.value),
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 )
                 .on_receive_request(
                     async move |request: TrackRequest,
@@ -322,10 +316,10 @@ async fn test_handler_priority_ordering() {
                             result: format!("handler2: {}", request.value),
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 );
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -337,13 +331,13 @@ async fn test_handler_priority_ordering() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         let response = recv(cx.send_request(TrackRequest {
                             value: "test".to_string(),
                         }))
                         .await
                         .map_err(|e| {
-                            agent_client_protocol_core::util::internal_error(format!(
+                            agent_client_protocol::util::internal_error(format!(
                                 "Track request failed: {e:?}"
                             ))
                         })?;
@@ -386,18 +380,18 @@ impl JsonRpcMessage for Method1Request {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -421,18 +415,18 @@ impl JsonRpcMessage for Method2Request {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -462,7 +456,7 @@ async fn test_fallthrough_behavior() {
             let handled_clone1 = handled.clone();
             let handled_clone2 = handled.clone();
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole
                 .builder()
                 .on_receive_request(
@@ -474,7 +468,7 @@ async fn test_fallthrough_behavior() {
                             result: format!("method1: {}", request.value),
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 )
                 .on_receive_request(
                     async move |request: Method2Request,
@@ -485,10 +479,10 @@ async fn test_fallthrough_behavior() {
                             result: format!("method2: {}", request.value),
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 );
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -500,14 +494,14 @@ async fn test_fallthrough_behavior() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         // Send method2 - should fallthrough handler1 to handler2
                         let response = recv(cx.send_request(Method2Request {
                             value: "fallthrough".to_string(),
                         }))
                         .await
                         .map_err(|e| {
-                            agent_client_protocol_core::util::internal_error(format!(
+                            agent_client_protocol::util::internal_error(format!(
                                 "Method2 request failed: {e:?}"
                             ))
                         })?;
@@ -551,7 +545,7 @@ async fn test_no_handler_claims() {
 
             // Handler that only handles "foo"
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |request: FooRequest,
                        responder: Responder<FooResponse>,
@@ -560,10 +554,10 @@ async fn test_no_handler_claims() {
                         result: format!("foo: {}", request.value),
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -575,7 +569,7 @@ async fn test_no_handler_claims() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         // Send "bar" request which no handler claims
                         let response_result = recv(cx.send_request(BarRequest {
                             value: "unclaimed".to_string(),
@@ -615,18 +609,18 @@ impl JsonRpcMessage for EventNotification {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -653,17 +647,17 @@ async fn test_handler_claims_notification() {
             // EventHandler claims notifications
             let events_clone = events.clone();
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_notification(
                 async move |notification: EventNotification,
                             _connection: ConnectionTo<UntypedRole>| {
                     events_clone.lock().unwrap().push(notification.event);
                     Ok(())
                 },
-                agent_client_protocol_core::on_receive_notification!(),
+                agent_client_protocol::on_receive_notification!(),
             );
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -675,12 +669,12 @@ async fn test_handler_claims_notification() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         cx.send_notification(EventNotification {
                             event: "test_event".to_string(),
                         })
                         .map_err(|e| {
-                            agent_client_protocol_core::util::internal_error(format!(
+                            agent_client_protocol::util::internal_error(format!(
                                 "Failed to send notification: {e:?}"
                             ))
                         })?;
@@ -707,7 +701,7 @@ async fn test_handler_claims_notification() {
 // ============================================================================
 
 #[tokio::test]
-async fn test_connection_builder_as_component() -> Result<(), agent_client_protocol_core::Error> {
+async fn test_connection_builder_as_component() -> Result<(), agent_client_protocol::Error> {
     // Create duplex streams
     let (server_stream, client_stream) = tokio::io::duplex(8192);
     let (server_read, server_write) = tokio::io::split(server_stream);
@@ -722,18 +716,14 @@ async fn test_connection_builder_as_component() -> Result<(), agent_client_proto
                 result: format!("component: {}", request.value),
             })
         },
-        agent_client_protocol_core::on_receive_request!(),
+        agent_client_protocol::on_receive_request!(),
     );
 
     // Create ByteStreams for both sides
-    let server_transport = agent_client_protocol_core::ByteStreams::new(
-        server_write.compat_write(),
-        server_read.compat(),
-    );
-    let client_transport = agent_client_protocol_core::ByteStreams::new(
-        client_write.compat_write(),
-        client_read.compat(),
-    );
+    let server_transport =
+        agent_client_protocol::ByteStreams::new(server_write.compat_write(), server_read.compat());
+    let client_transport =
+        agent_client_protocol::ByteStreams::new(client_write.compat_write(), client_read.compat());
 
     // Use Builder as a Component via run_until
     run_until(
diff --git a/src/agent-client-protocol-core/tests/jsonrpc_edge_cases.rs b/src/agent-client-protocol/tests/jsonrpc_edge_cases.rs
similarity index 83%
rename from src/agent-client-protocol-core/tests/jsonrpc_edge_cases.rs
rename to src/agent-client-protocol/tests/jsonrpc_edge_cases.rs
index 785e583..5ed92c3 100644
--- a/src/agent-client-protocol-core/tests/jsonrpc_edge_cases.rs
+++ b/src/agent-client-protocol/tests/jsonrpc_edge_cases.rs
@@ -6,7 +6,7 @@
 //! - Server shutdown scenarios
 //! - Client disconnect handling
 
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     ConnectionTo, JsonRpcMessage, JsonRpcRequest, JsonRpcResponse, Responder, SentRequest,
     role::UntypedRole,
 };
@@ -17,14 +17,14 @@ use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 /// Test helper to block and wait for a JSON-RPC response.
 async fn recv<T: JsonRpcResponse + Send>(
     response: SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 /// Helper to set up test streams.
@@ -63,16 +63,16 @@ impl JsonRpcMessage for EmptyRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         _params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
         Ok(EmptyRequest)
     }
@@ -99,18 +99,18 @@ impl JsonRpcMessage for OptionalParamsRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -124,18 +124,15 @@ struct SimpleResponse {
 }
 
 impl JsonRpcResponse for SimpleResponse {
-    fn into_json(
-        self,
-        _method: &str,
-    ) -> Result<serde_json::Value, agent_client_protocol_core::Error> {
-        serde_json::to_value(self).map_err(agent_client_protocol_core::Error::into_internal_error)
+    fn into_json(self, _method: &str) -> Result<serde_json::Value, agent_client_protocol::Error> {
+        serde_json::to_value(self).map_err(agent_client_protocol::Error::into_internal_error)
     }
 
     fn from_value(
         _method: &str,
         value: serde_json::Value,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(&value)
+    ) -> Result<Self, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(&value)
     }
 }
 
@@ -154,7 +151,7 @@ async fn test_empty_request() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |_request: EmptyRequest,
                        responder: Responder<SimpleResponse>,
@@ -163,11 +160,11 @@ async fn test_empty_request() {
                         result: "Got empty request".to_string(),
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -177,7 +174,7 @@ async fn test_empty_request() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> Result<(), agent_client_protocol::Error> {
                         let request = EmptyRequest;
 
                         let result: Result<SimpleResponse, _> =
@@ -213,7 +210,7 @@ async fn test_null_params() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |_request: OptionalParamsRequest,
                        responder: Responder<SimpleResponse>,
@@ -222,11 +219,11 @@ async fn test_null_params() {
                         result: "Has params: true".to_string(),
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -236,7 +233,7 @@ async fn test_null_params() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> Result<(), agent_client_protocol::Error> {
                         let request = OptionalParamsRequest { value: None };
 
                         let result: Result<SimpleResponse, _> =
@@ -269,7 +266,7 @@ async fn test_server_shutdown() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |_request: EmptyRequest,
                        responder: Responder<SimpleResponse>,
@@ -278,11 +275,11 @@ async fn test_server_shutdown() {
                         result: "Got empty request".to_string(),
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             let server_handle = tokio::task::spawn_local(async move {
@@ -293,7 +290,7 @@ async fn test_server_shutdown() {
                 client
                     .connect_with(
                         client_transport,
-                        async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                        async |cx| -> Result<(), agent_client_protocol::Error> {
                             let request = EmptyRequest;
 
                             // Send request and get future for response
@@ -346,7 +343,7 @@ async fn test_client_disconnect() {
             let server_writer = server_writer.compat_write();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |_request: EmptyRequest,
                        responder: Responder<SimpleResponse>,
@@ -355,7 +352,7 @@ async fn test_client_disconnect() {
                         result: "Got empty request".to_string(),
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             tokio::task::spawn_local(async move {
diff --git a/src/agent-client-protocol-core/tests/jsonrpc_error_handling.rs b/src/agent-client-protocol/tests/jsonrpc_error_handling.rs
similarity index 86%
rename from src/agent-client-protocol-core/tests/jsonrpc_error_handling.rs
rename to src/agent-client-protocol/tests/jsonrpc_error_handling.rs
index 2d7090a..ae23fc1 100644
--- a/src/agent-client-protocol-core/tests/jsonrpc_error_handling.rs
+++ b/src/agent-client-protocol/tests/jsonrpc_error_handling.rs
@@ -7,7 +7,7 @@
 //! - Serialization failures
 //! - Missing/invalid parameters
 
-use agent_client_protocol_core::{
+use agent_client_protocol::{
     ConnectionTo, JsonRpcMessage, JsonRpcRequest, JsonRpcResponse, Responder, SentRequest,
     role::UntypedRole,
 };
@@ -19,14 +19,14 @@ use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 /// Test helper to block and wait for a JSON-RPC response.
 async fn recv<T: JsonRpcResponse + Send>(
     response: SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 /// Helper to set up test streams.
@@ -67,18 +67,18 @@ impl JsonRpcMessage for SimpleRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast_params(params)
+        agent_client_protocol::util::json_cast_params(params)
     }
 }
 
@@ -92,18 +92,15 @@ struct SimpleResponse {
 }
 
 impl JsonRpcResponse for SimpleResponse {
-    fn into_json(
-        self,
-        _method: &str,
-    ) -> Result<serde_json::Value, agent_client_protocol_core::Error> {
-        serde_json::to_value(self).map_err(agent_client_protocol_core::Error::into_internal_error)
+    fn into_json(self, _method: &str) -> Result<serde_json::Value, agent_client_protocol::Error> {
+        serde_json::to_value(self).map_err(agent_client_protocol::Error::into_internal_error)
     }
 
     fn from_value(
         _method: &str,
         value: serde_json::Value,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(&value)
+    ) -> Result<Self, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(&value)
     }
 }
 
@@ -123,22 +120,22 @@ impl JsonRpcMessage for SimpleNotification {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast_params(params)
+        agent_client_protocol::util::json_cast_params(params)
     }
 }
 
-impl agent_client_protocol_core::JsonRpcNotification for SimpleNotification {}
+impl agent_client_protocol::JsonRpcNotification for SimpleNotification {}
 
 // ============================================================================
 // Test 1: Invalid JSON (complete line with parse error)
@@ -162,7 +159,7 @@ async fn test_invalid_json() {
 
             // No handlers - all requests will return errors
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder();
 
             // Spawn server
@@ -216,7 +213,7 @@ async fn test_incomplete_line() {
     let output = Cursor::new(Vec::new());
 
     // No handlers needed for EOF test
-    let transport = agent_client_protocol_core::ByteStreams::new(output, input);
+    let transport = agent_client_protocol::ByteStreams::new(output, input);
     let connection = UntypedRole.builder();
 
     // The server should handle EOF mid-message gracefully
@@ -242,10 +239,10 @@ async fn test_unknown_method() {
 
             // No handlers - all requests will be "method not found"
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder();
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             // Spawn server
@@ -257,7 +254,7 @@ async fn test_unknown_method() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> Result<(), agent_client_protocol::Error> {
                         let request = SimpleRequest {
                             message: "test".to_string(),
                         };
@@ -271,7 +268,7 @@ async fn test_unknown_method() {
                             // Should be "method not found" or similar error
                             assert!(matches!(
                                 err.code,
-                                agent_client_protocol_core::ErrorCode::MethodNotFound
+                                agent_client_protocol::ErrorCode::MethodNotFound
                             ));
                         }
                         Ok(())
@@ -304,18 +301,18 @@ impl JsonRpcMessage for ErrorRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast_params(params)
+        agent_client_protocol::util::json_cast_params(params)
     }
 }
 
@@ -334,20 +331,19 @@ async fn test_handler_returns_error() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |_request: ErrorRequest,
                        responder: Responder<SimpleResponse>,
                        _connection: ConnectionTo<UntypedRole>| {
                     // Explicitly return an error
-                    responder
-                        .respond_with_error(agent_client_protocol_core::Error::internal_error())
+                    responder.respond_with_error(agent_client_protocol::Error::internal_error())
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -357,7 +353,7 @@ async fn test_handler_returns_error() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> Result<(), agent_client_protocol::Error> {
                         let request = ErrorRequest {
                             value: "trigger error".to_string(),
                         };
@@ -370,7 +366,7 @@ async fn test_handler_returns_error() {
                         if let Err(err) = result {
                             assert!(matches!(
                                 err.code,
-                                agent_client_protocol_core::ErrorCode::InternalError
+                                agent_client_protocol::ErrorCode::InternalError
                             ));
                         }
                         Ok(())
@@ -401,16 +397,16 @@ impl JsonRpcMessage for EmptyRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         _params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
         Ok(EmptyRequest)
     }
@@ -433,7 +429,7 @@ async fn test_missing_required_params() {
             // Handler that validates params - since EmptyRequest has no params but we're checking
             // against SimpleRequest which requires a message field, this will fail
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |_request: EmptyRequest,
                        responder: Responder<SimpleResponse>,
@@ -443,14 +439,13 @@ async fn test_missing_required_params() {
                     // But with the new API, EmptyRequest parses successfully since it expects no params
                     // We need to manually check - but actually the parse_request for EmptyRequest
                     // accepts anything for "strict_method", so the error must come from somewhere else
-                    responder
-                        .respond_with_error(agent_client_protocol_core::Error::invalid_params())
+                    responder.respond_with_error(agent_client_protocol::Error::invalid_params())
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -460,7 +455,7 @@ async fn test_missing_required_params() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> Result<(), agent_client_protocol::Error> {
                         // Send request with no params (EmptyRequest has no fields)
                         let request = EmptyRequest;
 
@@ -472,7 +467,7 @@ async fn test_missing_required_params() {
                         if let Err(err) = result {
                             assert!(matches!(
                                 err.code,
-                                agent_client_protocol_core::ErrorCode::InvalidParams
+                                agent_client_protocol::ErrorCode::InvalidParams
                             )); // JSONRPC_INVALID_PARAMS
                         }
                         Ok(())
@@ -506,7 +501,7 @@ async fn test_invalid_params_keeps_connection_alive() {
 
             // Register a handler for SimpleRequest (requires "message" field)
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |request: SimpleRequest,
                        responder: Responder<SimpleResponse>,
@@ -515,7 +510,7 @@ async fn test_invalid_params_keeps_connection_alive() {
                         result: format!("echo: {}", request.message),
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             tokio::task::spawn_local(async move {
@@ -604,7 +599,7 @@ async fn test_bad_request_params_return_invalid_params_and_connection_stays_aliv
             let server_writer = server_writer.compat_write();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |request: SimpleRequest,
                        responder: Responder<SimpleResponse>,
@@ -613,7 +608,7 @@ async fn test_bad_request_params_return_invalid_params_and_connection_stays_aliv
                         result: format!("echo: {}", request.message),
                     })
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             tokio::task::spawn_local(async move {
@@ -695,7 +690,7 @@ async fn test_bad_notification_params_send_error_notification_and_connection_sta
             let server_writer = server_writer.compat_write();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole
                 .builder()
                 .on_receive_notification(
@@ -704,7 +699,7 @@ async fn test_bad_notification_params_send_error_notification_and_connection_sta
                         // If we get here, the notification parsed successfully.
                         Ok(())
                     },
-                    agent_client_protocol_core::on_receive_notification!(),
+                    agent_client_protocol::on_receive_notification!(),
                 )
                 .on_receive_request(
                     async |request: SimpleRequest,
@@ -714,7 +709,7 @@ async fn test_bad_notification_params_send_error_notification_and_connection_sta
                             result: format!("echo: {}", request.message),
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 );
 
             tokio::task::spawn_local(async move {
diff --git a/src/agent-client-protocol-core/tests/jsonrpc_hello.rs b/src/agent-client-protocol/tests/jsonrpc_hello.rs
similarity index 80%
rename from src/agent-client-protocol-core/tests/jsonrpc_hello.rs
rename to src/agent-client-protocol/tests/jsonrpc_hello.rs
index aa62eb6..f454b7e 100644
--- a/src/agent-client-protocol-core/tests/jsonrpc_hello.rs
+++ b/src/agent-client-protocol/tests/jsonrpc_hello.rs
@@ -3,8 +3,8 @@
 //! This test sets up two JSON-RPC connections and verifies they can
 //! exchange simple "hello world" messages.
 
-use agent_client_protocol_core::role::UntypedRole;
-use agent_client_protocol_core::{
+use agent_client_protocol::role::UntypedRole;
+use agent_client_protocol::{
     ConnectionTo, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, Responder,
     SentRequest,
 };
@@ -17,14 +17,14 @@ use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
 /// Test helper to block and wait for a JSON-RPC response.
 async fn recv<T: JsonRpcResponse + Send>(
     response: SentRequest<T>,
-) -> Result<T, agent_client_protocol_core::Error> {
+) -> Result<T, agent_client_protocol::Error> {
     let (tx, rx) = tokio::sync::oneshot::channel();
     response.on_receiving_result(async move |result| {
         tx.send(result)
-            .map_err(|_| agent_client_protocol_core::Error::internal_error())
+            .map_err(|_| agent_client_protocol::Error::internal_error())
     })?;
     rx.await
-        .map_err(|_| agent_client_protocol_core::Error::internal_error())?
+        .map_err(|_| agent_client_protocol::Error::internal_error())?
 }
 
 /// Helper to set up a client-server pair for testing.
@@ -63,18 +63,18 @@ impl JsonRpcMessage for PingRequest {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -89,18 +89,15 @@ struct PongResponse {
 }
 
 impl JsonRpcResponse for PongResponse {
-    fn into_json(
-        self,
-        _method: &str,
-    ) -> Result<serde_json::Value, agent_client_protocol_core::Error> {
-        serde_json::to_value(self).map_err(agent_client_protocol_core::Error::into_internal_error)
+    fn into_json(self, _method: &str) -> Result<serde_json::Value, agent_client_protocol::Error> {
+        serde_json::to_value(self).map_err(agent_client_protocol::Error::into_internal_error)
     }
 
     fn from_value(
         _method: &str,
         value: serde_json::Value,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(&value)
+    ) -> Result<Self, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(&value)
     }
 }
 
@@ -115,7 +112,7 @@ async fn test_hello_world() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async move |request: PingRequest,
                             responder: Responder<PongResponse>,
@@ -125,11 +122,11 @@ async fn test_hello_world() {
                     };
                     responder.respond(pong)
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             // Spawn the server in the background
@@ -143,13 +140,13 @@ async fn test_hello_world() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         let request = PingRequest {
                             message: "hello world".to_string(),
                         };
 
                         let response = recv(cx.send_request(request)).await.map_err(|e| {
-                            agent_client_protocol_core::util::internal_error(format!(
+                            agent_client_protocol::util::internal_error(format!(
                                 "Request failed: {e:?}"
                             ))
                         })?;
@@ -183,18 +180,18 @@ impl JsonRpcMessage for LogNotification {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::UntypedMessage::new(self.method(), self)
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        agent_client_protocol::UntypedMessage::new(self.method(), self)
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !Self::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
@@ -214,7 +211,7 @@ async fn test_notification() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_notification(
                 {
                     let logs = logs_clone.clone();
@@ -223,11 +220,11 @@ async fn test_notification() {
                         Ok(())
                     }
                 },
-                agent_client_protocol_core::on_receive_notification!(),
+                agent_client_protocol::on_receive_notification!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -239,13 +236,13 @@ async fn test_notification() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         // Send a notification (no response expected)
                         cx.send_notification(LogNotification {
                             message: "test log 1".to_string(),
                         })
                         .map_err(|e| {
-                            agent_client_protocol_core::util::internal_error(format!(
+                            agent_client_protocol::util::internal_error(format!(
                                 "Failed to send notification: {e:?}"
                             ))
                         })?;
@@ -254,7 +251,7 @@ async fn test_notification() {
                             message: "test log 2".to_string(),
                         })
                         .map_err(|e| {
-                            agent_client_protocol_core::util::internal_error(format!(
+                            agent_client_protocol::util::internal_error(format!(
                                 "Failed to send notification: {e:?}"
                             ))
                         })?;
@@ -288,7 +285,7 @@ async fn test_multiple_sequential_requests() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |request: PingRequest,
                        responder: Responder<PongResponse>,
@@ -298,11 +295,11 @@ async fn test_multiple_sequential_requests() {
                     };
                     responder.respond(pong)
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -314,7 +311,7 @@ async fn test_multiple_sequential_requests() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         // Send multiple requests sequentially
                         for i in 1..=5 {
                             let request = PingRequest {
@@ -322,7 +319,7 @@ async fn test_multiple_sequential_requests() {
                             };
 
                             let response = recv(cx.send_request(request)).await.map_err(|e| {
-                                agent_client_protocol_core::util::internal_error(format!(
+                                agent_client_protocol::util::internal_error(format!(
                                     "Request {i} failed: {e:?}"
                                 ))
                             })?;
@@ -351,7 +348,7 @@ async fn test_concurrent_requests() {
             let (server_reader, server_writer, client_reader, client_writer) = setup_test_streams();
 
             let server_transport =
-                agent_client_protocol_core::ByteStreams::new(server_writer, server_reader);
+                agent_client_protocol::ByteStreams::new(server_writer, server_reader);
             let server = UntypedRole.builder().on_receive_request(
                 async |request: PingRequest,
                        responder: Responder<PongResponse>,
@@ -361,11 +358,11 @@ async fn test_concurrent_requests() {
                     };
                     responder.respond(pong)
                 },
-                agent_client_protocol_core::on_receive_request!(),
+                agent_client_protocol::on_receive_request!(),
             );
 
             let client_transport =
-                agent_client_protocol_core::ByteStreams::new(client_writer, client_reader);
+                agent_client_protocol::ByteStreams::new(client_writer, client_reader);
             let client = UntypedRole.builder();
 
             tokio::task::spawn_local(async move {
@@ -377,7 +374,7 @@ async fn test_concurrent_requests() {
             let result = client
                 .connect_with(
                     client_transport,
-                    async |cx| -> std::result::Result<(), agent_client_protocol_core::Error> {
+                    async |cx| -> std::result::Result<(), agent_client_protocol::Error> {
                         // Send multiple requests concurrently
                         let mut responses = Vec::new();
 
@@ -393,7 +390,7 @@ async fn test_concurrent_requests() {
                         // Now await all responses
                         for (i, response_future) in responses {
                             let response = recv(response_future).await.map_err(|e| {
-                                agent_client_protocol_core::util::internal_error(format!(
+                                agent_client_protocol::util::internal_error(format!(
                                     "Request {i} failed: {e:?}"
                                 ))
                             })?;
diff --git a/src/agent-client-protocol-core/tests/match_dispatch.rs b/src/agent-client-protocol/tests/match_dispatch.rs
similarity index 82%
rename from src/agent-client-protocol-core/tests/match_dispatch.rs
rename to src/agent-client-protocol/tests/match_dispatch.rs
index b11b73c..635e3d4 100644
--- a/src/agent-client-protocol-core/tests/match_dispatch.rs
+++ b/src/agent-client-protocol/tests/match_dispatch.rs
@@ -1,7 +1,7 @@
-use agent_client_protocol_core::Role;
-use agent_client_protocol_core::role::UntypedRole;
-use agent_client_protocol_core::util::MatchDispatch;
-use agent_client_protocol_core::{
+use agent_client_protocol::Role;
+use agent_client_protocol::role::UntypedRole;
+use agent_client_protocol::util::MatchDispatch;
+use agent_client_protocol::{
     ConnectTo, ConnectionTo, Dispatch, HandleDispatchFrom, Handled, JsonRpcMessage, JsonRpcRequest,
     JsonRpcResponse, Responder, util::MatchDispatchFrom,
 };
@@ -23,37 +23,34 @@ impl JsonRpcMessage for EchoRequestResponse {
 
     fn to_untyped_message(
         &self,
-    ) -> Result<agent_client_protocol_core::UntypedMessage, agent_client_protocol_core::Error> {
-        Ok(agent_client_protocol_core::UntypedMessage {
+    ) -> Result<agent_client_protocol::UntypedMessage, agent_client_protocol::Error> {
+        Ok(agent_client_protocol::UntypedMessage {
             method: self.method().to_string(),
-            params: agent_client_protocol_core::util::json_cast(self)?,
+            params: agent_client_protocol::util::json_cast(self)?,
         })
     }
 
     fn parse_message(
         method: &str,
         params: &impl serde::Serialize,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
+    ) -> Result<Self, agent_client_protocol::Error> {
         if !<Self as JsonRpcMessage>::matches_method(method) {
-            return Err(agent_client_protocol_core::Error::method_not_found());
+            return Err(agent_client_protocol::Error::method_not_found());
         }
-        agent_client_protocol_core::util::json_cast(params)
+        agent_client_protocol::util::json_cast(params)
     }
 }
 
 impl JsonRpcResponse for EchoRequestResponse {
-    fn into_json(
-        self,
-        _method: &str,
-    ) -> Result<serde_json::Value, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(self)
+    fn into_json(self, _method: &str) -> Result<serde_json::Value, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(self)
     }
 
     fn from_value(
         _method: &str,
         value: serde_json::Value,
-    ) -> Result<Self, agent_client_protocol_core::Error> {
-        agent_client_protocol_core::util::json_cast(value)
+    ) -> Result<Self, agent_client_protocol::Error> {
+        agent_client_protocol::util::json_cast(value)
     }
 }
 
@@ -68,7 +65,7 @@ impl<Counterpart: Role> HandleDispatchFrom<Counterpart> for EchoHandler {
         &mut self,
         message: Dispatch,
         _connection: ConnectionTo<Counterpart>,
-    ) -> Result<Handled<Dispatch>, agent_client_protocol_core::Error> {
+    ) -> Result<Handled<Dispatch>, agent_client_protocol::Error> {
         MatchDispatch::new(message)
             .if_request(async move |request: EchoRequestResponse, responder| {
                 responder.respond(request)
@@ -83,7 +80,7 @@ impl<Counterpart: Role> HandleDispatchFrom<Counterpart> for EchoHandler {
 }
 
 #[tokio::test]
-async fn modify_message_en_route() -> Result<(), agent_client_protocol_core::Error> {
+async fn modify_message_en_route() -> Result<(), agent_client_protocol::Error> {
     // Demonstrate a case where we modify a message
     // using a `HandleDispatchFrom` invoked from `MatchDispatch`
 
@@ -93,7 +90,7 @@ async fn modify_message_en_route() -> Result<(), agent_client_protocol_core::Err
         async fn connect_to(
             self,
             client: impl ConnectTo<UntypedRole>,
-        ) -> Result<(), agent_client_protocol_core::Error> {
+        ) -> Result<(), agent_client_protocol::Error> {
             UntypedRole
                 .builder()
                 .with_handler(PushHandler {
@@ -114,7 +111,7 @@ async fn modify_message_en_route() -> Result<(), agent_client_protocol_core::Err
             &mut self,
             message: Dispatch,
             cx: ConnectionTo<UntypedRole>,
-        ) -> Result<Handled<Dispatch>, agent_client_protocol_core::Error> {
+        ) -> Result<Handled<Dispatch>, agent_client_protocol::Error> {
             MatchDispatchFrom::new(message, &cx)
                 .if_request(async move |mut request: EchoRequestResponse, responder| {
                     request.text.push(self.message.clone());
@@ -157,7 +154,7 @@ async fn modify_message_en_route() -> Result<(), agent_client_protocol_core::Err
 }
 
 #[tokio::test]
-async fn modify_message_en_route_inline() -> Result<(), agent_client_protocol_core::Error> {
+async fn modify_message_en_route_inline() -> Result<(), agent_client_protocol::Error> {
     // Demonstrate a case where we modify a message en route using an `on_receive_request` call
 
     struct TestComponent;
@@ -166,7 +163,7 @@ async fn modify_message_en_route_inline() -> Result<(), agent_client_protocol_co
         async fn connect_to(
             self,
             client: impl ConnectTo<UntypedRole>,
-        ) -> Result<(), agent_client_protocol_core::Error> {
+        ) -> Result<(), agent_client_protocol::Error> {
             UntypedRole
                 .builder()
                 .on_receive_request(
@@ -179,7 +176,7 @@ async fn modify_message_en_route_inline() -> Result<(), agent_client_protocol_co
                             retry: false,
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 )
                 .with_handler(EchoHandler)
                 .connect_to(client)
@@ -212,7 +209,7 @@ async fn modify_message_en_route_inline() -> Result<(), agent_client_protocol_co
 }
 
 #[tokio::test]
-async fn modify_message_and_stop() -> Result<(), agent_client_protocol_core::Error> {
+async fn modify_message_and_stop() -> Result<(), agent_client_protocol::Error> {
     // Demonstrate a case where we have an async handler that just returns `()`
     // in front (and hence we never see the `'b`).
 
@@ -222,7 +219,7 @@ async fn modify_message_and_stop() -> Result<(), agent_client_protocol_core::Err
         async fn connect_to(
             self,
             client: impl ConnectTo<UntypedRole>,
-        ) -> Result<(), agent_client_protocol_core::Error> {
+        ) -> Result<(), agent_client_protocol::Error> {
             UntypedRole
                 .builder()
                 .on_receive_request(
@@ -231,7 +228,7 @@ async fn modify_message_and_stop() -> Result<(), agent_client_protocol_core::Err
                                 _connection: ConnectionTo<UntypedRole>| {
                         responder.respond(request)
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 )
                 .on_receive_request(
                     async move |mut request: EchoRequestResponse,
@@ -243,7 +240,7 @@ async fn modify_message_and_stop() -> Result<(), agent_client_protocol_core::Err
                             retry: false,
                         })
                     },
-                    agent_client_protocol_core::on_receive_request!(),
+                    agent_client_protocol::on_receive_request!(),
                 )
                 .with_handler(EchoHandler)
                 .connect_to(client)
diff --git a/src/yopo/Cargo.toml b/src/yopo/Cargo.toml
index 99df2d3..9746bd4 100644
--- a/src/yopo/Cargo.toml
+++ b/src/yopo/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "agent-client-protocol-yopo"
-version = "0.1.0"
+version = "0.11.0"
 edition.workspace = true
 authors.workspace = true
 license.workspace = true
@@ -18,7 +18,7 @@ name = "yopo"
 path = "src/main.rs"
 
 [dependencies]
-agent-client-protocol-core.workspace = true
+agent-client-protocol.workspace = true
 agent-client-protocol-tokio.workspace = true
 clap.workspace = true
 tokio.workspace = true
diff --git a/src/yopo/src/lib.rs b/src/yopo/src/lib.rs
index 4bac474..e3a382d 100644
--- a/src/yopo/src/lib.rs
+++ b/src/yopo/src/lib.rs
@@ -2,13 +2,13 @@
 //!
 //! Provides a convenient API for running one-shot prompts against ACP components.
 
-use agent_client_protocol_core::schema::{
+use agent_client_protocol::schema::{
     AudioContent, ContentBlock, EmbeddedResourceResource, ImageContent, InitializeRequest,
     ProtocolVersion, RequestPermissionOutcome, RequestPermissionRequest, RequestPermissionResponse,
     SelectedPermissionOutcome, SessionNotification, TextContent,
 };
-use agent_client_protocol_core::util::MatchDispatch;
-use agent_client_protocol_core::{Agent, Client, ConnectTo, Dispatch, Handled, UntypedMessage};
+use agent_client_protocol::util::MatchDispatch;
+use agent_client_protocol::{Agent, Client, ConnectTo, Dispatch, Handled, UntypedMessage};
 use std::path::PathBuf;
 
 /// Converts a `ContentBlock` to its string representation.
@@ -24,7 +24,7 @@ use std::path::PathBuf;
 ///
 /// ```no_run
 /// use yopo::content_block_to_string;
-/// use agent_client_protocol_core::schema::{ContentBlock, TextContent};
+/// use agent_client_protocol::schema::{ContentBlock, TextContent};
 ///
 /// let block = ContentBlock::Text(TextContent::new("Hello".to_string()));
 /// assert_eq!(content_block_to_string(&block), "Hello");
@@ -70,7 +70,7 @@ pub fn content_block_to_string(block: &ContentBlock) -> String {
 /// use agent_client_protocol_tokio::AcpAgent;
 /// use std::str::FromStr;
 ///
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// let agent = AcpAgent::from_str("python agent.py")?;
 /// prompt_with_callback(agent, "What is 2+2?", async |block| {
 ///     print!("{}", content_block_to_string(&block));
@@ -82,7 +82,7 @@ pub async fn prompt_with_callback(
     component: impl ConnectTo<Client>,
     prompt_text: impl ToString,
     mut callback: impl AsyncFnMut(ContentBlock) + Send,
-) -> Result<(), agent_client_protocol_core::Error> {
+) -> Result<(), agent_client_protocol::Error> {
     // Convert prompt to String
     let prompt_text = prompt_text.to_string();
 
@@ -97,9 +97,9 @@ pub async fn prompt_with_callback(
                     retry: false,
                 })
             },
-            agent_client_protocol_core::on_receive_dispatch!(),
+            agent_client_protocol::on_receive_dispatch!(),
         )
-        .connect_with(component, |cx: agent_client_protocol_core::ConnectionTo<Agent>| async move {
+        .connect_with(component, |cx: agent_client_protocol::ConnectionTo<Agent>| async move {
             // Initialize the agent
             let _init_response = cx
                 .send_request(InitializeRequest::new(ProtocolVersion::V1))
@@ -117,7 +117,7 @@ pub async fn prompt_with_callback(
             loop {
                 let update = session.read_update().await?;
                 match update {
-                    agent_client_protocol_core::SessionMessage::SessionMessage(message) => {
+                    agent_client_protocol::SessionMessage::SessionMessage(message) => {
                         MatchDispatch::new(message)
                             .if_notification(async |notification: SessionNotification| {
                                 tracing::debug!(
@@ -125,7 +125,7 @@ pub async fn prompt_with_callback(
                                     "yopo: received SessionNotification"
                                 );
                                 // Call the callback for each agent message chunk
-                                if let agent_client_protocol_core::schema::SessionUpdate::AgentMessageChunk(
+                                if let agent_client_protocol::schema::SessionUpdate::AgentMessageChunk(
                                     content_chunk,
                                 ) = notification.update
                                 {
@@ -141,10 +141,10 @@ pub async fn prompt_with_callback(
                                     .options
                                     .iter()
                                     .find(|option| match option.kind {
-                                        agent_client_protocol_core::schema::PermissionOptionKind::AllowOnce
-                                        | agent_client_protocol_core::schema::PermissionOptionKind::AllowAlways => true,
-                                        agent_client_protocol_core::schema::PermissionOptionKind::RejectOnce
-                                        | agent_client_protocol_core::schema::PermissionOptionKind::RejectAlways
+                                        agent_client_protocol::schema::PermissionOptionKind::AllowOnce
+                                        | agent_client_protocol::schema::PermissionOptionKind::AllowAlways => true,
+                                        agent_client_protocol::schema::PermissionOptionKind::RejectOnce
+                                        | agent_client_protocol::schema::PermissionOptionKind::RejectAlways
                                         | _ => false,
                                     })
                                     .map_or(RequestPermissionOutcome::Cancelled, |option| {
@@ -163,12 +163,12 @@ pub async fn prompt_with_callback(
                             .otherwise(async |_msg| Ok(()))
                             .await?;
                     }
-                    agent_client_protocol_core::SessionMessage::StopReason(stop_reason) => match stop_reason {
-                        agent_client_protocol_core::schema::StopReason::EndTurn => break,
-                        agent_client_protocol_core::schema::StopReason::MaxTokens => todo!(),
-                        agent_client_protocol_core::schema::StopReason::MaxTurnRequests => todo!(),
-                        agent_client_protocol_core::schema::StopReason::Refusal => todo!(),
-                        agent_client_protocol_core::schema::StopReason::Cancelled => todo!(),
+                    agent_client_protocol::SessionMessage::StopReason(stop_reason) => match stop_reason {
+                        agent_client_protocol::schema::StopReason::EndTurn => break,
+                        agent_client_protocol::schema::StopReason::MaxTokens => todo!(),
+                        agent_client_protocol::schema::StopReason::MaxTurnRequests => todo!(),
+                        agent_client_protocol::schema::StopReason::Refusal => todo!(),
+                        agent_client_protocol::schema::StopReason::Cancelled => todo!(),
                         _ => todo!(),
                     },
                     _ => todo!(),
@@ -203,7 +203,7 @@ pub async fn prompt_with_callback(
 /// use agent_client_protocol_tokio::AcpAgent;
 /// use std::str::FromStr;
 ///
-/// # async fn example() -> Result<(), agent_client_protocol_core::Error> {
+/// # async fn example() -> Result<(), agent_client_protocol::Error> {
 /// let agent = AcpAgent::from_str("python agent.py")?;
 /// let response = prompt(agent, "What is 2+2?").await?;
 /// assert!(response.contains("4"));
@@ -213,7 +213,7 @@ pub async fn prompt_with_callback(
 pub async fn prompt(
     component: impl ConnectTo<Client>,
     prompt_text: impl ToString,
-) -> Result<String, agent_client_protocol_core::Error> {
+) -> Result<String, agent_client_protocol::Error> {
     let mut accumulated_text = String::new();
     prompt_with_callback(component, prompt_text, async |block| {
         let text = content_block_to_string(&block);
