Context
RemoteClaw is middleware that delegates LLM execution to CLI agents (Claude Code, Gemini, Codex, OpenCode). Each CLI manages its own reasoning/thinking configuration. RemoteClaw should not attempt to translate or control LLM-level thinking settings — that's platform territory and violates the middleware boundary.
Problem
The thinkingLevel config surface is user-settable but has no runtime effect. This is a broken half-implementation.
Flow analysis
- User sets it via CLI (
--thinking high), TUI (/thinking command), ACP set_config_option thinking_level, or cron job flag
- Value is persisted in session entries (
SessionEntry.thinkingLevel)
- Value is displayed back in the TUI (
src/tui/tui.ts:757-759) and surfaced to ACP clients (src/acp/translator.ts:1001)
- No CLI subprocess invocation passes the value. The CLI agents (
src/middleware/runtimes/claude.ts, codex.ts, gemini.ts, opencode.ts) consume thinking/reasoning as OUTPUT events from their subprocess streams; they do not accept a thinkingLevel input and do not forward it as a CLI flag.
- Merge logic in
src/auto-reply/thinking.shared.ts — specifically resolveThinkingDefaultForModel — has zero callers. Dead function.
src/agents/subagent-spawn.ts:279 reads params.thinking into _thinkingOverrideRaw — the leading underscore indicates intentionally unused; subagent spawning silently discards the thinking override.
- Tests asserting thinking-merge behavior (
src/commands/agent.test.ts:840-846 "prefers per-model thinking over global thinkingDefault") are orphan: they assert against a mock of runEmbeddedPiAgent, which is not imported anywhere in production src/ code (the embedded execution path was gutted).
What reasoningLevel does (and why it stays)
reasoningLevel is a different concept and must be KEPT. It controls Telegram channel display behavior (off | on | stream — drives suppression/streaming/block-streaming of reasoning-event rendering in Telegram drafts) via resolveTelegramReasoningLevel in src/telegram/bot-message-dispatch.ts:92-112. Downstream it flows through src/auto-reply/reply/get-reply.ts, get-reply-inline-actions.ts, commands-status.ts. This is a legitimate channel-bound middleware concern.
Do not confuse the two. Gut only thinkingLevel / thinkingDefault / thinking-related helpers. Keep reasoningLevel everywhere.
Tasks
Session/state
Config
CLI surface
TUI
ACP
Subagent spawn + cron jobs
Thinking helpers + orphan tests
Acceptance Criteria
rg "thinkingLevel|thinkingDefault|ThinkLevel" src/ returns no hits (migration-warning message text aside)
rg "\.thinking\b|params\.thinking" src/ returns no hits, except thinking_delta and type === \"thinking\" references in src/middleware/runtimes/*.ts (those are output-event stream parsers and must stay)
rg "reasoningLevel" src/ still returns live hits in Telegram, channel, ACP translator paths — this is intentional, reasoningLevel is kept
- User loading a config with
thinkingDefault: "high" sees a migration warning and the config still loads
remoteclaw cron add --thinking high — the flag either errors with "unknown option" or the whole line is removed; state the behavior in the PR description
tsc --noEmit clean
- Test suite passes with no new skips
Context
RemoteClaw is middleware that delegates LLM execution to CLI agents (Claude Code, Gemini, Codex, OpenCode). Each CLI manages its own reasoning/thinking configuration. RemoteClaw should not attempt to translate or control LLM-level thinking settings — that's platform territory and violates the middleware boundary.
Problem
The
thinkingLevelconfig surface is user-settable but has no runtime effect. This is a broken half-implementation.Flow analysis
--thinking high), TUI (/thinkingcommand), ACPset_config_option thinking_level, or cron job flagSessionEntry.thinkingLevel)src/tui/tui.ts:757-759) and surfaced to ACP clients (src/acp/translator.ts:1001)src/middleware/runtimes/claude.ts,codex.ts,gemini.ts,opencode.ts) consume thinking/reasoning as OUTPUT events from their subprocess streams; they do not accept athinkingLevelinput and do not forward it as a CLI flag.src/auto-reply/thinking.shared.ts— specificallyresolveThinkingDefaultForModel— has zero callers. Dead function.src/agents/subagent-spawn.ts:279readsparams.thinkinginto_thinkingOverrideRaw— the leading underscore indicates intentionally unused; subagent spawning silently discards the thinking override.src/commands/agent.test.ts:840-846"prefers per-model thinking over global thinkingDefault") are orphan: they assert against a mock ofrunEmbeddedPiAgent, which is not imported anywhere in production src/ code (the embedded execution path was gutted).What
reasoningLeveldoes (and why it stays)reasoningLevelis a different concept and must be KEPT. It controls Telegram channel display behavior (off | on | stream— drives suppression/streaming/block-streaming of reasoning-event rendering in Telegram drafts) viaresolveTelegramReasoningLevelinsrc/telegram/bot-message-dispatch.ts:92-112. Downstream it flows throughsrc/auto-reply/reply/get-reply.ts,get-reply-inline-actions.ts,commands-status.ts. This is a legitimate channel-bound middleware concern.Do not confuse the two. Gut only
thinkingLevel/thinkingDefault/ thinking-related helpers. KeepreasoningLeveleverywhere.Tasks
Session/state
thinkingLevelfield fromSessionEntrytype insrc/gateway/session-utils.types.ts:36andsrc/gateway/protocol/schema/sessions.ts:101thinkingLevelpersistence in gateway server methods:src/gateway/server-methods/sessions.ts:498src/gateway/server-methods/agent.ts:468src/gateway/server-methods/chat.ts:778-784src/gateway/server-node-events.ts:167src/gateway/session-utils.ts:826src/auto-reply/reply/session.tssession merge logic (lines 368, 370, 384, 386, 434)Config
thinkingDefaultfield fromsrc/config/types.agent-defaults.ts:178andsrc/config/zod-schema.agent-defaults.ts:132-141subagents.thinkingoverride insrc/config/zod-schema.agent-defaults.ts:182src/config/schema.base.generated.tsthinkingDefaultorsubagents.thinking(same channel used for other legacy-field warnings)CLI surface
--thinkingflag fromsrc/cli/cron-cli/register.cron-add.ts:178-179andregister.cron-edit.ts:211-212thinkingfield from cron test fixtures (src/cron/normalize.test.ts:368,src/cli/cron-cli.test.ts:233,402,408,430)thinking: opts.thinkingfromsrc/commands/agent-via-gateway.ts:140gateway payloadthinkingoption handling fromsrc/commands/agent.ts(search foropts.thinkingand the CLI option declaration)TUI
thinkingLevelfromsrc/tui/tui-types.ts:30thinkingLevelfromsrc/tui/tui-session-actions.ts:165-166, 288, 292thinkingLeveldisplay fromsrc/tui/tui.ts:757-759/thinkingcommand handler fromsrc/tui/tui-command-handlers.ts(search forthinkingLeveland remove the whole command branch)src/tui/gateway-chat.ts:80ACP
thinking_levelhandling insrc/acp/translator.ts:set_config_optionwrite path (~line 1030)thinking_levelfromsrc/acp/commands.tsif exposed as a config option ID theresrc/acp/translator.set-session-mode.test.ts:39, 50and fromsrc/acp/translator.session-rate-limit.test.tsSubagent spawn + cron jobs
thinkingparam fromsrc/agents/tools/sessions-spawn-tool.ts:27, 91, 123_thinkingOverrideRaw/params.thinkingdiscard insrc/agents/subagent-spawn.ts:279thinkingfield handling fromsrc/cron/service/jobs.ts:679-680, 763thinkingfield references fromsrc/agents/tools/sessions-history-tool.ts:66Thinking helpers + orphan tests
src/auto-reply/thinking.shared.ts, leaving onlyReasoningLevel,VerboseLevel, andnormalizeVerboseLevel(and anything else still used):ThinkLeveltyperesolveThinkingDefaultForModellistThinkingLevels,listThinkingLevelLabels,formatThinkingLevelsformatXHighModelHintisBinaryThinkingProviderThinkingCatalogEntrytypesrc/tui/tui-formatters.ts:181thinking-text display (verify it's the text-output rendering, not a level — if it's level-related, delete; if it's the stream of thinking text emitted by the CLI, keep since that's the output-event rendering and still in use)src/commands/agent.test.ts:expectDefaultThinkLevelhelper functiongetLastEmbeddedCall()?.thinkLevelAcceptance Criteria
rg "thinkingLevel|thinkingDefault|ThinkLevel" src/returns no hits (migration-warning message text aside)rg "\.thinking\b|params\.thinking" src/returns no hits, exceptthinking_deltaandtype === \"thinking\"references insrc/middleware/runtimes/*.ts(those are output-event stream parsers and must stay)rg "reasoningLevel" src/still returns live hits in Telegram, channel, ACP translator paths — this is intentional,reasoningLevelis keptthinkingDefault: "high"sees a migration warning and the config still loadsremoteclaw cron add --thinking high— the flag either errors with "unknown option" or the whole line is removed; state the behavior in the PR descriptiontsc --noEmitclean