---
title: "The Chatcode Gateway"
seoTitle: "Chatcode Gateway: Install, Trust & How It Works"
navTitle: "Gateway"
description: "What the Chatcode gateway is, where it runs (Linux vs macOS), how it talks to Chatcode, the trust trade-offs, and why macOS shows permission prompts."
slug: gateway
date: 2026-06-12
updated: 2026-06-12
author: Chatcode
section: Gateway
order: 1
keywords:
  - chatcode gateway
  - chatcode gateway install
  - chatcode gateway security
  - chatcode macos permissions
faq:
  - q: "Do I need my own server to run the gateway?"
    a: "No. In easy mode, Chatcode connects to DigitalOcean and provisions a Linux droplet that runs the gateway for you. The bring-your-own path installs the same gateway on a Linux server or a Mac you already own."
  - q: "Why does macOS say chatcode-gateway wants to access my Documents / Downloads / screen?"
    a: "On macOS the gateway runs as your own user, so the coding agent you're driving (Claude Code, Codex, etc.) has the same file access you do. When that agent reads a protected folder or uses a protected capability, macOS shows its standard privacy prompt and attributes it to the process that launched the agent — the gateway. It's your agent doing what you asked, surfaced through macOS's normal consent flow. Allow what you expect; deny what you don't."
  - q: "Does the gateway open ports on my machine?"
    a: "No inbound ports. The gateway makes an outbound TLS WebSocket connection to the Chatcode control plane and the control plane relays traffic from your browser and Telegram. (SSH for a debug session is separate and opt-in.)"
  - q: "Can Chatcode see my terminal traffic?"
    a: "In transit, yes. Traffic is TLS-encrypted per hop, but there is no end-to-end encryption between your browser and the gateway — by design. The control plane processes session content to power the Telegram experience (formatting agent output, file previews, voice transcription, notifications), so it sits in a trusted-relay position and can read terminal payloads. Your code, keys, and agent sessions still live only on your machine; to control the relay too, self-host it."
  - q: "Why does the gateway use passwordless sudo on Linux?"
    a: "So an agent you're driving can perform admin tasks (install a package, restart a service) without stalling on a password prompt you can't answer remotely. On Linux it runs as a dedicated `vibe` user, and every sudo command is written to a root-owned, append-only log you can review."
---

The **gateway** is the small program that makes Chatcode work on a machine you own. It runs your coding agents — Claude Code, Codex, Gemini, OpenCode — and connects them to the browser at [app.chatcode.dev](https://app.chatcode.dev) and to Telegram, **without exposing anything inbound on your machine**.

This page explains what it is, where it lives, how it talks to Chatcode, and the trust trade-offs in plain terms — including why **macOS sometimes shows alarming-looking permission prompts** (short version: it's your agent doing what you asked).

## What the gateway is

- A single binary, `chatcode-gateway` (built per platform: Linux/macOS × Intel/ARM), installed as a background service.
- It holds **one outbound connection** to the Chatcode control plane and runs your agent sessions in `tmux` workspaces under `~/workspace`.
- It's the "Your server + gateway" box in the [Chatcode architecture](/articles/claude-code-telegram-with-chatcode): browser ⇄ Chatcode ⇄ **your gateway** ⇄ agent session.
- The release binary is downloaded over HTTPS and **checksum-verified (SHA-256)** before it's installed.

## Where it runs: Linux vs macOS

The gateway uses two different models depending on the OS — this is the biggest practical difference.

### Linux — a dedicated `vibe` user (isolated)

Used by easy-mode DigitalOcean droplets and bring-your-own Linux servers. The installer runs as **root** and:

- Creates a dedicated **`vibe`** user — agents run as `vibe`, **not** as your login account — with its workspace at `/home/vibe/workspace`.
- Installs a **systemd** service (`chatcode-gateway.service`) that runs as `vibe`.
- Installs base tools including `tmux`, `git`, `ripgrep`, and **`bubblewrap`** (for sandboxing agent sessions).
- Pre-installs Claude Code + Codex and enables a daily maintenance timer that updates the agent CLIs and the gateway itself.

Because agents run as their own user, they're **isolated from your personal account and files** on that box.

### macOS — your own user

Used when you bring your own Mac. The installer runs as **your normal user (never `sudo`)** and:

- Installs the binary to `~/.local/bin/chatcode-gateway` and a **launchd** agent (`dev.chatcode.gateway`) that starts at login and stays running (kept awake with `caffeinate` on desktop Macs).
- Requires Homebrew plus `tmux`, `git`, `curl`.

Here the agent runs **as you**, so it has the same file access you have. That's convenient — and it's the reason macOS shows the permission prompts described below.

### Where things live

| | Linux (managed) | macOS (your user) |
| --- | --- | --- |
| Binary | `/usr/local/bin/chatcode-gateway` | `~/.local/bin/chatcode-gateway` |
| Service | systemd `chatcode-gateway.service` | launchd `dev.chatcode.gateway` |
| Config/env | `/etc/chatcode/gateway.env` (mode 600) | `~/.config/chatcode/gateway.env` (mode 600) |
| Runs as | dedicated `vibe` user | your login user |
| Workspace | `/home/vibe/workspace` | `~/workspace` |
| Logs | `journalctl -u chatcode-gateway` | `~/Library/Logs/chatcode-gateway.log` |

## Installing

In the app, **add a server** and Chatcode gives you a ready-to-run command with your gateway ID, auth token, and control-plane URL already filled in. It pipes the canonical installer at `https://chatcode.dev/install.sh` (which redirects to the latest release) into your shell:

```bash
# Linux — run as root (installs under a dedicated `vibe` user)
curl -fsSL https://chatcode.dev/install.sh | sudo bash -s -- \
  --gateway-id gw_xxx --gateway-auth-token tok_xxx \
  --cp-url wss://<control-plane>/gw/connect

# macOS — run as your normal user (do NOT use sudo)
curl -fsSL https://chatcode.dev/install.sh | bash -s -- \
  --gateway-id gw_xxx --gateway-auth-token tok_xxx \
  --cp-url wss://<control-plane>/gw/connect
```

The installer pulls the gateway binary from `releases.chatcode.dev` and **verifies its SHA-256 checksum** before installing. You can pin a version (`--version vX.Y.Z`) instead of tracking `latest`, or build the binary yourself and install it with `--binary-source /path/to/chatcode-gateway`.

## Passwordless sudo (and how it's kept honest)

When an agent you're driving needs an admin action — install a package, restart a service — it can't stop and ask you for a password through Telegram. So the gateway is set up for unattended admin:

- **Linux:** the `vibe` user gets `NOPASSWD` sudo — but every command is recorded (`use_pty`) to a **root-owned, append-only log** at `/var/log/chatcode/sudo-vibe.log` that `vibe` can read but not alter, rotated for 14 days. You can audit exactly what ran.
- **macOS:** passwordless sudo is **optional and only offered if you opt in** during install. Decline it and the gateway still works; you'll just be asked for your password (or admin tasks won't run) like any normal Mac.

This is a deliberate trade-off for "works while you're away," made auditable rather than hidden.

## macOS permission prompts — don't panic

If you run the gateway on your Mac, you'll likely see macOS prompts such as:

> **"chatcode-gateway" would like to access files in your Documents folder.**

…or prompts about your **Desktop**, **Downloads**, removable volumes, **Accessibility**, or **Screen Recording**. This can look alarming — as if the gateway wants to snoop. It doesn't.

Here's what's actually happening: on macOS the gateway runs **as you**, and it runs the agent **you** asked for. When that agent reads a file in a protected folder, or a tool it runs needs to automate the UI or capture the screen, **macOS's privacy system (TCC)** steps in and asks for consent — and it attributes the request to the process that launched the work, which is `chatcode-gateway`. So the name on the dialog is the gateway, but the intent is your agent doing the task you gave it.

What to do:

- **Allow what you expect.** If you asked the agent to work with files in `~/Documents`, allowing Documents access is exactly right.
- **Deny what you don't.** You're always in control; denying just means the agent can't touch that resource.
- **Manage it anytime** in **System Settings → Privacy & Security** (Files and Folders, Accessibility, Screen Recording).

On **Linux** there's no equivalent modal — the `vibe` user simply has its own Unix permissions, isolated from your account.

## How it communicates

```
Browser / Telegram  ⇄  Chatcode control plane  ⇄  your gateway  ⇄  agent session
      (you)                  (TLS relay)            (your machine)   (Claude/Codex/…)
```

- The gateway dials **out** to the control plane over a **TLS WebSocket** (`wss://…`). It never opens an inbound port on your machine.
- The browser and Telegram connect to the control plane, which **relays** traffic to your gateway.
- Your auth uses a session cookie; the gateway authenticates with a per-gateway token. The control plane **does not store your private SSH keys**.

### No end-to-end encryption — and why

There is **no end-to-end encryption between your browser and the gateway**, and that's a deliberate design choice, not an oversight. Each hop is TLS-encrypted, but the control plane terminates those connections so it can **process the session content** that makes the Telegram experience work — formatting agent output for chat, rendering file previews, transcribing voice notes, and deciding when to notify you. That processing needs readable payloads, so the control plane sits in a **trusted-relay position** and can read terminal traffic.

We'd rather state this plainly than imply a guarantee we don't offer. Your code, credentials, and agent sessions still live only on **your** machine. If you want the relay under your control as well, you can **self-host the control plane** in your own Cloudflare account.

## What the gateway shows in Telegram

Telegram is the continuity layer, and the gateway is what serves it. When you open a **file preview** from a chat, the gateway reads that file and hands it back through the relay. The bounds are deliberately tight:

- **Read-only.** Previews never write. Only session work and uploads write, and those are confined to `~/workspace`.
- **Scoped.** Previews resolve under `~/workspace` plus **non-hidden** paths in the gateway user's home. Hidden stores like `~/.ssh`, `~/.claude`, and `~/.codex` are off-limits unless they live inside `~/workspace` — and the check runs on the **symlink-resolved real path**, so it can't be tricked with a symlink.
- **Short-lived links.** A preview download uses a cookieless bearer URL that expires in about five minutes.

One caveat worth stating plainly: the preview read-root includes *non-hidden* files anywhere under the gateway user's home — so **keep secrets out of that home directory** (on Linux that's `/home/vibe`), not just out of dotfiles.

## Trust & privacy summary

- **Your machine, your subscription.** Agents run on hardware you own using your own Claude/ChatGPT login. Chatcode is the relay, not a cloud that copies your repo elsewhere.
- **No inbound ports.** Only an outbound WebSocket. SSH access for a debug session is **separate and opt-in** (you add a key; it's empty by default).
- **Workspace boundary.** Session work and uploads are constrained to `~/workspace`; Telegram previews are read-only and scoped (details above).
- **Auditable admin.** Passwordless sudo on Linux is logged to an append-only, root-owned file.
- **Secrets at rest.** The env file holding your gateway token is mode `600`.

## Verify what runs

You don't have to take our word for it:

1. **Read the installer.** It's a plain shell script you run yourself — inspect it before it touches the machine.
2. **Verify the checksum.** Every release ships a `.sha256`; the installer checks it, and you can re-verify.
3. **Pin a version** with `--version vX.Y.Z` instead of `latest`.
4. **Build from source** and install with `--binary-source`.
5. **Self-host the control plane** in your own Cloudflare account for full custody of the relay.

We're documenting the gateway **protocol** and opening more of the source over time, so the relay and on-machine behavior can be independently verified — transparency is how this earns trust.

## Updating & uninstalling

- **Update:** a daily maintenance job updates the gateway and agent CLIs automatically. To update now, rerun the installer with a newer `--version`.
- **Status / logs:** `systemctl status chatcode-gateway` and `journalctl -u chatcode-gateway` on Linux; `~/Library/Logs/chatcode-gateway.log` on macOS.
- **Uninstall:** run the cleanup script. It's **destructive by default** — read it first.

```bash
# Linux — removes the service, config, sudoers + log policy, and the `vibe` user + home
curl -fsSL https://chatcode.dev/cleanup.sh | sudo bash -s -- --yes

# macOS — removes the launchd agents, binary, config, and Chatcode-managed hooks; keeps ~/workspace
curl -fsSL https://chatcode.dev/cleanup.sh | bash -s -- --yes
```

Useful flags: `--keep-user` (Linux: keep the `vibe` user and its home), `--keep-workspace`, `--remove-workspace` (macOS: also delete `~/workspace`), and `--kill-tmux`. On macOS `~/workspace` is kept unless you pass `--remove-workspace`.

---

New to all this? Start with **[How to use Claude Code in Telegram with Chatcode](/articles/claude-code-telegram-with-chatcode)** for the big-picture setup.
