AI CMS is a website builder for Australian tradies — electricians, plumbers, carpenters. A new customer signs up, describes their business in plain English ("Smith Electrical, 0412 345 678, Parramatta NSW"), picks their trade, and in minutes they have a live, SEO-optimised website. From then on they edit it by chatting: "change my phone number," "add a services page," "make the hero blue."
Behind the scenes, AI CMS uses Nimblesite as its AI brain. Here's the full architecture.
The stack
- Frontend: React SPA
- Backend: C# Minimal APIs (orchestration, auth, site data, chat routing)
- Agent platform: Nimblesite (chat loop, memory, tool contract)
- Tool executor: Ephemeral Fly.io containers (filesystem, Eleventy build, git)
- Escalation path: Claude Code CLI for complex tasks (new pages, redesigns)
The critical separation: Nimblesite owns the agent; AI CMS owns the tools.
The agent config
AI CMS created one Nimblesite config for the editing assistant:
{
"name": "Tradie Site Editor",
"system_prompt": "You are a website editor for {tenant_name}, a {trade_type} business in {location}. Common services: {services}. When a user asks for a simple change (text, phone numbers, small CSS tweaks), use read_file, write_file, and replace_in_file. For complex work (new pages, redesigns), use escalate_to_claude_code.",
"model_config": {
"provider": "anthropic",
"model": "claude-haiku-4-5"
},
"tools_config": [
"read_file",
"write_file",
"replace_in_file",
"list_files",
"build_site",
"escalate_to_claude_code"
]
}
None of those tools live inside Nimblesite. They live inside AI CMS's own backend, which proxies calls to Fly.io containers.
The tool proxy
When Nimblesite returns a tool_calls array, AI CMS's C# backend does something like:
public async Task<ChatResult> HandleChatAsync(string message, Guid? conversationId)
{
var response = await _nimblesite.ChatAsync(ConfigId, new ChatRequest
{
Message = message,
ConversationId = conversationId,
});
while (response.ToolCalls.Any())
{
var results = new List<ToolResult>();
foreach (var call in response.ToolCalls)
{
var output = await _flyContainer.RunToolAsync(
response.ConversationId, call.Name, call.Arguments);
results.Add(new ToolResult(call.Name, output));
}
response = await _nimblesite.ChatAsync(ConfigId, new ChatRequest
{
ConversationId = response.ConversationId,
ToolResults = results,
});
}
return new ChatResult(response.Response);
}
Nimblesite never touches the website files. Never has SSH access to the container. Never holds credentials for the customer's site. The agent decides what to call; AI CMS's backend runs it.
The two-tier cost model
Most edits are trivial ("change my phone number"). Those go through the base config with claude-haiku-4-5 and cost a few cents.
For complex tasks the agent calls escalate_to_claude_code, which triggers a Fly.io container to launch the Claude Code CLI with the full site context. That's a $0.50–$2.00 operation, but it handles things like "redesign the services page" end-to-end, committing the result to git.
Two tiers, one config, one agent. The agent itself decides which tier to use based on the task.
The numbers
- Cost per chat edit: cents (basic agent handles 80%+ of edits)
- Cost per full site generation: low single-digit dollars (Claude Code handles the initial build)
- Customer subscription: $49/month
- Gross margin: 50–80%
AI CMS didn't build a conversation table. Didn't build a prompt template engine. Didn't build multi-tenancy. Didn't manage provider API keys per customer. Didn't write an agent loop. All of that came free with Nimblesite.
What AI CMS still owns
- The trade-specific knowledge injected into the system prompt
- The tool implementations (file reads, writes, builds)
- The Fly.io container lifecycle and scaling
- The customer dashboard and subscription billing
- The domain routing and SSL
That's the right split. AI CMS owns their product. Nimblesite owns the agent infrastructure they'd otherwise be forced to build.
The takeaway
AI CMS is a reference architecture for any SaaS that wants to drop a chat-to-edit or chat-to-operate experience into their product:
- Configure one Nimblesite agent with your system prompt and tool list
- Write your tools as normal functions in your backend
- Proxy tool calls between Nimblesite and your tool runtime
- Ship it
No framework. No loop code. No messages table. No multi-tenant scaffolding.
That's what "Agents as a Service" means in practice.