End-to-End Encryption for AI Coding Sessions
Your AI coding session contains more than just your question. It contains source code, file paths, database schemas, and occasionally credentials that slip into context. Styrby encrypts all of this before it leaves your machine. This article explains the encryption architecture, the key exchange protocol, and what the server can and cannot see.
Why Zero-Knowledge Matters for Code
AI agent sessions are not casual chat messages. They contain proprietary source code, API designs, and sometimes secrets a developer accidentally includes in context. A server breach that exposes these sessions could leak intellectual property or credentials.
Zero-knowledge architecture means the server stores only ciphertext. Even if someone compromises the server, they get encrypted blobs that are useless without the client-side keys. This is the same principle behind Signal and ProtonMail, applied to coding sessions.
The Encryption Stack
Styrby uses TweetNaCl (pronounced "tweet salt"), a compact, audited cryptography library. Specifically, it uses the nacl.box construction, which combines:
- Curve25519 for key exchange (Diffie-Hellman on an elliptic curve)
- XSalsa20 for symmetric encryption (stream cipher)
- Poly1305 for message authentication (MAC)
This combination provides authenticated encryption. An attacker cannot decrypt the message (confidentiality) or modify it without detection (integrity). Both properties matter: confidentiality keeps code private, integrity prevents tampering with permission responses.
Key Generation and Exchange
When you set up Styrby on a new device, the CLI generates a Curve25519 key pair:
// Key generation happens once per device
const keyPair = nacl.box.keyPair();
// keyPair.publicKey → 32 bytes, stored on server
// keyPair.secretKey → 32 bytes, stored ONLY on deviceThe public key is uploaded to Styrby's machine_keys table in Supabase. The secret key never leaves the device. It is stored in the system keychain (macOS Keychain, Windows Credential Manager, or Linux Secret Service).
When your mobile app connects to a CLI session, the two devices exchange public keys. Each device then computes a shared secret using its own secret key and the other device's public key:
// On the CLI side
const sharedKey = nacl.box.before(mobilePublicKey, cliSecretKey);
// On the mobile side
const sharedKey = nacl.box.before(cliPublicKey, mobileSecretKey);
// Both derive the same shared key (Diffie-Hellman property)Message Encryption Flow
Every session message goes through this process before transmission:
- The CLI captures agent output (code, explanations, permission requests).
- A random 24-byte nonce is generated for this message. Nonces are never reused.
- The message is encrypted using
nacl.box.afterwith the shared key and nonce. - The encrypted message and nonce are sent to the server together.
- The server stores both in the
session_messagestable without any ability to decrypt them. - The receiving device retrieves the ciphertext and nonce, then decrypts locally using the same shared key.
// Encryption (sender side)
const nonce = nacl.randomBytes(24);
const encrypted = nacl.box.after(
messageBytes,
nonce,
sharedKey
);
// Send { nonce, encrypted } to server
// Decryption (receiver side)
const decrypted = nacl.box.open.after(
encrypted,
nonce,
sharedKey
);What the Server Sees
The Styrby server has access to:
- Encrypted ciphertext (useless without keys)
- Message timestamps
- Token counts (for cost tracking, computed client-side before encryption)
- Session metadata: agent type, status, project name (configurable)
The server does NOT have access to:
- Source code
- Agent prompts or responses
- File contents
- Permission request details (only the approval/denial result)
- Secret keys
The Key Loss Problem
Zero-knowledge encryption has a real downside: if you lose your device keys, your encrypted session history becomes unrecoverable. Styrby cannot help you because Styrby does not have the keys.
Mitigation: Styrby supports registering multiple devices. Your mobile and your workstation each have their own key pairs and can both decrypt session data. Losing one device does not lose your history, as long as the other device still has its keys. Register at least two devices.
Why TweetNaCl Over WebCrypto or libsodium
TweetNaCl is a deliberate choice. It is a single-file, audited implementation with no dependencies. The entire library is about 7KB minified, which matters for a CLI tool where dependency weight and supply chain risk are real concerns.
WebCrypto is browser-native but has an inconsistent API across environments and does not work in all Node.js versions without polyfills. libsodium is more feature-rich but adds a larger dependency. For the specific operations Styrby needs (box encryption with Curve25519), TweetNaCl provides exactly the right primitives with minimal overhead.
Verification
The encryption implementation is open for review in the Styrby CLI source code. If you want to verify that messages are actually encrypted before transmission, inspect the network traffic: every message payload is base64-encoded ciphertext, not readable JSON.
Ready to manage your AI agents from one place?
Styrby gives you cost tracking, remote permissions, and session replay across five agents.