Wrap, Don't Fork: Building a SaaS on Stock Open Source
KiwiClaw runs stock OpenClaw Docker images. Zero code changes. Every tenant gets the exact same ghcr.io/openclaw/openclaw:latest image that anyone can pull from GitHub Container Registry. Our entire product -- auth, billing, LLM routing, compliance, team features -- is a management layer built around that stock image. About 12,000 lines of TypeScript that never touch the OpenClaw codebase.
This is a deliberate architectural decision, not a shortcut. Every other approach we considered involved modifying the upstream code, and every one of those approaches had the same fatal flaw: you become a fork maintainer.
The Fork Tax
OpenClaw moves fast. The project has over 180,000 GitHub stars, an active core team (now backed by OpenAI), and frequent releases that add features, fix bugs, and patch security vulnerabilities. In early 2026 alone, there were multiple critical CVEs including CVE-2026-25253, which exposed over 40,000 self-hosted instances to remote code execution.
When you fork, you pay a tax on every upstream release:
- Security patches must be manually merged into your fork. If you modified the affected code, the merge may conflict. You cannot just apply the patch and deploy. You must read, understand, test, and validate the fix against your modifications.
- New features must be rebased onto your changes. Feature branches in the upstream may refactor code you modified, turning a simple merge into a multi-day effort.
- Breaking changes in configuration, APIs, or internal architecture require expensive adaptation. Your fork's deviations compound with every upstream change.
- Testing multiplies. You cannot rely on upstream CI since your code is different. You need your own test suite for your modifications and regression tests to verify that upstream changes do not break your patches.
This tax compounds over time. Each month, the fork diverges further. Each merge becomes harder. Engineers who wrote the original patches leave. Context is lost. Eventually, you are maintaining your own fork of a fast-moving open-source project, and "fast-moving" means the tax bills come frequently.
The Wrapping Architecture
Instead of modifying OpenClaw, we built four services around it:
Cloudflare DNS (*.kiwiclaw.app)
|
v
Dashboard (Next.js 15 on Vercel)
| Auth (Clerk), Billing (Stripe), Agent UI
|
v
Orchestrator (Node.js on Fly.io)
| Fly Machines API, config injection, WS/HTTP proxy
|
+--- Tenant Machine (stock OpenClaw Docker image)
| Config delivered via env vars + boot script
|
v
LLM Proxy (Node.js on Fly.io internal network)
| JWT auth, usage caps, model routing
|
v
Upstream LLM APIs (Moonshot, Anthropic)
Total custom code: ~12,000 lines of TypeScript across four packages. Zero lines in the OpenClaw codebase.
How Config Injection Works
OpenClaw's configuration is a JSON file that controls LLM provider settings, gateway auth, browser automation, agent defaults, and sandbox mode. We generate this config per tenant and deliver it as a base64-encoded environment variable:
function generateManagedConfig(tenantSlug: string): OpenClawConfig {
return {
models: {
mode: "replace",
providers: {
moonshot: {
baseUrl: "http://kiwiclaw-llm-proxy.internal:8080/v1/moonshot/v1",
api: "openai-completions",
apiKey: "${KIWICLAW_PROXY_TOKEN}", // resolved by OpenClaw at runtime
models: [{ id: "kimi-k2.5", name: "Auto (Kimi K2.5)" }],
},
anthropic: {
baseUrl: "http://kiwiclaw-llm-proxy.internal:8080/v1/anthropic",
api: "anthropic-messages",
apiKey: "${KIWICLAW_PROXY_TOKEN}",
models: [{ id: "claude-opus-4-6", name: "MAX (Opus 4.6)" }],
},
},
},
gateway: {
controlUi: {
allowedOrigins: [
`https://${tenantSlug}.kiwiclaw.app`,
"https://app.kiwiclaw.app",
],
dangerouslyDisableDeviceAuth: true,
},
},
browser: {
enabled: true,
headless: true,
noSandbox: true,
executablePath: "/data/bin/chrome-headless-shell",
},
agents: {
defaults: {
model: { primary: "moonshot/kimi-k2.5" },
sandbox: { mode: "off" },
maxConcurrent: 4,
},
},
};
}
The key trick is the ${KIWICLAW_PROXY_TOKEN} syntax. OpenClaw resolves environment variable references in its config at load time. We set the actual JWT as a Fly machine environment variable (KIWICLAW_PROXY_TOKEN), and OpenClaw substitutes it into the config. The tenant never sees the raw JWT. Our pooled API keys stay in the LLM proxy service.
Env Vars vs. Config Files
We deliver configuration through environment variables rather than config files because of a Fly.io timing bug: Fly's files mechanism writes files before volume mounts happen. Our boot script decodes the base64 config after the volume is mounted, ensuring the file lands on persistent storage.
For BYOK tenants, API keys are also injected as environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY). OpenClaw's default provider registry picks them up automatically, with no config needed for provider URLs.
What We Get for Free
By running stock OpenClaw, we inherit every upstream improvement without effort:
- Security patches are deployed by pulling the new image tag. No merge conflicts. No testing our modifications against the patch. Pull, deploy, done.
- New features appear automatically when we update the image. New skills, new channel integrations, new agent capabilities. Our customers get them the same day.
- Performance improvements in the upstream agent, gateway, or tool execution benefit all our tenants immediately.
- Community ecosystem compatibility is guaranteed. Skills, channel adapters, and integrations built by the OpenClaw community work without modification.
The update process for a security patch is: change the image tag in our orchestrator config, deploy, and all new machines use the patched version. Existing machines get the update on their next restart. Total engineering time: minutes, not days.
What We Cannot Do
Wrapping has trade-offs. There are things we cannot do without forking:
- Deep UI customization of the OpenClaw control UI. We can inject CSS and JavaScript (we do, to hide internal UI elements), but we cannot fundamentally restructure the chat interface.
- Internal API changes to add features that OpenClaw does not expose via config. If we need a capability that is not configurable, we either wait for upstream to add it or build it in our management layer.
- Performance optimization of OpenClaw internals. We cannot optimize the agent's LLM call patterns, tool execution pipeline, or memory management. We optimize around it (proxy layer, machine sizing, volume caching).
We accept these trade-offs because the benefits of staying upstream-compatible far outweigh the limitations. The features we build in our management layer -- auth, billing, usage caps, tenant isolation, skills vetting, compliance -- are all things that belong outside the agent anyway.
The Management Layer Breakdown
| Component | LOC | Responsibility |
|---|---|---|
| Dashboard | ~5,000 | Auth (Clerk), billing (Stripe), agent UI, onboarding, settings |
| Orchestrator | ~4,000 | Fly Machines API, config injection, HTTP/WS proxy, tenant lifecycle |
| LLM Proxy | ~1,500 | JWT auth, SSE streaming, usage recording, cap enforcement |
| Shared package | ~1,500 | Types, constants, JWT utils, pricing config |
| Total | ~12,000 |
12,000 lines is small for a production SaaS. That is the point. The hard work (building an autonomous AI agent with browser automation, code execution, multi-channel support, and a skill ecosystem) was done by the OpenClaw project. We did the operations work: making it deployable, billable, and secure for customers who do not want to manage infrastructure.
Competitors Who Forked
We are aware of at least two competitors in the OpenClaw hosting space that forked the codebase to add features. Without naming names, the pattern is the same:
- Fork OpenClaw to add a custom billing UI, usage tracking, or authentication
- Ship quickly because the initial diff is small
- OpenClaw releases a major version with breaking changes to the gateway auth system
- Spend a week merging the upstream changes into the fork
- Repeat every release cycle
One competitor is still running an OpenClaw version from January 2026 because their fork has diverged too far to merge the February security patches cleanly. Their customers are running a version with known vulnerabilities because the fork tax caught up.
When Should You Fork?
Wrapping is not always the right answer. Fork when:
- The upstream project does not have sufficient configuration hooks for your needs
- You need to fundamentally change the runtime behavior (not just settings)
- The upstream release cadence is slow enough that the merge tax is manageable
- You have a dedicated team to maintain the fork long-term
Wrap when:
- The upstream project is configurable enough to support your use case
- Your value-add is around the software, not inside it (auth, billing, compliance, multi-tenancy)
- The upstream moves fast and you want to stay current
- You are a small team and cannot afford the ongoing merge tax
OpenClaw is one of the most configurable open-source projects we have worked with. Its JSON config supports provider replacement, gateway auth customization, browser settings, agent defaults, and environment variable interpolation. That configurability made wrapping viable. For a less configurable project, we might have had to fork.
Frequently Asked Questions
What does "wrap, don't fork" mean for SaaS?
Instead of forking the open-source codebase and modifying its source code, you run the stock software as-is and build a management layer around it. Configuration injection, environment variables, and external proxy services provide all the customization you need without changing a single line of upstream code.
How do you customize OpenClaw without changing its code?
OpenClaw is configurable through its JSON config file and environment variables. We generate per-tenant configs that set LLM provider URLs (pointing at our proxy), gateway authentication, browser automation config, and agent defaults. API keys and tokens are delivered as Fly machine environment variables that OpenClaw resolves at runtime.
Why is forking open source risky for a SaaS business?
When you fork, you take ownership of every upstream change. Security patches must be manually merged. New features must be rebased onto your modifications. Breaking changes require expensive adaptation. Over time, the fork diverges further, making each merge harder. This creates compounding technical debt.
How much custom code does KiwiClaw have?
About 12,000 lines of TypeScript across four components: the dashboard (Next.js), the orchestrator (Fly Machines API), the LLM proxy (SSE streaming), and a shared package (types, JWT, constants). This is the management layer that wraps stock OpenClaw. Zero lines of the OpenClaw codebase are modified.
Written by Amogh Reddy