Monorepo RFC 003 l1 domain taxonomy
RFC-003 — L1 Domain Taxonomy: five domains with a single criterion
| Field | Value |
|---|---|
| Status | *ccepted*(2026 |
| Author(s) | Rodrigo (with Claude as scribe) |
| Date | 2026 |
| Affects | Monorepo root structure; all modules |
| Depends on | monorepo-RFC-001-area-first-directory-structure.md, monorepo-RFC-002-directory-nomenclature.md |
1. Summary
Introduce a new level above the current Areas (L1 → L2) by grouping all directories into five *omains*at the true L1. Each Domain is defined by a single, uniform criterion: *ow is the component consumed?*
2. Problem
RFC001 established Areafirst directories, but the monorepo root remained heterogeneous: some Areas are defined by who uses them (suite/, vertical/), others by technical function (data/, infra/), others by artifact type (sdk/, brand/, docs/). No single classification criterion applies uniformly across all L1 directories.
This makes placement decisions arbitrary for new modules and creates ambiguity when reading the directory tree.
3. Principle: Linnaean taxonomy applied to the monorepo
Each level of the directory tree must have *ne and only one*classification criterion, consistent across all entries at that level — as in biology:
Kingdom → Phylum → Class → Order → Family → Genus → SpeciesThe criterion at each level is what defines the split. At the monorepo root (L1), the criterion must be answerable for any component, deterministically.
4. The criterion for L1: form of consumption
The most consistent single criterion across all components in the monorepo is:
*ow is this component consumed?*
This question has exactly five distinct answers, yielding five Domains:
| Answer | Domain | Directory |
|---|---|---|
| Direct interaction — UI / DX | The user interacts with it directly (UI, CLI experience, developer experience) | products/ |
| API call — service |
Other services or products call it over the network (HTTPgRPCWebSocket) | services/ |
| Embedding — import + execute locally | It is imported as a dependency and runs inside the caller (library, SDK, runtime, codec) | engines/ |
| Operation — deploy + configure | It is deployed and configured as infrastructure substrate; products do not import it | infra/ |
| Reading — documentation, reference | It is read by humans; not deployed as a service | meta/ |
5. The five Domains
5.1 products/ — consumed by direct interaction
Components with end users, UX/DX, and brand identity. The consumer interacts with the product directly through an interface.
*ub-Areas (L2):*
horizontal/— horizontal B2C products (any user, any industry) — renamed fromsuite/by RFC-007vertical/— vertical B2B solutions (specific sector)dev/— developer platform (B2D: git forge, CI, terminal, IDE, registry)
*ule of thumb:*if you would design an onboarding flow for it, it belongs here.
5.2 services/ — consumed by API call
Shared backend services consumed by products and other services over the network. No direct end-user UX. Deployed as servers.
*ub-Areas (L2):*
foundation/— cross-product primitives (identity, billing, payments, moderation, ads)ai/— AI services (gateway, runtime, recsys, voice, agents, RAG)media/— audio/video processing services (transcoding, streaming, manifests)
*ule of thumb:*if a product calls it via HTTP/gRPC, it belongs here.
5.3 engines/ — consumed by embedding
Reusable components that are imported and executed locally inside the caller. Stateless or nearly stateless. Portable across backends, frontends, CLIs, WASM, and standalone processes. Not deployed as independent network services. Includes both internal and external SDKs — the consumption form (embedding) is the criterion, not the audience (internal vs. external).
*ub-Areas (L2):*
kodec/— audio/video codec (Rust; native lib, C API, WASM, bindings, CLI)lang/— Kode language, runtime, compiler, stdlib, KMDsdk/— client SDKs (Go, JS, Python, Dart/Flutter, Rust) and internalcomponent libraries (
koder_kit,koder_ipc,koder_player,koder_web_kit)
*ule of thumb:*if a product imports it as a dependency and executes it locally (not via network call), it belongs here.
*ote on sdk:*the `sdk directory contains both internal SDKs used to build
Koder's own apps (koderkit, koderipc, etc.) and external SDKs distributed
to third-party developers (go, js, python, rust). Both are consumed by
embedding, so both belong in enginessdk. The internal/external distinction
is a sub-classification within sdk/`, not a Domain-level distinction.
5.4 infra/ — consumed by operation
Infrastructure substrate: the components that the platform runs on. Products and services do not import infra/ components as libraries — they depend on them operationally (they are configured, deployed, and managed separately).
*ub-Areas (L2):*
net/— network, security, edge, DNS, mesh (currentinfra/contents)data/— databases, queues, search, blob, pipelinesobserve/— APM, logs, metrics, alerting, uptime, dashboardslinux/— Koder Linux distro and desktop environment
*ule of thumb:*if removing it takes down the data center (not a specific product), it belongs here.
5.5 meta/ — consumed by reading
Non-deployed artifacts: documentation, brand assets, landing pages, internal tooling configuration. Consumed by humans reading, not by machines calling APIs or importing code.
*ub-Areas (L2):*
brand/— visual identity: logos, palettes, fonts, guidelinesdocs/— technical Stack documentation: RFCs, deep-dives, catalog, vocabularysites/— institutional and Area landing pagescontext/— internal Claude Code configuration (not a product)
*ule of thumb:*if a machine does not consume it at runtime, it belongs here.
6. Vocabulary: the term "Domain"
The L1 level is named *omain*(Domínio in Portuguese). This term sits above the existing terms Area (now L2) and Sector (now L3):
Domain (L1) → Area (L2) → Sector (L3) → Distribution form (L4)
products/ suite/ kmail/ backend/, app/mobile/, site/
services/ ai/ gateway/ backend/
engines/ sdk/ koder_kit/ (library — no L4 split)
infra/ data/ kdb/ backend/vocabulary.md is updated separately with the formal definition of Domain.
7. Placement decision tree
For any new module, answer these questions in order:
Does it have end users + UX + brand?
YES → products/
NO ↓
Does it expose a network API (HTTP/gRPC/WS) consumed by other services?
YES → services/
NO ↓
Is it imported as a dependency and executed locally?
YES → engines/
NO ↓
Is it infrastructure that products depend on operationally (not via import)?
YES → infra/
NO ↓
→ meta/8. Migration: current root → new structure
| Current path | New path |
|---|---|
suite/ |
products/horizontal/ (renamed from suite/ per RFC-007) |
vertical/ |
products/vertical/ |
dev/ |
products/dev/ |
foundation/ |
services/foundation/ |
ai/ |
services/ai/ |
media/ |
services/media/ |
core/kodec/ |
engines/kodec/ |
lang/ |
engines/lang/ |
sdk/ |
engines/sdk/ |
core/ (remainder) |
distribute per §5 (see below) |
infra/ |
infra/net/ |
data/ |
infra/data/ |
observe/ |
infra/observe/ |
linux/ |
infra/linux/ |
brand/ |
meta/brand/ |
docs/ |
meta/docs/ |
sites/ |
meta/sites/ |
context/ |
meta/context/ |
*core remainder** — after kodec moves to engines/, the remaining
core/ contents (apis, device, audiorecorderserver`) should each be classified individually using the decision tree in §7 before migration. This RFC does not pre-decide their placement., settings, bot
*egacy directories*(apps/, platform/, projects/, server/, tools/, store-cli/, koder-* top-level repos) are subject to a separate migration decision — they are not part of this RFC.
9. Rationale for the criterion choice
Several alternative criteria were considered and rejected:
| Criterion | Problem |
|---|---|
| Who uses it | Breaks for foundation/ (used by everyone) and sdk/ (used internally and externally) |
| Technical function | Every component has a function; produces too many categories |
| Deployment model | sdk/ and infra/ are both "deployed" but to very different ends |
| Importance / fundamentalness | Subjective; every team claims their module is "core" |
*orm of consumption*is the only criterion that is:
- Answerable for any component (deterministic)
- Consistent — the same question, the same five answers, always
- Stable over time — how you consume a component rarely changes
- Free of audience bias — the consumer (internal vs. external) is not the criterion
10. Acknowledgment
This RFC was validated by four independent AI systems (Gemini, Codex, Kimi, Qwen) that were given only the problem statement and six hypotheses. All four independently converged on engines/ for kodec + lang + sdk/, and on the formofconsumption as the unifying criterion. The sdk/koder_kit counterexample — an internal Flutter SDK consumed by embedding, not by external developer interaction — was raised after the AI consultation and confirmed that sdk/ as a whole belongs in engines/, not in products/dev/.