Agent Server is a production-ready service that exposes Claude Code and Codex-style coding agents over simple HTTP and WebSocket interfaces, packaged for easy deployment as a single Docker container. It includes durable session storage, a streaming generation API, a secure terminal WebSocket, and utility endpoints for environment, filesystem, and Git.
- What is Agent Server?
- Key benefits
- Features
- Getting Started
- Requirements
- Quick Start with Docker (GHCR or local build)
- Local development
- Configuration
- API Overview
- Health
- Sessions
- Generate (Claude Code / Codex)
- Stop generation
- Environment
- Git
- Terminal WebSocket
- Persistence and Data Stores
- Build from source
- Testing
- Deployment (GHCR)
- Contributing
- License
Agent Server is a lightweight orchestration layer that turns stateful coding agents into an easy-to-deploy service. It’s designed to run anywhere you can run Docker, with sensible defaults for security and durability.
- Resilient streaming with graceful shutdown and backpressure handling
- Durable, resumable sessions with background execution
- Secure by default with API key auth and tokenized terminal access
- One-container deployment that also boots a local Redis and Python LLM helper
- Observability via clear logs and a simple health endpoint
- HTTP endpoints to create/list sessions and stream generations
- Supports
agent: "claude-code" | "codex"with image input support - Built‑in terminal WebSocket (
/ws/terminal) protected by short‑lived JWTs - Git utilities: repository discovery and structured diffs
- Filesystem upload and directory listing helpers
- SQLite storage by default; Redis used for lightweight coordination/locks
- Docker Desktop (or any compatible runtime)
- For local dev: Node.js >= 22, pnpm >= 8
- Optional: Python 3.11+ (container uses
uvto run the bundledllm-server)
Pull from GHCR (replace OWNER/REPO if you fork):
docker pull ghcr.io/suhjohn/agent-server:latest
docker run --rm \
-p 3000:3000 -p 22:22 \
-e API_KEY=your-api-key \
-e ANTHROPIC_API_KEY=your-optional-claude-key \
-e ALLOWED_ORIGINS=http://localhost:3000 \
ghcr.io/suhjohn/agent-server:latestOr build locally:
docker build -t agent-server .
docker run --rm -p 3000:3000 -p 22:22 -e API_KEY=your-api-key agent-serverServer starts on port 3000 and exposes:
- HTTP API on
:3000(see endpoints below) - Terminal WebSocket on
ws://host:3000/ws/terminal - Optional SSH service on
:22(controlled via environment inentrypoint.sh)
pnpm install
cp env.example .env
pnpm devBuild and run:
pnpm build && pnpm startAgent Server reads environment variables via dotenv. See env.example for the full set. Common variables:
# Server
PORT=3000
NODE_ENV=development
API_KEY=your-api-key-here # Required for protected endpoints
ALLOWED_ORIGINS=http://localhost:3000
# Claude (optional)
ANTHROPIC_API_KEY=your-anthropic-api-key-here
USE_CLAUDE_CREDENTIALS=false
# Redis (internal by default)
REDIS_URL=redis://127.0.0.1:6379
# SQLite path (defaults to /home/appuser/data/agent_ts.db)
DATABASE_PATH=/home/appuser/data/agent_ts.dbNotes:
- API authentication uses
Authorization: Bearer <API_KEY>. - A local Redis is started by the container’s
entrypoint.shunlessREDIS_URLpoints elsewhere. - Data persists to an on-disk SQLite database; you can mount
/home/appuseras a volume to retain state.
All protected endpoints require Authorization: Bearer <API_KEY>.
curl http://localhost:3000/healthResponse includes server version and a database connectivity flag.
GET /sessions– list sessions and metadataPOST /sessions– create a session
Example:
curl -X POST http://localhost:3000/sessions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "my-session-1",
"agent": "claude-code",
"cwd": "/home/appuser/workspaces",
"model": "claude-code"
}'Endpoint: POST /generate/v2 (SSE stream). Agent can be "claude-code" or "codex".
curl -N http://localhost:3000/generate/v2 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"session_id": "my-session-1",
"agent": "claude-code",
"prompt": "Add a REST endpoint that returns the current time",
"cwd": "/home/appuser/workspaces/project",
"model": "claude-code"
}'Background mode (returns a task id):
curl -X POST http://localhost:3000/generate/v2 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"session_id": "my-session-1",
"agent": "codex",
"prompt": "Create unit tests for utils/date.ts",
"background": true
}'
curl http://localhost:3000/generate/v2/jobs/<taskId> \
-H "Authorization: Bearer $API_KEY"
curl -N http://localhost:3000/generate/v2/jobs/<taskId>/stream \
-H "Authorization: Bearer $API_KEY"curl -X DELETE http://localhost:3000/generate/<sessionId>/stop \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"session_id": "<sessionId>"}'Check if environment variables exist (supports comma-separated names):
curl http://localhost:3000/env/OPENAI_API_KEY,ANTHROPIC_API_KEY \
-H "Authorization: Bearer $API_KEY"GET /git/repositories– discover repos under the workspace (incl. worktrees)GET /git/diff?path=/path/to/repo&base=main&head=HEAD&staged=true&context=3
curl "http://localhost:3000/git/diff?path=/home/appuser/workspaces/proj&staged=false" \
-H "Authorization: Bearer $API_KEY"- Request a short‑lived token:
curl -X POST http://localhost:3000/terminal/token \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"deploymentId":"local-dev","terminalId":"term-1"}'- Connect using the token:
# Example with websocat
websocat "ws://localhost:3000/ws/terminal?token=<JWT>"Messages are JSON with { type: "data" | "resize" | "close" | "error" | "info" }.
- SQLite via
better-sqlite3atDATABASE_PATH(default/home/appuser/data/agent_ts.db). WAL mode is enabled for concurrency. - Redis for lightweight locks and coordination. The container starts a local Redis unless
REDIS_URLis set.
pnpm install
pnpm build
pnpm startDatabase tooling:
pnpm db:generate # generate Drizzle migrations
pnpm db:migrate # apply migrations
pnpm db:migrate:custom # run custom migration runnerIntegration tests use Vitest and Testcontainers:
pnpm test:integrationThis repo publishes a container image to GitHub Container Registry via GitHub Actions. The workflow is defined in .github/workflows/docker-publish.yml and pushes tags for latest, semver tags, and the commit SHA.
To pull the latest image:
docker pull ghcr.io/suhjohn/agent-server:latestIssues and PRs are welcome. Please run pnpm lint and pnpm type-check before submitting changes.
This repository does not currently include a license file. Until a license is added, all rights are reserved.