# ๐ŸŒ€ Setting Up Codex Agent: Self-Hosted AI Coding Agent (App-Server + Telegram Bot)

**Date:** July 16, 2026  
**Tags:** AI, Codex, Coding Agent, Self-Hosted, Telegram, 9Router, MCP, AI Agents

---

## ๐ŸŽฏ Overview

[Codex](https://github.com/openai/codex) (the OpenAI **Codex CLI**) is a terminal-native **AI coding agent** with a strong non-interactive mode (`codex exec`), a built-in **app-server** (WebSocket) for remote/UI clients, and a companion **Telegram bot**. On this VM it's the *exec-and-automate* coder โ€” great for one-shot `exec` runs, code reviews, and chat-driven coding via Telegram.

Like the rest of the stack, Codex rides **9Router** (primary) with an **OpenRouter** fallback for free inference, and speaks **MCP** so we wire in **GBrain** (shared memory).

### Why Codex?

| Feature | Benefit |
|---------|---------|
| **โšก `exec` mode** | Non-interactive one-shot coding/patches |
| **๐Ÿ” `review`** | Automated code review passes |
| **๐Ÿ›ฐ๏ธ app-server** | WebSocket server for remote/UI clients |
| **๐Ÿ“ก Telegram Bot** | Code from chat |
| **๐Ÿ”Œ MCP Ready** | GBrain + any MCP server |
| **๐Ÿ›ก๏ธ Sandbox** | Scoped `writable_roots` + network policy |

---

## ๐Ÿ—๏ธ Architecture Overview

```
   Telegram โ”€โ”€โ–บ codex-telegram-bot (Python) โ”€โ”€โ”
                                        โ”‚      โ”‚
   UI / CLI โ”€โ”€โ–บ codex (interactive/TUI) โ”€โ”ค      โ–ผ
                       โ”‚                 โ”œโ”€โ”€โ–บ codex app-server (ws://127.0.0.1:8765)
                       โ”‚                 โ”‚        โ”‚
                       โ”‚                 โ”‚        โ–ผ
                       โ”‚                 โ”‚   9Router / OpenRouter (free models)
                       โ”‚                 โ”‚        โ”‚
                       โ””โ”€โ”€ MCP โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ–บ GBrain (shared memory / Postgres)
```

---

## ๐Ÿ“‹ Prerequisites

- Linux VM with Node toolchain (Codex ships as a Node package).
- A model backend โ€” **9Router** (see the [9Router guide](/blog/9router-setup/)) and/or OpenRouter.
- (Optional) GBrain MCP server for shared memory.
- A Telegram bot token from [@BotFather](https://t.me/BotFather) (placeholder below).
- Non-root user (`ryan` in examples).

> โš ๏ธ **Security note:** Every secret below is a ``. Never commit real keys.

---

## ๐Ÿ“ฆ Step 1 โ€” Install Codex

```bash
# Install Codex globally
npm install -g @openai/codex

# On this VM the binary resolves here:
# /home/ryan/.hermes/node/bin/codex ->
#   ../lib/node_modules/@openai/codex/bin/codex.js
# A convenience symlink also lives at /home/ryan/.local/bin/codex

# Verify
which codex
codex --help

# Diagnose install/config/auth health
codex doctor
```

---

## โš™๏ธ Step 2 โ€” Model Backend (9Router + OpenRouter)

Codex reads config from `~/.codex/config.toml`. The model key is fetched at runtime by a small helper that reads from the env file:

```python
# ~/.codex/get-9router-key.py (sanitized concept)
# Reads NINE_ROUTER_API_KEY from ~/.hermes/.env and prints it.
from pathlib import Path
for line in Path('/home/ryan/.hermes/.env').read_text().splitlines():
    if line.startswith('NINE_ROUTER_API_KEY='):
        print(line.split('=', 1)[1].strip())   # use as 
        raise SystemExit(0)
raise SystemExit('NINE_ROUTER_API_KEY not found')
```

Point Codex's provider at `http://192.168.51.115:20128/v1` (9Router) with `api_key: ""`, and keep an OpenRouter key (``) as fallback. The `config.toml` also carries sandbox + MCP settings:

```toml
# ~/.codex/config.toml (sanitized)
[mcp_servers.gbrain]
command = "/home/ryan/.bun/bin/gbrain"
args = ["serve"]

[mcp_servers.gbrain.env]
GBRAIN_DATABASE_URL = ""
GBRAIN_DIRECT_DATABASE_URL = ""
PATH = "/home/ryan/.bun/bin:/home/ryan/.local/bin:/usr/local/bin:/usr/bin:/bin"

[projects."/home/ryan/.codex"]
trust_level = "trusted"

[tui.model_availability_nux]
"gpt-5.6-sol" = 1

[sandbox_workspace_write]
writable_roots = ["/home/ryan"]
network_access = true
```

---

## ๐Ÿงฉ Step 3 โ€” Wire GBrain via MCP

Codex supports MCP servers (same GBrain server as the other agents):

```toml
[mcp_servers.gbrain]
command = "/home/ryan/.bun/bin/gbrain"
args = ["serve"]

[mcp_servers.gbrain.env]
GBRAIN_DATABASE_URL = ""
GBRAIN_DIRECT_DATABASE_URL = ""
```

Verify before relying on it:

```bash
/home/ryan/.bun/bin/gbrain get_health
# -> healthy
```

You can also manage servers at runtime:

```bash
codex mcp list
codex mcp add gbrain -- /home/ryan/.bun/bin/gbrain serve
```

---

## ๐Ÿš€ Step 4 โ€” App-Server Mode (WebSocket)

Codex exposes an **app-server** over WebSocket so remote/UI clients can drive it:

```bash
# Start the app-server on a local WebSocket port
codex app-server --listen ws://127.0.0.1:8765

# On this VM this runs persistently (seen via):
pgrep -af 'codex app-server'
```

> ๐Ÿ’ก Bind to `127.0.0.1` only; put it behind a reverse proxy if external access is needed.

---

## ๐Ÿค– Step 5 โ€” Telegram Bot

Codex has a companion **Telegram bot** (Python) that bridges chat โ†’ coding sessions. It runs from a dedicated venv.

```ini
# ~/.config/systemd/user/codex-telegram-bot.service
[Unit]
Description=Codex Telegram Bot
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/home/ryan/telegram-codex
ExecStart=/home/ryan/telegram-codex/venv/bin/python /home/ryan/telegram-codex/bot.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=PATH=/home/ryan/telegram-codex/venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=TELEGRAM_BOT_TOKEN=
Environment=NINEROUTER_API_KEY=

[Install]
WantedBy=default.target
```

```bash
systemctl --user daemon-reload
systemctl --user enable --now codex-telegram-bot.service
systemctl --user is-active codex-telegram-bot.service
# -> active
```

> ๐Ÿ”‘ The bot token is a `` โ€” supply it via env, never commit.

---

## ๐Ÿงช Step 6 โ€” Usage Examples

**One-shot exec (non-interactive):**

```bash
codex exec -- "Add input validation to src/validate.py and run the tests"
```

**Code review:**

```bash
codex review
```

**Resume a session:**

```bash
codex resume --last
```

**Apply the last diff:**

```bash
codex apply
```

---

## ๐Ÿฉบ Step 7 โ€” Smoke Test

```bash
# 1. Codex binary resolves
which codex

# 2. app-server listening
pgrep -af 'codex app-server'

# 3. 9Router reachable with key (placeholder)
curl -s --max-time 8 -H "Authorization: Bearer " \
  http://192.168.51.115:20128/v1/models | head -c 200

# 4. Telegram bot service active
systemctl --user is-active codex-telegram-bot.service

# 5. GBrain MCP healthy
/home/ryan/.bun/bin/gbrain get_health

# 6. Doctor check
codex doctor
```

---

## ๐Ÿฉบ Troubleshooting

| Symptom | Likely cause | Fix |
|---------|-------------|-----|
| `codex: command not found` | Not on PATH | Use `/home/ryan/.hermes/node/bin/codex` or `npm link` |
| Model calls 401 | Wrong/expired key | Re-export `` / `` |
| Bot silent | Bad `TELEGRAM_BOT_TOKEN` | Re-paste placeholder, restart service |
| MCP tools missing | gbrain down / bad env | `gbrain get_health`, fix `` |
| Sandbox write denied | `writable_roots` too narrow | Widen `[sandbox_workspace_write]` in `config.toml` |

---

## ๐Ÿ” Security Checklist

- [ ] `TELEGRAM_BOT_TOKEN`, `NINEROUTER_API_KEY`, `OPENROUTER_API_KEY` are ``s, env-injected, never committed.
- [ ] GBrain Postgres URLs are placeholders; DB user is least-privilege.
- [ ] `codex app-server` binds `127.0.0.1` (or behind a proxy), not `0.0.0.0` unprotected.
- [ ] `[sandbox_workspace_write].writable_roots` scoped to `/home/ryan`.
- [ ] `network_access` deliberately set (here `true` for package installs during coding).

---

## โœ… Summary

You now have the **Codex Agent** wired into your AI stack:

- Installed as a global Node CLI (`~/.hermes/node/bin/codex`).
- Runs an **app-server** over WebSocket (`ws://127.0.0.1:8765`) for remote/UI clients.
- Bridges to **Telegram** through `codex-telegram-bot` (managed systemd service, Python venv).
- Routes models through **9Router** (primary) with **OpenRouter** fallback โ€” both free.
- Connected to **GBrain** via MCP for shared memory across all agents.
- Sandboxed with scoped `writable_roots` + network policy.

Codex joins [Pi](/blog/pi-coding-agent-setup/) and [OpenCode](/blog/opencode-agent-setup/) as a coding agent โ€” all behind [OpenClaw](/blog/openclaw-setup/) (gateway), orchestrated with [Hermes](/blog/hermes-setup/), leaning on [9Router](/blog/9router-setup/) for inference. ๐Ÿš€

---

*No API keys, tokens, or secrets are included in this guide โ€” every value is a `` you supply locally. Built with Astro, GitHub, and Cloudflare Pages.*