# Putting an existing API behind fluid-core fluid-core attaches **out of process** (ADR-0002). Your API contributes no code, imports no library, and may be written in any stack. Integration is over a wire contract, so the fact that fluid-core is written in Go is not something you need to care about. ## What you need 1. **A running service.** Anything that speaks HTTP. This becomes an *adapter*. 2. **A contract.** OpenAPI 3.1 today; the validator interface admits others. 3. **An interface evolution intent.** The governance document that bounds how the interface may change. Nothing else. In particular you do not need a Kubernetes cluster, a message broker, or Postgres — SQLite is the default evidence store. ## The five minutes version ```bash export FLUID_INTERFACE=my-api export FLUID_STORE=$PWD/fluid.db # 1. Record the intent that governs this interface. fluid intent put --version IEI-1 --file InterfaceEvolutionIntent.md --activate # 2. Publish a revision pointing at your existing service. fluid revision publish --file r1.yaml --ephemeral-key \ --adaptation-classes presentation --approved-by "$USER" --traffic-share 1.0 # 3. Route traffic to it. fluid policy put --file routing-policy.yaml ``` A revision descriptor is small: ```yaml revision: schema_version: "0.1" id: "R-1" interface: "my-api" state: "stable" contract: type: "openapi" digest: "sha256:" runtime: upstream: "http://my-existing-service:8080" # your service, unchanged timeout_ms: 5000 intent: version: "IEI-1" policy: compatibility: "additive" security_check: "passed" ``` `runtime.upstream` is the whole integration. Everything else is metadata about what that upstream is allowed to be. ## What you get immediately - **Revision identity.** Every response names the revision that served it. - **Telemetry.** Requests, errors, call sequences and adoption, redacted before storage. - **Contract enforcement.** Undeclared paths, methods and fields are refused rather than proxied. - **An audit trail.** `fluid audit trace R-1` reconstructs how a revision came to exist and what happened to it. That is FLUID-0 (Instrumented) conformance, and it needs no AI and no change to your service. ## What you should decide deliberately **The pseudonymization salt.** Consumer identities are pseudonymized with HMAC. The salt must be stable for the life of the interface — rotating it makes the same consumer look like a new one and breaks every longitudinal comparison. Store it where you store secrets, not in the repository. **The authority mode.** Your intent document declares one, `FLUID-0` through `FLUID-6`. This is a statement about authority, not maturity: a high-assurance interface may deliberately stay at FLUID-2 forever. The unfilled template is refused rather than defaulted, precisely so nobody inherits a permissive mode by accident. **Your complexity budget.** `policy.DefaultLimits()` permits only presentation and implementation adaptations, refuses breaking changes, and caps exposure at 25%. If your interface needs more, say so explicitly in the intent rather than widening the default. ## Adding a second revision This is where FLUID earns its keep. Publish a second revision pointing at a second adapter — a different build, a different service, a different language — and let the experiment controller split traffic between them: ```bash fluid revision publish --file r2.yaml --ephemeral-key ... fluid experiment design --file experiment.yaml fluid experiment start E-1 --generation 2 --default-revision R-1 --policy-out rp.json fluid policy put --file rp.json ``` The controller does not touch traffic. It emits a routing policy for you to install, which is what makes an experiment interruptible: stopping one replaces a document rather than unwinding anything. ## Signing `--ephemeral-key` is for development. It generates a throwaway key and warns that revisions signed with it will not verify after a restart, which is exactly what you want to hear before it happens in production. In production, generate a key pair, keep the private half in your secret store, and configure the gateway's registry with the public half. The router accepts only descriptors that verify — an unsigned or tampered descriptor is refused, including one that was signed and then edited. ## What fluid-core will not do for you - **It will not modify your backend.** Where a candidate needs capability the backend does not have, FLUID emits a structured requirement and stops. The backend owner accepts, plans, or declares it out of scope. - **It will not decide what "better" means.** There is no universal fitness scalar. You declare primary metrics and guardrails; the evaluator compares against what you declared and refuses to infer criteria from the data. - **It will not promote on thin evidence.** A comparison below the sample floor is inconclusive, not successful. You can override that with an acknowledged flag; the override is recorded as one. ## Reference - `examples/echo-interface/` — the two-revision fixture the conformance suite drives, and the smallest complete example. - `conformance/suite/` — every conformance requirement asserted as a test. `TestFirstVerticalSlice` is the whole loop in one function. - `spec/` — the normative documents. When this guide and the spec disagree, the spec is right and this guide is a bug.