Klor.

Integrate with an agent

A brief you can paste into Claude Code, Cursor, or whatever you already have open. It covers the install, the provider, the rules that are easy to get wrong, and the two extra options React Native needs.

The brief

Paste into your agent
Integrate Klor (klor.dev) into this project for remote config and feature flags.

Package: @klor/react, one package, works in React and React Native.

## Steps

1. Install it:
pnpm add @klor/react

2. Create the client once. It owns the refresh schedule, the disk cache, and
the telemetry buffer, so creating it per render would restart all three.

import { createKlorClient } from '@klor/react'
export const klor = createKlorClient({ apiKey: KLOR_PUBLIC_KEY })

Module scope is the simplest way to get "once". If you are server-rendering
and want to seed it with a snapshot the server already fetched, create it in
a useState initialiser instead, still once per mount, not per render:

const [klor] = useState(() =>
createKlorClient({ apiKey: KLOR_PUBLIC_KEY, initialSnapshot }),
)

3. Wrap the app root. The context is who the current user is; rules are matched
against it.

import { KlorProvider } from '@klor/react'

<KlorProvider
client={klor}
context={{ userId: user.id, attributes: { platform: 'web', country: user.country } }}
>
<App />
</KlorProvider>

4. Read flags where they are used:

import { useFlag } from '@klor/react'
const showNewCheckout = useFlag('checkout_v2', false)

## Rules

- The second argument to useFlag is the value served when Klor has nothing to
say, before the first fetch, on a dead network, or if the key does not exist.
Choose the behaviour you want if Klor were not installed at all.
- useFlag is synchronous and already returns that fallback. Do not gate the UI
on a loading state, and do not wrap it in useMemo or component state.
- Keys beginning klor_pub_ are public and may ship in client code. Keys
beginning klor_sec_ must never appear in anything sent to a browser or bundled
into an app, server only, through @klor/react/server.
- Flags marked sensitive in the dashboard are stripped from the payload public
keys receive. Do not rely on a public key to hide anything.

## React Native only

@klor/react has no react-native dependency, so two things must be passed in:

import AsyncStorage from '@react-native-async-storage/async-storage'
import { AppState } from 'react-native'

createKlorClient({
apiKey: KLOR_PUBLIC_KEY,
storage: AsyncStorage,
subscribeToForeground: (refresh) => {
const sub = AppState.addEventListener('change', (s) => s === 'active' && refresh())
return () => sub.remove()
},
})

Without storage, a cold start with no network serves fallbacks instead of the
last known config, which on mobile is the case most worth covering.

For update gating, useVersionGate() returns { status, message, storeUrl }. Klor
ships no UI; render your own prompt from it.

## If you need more

The complete reference (every client option, every rule operator, the version
comparison rules, and the HTTP endpoints) is one fetch away as plain text:

https://klor.dev/llms-full.txt

There is also https://klor.dev/llms.txt, a short index linking each docs page,
if you would rather read only the part you need.

## Before you start

Ask me for the Klor public API key and the flag keys I want to read. Do not
invent key names or commit a placeholder that looks real.

What to have ready

The brief ends by telling your agent to ask for two things rather than guess at them, so have both to hand:

A public API key from the environment you want to wire up, the dashboard shows it once, at creation. And the flag keys you intend to read. An agent left to invent key names will write plausible ones that do not exist, and every read will quietly return its fallback.

If you have not created any flags yet, do that first. A flag that does not exist behaves exactly like a flag that is switched off, which makes an empty project hard to tell apart from a broken integration.

What it will not do

The brief deliberately does not describe rules, rollouts, or update gating. Those are configured in the dashboard rather than in code, and an agent that tries to express them in your app has misunderstood where they live, the app only ever reads the result.

It also says nothing about your private key. klor_sec_ keys belong on a server and go through @klor/react/server; the brief is written for client integration and tells the agent not to put one anywhere near it.

Checking the result

Three things worth looking at in whatever your agent produces:

The client should be created once, at module scope, not inside a component, and not inside a useMemo. Every useFlag call should have a fallback that is the behaviour you want if Klor were not installed at all. And nothing should be gated on a loading state, because reads are synchronous and already return the fallback until the first snapshot arrives.