Skip to content

ACP chat sessions ignore the agent config's env (CLAUDE_CONFIG_DIR) and reject custom claude/codex configs #9505

Closed

Description

@resteqs

Problem

ACP chat sessions ignore the agent config they were started with, so two Claude accounts (e.g. work + personal, separated via CLAUDE_CONFIG_DIR in each agent config's env) can run side by side as terminals but not as chats.

Repro on 2.0.6 with two agent configs:

  • Config A: preset claude, env CLAUDE_CONFIG_DIR=~/.claude-a
  • Config B: preset custom, command claude, env CLAUDE_CONFIG_DIR=~/.claude-b
  1. superset sessions create --local --workspace <ws> --agent <A-uuid> --prompt 'run: echo $CLAUDE_CONFIG_DIR'
    → the chat starts, but prints the default account's dir (SUPERSET_DEFAULT_CLAUDE_CONFIG_DIR), not ~/.claude-a. The chat silently runs on the wrong account.
  2. superset sessions create ... --agent <B-uuid> ...
    → Agent <B-uuid> or its attachments cannot be used with ACP chat. No terminal was launched.

Cause

  • createChatSession only forwards harness to the chat runtime; the agent config id is dropped, so buildChatAgentEnv only ever applies the default-account env.
  • chatLaunchTarget maps presetId → ACP harness, so a custom config that runs claude/codex has no harness.

Proposed fix

Carry an optional agentConfigId on the chat session (persisted, inherited on resume/fork/rewind), layer the config's env over the default-account env when launching the ACP agent (same precedence as terminal launches), and let custom configs whose command is claude/codex chat as that preset. PR incoming.

Activity

  1. github-actions commented on Nov 8, 2026

    @github-actions
    Contributor

    Both problems are real, and the cause is what you described. A chat session never learns which agent config started it, so the ACP agent only gets the host-default account env. Separately, choosing a chat harness keys on the config's presetId, and a custom config only gets its command checked for omp.

    I read the code only; I didn't run anything or write a test.

    Summary

    Terminal launches put the agent config's own env on top of the default account's env, so a config that sets CLAUDE_CONFIG_DIR stays on its own account. Chat (ACP) launches skip that. The config is used only to pick a harness name, then dropped, so the spawned claude/codex uses the host-default CLAUDE_CONFIG_DIR / CODEX_HOME. A custom config that runs claude or codex can't be used for chat at all, because no harness matches the custom preset.

    Affected code

    1. Config env is dropped on the chat path

    • packages/host-service/src/trpc/router/agents/agents.ts:666-705: chatLaunchTarget resolves the config but returns only { harness, label, attachments }. The config id and env go no further.
    • packages/host-service/src/trpc/router/sessions/create-chat-session.ts:22-33: chat.commands.createSession gets scopeId, cwd, harness, terminalId, modelId, modeId and resume. Nothing names the agent config.
    • packages/host-service/src/chat-v3/acpHarnesses.ts:50-62: the harness factory builds env from buildChatAgentEnv({ db, cwd, workspaceId, terminalId }) only. It has no config to read.
    • packages/host-service/src/chat-v3/agentEnv.ts:56-76: buildChatAgentEnv adds resolveDefaultAccountTerminalEnv(db) (usage/default-account.ts:243), which is always the host-default Claude and Codex accounts.
    • The other buildChatAgentEnv calls (chat-v3/mount.ts:87,112 and agent-tooling/agent-tooling.ts:83) have the same gap.

    The terminal path does this correctly with agentLaunchEnv in packages/host-service/src/terminal-agents/agent-config.ts:101-106:

    return { ...resolveDefaultAccountEnv(db, config.presetId), ...config.env };

    seed-agent-trust.ts:84 uses the same order. So on the chat path, per-agent env never wins.

    The session's account is also read from this env (captureSessionAccount(..., env.CLAUDE_CONFIG_DIR ...) in acpHarnesses.ts:64-73). Once the env is fixed, the recorded account will be fixed too.

    2. custom configs are rejected for chat

    • agents.ts:696-701: the harness comes from acpHarnessForPreset(resolveAgentLaunchPresetId(config.presetId, config.command)).
    • packages/shared/src/agent-models.ts:725-735: resolveAgentLaunchPresetId only remaps the command omp / omp.exe to "omp". Any other command keeps presetId, here "custom".
    • packages/host-service/src/chat-v3/acpCatalogue.ts:98-108: ACP_HARNESS_BY_PRESET has no custom entry. chatLaunchTarget returns null, and session-service.ts:110-114 throws "…cannot be used with ACP chat. No terminal was launched."

    Reproduction

    Manual: follow the steps in the issue. With config A, the chat prints the default account's dir. With config B, the error above appears.

    As a bun:test sketch, next to the existing chatLaunchTarget tests in agents.test.ts (around line 1160):

    1. Insert a hostAgentConfigs row with presetId: "custom", command: "claude" and surface: "chat", then call chatLaunchTarget. It returns null today.
    2. For the env bug, insert a presetId: "claude" row whose envJson sets CLAUDE_CONFIG_DIR. Check that the env the chat launch builds contains that value. Today buildChatAgentEnv has no way to accept the config, so the test will first need a new parameter or a way to look up the config by session.

    Fix direction

    The proposal in the issue matches the code:

    1. Carry the config.
      • Return the config id from chatLaunchTarget and pass it through createChatSession into createSession. Store it on the session so resume, fork, rewind and restart keep it.
      • Expose it on the factory options.
      • Have buildChatAgentEnv add config.env last, the same way agentLaunchEnv does: { ...hostLaunchEnv, ...defaultAccountEnv, ...config.env }.
      • Sessions without a stored id fall back to today's behaviour.
    2. Accept custom configs. Extend resolveAgentLaunchPresetId to map claude and codex executables the way it maps omp. Model and mode checks (agents.ts:702-703) and agentLaunchEnv would then treat these configs as their real preset. This function is in packages/shared and other callers use it, so check their behaviour too.
    3. Check the CLI wrapper. The issue saw SUPERSET_DEFAULT_CLAUDE_CONFIG_DIR. default-account.ts:268-270 says the agent wrapper uses that variable to re-resolve the default account. Confirm that a CLAUDE_CONFIG_DIR set by the config is kept when the wrapper in ~/.paradev/bin, which withSupersetBinFirst puts first on PATH, starts the CLI.
    4. Compatibility. Any new optional field on a tRPC input or on stored session data should follow packages/trpc/AGENTS.md, because released clients still call these procedures.
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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions