Chat with your self-hosted AI agent from your phone, without handing your data to anyone.
cozygateway is a single self-hosted Node process you run next to your agent. It speaks a small published wire contract to chat clients and uses its attach data plane to let an agent harness dial in over a small WebSocket protocol and answer turns live.
There are two ways in. Pick the one that fits your machine.
curl -fsSL https://cozylabs.ai/install.sh | bashNo Docker, git, or build tools. It requires an existing Hermes installation and Node 24+. The
bootstrap verifies versioned release checksums for the gateway bundle, complete Hermes attach-plugin
archive, and installer payload. It discovers Hermes profile homes through the Hermes CLI, installs
one attach identity per selected profile, and supervises one shared gateway service. Existing Hermes
profile gateway services stay Hermes-owned. The default listener is local/LAN (0.0.0.0:8787); the
installer never configures Tailscale, Cloudflare, DNS, firewalls, or tunnels. See
docs/install-service.md and docs/connectivity.md.
Uninstall:
bash ~/.cozygateway/bin/agent-install.sh --uninstall --gateway-dir ~/.cozygatewayThis removes CozyGateway-owned service state, plugin copies, spools, and installer-written env keys; Hermes profiles and Hermes services remain.
The installer targets Hermes profiles already on this machine. For a narrower
selection, pass --profiles default,ops to the one-paste command. The command
uses the installed Hermes CLI as the source of truth for profile homes and does
not clone a repository or create a Docker deployment.
Self-hosted gateways use https://push.cozylabs.ai by default so the store app works
without APNs setup. The gateway encrypts every notification end to end before sending it.
The hosted relay sees only an opaque push ID, ciphertext, optional category and collapse
ID, and the source IP transiently for rate limiting. It never sees message content or
device identity. Override COZYGATEWAY_PUSH_RELAY_URL to use another relay.
A relay you host with your own APNs key cannot push to the store app because APNs keys
are scoped to the publisher team. The local-push Compose profile is for developers who
sign their own app with their own Apple team.
- Pairing: scan a QR code, get a revocable device token. No accounts.
- Threads: multiple renameable DM threads per agent, each bound to its own backend session.
- Streaming: agent replies stream live as typed rich content blocks over one WebSocket.
- History: SQLite-backed message history with strict per-thread ordering and gap replay.
- Push: end-to-end encrypted notifications through the accountless CozyLabs relay by default.
- Shipped: contract v1 (frozen), conformance suite, attach-v1 data plane, hosted relay plus encrypted push origination and APNs delivery (
contract/push-v0.md), TLS for the phone link (gateway-native, or a shipped Caddy sidecar example;docs/tls.md).
contract/: the human-readable, versioned wire contract spec.packages/contract: TypeBox schemas and TypeScript types for the contract (publishable ascozygateway-contract).packages/gateway: the gateway process, implementing contract v1.packages/relay: the push relay service (opaque push ids in, ciphertext through).packages/conformance: contract conformance suite that runs against any gateway implementation, validated against the reference gateway.integrations/attach-plugin: the reference Python platform plugin for the durable attach-v1 data plane; seecontract/attach-v1.mdanddocs/attach-v1-operations.md.
Your messages live in SQLite on your box. The gateway must read plaintext to drive your agent, and it never sends message content outside your box. TLS for the phone link ships two ways, gateway-native or a Caddy sidecar example, and the app pins the certificate on first use; see docs/tls.md. Plain HTTP remains the default, for boxes that already terminate TLS in front. Push leaves the box only as end-to-end encrypted ciphertext.
Requires Node 24+ and pnpm 10.
pnpm install
pnpm check # typecheck + test + buildMIT