How the OpenSEO Onboarding Chat System Works: Architecture and Implementation

The OpenSEO onboarding chat system is a durable-object-based AI agent that provides new users with 7 free SEO strategy questions before requiring a subscription, enforcing limits through both client-side gating and server-side credit metering.

OpenSEO's onboarding chat functions as a short-lived, credit-metered assistant that demonstrates the platform's SEO capabilities to prospective users. The system combines Durable Objects for stateful persistence, SQLite for conversation storage, and tool-augmented LLM calls to deliver contextual strategy advice. This article breaks down the complete architecture based on the every-app/open-seo source code.


Client-Side Gating: The Free Question Limit

The onboarding experience begins with a hardcoded constant that synchronizes client and server behavior.

// src/shared/onboardingChat.ts
export const FREE_ONBOARDING_QUESTION_LIMIT = 7;

This FREE_ONBOARDING_QUESTION_LIMIT serves as the single source of truth across both environments. The client UI consumes this constant to:

  • Display "X questions left" indicators
  • Disable the message composer when the limit is reached
  • Trigger subscription prompts at the appropriate moment

Keeping this value in a shared module ensures the client preview never diverges from server enforcement.


Server-Side Architecture: OnboardingChatAgent

The core of the OpenSEO onboarding chat is the OnboardingChatAgent class, a Durable Object that extends AIChatAgent and lives in src/server/features/onboarding/OnboardingChatAgent.ts.

Message Persistence and State

The agent maintains conversation history in SQLite, with automatic retry logic for transient database errors. The persistMessages method guarantees durability even under load spikes.

Dual Enforcement: Count and Credits

When processing a onChatMessage request, the agent performs two sequential checks:

  1. Question count – Filters stored messages by role === 'user' and compares against FREE_ONBOARDING_QUESTION_LIMIT. If exceeded and the organization lacks managed access, returns a static subscription response (lines 31-38).

  2. Credit balance – In hosted mode, calls checkUsageCreditsDepleted to verify onboarding credits remain. If depleted, returns the same subscription prompt (lines 42-48).

// Core enforcement logic from OnboardingChatAgent.ts
async onChatMessage(onFinish, options) {
  const project = await ProjectRepository.getProjectById(this.name);
  const questionCount = this.messages.filter(m => m.role === 'user').length;

  // Free-question cap enforcement
  if (questionCount > FREE_ONBOARDING_QUESTION_LIMIT && 
      !(await customerHasManagedAccess(project.organizationId))) {
    return staticAssistantResponse(
      'You\'ve used all your free strategy questions. Subscribe to continue.'
    );
  }

  // Credit enforcement in hosted environments
  if (await checkUsageCreditsDepleted(project.organizationId, 'onboarding')) {
    return staticAssistantResponse('Subscribe to continue.');
  }
  // ... LLM orchestration
}

LLM Orchestration and the "Sam" Persona

The OpenSEO onboarding chat presents itself as "Sam", an SEO strategy assistant. The buildSystemPrompt method (lines 26-60) constructs detailed instructions governing:

  • Tone and style – Professional but approachable SEO expert voice
  • Content boundaries – Allowed topics and response patterns
  • Tool availability – Which capabilities the model may invoke

Available Tools for the Onboarding Assistant

The buildOnboardingTools factory exposes SEO-specific capabilities:

Tool Purpose
read_website Fetches and analyzes page content
get_seo_metrics Retrieves performance indicators
research_keywords Identifies keyword opportunities

These tools allow the onboarding chat to demonstrate real OpenSEO functionality rather than generic advice.


Billing Integration and Cost Tracking

The OpenSEO onboarding chat system meters actual LLM spend against organization credits:

  • Token budgeting – Each request caps output at 4000 tokens
  • Per-step cost trackingstreamText runs with cost instrumentation
  • Credit consumptiontrackUsageCreditSpend records expenditure against the organization's onboarding credit pool (lines 70-84)

This ensures free previews remain economically bounded while providing genuine utility.


Key Files and Responsibilities

File Path Role in Onboarding Chat
src/shared/onboardingChat.ts Shared constants (FREE_ONBOARDING_QUESTION_LIMIT)
src/server/features/onboarding/OnboardingChatAgent.ts Durable Object agent, enforcement, LLM orchestration
src/server/features/onboarding/onboardingChatTools.ts Tool factories (read_website, get_seo_metrics, etc.)
src/server/lib/openrouter.ts Model selection and cost reporting
src/server/billing/subscription.ts Credit checking and tracking utilities
src/server/lib/chatAgent.ts Base agent utilities and cost calculations

Summary

  • The OpenSEO onboarding chat provides 7 free strategy questions via a synchronized client-server limit (FREE_ONBOARDING_QUESTION_LIMIT)
  • The OnboardingChatAgent Durable Object enforces both message-count and credit-based restrictions before serving LLM responses
  • The "Sam" persona operates through a constructed system prompt with access to real SEO tools (read_website, get_seo_metrics, research_keywords)
  • Cost tracking via trackUsageCreditSpend binds free usage to actual LLM expenditure, preventing abuse
  • SQLite persistence with retry logic ensures conversation state survives restarts and errors

Frequently Asked Questions

What happens when a user exceeds the free question limit in OpenSEO?

The OnboardingChatAgent counts user messages in its SQLite store. Once the count exceeds FREE_ONBOARDING_QUESTION_LIMIT (7) and the organization lacks managed access, the agent returns a static response prompting subscription. The client UI simultaneously disables the composer based on the same constant.

How does OpenSEO prevent unlimited free usage of the onboarding chat?

The system implements dual enforcement: message counting for immediate gating, plus credit balance checking via checkUsageCreditsDepleted for hosted deployments. Even if a client bypasses the UI limit, the server rejects requests when trackUsageCreditSpend indicates exhausted credits.

What tools can the onboarding chat assistant use?

According to buildSystemPrompt and buildOnboardingTools, the assistant "Sam" may invoke read_website, get_seo_metrics, and research_keywords. These tools demonstrate actual OpenSEO capabilities rather than delivering generic SEO advice.

Why does OpenSEO use a Durable Object for onboarding chat?

The OnboardingChatAgent extends AIChatAgent as a Durable Object to maintain stateful conversation persistence across HTTP requests. SQLite storage inside the Durable Object guarantees messages survive connection drops, with persistMessages implementing retry logic for transient failures.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →