Skip to content

Claude Code: dynamic agent sync via SessionStart hook #25

@chubes4

Description

@chubes4

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:

  1. Runs wp datamachine agents list --format=json --allow-root to discover all active agents
  2. For each agent, runs wp datamachine agent paths --agent=<slug> --format=json --allow-root to get its memory file paths
  3. Updates CLAUDE.md with @ includes for every discovered agent's files
  4. 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

  1. Read current CLAUDE.md
  2. Find the ## Data Machine Memory section (or create it if missing)
  3. Query DM for all agents + their paths
  4. Replace the @ includes in that section with current discovered paths
  5. Write the updated CLAUDE.md back to disk
  6. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions