AgentGate
Vibe-code from your phone, one container per project.
Drive Claude, Copilot, Codex, or Gemini CLIs on your projects from Telegram or Slack, one isolated Docker container per repo.
Vibe-code from your phone, one container per project.
Drive Claude, Copilot, Codex, or Gemini CLIs on your projects from Telegram or Slack, one isolated Docker container per repo.
AI coding CLIs are good company at a desk and useless the moment you leave one. The tools run in a terminal session tied to a machine. Step away and you lose the thread: an agent finishes a task and waits, hits an auth error, or needs a decision, and there is nobody to answer.
I wanted to keep moving work forward from a phone. Not a toy chat wrapper, but the actual Claude, Copilot, Codex, or Gemini CLI running against a real repository, reachable from Telegram or Slack. The constraint that shaped everything else: I run several projects at once, each with its own GitHub token and its own AI backend, and none of them should ever see another project’s secrets.
Most chat bots invent their own command vocabulary. AgentGate does the opposite. Every message you send, /init, /plan add OAuth login, or plain English, is passed straight through to the underlying CLI. You keep using the native commands you already know. AgentGate’s own utility commands live behind a configurable prefix (gate by default) so they never collide with the AI’s commands.
Each project is its own Docker Compose stack with its own .env. A bot clones exactly one repo, holds one fine-grained GitHub token scoped to that repo, and talks to one chat. Running five projects means five containers side by side, fully isolated. A leaked token or a confused agent cannot reach beyond its own workspace.
The backend is a config value, not a rewrite. AI_CLI selects Copilot, Codex, Claude, or Gemini, with a direct-API path for OpenAI, Anthropic, and Ollama. The CLI-based backends are field-tested; the direct-API path is implemented and unit-tested but not yet validated end to end, and the README says so plainly rather than overselling it.
Run several containers in one Slack workspace, each with a different backend and a unique prefix (dev, sec, docs). Agents delegate sub-tasks to each other through a [DELEGATE] protocol: a single docs command can trigger a documentation agent that hands code work to a Codex agent and a security review to a Copilot agent, with no human routing in between.
AgentGate runs as a persistent process inside a non-root Docker container. On startup it validates the environment and fails fast with a clear message, clones the target repo into /repo, auto-installs dependencies based on what it finds (package.json, pyproject.toml, or go.mod), opens a SQLite store for conversation history, starts the chosen AI backend, and posts a Ready message to the chat. From then on, incoming messages are forwarded to the backend as a subprocess, output is streamed back with throttled message edits, and per-chat history is injected as context for stateless backends.
Telegram / Slack
|
v
+-----------------+
| AgentGate | one container per project
| - platform I/O |
| - cmd router |---> gate utility commands (run, sync, git, cancel)
| - history (DB) |
+-----------------+
|
v
AI backend subprocess (copilot | codex | claude | gemini | api)
|
v
/repo (cloned GitHub repository)
On Slack, several of these containers share a workspace. Each listens for its own prefix, and trusted agent bot IDs let one container’s output reach another, which is what makes agent-to-agent delegation work.
I chose to shell out to each official CLI rather than import vendor SDKs. The tradeoff is real: subprocess management, stream parsing, and timeout handling are all on me. The payoff is that AgentGate inherits whatever the official CLI already does well, authentication, tool permissions, model selection, and stays useful as those CLIs evolve. Claude CLI even supports OAuth credentials from a Pro or Max subscription, so users can skip pay-per-use API keys entirely.
Forwarding /init and /plan verbatim to the AI means AgentGate cannot pretend Slack does not exist. Slack intercepts any message starting with / as a native slash command, so users must prefix a space to send one through. That is an awkward edge I accepted on purpose: a leaky abstraction that keeps the native CLI experience intact beats a clean abstraction that forces people to relearn commands.
The bot only answers a configured chat ID, with optional per-user allowlists on top. Shell commands run through gate run reject shell metacharacters outright, and an optional read-only mode or allowlist narrows them further. Destructive operations (push, merge, rm, force) require inline confirmation, and secrets are redacted from outgoing messages and commit text unless explicitly allowed. The default posture is cautious, and loosening it is a deliberate opt-in.
docker pull agigante80/agentgate:latest cp .env.example .env && docker compose up -d → Full setup guide configuration, deployment, troubleshooting