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
26 changes: 13 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
web_changed: ${{ steps.scope.outputs.web_changed }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0

Expand Down Expand Up @@ -92,10 +92,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
Expand All @@ -112,10 +112,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
Expand All @@ -134,10 +134,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
Expand All @@ -161,10 +161,10 @@ jobs:
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
Expand Down Expand Up @@ -206,10 +206,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
Expand All @@ -231,10 +231,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/deploy-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
Expand Down Expand Up @@ -73,7 +73,7 @@ jobs:
name: image-release
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
Expand Down
89 changes: 46 additions & 43 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ This guide covers the complete process for deploying Serverless OpenClaw on a cl

## 1. Prerequisites

| Item | Minimum Version | Verification Command |
|------|----------------|---------------------|
| AWS CLI | v2 | `aws --version` |
| AWS CDK CLI | v2.170+ | `npx cdk --version` |
| Node.js | v20+ | `node -v` |
| Docker | Latest | `docker --version` |
| npm | v9+ | `npm -v` |
| Item | Minimum Version | Verification Command |
| ----------- | --------------- | -------------------- |
| AWS CLI | v2 | `aws --version` |
| AWS CDK CLI | v2.170+ | `npx cdk --version` |
| Node.js | v22+ | `node -v` |
| Docker | Latest | `docker --version` |
| npm | v9+ | `npm -v` |

### AWS Account Setup

Expand Down Expand Up @@ -60,12 +60,12 @@ Secrets are managed by CDK via `SecretsStack`. On the first deploy, provide all

### Prepare Secret Values

| Parameter | How to Obtain |
|-----------|--------------|
| `BridgeAuthToken` | Random string: `openssl rand -hex 32` |
| `OpenclawGatewayToken` | Your OpenClaw Gateway token |
| `AnthropicApiKey` | Your Anthropic API key |
| `TelegramBotToken` | (Optional) Token from @BotFather |
| Parameter | How to Obtain |
| ----------------------- | --------------------------------------------------------------------------- |
| `BridgeAuthToken` | Random string: `openssl rand -hex 32` |
| `OpenclawGatewayToken` | Your OpenClaw Gateway token |
| `AnthropicApiKey` | Your Anthropic API key |
| `TelegramBotToken` | (Optional) Token from @BotFather |
| `TelegramWebhookSecret` | (Optional) Random string: `openssl rand -hex 32` (must **not** contain `:`) |

### When Using Telegram Bot (Optional)
Expand Down Expand Up @@ -258,16 +258,16 @@ aws cognito-idp admin-update-user-attributes \

Key values available from CDK Output:

| CDK Output | Purpose |
|------------|---------|
| `WebStack.WebAppUrl` | Web UI access URL |
| `WebStack.DistributionDomainName` | CloudFront domain |
| `ApiStack.WebSocketApiEndpoint` | WebSocket connection URL |
| `ApiStack.HttpApiEndpoint` | REST API + Telegram webhook URL |
| `AuthStack.UserPoolId` | Cognito User Pool ID |
| `AuthStack.UserPoolClientId` | Cognito App Client ID |
| `ComputeStack.ClusterArn` | ECS cluster ARN |
| `StorageStack.EcrRepositoryUri` | Docker image push target |
| CDK Output | Purpose |
| --------------------------------- | ------------------------------- |
| `WebStack.WebAppUrl` | Web UI access URL |
| `WebStack.DistributionDomainName` | CloudFront domain |
| `ApiStack.WebSocketApiEndpoint` | WebSocket connection URL |
| `ApiStack.HttpApiEndpoint` | REST API + Telegram webhook URL |
| `AuthStack.UserPoolId` | Cognito User Pool ID |
| `AuthStack.UserPoolClientId` | Cognito App Client ID |
| `ComputeStack.ClusterArn` | ECS cluster ARN |
| `StorageStack.EcrRepositoryUri` | Docker image push target |

### `.env.local` for Web UI Local Development

Expand All @@ -282,12 +282,12 @@ VITE_COGNITO_CLIENT_ID=<AuthStack.UserPoolClientId>

Set in `.env` or exported before running CDK commands.

| Variable | Default | Values | Purpose |
|----------|---------|--------|---------|
| `AGENT_RUNTIME` | `fargate` | `fargate` \| `lambda` \| `both` | Compute path selection |
| `AI_PROVIDER` | `anthropic` | `anthropic` \| `bedrock` | AI provider selection |
| `AI_MODEL` | _(provider default)_ | any model ID | Override default model |
| `DEPLOY_WEB` | `true` | `true` \| `false` | Include WebStack deployment |
| Variable | Default | Values | Purpose |
| --------------- | -------------------- | ------------------------------- | --------------------------- |
| `AGENT_RUNTIME` | `fargate` | `fargate` \| `lambda` \| `both` | Compute path selection |
| `AI_PROVIDER` | `anthropic` | `anthropic` \| `bedrock` | AI provider selection |
| `AI_MODEL` | _(provider default)_ | any model ID | Override default model |
| `DEPLOY_WEB` | `true` | `true` \| `false` | Include WebStack deployment |

---

Expand Down Expand Up @@ -383,11 +383,11 @@ npx cdk destroy --all --profile $AWS_PROFILE

The project currently runs with `AGENT_RUNTIME=both`, keeping both Lambda (primary) and Fargate (fallback) paths available. This allows gradual migration and instant rollback.

| Mode | Lambda Agent | Fargate | Use Case |
|------|-------------|---------|----------|
| `fargate` (default) | Skipped | Active | Original behavior, backward compatible |
| `lambda` | Active | Skipped | Lambda only, zero fixed cost |
| **`both`** | **Active (smart routing)** | **Active (reuse/fallback)** | **Current — smart routing based on task** |
| Mode | Lambda Agent | Fargate | Use Case |
| ------------------- | -------------------------- | --------------------------- | ----------------------------------------- |
| `fargate` (default) | Skipped | Active | Original behavior, backward compatible |
| `lambda` | Active | Skipped | Lambda only, zero fixed cost |
| **`both`** | **Active (smart routing)** | **Active (reuse/fallback)** | **Current — smart routing based on task** |

### Prerequisites

Expand Down Expand Up @@ -450,24 +450,25 @@ ComputeStack resources will be skipped. To rollback: set `AGENT_RUNTIME=fargate`

By default the system uses Anthropic (requires `AnthropicApiKey` in SecretsStack). Set `AI_PROVIDER=bedrock` to use Amazon Bedrock instead — no API key needed, authentication uses the Lambda execution role / Fargate task role via the AWS SDK default credential chain.

| Variable | Default | Description |
|----------|---------|-------------|
| `AI_PROVIDER` | `anthropic` | `anthropic` or `bedrock` |
| `AI_MODEL` | _(provider default)_ | Override model ID (optional) |
| Variable | Default | Description |
| ------------- | -------------------- | ---------------------------- |
| `AI_PROVIDER` | `anthropic` | `anthropic` or `bedrock` |
| `AI_MODEL` | _(provider default)_ | Override model ID (optional) |

**Default models:**

- Anthropic: `claude-sonnet-4-20250514`
- Bedrock: region-aware (see table below)

**Bedrock model selection — Cross-Region Inference (CRIS):**

The Bedrock model ID is derived automatically from `AWS_REGION` at runtime. Bedrock requires a geographic prefix to route requests within a compliance boundary:

| AWS Regions | Model ID used |
|-------------|---------------|
| `eu-*` | `eu.anthropic.claude-sonnet-4-20250514-v1:0` |
| `us-*`, `ca-*` | `us.anthropic.claude-sonnet-4-20250514-v1:0` |
| `ap-*` | `apac.anthropic.claude-sonnet-4-20250514-v1:0` |
| AWS Regions | Model ID used |
| ----------------- | ----------------------------------------------------- |
| `eu-*` | `eu.anthropic.claude-sonnet-4-20250514-v1:0` |
| `us-*`, `ca-*` | `us.anthropic.claude-sonnet-4-20250514-v1:0` |
| `ap-*` | `apac.anthropic.claude-sonnet-4-20250514-v1:0` |
| All other regions | `anthropic.claude-sonnet-4-20250514-v1:0` (no prefix) |

Set `AI_MODEL` to override automatic resolution (you are responsible for using the correct format). `bedrockDiscovery` is always disabled — model selection is explicit via `resolveBedrockModel()`.
Expand Down Expand Up @@ -520,6 +521,7 @@ aws logs tail /ecs/serverless-openclaw --follow --profile $AWS_PROFILE
```

**Common causes:**

- Image not pushed to ECR → build and push Docker image
- Insufficient SSM parameter access permissions → redeploy with CDK
- Insufficient memory → adjust `memoryLimitMiB` in `ComputeStack`
Expand All @@ -537,6 +539,7 @@ curl "https://api.telegram.org/bot<BOT_TOKEN>/getWebhookInfo"
```

**Common causes:**

- Webhook URL not registered → run `make telegram-webhook`
- Secret token mismatch (403 Forbidden) → run `make telegram-webhook` to re-register with SSM secret
- Lambda error → check CloudWatch logs for `telegram-webhook` function
54 changes: 27 additions & 27 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ This guide covers local development environment setup and workflows for contribu

### Required Tools

| Tool | Minimum Version | Purpose |
|------|----------------|---------|
| Node.js | v20+ | Runtime |
| npm | v9+ | Package manager (workspaces) |
| Docker | Latest | Container build/test |
| AWS CLI | v2 | CDK deployment, resource inspection |
| AWS CDK CLI | v2.170+ | Infrastructure deployment |
| Tool | Minimum Version | Purpose |
| ----------- | --------------- | ----------------------------------- |
| Node.js | v22+ | Runtime |
| npm | v9+ | Package manager (workspaces) |
| Docker | Latest | Container build/test |
| AWS CLI | v2 | CDK deployment, resource inspection |
| AWS CDK CLI | v2.170+ | Infrastructure deployment |

### Initial Setup

Expand Down Expand Up @@ -87,13 +87,13 @@ Managed as an npm workspaces monorepo + TypeScript project references. Inter-pac

## 3. Build Commands

| Command | Description |
|---------|-------------|
| `npm run build` | TypeScript build (`tsc --build`, all packages) |
| `npm run lint` | ESLint check (`packages/**/*.ts`) |
| `npm run format` | Prettier formatting |
| `npm run test` | Unit tests (vitest) |
| `npm run test:e2e` | E2E tests (vitest, `*.e2e.test.ts`) |
| Command | Description |
| ------------------ | ---------------------------------------------- |
| `npm run build` | TypeScript build (`tsc --build`, all packages) |
| `npm run lint` | ESLint check (`packages/**/*.ts`) |
| `npm run format` | Prettier formatting |
| `npm run test` | Unit tests (vitest) |
| `npm run test:e2e` | E2E tests (vitest, `*.e2e.test.ts`) |

### CDK Commands

Expand Down Expand Up @@ -188,17 +188,17 @@ npx vite dev # http://localhost:5173

Consists of 9 CDK stacks.

| Stack | Key Resources |
|-------|--------------|
| SecretsStack | SSM SecureString parameters (5 secrets) |
| NetworkStack | VPC, public subnets, VPC Gateway Endpoints, Security Group |
| StorageStack | 5 DynamoDB tables, S3, ECR |
| AuthStack | Cognito User Pool, App Client |
| ComputeStack | ECS cluster, Fargate Task Definition |
| Stack | Key Resources |
| ---------------- | ------------------------------------------------------------------ |
| SecretsStack | SSM SecureString parameters (5 secrets) |
| NetworkStack | VPC, public subnets, VPC Gateway Endpoints, Security Group |
| StorageStack | 5 DynamoDB tables, S3, ECR |
| AuthStack | Cognito User Pool, App Client |
| ComputeStack | ECS cluster, Fargate Task Definition |
| LambdaAgentStack | Lambda Container Image (DockerImageFunction, ARM64, 2048MB, 15min) |
| ApiStack | WebSocket API, HTTP API, 7 Lambda functions, EventBridge |
| WebStack | S3 (web assets), CloudFront (OAC) |
| MonitoringStack | CloudWatch Dashboard (6 rows, 10 custom metrics) |
| ApiStack | WebSocket API, HTTP API, 7 Lambda functions, EventBridge |
| WebStack | S3 (web assets), CloudFront (OAC) |
| MonitoringStack | CloudWatch Dashboard (6 rows, 10 custom metrics) |

**Dependencies:** SecretsStack + NetworkStack → StorageStack → {AuthStack, ComputeStack, LambdaAgentStack} → ApiStack → WebStack + MonitoringStack

Expand Down Expand Up @@ -232,10 +232,10 @@ npx vitest packages/gateway/__tests__/services/message.test.ts

Managed with husky and configured automatically.

| Hook | Execution | Purpose |
|------|-----------|---------|
| Hook | Execution | Purpose |
| ------------ | ----------------------------------------------- | --------------------------------------- |
| `pre-commit` | `npm run build && npm run lint && npm run test` | Ensure build, lint, and unit tests pass |
| `pre-push` | `npm run test:e2e` | Ensure E2E tests pass |
| `pre-push` | `npm run test:e2e` | Ensure E2E tests pass |

> You can bypass hooks with the `--no-verify` flag, but this is not recommended as it may cause CI failures.

Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"name": "serverless-openclaw",
"private": true,
"engines": {
"node": ">=22.0.0"
},
"workspaces": [
"packages/*"
],
Expand Down
15 changes: 7 additions & 8 deletions packages/cdk/lib/stacks/api-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ export class ApiStack extends cdk.Stack {
const bundlingDefaults = {
externalModules: ["@aws-sdk/*"],
sourceMap: true,
target: "node20",
target: "node22",
};

const nodejsFunctionDefaults = {
runtime: lambda.Runtime.NODEJS_20_X,
runtime: lambda.Runtime.NODEJS_22_X,
architecture: lambda.Architecture.ARM_64,
memorySize: 256,
timeout: cdk.Duration.seconds(30),
Expand Down Expand Up @@ -200,7 +200,10 @@ export class ApiStack extends cdk.Stack {
for (const fn of secretFunctions) {
fn.addEnvironment("SSM_BRIDGE_AUTH_TOKEN", SSM_SECRETS.BRIDGE_AUTH_TOKEN);
}
telegramWebhookFn.addEnvironment("SSM_TELEGRAM_SECRET_TOKEN", SSM_SECRETS.TELEGRAM_WEBHOOK_SECRET);
telegramWebhookFn.addEnvironment(
"SSM_TELEGRAM_SECRET_TOKEN",
SSM_SECRETS.TELEGRAM_WEBHOOK_SECRET,
);
telegramWebhookFn.addEnvironment("SSM_TELEGRAM_BOT_TOKEN", SSM_SECRETS.TELEGRAM_BOT_TOKEN);

// Grant SSM read access for secret resolution at runtime
Expand Down Expand Up @@ -247,11 +250,7 @@ export class ApiStack extends cdk.Stack {
for (const fn of containerFunctions) {
fn.addToRolePolicy(
new iam.PolicyStatement({
actions: [
"ecs:RunTask",
"ecs:StopTask",
"ecs:DescribeTasks",
],
actions: ["ecs:RunTask", "ecs:StopTask", "ecs:DescribeTasks"],
resources: ["*"],
}),
);
Expand Down
Loading