Raised: $0
0% of monthly goal Help us cross the finish line!
Goal: $12,000
Raised: $0 Goal: $12,000
0% of monthly goal Help us cross the finish line!
Sponsor DDEV

If you find this add-on useful, please star it on GitHub — stars show appreciation and help maintainers know their work matters.

add-on registry tests last commit release

ddev-agents-sync

A DDEV add-on that automatically syncs AI agent repositories and generates tool-specific configurations for OpenCode and Claude Code.

Part of DDEV AI Workspace — a modular ecosystem of DDEV add-ons for AI-powered Drupal development. Install the full stack with one command: ddev add-on get trebormc/ddev-ai-workspace

Created by Robert Menetray · Sponsored by DruScan

What problem does this solve? AI tools like OpenCode and Claude Code each expect agent configurations in a different format. This add-on lets you write agents once (using a shared “fat frontmatter” format) and automatically generates the correct configuration for each tool. It also resolves model tokens, so the same agent definition can use different models depending on the tool.

On every ddev start, this container clones or updates the configured repositories, resolves model aliases, and produces two separate agent directories (one optimized for each AI tool).

Quick Start

The recommended way to install this add-on is through the DDEV AI Workspace, which installs all tools and dependencies with a single command:

ddev add-on get trebormc/ddev-ai-workspace
ddev restart

This add-on is also automatically installed as a dependency when you install ddev-opencode or ddev-claude-code. You rarely need to install it directly.

Standalone installation

If you need to install it individually (requires familiarity with the DDEV add-on ecosystem):

ddev add-on get trebormc/ddev-agents-sync
ddev restart

OpenCode and Claude Code will automatically pick up the synced agents.

Prerequisites

Configuration

Edit .ddev/.env.agents-sync:

# Comma-separated list of git repositories to sync
# Later repos override earlier ones (useful for private overrides)
AGENTS_REPOS=https://github.com/trebormc/drupal-ai-agents.git

# Set to "false" to disable automatic sync on ddev start
AGENTS_AUTO_UPDATE=true

Multiple repos (public + private override)

AGENTS_REPOS=https://github.com/trebormc/drupal-ai-agents.git,https://github.com/your-org/private-agents.git

Files from later repos override earlier ones. This lets you use the public Drupal agents as a base and add (or replace) specific agents/skills from a private repo.

How It Works

On ddev start:
  ┌──────────────────────────────────────────────────────────────────┐
  │  agents-sync container                                          │
  │                                                                  │
  │  1. Clone/update each repo in AGENTS_REPOS                      │
  │                                                                  │
  │  2. Merge all repos into /tmp/agents-merged (later repos win)   │
  │                                                                  │
  │  3. Read .env.agents (model alias → real model name mapping)     │
  │                                                                  │
  │  4. Generate /agents-opencode/                                   │
  │     - envsubst: ${MODEL_CHEAP} → opencode/gpt-5-nano            │
  │     - Keeps OpenCode frontmatter (mode, tools object, permission)│
  │     - Removes allowed_tools line                                 │
  │     - Copies opencode.json.example, notifier config, etc.       │
  │                                                                  │
  │  5. Generate /agents-claude/                                     │
  │     - envsubst: ${MODEL_CHEAP} → haiku                          │
  │     - Converts frontmatter to Claude Code format                 │
  │     - Renames allowed_tools → tools (CSV)                        │
  │     - Removes mode, temperature, maxSteps, tools, permission     │
  │                                                                  │
  │  6. Sleep (stay alive for depends_on)                            │
  └──────────────────────────────────────────────────────────────────┘

  ┌─────────────────────────┐  ┌─────────────────────────┐
  │       OpenCode          │  │      Claude Code        │
  │  reads /agents-opencode │  │  reads /agents-claude   │
  │      (read-only)        │  │      (read-only)        │
  └─────────────────────────┘  └─────────────────────────┘

The output directories are Docker named volumes (ddev-{sitename}-agents-opencode and ddev-{sitename}-agents-claude). They persist between restarts and are not visible on the host filesystem.

Merge strategy

Files are copied from each repo in order. The merge is a simple file-level override:

Model Token System

Agent .md files use model tokens instead of hardcoded model names. This allows the same agent definition to work with both OpenCode and Claude Code, and makes it easy to change models globally.

Available tokens

Token Default (OpenCode) Default (Claude Code) Use for
${MODEL_MAIN} opencode/deepseek-v4-flash sonnet The orchestrator: default model of the tool’s main conversation loop
${MODEL_GENIUS} opencode/glm-5.2 opus Hardest tasks: important code reviews, architecture
${MODEL_SMART} opencode/glm-5.2 opus Quality gates, planning, research, delegation advice
${MODEL_NORMAL} opencode/deepseek-v4-pro sonnet General-purpose tasks
${MODEL_CHEAP} opencode/deepseek-v4-flash haiku Fast, cost-effective agents
${MODEL_APPLIER} opencode/gpt-5-nano haiku Mechanical code application
${MODEL_VISION} opencode/minimax-m3 sonnet Image/screenshot interpretation — MUST accept image input

When an .env.agents file does not define them, GENIUS falls back to the SMART value, VISION falls back to the NORMAL value, and MAIN falls back to CHEAP on OpenCode / NORMAL on Claude Code, so older override files keep working unchanged. GENIUS defaults to the same model as SMART — override it with a stronger model when you have one. VISION must be a vision-capable model or image analysis agents will not see anything.

${MODEL_MAIN} is special: besides being substituted in configs, the sync injects it as the DEFAULT model of each tool — the top-level model in the generated opencode.json and the model key in the generated Claude Code settings.generated.json. The main conversation loop dominates session cost, so it defaults to a cheap tier; expensive models are reserved for the specialist subagents.

How tokens are resolved

Token values come from .env.agents files, loaded as a variable-level cascade — each level only needs to define the variables it wants to override:

Priority Location Scope
1 (highest) .ddev/.env.agents in the project This project only
2 ~/.ddev/agents-sync/.env.agents on the host ALL your DDEV projects
3 (lowest) .env.agents in the agents repo Managed defaults

The repo default defines the full mapping:

# OpenCode models (provider/model-id format)
OC_MODEL_MAIN=opencode/deepseek-v4-flash
OC_MODEL_GENIUS=opencode/glm-5.2
OC_MODEL_SMART=opencode/glm-5.2
OC_MODEL_NORMAL=opencode/deepseek-v4-pro
OC_MODEL_CHEAP=opencode/deepseek-v4-flash
OC_MODEL_APPLIER=opencode/gpt-5-nano
OC_MODEL_VISION=opencode/minimax-m3

# Claude Code models (native aliases)
CC_MODEL_MAIN=sonnet
CC_MODEL_GENIUS=opus
CC_MODEL_SMART=opus
CC_MODEL_NORMAL=sonnet
CC_MODEL_CHEAP=haiku
CC_MODEL_APPLIER=haiku
CC_MODEL_VISION=sonnet

During sync, envsubst replaces the tokens with the appropriate values for each tool. Changes take effect after ddev agents-update && ddev restart.

Changing models

To change which models your agents use:

  1. For all projects: Edit ~/.ddev/agents-sync/.env.agents on the host (created by the installer) and uncomment/set only the variables you want to change — e.g. point everything to your own LiteLLM models.

  2. Per project: Edit .ddev/.env.agents in the project. It overrides both the host file and the repo defaults, again variable by variable.

  3. Managed defaults for a team: Fork drupal-ai-agents, edit its .env.agents, and point AGENTS_REPOS to your fork (or add a private repo with just an .env.agents as a second repo in AGENTS_REPOS — later repos override earlier ones).

Writing agents with tokens

If you create custom agents in your own repository, use the same tokens in the frontmatter:

---
description: My custom agent for code review.
model: ${MODEL_SMART}
mode: subagent
tools:
  read: true
  glob: true
  grep: true
  bash: false
permission:
  bash: deny
allowed_tools: Read, Glob, Grep
---

Your agent prompt here...

The sync script will automatically substitute the tokens when generating configs for each tool. See Fat Frontmatter for the full format.

Fat Frontmatter

Agent .md files use a “fat frontmatter” format that contains configuration for both OpenCode and Claude Code. Each tool reads the fields it understands and ignores the rest:

---
description: Short description of what this agent does.
model: ${MODEL_CHEAP}                  # Token, replaced by sync

# OpenCode fields (Claude Code ignores these)
mode: subagent                          # primary or subagent
temperature: 0.1                        # optional
tools:                                  # tool availability (YAML object)
  read: true
  glob: true
  grep: true
  bash: false
  write: false
  edit: false
permission:                             # permission policy
  bash: deny

# Claude Code field (OpenCode ignores this, sync renames to "tools:")
allowed_tools: Read, Glob, Grep         # tool availability (CSV)
---

Agent system prompt content...

During sync:

Git Access

By default AI agents are not allowed to run git write commands — they present a summary of their changes and you commit manually. This is controlled per tool by two flags in the same .env.agents cascade as the model tokens, so they follow the same repo default < ~/.ddev/agents-sync/.env.agents < .ddev/.env.agents priority.

Each flag holds a comma-separated list of the tools the capability is granted to. Valid tool ids: opencode, claude. An empty value grants it to no tool (the default).

Flag Default Allows (for the listed tools)
GIT_ALLOW_COMMIT (empty) git add, git commit
GIT_ALLOW_OPERATIONS (empty) git push (non-force), pull, fetch, merge, rebase, checkout/switch, reset, restore, stash, tag, cherry-pick

List a tool in a flag to enable that capability there — for example, let both tools commit locally but only Claude Code push:

# .ddev/.env.agents (this project) or ~/.ddev/agents-sync/.env.agents (all projects)
GIT_ALLOW_COMMIT=opencode,claude
GIT_ALLOW_OPERATIONS=claude

Changes take effect after ddev agents-update && ddev restart.

Always blocked, regardless of the flags: force-push (git push --force/-f/--force-with-lease) and remote-branch deletion (git push --delete/-d) — nothing may rewrite or destroy remote history.

The flags are enforced in both tools, not just documented in prompts:

The git-workflow rule shipped to each tool is generated from that tool’s resolved flags, so the prompt text always matches what is technically allowed.

Commands

ddev agents-update

Manually trigger a sync without restarting DDEV:

ddev agents-update

Uninstallation

ddev add-on remove ddev-agents-sync
ddev restart

Part of DDEV AI Workspace

This add-on is part of DDEV AI Workspace, a modular ecosystem of DDEV add-ons for AI-powered Drupal development.

Repository Description Relationship
ddev-ai-workspace Meta add-on that installs the full AI development stack with one command. Workspace
ddev-opencode OpenCode AI CLI container for interactive development. Auto-installs this add-on
ddev-claude-code Claude Code CLI container for interactive development. Auto-installs this add-on
ddev-ralph Autonomous AI task orchestrator. Delegates work to OpenCode or Claude Code. Does not require this add-on
ddev-beads Beads git-backed task tracker shared by all AI containers. Sibling dependency
ddev-ai-ssh SSH access to the web container for AI agents. Sibling dependency
ddev-playwright-mcp Headless Playwright browser for browser automation and visual testing. Sibling dependency
drupal-ai-agents 10 agents, 12 rules, 24 skills for Drupal development. Default repo synced by this add-on. Content synced by this add-on

Disclaimer

This project is an independent initiative by Robert Menetray, sponsored by DruScan. It is not affiliated with Anthropic, OpenCode, Beads, Playwright, Microsoft, or DDEV. AI-generated code may contain errors. Always review changes before deploying to production.

License

Apache-2.0. See LICENSE.

If you find this add-on useful, please star it on GitHub — stars show appreciation and help maintainers know their work matters.