The stance reads coherently once one distinction is on the table. At every layer where an open specification exists, Actionary implements a thin adapter. At every layer where the “ecosystem” is an opinionated framework masquerading as a standard, Actionary owns the code.

The stance follows Cockburn’s Hexagonal Architecture (2005), Wiggins’s Twelve-Factor App (2011), and Martin’s Chapter 32 “Frameworks Are Details” from Clean Architecture (2017), applied consistently. The adapters are open because the point of an adapter is portability. The core is owned because business logic encodes decisions specific to the domain.

What’s open at the boundary

Seven substrates, each a public specification with multiple compatible implementations:

  • PostgreSQL 16. pg_dump produces a portable backup of the whole stack, including the pgvector retrieval index.
  • S3-API. shared/storage/storage_adapter.py swaps between AWS S3, Cloudflare R2, MinIO, and Backblaze B2 with one env var. Presigned uploads are the industry-standard shape.
  • Redis wire protocol. Any protocol-compatible store — Dragonfly, KeyDB, Valkey, ElastiCache, Upstash — is a swap target.
  • OpenTelemetry. Traces, metrics, and logs emit through vendor-neutral OTLP. The application tier stays free of vendor-specific observability SDKs.
  • Model Context Protocol. The agent surface is exposed through Anthropic’s open specification. Claude Desktop, Cursor, Zed, Sourcegraph Cody, and Continue.dev all speak it.
  • OAuth 2.1 with DCR and PKCE. IETF-standard trust flows for SSO and machine identity. Any DCR-compliant client can register; any OIDC IdP can be the identity source.
  • HTTP with OpenAPI. The public REST surface is described at /.well-known/openapi.json. SDK generation is @hey-api/openapi-ts running against the schema — zero hand-written API types.

Every LLM provider is an adapter too. Anthropic, OpenAI, Bedrock, Azure OpenAI, and Gemini ship as full streaming implementations behind one LLMProvider Protocol. Per-tenant primary + fallback with automatic failover on provider_unavailable.

What’s owned at the core

Five layers of code Actionary maintains directly, without an imported orchestration framework:

  • The RAG pipelineservices/core_api/application/upload_indexer_service.py (extract, chunk, embed, persist) and services/core_api/infra/repositories/content_asset_chunks_repository.py (hand-written SQL against pgvector).
  • The workflow engineworkflow_runs with FOR UPDATE SKIP LOCKED step claims. Durable execution on Postgres, one fewer stateful service in the deploy topology.
  • Agent orchestration — propose-then-execute on the MCP tool surface, destructive-confirm staging in the agent loop. The loop is code Actionary owns end to end.
  • The entity metadata layerentity_config reads through entity_service.py. One schema drives the SPA, the admin API, and the MCP tool surface.
  • Permission enforcement — Postgres RLS keyed on app.current_tenant_id under a NOSUPERUSER NOBYPASSRLS request role, plus a _permissions contract on every list response.

The roads not taken, named with reasoning

  • LangChain, LlamaIndex. Orchestration middleware. Adopting them means adopting their Chain / Runnable / Retriever abstractions and their breaking-change history. The chunker + embedder + retriever code that already exists is a few hundred lines and does exactly what the domain needs.
  • Pinecone, Weaviate. Hosted vector stores. Adopting them means data leaves Postgres — backup surface splits in two, audit surface splits in two, the record_access visibility gate stops applying to the external store.
  • Temporal, Airflow. Durable-execution frameworks. Adopting them means a second stateful service in the deploy topology when workflow_runs on Postgres already delivers the same idempotent-step guarantee.
  • Kafka, RabbitMQ. Dedicated brokers. Redis lists via BLPOP with an orphan sweep against a Postgres state table is enough at Actionary’s shape. A dedicated broker is the right choice when throughput or cross-region delivery guarantees demand it; that threshold is ahead of us.

Every one of these is a valid architecture for a codebase built around them. The stance is about which layer of the stack imports the framework.

Fifteen principles, 1974 to 2024

The architecture is assembled from foundational principles. The full catalogue traces every layer to a principle the industry has agreed on for two decades or more.

  • Separation of Concerns — Dijkstra, 1974. Three-layer backend enforced by CI.
  • Least Privilege — Saltzer & Schroeder, 1975. Five-role DB model; RLS at the substrate.
  • PoEAA — Repository, Service Layer, Domain Model — Fowler, 2002. 87 repository files. Zero inline SQL in routers.
  • Domain-Driven Design — Evans, 2003. The metadata-driven entity model is DDD applied to a runtime substrate.
  • Hexagonal Architecture — Cockburn, 2005. Two HTTP adapters (REST + MCP) over one application core.
  • Twelve-Factor App — Wiggins, 2011. Twelve out of twelve.
  • Clean Architecture — Martin, 2012 / 2017. Dependencies point inward; a CI lint rejects the reverse.
  • Trunk-Based Development — Forsgren, Humble, Kim, 2018. Eight-phase health-gated deploy, expand/contract migration policy.
  • Contract-First API — OpenAPI Initiative, 2011 / 2017. Typed SDK regenerated on every schema change.
  • OpenTelemetry — CNCF, 2019. Distributed tracing across browser, core-api, MCP server, LLM providers.
  • Row-Level Security — Postgres 9.5 (2016), popularised by Supabase. Migration 338 enabled it on every tenant-scoped table.
  • Zero Trust — NIST SP 800-207 / Google BeyondCorp. Every request re-derives session_kind; every MCP tool call re-checks per-row visibility.
  • Feature-Sliced Design — community, ongoing. 21 feature modules under apps/web/src/features/.
  • Metadata-driven substrate — the industry pattern. Adding a field is a database row.
  • Model Context Protocol — Anthropic, 2024. 72 MCP tools, one canonical catalogue.

The takeaway

Every foundational principle is 15 to 50 years old. Every modern principle is production-proven at cloud-scale organisations today — Netflix, Uber, AWS, Microsoft, Apple, Google, Stripe, Supabase. The architecture is a coherent stack of those principles. The substrate it produces is portable at every wire boundary and coherent at every application layer. That is what enterprise-grade means.