"I Stopped Choosing Between Claude Code and Codex. I Put Both in One Chat Window" A solution to the frustration of switching between coding agents Claude Code and Codex by integrating both into a single chat window. The author implemented a mode-switching system using simple commands like `/cligate` for assistant-mediated tasks and `/runtime` for direct runtime control, preventing the assistant from intercepting messages meant for the active coding session. This design prioritizes predictable behavior, ensuring that direct runtime messages are not hijacked unless the user explicitly requests assistant intervention. Every "Claude Code vs Codex" comparison eventually runs into the same boring truth: I do not want to pick one forever. Some tasks feel better in Claude Code. Some feel better in Codex. Some days one account is rate-limited, one model is cheaper, or one runtime is already holding the context I need. The annoying part is not choosing the better agent. The annoying part is switching surfaces every time I change my mind. The workflow I wanted I wanted one local chat window where I could do this: Use Codex for this task. Continue that same runtime. Switch to Claude Code for the next one. Ask the assistant to plan first. Go back to direct runtime mode. That sounds like a UI problem, but it is really a control problem. There are two different things happening: - direct runtime work, where the next message should go straight to Claude Code or Codex - assistant-mediated work, where a supervisor decides whether to answer, ask a question, or delegate to a runtime If those two modes are not explicit, the chat window turns into a trap. A short follow-up like: make it smaller can either mean: - continue the active Codex runtime - ask the product assistant - start a new Claude Code task - answer a pending approval Guessing wrong here is exactly how coding agents become frustrating. So I made direct runtime the default In CliGate https://github.com/codeking-ai/cligate , the chat UI conversation now defaults to direct runtime mode. That was a deliberate choice. Most of the time, when I am using a coding agent, I do not want an assistant to intercept every message and "think about what I meant." I want the current runtime to continue until I explicitly ask for something else. There is a test that pins this behavior: test 'ChatUiConversationStore defaults new chat-ui conversations to direct-runtime control mode', = { const conversation = conversationStore.findOrCreateBySessionId 'chat-ui-default-direct-runtime-1' ; assert.equal conversation.metadata?.assistantCore?.mode, 'direct-runtime' ; assert.equal conversation.metadata?.assistantCore?.controlMode, 'direct-runtime' ; } ; That means a normal chat message does not automatically become "assistant work." It stays on the runtime path. The two commands that made the UI usable I ended up with a small mode switch instead of another complicated settings panel: /cligate /runtime The mode parser is intentionally tiny: js const cligateMatch = trimmed.match /^\/cligate ?:\s+ .+ ?$/is ; if cligateMatch { return { command: 'cligate', args: String cligateMatch 1 || '' .trim }; } if /^\/runtime$/i.test trimmed { return { command: 'runtime', args: '' }; } The behavior is: - /cligate enters assistant mode - /cligate