Skip to content
Closed
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
217 changes: 191 additions & 26 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,59 @@
# === Required ===

# GitHub Personal Access Token — needs public_repo scope at minimum
# IMPORTANT: must be a classic token (ghp_*). Fine-grained tokens (github_pat_*)
# cannot create PRs in other people's repos. See docs/quickstart.md.
GITHUB_TOKEN=ghp_your-token-here

# Choose models in provider/model format.
# Examples:
# - openai/gpt-4.1
# - openai/gpt-4.1-mini
# - openrouter/openai/gpt-4.1-mini
# - deepseek/deepseek-chat
# - minimax/MiniMax-M2.7
# - kimi/moonshot-v1-32k
CLAWOSS_PRIMARY_MODEL=openai/gpt-4.1
CLAWOSS_FALLBACK_MODEL=
CLAWOSS_SUBAGENT_MODEL=openai/gpt-4.1-mini
CLAWOSS_HEARTBEAT_MODEL=openai/gpt-4.1
CLAWOSS_AGENT_MODEL=openai/gpt-4.1

# Set the API key(s) for whichever provider(s) your selected models use.
OPENAI_API_KEY=sk-openai-your-key-here
OPENROUTER_API_KEY=
DEEPSEEK_API_KEY=
MINIMAX_API_KEY=
KIMI_API_KEY=

# Optional custom OpenAI-compatible endpoint.
CUSTOM_OPENAI_API_KEY=
CUSTOM_OPENAI_BASE_URL=
# === LLM Model Configuration ===
# See docs/model-routing.md for full provider examples (OpenAI, DeepSeek, MiniMax, etc.)
# See the "Provider Quick Reference" section at the bottom of this file.

# Provider name — becomes the OpenClaw provider block key and model ID prefix
LLM_PROVIDER=anthropic

# OpenAI-compatible API endpoint for this provider
LLM_BASE_URL=https://api.anthropic.com/v1

# API key for the provider above
LLM_API_KEY=sk-ant-your-key-here

# Complex model (Opus-tier) — used by implementation sub-agents (code writing, debugging)
LLM_MODEL_COMPLEX=claude-opus-4-6

# Simple model (Sonnet-tier) — used by orchestrator/heartbeat (routing, file reads)
LLM_MODEL_SIMPLE=claude-sonnet-4-6

# Cost per million tokens in USD (used for dashboard spend display).
# Per-model pricing — complex (Opus-tier) and simple (Sonnet-tier) can differ.
# If per-model vars are not set, INPUT_COST_PER_M / OUTPUT_COST_PER_M are used as fallback.
INPUT_COST_PER_M_COMPLEX=5.0 # Claude Opus 4.6 input ($5/M)
OUTPUT_COST_PER_M_COMPLEX=25.0 # Claude Opus 4.6 output ($25/M)
INPUT_COST_PER_M_SIMPLE=3.0 # Claude Sonnet 4.6 input ($3/M)
OUTPUT_COST_PER_M_SIMPLE=15.0 # Claude Sonnet 4.6 output ($15/M)
# Fallback if per-model vars are absent (set to your average expected price)
INPUT_COST_PER_M=3.0
OUTPUT_COST_PER_M=15.0

# Context window and max output tokens (model-specific)
LLM_CONTEXT_WINDOW=1000000
LLM_MAX_TOKENS=32000

# Public vars exposed to dashboard browser bundle (mirrors LLM_* above)
NEXT_PUBLIC_LLM_PROVIDER=anthropic
NEXT_PUBLIC_LLM_MODEL_COMPLEX=claude-opus-4-6
NEXT_PUBLIC_LLM_MODEL_SIMPLE=claude-sonnet-4-6

# === Budget Control ===
# Total cumulative spend cap in USD. Agent pauses when reached. 0 = unlimited.
BUDGET_USD_TOTAL=20.0

# Per-model token caps (JSON map). Keys are BARE model names — matched across
# all providers (e.g. `glm-4.6` covers `z-ai/glm-4.6`, `openrouter/glm-4.6`, etc).
# Value is total tokens (input + output). Missing key or value 0 = unlimited.
# When a model exceeds its cap, the agent stops using it AND a red banner shows
# at the top of the dashboard. See docs/model-routing.md.
# MODEL_TOKEN_BUDGETS={"glm-4.6":20000000,"deepseek-chat":50000000,"claude-opus-4-6":10000000}

# === Optional ===

Expand All @@ -42,8 +69,146 @@ DASHBOARD_URL=https://clawoss-dashboard.vercel.app
CLAW_API_KEY=your-shared-secret-here

# Override only if your clone lives outside the default detected path
CLAWOSS_ROOT=/absolute/path/to/ClawOSS
# CLAWOSS_ROOT=/absolute/path/to/ClawOSS

# Structured event logging for decision/outcome/reflection pipelines
# Structured event logging for decision/outcome/reflection pipelines (alpha)
CLAWOSS_RECORD_DECISIONS=1
CLAWOSS_RECORD_OUTCOMES=1

# === Legacy / Alpha compatibility (optional overrides) ===
# If set, these take priority over LLM_* above. Useful during the alpha
# transition when you want to pin a specific full model ID.
# CLAWOSS_PRIMARY_MODEL=anthropic/claude-opus-4-6
# CLAWOSS_SUBAGENT_MODEL=anthropic/claude-opus-4-6
# CLAWOSS_HEARTBEAT_MODEL=anthropic/claude-sonnet-4-6
# CLAWOSS_AGENT_MODEL=anthropic/claude-sonnet-4-6
# CLAWOSS_FALLBACK_MODEL=

# Legacy per-provider API keys (no longer required — use LLM_API_KEY above).
# Kept for historical alpha deployments.
# KIMI_API_KEY=sk-kimi-your-key-here
# MINIMAX_API_KEY=your-minimax-key-here

# =============================================================================
# Provider Quick Reference — copy the block you want and replace the defaults
# Prices: April 2026. Verify at provider docs before setting budget.
# =============================================================================

# ── Google Gemini ─────────────────────────────────────────────────────────────
# Docs: https://ai.google.dev/gemini-api/docs/pricing
# Uses OpenAI-compatible endpoint. 2.5 Pro >200k context doubles price.
# All models have free tier with limited requests.
#
# LLM_PROVIDER=google
# LLM_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai
# LLM_API_KEY=your-gemini-key
# LLM_MODEL_COMPLEX=gemini-2.5-pro
# LLM_MODEL_SIMPLE=gemini-2.5-flash
# INPUT_COST_PER_M_COMPLEX=1.25
# OUTPUT_COST_PER_M_COMPLEX=10.0
# INPUT_COST_PER_M_SIMPLE=0.30
# OUTPUT_COST_PER_M_SIMPLE=2.50
# LLM_CONTEXT_WINDOW=1000000
# LLM_MAX_TOKENS=65536
# NEXT_PUBLIC_LLM_PROVIDER=google
# NEXT_PUBLIC_LLM_MODEL_COMPLEX=gemini-2.5-pro
# NEXT_PUBLIC_LLM_MODEL_SIMPLE=gemini-2.5-flash

# ── Mistral AI ───────────────────────────────────────────────────────────────
# Docs: https://mistral.ai/pricing
# Large 3 for complex, Small 3.1 for orchestration. Nemo ($0.02/M) is cheapest.
#
# LLM_PROVIDER=mistral
# LLM_BASE_URL=https://api.mistral.ai/v1
# LLM_API_KEY=your-mistral-key
# LLM_MODEL_COMPLEX=mistral-large-3
# LLM_MODEL_SIMPLE=mistral-small-3.1
# INPUT_COST_PER_M_COMPLEX=2.0
# OUTPUT_COST_PER_M_COMPLEX=6.0
# INPUT_COST_PER_M_SIMPLE=0.20
# OUTPUT_COST_PER_M_SIMPLE=0.60
# LLM_CONTEXT_WINDOW=128000
# LLM_MAX_TOKENS=32000
# NEXT_PUBLIC_LLM_PROVIDER=mistral
# NEXT_PUBLIC_LLM_MODEL_COMPLEX=mistral-large-3
# NEXT_PUBLIC_LLM_MODEL_SIMPLE=mistral-small-3.1

# ── DeepSeek ──────────────────────────────────────────────────────────────────
# Docs: https://api-docs.deepseek.com/quick_start/pricing
# deepseek-chat = V3.2 non-thinking | deepseek-reasoner = V3.2 thinking mode
# Same price, reasoner supports 32K output vs 8K.
# Cache hit: $0.028/M input (90% off)
#
# LLM_PROVIDER=deepseek
# LLM_BASE_URL=https://api.deepseek.com/v1
# LLM_API_KEY=sk-your-deepseek-key
# LLM_MODEL_COMPLEX=deepseek-reasoner # thinking mode for complex tasks
# LLM_MODEL_SIMPLE=deepseek-chat # non-thinking for orchestration
# INPUT_COST_PER_M_COMPLEX=0.28
# OUTPUT_COST_PER_M_COMPLEX=0.42
# INPUT_COST_PER_M_SIMPLE=0.28
# OUTPUT_COST_PER_M_SIMPLE=0.42
# LLM_CONTEXT_WINDOW=128000
# LLM_MAX_TOKENS=32000
# NEXT_PUBLIC_LLM_PROVIDER=deepseek
# NEXT_PUBLIC_LLM_MODEL_COMPLEX=deepseek-reasoner
# NEXT_PUBLIC_LLM_MODEL_SIMPLE=deepseek-chat

# ── MiniMax ───────────────────────────────────────────────────────────────────
# Docs: https://platform.minimax.io/docs/guides/pricing-paygo
# highspeed variants are 2× price but lower latency
#
# LLM_PROVIDER=minimax
# LLM_BASE_URL=https://api.minimaxi.com/v1
# LLM_API_KEY=your-minimax-key
# LLM_MODEL_COMPLEX=MiniMax-M2.7
# LLM_MODEL_SIMPLE=MiniMax-M2.5
# INPUT_COST_PER_M_COMPLEX=0.30
# OUTPUT_COST_PER_M_COMPLEX=1.20
# INPUT_COST_PER_M_SIMPLE=0.30
# OUTPUT_COST_PER_M_SIMPLE=1.20
# LLM_CONTEXT_WINDOW=204800
# LLM_MAX_TOKENS=131072
# NEXT_PUBLIC_LLM_PROVIDER=minimax
# NEXT_PUBLIC_LLM_MODEL_COMPLEX=MiniMax-M2.7
# NEXT_PUBLIC_LLM_MODEL_SIMPLE=MiniMax-M2.5

# ── Kimi / Moonshot ───────────────────────────────────────────────────────────
# Docs: https://platform.kimi.ai/docs/pricing/chat
# kimi-k2.5 = latest coding model | moonshot-v1-32k = general purpose
# Cache hit: $0.10/M input (vs $0.60/M cache miss)
#
# LLM_PROVIDER=moonshot
# LLM_BASE_URL=https://api.moonshot.cn/v1
# LLM_API_KEY=sk-your-moonshot-key
# LLM_MODEL_COMPLEX=kimi-k2.5
# LLM_MODEL_SIMPLE=moonshot-v1-32k
# INPUT_COST_PER_M_COMPLEX=0.60
# OUTPUT_COST_PER_M_COMPLEX=3.00
# INPUT_COST_PER_M_SIMPLE=3.29
# OUTPUT_COST_PER_M_SIMPLE=3.29
# LLM_CONTEXT_WINDOW=131072
# LLM_MAX_TOKENS=32000
# NEXT_PUBLIC_LLM_PROVIDER=moonshot
# NEXT_PUBLIC_LLM_MODEL_COMPLEX=kimi-k2.5
# NEXT_PUBLIC_LLM_MODEL_SIMPLE=moonshot-v1-32k

# ── GLM / Zhipu AI (Z.AI) ─────────────────────────────────────────────────────
# Docs: https://docs.z.ai/guides/overview/pricing
# International endpoint: api.z.ai/v1 | China endpoint: open.bigmodel.cn/api/paas/v4
# glm-4.7-flash is FREE — useful as the simple/orchestrator model
#
# LLM_PROVIDER=z-ai
# LLM_BASE_URL=https://api.z.ai/v1
# LLM_API_KEY=your-zhipu-key
# LLM_MODEL_COMPLEX=glm-4.7 # $0.60/$2.20 per M
# LLM_MODEL_SIMPLE=glm-4.5-air # $0.20/$1.10 per M (or glm-4.7-flash for free)
# INPUT_COST_PER_M_COMPLEX=0.60
# OUTPUT_COST_PER_M_COMPLEX=2.20
# INPUT_COST_PER_M_SIMPLE=0.20
# OUTPUT_COST_PER_M_SIMPLE=1.10
# LLM_CONTEXT_WINDOW=128000
# LLM_MAX_TOKENS=32000
# NEXT_PUBLIC_LLM_PROVIDER=z-ai
# NEXT_PUBLIC_LLM_MODEL_COMPLEX=glm-4.7
# NEXT_PUBLIC_LLM_MODEL_SIMPLE=glm-4.5-air
87 changes: 87 additions & 0 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Smoke

# Minimal pre-merge gate for Phase-1 demo deployment. Runs on every PR to
# main or alpha/**. Kept intentionally small — if this goes red, the PR
# shouldn't merge. Heavier tests live in validate.yml.

on:
pull_request:
branches: [main, "alpha/**"]
push:
branches: [main, "alpha/**"]

jobs:
bash-scripts:
name: Bash script syntax
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Syntax-check every shell script
run: |
set -e
fail=0
while IFS= read -r -d '' f; do
if ! bash -n "$f"; then
echo "::error file=$f::bash -n failed"
fail=1
fi
done < <(find scripts deploy -type f -name '*.sh' -print0)
exit "$fail"

env-example-parses:
name: .env.example is a valid env file
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Source .env.example
run: |
# .env.example ships provider snippets commented out — sourcing it
# should succeed and should set the required LLM_* vars. This catches
# accidental stray "$(...)" expansions or unbalanced quotes before
# they reach a user's .env.
set -a
# shellcheck disable=SC1091
. ./.env.example
set +a
for v in LLM_PROVIDER LLM_BASE_URL LLM_MODEL_COMPLEX LLM_MODEL_SIMPLE; do
if [ -z "${!v:-}" ]; then
echo "::error::.env.example did not set $v"
exit 1
fi
done
echo "LLM_PROVIDER=$LLM_PROVIDER LLM_MODEL_COMPLEX=$LLM_MODEL_COMPLEX LLM_MODEL_SIMPLE=$LLM_MODEL_SIMPLE"

openclaw-json-substitutes:
name: openclaw.json template substitution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"

- name: Run validate-config.mjs
run: node scripts/validate-config.mjs || (echo "::error::validate-config.mjs failed" && exit 1)

docker-build:
name: Agent Docker image builds
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Build agent image (no push)
# The image pulls openclaw from npm and a few apt packages. We only
# care that the build graph succeeds — we do not run the container
# (that requires real LLM / GitHub credentials).
run: |
docker build \
-f deploy/docker/Dockerfile \
-t clawoss-agent:ci \
.

- name: Docker compose config lint
run: |
docker compose -f deploy/docker/docker-compose.yml config > /dev/null
12 changes: 8 additions & 4 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Validate

on:
push:
branches: [main]
branches: [main, "alpha/**"]
pull_request:
branches: [main]
branches: [main, "alpha/**"]

jobs:
validate-config:
Expand All @@ -17,8 +17,12 @@ jobs:
with:
node-version: "20"

- name: Validate openclaw.json
run: node -e "JSON.parse(require('fs').readFileSync('config/openclaw.json', 'utf8'))"
# openclaw.json uses __PLACEHOLDER__ tokens that are substituted by
# restart.sh / deploy/docker/entrypoint.sh. validate-config.mjs below
# runs the full post-substitution parse. This inline check just sanity-
# asserts the file exists and isn't empty.
- name: Ensure openclaw.json is present
run: test -s config/openclaw.json

- name: Validate cron-jobs.json
run: node -e "JSON.parse(require('fs').readFileSync('config/cron-jobs.json', 'utf8'))"
Expand Down
9 changes: 5 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ The quality of ClawOSS output is 100% determined by its prompts. When strategy c
- Review prompts regularly for cross-file consistency

## Model
- MiniMax M2.7 via direct API (`https://api.minimaxi.com/v1`)
- 204k context window, 131k max output
- Fallback: Kimi Code k2p5
- API key env var: `MINIMAX_API_KEY`
- Configured via env vars: `LLM_PROVIDER` / `LLM_MODEL_COMPLEX` / `LLM_MODEL_SIMPLE`
- Complex tasks (sub-agents): `LLM_MODEL_COMPLEX` (default: `anthropic/claude-opus-4-6`)
- Simple tasks (orchestrator/heartbeat): `LLM_MODEL_SIMPLE` (default: `anthropic/claude-sonnet-4-6`)
- API key: `LLM_API_KEY`; endpoint: `LLM_BASE_URL`
- See `docs/model-routing.md` for provider examples and budget config

## Common Commands
```bash
Expand Down
Loading
Loading