Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
dist
.env
*.log
.git
36 changes: 36 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -- build stage --
FROM node:20-slim AS build

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src/ src/
RUN npm run build

# -- production stage --
FROM node:20-slim

# Build tools for node-pty native module
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential python3 git && \
rm -rf /var/lib/apt/lists/*

# Install agent CLIs globally
RUN npm install -g @anthropic-ai/claude-code @openai/codex

WORKDIR /app

COPY package*.json ./
RUN npm ci --omit=dev

COPY --from=build /app/dist/ dist/

# Workspace volume mount point
RUN mkdir -p /workspace
ENV WORKSPACE_DIR=/workspace

EXPOSE 8080
ENV PORT=8080

CMD ["node", "dist/index.js"]
69 changes: 62 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,70 @@ An MCP server (SSE transport) that lets any MCP client spawn and control [Codex
- Per-IP rate limiting and SSE connection caps
- Graceful shutdown with SIGTERM/SIGINT handling

## Prerequisites
## Deploy to Fly.io

If you'd rather run pokeclaw in the cloud instead of locally, you can deploy to [Fly.io](https://fly.io) in a few minutes.

### Prerequisites

- A [Fly.io account](https://fly.io/app/sign-up) (free tier works)
- [`flyctl` CLI](https://fly.io/docs/flyctl/install/) installed

### Quick start

```bash
# Clone and enter the repo
git clone https://github.com/meimakes/pokeclaw.git
cd pokeclaw

# Launch on Fly (creates the app + a persistent volume for /workspace)
fly launch --copy-config --yes

# Set your auth token (clients use this to connect)
fly secrets set AUTH_TOKEN=<pick-a-secret>

# Forward API keys for the agents you plan to use
# If using API keys instead of OAuth, forward them to child processes
fly secrets set CHILD_ENV_OPENAI_API_KEY=<your-openai-key> # optional, for Codex
fly secrets set CHILD_ENV_ANTHROPIC_API_KEY=<your-anthropic-key> # optional, for Claude Code

# Deploy
fly deploy
```

Your server will be available at `https://<app-name>.fly.dev`. Point your MCP client at:

```json
{
"mcpServers": {
"coding-agent": {
"url": "https://<app-name>.fly.dev/sse",
"headers": {
"Authorization": "Bearer <your-AUTH_TOKEN>"
}
}
}
}
```

### Notes

- **Persistent storage**: The `fly.toml` mounts a volume at `/workspace` so session data survives restarts. Fly creates the volume automatically on first deploy.
- **Region**: Defaults to `sjc` (San Jose). Change `primary_region` in `fly.toml` or pass `--region` to `fly launch`.
- **Scaling**: This is a stateful, single-instance service. The config uses `auto_stop_machines = "suspend"` to save costs when idle, and `auto_start_machines = true` to wake on incoming requests.
- **Agent CLIs**: The Dockerfile installs both `@anthropic-ai/claude-code` and `@openai/codex` globally. Sessions use `CHILD_ENV_*` secrets as API keys — `AUTH_TOKEN` is never forwarded to child processes.

## Local Setup

### Prerequisites

- Node.js 20+
- [`codex` CLI](https://github.com/openai/codex) installed globally (for Codex sessions): `npm install -g @openai/codex`
- [`claude` CLI](https://docs.anthropic.com/en/docs/claude-code/getting-started) installed globally (for Claude Code sessions): `npm install -g @anthropic-ai/claude-code`

Only the agent(s) you plan to use need to be installed. Claude Code requires OAuth login (`claude login`); Codex requires an `OPENAI_API_KEY`.
Only the agent(s) you plan to use need to be installed. Both require OAuth login (`claude login` / `codex login`).

## Setup
### Build

```bash
git clone https://github.com/meimakes/pokeclaw.git
Expand All @@ -43,7 +98,7 @@ npm install
npm run build
```

## Configuration
### Configuration

Set environment variables (or copy `.env.example` to `.env`):

Expand All @@ -58,7 +113,7 @@ Set environment variables (or copy `.env.example` to `.env`):
| `RATE_LIMIT_RPM` | No | `120` | Max requests per minute per IP on POST /messages |
| `CHILD_ENV_*` | No | — | Extra env vars forwarded to child processes (prefix stripped) |

## Running
### Running

```bash
# Production
Expand All @@ -68,7 +123,7 @@ AUTH_TOKEN=my-secret npm start
AUTH_TOKEN=my-secret npm run dev
```

## MCP Client Configuration
### MCP Client Configuration

Add to your MCP client config:

Expand Down Expand Up @@ -301,7 +356,7 @@ Ensure the `PATH` in your LaunchAgent or environment puts the desired version fi
### Sessions exit immediately with code 1

Check the session output via `session_output` — it includes the error message. Common causes:
- Missing API key (`OPENAI_API_KEY` for Codex, OAuth login for Claude Code)
- Missing credentials (OAuth login or API key not configured for the agent)
- CLI binary not found in `PATH`
- Working directory doesn't exist

Expand Down
26 changes: 26 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
app = "pokeclaw"
primary_region = "sjc"

[build]

[env]
PORT = "8080"
WORKSPACE_DIR = "/workspace"

[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = "suspend"
auto_start_machines = true
min_machines_running = 0

[[http_service.checks]]
grace_period = "10s"
interval = "30s"
method = "GET"
path = "/health"
timeout = "5s"

[mounts]
source = "workspace"
destination = "/workspace"
Loading