// architecture

Architecture

The map of the core codebase: what lives where, why it lives there, and what a change may not do. The boundaries are not aesthetic — each one exists because breaking it would be invisible in a diff and visible in production.

The four planes

Every request moves through four trust levels. Each boundary is a place where a credential is checked.

1

Edge

aetherin-middleware (Vercel)

Public entry point: auth gate, CORS, size limits, circuit breaker, security headers, request id.

2

Host Edge

Caddy on the box (optional)

TLS termination; /aether/api → core, /aether/gateway/* routes.

3

Core

aetherin-server-core

Splits into a hot data plane and a high-impact control plane (see below).

4

Platform

internal only, never exposed

Kernel, plugins, providers, store, sealed secrets, discovery worker, pricing engine, policies.

Why the planes are separated

A defect in the data plane costs latency and money; a defect in the control plane costs credentials, other tenants' data, or the deployment. They have different failure costs, different review depths, and different availability requirements — so they must not share a package where a change to one is indistinguishable from a change to the other.

Data plane vs control plane

Data plane

high volume, hot path

  • →Chat, embeddings, usage, budgets
  • →Credential: API key
  • →No cookie, no CSRF
  • →Owns its benchmarks — the hot path

Control plane

low volume, high impact

  • →Keys, providers, models, orgs, team, admin, pricing, billing
  • →Credential: session + CSRF proof, role-gated
  • →Where role checks, CSRF proofs and the audit trail live

Package map

PackageWhat it owns
pkg/pluginsdkThe public plugin contract — semver-frozen, no internal imports.
internal/kernelThe microkernel: transport, plugin host, config, events, secrets, storage. Stdlib-only.
internal/platformCross-cutting runtime: origin policy, CSRF proof, SSRF target policy, CORS, request-id propagation.
internal/apiThe HTTP boundary: handlers, DTOs, authorization, CSRF, error envelope, route registration.
internal/providersUpstream adapters (OpenAI, Anthropic, Gemini, …).
internal/storePersistence: Postgres + the in-memory fakes.
plugins/ring0Kernel plugins: healthz (real), config, eventbus, registry, secrets, storage, transport.
plugins/ring1Product plugins: auth, metering, providerregistry, ratelimit, router.

The rules

  • ▸internal/kernel imports nothing outside itself and pkg/pluginsdk.
  • ▸pkg/pluginsdk imports nothing from internal/.
  • ▸internal/platform imports no product package.
  • ▸A plugin never imports another plugin.
  • ▸The direct Go dependency set is frozen — adding one is an architectural decision.
  • ▸The request fast path does not allocate per chunk.
  • ▸Metering and logging never block a streaming response.

Storage

Postgres

Primary store — users, orgs, keys, usage events, billing.

Redis

Rate-limit counters, budget counters, session/cache state.