Skip to content

Drupal Recipe Factory Playbook

Classification: PROCEDURE. Not authority; the governing standard below owns the rules.
Authority: how-we-build §4-5
Reference: Drupal Recipes Cookbook & Site Templates


1. Core Architecture of a Drupal Recipe

A Drupal Recipe packages features, configuration, roles, permissions, and dependencies as a declarative, repeatable, one-time application:

my_recipe/
├── recipe.yml           # Mandatory manifest (name, description, install, config, actions)
├── composer.json        # Mandatory package definition (type: "drupal-recipe")
├── config/              # Static YAML configuration files
└── content/             # Optional default content YAML files

1.1 composer.json Standard

{
    "name": "blueflyio/recipe_contextual_memory",
    "description": "Shared context schema for ContextControl.ai and agent memory",
    "type": "drupal-recipe",
    "license": "GPL-2.0-or-later",
    "require": {
        "drupal/ai_context": "^1.0@beta",
        "drupal/tool_belt": "^1.0@alpha",
        "drupal/key": "^1.18"
    }
}

2. Crafting recipe.yml

name: 'Contextual Memory Schema'
type: 'AI Context'
description: 'Provisions ai_context_item bundles and evidence fields for agent memory'

# Dependent recipes (composability)
recipes:
  - core/recipes/administrator_role

# Required modules to enable
install:
  - ai_context
  - tool_belt
  - key

# Configuration imports
config:
  import:
    ai_context: '*'
    tool_belt:
      - toolbelt.toolbelt.kb_cache_context

# Config Actions (idempotent mutations)
actions:
  user.role.memory_agent:
    grantPermissions:
      - 'view ai_context_item entities'
      - 'create ai_context_item entities'
      - 'edit own ai_context_item entities'
  ai_context.settings:
    simpleConfigUpdate:
      enable_moderation: true
      default_token_budget: 4096

3. Recipe Development Lifecycle

Step 1: Clean Site Baseline

  1. Start with a clean site or isolated worktree.
  2. Export clean baseline config: drush cex -y.

Step 2: Configure in Drupal UI or via Drush

  1. Install modules via Composer.
  2. Build content types, bundles, field definitions, and displays.
  3. Export new config state: drush cex -y.

Step 3: Extract Delta into Recipe

  1. Copy newly exported config files from config/sync/ into recipes/<my_recipe>/config/.
  2. Author recipe.yml with dependencies, imports, and config actions.
  3. Validate recipe syntax: drush recipe:validate recipes/<my_recipe> (or via test runner).

Step 4: Test Recipe Application

# Test applying the recipe to a fresh site
drush recipe recipes/<my_recipe> -v

# Verify configuration imported without error
drush config:inspect --show-errors

4. Production Recipe Invariants

  1. Zero Custom PHP: A recipe contains ONLY YAML config, content, and composer.json. Never add .module, .php, or custom hooks inside a recipe directory.
  2. Granularity: Keep recipes single-purpose (e.g. recipe_contextual_memory, recipe_factory_board, recipe_contractplane_intent). Combine them via master site-template recipes.
  3. Strict Validation: Always ensure all referenced field storage, bundles, and roles exist or are created by the recipe.