ContextControl.ai — Technical Architecture v2¶
Version: 2.0.0 | Date: 2026-04-21 Author: Thomas Scola, Bluefly.io Supersedes: CONTEXTCONTROL-TECHNICAL-ARCHITECTURE.md v1.0.0 Purpose: Build bible for Claude Code agents. Thin-install, contrib-first, capability-pack architecture.
Authority model¶
This file (CONTEXTCONTROLTECHNICALARCHITECTUREv2.md) is the only human-readable source of truth for ContextControl.ai architecture, SaaS product behavior, and implementation order.
openapi.jsonis the machine-readable description of custom HTTP routes only. It does not replace this document.- Files
01-SAAS-Platform-Plan.md,02-CLI-and-API.md, and03-Drupal-Modules-Map.mdin this folder are non-normative pointer stubs; they must not introduce requirements.
Documentation boundary¶
- Normative requirements for ContextControl.ai live only in this file.
- Entity CRUD for tenants and product data uses Drupal core JSON:API (see Section 4.1). That surface is not duplicated in
openapi.json. - MCP (tenant-scoped developer access via
drupal/mcp, Tool API, and related config) is specified here and in Drupal configuration.openapi.jsondoes not document MCP unless stable HTTP descriptors are added later by explicit decision. - ContractPlane.ai (Drupal
contractplanemodule and its HTTP helpers) is an optional governance integration for policy-style decisions. It is not the primary subject of ContextControl.ai documentation.
0. Architectural Philosophy¶
What Changed from v1¶
v1 treated ContextControl as a monolithic platform with 90+ custom routes across 12+ custom modules. v2 inverts the model:
- Thin application assembly — install only what the product screens demand today
- Contrib-first mentality — dogfood
drupal/aiand its submodules heavily; every custom controller must justify why ECA + Views + JSON:API cannot handle it - Three tiers — Install Now / Add If Needed / Keep Out
- Capability packs — modules that aren't in the core install are packaged as optional add-ons that can be composed in later without reinstalling
What ContextControl.ai IS¶
- A SaaS control plane — multi-tenant via
drupal/group(companies → workspaces → projects → teams) - A skills/workflow UI — browse, compose, and wire agent capabilities via ECA
- A source connector UI — configure where agents read from (MCP servers, APIs, Drupal sites)
- A memory/orchestration layer — governed shared context with audit trail
- A normalized API surface — JSON:API for CRUD, custom endpoints only for spec compliance (OSSA, DUADP, WebFinger)
- A governed agent registry — register agents, enforce policies, manage trust posture
What ContextControl.ai IS NOT¶
- NOT a full agent execution runtime (that's CoPaw.us — Month 4+)
- NOT a marketplace (that's a separate product)
- NOT a Cedar policy engine (full Cedar comes later as a capability pack). Optional
contractplaneintegration may supply lightweight governance; that is not the product identity of ContextControl.ai. - NOT every contrib or Bluefly module installed at once
SaaS Multi-Tenancy via Groups¶
ContextControl.ai is a SaaS product. Multi-tenancy is foundational, not optional. The drupal/group module and its ecosystem provide the tenant isolation model:
Hierarchy: Organization (Group type) → Workspace (Subgroup) → Project (Subgroup) → Team (Group role collection)
Why Groups over permissions_by_term (v1 approach):
- Groups provides true entity-level access control with membership model
- Content, users, roles, and permissions are scoped per group — not just per taxonomy term
- Subgroups (via ggroup) enable the org → workspace → project hierarchy
- Group roles are independent of Drupal site roles — a user can be admin in one workspace and viewer in another
- Group content plugins automatically scope entities (nodes, media, ai_context_items, ossa_agents) to their group
- Menu per group (via groupmenu) enables workspace-specific navigation
Groups ecosystem modules (all Install Now):
- drupal/group — core group entity, membership, roles, permissions, content plugins
- ggroup (submodule) — subgroup support for hierarchical tenancy
- group_permissions — granular per-group permission overrides
- groupmenu — per-group menu trees
- group_content_menu — content-aware group menus
- ginvite (or custom invite) — group membership invitation workflow
Each group = a tenant boundary: - All OSSA agents belong to a group (workspace) - All ai_context_items (memories, compliance events) belong to a group - Where the contractplane integration is enabled, tenant-scoped policy artifacts and governed writes are tied to the same group hierarchy (not a parallel taxonomy tenancy) - Users access only groups they're members of - Group admins manage their own users, roles, agents, and policies - Site admins see all groups (super-admin / platform operator role)
CRITICAL CHANGE: cedar_policy is OUT¶
This is the biggest architectural shift from v1. The cedar_policy module (40+ routes, SOC2/HIPAA/healthcare dashboards, Cedar gate, security agents) is removed from the initial install. Rationale:
cedar_policyis massive and brings operational complexity that kills the thin-install goal- The
contractplanemodule provides lightweight governance (policy evaluation, audit logging, posture management) without the framework-specific overhead - Cedar policy language support is added later as a capability pack when customers need formal policy authoring
- The compliance dashboard is rebuilt as Views + ECA on
ai_context_itembundles, not a monolithic controller
ContextControl.ai — SaaS product flows (required)¶
ContextControl.ai is a multi-tenant Drupal SaaS product. Tenancy uses drupal/group and ggroup only: no taxonomy.vocabulary.workspace and no site-wide user.role.workspace_* for workspace access (workspace access is group roles).
End-user and tenant lifecycle¶
- Public registration: Anonymous users can register per Drupal user settings (who may register, verification, security modules). Outcome: a user account.
- Company / account (organization): After registration (or first login, depending on UX), the product creates or associates an organization group representing the customer account.
- Default workspace / team: Bootstrap at least one workspace subgroup under that organization (default team/workspace). The creating user receives appropriate group roles on organization and workspace (see group role tables in this document).
- Invitations: Additional users join via group membership (
ginviteor equivalent flows). Permissions and visibility are workspace- and org-scoped; no cross-tenant data paths. - Projects: Project subgroups under a workspace model larger initiatives; create/list/manage stays inside Groups (same permission model as workspace content).
Tenant developers and MCP¶
Developers who are members of a tenant workspace must get MCP access scoped to that workspace: drupal/mcp (server), mcp_tools / Tool API bridging, and configuration under group scope. MCP is not described in openapi.json in v2; document transport, auth, and permission checks here and in Drupal config.
Optional governance integration (ContractPlane)¶
The contractplane Drupal module is an integration for policy evaluation and audit-style decisions on governed operations. It supports product requirements (e.g. memory writes) but does not define ContextControl.ai’s core story (registration, workspaces, projects, MCP).
Future Capability: Knowledge Authority Assurance¶
While initially an internal Bluefly Factory capability, Knowledge Authority Assurance represents a future customer-facing feature governed by ContractPlane. It deterministically detects: - Conflicting policies or duplicate standards - Stale procedures and orphaned knowledge - Invalid ownership and superseded doctrine
Architecture: Rather than an "agent polling" model, it relies on deterministic CI checks and scheduled Gas City Orders (Formulas) that emit docs.integrity_finding events. These findings create deduplicated Beads mapped to semantic owners. ContractPlane governs the resolution rules, ensuring that AI reasoning is only invoked for genuine ambiguity, and ContextControl serves the findings via its human control plane.
Commercial / billing (Phase 3)¶
Paid tiers, Stripe, and subscriptions are explicitly Phase 3. They are not prerequisites to document or implement the tenant flows above in early phases; when added, entitlements should attach to organization (or a dedicated billing profile linked to it).
1. Module Decision Matrix¶
Tier 1: Install Now (Core Platform)¶
| Module | Purpose | Replaces Custom Code? | Dependencies | Phase |
|---|---|---|---|---|
| SaaS Tenancy | ||||
group |
Core multi-tenant entity: groups, membership, roles, content plugins | Replaces permissions_by_term tenant model |
— | Month 1 |
ggroup (submodule) |
Subgroup hierarchy: org → workspace → project | Enables nested tenancy | group |
Month 1 |
group_permissions |
Per-group permission overrides | Fine-grained workspace-level access control | group |
Month 1 |
groupmenu |
Per-group menu trees | Workspace-specific navigation | group |
Month 1 |
group_content_menu |
Content-aware group menus | Dynamic workspace menus | group, groupmenu |
Month 1 |
ginvite |
Group membership invitation | Workspace invite workflow | group |
Month 1 |
| Agent Platform | ||||
ai_agents_ossa |
OSSA agent registry, import/export, discovery, wizard, sandbox | Core pillar — keep | ai_agents, ai |
Month 1 |
ai_agents_explorer |
Agent running/debugging explorer tool | Dev/admin agent testing UI | ai_agents |
Month 1 |
agent_workflow_engine |
ECA-backed agent workflow orchestration | Replaces custom workflow controllers | eca, orchestration |
Month 1 |
orchestration |
Multi-step workflow orchestration entities | Foundation for agent_workflow_engine |
— | Month 1 |
modeler |
BPMN workflow diagram UI | Visual workflow modeling; pairs with Section 2.9 | modeler_api |
Month 1 |
modeler_api |
BPMN API and diagram rendering (bpmn_io) |
Required by modeler |
— | Month 1 |
kb_cache |
Context memory API — bootstrap, authority, governed writes | Core pillar — simplified to glue | ai_context |
Month 1 |
source_connector |
Base source connector framework | Foundation for MCP/API source integration | — | Month 1 |
source_connector_mcp |
MCP-backed source connectors (consume external MCP servers) | Leverages mcp_client for source ingestion |
source_connector, mcp_client |
Month 1 |
skills_browser |
Project Browser-style skills/agent browsing UI | Replaces custom browser controllers | — | Month 1 |
api_normalization |
OpenAPI spec → managed Drupal data sources, auto-generated entities | Replaces custom API integration code | eck |
Month 1 |
ai_provider_routing_eca |
ECA-based AI provider routing (model selection, fallback, cost routing) | Replaces hardcoded provider config | eca, ai |
Month 1 |
contractplane |
Optional governance integration (policy evaluation, audit trail) — not the product core | Replaces cedar_policy where governance is needed |
— | Month 1 |
duadp |
Agent discovery, browser, registry, WebFinger, federation stubs | Core pillar — simplified | — | Month 1 |
agent_registry_consumer |
Consume remote agent registries (DUADP peers) | Foundation for federation | duadp |
Month 1 |
drupal_audit |
Structured audit logging with export | Replaces custom audit controllers in cedar_policy |
— | Month 1 |
| AI Stack (Contrib) | ||||
ai (base) |
Provider-agnostic AI abstraction, operation types, model config | Foundation for all AI operations | — | Month 1 |
ai_automators |
Auto-generate field values on entity save (summarize, tag, alt-text) | Replaces custom AI field processing | ai, token |
Month 1 |
ai_search |
Vector DB-backed Search API implementation | Replaces custom kb_cache search endpoints |
ai, search_api |
Month 1 |
ai_ckeditor |
AI writing assistance in CKEditor 5 | Policy description editing, KB article authoring | ai, ckeditor5 |
Month 1 |
ai_assistant_api |
Decoupled AI assistant entities for any frontend | "Ask about this agent" panel, embedded assistants | ai |
Month 1 |
ai_chatbot |
Chatbot frontend for AI Assistant API | User-facing AI chat widget | ai_assistant_api |
Month 1 |
ai_observability |
OpenTelemetry + Drupal Logger for AI requests | AI operation audit trail (required for compliance) | ai |
Month 1 |
ai_integration_eca |
ECA actions for AI operations (chat, summarize, classify, embed) | Powers all ECA-based AI workflows | ai, eca |
Month 1 |
ai_vdb_provider_qdrant |
Qdrant vector database backend for ai_search | Production vector search for context memories | ai |
Month 1 |
ai_image_alt_text |
Auto-generate image alt text via AI | WCAG compliance for uploaded images | ai |
Month 1 |
api_normalization and ECK (mandatory risk statement): api_normalization deliberately depends on Entity Construction Kit (eck). ECK allows admins to define new entity types from the UI. That increases configuration complexity, attack surface, and risk of uncontrolled entity sprawl across tenants. Mitigations: platform-only ECK administration; allowlisted bundles for API-imported sources; never treat ECK as a free-for-all tenant customization layer; prefer JSON:API-only ingestion when ECK adds no value. Section 2.9 repeats evaluation notes; the Tier 1 table in Section 1 is the only authoritative "Install Now" list (including modeler and modeler_api, which must stay in sync with that table).
Tier 2: Add Only If Needed Immediately¶
| Module | Trigger Condition | Dependencies |
|---|---|---|
ai_agents_claude |
Anthropic is primary provider (likely yes for MVP) | ai_agents, ai_provider_anthropic |
ai_provider_langchain |
LangChain integration required | ai |
ai_agents_huggingface |
Calling HF models directly | ai_agents, ai_provider_huggingface |
ai_agents_marketplace / agent_marketplace |
Marketplace features in scope | ai_agents, duadp |
ai_agents_communication |
Agents send email/SMS/webhooks | ai_agents |
ai_agents_tunnel |
Platform callback URLs required | ai_agents |
source_connector_compliance |
Governance pipeline for source connectors in MVP | source_connector, contractplane |
drupal_patch_framework |
Standardizing patch workflows across fleet | — |
agentic_canvas_blocks |
UI depends on Canvas AI blocks | canvas |
Tier 3: Keep Out For Now¶
| Module | Reason |
|---|---|
blockchain_manager |
Experimental, no product screen requires it |
cedar_policy |
REMOVED from initial install — ContractPlane handles governance; Cedar is a future capability pack |
code_executor |
Agent code execution is Month 4+ |
dragonfly_client |
P0 blocked — backend service broken, Month 4+ |
dita_ccms |
DITA/XML publishing — no product screen |
charts_ai_analytics |
Visualization layer — add when dashboards need charts (Month 2) |
layout_system_converter |
Layout migration tool — not needed |
external_migration |
Migration framework — not needed for MVP |
ai_agents_cursor |
Cursor IDE agent — not needed |
ai_agents_crewai |
CrewAI orchestration — not needed |
ai_agents_kagent |
K8s agent — not needed |
ai_agents_orchestra |
Orchestra framework — not needed |
ai_provider_apple |
Apple Intelligence provider — not needed |
agentdash_platform |
Dashboard platform — replaced by ai_agents_dashboard + Views |
apidog_integration |
API testing integration — dev tool, not product |
source_connect |
Legacy source connector (replaced by source_connector) |
mcp_registry |
MCP server registry — deferred to Month 3+ |
alternative_services |
Experimental |
copaw_bridge |
Agent execution gateway — Month 4+ |
2. Contrib Module Deep Dive¶
2.0 drupal/group — SaaS Multi-Tenancy Foundation¶
What it does: Entity-based access control with membership model. Defines group entities with types, memberships, roles, permissions, and content plugins. Each group is an isolated tenant boundary with its own users, content, roles, and permissions.
Group Types for ContextControl SaaS:
| Group Type | Purpose | Parent | Content Plugins |
|---|---|---|---|
organization |
Top-level customer tenant (company) | None | Users (members), billing settings |
workspace |
Operational workspace within an org | organization (via ggroup) |
OSSA agents, ai_context_items, ContractPlane policies, nodes |
project |
Optional sub-workspace for large teams | workspace (via ggroup) |
Scoped agents and memories |
Submodules and ecosystem:
| Module | What It Does | ContextControl Use | Priority |
|---|---|---|---|
group (base) |
Group entity, membership, roles, content plugins | Foundation — every tenant operation uses this | Install Now |
ggroup (submodule) |
Subgroup relationships (parent → child) | org → workspace → project hierarchy | Install Now |
group_permissions |
Per-group permission overrides beyond role defaults | Workspace-level custom permissions (e.g., one workspace allows agent execution, another doesn't) | Install Now |
groupmenu |
Per-group menu trees | Workspace-specific navigation sidebar | Install Now |
group_content_menu |
Content-aware group menus (auto-add content to group menu) | Auto-menu agent registry, memory browser per workspace | Install Now |
ginvite |
Email-based group membership invitation | "Invite to workspace" workflow (replaces custom invite form) | Install Now |
How Groups replaces permissions_by_term (v1):
| Feature | v1 (permissions_by_term) |
v2 (group) |
|---|---|---|
| Tenant scoping | Taxonomy term reference on every entity | Group content plugin automatically scopes entities |
| User membership | Manual term assignment | Group membership entity with roles |
| Role isolation | Site-wide Drupal roles only | Per-group roles (admin in workspace A, viewer in B) |
| Hierarchy | Flat (one vocabulary) | Nested via ggroup (org → workspace → project) |
| Permissions | Read/view only via term access | Full CRUD + custom permissions per group |
| Invitation | Custom form + code | ginvite module handles entire flow |
| Content access | permissions_by_term hook_node_access |
Group content access plugin (entity-agnostic) |
Group content plugins to register:
# Each entity type that belongs to a workspace gets a group content plugin
group.content_enabler.group_node:workspace_landing:
group_type: workspace
entity_type_id: node
bundle: workspace_landing
group.content_enabler.group_ai_context_item:agent_memory:
group_type: workspace
entity_type_id: ai_context_item
bundle: agent_memory
group.content_enabler.group_ai_context_item:compliance_event:
group_type: workspace
entity_type_id: ai_context_item
bundle: compliance_event
# ossa_agent is a ConfigEntity — Group doesn't natively support ConfigEntities.
# Solution: thin glue module that stores ossa_agent → group mapping
# OR: migrate ossa_agent to ContentEntity (recommended for SaaS)
Critical design decision: ossa_agent is currently a ConfigEntity. ConfigEntities are not natively supported by Group content plugins. Recommended path: Convert ossa_agent to a ContentEntity for the SaaS model. Content entities support Group scoping, revisions, access control, and JSON:API out of the box. The OSSA manifest data (YAML/JSON) is stored as a field.
Group roles for ContextControl:
| Role | Scope | Permissions |
|---|---|---|
organization_owner |
Organization group | Manage all workspaces, billing, SSO config |
organization_admin |
Organization group | Manage workspaces and users, no billing |
workspace_admin |
Workspace group | Full CRUD on agents, policies, memories; manage workspace members |
workspace_operator |
Workspace group | Edit agents and memories; view policies; no member management |
workspace_viewer |
Workspace group | Read-only access to all workspace content |
platform_operator |
Site-wide (Drupal role) | Super-admin; access all groups; manage platform config |
2.1 drupal/ai — Core AI Abstraction Layer¶
What it does: Provider-agnostic AI abstraction. Defines operation types (chat, embeddings, moderation, text-to-image, speech-to-text, etc.) and a plugin system for providers. Every AI call in Drupal goes through this module's API.
How the provider abstraction works:
1. ai.settings.yml defines default providers per operation type
2. Provider plugins (e.g., ai_provider_anthropic) register supported operation types and models
3. Any module calls \Drupal::service('ai.provider')->createInstance($operation_type) to get the configured provider
4. Provider routing can be overridden per-context via ai_provider_routing_eca
Submodules — Complete Inventory (from actual installed code):
| Submodule | What It Does | Lifecycle | ContextControl Use | Tier |
|---|---|---|---|---|
ai (base) |
Provider abstraction, operation types, model config, moderation (merged from ai_external_moderation) |
Stable | Foundation — every AI call routes through this | Install Now |
ai_automators |
Auto-generate field values on entity save (summarize, tag, classify, alt-text) | Stable | Auto-summarize agent memories; auto-tag context items by domain; auto-alt-text on images | Install Now |
ai_search |
Vector DB-backed Search API backend using embeddings | Experimental | Semantic search over context memories (replaces custom kb_cache search endpoints) |
Install Now |
ai_ckeditor |
AI writing assistance in CKEditor 5 (generate, rewrite, expand, summarize) | Stable | KB article authoring, policy description editing, announcement writing | Install Now |
ai_assistant_api |
Decoupled AI assistant entities — config entity defining assistant behavior for any frontend | Stable | "Ask about this agent" assistant panel; embedded compliance Q&A; workspace AI helper | Install Now |
ai_chatbot |
Chatbot frontend widget for AI Assistant API | Stable | User-facing AI chat widget embedded on dashboard and agent detail pages | Install Now |
ai_observability |
OpenTelemetry + Drupal Logger for all AI requests/responses | Stable | Critical for compliance — logs every AI call with tokens, latency, provider, model | Install Now |
ai_api_explorer |
Developer explorer UI for testing AI provider settings | Stable | Admin tool for testing provider config, model parameters, prompt templates | Install Now (dev/admin) |
ai_content_suggestions |
AI-suggested content alterations | ⚠️ DEPRECATED (→ use ai_automators) |
Do NOT install; use ai_automators instead |
Keep Out |
ai_eca |
ECA integration for AI operations | ⚠️ DEPRECATED (removed in AI 2.0.0; → use ai_integration_eca separate module) |
Do NOT install; use ai_integration_eca (separate contrib) |
Keep Out |
ai_external_moderation |
External content moderation | ⚠️ DEPRECATED (merged into ai base) |
Do NOT install; functionality now in ai core |
Keep Out |
ai_logging |
AI request/response logging | ⚠️ DEPRECATED (→ use ai_observability) |
Do NOT install; use ai_observability instead |
Keep Out |
ai_translate |
One-click AI translations | ⚠️ DEPRECATED | Do NOT install; use ai_automators with translation operation or drupal/content_translation + AI provider |
Keep Out |
ai_validations |
AI-powered field validation | ⚠️ DEPRECATED | Do NOT install; requires field_validation module |
Keep Out |
field_widget_actions |
Attach actions to field widgets | ⚠️ DEPRECATED | Do NOT install; replaced by ai_automators |
Keep Out |
⚠️ DEPRECATION WARNING: 6 of 15 submodules in drupal/ai are deprecated as of v1.3.3. The AI module is consolidating toward fewer, more capable submodules for the 2.0 release. The active submodules are: ai (base), ai_automators, ai_search, ai_ckeditor, ai_assistant_api, ai_chatbot, ai_observability, ai_api_explorer.
Separate contrib module (NOT a submodule):
- ai_integration_eca (drupal.org project) — replaces deprecated ai_eca submodule. Provides ECA events/conditions/actions for AI operations. Install Now.
- ai_image_alt_text (drupal.org project) — separate module for auto-generating image alt text. Install Now (WCAG compliance).
- ai_dashboard (drupal.org project) — separate module for AI usage analytics. Install Now.
- ai_vdb_provider_qdrant (drupal.org project) — Qdrant vector DB backend for ai_search. Install Now.
Configuration approach:
# config/sync/ai.settings.yml
default_providers:
chat:
provider_id: anthropic
model_id: claude-sonnet-4-20250514
embeddings:
provider_id: openai
model_id: text-embedding-3-small
moderation:
provider_id: openai
model_id: omni-moderation-latest
What it replaces in ContextControl: The entire custom AI provider wiring in kb_cache (semantic search, summarization, classification) and cedar_policy (AI-assisted policy generation) is replaced by ai + ai_search + ai_integration_eca. No custom AI provider code needed.
Provider modules:
| Provider | What It Does | Tier | Notes |
|---|---|---|---|
ai_provider_anthropic |
Claude models (Sonnet, Opus, Haiku) | Install Now | Primary chat/reasoning provider |
ai_provider_openai |
GPT models + embeddings + moderation | Install Now | Embeddings + moderation |
ai_provider_huggingface |
HuggingFace Inference API | Add If Needed | Only if calling HF models directly |
ai_provider_ollama |
Local Ollama models (Llama, Mistral, etc.) | Add If Needed | For air-gapped / on-prem deployments |
ai_provider_langchain |
LangChain integration | Add If Needed | Only if LangChain orchestration required |
ai_provider_apple |
Apple Intelligence | Keep Out | Not relevant |
ai_provider_amazeeio |
Amazee.io hosting AI | Keep Out | Not relevant |
Vector DB providers:
| Provider | What It Does | Tier | Notes |
|---|---|---|---|
ai_vdb_provider_qdrant |
Qdrant vector DB backend | Install Now | Primary vector store for semantic search |
ai_vdb_provider_milvus |
Milvus vector DB backend | Add If Needed | Alternative to Qdrant; evaluate if Milvus preferred |
2.2 drupal/ai_agents — Base Agent Framework¶
What it does: Drupal-native agent framework. Defines ai_agent config entities, prompt building via BuildSystemPromptEvent, tool execution via Drupal Tool API, and agent configuration UI at /admin/config/ai/agents.
Submodules — Complete Inventory (from actual installed code):
| Submodule | What It Does | Lifecycle | ContextControl Use | Tier |
|---|---|---|---|---|
ai_agents (base) |
Agent config entities, prompt event system, tool bridge, system prompt building | Stable | Foundation — ai_agents_ossa extends this |
Install Now |
ai_agents_explorer |
Developer tool for running and debugging agents interactively | Stable | Admin/dev tool for testing agent configurations, inspecting prompt chains, debugging tool invocations | Install Now |
ai_agents_extra |
Experimental extra agents (Views agent, Webform agent, Module agent) | ⚠️ Experimental, hidden | Evaluate — Views agent could auto-generate Views; Webform agent could build forms | Add If Needed |
ai_agents_extra_tools |
Experimental extra tools for agents | ⚠️ Deprecated, hidden | Do NOT install; security concerns noted | Keep Out |
ai_agents_form_integration |
AI-assisted form generation and config creation | ⚠️ Experimental, hidden | Could assist in agent registration wizard | Add If Needed |
External ai_agents_* modules (separate drupal.org projects):
| Module | What It Does | Tier | Notes |
|---|---|---|---|
ai_agents_ossa |
OSSA manifest support, import/export, discovery, wizard, sandbox | Install Now | Core pillar — Bluefly custom module |
ai_agents_claude |
Anthropic Claude-specific agent capabilities and tool bindings | Add If Needed | Likely yes for MVP if Anthropic is primary |
ai_agents_huggingface |
HuggingFace model integration for agents | Add If Needed | Only if calling HF models |
ai_agents_communication |
Email/SMS/webhook agent notification channels | Add If Needed | When agents need to send notifications |
ai_agents_tunnel |
Reverse tunnel for platform callbacks to agents | Add If Needed | When platform needs to call back to agent |
ai_agents_marketplace |
Marketplace publishing/browsing for agents | Keep Out | Separate product |
ai_agents_crewai |
CrewAI multi-agent framework integration | Keep Out | Not needed |
ai_agents_cursor |
Cursor IDE agent integration | Keep Out | Not needed |
ai_agents_kagent |
Kubernetes agent | Keep Out | Not needed |
ai_agents_orchestra |
Orchestra multi-agent framework | Keep Out | Not needed |
Relationship to ai_agents_ossa: ai_agents provides the base AiAgentInterface and BuildSystemPromptEvent. ai_agents_ossa subscribes to this event via OssaPromptSubscriber and injects OSSA manifest context. Both coexist — ai_agents handles Drupal-native agents (content triage, field agents), ai_agents_ossa handles OSSA-standard agents from external platforms.
Built-in triage agents (already configured):
- content_type_agent_triage — routes requests to content-type-specific agents
- field_agent_triage — field-level AI triage
- taxonomy_agent_config — taxonomy classification agent
How it replaces custom code: The custom agent list controllers, status dashboards, and health check endpoints in the v1 architecture are all replaced by ai_agents_explorer for debugging + Views for listing. The custom HarnessController (7 routes) is entirely eliminated — agent execution is handled by the ai_agents framework + Tool API.
2.2a drupal/tool — Tool Plugin Framework¶
What it does: Provides the Tool plugin type for creating well-defined, discoverable actions that agents can invoke. This is the Drupal Tool API that bridges agent capabilities to Drupal operations.
ContextControl use: Every agent tool (query memories, evaluate policy, search agents, write context) is a Tool plugin. ai_agents discovers and invokes these tools. mcp_tools bridges them to MCP protocol.
Installed alongside: tool_belt — additional utility tools.
Tier: Install Now (already in composer.json)
2.3 drupal/mcp_client — MCP Client¶
What it does: Allows Drupal to consume external MCP servers. Configures MCP server connections (URL, auth, transport), discovers available tools/resources/prompts, and makes them available as Drupal Tool API plugins.
How this powers source_connector_mcp: The source_connector_mcp module registers MCP servers as "sources" in the source connector framework. When a user configures an MCP source (e.g., "Connect to my Acquia site's MCP server"), mcp_client handles the transport and tool discovery. The source connector UI wraps this in a user-friendly form.
Configuration:
# MCP server connection config entity
mcp_client.server.acquia_site:
id: acquia_site
label: 'Acquia Production Site'
url: 'https://mysite.acquia.com/mcp'
transport: streamable_http
auth_type: bearer_token
auth_key: acquia_mcp_token # References key.key entity
Also installed: drupal/mcp (MCP server — makes ContextControl itself an MCP server) and drupal/mcp_tools (bridges Drupal Tool API plugins to MCP tools). Together these make ContextControl both an MCP server (agents connect TO it) and an MCP client (it connects to other MCP servers).
2.4 drupal/eca — Event-Condition-Action Framework¶
What it does: Visual workflow builder for Drupal. Replaces custom event subscribers, hook implementations, and cron jobs with config-exportable workflow models. Every workflow in ContextControl v2 is an ECA model.
⚠️ IMPORTANT: Use ai_integration_eca (separate contrib module), NOT the deprecated ai_eca submodule of drupal/ai. The ai_eca submodule is being removed in AI 2.0.0.
AI-related ECA events/conditions/actions (via ai_integration_eca):
Events:
- ai.operation.pre_execute — before any AI operation fires
- ai.operation.post_execute — after AI operation completes
- ai.agent.prompt_build — during agent prompt assembly
- ai.agent.tool_invoke — when agent invokes a tool
- ai.agent.execution_complete — after agent finishes
- ai_context_item.insert / .update / .delete — context item lifecycle
- group.membership.insert / .update / .delete — group membership changes (for invite/offboard workflows)
- group_content.insert — content added to group (for scoping validation)
Conditions: - AI operation type matches (chat, embeddings, etc.) - AI provider matches - Token count exceeds threshold - Agent trust tier at or above level - Context item bundle matches - Group type matches (organization, workspace, project) - User has group role (workspace_admin, workspace_operator, etc.) - Group compliance profile includes framework
Actions:
- ai_chat — send prompt to AI provider, store response in token
- ai_summarize — summarize text
- ai_classify — classify content into categories
- ai_embed — generate embedding vector
- ai_moderate — run moderation check
- create_ai_context_item — create a context memory
- update_entity_field — set field values on any entity
- send_email — SMTP notification
- log_message — watchdog logging
- execute_views_query — run a View and process results
- add_group_membership — add user to group with role
- remove_group_membership — remove user from group
How to replace custom workflow code with ECA models:
| v1 Custom Code | v2 ECA Model | Benefit |
|---|---|---|
cedar_policy ComplianceApiController security event tracking |
ECA: on login failure → create compliance_event ai_context_item |
Config-exportable, no PHP |
cedar_policy compliance score recalculation (custom cron) |
ECA: cron every 15min → Views query compliance_events → calculate ratio → update workspace group metric field (Groups model; not a workspace taxonomy term) | Admin-editable schedule |
kb_cache memory governance validation |
ECA: on ai_context_item insert → validate workspace → check limits → ContractPlane authorize → log | Auditable workflow definition |
| Custom email notifications for policy violations | ECA: on compliance_event with decision=deny AND severity=critical → email workspace admin | No custom mail hook |
| Agent registration approval workflow | ECA: on ossa_agent create → check compliance profile → conditionally disable + email admin | Visible in ECA modeler UI |
| Daily compliance digest | ECA: daily cron → Views query → ai_summarize → email | AI-powered, config-managed |
ai_provider_routing_eca specifics: This module adds ECA conditions and actions for dynamic provider routing. Instead of hardcoding "use Anthropic for chat" in ai.settings.yml, you define ECA rules:
- If agent trust_tier = "verified" AND operation = "chat" → use Claude Opus
- If agent trust_tier = "provisional" → use Claude Sonnet (cheaper)
- If operation = "embeddings" → always use OpenAI text-embedding-3-small
- If rate limit exceeded on primary → fallback to secondary provider
This replaces any custom provider selection logic.
2.5 drupal/orchestration — Workflow Orchestration¶
What it does: Multi-step workflow orchestration with state tracking. Defines orchestration entities that track workflow progress through states, with support for parallel execution, conditional branching, and error handling.
How agent_workflow_engine uses it: The agent_workflow_engine module extends orchestration to define agent-specific workflows:
- Agent registration → validation → trust assessment → activation
- Memory write → governance check → persist → broadcast
- Source ingestion → transform → store → index
Each workflow step is an orchestration state with ECA-triggered transitions.
Maestro integration possibilities: The drupal/orchestration module can be extended with Maestro for complex BPMN workflows. However, for MVP, ECA + orchestration is sufficient. Maestro adds value in Month 3+ for multi-approval chains and long-running processes.
2.6 drupal/flowdrop — Visual Flow Builder¶
What it does: Drag-and-drop flow builder UI for creating data pipelines and transformation workflows. Built on top of orchestration.
ContextControl use: Flow builder for source connector pipelines — "drag an MCP source, connect to a transform step, connect to a memory store." Deferred to Month 2 when the source connector UI is polished.
2.7 Canvas / Experience Builder¶
What it does: React-based visual page builder for Drupal 11.1+. Replaces Layout Builder with a modern, component-driven page composition system.
Key pieces:
| Component | Role | ContextControl Use |
|---|---|---|
canvas (base) |
Page builder engine, component registry | Page layout for dashboard, agent detail, compliance views |
canvas_ai (submodule) |
AI-assisted component generation, text rewriting, SDC synthesis | "Generate a dashboard layout for compliance monitoring" |
| SDC API | Single Directory Components — self-contained UI components | All ContextControl UI components (agent-card, compliance-score, memory-timeline, etc.) |
| Code Components | Custom React components within Canvas | Interactive widgets (compliance score ring, activity timeline) |
How to build the ContextControl UI with Canvas:
- SDC components (defined in
bluefly_theme/components/) provide the atomic UI pieces (see §7) - Canvas layouts compose SDCs into page layouts
- canvas_ai assists in generating new component variations and page layouts
- Month 1: Dashboard is a custom controller (speed). Agent browser uses DUADP's existing controller.
- Month 2: Migrate dashboard, agent detail, and compliance pages to Canvas layouts
2.8 Drupal CMS 2.x Recipes Ecosystem¶
What it does: Recipes are composable, declarative site configurations that replace custom install profiles. They define modules to enable, config to import, content to create, and permissions to set — all in YAML.
Key recipe modules:
| Recipe/Module | What It Does | ContextControl Use |
|---|---|---|
drupal_cms_ai |
Installs and configures AI module stack with sensible defaults | Base AI setup — providers, automators, CKEditor integration |
drupal_cms_ai_ckeditor |
AI writing tools in CKEditor | Policy description editing, KB article authoring |
drupal_cms_search |
Search API + facets configuration | Memory search, agent search |
drupal_cms_analytics |
Google Analytics / Matomo integration | Usage tracking |
drupal_cms_content_type_base |
Base content type with standard fields (SEO, scheduling, workflow) | Foundation for workspace_landing, announcement, kb_article |
recipe_installer_kit |
Utilities for building recipes (config actions, entity creation) | Build ContextControl as a recipe kit |
site_template_helper |
Site template scaffolding | Package ContextControl as a site template |
How to build ContextControl as a site template / recipe kit:
contextcontrol/
├── recipe.yml # Root recipe
├── recipes/
│ ├── contextcontrol_core/
│ │ └── recipe.yml # Core: ai_agents_ossa, kb_cache, duadp, contractplane
│ ├── contextcontrol_workspace/
│ │ └── recipe.yml # Group types, group roles, group content plugins (v2: no workspace taxonomy)
│ ├── contextcontrol_compliance/
│ │ └── recipe.yml # Compliance event bundle, dashboards, ECA models
│ ├── contextcontrol_ui/
│ │ └── recipe.yml # Theme, SDCs, Canvas layouts, dashboard
│ └── contextcontrol_providers/
│ └── recipe.yml # AI provider config (Anthropic, OpenAI)
Each recipe is independently applicable. A customer can apply contextcontrol_core without contextcontrol_compliance if they don't need governance yet.
Root recipe.yml:
name: 'ContextControl'
description: 'Governed AI workspace for agent registration, policy enforcement, and shared context.'
type: 'Site template'
recipes:
- contextcontrol_core
- contextcontrol_workspace
- contextcontrol_compliance
- contextcontrol_ui
- contextcontrol_providers
install:
- ai_agents_ossa
- ai_agents_ui
- ai_agents_dashboard
- agent_workflow_engine
- kb_cache
- source_connector
- source_connector_mcp
- skills_browser
- api_normalization
- ai_provider_routing_eca
- contractplane
- duadp
- agent_registry_consumer
- drupal_audit
config:
actions:
# Config actions applied after install
2.9 Additional Contrib Evaluation¶
The Tier 1 table in Section 1 is authoritative for which modules are Install Now. Rows below are evaluation notes; when they say Install Now, the module must also appear in that Tier 1 table (or the table is updated first). modeler and modeler_api are Install Now in Tier 1 and repeated here for evaluation context only.
| Module | What It Does | Useful for ContextControl? | Tier | Rationale |
|---|---|---|---|---|
Byte (drupal/byte) |
Binary data handling, byte-level file processing, encoding utilities | Agent artifact storage (OSSA YAML bundles, signed manifests, binary attestations). Also useful for processing uploaded OSSA files that may contain embedded binary signatures. | Add If Needed | Not required for MVP text-based manifests; add when binary artifact signing is in scope |
Diagnosis (drupal/diagnosis) |
System health diagnostics — requirement checks, status monitoring, service connectivity verification | Platform health dashboard at /admin/reports/platform-health showing: module status, AI provider connectivity, Qdrant vector DB health, MCP server availability, group/workspace counts, memory usage stats |
Add If Needed | Useful for Month 2 platform operator dashboard; pair with health_check for API health endpoint |
Healthcare (drupal/healthcare) |
HIPAA-aligned content types, patient data handling, compliance workflows, audit requirements | Capability pack for healthcare vertical. When a healthcare customer needs HIPAA content types and PHI handling, this module provides the entity model. It does NOT replace ContractPlane for policy governance — it adds healthcare-specific content structures. | Keep Out | Only add as capability pack when selling to healthcare customers |
Modeler (drupal/modeler) |
Visual BPMN modeling UI — drag-and-drop workflow builder, process diagram rendering | Visual agent workflow modeling in the admin UI. Workspace admins can see and edit orchestration flows as diagrams. Pairs with modeler_api for programmatic diagram generation. |
Install Now | Already in composer.json. Powers the workflow visualization layer for agent_workflow_engine. |
Modeler API (drupal/modeler_api) |
Programmatic API for BPMN diagram creation, rendering, and manipulation. Includes bpmn_io integration for BPMN.js rendering. |
Backend for diagram generation — agents can produce workflow diagrams; compliance reports can include process flow visualizations. | Install Now | Already in composer.json. Required by modeler. |
| Saplings AI Agent Modeler | Visual drag-and-drop agent composition UI — wire capabilities, tools, prompts, and memory sources into agent definitions | Could replace the custom ai_agents_ossa_wizard submodule for agent creation. Evaluate whether it can output OSSA-format manifests. If yes, it becomes the primary agent builder UI. If no, use as visual preview only. |
Add If Needed | Evaluate compatibility with ai_agents_ossa manifest format. High potential to reduce custom wizard code. |
Charts AI Agents (drupal/charts + AI extensions) |
AI-powered chart and visualization generation for dashboards. Takes data + prompt → produces chart config. | Month 2: AI-generated compliance trend charts, agent activity visualizations, memory growth graphs. Powers the dashboard Charts widgets. | Keep Out Month 1, Add If Needed Month 2 | drupal/charts is already installed. AI chart generation is additive. |
| Paragraphs AI | AI-assisted paragraph/component assembly — suggest paragraph types, auto-populate fields, generate structured content blocks | KB article generation: "Generate a getting-started guide" → structured paragraphs with headings, steps, code blocks. Compliance report assembly: structured sections with evidence links. | Add If Needed | Useful for Month 2 KB module. Not needed for MVP which uses basic node fields. |
Maestro (drupal/maestro) |
Full BPMN workflow engine with persistent state, human task assignment, timer events, conditional gateways. Activepieces integration for external automations. | Complex multi-step approval workflows: agent registration approval chain (security team → compliance team → workspace admin). Long-running agent orchestration with checkpoints. Audit evidence collection workflows spanning days/weeks. | Add If Needed Month 3 | ECA handles simple event-driven workflows. Maestro is needed when workflows require: (a) human tasks with assignment, (b) timer-based escalation, (c) persistent state across days, (d) complex conditional branching. Not Month 1. |
Orchestration (drupal/orchestration) |
Multi-step workflow orchestration with state tracking, parallel execution, conditional branching, error handling | Foundation for agent_workflow_engine. Defines orchestration entities that track workflow progress through states. Simpler than Maestro but sufficient for agent workflows. |
Install Now | Already in composer.json. Required by agent_workflow_engine. |
FlowDrop (drupal/flowdrop) |
Drag-and-drop flow builder UI for data pipelines and transformation workflows. Built on orchestration. |
Source connector pipeline builder: "drag MCP source → connect to transform → connect to memory store." Visual flow composition for non-technical workspace admins. | Add If Needed Month 2 | Not needed for MVP. Add when source connector UI needs visual flow building. |
2.10 GitLab Integration Points¶
| GitLab Feature | Bluefly Mapping | Implementation |
|---|---|---|
| GitLab Duo Agent Platform | Maps to OSSA — GitLab's native agent framework can register agents as OSSA manifests | ai_agents_ossa import supports GitLab agent definitions; /.well-known/ossa discovery enables GitLab to find ContextControl agents |
| GitLab AI Catalog | Maps to DUADP — GitLab's AI model/tool catalog is analogous to DUADP's agent/skill registry | duadp browser can consume GitLab AI Catalog entries; federation protocol supports GitLab as a peer node |
| GitLab Flows | Maps to agent_workflow_engine — GitLab CI/CD flows trigger agent workflows |
ECA event on webhook receipt → orchestration workflow step → agent execution |
| GitLab CI Components | Deployment recipes — reusable CI/CD templates for ContextControl deployment | @bluefly/gitlab_components/contextcontrol-deploy component for standardized deployment pipeline |
CI/CD recipe for ContextControl deployment:
# .gitlab-ci.yml using GitLab CI Components
include:
- component: gitlab.com/blueflyio/gitlab-components/[email protected]
inputs:
site: contextcontrol
environment: production
recipe: contextcontrol_core
drush_commands:
- "recipe:apply contextcontrol_core"
- "cr"
- "updb"
3. Content Model (v2 — Thinner Install, Groups-Based)¶
3.1 What Changes from v1¶
- REPLACED:
permissions_by_termtenant model →drupal/groupwith subgroups for SaaS multi-tenancy - REMOVED:
cedar_policyECK entity type and all its bundles — governance handled bycontractplaneentities - REMOVED:
api_endpointECK entity type —api_normalizationprovides its own entity model - REMOVED:
gitlab_issuenode type — no longer importing GitLab issues - SIMPLIFIED:
compliance_eventai_context_item bundle replaces the entirecedar_policyaudit log - ADDED:
contractplaneprovides its own lightweight policy entity - ADDED:
groupentity types for organization, workspace, project - RECOMMENDED: Convert
ossa_agentfrom ConfigEntity to ContentEntity for Group content plugin support
3.2 Entity Ownership Map¶
| Entity Type | Source (Contrib vs Custom) | Module | Group-Scoped? |
|---|---|---|---|
group (organization, workspace, project) |
Contrib | drupal/group |
N/A (is the scope) |
group_membership |
Contrib | drupal/group |
Per-group |
ossa_agent (ContentEntity — migrated) |
Custom (Bluefly) | ai_agents_ossa |
Yes — group content |
ai_context_item (ContentEntity) |
Contrib | drupal/ai_context |
Yes — group content |
ai_agent (ConfigEntity) |
Contrib | drupal/ai_agents |
No (site-wide config) |
ai_assistant (ConfigEntity) |
Contrib | drupal/ai_assistant_api |
No (site-wide config) |
duadp_node (ConfigEntity) |
Custom (Bluefly) | duadp |
No (site-wide config) |
tool_binding (ConfigEntity) |
Custom (Bluefly) | duadp |
No (site-wide config) |
contractplane_policy (ContentEntity) |
Custom (Bluefly) | contractplane |
Yes — group content |
contractplane_decision (ContentEntity) |
Custom (Bluefly) | contractplane |
Yes — group content |
| Taxonomy terms | Core | Drupal core | Some (workspace-specific vocabs via Group) |
| Nodes | Core | Drupal core | Yes — group content |
| Users | Core | Drupal core | Via group membership |
Key insight: Groups replaces the taxonomy-based scoping from v1. Every ContentEntity that belongs to a workspace is a Group content relation. ConfigEntities remain site-wide (they're deployment config, not tenant content). The ossa_agent migration from ConfigEntity to ContentEntity is recommended to enable proper Group scoping — this is the single biggest data model change from v1.
3.3 ai_context_item Bundles (v2)¶
| Bundle | Purpose | Key Fields | Source |
|---|---|---|---|
agent_memory |
Agent-produced memories | agent_id, content, type, confidence, session_id, gaid, domain, workspace | Existing |
compliance_event |
ContractPlane decision audit log | decision (allow/deny), principal, action, resource, policy_ref, severity, context_json, eval_time_ms, workspace | NEW |
shared_context |
Cross-agent shared context | base fields + workspace | Existing |
plan_item |
Plan tracking | plan_id, status, priority, category, domain, deadline | Existing (disable for MVP) |
3.4 Taxonomy Vocabularies (v2)¶
Groups replaces the workspace taxonomy for tenant scoping. Remaining vocabularies:
- ~~
workspace~~ — REMOVED — replaced bygroupentity (type: workspace) compliance_framework— KEEP (SOC2, HIPAA, FedRAMP, etc.) — referenced by group fieldsagent_capability— KEEP (capability tags)trust_tier— KEEP (6-state posture)policy_category— KEEP (policy organization)kb_category— KEEP (KB article categories)tags— KEEP (general purpose)ai_context_tags— KEEP (ai_context module uses this)- ~~
kb_domain~~ — REMOVED — workspace scoping via Groups - ~~
memory_domain~~ — REMOVED — workspace scoping via Groups
3.5 Node Types (v2)¶
| Type | Status | Notes |
|---|---|---|
workspace_landing |
NEW | Per-workspace landing page |
announcement |
NEW | Platform announcements |
kb_article |
NEW | Knowledge base articles |
article |
KEEP | Marketing/blog content |
page |
KEEP | Static pages |
kb_context_memory |
KEEP | Human-curated "golden" memories |
gitlab_issue |
REMOVE | Tied to api_normalization which is now thin |
kb_idea |
DISABLE | Month 2+ |
kb_plan |
DISABLE | Month 2+ |
kb_project |
DISABLE | Month 2+ |
kb_ownership |
DISABLE | Month 2+ |
4. API Architecture (v2)¶
4.0 API surface boundary¶
| Surface | Role | Where specified |
|---|---|---|
| Drupal JSON:API | Default CRUD for content and config entities exposed by the site | This document (Section 4.1); not in openapi.json |
openapi.json |
Custom HTTP routes only (Section 4.2), for specs and integrations that should not be modeled as JSON:API | Repository file openapi.json |
| MCP + Tool API | Tenant developer access and agent tooling, scoped to group | This document (Sections 2.x MCP modules, product flows above); not in openapi.json unless HTTP mapping is added later |
/api/contractplane/* |
Optional governance integration HTTP helpers when contractplane is enabled |
openapi.json + Section 4.2 |
4.1 JSON:API for Standard CRUD (Unchanged from v1)¶
All entity CRUD goes through Drupal's core JSON:API module. No custom REST endpoints for CRUD operations.
Entities exposed:
| Entity | Bundle(s) | Path |
|---|---|---|
ai_context_item |
agent_memory, compliance_event, shared_context | /jsonapi/ai-context-item/{bundle} |
node |
workspace_landing, announcement, kb_article, article, page | /jsonapi/node/{type} |
taxonomy_term |
compliance_framework, agent_capability, trust_tier, policy_category, kb_category, tags, ai_context_tags (not workspace — workspace scope is group) |
/jsonapi/taxonomy-term/{vocabulary} |
user |
— | /jsonapi/user/user |
4.2 Custom Endpoints (Only for Spec Compliance)¶
Total custom routes in v2 MVP: 11 (down from 13 in v1, down from 90+ in original modules). Routes whose primary purpose is OSSA / DUADP / WebFinger / health / kb_cache bootstrap are product-facing. Routes under /api/contractplane/* are optional governance integration helpers when contractplane is installed; they do not define the core SaaS flows in Section “SaaS product flows”.
| Route | Method | Module | Reason |
|---|---|---|---|
/.well-known/ossa/{slug} |
GET | ai_agents_ossa |
OSSA spec format |
/.well-known/duadp.json |
GET | duadp |
DUADP spec format |
/.well-known/webfinger |
GET | duadp |
RFC 7033 |
/api/v1/agents |
GET | duadp |
DUADP-format response |
/api/v1/publish |
POST | duadp |
OSSA manifest parse + validate |
/api/v1/search |
GET | duadp |
Cross-entity DUADP search |
/api/v1/health |
GET | duadp |
Aggregated health check |
/api/contractplane/authorize |
POST | contractplane |
Policy evaluation (replaces Cedar gate) |
/api/contractplane/status |
GET | contractplane |
Governance status |
/api/v1/bootstrap/authority |
GET | kb_cache |
Agent bootstrap protocol |
/dashboard |
GET | custom controller | Rendered HTML |
4.3 api_normalization Module Role¶
api_normalization transforms external OpenAPI/Swagger specs into managed Drupal data sources. In ContextControl v2, it serves as:
- Source connector backend — when a user adds an API source,
api_normalizationparses its OpenAPI spec and auto-generates field mappings - Provider management — AI provider APIs can be registered as normalized sources, enabling dynamic provider discovery
- NOT needed for: internal ContextControl API surface (that's JSON:API + custom endpoints above)
5. Workflow Architecture (ECA-First)¶
5.1 Principle¶
Every workflow is an ECA model. No custom event subscribers. No custom cron hooks. No custom form alters unless ECA truly cannot handle the use case.
5.2 Complete ECA Model Inventory¶
Groups integration: All flows use
groupentities (organization/workspace/project) instead of taxonomy-based workspace references. Membership is viagroup_membershipcontent plugin; roles aregroup_roleentities. Nopermissions_by_term.
Organization + Workspace Creation Flow¶
Event: entity.insert (entity_type = group, bundle = organization)
Conditions: none
Actions:
1. Create default child workspace group (subgroup via ggroup):
type=workspace, label="{org.label} — Default Workspace"
2. Add creating user as organization admin (group_membership + group_role=org_admin)
3. Add creating user as workspace admin on the default workspace
4. Create ai_context_item bundle=compliance_event:
title="Organization {label} created", decision=allow, principal=current_user
5. IF organization.field_plan = "enterprise":
a. Create ContractPlane tenant record (POST /api/contractplane/tenant)
6. Log to watchdog
Agent Registration Flow¶
Event: entity.insert (entity_type = group_content, plugin = group_ossa_agent)
— ossa_agent added to a workspace group
Conditions: none
Actions:
1. Resolve parent workspace group from group_content relationship
2. Check workspace agent count limit (Views: count group_content where
group=workspace AND plugin=group_ossa_agent vs workspace.field_max_agents)
3. Create ai_context_item bundle=compliance_event as group content of workspace:
title="Agent {agent.label} registered in {workspace.label}",
decision=allow, principal=current_user
4. IF workspace.field_compliance_profile includes soc2 OR hipaa:
a. Set agent entity status = FALSE (disabled)
b. Email workspace admins (ginvite: group role = workspace_admin):
"Agent {label} requires approval"
5. Log to watchdog
Memory Governance Flow¶
Event: entity.insert (entity_type = ai_context_item, bundle = agent_memory)
Conditions: entity is group content of a workspace group (group_content exists)
Actions:
1. Resolve parent workspace group from group_content relationship
2. Check workspace memory count limit (Views: count ai_context_item where
group=workspace AND bundle=agent_memory vs workspace.field_max_memories)
3. IF over limit: reject write, create compliance_event (decision=deny)
4. POST to /api/contractplane/authorize with:
principal=field_kb_agent_id, action=memory.write,
resource=group:workspace:{group_id}
5. IF ContractPlane denies: delete the entity, create compliance_event
6. ai_classify: auto-tag the memory by domain
7. ai_embed: generate embedding for vector search index
8. Log to watchdog
Source Ingestion Flow¶
Event: custom event "source_connector.ingest"
Conditions: source connector is active AND is group content of a workspace
Actions:
1. Resolve parent workspace group from source connector group_content
2. Fetch data from source (MCP call or API call via api_normalization)
3. Transform via Tamper (field mapping, data cleaning)
4. Create ai_context_item bundle=shared_context as group content of workspace
5. ai_embed: generate embeddings for search
6. Log ingestion stats to watchdog
Compliance Alert Flow¶
Event: entity.insert (entity_type = ai_context_item, bundle = compliance_event)
Conditions: field_decision = "deny" AND field_severity IN [critical, high]
Actions:
1. Resolve parent workspace group from group_content relationship
2. Send email to workspace admins (users with workspace_admin group role)
3. IF 5+ denials in last hour for this workspace (Views count):
a. Resolve parent organization group (ggroup parent)
b. Send escalation email to organization admins
4. Log to watchdog with severity=alert
Daily Digest Flow¶
Event: ECA cron, daily at 08:00 UTC
Conditions: none
Actions:
1. For each workspace group with active members (Views: group_membership
where group.bundle=workspace AND member.access > now()-30d):
a. Count agents (Views: group_content plugin=group_ossa_agent)
b. Count memories written in 24h (Views: ai_context_item in workspace)
c. Count compliance decisions (Views: compliance_event in workspace)
d. ai_summarize: generate digest summary via drupal/ai
e. Send email to workspace admin members (group_role=workspace_admin)
User Invite Flow (ginvite)¶
Event: custom event "contextcontrol.workspace.member_invite"
Conditions: current user has group permission "administer members" in target workspace
Actions:
1. Check if user with email exists in Drupal
2. IF exists:
a. Add user to workspace group via group_membership content plugin
b. Assign requested group_role (viewer/editor/admin)
c. Send notification email
3. IF new user:
a. Create ginvite invitation entity for workspace group
b. Assign requested group_role to invitation
c. Send invite email with registration + group-join link
4. Create ai_context_item bundle=compliance_event as group content:
"User {email} invited to {workspace.label} as {role}"
5. Log to watchdog
Project Creation Flow (ggroup subgroup)¶
Event: entity.insert (entity_type = group, bundle = project)
— project is a subgroup of a workspace via ggroup
Conditions: none
Actions:
1. Inherit workspace group members with mapped roles (ggroup inheritance)
2. Create ai_context_item bundle=compliance_event as group content of workspace:
title="Project {label} created in {workspace.label}"
3. Log to watchdog
6. Canvas / UI Architecture¶
6.1 SDC Components Needed¶
All SDC components live in web/themes/custom/bluefly_theme/components/.
| Component | Purpose | Props |
|---|---|---|
contextcontrol-agent-card |
Agent summary card | agent_id, label, type, trust_tier, capabilities[], status, workspace |
contextcontrol-compliance-score |
Compliance posture ring | score (0-100), label, allows, denies, trend |
contextcontrol-memory-timeline |
Vertical timeline of context events | items[]{timestamp, agent_id, action, content_preview, memory_type} |
contextcontrol-policy-decision-log |
Table of policy decisions | decisions[]{timestamp, decision, principal, action, resource, policy_id} |
contextcontrol-workspace-switcher |
Workspace context dropdown | workspaces[]{id, name, slug}, active_workspace |
contextcontrol-stat-card |
Generic stat card (count + label + trend) | value, label, trend, icon, link |
contextcontrol-activity-feed |
Recent activity list | items[]{timestamp, actor, action, target, workspace} |
6.2 Dashboard Composition¶
Month 1 (custom controller): Four contextcontrol-stat-card SDCs in a 2×2 CSS Grid, plus contextcontrol-activity-feed below.
Month 2 (Canvas layout): Dashboard page built in Canvas with:
- Row 1: 4× contextcontrol-stat-card (agents, compliance, context, activity count)
- Row 2: contextcontrol-compliance-score + contextcontrol-policy-decision-log
- Row 3: contextcontrol-memory-timeline + contextcontrol-activity-feed
- All components are Views-powered with contextual workspace filter
6.3 canvas_ai for AI-Assisted Page Building¶
canvas_ai enables:
- "Generate a compliance monitoring layout" → AI creates Canvas page with appropriate SDCs
- "Rewrite this dashboard description" → AI rewrites in-place
- SDC synthesis — AI can generate new component variants based on existing ones
In v2, canvas_ai is available but not relied upon for MVP screens. It becomes the power tool in Month 2 for rapid page iteration.
7. Drupal CMS 2.x Recipe Strategy¶
7.1 Recipe Composition¶
ContextControl is packaged as a recipe kit — a set of composable recipes that can be applied independently or together.
recipes/
├── contextcontrol_core/
│ ├── recipe.yml
│ └── config/
│ ├── ai_agents_ossa.settings.yml
│ ├── kb_cache.settings.yml
│ └── duadp.settings.yml
├── contextcontrol_workspace/
│ ├── recipe.yml
│ └── config/
│ ├── group.type.*.yml
│ ├── group.role.*.yml
│ ├── group.content_enabler.*.yml
│ └── field.storage.*.yml
├── contextcontrol_compliance/
│ ├── recipe.yml
│ └── config/
│ ├── ai_context.ai_context_item_type.compliance_event.yml
│ ├── views.view.compliance_dashboard.yml
│ └── eca.eca_model.compliance_alert.yml
├── contextcontrol_ui/
│ ├── recipe.yml
│ └── config/
│ ├── views.view.memory_browser.yml
│ ├── dashboards.dashboard.main.yml
│ └── bluefly_theme.settings.yml
├── contextcontrol_providers/
│ ├── recipe.yml
│ └── config/
│ ├── ai.settings.yml
│ ├── key.key.anthropic_api_key.yml
│ └── key.key.openai_api_key.yml
└── contextcontrol_seed/
├── recipe.yml
└── content/
├── ossa_agents/ # 3 sample agents
├── policies/ # 10 starter policies
└── memories/ # 5 sample memories
contextcontrol_workspace exports (v2): Do not include taxonomy.vocabulary.workspace or site-wide user.role.workspace_*. Multi-tenancy is Groups-only (group types, group roles, group content plugins); see Section 3.
7.2 Site Template Approach¶
Using drupal_cms_site_template_base + site_template_helper, ContextControl can be published as a site template that appears in the Drupal CMS installer. New users select "ContextControl" during install and get a fully configured instance.
site_template.yml:
name: 'ContextControl'
description: 'Governed AI workspace for agent registration, policy enforcement, and shared context.'
icon: contextcontrol-icon.svg
recipes:
- drupal_cms_starter
- drupal_cms_ai
- drupal_cms_search
- contextcontrol_core
- contextcontrol_workspace
- contextcontrol_compliance
- contextcontrol_ui
- contextcontrol_providers
- contextcontrol_seed
8. Custom Module Reduction Plan (v2)¶
8.1 The 14 Custom Modules — Mapped Against Contrib-First¶
| Custom Module | v1 Status | v2 Action | Replacement | Custom Code Remaining |
|---|---|---|---|---|
ai_agents_ossa |
14 routes, core pillar | KEEP but trim — disable harness/emotion/cognitive routes | N/A | ~50% of routes disabled, entity + import/export + discovery kept |
cedar_policy |
40+ routes, massive | REMOVE from install | contractplane for governance, ai_context_item compliance_event + Views for dashboards |
Zero — entirely replaced |
kb_cache |
10 routes, platform internal | SIMPLIFY to glue | JSON:API for memory CRUD, ai_search for semantic search, existing Views for dashboards |
~2 routes kept (bootstrap authority, bootstrap export) |
duadp |
25+ routes | SIMPLIFY — keep browser + spec endpoints | JSON:API for CRUD, keep 8 spec-required routes | ~10 routes kept |
skills_browser |
2 routes, thin | KEEP | Already minimal | No change |
api_normalization |
Many routes | KEEP but scope — source connector backend only | N/A | Used for source ingestion, not internal APIs |
source_connector_mcp |
Few routes | KEEP | N/A | Thin glue to mcp_client |
source_connector |
Framework | KEEP | N/A | Framework module |
contractplane |
New | INSTALL — replaces cedar_policy |
N/A | Lightweight governance module |
agent_workflow_engine |
New/existing | INSTALL | N/A | ECA + orchestration wrapper |
agent_registry_consumer |
New/existing | INSTALL | N/A | Remote registry consumer |
drupal_audit |
New/existing | INSTALL | Replaces custom audit in cedar_policy |
Structured audit logging |
dragonfly_client |
Blocked | REMOVE from install | Month 4+ capability pack | Zero |
blockchain_manager |
Experimental | REMOVE | N/A | Zero |
dita_ccms |
Experimental | REMOVE | N/A | Zero |
alternative_services |
Experimental | REMOVE | N/A | Zero |
copaw_bridge |
Month 4 | REMOVE from install | Month 4+ capability pack | Zero |
8.2 Custom Controller Elimination Checklist¶
Every custom controller must answer: Can ECA + Views + JSON:API handle this instead?
| Controller | Module | Routes | Can Replace? | Replacement |
|---|---|---|---|---|
ComplianceApiController |
cedar_policy |
12 | YES | JSON:API on compliance_event + Views |
ComplianceDashboardController |
cedar_policy |
1 | YES | Views page display with exposed filters |
Soc2DashboardController |
cedar_policy |
7 | YES (Month 2) | Views + Webform for evidence upload |
HealthcareDashboardController |
cedar_policy |
10 | YES (Month 3) | Views |
SecurityAgentController |
cedar_policy |
6 | YES | ECA + ai_agents |
DevStandardsController |
cedar_policy |
4 | YES | Remove entirely (dev tool, not product) |
CedarGateController |
cedar_policy |
3 | PARTIAL | contractplane authorize endpoint replaces this |
SharedContextController |
kb_cache |
5 | YES | JSON:API + ai_search |
ContextMemoryHealthController |
kb_cache |
1 | YES | drupal/health_check plugin |
DuadpRegistryController (CRUD) |
duadp |
8 | YES | JSON:API for CRUD, keep spec endpoints |
DuadpFederationController |
duadp |
3 | DEFER | Month 5 |
HarnessController |
ai_agents_ossa |
7 | YES | ai_agents framework handles execution |
DashboardController |
custom | 1 | PARTIAL | Custom for Month 1, Views + dashboards for Month 2 |
DuadpBrowserController |
duadp |
1 | NO | Keep — Project Browser-style UI needs custom rendering |
Result: 67 custom controller routes eliminated. 11 remain.
9. Claude Code Build Instructions (v2 — Contrib-First)¶
Principle¶
Every build task follows this order:
1. Install contrib — composer require and drush en
2. Configure contrib — export config YAML
3. Create ECA model — define workflow as config
4. Write custom code ONLY if contrib + ECA cannot handle the requirement
5. Test — verify the screen works
Task 1: Core Platform Install¶
## Task: Install Tier 1 Modules + Configure
### Step 1: Clean composer.json
Remove from require:
- drupal/blockchain_manager
- drupal/cedar_policy
- drupal/dita_ccms
- drupal/alternative_services
- drupal/ai_agents_crewai
- drupal/ai_agents_cursor
- drupal/ai_provider_apple
- drupal/external_migration
- drupal/dragonfly_client
- drupal/apidog_integration
### Step 2: Verify Tier 1 modules installed
composer require (if not already):
- drupal/ai_agents_ossa (already present)
- drupal/contractplane (already present)
- drupal/duadp (already present)
- drupal/kb_cache (already present)
- drupal/skills_browser (already present)
- drupal/api_normalization (already present)
- drupal/source_connector_mcp (already present)
- drupal/drupal_audit (if not present, add)
- drupal/agent_workflow_engine (if not present, add)
- drupal/agent_registry_consumer (if not present, add)
### Step 3: Enable modules
drush en ai_agents_ossa ai_agents_ui ai_agents_dashboard \
agent_workflow_engine kb_cache source_connector source_connector_mcp \
skills_browser api_normalization ai_provider_routing_eca \
contractplane duadp agent_registry_consumer drupal_audit \
ai_automators ai_search ai_integration_eca ai_logging ai_dashboard \
ai_vdb_provider_qdrant ai_image_alt_text
### Step 4: Disable/uninstall Tier 3
drush pm:uninstall blockchain_manager dita_ccms alternative_services \
ai_agents_crewai ai_agents_cursor ai_provider_apple external_migration \
dragonfly_client apidog_integration copaw_bridge
### Step 5: Export config
drush cex -y
### Test
drush st — verify all Tier 1 modules enabled
drush pm:list --type=module --status=enabled | grep -E "ai_agents|kb_cache|duadp|contractplane"
Task 2: Group-Based Tenant Scoping (Replaces v1 Task 1)¶
Configure drupal/group for SaaS multi-tenancy:
1. Create group types: organization, workspace, project
2. Configure ggroup for subgroup hierarchy: organization → workspace → project
3. Create group content plugins for: ossa_agent, ai_context_item, node
4. Create group roles: org_admin, workspace_admin, workspace_editor, workspace_viewer
5. Configure ginvite for email-based invitation flow
6. Create groupmenu per workspace for navigation scoping
7. Export all group config YAMLs to recipe
Task 3: Compliance Events via ai_context_item¶
## Task: Create compliance_event Bundle + Views Dashboard
### Step 1: Create bundle (config only, no PHP)
Export config YAMLs:
- ai_context.ai_context_item_type.compliance_event.yml
- field.storage.ai_context_item.field_decision.yml
- field.storage.ai_context_item.field_principal.yml
- field.storage.ai_context_item.field_action_name.yml
- field.storage.ai_context_item.field_resource.yml
- field.storage.ai_context_item.field_severity.yml
- field.storage.ai_context_item.field_context_json.yml
- field.storage.ai_context_item.field_eval_time_ms.yml
+ field instance configs for compliance_event bundle
### Step 2: Create compliance dashboard View (config only)
views.view.contextcontrol_compliance_dashboard.yml:
- Page display at /admin/reports/compliance-dashboard
- Data source: ai_context_item (bundle=compliance_event)
- Fields: created, field_decision (badge), field_principal, field_action_name, field_resource, field_severity
- Exposed filters: field_decision, date range, field_severity
- Contextual filter: group_id (from group context via `group` module's context provider)
- Header: Global summary with allow/deny counts (Views aggregation)
### Step 3: Create ECA model for compliance alerting
eca.eca_model.compliance_alert.yml:
- Event: entity.insert (ai_context_item, bundle=compliance_event)
- Condition: field_decision=deny AND field_severity IN [critical, high]
- Actions: email workspace admin, log
### Step 4: Wire ContractPlane authorize endpoint
contractplane module provides POST /api/contractplane/authorize
Verify it creates compliance_event ai_context_items on each decision.
### Test
1. POST to /api/contractplane/authorize with test payload
2. GET /admin/reports/compliance-dashboard — verify event appears
3. Verify email sent for critical denial
Task 4: Memory Browser via Views + ai_search¶
## Task: Wire Context Memory via Contrib
### Step 1: Configure ai_search index
search_api.index.context_memory.yml:
- Datasource: entity:ai_context_item (bundles: agent_memory, shared_context)
- Backend: search_api_db (database) for MVP; switch to Qdrant later
- Fields: title, field_kb_agent_memory_content (fulltext), field_kb_agent_id, group_id (from group_content), field_kb_agent_memory_type, created
### Step 2: Create memory browser View (config only)
views.view.contextcontrol_memory_browser.yml:
- Page at /admin/content/context
- Data source: search_api index context_memory
- Fields: title, agent_id, memory_type, confidence, created, operations
- Exposed filters: fulltext search, memory_type, date range
- Contextual filter: group_id from group context (workspace group)
- Sort: created DESC
### Step 3: Verify JSON:API CRUD
GET /jsonapi/ai-context-item/agent-memory — works out of box
POST /jsonapi/ai-context-item/agent-memory — works with auth
No custom code needed.
### Step 4: Create ECA model for memory governance
eca.eca_model.memory_governance.yml:
(see §5.2 Memory Governance Flow)
### Test
1. POST memory via JSON:API
2. GET /admin/content/context — verify it appears
3. Search for keyword — verify fulltext search works
4. Verify workspace scoping
Task 5: Dashboard (Custom Controller — Thin)¶
Same as v1 Task 2 but with one change: compliance queries hit contractplane entities instead of cedar_policy entities.
Task 6: Agent Browser + Import (Simplify Existing)¶
Same as v1 Task 4 + Task 7, but also disable harness routes:
RouteSubscriber removes:
- ai_agents_ossa.harness.* (all 7)
- ai_agents_ossa.gitlab_webhook
- ai_agents_ossa.harness.emotion
- ai_agents_ossa.harness.cognitive_topology
Task 7: ECA Model Definitions¶
## Task: Create All ECA Models (Config Only)
Create YAML config for each ECA model in §5.2:
1. eca.eca_model.workspace_create.yml
2. eca.eca_model.workspace_member_add.yml
3. eca.eca_model.agent_import.yml
4. eca.eca_model.memory_governance.yml
5. eca.eca_model.compliance_alert.yml
6. eca.eca_model.daily_digest.yml
7. eca.eca_model.user_invite.yml
8. eca.eca_model.provider_routing.yml (ai_provider_routing_eca rules)
Each model is pure config — no PHP required.
Import via: drush cim -y
Verify via: /admin/config/workflow/eca — all models visible
Task 8: Landing Page, Auth Hardening, Seed Content¶
Same as v1 Tasks 8 and 9. No changes needed — these are already contrib-first.
10. Provider Strategy¶
10.1 Only Install Providers You Use¶
Month 1 MVP:
- ai_provider_anthropic — primary chat/reasoning (Claude Sonnet 4)
- ai_provider_openai — embeddings (text-embedding-3-small) + moderation
Add later as needed:
- ai_provider_huggingface — only if calling HF models
- ai_provider_langchain — only if LangChain integration needed
- ai_provider_apple — Keep Out (not relevant)
10.2 Provider Routing via ECA¶
Instead of hardcoding provider selection in ai.settings.yml, use ai_provider_routing_eca for dynamic routing:
# ECA model: provider_routing
# Event: ai.operation.pre_execute
# Rules:
# 1. IF operation=chat AND context.trust_tier=verified → anthropic/claude-opus-4
# 2. IF operation=chat AND context.trust_tier=provisional → anthropic/claude-sonnet-4
# 3. IF operation=embeddings → openai/text-embedding-3-small (always)
# 4. IF operation=moderation → openai/omni-moderation-latest (always)
# 5. IF primary provider rate limited → fallback to secondary
10.3 Adding Providers Later Without Reinstall¶
To add a new provider:
1. composer require drupal/ai_provider_{name}
2. drush en ai_provider_{name}
3. Add key.key.{name}_api_key.yml config
4. Update ECA provider routing model
5. drush cim && drush cr
No module reinstall, no schema changes, no custom code.
11. GitLab Integration Architecture¶
11.1 GitLab Duo Agent Platform ↔ ContextControl¶
| GitLab Concept | ContextControl Equivalent | Integration Point |
|---|---|---|
| GitLab AI Agent | OSSA Agent (ossa_agent ConfigEntity) |
Import GitLab agent definition as OSSA manifest |
| Agent Tool | Drupal Tool API plugin + Tool Binding | tool_binding ConfigEntity maps DUADP tools to Drupal tools |
| Agent Prompt | BuildSystemPromptEvent subscriber |
ai_agents_ossa.prompt_subscriber injects manifest context |
| Agent Execution | ai_agents framework |
Month 4 via CoPaw gateway |
11.2 GitLab AI Catalog ↔ DUADP¶
| GitLab Concept | DUADP Equivalent | Integration |
|---|---|---|
| Model Catalog | DUADP Agent Registry | GET /api/v1/agents returns DUADP-format catalog |
| Model Card | OSSA Manifest | /.well-known/ossa/{slug} serves agent cards |
| Catalog Search | DUADP Search | GET /api/v1/search with DUADP response format |
| Catalog Publish | DUADP Publish | POST /api/v1/publish accepts OSSA manifests |
11.3 CI/CD Recipes for Deployment¶
GitLab CI Component for ContextControl deployment:
# .gitlab-ci.yml
stages:
- validate
- build
- deploy
include:
- component: gitlab.com/blueflyio/gitlab-components/[email protected]
inputs:
phpcs_standard: Drupal,DrupalPractice
phpstan_level: 6
- component: gitlab.com/blueflyio/gitlab-components/[email protected]
inputs:
site: contextcontrol
drush_post_deploy:
- "cr"
- "updb -y"
- "cim -y"
- "recipe:apply contextcontrol_core"
validate:
extends: .drupal-quality
build:
stage: build
script:
- composer install --no-dev --optimize-autoloader
- drush cr
artifacts:
paths:
- vendor/
- web/
deploy:production:
extends: .drupal-deploy
environment:
name: production
url: https://contextcontrol.ai
rules:
- if: $CI_COMMIT_BRANCH == "main"
12. Composer.json Changes (v2)¶
Packages to REMOVE¶
drupal/blockchain_manager
drupal/cedar_policy
drupal/dita_ccms
drupal/alternative_services
drupal/ai_agents_crewai
drupal/ai_agents_cursor
drupal/ai_provider_apple
drupal/external_migration
drupal/dragonfly_client
drupal/apidog_integration
drupal/code_executor (if present)
drupal/layout_system_converter
drupal/source_connect (legacy, replaced by source_connector)
drupal/mcp_registry (deferred)
drupal/agentdash_platform (if present)
Packages to KEEP (Tier 1 — Install Now)¶
drupal/ai_agents_ossa
drupal/contractplane
drupal/duadp
drupal/kb_cache
bluefly/skills_browser
bluefly/api_normalization
drupal/source_connector_mcp
drupal/ai_context
drupal/ai_provider_anthropic
drupal/ai_provider_openai
drupal/eca
drupal/eca_tamper
drupal/eca_tool
drupal/orchestration
drupal/mcp
drupal/mcp_client
drupal/mcp_tools
drupal/modeler
drupal/modeler_api
Packages to ADD (if not already present)¶
drupal/drupal_audit
drupal/agent_workflow_engine
drupal/agent_registry_consumer
drupal/ai_agents_ui (may be submodule of ai_agents)
drupal/ai_agents_dashboard (may be submodule of ai_agents)
drupal/ai_provider_routing_eca (may be submodule of eca)
13. Migration Path from v1¶
Week 1: Module Cleanup¶
- Uninstall Tier 3 modules
- Remove from composer.json
composer update- Export clean config
Week 2: Governance integration — ContractPlane replaces Cedar (optional path)¶
- Enable
contractplane(governance integration, not the SaaS core) - Migrate Cedar policies to ContractPlane policy entities (scripted migration)
- Create
compliance_eventai_context_item bundle - Wire authorize endpoint for governed writes where required
- Disable
cedar_policyroutes via RouteSubscriber - Verify compliance dashboard (Views)
Week 3: Simplify Custom Modules¶
- Disable kb_cache platform-internal routes
- Wire JSON:API for memory CRUD
- Configure ai_search index
- Disable DUADP CRUD routes (JSON:API replaces them)
- Disable ai_agents_ossa harness routes
Week 4: ECA + Recipe Packaging¶
- Create all ECA models
- Package as recipe kit
- Test full install from scratch using recipes
- Validate all 9 product screens work
14. Canonical Architecture — 9-Layer Model¶
Source: Bluefly Module Audit across 58 repos.
ContextControl.ai maps every contrib and custom module to exactly one of these layers. No module may span layers — if it does, split it or wrap it.
| Layer | # | Responsibility | Key Modules |
|---|---|---|---|
| L1 — Standards & Runtime | 1 | OSSA manifests, GAID identity, DID resolution, agent card schema | ai_agents_ossa, duadp |
| L2 — Policy & Governance | 2 | Cedar-equivalent policy eval, compliance events, audit trail | contractplane, drupal_audit, ai_context (compliance_event bundle) |
| L3 — Memory & Data | 3 | Vector storage, knowledge cache, context items, embeddings | kb_cache, ai_context, ai_search, ai_vdb_provider_qdrant |
| L4 — Marketplace & Registry | 4 | Agent discovery, skill browser, catalog sync | duadp, skills_browser, api_normalization |
| L5 — Source Connectors | 5 | Ingest from external systems (MCP, REST, file) | source_connector_mcp, mcp_client, api_normalization |
| L6 — Workflow & Orchestration | 6 | ECA models, cron flows, event routing | eca, eca_tamper, eca_tool, ai_integration_eca |
| L7 — Provider Plugins | 7 | LLM transport ONLY — model routing, key management | ai (core), ai_provider_*, key |
| L8 — UI & Presentation | 8 | Canvas SDC components, dashboards, theme | experience_builder, canvas_ai, bluefly_theme |
| L9 — Recipes | 9 | Composable install packages | contextcontrol_base, contextcontrol_compliance, etc. |
Layer Boundary Rules¶
These are hard rules derived from the Bluefly module audit. Violations require written justification in the architecture decision log.
drupal/aiis the ONLY transport layer for LLM calls. No custom HTTP client calls to OpenAI/Anthropic/Ollama. All model invocations go through\Drupal\ai\AiProviderPluginManager. This is L7 only.drupal/toolis the ONLY mechanism for agent capabilities. All tool definitions useToolPluginManager. No ad-hoc function registration. This is the bridge between L1 (agent standards) and L7 (provider execution).drupal/orchestrationis EXTERNAL-ONLY. It orchestrates multi-step agent workflows that span beyond Drupal. Internal Drupal workflows use ECA (L6). Never use orchestration for form processing, cron, or config events.drupal/groupowns all tenancy boundaries. No entity may be tenant-scoped via taxonomy reference or field_workspace. All tenant scoping flows through group content plugins.- Governed writes that require policy checks should use the
contractplaneintegration (authorize flow) when enabled—not ad hoc access bypasses. Every deny/allow decision is logged as acompliance_eventwhere that integration is in use.
Layer → Three-Tier Mapping¶
Every module in every layer also maps to exactly one ownership class:
| Class | Prefix | Example | Distribution |
|---|---|---|---|
| Public / Contrib | drupal/* |
drupal/ai, drupal/group, drupal/eca |
drupal.org, composer |
| BlueFly Private Reusable | blu_* |
blu_contractplane, blu_kb_cache, blu_ai_context |
GitLab @bluefly group, deployable to any Bluefly client |
| Site-Specific | cc_* |
cc_dashboard, cc_landing, cc_seed |
This repo only, not reusable |
Rules:
- Public/Contrib: Never fork. If a patch is needed, contribute upstream or use composer patches.
- BlueFly Private (blu_): Must be installable on any Drupal 11 site without ContextControl. No hard dependency on cc_* modules. Published to @bluefly GitLab package registry.
- Site-Specific (cc_): May depend on blu_* and contrib. These are the 4 remaining custom controllers (dashboard, landing, admin theme glue, seed content).
15. Gap Analysis — What ContextControl.ai Fills¶
Source: Bluefly Gap Analysis document.
The Drupal AI ecosystem (drupal/ai + drupal/ai_agents + drupal/tool + drupal/eca) provides a solid foundation but has 7 architectural gaps that ContextControl.ai fills:
| # | Gap | What's Missing | ContextControl Solution | Modules |
|---|---|---|---|---|
| 1 | Agent Identity | No standard identity scheme. Agents are config entities with machine names — no global addressability, no cryptographic identity. | OSSA manifests with GAID (Globally Addressable ID). Every agent has a DID-based identity resolvable across sites. | ai_agents_ossa |
| 2 | Agent Discovery | No cross-site agent catalog. Each Drupal site is an island. | DUADP federation protocol. Agents publish to discovery network; sites consume from catalog. Skills browser for marketplace UX. | duadp, skills_browser |
| 3 | Cross-Site Governance | drupal/ai has no policy engine. Access control is Drupal permissions only — per-site, per-role. No cross-site policy federation. |
ContractPlane governance substrate. Policy evaluation as a service. Compliance events as auditable entities. | contractplane |
| 4 | AI Governance at Scale | Individual site permissions don't scale to multi-tenant SaaS. No compliance dashboards, no audit trail queryable by workspace. | Group-scoped compliance_event entities + Views dashboards. Every policy decision is an ai_context_item queryable by workspace, severity, and time. | ai_context, drupal/group, Views |
| 5 | Background Agent Safety | drupal/ai_agents runs agents synchronously. No verification of agent output before it lands in content. No kill switch. |
Dragonfly verification boundary (future). Immediate: ECA post-execution validation + ContractPlane authorize on every write. | eca, contractplane, (future: dragonfly_client) |
| 6 | Context Control Center Write-Back | ai_context provides read context to LLMs but no governed write-back loop. Agents can't persist learnings. |
kb_cache governed write pipeline: agent writes → ContractPlane authorize → ai_classify → ai_embed → persist. Full audit trail. | kb_cache, contractplane, ai_context |
| 7 | Multi-Model Knowledge Base | ai_search provides vector search but no multi-model routing. All queries go to one provider. |
Provider routing via ECA: classify query → route to optimal model (embeddings via Ollama, generation via Anthropic, search via Qdrant). | eca, ai_provider_*, ai_vdb_provider_qdrant |
16. Dragonfly Verification Architecture (Future — Tier 3)¶
dragonfly_clientis Keep Out for MVP. This section documents the architectural intent so the system is designed to accept Dragonfly when activated.
What Dragonfly Does¶
Dragonfly is a fail-closed enforcement boundary that verifies agent outputs before they land in production content. It operates as a POST /verify endpoint that every agent write passes through.
Five-Plane Layer Separation¶
Dragonfly enforces the Bluefly Five-Plane Model at the verification boundary:
| Plane | What It Verifies | ContextControl Integration Point |
|---|---|---|
| Identity Plane | Agent GAID is valid, not revoked, trust posture is verified/provisional | ai_agents_ossa entity status + GAID resolution |
| Policy Plane | Action is permitted by ContractPlane policy for this principal/resource/action | contractplane authorize endpoint |
| Data Plane | Output content passes classification checks (PII, PHI, secrets) | ai_classify + secret detection |
| Execution Plane | Agent ran within declared capability bounds (tools used ⊆ manifest tools) | OSSA manifest capabilities vs execution trace |
| Audit Plane | Complete trace is persisted before output is committed | compliance_event creation |
MVP Preparation (No Dragonfly Module Required)¶
Even without dragonfly_client, ContextControl implements the verification pattern:
- Every agent write passes through the Memory Governance ECA flow (§5.2)
- ContractPlane authorize is called pre-write (Policy Plane equivalent)
- compliance_event is created for every decision (Audit Plane equivalent)
- ai_classify tags content post-write (Data Plane equivalent)
When Dragonfly is activated (Month 3+), the ECA flow adds one action: POST to Dragonfly /verify before the persist step. If Dragonfly denies, the write is rolled back and a compliance_event with decision=deny, source=dragonfly is created.
Activation Path¶
Month 1-2: ECA-based verification (current design)
Month 3: composer require drupal/dragonfly_client
Enable module
Add Dragonfly verify action to Memory Governance ECA flow
Add Dragonfly verify action to Agent Registration ECA flow
Configure Dragonfly endpoint URL (env var)
Month 4+: Dragonfly as mandatory gate for all content publishing
17. Authority Chain & Governance Precedence¶
Source: Bluefly README authority chain.
Document Precedence (Highest → Lowest)¶
domains.yaml — Domain isolation boundaries (immutable)
FINAL plans — Sprint-level delivery commitments
OWNERSHIP.md — File/module/repo ownership declarations
RUNTIME-SPINE — Runtime service topology
This document (v2) — Technical architecture decisions
Product Definition — Feature scope and screen definitions
When a conflict exists between this architecture document and a higher-precedence source, the higher source wins. Example: if domains.yaml declares that contractplane operates in its own domain boundary, this document cannot move it into the core domain.
Governance Flow for Architecture Changes¶
- Propose change in GitLab issue with
~architecturelabel - Map change to affected layers (§14) and modules
- Verify change doesn't violate layer boundary rules
- Verify change doesn't violate three-class ownership rules
- Update this document + affected FINAL plan
- MR review by module owner (per OWNERSHIP.md)
Appendix A: Module Count Summary¶
| Category | v1 Count | v2 Count | Delta |
|---|---|---|---|
| Custom modules installed | 14+ | 14 (different set) | ~0 (but different composition) |
| Custom routes active | 90+ | 11 | -88% |
| Custom controllers | 25+ | 4 | -84% |
| Contrib modules (AI stack) | ~12 | ~18 | +6 (more contrib, less custom) |
| ECA models | 0 | 8 | +8 (replaces custom event subscribers) |
| Recipes | 0 | 6 | +6 (composable install) |
Appendix B: Screen → Module Mapping (v2)¶
| Screen | URL | Primary Module | Supporting Modules |
|---|---|---|---|
| Login/Signup | /user/login |
Core + tfa + login_security | antibot, autologout |
| Dashboard | /dashboard |
custom controller | ai_agents_ossa, contractplane, kb_cache, duadp |
| Workspace Create | /group/add/workspace |
drupal/group + ggroup | ECA, ginvite |
| Agent Import | /admin/config/ai/ossa/agents/import |
ai_agents_ossa | ai_agents, ai_context |
| Agent Browser | /admin/content/agents/browser |
duadp | skills_browser, ai_agents_ossa |
| Compliance Dashboard | /admin/reports/compliance-dashboard |
Views (on ai_context_item) | contractplane, drupal_audit |
| Context Memory | /admin/content/context |
Views (search_api index) | ai_context, ai_search, kb_cache |
| Agent Detail | /admin/config/ai/ossa/agents/{id} |
ai_agents_ossa | ai_agents_ui |
| Landing Page | / |
custom controller or node | bluefly_theme |
Appendix C: What cedar_policy Provided vs. v2 Replacements¶
| cedar_policy Feature | Routes | v2 Replacement | Module |
|---|---|---|---|
| Cedar Gate authorize | 3 | ContractPlane authorize | contractplane |
| Cedar Policy CRUD | 6 | ContractPlane policy entities | contractplane |
| Compliance Dashboard | 1 | Views on compliance_event | Views (core) |
| SOC2 Dashboard | 7 | Views + Webform (Month 2) | Views + Webform |
| Healthcare Dashboard | 10 | Views (Month 3) | Views |
| Security Agents | 6 | ECA + ai_agents | eca + ai_agents |
| Dev Standards | 4 | Remove (not product) | — |
| Audit Logging | 3 | ai_context_item + drupal_audit | ai_context + drupal_audit |
| DUADP Policy API | 2 | JSON:API on ContractPlane entities | JSON:API (core) |
| Total | 42 | 0 custom routes | All handled by contrib + config |