You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
condense ignores the agent provider: the reflector is wired to a global command with a hardcoded Claude model and Claude-only flags, so an all-OpenCode floor still burns a hidden Claude session #596
The memory reflector (MemoryReflector / condense) does not use the agent's provider. It is wired to a single global command with a hardcoded claude fallback, a hardcoded Claude model, and Claude-CLI-specific flags. On a floor where every agent runs on OpenCode — which is the whole point of deploying OpenCode — the condense pass is still a hidden Claude session that consumes the Claude subscription.
So the one subsystem that was supposed to be provider-agnostic is the one that still requires Claude.
Evidence (0.4.6, Linux x64, read from app.asar)
1. The reflector is constructed with a global command, not a per-agent provider:
constreflector=newMemoryReflector(()=>readConfig().harnessHome,()=>readConfig().defaultCommand??"claude",// <- single global value()=>memory.env(),reflectSettings,(event)=>{ ... });
2. The constructor's own doc comment says it is Claude:
6. There is no provider/model control in the reflect settings at all — reflectSettings() exposes only enabled, intervalMs, byteTriggerPct, sectionTrigger, recentKeep, minBytes. Grepping the bundle for condenseProvider, condenseCommand, reflectCommand, memoryCommand returns zero occurrences.
Every non-archived agent has provider: opencode. Live process check: 5–7 opencode --model … processes, zeroclaude processes. Yet condense runs a hidden Claude session on a ~30-minute timer, and has been failing hourly:
condense-abort reason=summarize-failed
detail: Error: condense: response contained no parseable JSON
Why it fails (the mechanism)
summarize() requires strict JSON:
Produce STRICT JSON: {"condensed": "<text>", "hoist": ["<line>", ...]}.
When the Claude subscription hits its weekly limit, claude -p returns plain text:
You've hit your weekly limit · resets Sep 25, 6am (UTC)
That is not JSON, so parseSummary() returns nothing and the call throws. Verified directly — both claude-haiku-4-5 and claude-sonnet-5 return the limit line (subscription pro).
Note: the limit is the symptom. Even with quota available, this path still (a) burns Claude usage on a floor that was deliberately moved to OpenCode, and (b) spends a hidden invocation every cycle it cannot succeed.
Why this matters
It defeats the purpose of the OpenCode deployment. Operators move to OpenCode/self-hosted models specifically to get off the Claude subscription. Condensation is the one piece that never made the move, and it is the piece that runs unattended on a timer.
It is not configurable away. With defaultCommand: "claude" the binary is Claude; pointing defaultCommand at opencode does not help either, because the model (claude-haiku-4-5) and the flags (--permission-mode, --disallowedTools) are Claude-specific. There is no supported way to say "condense with my configured provider".
Expected
The reflector should resolve the provider of the agent being condensed (or at minimum a configurable reflectProvider / reflectModel / reflectCommand), and
build the arguments from that provider's preset (providerPreset() already exists in the bundle and is used for spawning) instead of hardcoding Claude flags, and
detect a limit/quota response and record it as its own reason (e.g. rate-limited with the reset time) rather than retrying blind.
Summary
The memory reflector (
MemoryReflector/condense) does not use the agent's provider. It is wired to a single global command with a hardcodedclaudefallback, a hardcoded Claude model, and Claude-CLI-specific flags. On a floor where every agent runs on OpenCode — which is the whole point of deploying OpenCode — the condense pass is still a hidden Claude session that consumes the Claude subscription.So the one subsystem that was supposed to be provider-agnostic is the one that still requires Claude.
Evidence (0.4.6, Linux x64, read from
app.asar)1. The reflector is constructed with a global command, not a per-agent provider:
2. The constructor's own doc comment says it is Claude:
3. The model is hardcoded, not configurable:
4. The hidden call builds Claude-CLI flags regardless of which binary was resolved:
--permission-mode/--disallowedToolsare Claude Code flags. They are passed whether the resolved binary isclaudeor something else.5. The fallback is baked into the runner too:
6. There is no provider/model control in the reflect settings at all —
reflectSettings()exposes onlyenabled,intervalMs,byteTriggerPct,sectionTrigger,recentKeep,minBytes. Grepping the bundle forcondenseProvider,condenseCommand,reflectCommand,memoryCommandreturns zero occurrences.Our situation
Config:
Every non-archived agent has
provider: opencode. Live process check: 5–7opencode --model …processes, zeroclaudeprocesses. Yetcondenseruns a hidden Claude session on a ~30-minute timer, and has been failing hourly:Why it fails (the mechanism)
summarize()requires strict JSON:When the Claude subscription hits its weekly limit,
claude -preturns plain text:That is not JSON, so
parseSummary()returns nothing and the call throws. Verified directly — bothclaude-haiku-4-5andclaude-sonnet-5return the limit line (subscriptionpro).Note: the limit is the symptom. Even with quota available, this path still (a) burns Claude usage on a floor that was deliberately moved to OpenCode, and (b) spends a hidden invocation every cycle it cannot succeed.
Why this matters
fleet.jsondistinguishes "condensing is failing" from "condensing is idle", and the abort shares its log line with the unrelated JSON-escaping failure in Memory condensation aborts ~80% of the time: the payload has to survive JSON string escaping #459 — three distinct causes collapse intono parseable JSON.defaultCommand: "claude"the binary is Claude; pointingdefaultCommandatopencodedoes not help either, because the model (claude-haiku-4-5) and the flags (--permission-mode,--disallowedTools) are Claude-specific. There is no supported way to say "condense with my configured provider".Expected
reflectProvider/reflectModel/reflectCommand), andproviderPreset()already exists in the bundle and is used for spawning) instead of hardcoding Claude flags, andrate-limitedwith the reset time) rather than retrying blind.Related
providerignored, flags assumed to be Claude's), but on the spawn path. The reflector is the unattended twin of this.Happy to test a patch — we have a reproducible floor and log evidence.