I get to test new Bob features early. Sometimes I also get access to features that are already built but still in stealth testing. ACP was one of them.
The note was short: run bob acp -h.
I opened a terminal. bob --help only lists chat, run, and mcp. The public Bob Shell pages describe the terminal client and the Bob IDE companion. Yet Bob Shell 2.0.1 can already start as an Agent Client Protocol server.
ACP gives editors a standard way to start and control coding agents. With Bob, Zed owns the agent panel, permission dialogs, plans, and diff rendering. Bob keeps control of the agent harness, model connection, project instructions, and command execution. They exchange JSON-RPC messages over standard input and output. Zed works with those structured messages and leaves Bob’s terminal UI alone.
I wanted to see how complete this hidden integration was. After the command worked, I checked permission prompts, inline diffs, plans, session restore, and MCP handoff inside another editor. So I connected Bob to Zed and used one small Java failure to exercise the path end to end.
What I Wanted to Verify
I use a small Java lab with one failing check. The code is deliberately plain because the interesting part is the integration. Two prompts make the behavior visible:
A read-only diagnosis that should run without a permission dialog
A repair that streams a plan, asks before editing and running a command, shows an inline diff, and finishes with a green check
After that, we inspect the ACP handshake and look at session restore, MCP servers, and the flags that remove safety gates.
The process boundary looks like this:
ACP connects the editor to the agent. MCP connects the agent to external tools and context. The ACP architecture keeps those roles separate. An ACP client can still pass its MCP server configuration to the agent when it creates a session.
What You Need
You need an IBM account with Bob access (grab a free trial), or a Bob API key, before the model can answer. I used the following setup:
Bob Shell 2.0.1 available as
bobA current Zed release with custom external-agent support
Java 21 or newer for the small lab
Git
IBM’s Bob Shell installation page covers installation and the BOBSHELL_API_KEY environment variable. Zed documents custom ACP processes under External Agents.
Ask the Installed Binary
For a feature that has no public page, the installed binary is the first source I check. Start with the version on your PATH:
bob --versionThe tested build returns:
2.0.1
commit: e6a3e508Then ask the unlisted command for help:
bob acp -hExpected output:
Usage: bob acp [options]
Start Bob Shell as an Agent Client Protocol server
Options:
--log-level <level> Log level: debug, info, warn, error, silent
(or set BOB_LOG_LEVEL env var)
--trust Trust each workspace opened by this ACP server
--auto-approve Skip ACP permission prompts and approve every tool call
--disable-mcp Disable MCP server initialization
--disable-subagents Disable subagent tool registration
--accept-license Accept the IBM license agreement and continue
-h, --help display help for commandFor a stealth feature, this help is surprisingly complete. Running bob acp directly will still look as if nothing happens because the process waits for JSON-RPC on standard input. The ACP client must start it and speak the protocol.
Review the license before using --accept-license in a non-interactive setup:
bob --show-license acpThe command prints the full paths to IBM’s license, third-party license, and notices files, then exits. The flag --accept-license records acceptance. I only put it into managed bootstrap configuration after the organization or user has reviewed those files.
Give Bob a Predictable Failure
I wanted a failure Bob could understand quickly and repair in one line. Clone the example and enter the lab directory:
git clone https://github.com/myfear/the-main-thread.git
cd the-main-thread/bob-acp-zed/labRun the check once without an agent:
./verify.shIt compiles two Java files and fails with this assertion:
Exception in thread "main" java.lang.AssertionError: expected 32 but got 0The broken implementation is intentionally small:
package dev.mainthread.acp;
public final class TemperatureConverter {
private TemperatureConverter() {
}
public static int celsiusToFahrenheit(int celsius) {
return celsius * 9 / 5;
}
}The formula is missing the Fahrenheit offset. We already know the answer, so any friction from here comes from the ACP integration and its controls. Open bob-acp-zed/lab as the workspace in Zed.
Add Bob to Zed
I used Zed because it supports external ACP agents directly and makes plans, permissions, and diffs visible. Open Zed’s Command Palette and run agent: open settings. Under External Agents, choose Add Agent, then Add Custom Agent. Zed opens the settings file with an agent_servers entry.
Merge this entry into settings.json:
{
"agent_servers": {
"Bob": {
"type": "custom",
"command": "bob",
"args": ["acp"],
"env": {}
}
}
}The type value marks this as a custom ACP server. Zed runs bob acp when you open a Bob thread and communicates through its stdin and stdout. Bob writes diagnostics to stderr, which keeps stdout available for protocol messages.
If Zed reports that it cannot find bob, run this in a terminal:
command -v bobReplace "command": "bob" with the absolute path returned by that command. A macOS application started from Finder may inherit a smaller PATH than your login shell. This explains why a command can work in Terminal and still be missing inside Zed.
Start the First Bob Thread
Open Zed’s Agent Panel, create a new external-agent thread, and select Bob. Zed starts bob acp, sends initialize, and creates a session for the open workspace. Authentication and workspace trust can stop that first session before a prompt reaches the model.
Authenticate Bob
Bob advertises an SSO authentication method during ACP initialization. If BOBSHELL_API_KEY is available to the Bob process, it uses the key and no login is needed. I keep the key in the environment or a secret manager. It does not belong in Zed’s JSON settings.
Without an API key or stored token, session/new returns Authentication required. Zed shows an Authenticate action. Complete SSO in the browser and return to the editor. Bob stores the token, so later ACP sessions on the same machine reuse it.
On a remote or SSH machine without a browser, change the arguments temporarily:
"args": ["acp", "--log-level", "info"]Then run dev: open acp logs from Zed’s Command Palette and copy the login URL from the agent server’s stderr. These logs can contain protocol metadata and task context, so handle them like any other diagnostic output with user data.
Trust the workspace
Bob Shell checks workspace trust separately from tool permissions. An untrusted directory fails session creation with a message similar to this:
Invalid request: Workspace "/path/to/project" is not trusted.Open a terminal in that exact workspace, run Bob Shell interactively, review the project, and choose a trust level:
cd /path/to/project
bobExit the terminal session after trust is recorded, then create the Zed thread again. For a disposable lab, "args": ["acp", "--trust"] also works. That flag trusts every workspace opened by this ACP server, so I keep it out of a permanent Zed configuration and trust real repositories one at a time.
Begin with a Read-Only Prompt
I start with read-only work because it shows the default permission model without changing the repository. Send this prompt:
Read all source and test files in this workspace. Explain why ./verify.sh fails.
Do not run commands and do not edit files.Bob should read TemperatureConverter.java, TemperatureConverterTest.java, and verify.sh, then identify the missing + 32. No permission dialog should appear because Bob’s ACP server lets read-only tools run without asking the client.
This saves a lot of approval clicks. Read access can still send repository content to Bob’s configured model provider. The permission UI controls tool calls; it does not keep model processing local. Zed explains the same ownership model in its external-agent configuration guidance: the external agent owns its runtime, authentication, and provider relationship.
Let Bob Edit and Test
Now I ask Bob for one bounded change in the same thread:
Fix the temperature conversion bug. Start with a short plan. Edit only
src/main/java/dev/mainthread/acp/TemperatureConverter.java, run ./verify.sh,
and summarize the changed line and the test result.Bob’s todo updates arrive as ACP plan updates, so Zed can render the current steps in its plan panel. This showed that ACP was carrying plan state alongside the chat text.
The file edit triggers an ACP permission request. Bob offers Allow once, Always allow, Reject, and Always reject. I choose Allow once for the lab. The two Always decisions last for the current session and are keyed by tool name, which makes them broader than one file or one set of arguments.
The change should arrive as inline diff content with the source location:
- return celsius * 9 / 5;
+ return celsius * 9 / 5 + 32;Bob then asks before the command tool runs ./verify.sh. Choose Allow once again. Bob executes the command in its own shell and streams the tool result back through ACP. The final output should contain:
All checks passedRun the script yourself once more in Zed’s terminal:
./verify.shThis second run gives us an independent check. Bob’s tool output and your direct terminal output should agree.
Inspect the Real Handshake
When a feature is hidden, I inspect what the process advertises. Run dev: open acp logs in Zed and find the initialize response. Bob Shell 2.0.1 identifies itself and negotiates protocol version 1:
{
"protocolVersion": 1,
"agentCapabilities": {
"loadSession": true,
"sessionCapabilities": {
"list": {},
"delete": {},
"resume": {},
"close": {}
},
"promptCapabilities": {
"embeddedContext": true,
"image": true
},
"mcpCapabilities": {
"http": true,
"sse": true
}
},
"agentInfo": {
"name": "bob-shell",
"title": "Bob",
"version": "2.0.1"
}
}The local -h output proves the command exists. The handshake goes further and shows what the running server supports with this client. ACP’s initialization rules require both sides to negotiate the protocol version and advertise optional capabilities before session creation.
Reopen the Session
After a successful prompt turn, Bob sends live session-title and last-activity updates. Close Zed, reopen the same project, and select the Bob thread from the Threads Sidebar. Bob advertises session/resume, so a compatible client can reconnect without replaying messages that are already visible.
Bob also keeps file-based session history in its shared store. In Zed, open Thread History, choose Import Threads, select Bob, and import sessions that are not already present. Zed’s thread-import workflow skips sessions without a working directory and avoids importing the same thread twice.
Bob has two restore methods. session/resume reconnects without replay. session/load gives clients the complete history again, including tool calls, diffs, and the last plan state. A client that already stored the visible thread can use resume and avoid duplicate messages.
Keep Models on the Bob Side
One limit showed up in 2.0.1: Bob does not implement ACP’s session/set_model operation. A generic client model picker cannot switch Bob’s model through the protocol. Use the modes Bob advertises for the session, and keep provider or model configuration on the Bob side.
This follows Zed’s external-agent boundary. The editor owns the thread UI, while Bob owns its model access and native configuration. A model setting for the built-in Zed Agent does not reconfigure Bob.
Give Each MCP Server One Owner
Zed can pass client-configured MCP servers to Bob during session/new. Bob also reads its native MCP configuration unless MCP initialization is disabled. Both paths end inside the Bob session harness, which makes duplicate configuration easy to miss.
Each ACP session creates its own harness, including its configured MCP servers. A local MCP process may therefore start once per active Bob session. Check resource use before opening many parallel threads, especially when an MCP server starts a JVM, a container, or a local model.
I prefer one owner for each server. When an MCP tool is missing, inspect both Zed’s MCP settings and Bob’s native MCP configuration. The Zed MCP documentation confirms that external agents can receive Zed-configured servers while still using their own configuration.
To isolate startup problems, add --disable-mcp to the Bob ACP arguments and start a fresh thread. The flag stops MCP server initialization and shows whether a slow or broken server is blocking the session. Remove it before testing MCP tools.
Use Flags for a Reason
I would start with "args": ["acp"] and add flags only for a concrete reason.
--log-level <level> — Writes Bob diagnostics at debug, info, warn, error, or silent. BOB_LOG_LEVEL sets the same value through the environment. Use info for SSO on a headless machine and debug for protocol startup problems.
--trust — Trusts every workspace this server opens. This removes a project boundary, so it belongs in controlled environments or short-lived labs.
--auto-approve — Approves every tool call and removes ACP permission dialogs. It is broader than choosing Always allow for one tool inside one session.
--disable-mcp — Stops MCP server initialization. Use it to isolate startup and tool-discovery failures.
--disable-subagents — Omits Bob’s subagent tool registration. This reduces the available tool set when the task does not need delegation.
--accept-license — Records license acceptance before server startup. Review the files reported by bob --show-license acp first.
The combination --trust --auto-approve removes both the workspace gate and per-tool approval. A prompt can act in any workspace opened by that server without another human decision. I keep both flags out of the default Zed entry.
Remember That Bob Has Its Own Shell
ACP includes optional client terminal operations, but Bob Shell 2.0.1 executes commands in its own shell and reports the result as a tool update.
This explains a common debugging mismatch. A command may work in Zed’s terminal while Bob cannot find it because the Bob child process inherited a different PATH, working directory, or environment. Check the process that launches bob acp, use absolute paths for critical executables, and keep the workspace cwd visible in the ACP logs.
Changes inside an existing Zed terminal do not reach the running Bob process. If you run cd or export a variable there, restart the external-agent thread after you update Bob’s launch environment.
Conclusion
I started with one command that was missing from the main help output. Bob Shell 2.0.1 turned out to expose a real ACP integration with authentication, permissions, plans, inline diffs, MCP handoff, and persistent sessions. Zed owns the client experience, while Bob keeps control of the agent runtime and its shell.



