Skip to content

fix(claude): symlink CLAUDE.md → AGENTS.md so Claude-model sessions inherit DM context#109

Merged
chubes4 merged 1 commit intomainfrom
fix/claude-md-cross-runtime
May 3, 2026
Merged

fix(claude): symlink CLAUDE.md → AGENTS.md so Claude-model sessions inherit DM context#109
chubes4 merged 1 commit intomainfrom
fix/claude-md-cross-runtime

Conversation

@chubes4
Copy link
Copy Markdown
Member

@chubes4 chubes4 commented May 3, 2026

Closes #108

Problem

upgrade.sh Phase 5 regenerates AGENTS.md via wp datamachine memory compose, but CLAUDE.md is only generated by hooks/dm-agent-sync.sh which is gated to Claude Code's SessionStart hook. On opencode-runtime + kimaki-bridge installs, CLAUDE.md is never created.

Empirical evidence

On the extrachill.com VPS, a fresh OpenCode session running claude-opus-4-7 does not honor SOUL.md/MEMORY.md content and self-reports the DM bundle as "not in context." A side-by-side fresh session with the same config running glm-5.1 self-identifies as "Extra Chill Bot" with phrasing pulled directly from SOUL.md.

AGENTS.md alone is insufficient for the Claude model — CLAUDE.md is needed.

Why a symlink (Option 3)

Three options were considered in #108:

  1. Duplicate compose — run datamachine memory compose CLAUDE.md alongside AGENTS.md. Risks drift if one compose succeeds and the other fails, plus duplicated bytes on disk.
  2. Refactor the hook — pull dm-agent-sync.sh out of the Claude Code SessionStart gate and run it for opencode too. Larger blast radius, requires reworking the runtime hook contract.
  3. Symlink CLAUDE.md → AGENTS.md ✅ — self-healing on regeneration, no duplication, no drift, minimal change. OpenCode reads both filenames; Claude Code reads CLAUDE.md.

OpenCode source globs ["AGENTS.md", "CLAUDE.md", "CONTEXT.md"] upward from cwd (deduped), so writing CLAUDE.md is purely additive — it does not break opencode users and gives Claude-model users the context they need.

Changes

upgrade.sh Phase 5

After wp datamachine memory compose AGENTS.md succeeds, ensure CLAUDE.md → AGENTS.md symlink exists. Dry-run path prints the would-be action. Skips when CLAUDE.md is a regular file (claude-code/studio-code runtimes ship their own template-based CLAUDE.md).

runtimes/opencode.sh::runtime_generate_instructions

Fresh installs via the opencode runtime now also create the symlink — both on the compose-success path and on the static-template fallback path. Extracted into helper _opencode_symlink_claude_md so it is called from every code path that writes AGENTS.md, including the "AGENTS.md already exists, skipping" branch (so existing installs get the symlink on next run even without a regeneration).

Scope

  • ✅ Tied to AGENTS.md regeneration, runs under --agents-md-only (verified via dry-run, see below)
  • ✅ Relative target (ln -sf AGENTS.md CLAUDE.md from $SITE_PATH) — survives directory moves
  • ✅ No CHANGELOG.md or VERSION edits (homeboy owns both)
  • ✅ Idempotent — ln -sf overwrites an existing symlink, helper guards against clobbering a real CLAUDE.md file

Verification

./upgrade.sh --dry-run --agents-md-only on extrachill.com:

[wp-coding-agents] Phase 5: Regenerating AGENTS.md...
[dry-run] Would backup /var/www/extrachill.com/AGENTS.md → ...AGENTS.md.backup.20260503-182449
[dry-run] Would run: wp datamachine memory compose AGENTS.md --allow-root
[dry-run] Would symlink /var/www/extrachill.com/CLAUDE.md → AGENTS.md (Claude-model context)

bash -n syntax check passes on both modified files.

git diff origin/main shows ONLY the symlink addition + dry-run handling. No unrelated edits.

Acceptance criteria (from #108)

  • On opencode-runtime + kimaki-bridge installs, CLAUDE.md exists after upgrade.sh runs
  • CLAUDE.md content is identical to AGENTS.md (it is the same file via symlink)
  • Symlink is regenerated/preserved on subsequent upgrade.sh runs (idempotent)
  • Symlink uses a relative target so directory moves don't break it
  • Fresh installs via the opencode runtime also get the symlink
  • claude-code / studio-code runtimes that ship a real CLAUDE.md are not clobbered
  • --agents-md-only scope flag covers the symlink (it is part of Phase 5, not gated separately)
  • No changes to CHANGELOG.md or VERSION

…sessions

The Claude model running inside an OpenCode session does not honor
SOUL.md/MEMORY.md content composed into AGENTS.md alone — empirically
it self-reports the DM bundle as 'not in context'. A side-by-side
fresh session with the same config running glm-5.1 self-identifies
as 'Extra Chill Bot' with phrasing pulled from SOUL.md.

OpenCode reads both AGENTS.md and CLAUDE.md from cwd (it globs
["AGENTS.md", "CLAUDE.md", "CONTEXT.md"], deduped), so writing
CLAUDE.md is purely additive. Claude Code reads only CLAUDE.md.
The fix symlinks CLAUDE.md → AGENTS.md (relative target) so:

  - upgrade.sh Phase 5 self-heals the symlink after every compose
  - runtimes/opencode.sh fresh installs create the symlink at first run
  - claude-code/studio-code runtimes that ship a real CLAUDE.md are
    left untouched (the helper only acts when CLAUDE.md is missing
    or already a symlink)

Closes #108
@chubes4 chubes4 merged commit b7e5acb into main May 3, 2026
3 checks passed
@chubes4 chubes4 deleted the fix/claude-md-cross-runtime branch May 3, 2026 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AGENTS.md alone is insufficient — Claude model needs CLAUDE.md regardless of runtime

1 participant