Skip to content

STD-DRUPAL-002 — Bluefly Drupal-Native Architecture & Upstream-First Refactoring Contract

Standard ID: STD-DRUPAL-002
Applies to: bluefly.io and every Bluefly-owned Drupal module, recipe, theme, integration, and package consumed by or designed for the site.


Purpose

This contract governs bluefly.io and every Bluefly-owned Drupal module, recipe, theme, integration, and package consumed by or designed for the site.

The objective is not merely to make the current code work.

The objective is:

USE DRUPAL CORRECTLY.

DELETE PARALLEL FRAMEWORKS.

USE CORE FIRST.
USE CONTRIB SECOND.
USE CONFIGURATION THIRD.
USE RECIPES FOURTH.
USE EXISTING DRUPAL EXTENSION POINTS.
CUSTOM PHP LAST.

MAKE BLUEFLY'S CUSTOM CODE SMALLER,
MORE GENERIC,
MORE UPSTREAMABLE,
AND EASIER TO DELETE.

Every custom line of code is a liability until an upstream gap proves it is necessary.


1. REQUIRED IMPLEMENTATION ORDER

For every capability:

DRUPAL CORE
→ EXISTING CONTRIB
→ CONTRIB CONFIGURATION
→ RECIPE / CONFIG ACTION
→ CANVAS / SDC
→ ECA / FLOWDROP
→ DRUPAL AI
→ AI_AGENTS
→ TOOL API
→ MCP SERVER (drupal/mcp_server 2.x)
→ EXISTING BLUEFLY MODULE
→ NEW CUSTOM CODE

Custom code may only survive when every earlier layer has been evaluated and rejected with evidence.


2. WHAT COUNTS AS A VIOLATION

Every implementation must be classified against these questions:

IS_THIS_ACTUALLY_DRUPAL?

DOES_CORE_ALREADY_DO_THIS?

DOES_CONTRIB_ALREADY_DO_THIS?

DOES_DRUPAL_AI_ALREADY OWN THIS?

DOES_AI_AGENTS ALREADY OWN THIS?

DOES_TOOL API ALREADY OWN THIS?

DOES_ECA ALREADY OWN THIS?

DOES_FLOWDROP ALREADY OWN THIS?

DOES_MCP_SERVER ALREADY OWN THIS?

DOES_ADVANCEDQUEUE ALREADY OWN THIS?

DOES_MIGRATE ALREADY OWN THIS?

DOES_CANVAS ALREADY OWN THIS?

DOES VIEWS ALREADY OWN THIS?

DOES CONFIGURATION ALREADY OWN THIS?

DOES A RECIPE ALREADY OWN THIS?

IS THIS FUNCTION IN THE WRONG MODULE?

IS THIS GENERIC ENOUGH TO BELONG UPSTREAM?

IS THIS A ONE-OFF BLUEFLY IMPLEMENTATION OF A GENERIC PROBLEM?

IS THIS AN INTERNAL DEVELOPMENT TOOL INSIDE A PRODUCTION DRUPAL MODULE?

IS THIS CUSTOM BECAUSE SOMEBODY DID NOT LOOK FOR THE EXISTING FRAMEWORK?

If yes, it is remediation work.


3. EXECUTION PRECEDENCE & ACTIVE PRODUCER LAW

The global architectural priority list does NOT override active claimed work. Finish what is already claimed to witness and merge before starting the next producer.

ACTIVE CLAIMED PRODUCER
→ COMPLETE IMPLEMENTATION
→ CI GREEN
→ WITNESS VERIFIED
→ MR MERGED
→ CONSUMER UPDATED
→ CLOSE BEAD
→ NEXT GLOBAL PRIORITY

Current Active Producer:

  • Bead: mba-3lyul
  • Producer: mcp_registry / mcp_gateway → drupal/mcp_server convergence
  • Status: IN_PROGRESS
  • Rule: Do NOT start ai_agents_orchestra, alternative_services, or recipe_onboarding until mba-3lyul is closed or blocked with durable evidence.

4. NORMALIZED MCP UPSTREAM OWNERSHIP

Current upstream direction establishes drupal/mcp_server 2.x (built on drupal/tool Tool API, HTTP/STDIO transports, and OAuth configuration) as the canonical server implementation.

Normalized MCP ownership boundaries:

MCP_SERVER       = drupal/mcp_server (2.x)
MCP_CLIENT       = drupal/mcp_client
MCP_TOOL_BRIDGE  = mcp_tools / Tool API
MCP_RESOURCES    = drupal/mcp_server
MCP_PROMPTS      = drupal/mcp_server
MCP_OAUTH        = drupal/mcp_server

Do not confuse client and server responsibilities. Do not implement custom MCP servers or transports when drupal/mcp_server provides the standard Drupal configuration and routing layer.


5. P0 — ai_agents_orchestra MUST BE DISMANTLED

Repository:

blueflyio/agent-platform/drupal/private/ai_agents_orchestra

This is currently the clearest example of architecture slop.

The module claims in its own README:

NEVER implement:
- custom vector stores
- raw Guzzle clients
- custom LLM mechanics

Current source does all three.

It contains:

custom agent entities
custom agent-type entities
custom orchestration sessions
custom AI provider plugins
custom provider management
custom workflow engines
custom vector memory
custom Qdrant integration
custom dashboards
custom marketplaces
custom registries
custom MCP controllers
custom execution controllers
custom policy engine
custom audit layer
custom agent routing
custom framework bridges
custom CrewAI abstractions
custom LangChain abstractions
custom OpenAI abstractions
custom GitLab ML inference
custom multi-site management
custom ROI systems
custom performance agents
custom queue orchestration
custom context/memory orchestration

It also contains numerous direct:

GuzzleHttp\Client
GuzzleHttp\ClientInterface
curl_init()
curl_exec()

including code with a hard-coded:

https://llm-platform.ddev.site

and fake embedding behavior such as:

array_fill(...)
crc32(...)

presented inside AI/vector logic.

That is not acceptable production architecture.

Required decomposition

LLM/model execution

MOVE TO:

drupal/ai

There will be no:

custom model client
custom OpenAI router
custom Anthropic router
custom provider manager
custom provider SDK wrapper

when Drupal AI provides the abstraction.


Agents

MOVE TO:

drupal/ai_agents

Agents become:

AiAgent plugins
configurable AiAgent entities
tools
instructions
permissions

Do not invent another Agent entity framework.

DELETE custom:

AIAgent entity
AIAgentType entity
agent-type plugin system
parallel agent registry
parallel execution loop

unless a specific upstream gap is proven.


Memory/context

MOVE TO:

drupal/ai_context
Drupal AI Search
Search API
appropriate vector provider

Delete custom generic:

VectorMemoryService
QdrantVectorService
framework-specific memory abstractions
OpenAI vector-store wrappers

unless an upstream extension interface specifically requires an adapter.


Event-driven workflow

MOVE TO:

ECA

Do not implement another generic PHP workflow engine.


Visual/data workflow

MOVE TO:

FlowDrop

Do not create another graph/workflow format inside Orchestra.


Async execution

MOVE TO:

AdvancedQueue
Drupal Queue API

Do not implement a parallel scheduler.


External automation bridges

MOVE TO:

drupal/orchestration

Orchestration is for external workflow bridges.

It is NOT a second internal Drupal workflow engine.


Executable capabilities

MOVE TO:

drupal/tool

Do not expose arbitrary custom execution APIs when a Tool plugin expresses the capability.


Discovery

MOVE TO:

DUADP
OSSA

Discovery is not Orchestra's job.


Policy

MOVE TO:

cedar_policy
contractplane_client
compliance-engine

Orchestra must not contain another PolicyEngine.


Marketplace

MOVE TO:

ai_marketplace
Drupal entities
Views

Orchestra is not a marketplace.


Dashboards

MOVE TO:

Drupal Dashboard
Views
standard entity list builders

Delete the pile of custom:

AgentDashboardController
EnhancedDashboardController
IntegratedDashboardController
UnifiedDashboardController
UnifiedAgentDashboardController
...

One module should not contain five interpretations of the same dashboard.


6. ai_agents_orchestra CONFIG CONVERGENCE

Current source contains parallel config naming variants including patterns like:

ai-agent-orchestra.*
ai_agent_orchestra.*
ai_agents_orchestra.*

and similar:

hyphenated
underscored
pluralized
singular

variants of the same conceptual configuration.

There are duplicate:

ECA models
Views
ECK entity types
ECK bundles
fields
Group types
roles
workflow configs
queue configs

under slightly different machine names.

Required:

ONE MACHINE NAME
ONE CONFIG CONTRACT
ZERO DUPLICATE CONFIG FAMILIES

Before deleting anything:

ACTIVE CONFIG=
INSTALL CONFIG=
CONSUMERS=
UNIQUE PURPOSE=

must be established. Then converge.


7. P0 — alternative_services IS THE WRONG LAYER

Repository:

blueflyio/agent-platform/drupal/private/alternative_services

This module is doing operating-system and developer-workstation management from inside Drupal.

Current source contains capabilities for:

DDEV start
DDEV stop
DDEV restart
DDEV addon install
DDEV addon remove
DDEV addon registry
DDEV snapshots
DDEV database export
DDEV database import
DDEV logs
Xdebug management
container execution
Composer execution
Drush execution
local process execution
Tailscale Funnel management
SSL operations
service orchestration
service routing
external-process management

This is not the responsibility of a production Drupal application.

Drupal should not be the workstation's shell.

Move DDEV operations to:

DDEV addons
DDEV commands
host tooling
Gas City execution
agent tooling
CI

not Drupal runtime PHP.

Remove production Drupal code which shells out to:

ddev
composer
drush
tailscale
host processes

unless a narrowly scoped, proven administrative integration absolutely requires it.


8. alternative_services SUBMODULE DECOMPOSITION

It contains submodules including:

alternative_mcp
alternative_platform_mcp
alternative_router
alternative_dragonfly
alternative_knowledge_graph
alternative_services_ddev
alternative_services_eca
alternative_services_flowdrop
alternative_services_orchestration

These collide directly with existing ownership.

alternative_mcp

SHOULD BE:

drupal/mcp_server
drupal/mcp_client
mcp_tools
Tool API

alternative_router

SHOULD BE:

drupal/orchestration
ECA
HTTP Client Manager

depending on the operation.

alternative_dragonfly

SHOULD BE:

dragonfly_client

There must not be two Dragonfly clients.

DDEV submodules

MOVE OUT OF DRUPAL.

Knowledge graph

The generic graph capability must be evaluated independently.

Do not bury a full knowledge-graph platform inside a "services" module.

If useful generically:

dedicated module
existing graph contrib
external graph service
Search API/index abstraction

must be evaluated.


9. P0 — recipe_onboarding REIMPLEMENTS DRUPAL RECIPES

Repository:

blueflyio/agent-platform/drupal/private/recipe_onboarding

Current source defines its own:

Recipe Config Entity
RecipeListBuilder
RecipeForm
RecipeDeleteForm
RecipeApplyForm
recipe status
recipe version
recipe author
recipe tags
recipe application state

Drupal core already has a Recipe system.

The Bluefly site also already requires:

drupal/core-recipe-unpack
drupal/recipe_installer_kit
drupal/recipe_ops

This is a direct architecture smell.

Required target

Recipes remain:

Drupal Recipe artifacts
recipe.yml
config actions
Composer packages

Recipe application uses:

Drupal core Recipe API / RecipeRunner

Additional UX should use or contribute to:

Recipe Installer Kit
Recipe Ops
Project Browser

where appropriate.

Do not create a parallel Recipe entity system.

If Bluefly requires:

recipe inventory
recipe validation
recipe audit
fleet status

those must be thin services over the actual Recipe artifacts.

The actual Recipe remains the authority.


10. PROTOCOL VS PRODUCT SEPARATION

Keep this durable separation: * OSSA: Authoritative portable agent definitions & manifests. * DUADP: Agent discovery and federation protocol. * AI Agents (drupal/ai_agents): Drupal-native agent execution. * MCP Server (drupal/mcp_server): Standard MCP protocol exposure via Tool API. * Tool API (drupal/tool): Executable agent capabilities.

Do NOT let ai_agents_communication, dragonfly_client, or ai_agents_client become duplicate discovery or protocol registries.


11. FUNCTION OWNERSHIP MAP

Apply this ownership contract:

Functionality Current/likely wrong home Correct owner
Model/provider abstraction Orchestra/custom clients drupal/ai
Agent execution Orchestra/custom loops ai_agents
Agent definition portability custom agent registries OSSA
Agent discovery client/communication/Dragonfly registries DUADP
AI context/memory Orchestra/Dragonfly custom memory ai_context
Vector search custom Qdrant/vector managers AI Search/Search API/provider
Executable AI capability custom controller/service Tool API
MCP protocol exposure custom adapters/gateway drupal/mcp_server (2.x)
MCP client operations custom client wrapper drupal/mcp_client
MCP tool discovery custom registry mcp_tools, Tool API
Internal automation custom workflow engine ECA
Visual pipeline custom graphs FlowDrop
Async work custom task executor AdvancedQueue/Queue API
Editorial state custom publish state Content Moderation/Workflows
External workflow bridge custom orchestration client orchestration
Recipe execution custom Recipe entity Drupal Recipe API
Migration custom migration engine Migrate API
Site composition custom page builder Canvas
Component rendering custom HTML controllers SDC
Lists/dashboards custom list controllers Views/Dashboard
API clients raw Guzzle wrappers HTTP Client Manager/api_normalization
Credentials env strings/custom secrets Key
Health custom health framework Health Check/Monitoring
DDEV operation Drupal module DDEV/host tooling/Gas City
CI/release policy consumer scripts gitlab_components
Generic repository validation site Node scripts shared build/tooling project

12. GLOBAL ORDER OF EXECUTION

Remediation proceeds in strict sequential order:

ACTIVE  Finish mba-3lyul (mcp_registry → drupal/mcp_server) to WITNESS + MERGE

P0-1    ai_agents_orchestra dismantling
P0-2    alternative_services de-scoping (remove host/DDEV management)
P0-3    recipe_onboarding elimination (defer to core Recipe API)

P1-1    ai_agents_client normalization
P1-2    ai_agents_communication split (a2a_protocol vs ai_agents)
P1-3    dragonfly_client convergence
P1-4    layout_system_converter de-scoping
P1-5    external_migration de-scoping

P1-6    bluefly.io control-plane slop removal (.agents-workspace)
P1-7    ai.json runtime-authority drift resolution
P1-8    tracked package source under web/ retirement

P2-1    Analytics overlap consolidation
P2-2    CAPTCHA/bot overlap consolidation
P2-3    Mail transport/routing overlap consolidation
P2-4    Search API/core Search consolidation
P2-5    Workflow module overlap consolidation

13. GLOBAL MODULE SURVIVAL TEST

Every Bluefly custom module must produce this:

MODULE=
CUSTOM_PURPOSE=

CORE_ALTERNATIVE=
CONTRIB_ALTERNATIVE=
DRUPAL_AI_ALTERNATIVE=
AI_AGENTS_ALTERNATIVE=
TOOL_ALTERNATIVE=
ECA_ALTERNATIVE=
FLOWDROP_ALTERNATIVE=
MCP_ALTERNATIVE=

WHY_NONE_SUFFICE=

MINIMUM_CUSTOM_SURFACE=

UPSTREAM_CANDIDATE=YES|NO

DELETION_TRIGGER=
OWNER=

If WHY_NONE_SUFFICE= cannot be answered with a concrete technical gap: DELETE / REPLACE THE CUSTOM CODE.


14. TARGET STATE

At completion:

CUSTOM_LLM_CLIENTS=0
CUSTOM_MODEL_ROUTING=0
CUSTOM_AGENT_FRAMEWORKS=0
CUSTOM_GENERIC_WORKFLOW_ENGINES=0
CUSTOM_MCP_TRANSPORTS=0
CUSTOM_RECIPE_ENTITY_SYSTEMS=0
CUSTOM_DDEV_PROCESS_EXECUTION_IN_DRUPAL=0
CUSTOM_GENERIC_VECTOR_MANAGERS=0
HARDCODED_PROVIDER_MODELS=0
RAW_CURL_FOR_AI=0

DUPLICATE_DESIGN_SYSTEM_AUTHORITIES=0
DUPLICATE_RELEASE_SYSTEMS=0

UNJUSTIFIED_CUSTOM_MODULES=0
UNJUSTIFIED_CUSTOM_CONTROLLERS=0
UNJUSTIFIED_CUSTOM_SERVICES=0
UNJUSTIFIED_CONTRIB_OVERLAP=0

DRUPAL_AI_USED_FOR_AI=YES
AI_AGENTS_USED_FOR_AGENTS=YES
AI_CONTEXT_USED_FOR_CONTEXT=YES
TOOL_API_USED_FOR_CAPABILITIES=YES
MCP_SERVER_USED_FOR_MCP_SERVER=YES
ECA_USED_FOR_EVENT_AUTOMATION=YES
FLOWDROP_USED_FOR_VISUAL_PIPELINES=YES
ADVANCEDQUEUE_USED_FOR_DURABLE_ASYNC=YES
MIGRATE_USED_FOR_MIGRATION=YES
CANVAS_USED_FOR_COMPOSITION=YES
SDC_USED_FOR_COMPONENTS=YES
VIEWS_USED_FOR_LISTS=YES
RECIPES_USED_FOR_SITE_ASSEMBLY=YES
GAS_CITY_OWNS_ENGINEERING_ORCHESTRATION=YES
DRUPAL_MANAGES_FACTORY=NO