Acquia Source × Bluefly: Technical Specification¶
Updated: 2026-04-25 | Status: Active | Owner: Thomas Scola
Production Requirement: An OSSA-compliant system MUST trace every action, attribute every cost, enforce every constraint, and expose every capability via contract.
Invariant: An agent that cannot be traced, cost-attributed, and constrained MUST NOT be deployed.
Kind Enforcement Rules (STRICT)¶
Three kinds. No exceptions.
| Kind | MAY define llm |
MUST define observability + cost_tracking |
Execution rules |
|---|---|---|---|
| Agent | Yes | Yes — REQUIRED | Bounded autonomy under enforced constraints. Emits trace spans for every decision cycle. |
| Task | No — MUST NOT | Yes — REQUIRED | Deterministic. No LLM calls. Repeatable given same input. |
| Workflow | No — MUST NOT | Yes — REQUIRED | Orchestration layer ONLY. MUST NOT execute logic. Composes agents and tasks. |
Identity (REQUIRED — All Agents)¶
spec:
identity:
service_name: "" # REQUIRED — unique agent name
service_namespace: "" # REQUIRED — org/domain namespace
service_version: "" # REQUIRED — semver
service_instance_id: "" # REQUIRED — unique per runtime instance
service_instance_id MUST be unique per runtime instance. No two running instances may share an ID.
Observability (REQUIRED — Not Optional)¶
spec:
observability:
tracing:
enabled: true # REQUIRED — no exceptions
metrics:
enabled: true # REQUIRED — no exceptions
Agents MUST emit trace spans for every decision cycle. Metrics MUST include: latency, error rate, cost per execution, step count.
Bounded Autonomy (REQUIRED — All Agents)¶
constraints:
execution:
maxRuntimeSeconds: 300 # Default ceiling — configurable down, not up without escalation
maxSteps: 50 # Maximum decision cycles per invocation
timeoutStrategy: abort # abort | suspend | escalate
Agents without execution bounds are unsafe for production. Unbounded agents MUST NOT be deployed.
Cost Governance (REQUIRED)¶
constraints:
cost:
maxCostPerDay: "" # REQUIRED — USD ceiling per agent per day
llm:
cost_tracking:
enabled: true # REQUIRED
Cost MUST be attributable per agent execution. Per-invocation cost emitted as metric. Daily aggregation enforced by ContractPlane.
Messaging Reliability (REQUIRED)¶
spec:
messaging:
reliability:
deliveryGuarantee: at-least-once # Default
retry:
maxAttempts: 3
backoff:
strategy: exponential
Default delivery guarantee is at-least-once. Commands MUST be idempotent unless explicitly declared otherwise.
commands:
- name: ""
idempotent: true # Default — REQUIRED unless documented exception
Failure Model (REQUIRED)¶
spec:
failure:
retryable_errors:
- timeout
- rate_limited
- transient_network
fatal_errors:
- policy_deny
- identity_invalid
- cost_ceiling_exceeded
- dragonfly_fail
Fatal errors halt execution immediately. No retry. Escalate to ContractPlane A2H queue.
Integration Surfaces (Exhaustive — No Fifth Category)¶
| Surface | Mechanism | Bluefly Use | Direction |
|---|---|---|---|
| OAuth 2.0 | client_credentials + scoped tokens |
Separate credentials per lane: Governance (read-only), Application (write), CI/CD (deploy) | Bidirectional |
| JSON:API | Core + JSON:API Extras | Content CRUD (nodes, media, taxonomy, users, menus), component metadata, audit queries | Bidirectional |
| Webhooks | Outbound from Source | Trigger pipelines on publish/update/delete; ECA receives on governance plane | Source → Bluefly |
| Canvas CLI | @drupal-canvas/cli v0.10.0 |
Component push (React/JSX), page creation, asset library management | Bluefly → Source |
Security note: Source authorization is scope-driven, not Drupal roles. Governance MUST sit above Source scopes via Cedar + DUADP.
OAuth Lane Architecture¶
| Lane | Scopes | Purpose |
|---|---|---|
| Governance | content:read, canvas:read |
Cedar policy evaluation context (read-only) |
| Application | content:write, canvas:push, media:write |
Agent-driven content and component operations |
| CI/CD | canvas:asset_library, canvas:js_component |
Pipeline-driven component deployment |
Secrets in Drupal Key module (governance plane). CI/CD secrets as GitLab CI variables (masked, protected). No secrets in code or OSSA manifests.
ContextControl.ai Integration with Source¶
Primary product for Acquia Source. Constrained reasoning services running inside Source use ContextControl.ai as their shared memory layer.
How It Works¶
- Source agent executes → produces context (content decisions, component metadata, user preferences, compliance state)
- Agent calls ContextControl.ai API →
POST api.contextcontrol.ai/contextwithai_contextentity payload - Cedar policy evaluates → permission check (per-site, per-account, per-agent)
- Context stored → Postgres + pgvector for semantic retrieval
- Other agents query →
GET api.contextcontrol.ai/context?scope=site|account|globalwith Cedar-gated access - Cross-site federation → agents on Site A can access context from Site B if Cedar permits
Permission Model¶
| Scope | Description | Cedar Policy |
|---|---|---|
| Per-site | Context visible only to agents on the same Source site | site_id == resource.site_id |
| Per-account | Context shared across all sites in the same Acquia account | account_id == resource.account_id |
| Per-agent | Context restricted to the specific agent that created it | agent_gaid == resource.creator_gaid |
| Cross-account | Context shared between separate Acquia accounts (enterprise) | Explicit Cedar permit with bilateral approval |
| Global | Platform-wide context (rare — compliance templates, shared vocabularies) | Platform admin only |
What Source Agents Get¶
- Persistent memory across sessions — chat agents remember previous interactions
- Cross-site awareness — deployed agents know what happened on other sites in the fleet
- Compliance context — agents inherit compliance requirements from the account's Cedar policies
- Semantic search — retrieve context by meaning, not just key-value lookup
- Audit trail — every context read/write is logged with GAID provenance and cost attribution
API Surface (Fastify + Postgres + pgvector)¶
POST /context — Create context item (Cedar-gated)
GET /context/:id — Read context item (Cedar-gated)
GET /context?scope=... — Query context by scope (Cedar-gated)
PUT /context/:id — Update context item (Cedar-gated)
DELETE /context/:id — Soft-delete with audit record (Cedar-gated)
POST /context/search — Semantic search via pgvector (Cedar-gated)
GET /context/federation — Cross-site context federation endpoint
All endpoints emit trace spans. All writes are idempotent (upsert by GAID + content hash).
Canvas Page Migration Pipeline¶
Second product for Acquia Source: take any URL and migrate its content into a Source site as Canvas components.
Pipeline Flow¶
1. Input URL → Headless browser scrape (Playwright)
2. Extract content + structure → semantic HTML parsing
3. Map to Canvas component schemas → Bluefly component library
4. Cedar policy check → accessibility (WCAG), brand compliance, content governance
5. Validated components → canvas push to Source site via CLI
6. Audit record → GAID provenance + migration evidence + cost attribution
Component Mapping¶
| Source Content | Canvas Component | Validation |
|---|---|---|
| Hero/banner sections | bluefly-hero |
Image alt text, heading hierarchy, contrast ratio |
| Navigation | bluefly-nav |
ARIA landmarks, keyboard navigation |
| Content blocks | bluefly-content-section |
Semantic HTML, reading level |
| Media galleries | bluefly-media-grid |
Alt text, lazy loading, responsive |
| Forms | bluefly-form |
Label association, error states, ARIA |
| Footers | bluefly-footer |
Link integrity, legal compliance |
Key Technical Decisions¶
- Components use
drupal-attributefor Drupal integration - All components are React/JSX + Tailwind (Source-native)
- Component prop descriptions ARE the AI instructions (Source's "Configuration IS the Prompting layer")
- Single component library shared across multiple Source sites
- Migration produces a manifest linking source URL → component mapping → Cedar policy result
Surface Compliance Matrix¶
Every integration maps to exactly one allowed surface. Unmapped integrations are invalid.
| Integration | Surface | Cedar Gate | Status |
|---|---|---|---|
| Content publish event (Source → Bluefly) | Webhook | Yes | Active |
| Content read (Bluefly → Source) | JSON:API | Yes | Active |
| Content write (Bluefly → Source) | JSON:API | Yes | Active |
| Canvas component push | Canvas CLI | Yes | Active |
| OAuth token acquisition | OAuth 2.0 | No (pre-auth) | Active |
| MCP tool discovery (WebFinger) | JSON:API | Yes | Active |
| MCP canvas scaffold call | Canvas CLI | Yes | Active |
| Local DDEV equivalence testing | JSON:API | No (test env) | Active |
| Context write (agent → ContextControl) | External API | Yes | Active |
| Context read (agent → ContextControl) | External API | Yes | Active |
| Page migration (URL → Source) | Canvas CLI | Yes | New |
Prohibited Patterns (Kill on Sight)¶
- Custom PHP webhook controller inside
source_connectcompeting with ECA - Ad-hoc HTTP orchestration endpoints (new routes not backed by ECA + contrib)
- One-off agent runners outside OSSA /
ai_agents_ossa - Duplicate webhook controllers inside
source_connect - Any custom code running inside Acquia Source tenant
Contrib Audit Gate¶
Before any custom PHP, audit contrib + config in this order:
| # | Check | Module | Required |
|---|---|---|---|
| 1 | ECA as sole on-platform orchestration | drupal/eca |
Yes |
| 2 | Webhooks module for webhook handling | drupal/webhooks |
Yes (if webhook surface used) |
| 3 | JSON:API core + Extras for REST surface | drupal/jsonapi_extras |
Yes (if JSON:API surface used) |
| 4 | Secret management & auth keys | drupal/key |
Yes |
| 5 | MCP Client for remote HTTP MCP servers | drupal/mcp_client (Note: drupal/mcp_client is the single authorized MCP package; earlier references to drupal/mcp are historical and refer to the same capability) |
Yes |
| 6 | Tool API for agent tool exposure | drupal/tool |
Yes |
Stop rule: Any *.php file that isn't a plugin implementing an existing contrib API → pipeline FAIL → escalate with proof contrib cannot satisfy the requirement.
CI enforcement: Gate runs in validate stage. allow_failure: false. Output artifact: reports/contrib_audit_gate.yaml.
Flow Contract Template¶
Every flow touching Acquia Source must declare:
- Surface: Which of the 4 allowed surfaces (oauth, json_api, webhook, canvas_cli)
- ECA trigger: Config name, event plugin, condition, action chain
- Cedar policy: Policy file, principal, action, resource, permit/deny default
- Governance plane interaction: Endpoint, type (read/write/evaluate/audit), payload
- Contrib audit result: PASS/FAIL per check, escalation ticket if custom PHP required
- Pilot readiness: Denver → Pilot path must be
direct_scale, notrequires_redesign
What's Built vs. What's Needed¶
Built (Production-Ready)¶
| Component | Package | Notes |
|---|---|---|
| Acquia Source integration & governance layer | source_connect |
Unifies mcp_client, tool, and key for remote tools |
| Canvas blocks (4 block plugins) | agentic-canvas-blocks |
Dashboard, health, command palette |
| Canvas component factory | source-templates |
Validate → build → publish pipeline |
| Cedar policy library | cedar-policies repo |
229+ rules |
| OSSA spec + CLI | ossa repo |
Active |
| DUADP discovery | duadp repo |
Stabilized 2026-04-09 |
| Execution gateway | agent-platform |
Running at api.copaw.us:3050 |
| ContractPlane UI | contractplane.ai |
Running at contractplane.ai:3000 |
| GitLab CI components | gitlab_components |
Public, MIT |
Needs Completion¶
| Component | Gap | Priority |
|---|---|---|
| ContextControl.ai API | Fastify service with Cedar-gated CRUD + pgvector search | P0 — core product for Source |
| Canvas page migration tool | Playwright scraper + component mapper + Cedar gate | P0 — second product for Source |
| Dragonfly | COMPLIANCE_ENGINE_URL fix, suspended process |
P1 |
| Per-domain compliance engines | 7 of 8 Cedar PDP containers need deployment | P1 |
kb_cache cross-session persistence |
85% built, missing persistence layer | P2 |
blueflyio/compliance-cli Docker image |
CI pipeline Cedar evaluation | P2 |
blueflyio/canvas-cli Docker image |
Governed Canvas push | P2 |
| Compliance report generator | Colorado AI Act / EU AI Act / NIST AI RMF exports | P2 |
Regulatory Deadlines¶
- Colorado AI Act — June 2026: Audit evidence export + GAID provenance must be operational
- EU AI Act — August 2026: OSSA manifest classification + prohibited use enforcement
Hybrid Estate Support¶
Many Acquia customers run Source + traditional Drupal. One governance standard across both.
| Estate | Integration | Package |
|---|---|---|
| Acquia Source | OAuth + JSON:API + Canvas CLI + Webhooks (external) | source_connect |
| Acquia Cloud (traditional) | Direct Drupal module installation | ai_agents, ai_agents_ossa, cedar_policy, mcp_client, tool, key |
| Site Factory | Modules per factory + DUADP cross-site discovery | Same as Cloud + duadp |
| Self-hosted Drupal | Modules + DUADP node | Full module suite |
OSSA manifests are the portable unit. Agent defined for Source → importable to traditional Drupal via ai_agents_ossa Drush, and vice versa. Cedar policies shared via cedar-policies repo.
bluefly/source_connect Extension Architecture¶
bluefly/source_connect
├── source_connector (Core)
│ ├── SourceConnection (Config Entity)
│ ├── AcquiaSourceCapabilityDiscovery
│ ├── SourcePolicyEvaluator / Governance Profiles
│ └── Drush CLI (source-connect:list, capabilities, doctor)
├── source_connector_acquia (Acquia Platform)
│ ├── Source CMS Profile & Acquia Cloud API v2
│ └── Canvas Semantics
├── source_connector_compliance (Governance)
│ └── Cedar Bridge, Policy Evaluation & Evidence
└── source_connector_mcp (MCP Integration)
└── Provisioner & Adapter around drupal/mcp_client
Core Architecture Invariant¶
REUSE THE OWNER. FIX THE OWNER. EXTEND THE OWNER. DO NOT DUPLICATE THE OWNER.
- CUSTOM_MCP_PROTOCOL_CLIENT = NO (delegated to drupal/mcp_client)
- CUSTOM_JSON_RPC_IMPLEMENTATION = NO (delegated to drupal/mcp_client)
- CUSTOM_MCP_TOOL_DERIVER = NO (delegated to drupal/mcp_client)
bluefly/source_connect owns connection profiling, Key-backed OAuth credentials, capability normalization, Cedar policy boundaries, and higher-level compound Tool API operations.
<!-- BLUEFLY-DOC-GOVERNANCE This is a governed Bluefly document.