Independent .NET implementation of the OpenClaw agent runtime and gateway, built for deployable .NET services, a strong NativeAOT lane, optional MAF orchestration in the MAF-enabled artifacts, and practical compatibility with the JavaScript plugin ecosystem.
Disclaimer: This project is not affiliated with, endorsed by, or associated with OpenClaw. It is an independent implementation inspired by their work.
Most agent stacks still assume Python- or Node-first runtimes. That works until you want to keep the rest of your system in .NET, publish lean self-contained binaries, or reuse existing infrastructure without rebuilding your runtime assumptions around another language stack.
OpenClaw.NET takes a different path:
- .NET-first gateway and agent runtime with a real NativeAOT-friendly deployment lane
- practical reuse of OpenClaw JS/TS plugins through a JSON-RPC bridge instead of forcing rewrites
- explicit compatibility diagnostics instead of vague "mostly compatible" claims
- an optional Microsoft Agent Framework orchestrator path in the MAF-enabled artifacts while keeping the native runtime as the default
- a platform for production-oriented agent infrastructure in .NET: auth, policy, memory, channels, observability, and packaged deployment targets
If this repo is useful to you, star it.
- Gateway surfaces for HTTP, WebSocket, browser UI, webhooks, and OpenAI-compatible endpoints
- Gateway-hosted typed integration API under
/api/integration/*and a token-authenticated MCP JSON-RPC facade at/mcp - Agent runtime for tools, memory, sessions, skills, policy, approvals, and message pipeline execution
- Two runtime lanes: trim-safe
aotand broader-compatibilityjit - Two artifact families: standard artifacts plus MAF-enabled artifacts where
Runtime.Orchestrator=mafis optional - Built-in clients: browser UI at
/chat, CLI, and Avalonia desktop companion - Reusable library packages in-repo:
OpenClaw.Client,OpenClaw.Core,OpenClaw.PluginKit, andOpenClaw.SemanticKernelAdapter - Optional integrations for Telegram, Twilio SMS, WhatsApp, Semantic Kernel, the JS/TS plugin bridge, and the MAF adapter
OpenClaw.NET is focused on practical compatibility, especially around tools, skills, and the mainstream plugin path.
| Surface | Status on main after this merge |
Notes |
|---|---|---|
Standalone SKILL.md packages |
Supported | Run natively; no JS bridge required. |
| JS/TS tool plugins | Supported | Run through the Node bridge. |
| Trim-safe compatibility lane | Supported in aot |
Conservative deployment path. |
registerChannel() / registerCommand() / registerProvider() / api.on(...) |
Supported in jit |
Dynamic plugin surfaces are intentionally JIT-only. |
Runtime.Orchestrator=maf |
Supported in MAF-enabled artifacts | native remains the default orchestrator everywhere. |
| Unsupported plugin/runtime capabilities | Rejected explicitly | The gateway fails fast with compatibility diagnostics instead of partially loading the plugin. |
The goal is not full upstream extension-host parity. The goal is a clear, dependable compatibility contract with honest failure modes.
For the exact compatibility matrix, see docs/COMPATIBILITY.md.
OpenClaw.NET now has two related selectors:
Runtime.Mode:aot,jit, orautoRuntime.Orchestrator:nativeeverywhere, ormafonly in the MAF-enabled artifacts
In practice:
aotkeeps the trim-safe, lower-memory lanejitenables the broader dynamic/plugin compatibility laneautochooses betweenaotandjitbased on runtime capabilitiesnativeremains the default orchestrator even in MAF-enabled artifacts
OpenClaw.NET can optionally route high-risk native tools through OpenSandbox instead of executing them on the gateway host.
Current scope:
shellcode_execbrowser
Key points:
- sandbox routing is enabled by default in the shipped gateway config
- the standard runtime artifact does not include the OpenSandbox integration package
- the sandbox-enabled build is produced with
-p:OpenClawEnableOpenSandbox=true Prefermode falls back to local execution if the provider is unavailableRequiremode fails closed and is the recommended public-bind setting forshell- set
OpenClaw:Sandbox:Provider=Noneto force all sandbox-capable tools back to local execution
Example:
"OpenClaw": {
"Sandbox": {
"Provider": "OpenSandbox",
"Endpoint": "http://localhost:5000",
"ApiKey": "env:OPEN_SANDBOX_API_KEY",
"DefaultTTL": 300,
"Tools": {
"shell": {
"Mode": "Prefer",
"Template": "alpine:3.20",
"TTL": 300
},
"code_exec": {
"Mode": "Prefer",
"Template": "nikolaik/python-nodejs:python3.12-nodejs22-slim",
"TTL": 300
},
"browser": {
"Mode": "Prefer",
"Template": "mcr.microsoft.com/playwright:v1.52.0-noble",
"TTL": 600
}
}
}
}These are starter image choices. For public or production deployments, promote tools like shell to Require and replace the image URIs with images you control.
See docs/sandboxing.md for the architecture, build flag, local-switch behavior, and full config examples.
- Quickstart Guide
- User Guide
- Tool Guide
- Security Guide
- Plugin Compatibility Guide
- Semantic Kernel Guide
- Plugin Compatibility Guide
- Semantic Kernel Guide
- Sandboxing Guide
- MAF Readiness Notes
- Startup Architecture Notes
- Changelog
- Docker Image Notes
Published container images:
ghcr.io/clawdotnet/openclaw.net:latesttellikoroma/openclaw.net:latestpublic.ecr.aws/u6i5b9b7/openclaw.net:latest
OpenClaw.NET separates gateway startup and runtime composition into explicit layers instead of a single startup path.
Startup flow:
Bootstrap/
- Loads config, resolves runtime mode and orchestrator, applies validation and hardening, and handles early exits such as
--doctor.
Composition/andProfiles/
- Registers services and applies the effective runtime lane:
aotfor trim-safe deployments orjitfor expanded compatibility.
Pipeline/andEndpoints/
- Wires middleware, channel startup, workers, shutdown handling, and the grouped HTTP/WebSocket surfaces.
Runtime flow:
- The Gateway handles HTTP, WebSocket, webhook, auth, policy, and observability concerns.
- The Agent Runtime owns reasoning, tool execution, memory interaction, and skill loading.
- Native tools run in-process.
- JS/TS plugins run through the Node.js bridge, with capability enforcement depending on the effective runtime lane.
- The optional MAF adapter swaps orchestration strategy inside the MAF-enabled artifacts; it does not replace the gateway/runtime ownership model.
- Pure
SKILL.mdpackages remain independent of the plugin bridge.
graph TD
Client[Web UI / CLI / Companion / WebSocket Client] <--> Gateway[Gateway]
Webhooks[Telegram / Twilio / WhatsApp / Generic Webhooks] --> Gateway
subgraph Startup
Bootstrap[Bootstrap]
Composition[Composition]
Profiles[Runtime Profiles]
Pipeline[Pipeline + Endpoints]
Bootstrap --> Composition --> Profiles --> Pipeline
end
subgraph Runtime
Gateway <--> Agent[Agent Runtime]
Agent <--> Tools[Native Tools]
Agent <--> Memory[(Memory + Sessions)]
Agent <-->|Provider API| LLM{LLM Provider}
Agent <-->|Bridge transport| Bridge[Node.js Plugin Bridge]
Bridge <--> JSPlugins[TS / JS Plugins]
end
Runtime lanes:
OpenClaw:Runtime:Mode="aot"keeps the trim-safe, low-memory lane.OpenClaw:Runtime:Mode="jit"enables expanded bridge surfaces and native dynamic plugins.OpenClaw:Runtime:Mode="auto"selectsjitwhen dynamic code is available andaototherwise.
For the full startup-module breakdown, see docs/architecture-startup-refactor.md.
See docs/QUICKSTART.md for the fastest path from zero to a running gateway.
The shortest local path is:
- Set your API key:
export MODEL_PROVIDER_KEY="..."- Optional workspace:
export OPENCLAW_WORKSPACE="$PWD/workspace" - Optional runtime selection:
export OpenClaw__Runtime__Mode="jit"
- Run the gateway:
dotnet run --project src/OpenClaw.Gateway -c Release- Or validate config first:
dotnet run --project src/OpenClaw.Gateway -c Release -- --doctor - Optional config file:
dotnet run --project src/OpenClaw.Gateway -c Release -- --config ~/.openclaw/config.json
- Use one of the built-in clients:
- Web UI:
http://127.0.0.1:18789/chat - WebSocket endpoint:
ws://127.0.0.1:18789/ws - Integration status:
http://127.0.0.1:18789/api/integration/status - MCP endpoint:
http://127.0.0.1:18789/mcp - CLI:
dotnet run --project src/OpenClaw.Cli -c Release -- chat - Companion app:
dotnet run --project src/OpenClaw.Companion -c Release
Environment variables for the CLI:
OPENCLAW_BASE_URL(defaulthttp://127.0.0.1:18789)OPENCLAW_AUTH_TOKEN(only required when the gateway enforces auth)
For advanced provider setup, webhook channels, and deployment hardening, see the User Guide and Security Guide.
Common local usage paths:
- Browser UI: start the gateway and open
http://127.0.0.1:18789/chat - CLI chat:
dotnet run --project src/OpenClaw.Cli -c Release -- chat - One-shot CLI run:
dotnet run --project src/OpenClaw.Cli -c Release -- run "summarize this README" --file ./README.md - Desktop companion:
dotnet run --project src/OpenClaw.Companion -c Release - Typed integration API:
curl http://127.0.0.1:18789/api/integration/status - MCP JSON-RPC:
POST http://127.0.0.1:18789/mcp - Doctor/report mode:
dotnet run --project src/OpenClaw.Gateway -c Release -- --doctor
Common runtime choices:
- Use
aotwhen you want the trim-safe mainstream lane. - Use
jitwhen you need expanded plugin compatibility or native dynamic plugins. - Leave
autoif you want the artifact to choose based on dynamic-code support.
The most practical local setup is:
- Web UI or Companion for interactive usage
- CLI for scripting and automation
OpenClaw.Clientwhen you want typed .NET access to the integration API or MCP surface--doctorbefore exposing a public bind or enabling plugins
The gateway now exposes three complementary remote surfaces:
/v1/*for OpenAI-compatible clients/api/integration/*for stable typed operational reads and message enqueueing/mcpfor a gateway-hosted MCP JSON-RPC facade over the same integration/runtime data
The typed integration API currently covers status, dashboard, approvals, approval history, providers, plugins, operator audit, sessions, session timelines, runtime events, and inbound message enqueueing.
The MCP facade currently supports:
initializetools/listandtools/callresources/list,resources/templates/list, andresources/readprompts/listandprompts/get
The shared OpenClaw.Client package now exposes matching .NET methods for both the typed integration API and the MCP surface.
Example:
using System.Text.Json;
using OpenClaw.Client;
using OpenClaw.Core.Models;
using var client = new OpenClawHttpClient("http://127.0.0.1:18789", authToken: null);
var dashboard = await client.GetIntegrationDashboardAsync(CancellationToken.None);
var initialize = await client.InitializeMcpAsync(
new McpInitializeRequest { ProtocolVersion = "2025-03-26" },
CancellationToken.None);
using var emptyArguments = JsonDocument.Parse("{}");
var statusTool = await client.CallMcpToolAsync(
"openclaw.get_status",
emptyArguments.RootElement.Clone(),
CancellationToken.None);When the gateway enforces auth, use Authorization: Bearer <token> for /api/integration/* and /mcp just like the other non-loopback client surfaces.
Run the cross-platform desktop companion:
dotnet run --project src/OpenClaw.Companion -c Release
Notes:
- For non-loopback binds, set
OPENCLAW_AUTH_TOKENon the gateway and enter the same token in the companion app. - If you enable “Remember”, the token is saved to
settings.jsonunder your OS application data directory.
The gateway supports both:
- Client sends: raw UTF-8 text
- Server replies: raw UTF-8 text
If the client sends JSON shaped like this, the gateway replies with JSON:
Client → Server:
{ "type": "user_message", "text": "hello", "messageId": "optional", "replyToMessageId": "optional" }Server → Client:
{ "type": "assistant_message", "text": "hi", "inReplyToMessageId": "optional" }If OpenClaw:BindAddress is not loopback (e.g. 0.0.0.0), you must set OpenClaw:AuthToken / OPENCLAW_AUTH_TOKEN.
Preferred client auth:
Authorization: Bearer <token>
Optional legacy auth (disabled by default):
?token=<token>whenOpenClaw:Security:AllowQueryStringToken=true
Built-in WebChat auth behavior:
- The
/chatUI connects to/wsusing?token=<token>from the Auth Token field. - For Internet-facing/non-loopback binds, set
OpenClaw:Security:AllowQueryStringToken=trueif you use the built-in WebChat. - Tokens are stored in
sessionStorageby default. Enabling Remember also storesopenclaw_tokeninlocalStorage.
You can run TLS either:
- Behind a reverse proxy (recommended): nginx / Caddy / Cloudflare, forwarding to
http://127.0.0.1:18789 - Directly in Kestrel: configure HTTPS endpoints/certs via standard ASP.NET Core configuration
If you enable OpenClaw:Security:TrustForwardedHeaders=true, set OpenClaw:Security:KnownProxies to the IPs of your reverse proxies.
When binding to a non-loopback address, the gateway refuses to start unless you explicitly harden (or opt in to) the most dangerous settings:
- Wildcard tooling roots (
AllowedReadRoots=["*"],AllowedWriteRoots=["*"]) OpenClaw:Tooling:AllowShell=trueOpenClaw:Plugins:Enabled=trueorOpenClaw:Plugins:DynamicNative:Enabled=true(third-party plugin execution)- WhatsApp official webhooks without signature validation (
ValidateSignature=true+WebhookAppSecretRefrequired) - WhatsApp bridge webhooks without a bridge token (
BridgeTokenRef/BridgeTokenrequired) raw:secret refs (to reduce accidental secret commits)
To override (not recommended), set:
OpenClaw:Security:AllowUnsafeToolingOnPublicBind=trueOpenClaw:Security:AllowPluginBridgeOnPublicBind=trueOpenClaw:Security:AllowRawSecretRefsOnPublicBind=true
This project includes local tools (shell, read_file, write_file). If you expose the gateway publicly, strongly consider restricting:
OpenClaw:Tooling:AllowShell=falseOpenClaw:Tooling:AllowedReadRoots/AllowedWriteRootsto specific directories
If you are connecting from a browser-based client hosted on a different origin, configure:
OpenClaw:Security:AllowedOrigins=["https://your-ui-host"]
If AllowedOrigins is not configured and the client sends an Origin header, the gateway requires same-origin.
OpenClaw.NET now exposes two explicit runtime lanes:
OpenClaw:Runtime:Mode="aot"keeps the low-memory, trim-safe lane. Supported plugin capabilities here areregisterTool(),registerService(), plugin-packaged skills, and the supported manifest/config subset.OpenClaw:Runtime:Mode="jit"enables the expanded compatibility lane. In this mode the bridge also supportsregisterChannel(),registerCommand(),registerProvider(), andapi.on(...), and the gateway can load JIT-only in-process native dynamic plugins.
Pure ClawHub SKILL.md packages are independent of the bridge and remain the most plug-and-play compatibility path.
When you enable OpenClaw:Plugins:Enabled=true, the Gateway spawns a Node.js JSON-RPC bridge. When you enable OpenClaw:Plugins:DynamicNative:Enabled=true, the gateway also loads JIT-only in-process .NET plugins through the native dynamic host.
Across both lanes, unsupported surfaces fail fast with explicit diagnostics instead of silently degrading:
registerGatewayMethod()registerCli()- any JIT-only capability when the effective runtime mode is
aot
The /doctor report includes per-plugin load diagnostics, and the repo now includes hermetic bridge tests plus a pinned public smoke manifest for mainstream packages. For the exact matrix and TypeScript requirements such as jiti, see Plugin Compatibility Guide.
OpenClaw.NET is not a replacement for Semantic Kernel. If you're already using Microsoft.SemanticKernel, OpenClaw can act as the production gateway/runtime host (auth, rate limits, channels, OTEL, policy) around your SK code.
Supported integration patterns today:
- Wrap your SK orchestration as an OpenClaw tool: keep SK in-process, expose a single "entrypoint" tool the OpenClaw agent can call.
- Host SK-based agents behind the OpenClaw gateway: use OpenClaw for Internet-facing concerns (WebSocket,
/v1/*, Telegram/Twilio/WhatsApp), while your SK logic stays in your app/tool layer.
More details and AOT/trimming notes: see docs/SEMANTIC_KERNEL.md.
Conceptual example (tool wrapper):
// Your tool can instantiate and call Semantic Kernel. OpenClaw policies still apply
// to *when* this tool runs, who can call it, and how often.
public sealed class SemanticKernelTool : ITool
{
public string Name => "sk_example";
public string Description => "Example SK-backed tool.";
public string ParameterSchema => "{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"}},\"required\":[\"text\"]}";
public async ValueTask<string> ExecuteAsync(string argumentsJson, CancellationToken ct)
{
// Parse argsJson, then run SK here (Kernel builder + plugin invocation).
throw new NotImplementedException();
}
}Notes:
- NativeAOT: Semantic Kernel usage may require additional trimming/reflection configuration. Keep SK interop optional so the core gateway/runtime remains NativeAOT-friendly.
Available:
src/OpenClaw.SemanticKernelAdapter— optional adapter library that exposes SK functions as OpenClaw tools.samples/OpenClaw.SemanticKernelInteropHost— runnable sample host demonstrating/v1/responseswithout requiring external LLM access.
- Create a Telegram Bot via BotFather and obtain the Bot Token.
- Set the auth token as an environment variable:
export TELEGRAM_BOT_TOKEN="..."
- Configure
OpenClaw:Channels:Telegraminsrc/OpenClaw.Gateway/appsettings.json:Enabled=trueBotTokenRef="env:TELEGRAM_BOT_TOKEN"MaxRequestBytes=65536(default; inbound webhook body cap)
Register your public webhook URL directly with Telegram's API:
POST https://api.telegram.org/bot<your-bot-token>/setWebhook?url=https://<your-public-host>/telegram/inbound
Notes:
- The inbound webhook path is configurable via
OpenClaw:Channels:Telegram:WebhookPath(default:/telegram/inbound). AllowedFromUserIdscurrently checks the numericchat.idvalue from Telegram updates (not thefrom.iduser id).
- Create a Twilio Messaging Service (recommended) or buy a Twilio phone number.
- Set the auth token as an environment variable:
export TWILIO_AUTH_TOKEN="..."
- Configure
OpenClaw:Channels:Sms:Twilioinsrc/OpenClaw.Gateway/appsettings.json:Enabled=trueAccountSid=...AuthTokenRef="env:TWILIO_AUTH_TOKEN"MessagingServiceSid=...(preferred) orFromNumber="+1..."(fallback)AllowedFromNumbers=[ "+1YOUR_MOBILE" ]AllowedToNumbers=[ "+1YOUR_TWILIO_NUMBER" ]WebhookPublicBaseUrl="https://<your-public-host>"(required whenValidateSignature=true)MaxRequestBytes=65536(default; inbound webhook body cap)
Point Twilio’s inbound SMS webhook to:
POST https://<your-public-host>/twilio/sms/inbound
Recommended exposure options:
- Reverse proxy with TLS
- Cloudflare Tunnel
- Tailscale funnel / reverse proxy
- Keep
ValidateSignature=true - Use strict allowlists (
AllowedFromNumbers,AllowedToNumbers) - Do not set
AuthTokenReftoraw:...outside local development
Inbound webhook payloads are hard-capped before parsing. Configure these limits as needed:
OpenClaw:Channels:Sms:Twilio:MaxRequestBytes(default65536)OpenClaw:Channels:Telegram:MaxRequestBytes(default65536)OpenClaw:Channels:WhatsApp:MaxRequestBytes(default65536)OpenClaw:Webhooks:Endpoints:<name>:MaxRequestBytes(default131072)
For generic /webhooks/{name} endpoints, MaxBodyLength still controls prompt truncation after request-size validation.
If ValidateHmac=true, Secret is required; startup validation fails otherwise.
- Set required environment variables:
Bash / Zsh:
export MODEL_PROVIDER_KEY="sk-..."
export OPENCLAW_AUTH_TOKEN="$(openssl rand -hex 32)"PowerShell:
$env:MODEL_PROVIDER_KEY = "sk-..."
$env:OPENCLAW_AUTH_TOKEN = [Convert]::ToHexString((1..32 | Array { Get-Random -Min 0 -Max 256 }))
$env:EMAIL_PASSWORD = "..." # (Optional) For email toolNote: For the built-in WebChat UI (
http://<ip>:18789/chat), enter this exactOPENCLAW_AUTH_TOKENvalue in the "Auth Token" field. WebChat connects with a query token (?token=), so on non-loopback binds you must also setOpenClaw:Security:AllowQueryStringToken=true. Tokens are session-scoped by default; check Remember to persist across browser restarts. If you enable the Email Tool, setEMAIL_PASSWORDsimilarly.
docker compose up -d openclaw
export OPENCLAW_DOMAIN="openclaw.example.com" docker compose --profile with-tls up -d
### Build from source
```bash
docker build -t openclaw.net .
docker run -d -p 18789:18789 \
-e MODEL_PROVIDER_KEY="sk-..." \
-e OPENCLAW_AUTH_TOKEN="change-me" \
-v openclaw-memory:/app/memory \
openclaw.net
OpenClaw ships with native as the default orchestrator. Microsoft Agent Framework (MAF) is supported as an optional backend only in the MAF-enabled build artifacts.
Runtime selection:
{
"OpenClaw": {
"Runtime": {
"Mode": "auto|jit|aot",
"Orchestrator": "native|maf"
}
}
}- Standard artifacts support
Runtime.Orchestrator=nativeonly and fail fast ifmafis configured. - MAF-enabled artifacts support both
nativeandmaf. Runtime.Mode=autobehavior is unchanged.nativeremains the default even in MAF-enabled artifacts.
Publish the supported artifact set with:
bash eng/publish-gateway-artifacts.shThis produces:
artifacts/releases/gateway-standard-jitartifacts/releases/gateway-maf-enabled-jitartifacts/releases/gateway-standard-aotartifacts/releases/gateway-maf-enabled-aot
MAF is still a prerelease dependency, so the MAF-enabled artifacts should be versioned and rolled out deliberately even though the backend is feature-complete in this repository.
The same multi-arch image is published to:
ghcr.io/clawdotnet/openclaw.net:latesttellikoroma/openclaw.net:latestpublic.ecr.aws/u6i5b9b7/openclaw.net:latest
Example pull:
docker pull ghcr.io/clawdotnet/openclaw.net:latestMulti-arch push (recommended):
docker buildx build --platform linux/amd64,linux/arm64 \
-t ghcr.io/clawdotnet/openclaw.net:latest \
-t ghcr.io/clawdotnet/openclaw.net:<version> \
-t tellikoroma/openclaw.net:latest \
-t tellikoroma/openclaw.net:<version> \
-t public.ecr.aws/u6i5b9b7/openclaw.net:latest \
-t public.ecr.aws/u6i5b9b7/openclaw.net:<version> \
--push .The Dockerfile uses a multi-stage build:
- Build stage — full .NET SDK, runs tests, publishes NativeAOT binary
- Runtime stage — Ubuntu Chiseled (distroless), ~23 MB NativeAOT binary, non-root user
| Path | Purpose |
|---|---|
/app/memory |
Session history + memory notes (persist across restarts) |
/app/workspace |
Mounted workspace for file tools (optional) |
- Set
OPENCLAW_AUTH_TOKENto a strong random value - Set
MODEL_PROVIDER_KEYvia environment variable (never in config files) - Use
appsettings.Production.json(AllowShell=false, restricted roots) - Enable TLS (reverse proxy or Kestrel HTTPS)
- Set
AllowedOriginsif serving a web frontend - Set
TrustForwardedHeaders=true+KnownProxiesif behind a proxy - Set
MaxConnectionsPerIpandMessagesPerMinutePerConnectionfor rate limiting - Set
OpenClaw:SessionRateLimitPerMinuteto rate limit inbound messages (also applies to/v1/*OpenAI-compatible endpoints) - Monitor
/healthand/metricsendpoints - Pin a specific Docker image tag (not
:latest) in production
The included docker-compose.yml has a Caddy service with automatic HTTPS:
export OPENCLAW_DOMAIN="openclaw.example.com"
docker compose --profile with-tls up -dCaddy auto-provisions Let's Encrypt certificates. Edit deploy/Caddyfile to customize.
If you want the gateway to trust X-Forwarded-* headers from your proxy, set:
OpenClaw__Security__TrustForwardedHeaders=trueOpenClaw__Security__KnownProxies__0=<your-proxy-ip>
server {
listen 443 ssl http2;
server_name openclaw.example.com;
ssl_certificate /etc/letsencrypt/live/openclaw.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/openclaw.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:18789;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Configure directly in appsettings.json:
{
"Kestrel": {
"Endpoints": {
"Https": {
"Url": "https://0.0.0.0:443",
"Certificate": {
"Path": "/certs/cert.pfx",
"Password": "env:CERT_PASSWORD"
}
}
}
}
}OpenClaw now supports a background retention sweeper for persisted sessions + branches.
- Default is off:
OpenClaw:Memory:Retention:Enabled=false - Expired items are archived as raw JSON before delete
- Default TTLs: sessions
30days, branches14days - Default archive retention:
30days
Example config:
{
"OpenClaw": {
"Memory": {
"Retention": {
"Enabled": true,
"RunOnStartup": true,
"SweepIntervalMinutes": 30,
"SessionTtlDays": 30,
"BranchTtlDays": 14,
"ArchiveEnabled": true,
"ArchivePath": "./memory/archive",
"ArchiveRetentionDays": 30,
"MaxItemsPerSweep": 1000
}
}
}
}Recommended rollout:
- Run a dry-run first:
POST /memory/retention/sweep?dryRun=true - Review
GET /memory/retention/statusand/doctor/text - Confirm archive path sizing and filesystem permissions
Compaction remains disabled by default. If enabling compaction, CompactionThreshold must be greater than MaxHistoryTurns.
OpenClaw natively integrates with OpenTelemetry, providing deep insights into agent reasoning, tool execution, and session lifecycles.
| Endpoint | Auth | Description |
|---|---|---|
GET /health |
Token (if non-loopback) | Basic health check ({ status, uptime }) |
GET /metrics |
Token (if non-loopback) | Runtime counters (requests, tokens, tool calls, circuit breaker state, retention runs/outcomes) |
GET /memory/retention/status |
Token (if non-loopback) | Retention config + last run state + persisted session/branch counts |
| `POST /memory/retention/sweep?dryRun=true | false` | Token (if non-loopback) |
All agent operations emit structured logs and .NET Activity traces with correlation IDs. You can export these to OTLP collectors like Jaeger, Prometheus, or Grafana:
[abc123def456] Turn start session=ws:user1 channel=websocket
[abc123def456] Tool browser completed in 1250ms ok=True
[abc123def456] Turn complete: Turn[abc123def456] session=ws:user1 llm=2 retries=0 tokens=150in/80out tools=1
Set log levels in config:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"AgentRuntime": "Debug",
"SessionManager": "Information"
}
}
}GitHub Actions workflow (.github/workflows/ci.yml):
- On push/PR to main: build + test both the standard and MAF-enabled gateway/test targets
- On push to main: publish and upload
gateway-standard-{jit|aot}plusgateway-maf-enabled-{jit|aot}gateway artifacts - On push to main: publish NativeAOT CLI artifact + Docker image to GitHub Container Registry
Looking for:
- Security review
- NativeAOT trimming improvements
- Tool sandboxing ideas
- Performance benchmarks
If this aligns with your interests, open an issue.
⭐ If this project helps your .NET AI work, consider starring it.
