docs(agents): document Jinja system-message constraint and session-start delivery

- Add forbidden pattern: using experimental.chat.system.transform for
  session-start injection causes Jinja 'System message must be at the
  beginning' on Qwen-family GGUF models when orchestrator spawns subagents
- Add note to session-start.sh section explaining OpenCode delivery via
  output.parts.unshift() on first chat.message turn (not system.transform)
This commit is contained in:
Brydon DeWitt 2026-05-23 00:00:40 -04:00
parent 2949981e43
commit 3738732156

View File

@ -151,6 +151,12 @@ calling the script. See `agent-infrastructure.md` item 22 for the refactor plan.
- Fires once per session. Good for: current branch, active investigations, dead
ends.
- Not good for: precise rule reminders (use PostToolUse or nested AGENTS.md).
- **OpenCode delivery:** injected as a synthetic `text` part via
`output.parts.unshift()` on the first `chat.message` turn. **Not** via
`experimental.chat.system.transform` — that hook fires for task-spawned
subagent sessions after a user message is already in context, which causes
Qwen-family GGUF models to abort with a Jinja "System message must be at the
beginning" error. See Forbidden Patterns below.
### `stop.sh` — End-of-session reflection
@ -237,6 +243,15 @@ Some things cannot be unified and live in tool-specific locations:
model may be correct. Applies to: OpenCode tool names (`read`/`edit`/`task`),
parameter names (`offset`/`limit` not `startLine`/`endLine`), and plugin guard
logic.
- ❌ Using `experimental.chat.system.transform` to inject session-start content
in OpenCode. That hook fires for every model call — including task-spawned
subagent sessions — **after** the task prompt (a user message) is already in
the conversation. Pushing to `output.system` at that point places a system
message at a non-zero position, which Qwen-family GGUF models reject with
_"System message must be at the beginning"_ (Jinja chat template guard).
Fix: inject session-start as a synthetic `text` part via `output.parts.unshift()`
on the first `chat.message` turn (guarded by an `initializedSessions` set).
Text parts have no position constraint. Committed `f0d21e9` in dotfiles.
- ❌ Asserting that a third-party tool does **not** support a feature (config
mechanism, directory, option) without fetching the tool's current docs first.
Training data is frequently stale. Negative claims ("X doesn't have Y") must