A self-hosted platform for running Claude Code from anywhere.
Human-in-the-loop AI development — get push notifications when Claude needs you, review and respond from any device.
Claude Code is powerful, but it runs in your local terminal. Close your laptop and the session dies. Remote Agent puts Claude Code on your server so it keeps working while you're away — and pings your phone when it needs your input.
- Start a task, walk away — Claude keeps coding on your server
- Get notified instantly — push alerts when Claude needs input, hits a permission wall, or finishes
- Respond from anywhere — phone, tablet, or another computer
- Manage everything in the browser — terminal, git, files, docker, and more
Claude Code hooks integrate with Remote Agent's notification system. When Claude needs your attention — waiting for input, requesting permission, or finishing a task — you get a push notification on your phone or desktop. A notification panel in the UI keeps a full history so you never miss anything.
| Notification Type | Trigger |
|---|---|
| Input Required | Claude is waiting for your response |
| Permission Request | Claude needs approval to proceed |
| Task Complete | A session finished its work |
| Error | Something went wrong |
Create and manage multiple concurrent Claude Code sessions. Each session gets its own PTY terminal rendered with xterm.js in the browser. Multiple browser tabs can connect to the same session simultaneously — start a task on your desktop, check progress on your phone.
Sessions include a tabbed workspace with:
- Claude — Interactive Claude Code terminal
- Shell — Additional shell terminals
- Git — Stage, commit, push, pull, branch, and view diffs
- Run — Detect and execute npm scripts or custom commands
- Env — Manage environment variables per project
- Docker — List containers, build images, compose up/down
- Preview — Browser preview for web development
- Editor — Launch code-server for full VS Code editing
- Files — Browse, upload, edit, and manage project files
Organize work into projects backed by git repositories. Clone repos via SSH or HTTPS, manage branches, and perform git operations directly from the UI.
Multi-project workspaces let you link multiple repositories under a single parent project using symlinks — useful for monorepo-style workflows where Claude needs access to several repos at once.
Built-in task management with:
- Drag-and-drop columns by status
- Priority levels, assignees, and project linking
- Task comments with threading
- File attachments
- Task dependencies
- Auto-flows for triggering Claude sessions on task transitions
View and manage Docker containers running on the host. Start, stop, restart, and remove containers. Detect Dockerfiles and compose files in your project, build images, and run docker compose up/down from the UI.
Browse project files with a tree view, view file contents with Shiki syntax highlighting, upload files, and perform move/copy/delete operations. Symlink-aware path validation ensures security across multi-project workspaces.
Add inline review comments to Claude's work, batch them, and send them back to Claude for iteration. Resolve or rerun review batches to refine output.
Launch a browser preview for web development projects with viewport presets (mobile, tablet, desktop). Powered by Puppeteer with real-time screenshot streaming.
curl -fsSL https://raw.githubusercontent.com/mrtcmn/remote-agent/main/install.sh | bashThe installer will:
- Check and install Docker & Docker Compose if needed
- Create the installation directory at
/opt/remote-agent - Prompt you for required API keys (Anthropic, GitHub OAuth)
- Optionally configure Firebase push notifications
- Auto-generate secure
POSTGRES_PASSWORDandJWT_SECRET - Pull the Docker image and start services
Once complete, access the UI at http://localhost:5100.
Custom install path:
INSTALL_DIR=~/remote-agent bash install.sh
- Linux server (Debian/Ubuntu recommended)
- Docker (20.10+) and Docker Compose (v2)
- Anthropic API Key — console.anthropic.com
- GitHub OAuth App — For authentication
Three configurations are provided:
| File | Use Case |
|---|---|
docker/docker-compose.prod.yml |
Production — pulls pre-built image from GHCR |
docker/docker-compose.yml |
Default — build from source or pull image |
docker/docker-compose.dev.yml |
Development — hot-reload with source bind-mount |
cd docker
docker compose -f docker-compose.prod.yml up -dPersistent Volumes:
| Volume | Purpose |
|---|---|
remote-agent-postgres |
Database storage |
remote-agent-workspaces |
Project files and cloned repositories |
remote-agent-ssh-keys |
SSH key pairs |
remote-agent-config |
Custom hooks and skills |
cd docker
docker compose -f docker-compose.dev.yml up -dHot-reloading via Bun's --watch flag, PostgreSQL exposed at 127.0.0.1:5432, and Bun inspector on port 6499.
| Variable | Description |
|---|---|
ANTHROPIC_API_KEY |
Anthropic API key for Claude Code |
GITHUB_CLIENT_ID |
GitHub OAuth App Client ID |
GITHUB_CLIENT_SECRET |
GitHub OAuth App Client Secret |
POSTGRES_PASSWORD |
PostgreSQL database password |
JWT_SECRET |
64-character hex string for session signing |
| Variable | Default | Description |
|---|---|---|
PORT |
5100 |
Server port |
APP_URL |
http://localhost:5100 |
Public-facing URL (used for OAuth callbacks) |
CORS_ORIGIN |
* |
Allowed CORS origins |
NODE_ENV |
production |
Node environment |
IMAGE_TAG |
latest |
Docker image version tag |
| Variable | Default | Description |
|---|---|---|
POSTGRES_USER |
agent |
PostgreSQL username |
POSTGRES_DB |
remote_agent |
PostgreSQL database name |
DATABASE_URL |
(auto-composed) | Full connection string |
Server-side (Admin SDK):
| Variable | Description |
|---|---|
FIREBASE_PROJECT_ID |
Firebase project ID |
FIREBASE_PRIVATE_KEY |
Service account private key (PEM format) |
FIREBASE_CLIENT_EMAIL |
Service account email |
Client-side (injected into frontend at runtime):
| Variable | Description |
|---|---|
VITE_FIREBASE_API_KEY |
Firebase Web API key |
VITE_FIREBASE_AUTH_DOMAIN |
Firebase auth domain |
VITE_FIREBASE_PROJECT_ID |
Firebase project ID |
VITE_FIREBASE_STORAGE_BUCKET |
Firebase storage bucket |
VITE_FIREBASE_MESSAGING_SENDER_ID |
Firebase messaging sender ID |
VITE_FIREBASE_APP_ID |
Firebase app ID |
VITE_FIREBASE_MEASUREMENT_ID |
Firebase analytics measurement ID |
VITE_FIREBASE_VAPID_KEY |
VAPID key for web push |
IMAGE_TAG=latest
POSTGRES_USER=agent
POSTGRES_PASSWORD=your-secure-password-here
POSTGRES_DB=remote_agent
ANTHROPIC_API_KEY=sk-ant-xxxxx
GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxx
GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
JWT_SECRET=your-64-char-hex-string
PORT=5100
APP_URL=http://your-server-ip:5100
NODE_ENV=production- Add keys via the UI — Settings > SSH Keys
- Keys are stored securely —
/app/ssh-keys/{userId}/withchmod 600 - Assign keys to projects — Select an SSH key when creating or editing a project
- Automatic agent registration — All keys registered with
ssh-agenton container startup
# Generate a dedicated key pair
ssh-keygen -t ed25519 -C "remote-agent" -f remote-agent-key
# Add the public key to your Git provider, then paste both keys into SettingsFirebase Cloud Messaging sends push notifications when Claude needs attention.
- Create a Firebase project at console.firebase.google.com
- Enable Cloud Messaging API (V2) in Project Settings > Cloud Messaging
- Generate a VAPID key under Web configuration
- Create a service account and download the JSON key
- Add a web app and copy the config values
- Set all
FIREBASE_*andVITE_FIREBASE_*variables in.envand restart
- Quiet hours — suppress notifications during set times
- Per-type preferences — choose which notification types to receive
- Device management — register/unregister multiple devices
- Debouncing — duplicate notifications within 2 minutes are suppressed
- Action buttons — tap to jump directly to the session
The app binds to 127.0.0.1:5100. Use a reverse proxy for external HTTPS access.
server {
listen 443 ssl;
server_name agent.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/agent.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/agent.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5100;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_for_addr;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support (required for terminal)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}Update .env after setup:
APP_URL=https://agent.yourdomain.comcd /opt/remote-agent
# Check for updates
./upgrade.sh --check
# Upgrade to latest
./upgrade.sh
# Upgrade to a specific version
./upgrade.sh --version v1.2.3The upgrade script creates a PostgreSQL backup before updating, and automatically rolls back if migrations or the health check fail.
- Bun 1.3+
- Docker & Docker Compose (for PostgreSQL)
git clone https://github.com/mrtcmn/remote-agent.git
cd remote-agent
bun install
# Start PostgreSQL
docker run -d --name remote-agent-db \
-e POSTGRES_USER=agent \
-e POSTGRES_PASSWORD=agent \
-e POSTGRES_DB=remote_agent \
-p 5432:5432 \
postgres:16-alpine
# Configure
export ANTHROPIC_API_KEY=sk-ant-xxxxx
export DATABASE_URL=postgres://agent:agent@localhost:5432/remote_agent
export JWT_SECRET=dev-secret-change-in-production
# Run migrations and start
bun run db:migrate
bun run dev:allAPI runs on port 5100, UI dev server on 5173 (proxied to API).
remote-agent/
├── packages/
│ ├── api/ # Backend (Bun + Elysia)
│ │ ├── src/
│ │ │ ├── auth/ # Authentication (Better Auth + OAuth)
│ │ │ ├── db/ # Drizzle ORM + PostgreSQL schema
│ │ │ ├── routes/ # API routes + WebSocket handlers
│ │ │ └── services/
│ │ │ ├── terminal/ # PTY terminal management
│ │ │ ├── git/ # Git operations
│ │ │ ├── notification/ # Push notification adapters
│ │ │ ├── workspace/ # SSH keys, multi-project, env vars
│ │ │ ├── docker/ # Docker container management
│ │ │ ├── browser-preview/ # Puppeteer browser preview
│ │ │ ├── run-config/ # Run configuration execution
│ │ │ ├── code-editor/ # code-server integration
│ │ │ ├── kanban/ # Task board service
│ │ │ ├── auto-flow/ # Task automation flows
│ │ │ └── cli-adapter/ # CLI tool adapters
│ │ └── drizzle/ # SQL migration files
│ └── ui/ # Frontend (React + Vite + Tailwind)
│ └── src/
│ ├── pages/ # Dashboard, Session, Projects, Kanban, Settings
│ ├── components/ # Terminal, Git, Docker, File Explorer, etc.
│ └── hooks/ # React Query data hooks
├── docker/ # Dockerfiles and compose configs
├── scripts/ # Upgrade, build, and dev scripts
└── install.sh # One-command installer
┌────────────────────────────────────────────────────────────────┐
│ Docker Environment │
│ │
│ ┌──────────────┐ ┌────────────────────────────────────┐ │
│ │ React UI │──────>│ Elysia API (Bun) │ │
│ │ (Vite SPA) │ │ │ │
│ │ │ WS │ /api/sessions Session mgmt │ │
│ │ Dashboard │<─────>│ /api/terminals PTY terminals │ │
│ │ Terminal │ │ /api/projects Git repositories │ │
│ │ Projects │ │ /api/kanban Task board │ │
│ │ Kanban │ │ /api/docker Containers │ │
│ │ Settings │ │ /api/notifications Push alerts │ │
│ └──────────────┘ └──────────┬─────────────────────────┘ │
│ │ │
│ ┌──────────────▼──────────────┐ │
│ │ Terminal Service │ │
│ │ (Bun native PTY spawn) │ │
│ └──────┬───────────┬──────────┘ │
│ │ │ │
│ ┌─────────────────▼─┐ ┌─────▼─────────────────┐ │
│ │ Claude Code CLI │ │ Shell / Process │ │
│ │ (hooks → push │ │ terminals │ │
│ │ notifications) │ │ │ │
│ └───────────────────┘ └────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌────────────────────────────┐ │
│ │ PostgreSQL │<──────────│ Drizzle ORM │ │
│ │ (persistent) │ │ sessions, projects, tasks │ │
│ └──────────────┘ └────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────┘
│
▼ push notifications
┌──────────────────┐
│ Firebase FCM │──> Phone / Desktop alerts
└──────────────────┘
- GitHub OAuth primary authentication with optional PIN protection for sensitive operations
- All data scoped per user — queries always filter by
userId - JWT session tokens with 7-day expiry
- SSH keys stored with
chmod 600, container user has no sudo access - Internal hook endpoints only accept requests from
localhost - App binds to
127.0.0.1only — use a reverse proxy for external access - Symlink-aware path validation prevents directory traversal
- Claude Code runs with
--dangerously-skip-permissions— by design for remote autonomous operation
docker compose logs remote-agent
# Most common: missing ANTHROPIC_API_KEY- Verify
GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRET - Callback URL must match:
{APP_URL}/api/auth/callback/github - With a reverse proxy, ensure
APP_URLuseshttps://
docker exec remote-agent ls -la /app/ssh-keys/
docker exec remote-agent ssh-add -l
docker exec remote-agent ssh -T git@github.com- Verify all
FIREBASE_*andVITE_FIREBASE_*variables are set - Check that Cloud Messaging API (V2) is enabled
- Ensure browser has granted notification permissions
docker exec remote-agent bun run db:migrate
docker exec -it remote-agent-db psql -U agent remote_agentMIT




