Skip to content

Example .drupalaibp/ configs

Two complete, runnable configs live in this directory in the repository:

  • drupal/: a Drupal CMS site with the full provisioning surface, custom questions, and hook scripts. Reach for it as the template for a real Drupal team config.
  • storybook/: a non-Drupal Node/Storybook project built entirely by hooks. Reach for it when you want DDEV plus coding agents around something that is not Drupal.

Running an example

Each example directory is self-contained. Either copy it and let the installer auto-detect the config:

cp -R docs/examples/drupal ~/my-build && cd ~/my-build
bash <(curl -fsSL https://aibp.drupalstarforge.ai/install.sh)

or point the installer at the directory with --config-path (or the positional source argument):

drupalaibp --config-path path/to/one_line_installer/docs/examples/drupal

A team config repo works the same way with --config-url <git-url>: put the .drupalaibp/ directory at the repo root (exactly as these examples model it inside their subdirectories) and the installer clones the repo, builds from its config, and copies the repo into the project.

How a config works

Drop a .drupalaibp/ directory (containing a config *.json) in the directory where you launch the installer and it pre-configures the build from that config — creating the project, installing the coding agents/skills, provisioning, asking any custom questions, and firing your hook scripts at named build events. Hook script paths resolve relative to the config file and are copied into the new project root before they run. Since the config now lives at .drupalaibp/config.json, a script that sits beside it is referenced as ./seed-content.sh — paths are relative to the .drupalaibp/ directory (the CONFIG_BASEDIR).

Each example below is a self-contained directory: copy it somewhere, cd into it, and run the installer. The config and its hook scripts/assets all live together inside the .drupalaibp/ directory, so a hook script (or a copy_paths entry) is written relative to that directory.

drupal/ — a Drupal site with provisioning

is_drupal: true, Drupal CMS on Drupal 11. It shows the full Drupal path:

  • a private repositories entry registered before composer_projects are required (so acme/acme_ai_glue resolves);
  • composer_projects (fetch, here with composer_with_all_dependencies: true) + install_modules (enable) + a recipes apply. Note the split: recipes only applies (drush recipe), so the drupal/drupal_cms_blog recipe is listed in both composer_projects (to fetch it) and recipes (to apply it);
  • Toolbelt expressed as ordinary provisioning — drupal/tool + drupal/tool_belt in composer_projects and tool/tool_belt/tool_belt_* in install_modules. There is no dedicated toolbelt flag: a built-in handler notices those packages and applies the alpha-stability + tbachert/spi plugin-trust setup they need;
  • Selenium as a plain ddev_addons entry (ddev/ddev-selenium-standalone-chrome) plus a Redis add-on. A built-in handler fires after the add-on is pulled to rewrite its docker-compose/config for headed Chrome watchable over VNC — no dedicated selenium flag;
  • questions — a password (OpenAI key → .ddev/.env, never committed), a single-select-options flavor, and one carrying a value (SITE_ENV) which pre-answers it so no prompt is shown (distinct from default, which only pre-fills an editable prompt);
  • an agents_md block whose paragraphs are appended into the installer-managed section of AGENTS.md — project-specific agent instructions with no hook script;
  • hooks on ddev_started (seed content, reading $SITE_FLAVOR) and coding_agent_added (per-agent notes, receiving the agent name as $1).

AI Best Practices (drupal/ai_best_practices) and drupal/core-dev + phpunit.xml are not listed here — they are built-in defaults for every is_drupal: true build.

DTK works the same way as Toolbelt: add drupal/dtk:1.0.x-dev to composer_projects and dtk to install_modules.

storybook/ — a non-Drupal Node/Storybook project

is_drupal: false, so every Drupal-specific step self-skips (no composer create-project, no drush, no config export). DDEV + the coding agents + skills are still set up; the actual project work is driven entirely by hooks. docroot is set to storybook-static (the directory storybook build writes to) so DDEV serves the built site directly — a non-Drupal config has no web/ to fall back on, so docroot must point at wherever the hooks actually produce output. docroot is also written to .ddev/.env as $DOCROOT, so build-storybook.sh reads it instead of hardcoding storybook-static a second time — keep any hook that writes a build output reading $DOCROOT rather than repeating the directory name:

  • ddev_started weight 10 → npm-install.sh (runs npm init, npx storybook init, installs the selected addons)
  • ddev_started weight 20 → build-storybook.sh

Both hooks set "where": "web", so they run inside the DDEV web container and call npm/npx directly (no ddev exec wrapper). A hook's where is host, web (default), or a ddev service name; a hook on a pre-start event (e.g. coding_agent_added in the Drupal example) must use where: host because the container isn't up yet.

If your project has its own hand-authored .storybook/ config (a real main.ts/preview.tsx/theme.ts, not the placeholder storybook init scaffolds), keep it next to the config under a non-.storybook name — e.g. ./.drupalaibp/storybook-config/ — and add it to copy_paths ("copy_paths": ["./storybook-config"], relative to .drupalaibp/). That stages it into the new project root at ./storybook-config (a copy_paths entry is mirrored to the same relative path in the project). Then have npm-install.sh copy it over the generic generated .storybook/ after storybook init:

npx --yes storybook@latest init --type "${framework}" --builder vite --yes
if [ -d storybook-config ]; then
  rm -rf .storybook
  cp -R storybook-config .storybook
fi

It is stored as storybook-config rather than .storybook directly because a copy_paths entry is mirrored to the same project-root path — a staged .storybook/ would be overwritten by storybook init; staging it under a different name and copying it over after init sidesteps that collision.

It also demonstrates every question type driving those npm commands: a single-select-options (STORYBOOK_FRAMEWORKstorybook init --type), a multi-select-options (STORYBOOK_ADDONS → one npm install per selected addon; the answer arrives comma-joined), a text (STORYBOOK_PORT), and a password (NPM_REGISTRY_TOKEN). All land in .ddev/.env and reach the hook scripts as environment variables.

Schema reference

See the schema doc for the full schema and semantics: docs/drupalaibp-json.md.

Available hook events: before_<step> / <step>_done for every pipeline step, plus the semantic events before_ddev_start, ddev_started, coding_agent_added, skill_added, and ask_questions.