Problem
When using Claude Code as the runtime, CLAUDE.md is generated once by the setup script with static @ includes pointing to Data Machine agent files. If you create a new agent in WordPress after setup, CLAUDE.md doesn't know about it — the new agent's memory files (SOUL.md, MEMORY.md) are never injected into sessions.
OpenCode solves this with kimaki/plugins/dm-agent-sync.ts — a plugin that queries wp datamachine agents list on every session start and dynamically registers all agents with their file paths. Claude Code needs an equivalent.
Solution
Build a Claude Code SessionStart hook that:
- Runs
wp datamachine agents list --format=json --allow-root to discover all active agents
- For each agent, runs
wp datamachine agent paths --agent=<slug> --format=json --allow-root to get its memory file paths
- Updates CLAUDE.md with
@ includes for every discovered agent's files
- Preserves any non-DM content in CLAUDE.md (user customizations, rules, etc.)
The hook should be a shell script in claude-code/hooks/ (or similar), registered in .claude/settings.json as a SessionStart command hook.
What dm-agent-sync.ts does (reference)
// On session start:
// 1. Query all agents
const agentsRaw = await $`wp datamachine agents list --format=json --allow-root 2>/dev/null`
// 2. For each active agent, get paths
const paths = await $`wp datamachine agent paths --agent=${agent.agent_slug} --format=json --allow-root 2>/dev/null`
// 3. Build prompt from discovered files
const prompt = ["{file:./AGENTS.md}", ...paths.relative_files.map(f => `{file:./${f}}`)].join("\n")
// 4. Register in config
config.agent[agentSlug] = { prompt, description: `Data Machine agent: ${agent.agent_name}` }
Claude Code hooks reference
Claude Code supports SessionStart hooks in .claude/settings.json:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/dm-agent-sync.sh"
}
]
}
]
}
}
On SessionStart, stdout is injected as context that Claude can see. The hook receives JSON on stdin with session metadata.
Key difference from OpenCode: Claude Code doesn't have an agent switcher. The goal is to ensure all DM memory files are included in the session context, not to register separate agent identities. The hook should update the @ includes in the Data Machine Memory section of CLAUDE.md.
What the hook script needs to do
- Read current CLAUDE.md
- Find the
## Data Machine Memory section (or create it if missing)
- Query DM for all agents + their paths
- Replace the
@ includes in that section with current discovered paths
- Write the updated CLAUDE.md back to disk
- Keep everything else in CLAUDE.md untouched
Setup script integration
The setup script (runtimes/claude-code.sh) should:
- Install the hook script to
.claude/hooks/dm-agent-sync.sh in the WordPress root
- Register it in
.claude/settings.json as a SessionStart hook
- Remove or simplify the static
@ include generation in runtime_generate_config() since the hook handles it dynamically
Edge cases
- Data Machine not installed: hook should be a no-op, don't touch CLAUDE.md
- No agents exist yet: leave the DM section empty or with a comment
- Multiple agents: include files for all of them (shared files like SITE.md only once)
- USER.md is per-user, agent files are per-agent — handle the layering correctly
- CLAUDE.md doesn't exist yet: create it with a minimal template
- The hook runs before Claude reads CLAUDE.md, so the updated file is picked up automatically
Files to create/modify
- New:
claude-code/hooks/dm-agent-sync.sh — the hook script
- Modify:
runtimes/claude-code.sh — install the hook + register in settings.json, simplify static config generation
- Possibly modify:
workspace/CLAUDE.md.tmpl — simplify since dynamic content is handled by the hook
Problem
When using Claude Code as the runtime, CLAUDE.md is generated once by the setup script with static
@includes pointing to Data Machine agent files. If you create a new agent in WordPress after setup, CLAUDE.md doesn't know about it — the new agent's memory files (SOUL.md, MEMORY.md) are never injected into sessions.OpenCode solves this with
kimaki/plugins/dm-agent-sync.ts— a plugin that querieswp datamachine agents liston every session start and dynamically registers all agents with their file paths. Claude Code needs an equivalent.Solution
Build a Claude Code
SessionStarthook that:wp datamachine agents list --format=json --allow-rootto discover all active agentswp datamachine agent paths --agent=<slug> --format=json --allow-rootto get its memory file paths@includes for every discovered agent's filesThe hook should be a shell script in
claude-code/hooks/(or similar), registered in.claude/settings.jsonas aSessionStartcommand hook.What dm-agent-sync.ts does (reference)
Claude Code hooks reference
Claude Code supports
SessionStarthooks in.claude/settings.json:{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/dm-agent-sync.sh" } ] } ] } }On
SessionStart, stdout is injected as context that Claude can see. The hook receives JSON on stdin with session metadata.Key difference from OpenCode: Claude Code doesn't have an agent switcher. The goal is to ensure all DM memory files are included in the session context, not to register separate agent identities. The hook should update the
@includes in the Data Machine Memory section of CLAUDE.md.What the hook script needs to do
## Data Machine Memorysection (or create it if missing)@includes in that section with current discovered pathsSetup script integration
The setup script (
runtimes/claude-code.sh) should:.claude/hooks/dm-agent-sync.shin the WordPress root.claude/settings.jsonas aSessionStarthook@include generation inruntime_generate_config()since the hook handles it dynamicallyEdge cases
Files to create/modify
claude-code/hooks/dm-agent-sync.sh— the hook scriptruntimes/claude-code.sh— install the hook + register in settings.json, simplify static config generationworkspace/CLAUDE.md.tmpl— simplify since dynamic content is handled by the hook