fix(opencode): use native instructions config to load CLAUDE.md and fragments#2153
Merged
gavrielc merged 2 commits intoMay 1, 2026
Merged
Conversation
Before: wrapPromptWithContext concatenated /workspace/agent/CLAUDE.md
verbatim into a <system>...</system> block in the user-message text.
That file is the host-composed entry point that contains only `@./...`
includes (the .claude-shared.md symlink to /app/CLAUDE.md, plus the
module fragments). OpenCode does not expand `@` in instruction files —
the syntax is a Claude Code convention for the model's own Read tool
to lazy-load. Result: the model received the literal lines
"@./.claude-shared.md\n@./.claude-fragments/module-...md" as text and
saw none of the actual content (workspace, memory, conversation
history, agents/core/interactive/scheduling/self-mod modules, OneCLI,
etc.). Confirmed empirically by dumping the constructed prompt for a
turn before any fix.
After: pass the concrete files via OpenCode's native `instructions`
config field. Per packages/opencode/src/session/instruction.ts on the
upstream `dev` branch, absolute paths and globs are resolved with
`fs.glob(basename, { cwd: dirname, absolute: true, include: 'file' })`,
files are read raw, and the resulting strings are concatenated into
the LLM's system prompt at packages/opencode/src/session/prompt.ts:1442.
That is the canonical channel — same one OpenCode uses for AGENTS.md /
CLAUDE.md auto-discovery.
Configured set:
/app/CLAUDE.md shared base
/workspace/agent/.claude-fragments/*.md per-skill fragments
/workspace/agent/CLAUDE.local.md per-group memory
/workspace/global/CLAUDE.md cross-group memory (non-main)
Removed: readClaudeMdForPrompt, the manual <system> wrap of its output,
and the now-unused `fs` import. The dynamic systemInstructions wrap
(assistant name + destinations) stays as-is — that varies per call.
Verified post-fix: Citiclaw (gemma4:31b via Ollama) responded to "what
self-modification tools do you have" with the exact MCP tool names and
a structured bullet list — vs. the previous ungrounded "I haven't
received instructions" response.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 1, 2026
NANOCLAW_IS_MAIN no longer exists in the v2 codebase, and groups/global/ is explicitly migrated away by composeGroupClaudeMd (shared base now lives in container/CLAUDE.md → /app/CLAUDE.md, which the instructions array already includes). Carrying /workspace/global would give OpenCode more context than the Claude provider sees. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Type of Change
.claude/skills/<name>/, no source changes)Description
Closes #2150.
wrapPromptWithContextpreviously concatenated/workspace/agent/CLAUDE.mdverbatim into a<system>...</system>block in the user-message text. That file is the host-composed entry point that contains only@./...includes (the.claude-shared.mdsymlink to/app/CLAUDE.md, plus the module fragments). OpenCode does not expand@in instruction files — the syntax is a Claude Code convention for the model's own Read tool to lazy-load. Result: the model received the literal lines@./.claude-shared.md\n@./.claude-fragments/module-...mdas text and saw none of the actual fragment content (workspace, memory, conversation history, agents/core/interactive/scheduling/self-mod modules, OneCLI, etc.). Strong-prior models (Claude, GPT-4) masked the gap; weaker local models visibly lacked NanoClaw conventions.This PR routes the concrete files through OpenCode's native
instructionsconfig field. Perpackages/opencode/src/session/instruction.tson the upstreamdevbranch (already shipped in@opencode-ai/sdk@1.4.17, the version pinned by/add-opencode), absolute paths and globs are resolved withfs.glob(basename, { cwd: dirname, absolute: true, include: 'file' }), files are read raw, and the resulting strings are concatenated into the LLM's system prompt atpackages/opencode/src/session/prompt.ts:1442. That is the canonical channel — same one OpenCode uses forAGENTS.md/CLAUDE.mdauto-discovery.Configured set
Removed:
readClaudeMdForPrompt, the manual<system>wrap of its output inwrapPromptWithContext, and the now-unusedfsimport. The dynamicsystemInstructionswrap (assistant name + destinations) stays as-is — that's per-call data, not file content.Verification
Empirically tested with
gemma4:31bon local Ollama before the fix: agent replied"I haven't received instructions"to "what self-modification tools do you have". Post-fix: agent listed the exact MCP tool names (install_packages,add_mcp_server) and structured response frommodule-self-mod.mdcontent. Base model has no priors for those tools, so the only place that knowledge can come from is the fragment now reaching the system prompt.Note on
composeGroupClaudeMdsrc/claude-md-compose.tsstill produces/workspace/agent/CLAUDE.mdwith@./...includes. That file remains required for the Claude provider (whose SDK does expand@correctly) but is now redundant for OpenCode users — OpenCode also auto-discovers it viafindUpand adds the literal text again, butinstructionstakes precedence for actual content. Cleanup is out of scope for this fix; flagging so future work knows.Related
For Skills
Not a skill PR — section N/A.