Summary
The v1.4.8 change (#148) relocates all non-core system prompt entries to the first user message to work around Anthropic's OAuth 400 rejection. While this fixes the immediate API error, it introduces a meaningful regression in instruction-following quality, particularly in long conversations.
Problem
The relocated content includes the entire OpenCode system prompt (~30K+ chars):
- OpenCode's agent instructions (tone/style, tool usage policy, task management, code reference format)
- Environment metadata (working directory, git status, platform)
- Skills block (available skill descriptions)
- User instruction files (AGENTS.md / CLAUDE.md contents)
- Per-message system prompts
This content is prepended to the first user message via:
const firstUser = parsed.messages.find((m) => m.role === "user")
As the conversation grows, these instructions drift further from the current exchange:
Turn 1: [system] [user₁ + instructions] → near the latest context
Turn 5: [system] [user₁ + instructions] [asst] [user₂] ... [user₅] → drifting
Turn 30: [system] [user₁ + instructions] [asst] [user₂] ... [user₃₀] → buried
Why this matters
System prompts occupy a privileged architectural position in Claude — they're always attended to regardless of context length. User messages don't have this property. They're subject to the "lost in the middle" effect, where content at the start of a long context receives less attention than content near the end.
In practice, this means:
- Tool usage policies become less reliably followed in long sessions
- Coding conventions from AGENTS.md/CLAUDE.md fade in influence
- Tone/style guidelines may be ignored as the conversation grows
- Prompt cache efficiency is reduced — system prompts cache well because they're static; instructions stuffed into user messages are interleaved with per-turn content that changes
The only thing that retains full system-level priority is the one-sentence Claude Code identity prefix.
Possible alternatives
Some ideas for fixing the OAuth rejection without sacrificing instruction priority:
-
Split the system prompt into identity + billing (kept) and instructions (kept separately with the identity prefix prepended) — if the API check is specifically about entries that don't look like Claude Code's system prompt, prefixing each system entry with a recognized header might pass validation.
-
Inject instructions into the most recent user message instead of the first — this doesn't solve the architectural privilege issue but avoids the "lost in the middle" problem by keeping instructions near the active context.
-
Use a hybrid approach — keep critical instructions (tool policy, AGENTS.md) in system with a format that passes validation, and only relocate the less critical metadata to user messages.
Environment
Summary
The v1.4.8 change (#148) relocates all non-core system prompt entries to the first user message to work around Anthropic's OAuth 400 rejection. While this fixes the immediate API error, it introduces a meaningful regression in instruction-following quality, particularly in long conversations.
Problem
The relocated content includes the entire OpenCode system prompt (~30K+ chars):
This content is prepended to the first user message via:
As the conversation grows, these instructions drift further from the current exchange:
Why this matters
System prompts occupy a privileged architectural position in Claude — they're always attended to regardless of context length. User messages don't have this property. They're subject to the "lost in the middle" effect, where content at the start of a long context receives less attention than content near the end.
In practice, this means:
The only thing that retains full system-level priority is the one-sentence Claude Code identity prefix.
Possible alternatives
Some ideas for fixing the OAuth rejection without sacrificing instruction priority:
Split the system prompt into identity + billing (kept) and instructions (kept separately with the identity prefix prepended) — if the API check is specifically about entries that don't look like Claude Code's system prompt, prefixing each system entry with a recognized header might pass validation.
Inject instructions into the most recent user message instead of the first — this doesn't solve the architectural privilege issue but avoids the "lost in the middle" problem by keeping instructions near the active context.
Use a hybrid approach — keep critical instructions (tool policy, AGENTS.md) in system with a format that passes validation, and only relocate the less critical metadata to user messages.
Environment