Self-Hosted First

mandatory

Quando uma decisão de stack tech tiver duas opções viáveis — um componente Koder self-hosted e uma alternativa externa — preferir o Koder se ele passar nos 5 gates desta policy para o caso-de-uso específico. A política é algoritmo-estático, dado-dinâmico: os gates e o protocolo vivem aqui; o status por componente vive em `koder.toml [self_hosted]` blocks; um registry auto-gerado agrega; a IA consulta o registry, não esta policy. Subsume a decisão histórica de `web-server.kmd` (Koder Jet) e a Diretriz do Flipping Point do kodec em CLAUDE.md como casos aplicados.

Policy — Self-Hosted First

When a tech-stack decision has two viable options — a Koder Stack self-hosted component and an external alternative — prefer the Koder component if it clears all five gates of this policy for the specific case at hand. If any gate fails, the external alternative remains preferred for that case until the gap is closed.

This policy is *lgorithmstatic, datadynamic* the five gates and the decision protocol live in this file; the per-component status lives in koder.toml [self_hosted] blocks across the monorepo; an auto-generated registry at meta/docs/stack/registries/self-hosted-pairs.md agglomerates them; AI sessions read the registry, not the policy text, when applying the policy.

Sibling of reuse-first.kmd (cross-cutting reuse within the Stack) and code-first.kmd (mechanical- vs-analytical axis). Three orthogonal axes; all three apply at every implementation decision.

When this applies

  • Choosing a tech-stack component for new code that has at least one Koder Stack alternative.
  • Reviewing existing code that currently uses an external dependency for which a Koder alternative now exists.
  • Deciding whether to write a new module in Koder Koda vs RustGoC (Koder Koda is in scope as a self-hosted alternative once the registry lists it for the relevant case).

When this does NOT apply

  • *xisting legacy code*still using an external dependency. Migration is governed by runtime-lib-first.kmd § Strict SemVer deprecation cycles, not by this policy. This policy applies forward-looking, to new code.
  • *ases where no Koder candidate exists*in the registry. The case is outside this policy's reach; the external choice is unencumbered.
  • *ne-off scripts* test code, build configuration outside the inventory.
  • *otfixes*that cannot wait for a selfhosted component to mature; document the exception and open a backlog ticket toward the Koder alternative for followup.

The five gates

A Koder self-hosted component is preferred over an external alternative for a specific case when *ll five gates pass*for that case. Default thresholds are below; a component may tighten them in its koder.toml but cannot loosen them without an RFC amendment.

Gate Question Pass criterion (default)
*1 — Feature parity* Does the Koder component cover the case? Required capabilities for this case (FFI, IDE-debug, async, TLS, codec, …) exist and are documented.
*2 — Performance parity* Is performance within an acceptable margin? Hotpath: Koder ≤ external × 1.05 on a documented benchmark. Nonhotpath: ≤ × 1.20 with a CHANGELOG note for followup.
*3 — Stability* Has the component left experimental and held for ≥ 3 releases? Documented in koder.toml [self_hosted].status ∈ {stable, official} and confirmed by koder-spec-audit self-hosted --history.
*4 — Capability gate (per-category)* Are the categorical capabilities for this kind of use case present? Percategory subgates are defined in the relevant policies/reuse/<category>-first.kmd (UI: a11y baseline + theme contract; runtimelib: SemVer + tiers; buildtooling: determinism + idempotence; protocol: version negotiation + cross-impl tests).
*5 — Critical-path readiness* Is the component proven in production in the Stack? Used by ≥ 2 consuming Koder modules currently in production (not behind a feature flag, not in a smoke-test setup).

The gates are *onjunctive*(all must pass) and evaluated *er caseofuse* not per component globally. The same component may be official for one case (e.g. kodec for mp3) while still gated for another (e.g. kodec for HEVC).

Decision protocol (3 questions answered in chat)

When you are about to write code that picks between a Koder component and an external alternative, *efore the first Write/Edit call* answer these three questions in your response:

  1. *hat case am I solving?*A onesentence caseofuse string (e.g. `"a TLSterminating reverse proxy for s.forge vhosts", "a Linux mipmap launcher icon for an Android app", "a high-throughput H.264 decoder for a 4K transcoding pipeline"`).
  1. *eading registries/self-hosted-pairs.md, is there a Koder component that lists my external alternative under replaces and clears all 5 gates for this case?*
    • *es*→ use the Koder component. Cite the registry row.
    • *es for some gates, no for others*→ name the failing gates explicitly. Either accept the external alternative (and optionally open a promotion ticket on the Koder candidate's backlog to close the gap) or override (and accept the maintenance burden + log it in CHANGELOG).
    • *o*(no candidate in the registry) → the case is outside this policy's reach; pick the external alternative without ceremony.
  1. *oes my decision warrant a CHANGELOG entry or a follow-up ticket?*
    • First adoption of a Koder alternative in a high-traffic module → CHANGELOG note.
    • Continued use of an external alternative after gates were closed → ticket recommending migration on next refactor.
    • Discovery of a missing gate on a candidate → ticket on the candidate's backlog to close it.

Data model — koder.toml [self_hosted] block

Components that compete with an external alternative declare their state declaratively:

[self_hosted]
# External alternatives this component substitutes (free-form list).
replaces      = ["nginx", "caddy", "apache", "traefik"]

# Maturity status. Enum: experimental | stable | official | legacy.
#   experimental — public API may change; gate G3 fails.
#   stable       — API stable; gate G3 passes for documented cases.
#   official     — Stack default for the case; new code MUST prefer it
#                  unless an explicit gate fails for the specific case.
#   legacy       — superseded by another self-hosted component; new
#                  code MUST NOT use it.
status        = "official"

# Gates the component currently clears, per-case where relevant.
# Generic gates (no case suffix) apply to all cases.
gates_passed  = [
  "feature_parity",
  "performance",
  "stability",
  "capability:tls",
  "capability:reverse_proxy",
  "capability:hot_reload",
  "production_proven",
]

# Gates known to be missing, with optional ticket / RFC link in the
# value position. Each entry suppresses recommendation for the case
# until the gate is closed.
gates_pending = [
  # "capability:http3 = sites/jet/backlog/pending/047-http3-support.md",
]

# Evidence — where to verify the gate claims.
benchmark_ref   = "infra/net/jet/bench/jet-vs-nginx-2026-03.md"
production_ref  = ["s.forge", "s.poc.vivver.com"]

koder-spec-audit self-hosted --validate <module> checks the schema (gatespassed and gatespending are disjoint; status is in the enum; etc.). Substantive validation (benchmark file exists, production_ref hosts respond) lands in Phase 5 of policies-RFC-002.

Anti-patterns

  • *witching by hype*— adopting a self-hosted alternative before its gates close. Cost: regression risk in production code; rework when the candidate's API stabilises late.
  • *witching by inertia*— continuing with the external alternative after the gates are clearly met. Cost: dependency drag, security patches, divergence from the reference architecture.
  • *orgetting to declare [self_hosted] block*— components clearly competing with an external alternative but missing the block in koder.toml. The antidrift heuristic (see RFC002 §3.4) raises a warning when the component name starts with koder-, lives under engines/sdk/ / infra/ / products/dev/, or appears in this policy's precedent list.
  • *enchmark gaming*— picking favourable benchmarks for G2 to claim parity. Reviewers verify that benchmark_ref covers the case under test.

Anti-drift heuristic

A component is plausibly a self-hosted alternative if it satisfies any of:

  • module name starts with koder- and is not a product (products/).
  • path is under engines/sdk/, infra/, or products/dev/.
  • name appears in CLAUDE.md § Arquitetura de Referência or in web-server.kmd's precedent list.
  • (Phase 4 onwards) koder.toml declares category ∈ {engine, infra-tooling}.

When the audit finds such a candidate *ithout*a [self_hosted] block, it emits a warning. Advisory in Phases 1–3; strict in Phase 5 (per RFC-002 §5).

Promotion pipeline

A pair (Koder candidate, external alternative) may begin life as experimental. As gates close, the maintainer of the Koder candidate updates koder.toml [self_hosted]:

  • experimental → stable: maintainer's call once gates G1–G3 close for at least one case. Document in CHANGELOG.
  • stable → official: requires Stacklevel review (Rodrigo or designate). Default is onePR proposal updating status, plus the relevant gate evidence; review confirms gates clear universally for documented cases.
  • official → legacy: when superseded by another self-hosted component. The deprecating PR also points at the successor in the registry.

The registry is regenerated on every PR that touches any koder.toml [self_hosted] block (CI-enforced from Phase 5).

Applied cases

  • *oder Jet*vs nginx / Caddy / Apache / Traefik → see policies/web-server.kmd for the existing decree. Status: official (with documented exception poc-5).
  • *odec*vs FFmpeg / GStreamer → CLAUDE.md § Arquitetura de Referência (Flipping Point 20260428). Status: stable for mp3mp4wav; experimental for other codecs.
  • *icon*vs ImageMagick / handPNGs → builtin to the build-tooling category. Status: official.
  • The full inventory lives in the registry; this policy lists only canonical examples.

Audit

koder-spec-audit self-hosted (binary, in line with code-first.kmd):

  • --report walks every koder.toml, agglomerates [self_hosted] blocks, regenerates registries/self-hosted-pairs.md.
  • --validate <module> checks schema correctness for one component.
  • --gate-check (Phase 5) validates gates_passed claims are backed by evidence.

Cross-references

Source: ../home/koder/dev/koder/meta/docs/stack/policies/self-hosted-first.kmd