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_serverconvergence - Status: IN_PROGRESS
- Rule: Do NOT start
ai_agents_orchestra,alternative_services, orrecipe_onboardinguntilmba-3lyulis 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