Skip to content

ACP: /rename reports success but doesn't rename the session #5115

Open

Description

@miriver

Describe the bug

In ACP mode (copilot --acp --stdio), /rename <name> reports success but doesn't rename the session. Copilot advertises the command in available_commands_update, and sending it as a session/prompt ends end_turn in about 1 ms, with no model call, with the reply Session renamed to: <name>. But nothing is saved: the session's workspace.yaml keeps its old name and user_named: false, and session/list keeps returning the old title, from the same process and from a new one. /session rename <name> behaves the same.

ACP has no client method to set a session's title (titles are agent-owned and reported with session_info_update), so /rename is the only way for an ACP client to rename a Copilot session.

Affected version

GitHub Copilot CLI 1.0.95

Steps to reproduce the behavior

  1. Start copilot --acp --stdio and initialize.
  2. session/new with a cwd, and send one ordinary prompt, so the session is saved and listed (its title is the first message).
  3. Send a session/prompt with the text /rename My new name.
  4. The reply is Session renamed to: My new name, with stopReason: end_turn.
  5. Call session/list with that cwd, in the same process or a new one: the session's title is still the first message.
  6. Open ~/.copilot/session-state/<id>/workspace.yaml: still the old name, and user_named: false. No session_info_update is sent with the new title.

Expected behavior

/rename <name> over ACP renames the session as it does in the interactive CLI: it saves the name (name, user_named: true), session/list returns it, and Copilot sends a session_info_update with the new title, so the client can update its view.

Additional context

  • Windows 11, x86_64. Driven from a Node ACP client (@agentclientprotocol/sdk).
  • Writing name and user_named: true into workspace.yaml by hand does change the title in session/list, so the listing side works. Only the command doesn't save.
  • In the 1.0.95 bundle, one session implementation's renameSession() calls the native session.name.set, and another's is an empty stub (async renameSession(t){}, next to getWorkspace(){return null}). The ACP session seems to get the stub. The success message is printed either way.
  • Related: Support /rename in VS Code agent sessions, and let the agent invoke it #4244 (/rename in VS Code agent sessions), Manual /rename is overwritten by later auto-generated session name #2622 (a manual name overwritten by an automatic one).

Activity

  1. rishidevcli54-mcp commented on Oct 11, 2026

    @rishidevcli54-mcp
  2. added
    area:non-interactiveNon-interactive mode (-p), CI/CD, ACP protocol, and headless automation
    area:sessionsSession management, resume, history, session picker, and session state
    and removed on Oct 12, 2026
  3. impartshadow commented on Oct 13, 2026

    @impartshadow

    This is a split-implementation bug: two code paths claim to do the same thing, and only one of them actually does it.

    The issue body gives the exact mechanism — "one session implementation's renameSession() calls the native session.name.set, and another's is an empty stub (async renameSession(t){}, next to getWorkspace(){return null})." The ACP session object is getting routed to the stub implementation, but the command handler that prints "Session renamed to: " doesn't check the return value or whether the underlying write happened — it just assumes success once the command parses and dispatches. That's why end_turn fires in ~1ms with no model call: the whole path is non-blocking because nothing is actually persisted.

    The check that would catch this before it ships: after renameSession() returns, read back workspace.yaml (or whatever the session accessor exposes) and assert name === requestedName && user_named === true before emitting the success string; if the stub path returns without writing, that assertion fails immediately in CI with a fake/ACP session fixture, instead of silently succeeding. Equivalently, a contract test instantiating both session implementations against the same interface and diffing observable state after renameSession() would surface the stub immediately — any implementation that doesn't mutate state it claims to own is the bug, full stop.

    Open question: I'm inferring the ACP session object literally is the one with the stub renameSession/getWorkspace() { return null } pair based on the quoted snippet, but I haven't seen which concrete class gets wired to ACP vs. interactive mode — that mapping (likely in the session factory/router) would confirm or kill this hypothesis.

    Advisory SFA-2026-1F8C7A25AE · Full redacted write-up: https://impartshadow.github.io/echo-site/failure-cases/acp-rename-reports-success-but-doesn-t-rename-the-se-1f8c7a25ae.html
    If this diagnosis is useful, react 👍 to this comment; if it is wrong, react 👎 — I use the verdict to choose what I investigate next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:non-interactiveNon-interactive mode (-p), CI/CD, ACP protocol, and headless automationarea:sessionsSession management, resume, history, session picker, and session state

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions