Written to be accurate about how the software actually works, not to be vague.

The short version

KLØDD is a remote control for AI coding agents that run on your own computer. The agent, your files and your model API keys stay on that computer. Our servers do not run agents, do not call language models and do not store your conversations.

What does travel is what your phone needs in order to show you what the agent is doing. That includes the agent’s output, and the agent’s output includes file paths, diffs and tool results — which is to say parts of your source code. We would rather say that plainly than let you infer something more flattering.

When you enable an encryption key, that traffic is sealed on your own devices and the transport carries ciphertext only. The key never reaches us.

What never leaves your machine

  • The agent process. Claude Code, opencode, Kilo Code, Hermes and Codex run as ordinary local processes on your computer, under your own user account. There is no KLØDD-operated execution environment anywhere.
  • File access. Reading and writing files is done by that local process, on your local disk, under your user account.
  • Model inference. Requests go from your machine directly to whichever provider you configured. We do not proxy them, we do not see them, and we do not resell tokens.
  • The provider API keys you give to kotg. On macOS these are stored as individual generic-password items in your login keychain and handed to the agent process in its environment. kotg never writes them into a configuration file and never sends them over the relay. On a platform without a keychain the operation fails with an error naming the reason rather than quietly falling back to a file on disk. To be exact about the boundary: that covers the credentials you connect through kotg itself. An agent that manages its own provider login — Claude Code and opencode both keep their own credential stores — holds those credentials in its own location, and kotg neither writes nor manages them.
  • Absolute workspace paths. A workspace is published to your own devices as an identifier and a display name; its root directory path stays local.

What does cross the relay

Your phone is a window onto the session, so the session’s contents are what it receives. Concretely:

  • The assistant’s messages, reasoning summaries and plan steps, as they stream.
  • Tool calls and their combined output. For a file-reading or search tool, that output is file content, truncated to fit the transport. Also a per-turn digest of which tools ran and how often.
  • File parts: the path of a file the agent touched, and where the agent supplies one, a unified diff of the change.
  • Permission requests, including the full command awaiting approval.
  • Questions the agent asks you, with their option labels.
  • Updates from any subagent the agent starts, including its task text.
  • Your messages and answers, going the other way.
  • Text you dictate, when you use a voice feature that asks the agent to rewrite it — which means that text also reaches your own model provider.
  • Earlier conversation, not only live output. When your phone attaches to a session it is sent a bounded snapshot of the conversation so far, and it can ask for older pages on demand. Those come from the agent’s own store on your machine, across the relay, the same way live messages do.
  • Per-message token counts and cost as your provider reports them, and the token counts involved when a conversation is compacted.
  • The names and descriptions of the skills or slash commands your agent has available, and the catalogue of models you can switch to.
  • Session metadata shown in the lobby: the session title, the git branch, the model in use, the workspace name, the host computer’s hostname, and the local network address of the agent server on that machine.

The transport is Ably. We do not receive a copy of this traffic ourselves — there is no KLØDD message server — but it passes through Ably’s network, and in hosted mode the channel it passes through belongs to our Ably account.

Encryption, and what it does not cover

Encryption is offered when you set up a host and defaults to on; the desktop app always enables it. It is possible to decline it at the command line, and if you do, everything in the section above travels in the clear. The app tells you which state you are in rather than showing a lock that means nothing.

With a key set, message and presence payloads are sealed with XChaCha20-Poly1305 before they are published, using a 32-byte key generated on your host. It is never uploaded, never escrowed, and we cannot recover it for you.

How the key reaches your other devices. It never travels over the relay, but it does have more than one route, and each is a route someone could intercept if you are careless with it: the QR code kotg pair prints; a text join code you paste into a second machine; a pairing link, which carries the key in the URL fragment — the part a browser never sends to a server; and typing the code by hand. Treat any of them the way you would treat a password.

What the encryption proves, and what it does not. It is authenticated, so a message altered in transit fails its tag and is rejected rather than displayed. A replayed message is a different problem, because a byte-identical copy is still cryptographically valid — so replay is caught separately rather than by the cipher: the phone keeps a nonce cache and a five-minute freshness window over the messages it receives, and the host de-duplicates commands with a time-to-live. Presence updates are deliberately not replay-guarded, because a stale presence entry is superseded rather than acted on.

What remains visible to the transport even with encryption on:

  • Channel names, which contain your account’s user identifier, an identifier for the host installation, and the session identifier.
  • Client identifiers, which contain the same account identifier plus a per-installation random identifier for the host or the phone.
  • The event name of each message — for example that a message was a permission request rather than a chat message — because only the payload is sealed, not the label.
  • Connection metadata: when your devices connect, how many messages they exchange, and how large each one is. Ciphertext is very close in size to the plaintext it replaces.
  • A marker naming the cipher suite in use.
  • Push notification content — see Push notifications, which is a real exception and not a footnote.

If you turn encryption on after having used the product without it, messages sent earlier may remain briefly in the transport’s recent-message buffer in the clear.

What we store on our servers

Our backend is a small set of functions on Google Firebase whose job is to authenticate you and hand your devices a short-lived transport token. Our database rules deny all direct client access; only those functions can read or write.

Everything our database holds is in this list.

  • Your account record, held by Firebase Authentication: an account identifier, the email address or the Apple/Google account identifier you signed in with, a password credential if you chose email and password, and sign-in timestamps.
  • A rate-limit counter — a number of requests in the current sixty-second window, keyed to your account identifier, with an expiry timestamp.
  • A monthly usage counter — a single integer of billable transport units for the current month, keyed to your account identifier, with an expiry timestamp. It is an aggregate. It says nothing about what you sent.
  • Companion-pet state, if you use that feature. The content is a set of blobs encrypted on your machine with your own channel key, which the server does not have, so the server can measure them and never read them. Around each blob sits an unencrypted envelope, and it is worth naming what that holds: an identifier for the machine that wrote the chunk, a sequence number, a hash of the sealed content, a count of entries, a byte size, the clock time on your machine when it was written, and the time we received it.

No conversation text, no prompts, no tool output, no file contents and no transcripts are stored in our database. The functions accept only a sign-in token, a client identifier, a usage integer and those sealed blobs — there is no code path that could receive the rest.

Two things sit outside that database and are better said than left implied. Google Cloud keeps ordinary request logs for our functions — timestamps, IP address, user agent — as any web backend does. And when a function fails we record the error, with credential-shaped strings redacted and the message truncated; the token-vending function logs no account identifier, no token and no client identifier at all, on success or on failure.

We run no analytics product, no crash-reporting product in our own backend, and no product-usage tracking. There is no Firebase Analytics, no Crashlytics and no performance monitoring in the apps.

The waitlist

If you give us your email address on this website, we store it so we can write to you once, when there is something to open. That is the only reason it exists and the only thing it is used for. We do not sell, rent or share the list, and there is no newsletter attached to it.

The row we create holds three things and nothing else:

  • the email address you typed;
  • the time it was added, taken from our server’s clock;
  • which page of this site you added it from.

We do not store your IP address, your user agent, your referrer or any tracking identifier beside it. Google Cloud keeps its ordinary request log for the function that receives the submission, as described above, and that log is the only place a network address appears.

The row is keyed by a one-way digest of your address rather than by the address itself. That is a safe key, not anonymisation: the row still contains your address, because we have to be able to write to you.

How to come off the list. Write to privacy@klodd.app and we will delete the row. If you later hold a KLØDD account under the same address, deleting that account deletes this row too — not as a promise to remember, but because the waitlist is one of the collections the deletion path is derived from. The next section says how that works.

Third parties, and what each one receives

The third parties the shipping product contacts, and the narrowest true description of what each one gets. The website you are reading is served by our hosting provider, which sees the request like any web host.
ServiceWhyWhat it receives
Google FirebaseSign-in, and vending the short-lived transport tokenYour sign-in credential and account identifier; the counters described above. Not your conversations.
AblyThe relay transport and presenceChannel and client identifiers containing your account identifier; message event names, sizes and timing. Message and presence payloads as ciphertext when you have enabled a key, and as plaintext when you have not.
RevenueCatRecording which subscription you holdYour Firebase account identifier, used directly as the customer identifier, and store purchase receipts. We set no name, email or other attribute on that customer record.
PaddleMerchant of record for macOS and web purchases, once checkout opens (not live today)Your billing details and payment instrument, handled by Paddle. We never see or store a card number.
Apple and GoogleSign in with Apple and Google Sign-In; in-app purchases; push deliveryThe sign-in exchange, purchase records for store purchases, and — for push — your device push token and the notification itself.
Expo (EAS Update)Delivering app updates to the phone appAn update request from your app, including its version and platform, in order to be served the right bundle.
Hugging FaceOne-time download of the on-device speech model, if you use hands-free voice on the phoneA request for a specific pinned model file, verified by checksum. Your speech is processed on the device and is not sent there.
npm registryChecking for and installing kotg updates on your own machineA package version request, as any package install makes.
GitHubUpdate manifests and release downloads for the kotg CLI and the desktop appA request for a release file, which reveals your IP address and that you are checking for an update, as any download does.
Your model providerInference, and where the provider offers one, the list of models you can choose fromYour prompts, your files as your agent sends them, and your own API key — directly from your machine, under that provider’s own terms and billed to your own account. We are not in that path.
SentryCrash reporting in the phone app — only when a build is configured with itWhen enabled: crash stack traces and a small sample of app-start traces. Console logs are dropped, request bodies are removed, personally identifying data is not sent, and session replay is not used. Without that configuration the library is present in the app but is never initialised, so nothing is collected and nothing is sent.

The desktop app’s interface cannot make network requests at all — its content security policy permits only communication with its own local shell. The app does check for its own updates, from the shell rather than from the interface, and the rest of its network access happens in the kotg daemon.

Push notifications

This is the one place where end-to-end encryption does not reach, and it is worth being exact about.

A push notification has to be readable by Apple’s or Google’s delivery service in order to be displayed on a locked screen, so its title and body travel outside the encrypted envelope. Alongside them travels a small plaintext data map identifying the notification type, your account identifier, the host identifier and the session identifier.

  • If the receiving device holds your encryption key, the notification body is a fixed generic sentence — for example that an agent needs approval to continue — and the detail is fetched over the encrypted channel once you open the app.
  • If the receiving device does not hold a key, the body carries a short preview — up to about 120 characters of the command, prompt, question, or the session title — because there would be nothing gained by withholding it from a channel that is already in the clear.

Push is optional. Registering for it sends your device’s push token to the transport so it can be addressed.

Payments

Checkout is not open yet. When it opens, Paddle.com Market Ltd will be the merchant of record for purchases made on macOS and on this website: Paddle handles the payment, holds the billing details, and appears on your statement. Purchases made inside the iPhone or Android app are handled by Apple and Google respectively under their own terms.

In every case we receive the fact that an account holds a subscription and the plan it holds. We do not receive, store or process card numbers.

Retention

  • Account record: kept while your account exists, deleted when you delete it.
  • Rate-limit counter: carries an expiry timestamp a minute or so after the window it counts, is reclaimed by the database’s expiry policy, and is deleted when you delete your account.
  • Monthly usage counter: carries an expiry timestamp, is reclaimed after the billing period it belongs to, and is deleted when you delete your account.
  • Sealed companion-pet blobs: kept while your account exists, deleted when you delete it.
  • Waitlist row: kept until the launch it exists for, or until you ask us to delete it, or until you delete an account held under the same address — whichever comes first.
  • Messages in transit: your phone asks the transport for roughly the last two minutes of a channel when it reconnects, so a brief reconnect does not lose what arrived while you were in a lift. Neither app asks the transport for older history than that. It is a separate thing that your phone can ask your own machine for earlier conversation, as what crosses the relay describes; that content comes from the agent’s store on your computer, not from us.

Your rights, and deleting your account

You can delete your account from inside the phone app. Doing so deletes your Firebase Authentication record, deletes your customer record at RevenueCat, and deletes everything we hold under your account identifier: the rate-limit counter, the monthly usage counter, the sealed companion-pet blobs together with every sealed ledger chunk beneath them, and the waitlist row for your address if one exists. Because we never held your conversations, there is no conversation history for us to delete.

That list is derived rather than remembered. Every collection our backend writes is classified in one place, and the deletion plan is generated from that classification — so a store we add later is either erased or it fails our build. It is not a list somebody has to keep updating, which is the way such a list stops being true.

Depending on where you live you may have rights to access, correct, export or erase personal data we hold, and to object to its processing. Given how little we hold, most such requests resolve to the account record and the two counters. Write to privacy@klodd.app and we will answer.

Marcus Ong is the data controller for the account record and counters described here — a Swedish enskild firma (sole trader), so the controller is that natural person rather than a company.

Security

  • Transport tokens are short-lived, scoped to your own account’s channels, and never grant administrative capability.
  • The provider API keys you connect through kotg live in the operating system keychain, are handed to the agent process through its environment rather than through a file, and are never included in configuration kotg writes or in anything it publishes.
  • Payload encryption is authenticated, and binds each message to its channel and direction, so a message captured on one session cannot be made to open on another.
  • This website is served over HTTPS only. Both klodd.app and klodd.dev sit under top-level domains on the HSTS preload list, which means browsers refuse an insecure connection to them outright rather than warning about it.

No system is perfect, and we will not claim otherwise. If you find a security problem, write to support@klodd.app.

Children

KLØDD is a developer tool and is not directed at children. We do not knowingly collect personal data from anyone under 16. If you believe a child has created an account, write to privacy@klodd.app and we will delete it.

Changes to this policy

When this policy changes we update the date at the top. If a change materially widens what we collect or who receives it, we will say so in the app as well as here, rather than relying on you to re-read the page.

Contact

Privacy questions: privacy@klodd.app. Everything else: support@klodd.app. Marcus Ong is the operator of KLØDD. See also the Terms of service.

Also read: Terms of service · Privacy policy · Refund policy