SVE Chat
RAG-powered AI chat for SVE residents. Ask questions about community documents, upcoming events, and amenity availability — and get accurate, sourced answers instantly.
What is SVE Chat?
SVE Chat is an AI-powered question-and-answer widget for the Sunland Village East HOA website. Residents type a question in plain English and receive a concise answer drawn from:
- HOA governing documents — CC&Rs, bylaws, rules, policies, and other community documents stored in the SVE document database.
- Live calendar events — upcoming tournaments, club meetings, classes, and activities from the SVE Community Calendar.
- Amenity availability — open booking slots for the clubhouse, pool, courts, gym, and other facilities via the SVE Fastbook system.
The chat is powered by Claude (Anthropic) and uses a Retrieval-Augmented Generation (RAG) pipeline — the AI never guesses from general knowledge; it only answers from SVE-specific sources.
How It Works
Every question goes through a multi-step pipeline before an answer is returned:
1. Document Retrieval
The question is embedded and compared against all SVE documents stored in a PostgreSQL pgvector database. Up to 10 chunks scoring above a 0.35 cosine similarity threshold are retrieved and sent to the AI as context.
2. AI Answer Generation
Claude receives the document excerpts and the resident’s question. It may also call live tools — the calendar search or amenity availability tool — before producing its final answer.
3. Tool Use (Agentic Loop)
When a question is about events or amenities, Claude calls the appropriate tool, receives real-time data, and incorporates it into the answer. The loop runs up to 5 iterations.
4. Unanswered Logging
If the AI cannot find an answer in the documents or tools, the question is automatically logged to the Unanswered Questions database for admin review and follow-up.
Requirements
| Requirement | Minimum Version / Notes |
|---|---|
| PHP | 8.1 or higher |
| WordPress | 6.4 or higher |
| Anthropic API Key | ANTHROPIC_API_KEY constant in wp-config.php |
| SVE AI Engine Bridge | MU-plugin providing sve_pg_search_run() (pgvector search) |
| SVE Community Calendar | Optional — required for live event search tool |
| SVE Fastbook | Optional — required for amenity availability tool |
| SVE Docs Plugin | Optional — provides sve_docs_get_setting() for access-control integration |
Using the Chat Widget
The chat widget appears on any page where an administrator has placed the
shortcode. You must be logged in to your SVE HOA account to use it.
-
Navigate to the page with the chat widget. Ask your community manager or check the HOA website for the page where SVE Chat is available.
-
Type your question in the text box at the bottom of the widget. You can ask in plain, conversational English — no special syntax required. Questions can be up to 500 characters.
-
Press Enter or click the send button. A loading indicator appears while the AI retrieves and processes your answer, typically within a few seconds.
-
Read the answer. The AI cites the source document or section where applicable. If it cannot find an answer, it will tell you rather than guess.
-
Continue the conversation. You can ask follow-up questions. Each question is answered independently — the AI does not carry memory between questions.
What to Ask
SVE Chat is designed to answer questions about SVE community life. Here are good examples by category:
Rules & Policies
- “What are the quiet hours in SVE?”
- “Can I park an RV in my driveway?”
- “What is the pet policy for SVE?”
- “How do I get approval for a home improvement project?”
- “What are the rules for garage sales?”
Community Events
- “What events are happening this week?”
- “When is the next pickleball tournament?”
- “Are there any club meetings this month?”
- “What fitness classes are offered?”
Amenity Booking
- “When is the clubhouse available this weekend?”
- “Are there any open tennis court slots tomorrow?”
- “How do I book the pool area for a party?”
- “Is the gym available on Saturday mornings?”
Governing Documents
- “What does the CC&R say about fences?”
- “How are HOA board members elected?”
- “What are the landscaping requirements?”
- “What is the process for filing an architectural review request?”
Tips for Better Answers
Be specific
Instead of “what are the rules?”, ask “what are the rules about holiday decorations?” The more specific your question, the more relevant the document excerpts will be.
Include date context for events
Instead of “what’s coming up?”, ask “what events are happening in April?” Providing a time frame helps the calendar search return the most useful results.
Ask one question at a time
Each submission is handled as a single query. If you have multiple questions, ask them separately to get the most focused answers.
Understand the limits
SVE Chat only knows what is in the SVE document database and the live calendar/amenity systems. It cannot answer questions about individual accounts, billing, or information not stored in those sources. For those, contact the HOA office directly.
Installation & Setup
1. Install the Plugin
Upload the sve-chat folder to wp-content/plugins/ and activate it through the WordPress admin. A database table ({prefix}sve_chat_unanswered) is created automatically on activation.
2. Add the Anthropic API Key
Add the following constant to wp-config.php:
define( 'ANTHROPIC_API_KEY', 'sk-ant-...' );
3. Verify the AI Engine Bridge
The MU-plugin sve-ai-engine-bridge.php must be present in wp-content/mu-plugins/ and must provide the sve_pg_search_run() function. SVE Chat will throw an error if this function is missing when a question is submitted.
ANTHROPIC_API_KEY to version control. Store it only in wp-config.php or a secrets manager.Adding the Widget to a Page
Place the
shortcode in any page or post content. The widget renders a self-contained chat interface with no additional configuration required.
Shortcode Attributes
| Attribute | Default | Description |
|---|---|---|
title |
Ask About SVE |
Header text shown at the top of the widget. |
placeholder |
Ask a question about SVE rules, documents, or policies… |
Placeholder text in the question input box. |
height |
460 |
Height of the message area in pixels. Minimum 200. |
Examples
Unanswered Questions Log
When the AI cannot find an answer — because the relevant information is not in the document database or tool results — the question is automatically logged. This log is a valuable tool for identifying gaps in your SVE document library.
Dashboard Statistics
The top of the admin page shows three summary cards:
Total Unanswered
Lifetime count of questions the AI could not answer from available sources.
Last 24 Hours / 7 Days
Recent volume indicators — useful for spotting spikes after community announcements or events.
Most Common Unanswered Questions
A ranked table of the questions asked most frequently that did not receive a satisfactory answer. Use this to prioritize which documents to add or update in the SVE document library.
Full Question Log
A paginated table (50 per page) showing every logged question with:
- Date and time asked
- The full question text
- IP address of the requester
- Resident name (linked to their WordPress user profile) if logged in
Individual entries can be deleted once reviewed. Use the search box to filter by keyword.
Exporting to CSV
The admin page includes a SQL query you can run directly in your database client (phpMyAdmin, TablePlus, etc.) to export all unanswered questions:
SELECT question, user_ip, user_id, blog_id, asked_at
FROM wp_sve_chat_unanswered
ORDER BY asked_at DESC;
Access Control
SVE Chat mirrors the access level configured in the SVE Docs plugin (min_role_view setting). This ensures the chat widget is only accessible to residents who are already permitted to browse HOA documents.
| SVE Docs Setting | Who Can Use SVE Chat |
|---|---|
guest | Anyone, including logged-out visitors |
subscriber | Any logged-in WordPress user |
contributor | Users with edit_posts capability |
author | Users with publish_posts capability |
editor | Users with edit_others_posts capability |
administrator | Administrators only |
subscriber level).Access control is enforced at the REST API level (POST /wp-json/sve-chat/v1/ask). Unauthenticated or insufficiently privileged requests receive an HTTP 401 response and are not counted against the rate limit.
Rate Limiting
To prevent abuse and control API costs, SVE Chat limits each IP address to 30 questions per hour. This limit is enforced using WordPress site transients and is network-scoped — the same 30-question budget applies across all subsites in the multisite installation.
When the limit is reached, the API returns HTTP 429 and the widget displays a friendly message asking the resident to wait before asking more questions. The counter resets automatically after 60 minutes.
RATE_LIMIT constant in includes/class-chat-api.php.Dependencies
| Dependency | Where Configured | Required? |
|---|---|---|
ANTHROPIC_API_KEY |
wp-config.php constant |
Required |
sve_pg_search_run() |
MU-plugin: sve-ai-engine-bridge.php |
Required |
sve_docs_get_setting() |
SVE Docs plugin | Optional |
scc_switch_to_blog() / SCC_MAIN_BLOG_ID |
SVE Community Calendar plugin | Optional |
SVE_Fastbook_Amenity / SVE_Fastbook_Booking |
SVE Fastbook plugin | Optional |
OPENAI_API_KEY |
wp-config.php constant |
Optional (only if switching provider to openai) |
AI Tools
When the Anthropic provider is active, Claude has access to tools it can call during the agentic loop. Two tools are built in. Additional tools can be added by any plugin — see Adding a Tool.
search_calendar_events
Queries the SVE Community Calendar for upcoming events. Claude uses this tool whenever a resident asks about when something is happening, what activities are scheduled, or anything involving future community events.
Input Parameters
| Parameter | Type | Description |
|---|---|---|
start_date | string (Y-m-d) | Beginning of the date range. Defaults to today. |
end_date | string (Y-m-d) | End of the date range. Defaults to 30 days after start. |
keyword | string | Optional text to filter event titles or descriptions. |
category | string | Optional event category (e.g. Social, Sports, Club Meeting). |
Returns up to 20 events with title, start/end times, venue, and a truncated description. Requires the SVE Community Calendar plugin with scc_switch_to_blog() and SCC_MAIN_BLOG_ID defined.
search_amenity_availability
Queries SVE Fastbook for open booking slots. Claude uses this tool when a resident asks about reserving or checking availability for any community facility.
Input Parameters
| Parameter | Type | Description |
|---|---|---|
amenity_type | string | Category: clubhouse, pool, court, gym, outdoor, room, equipment, or general. |
amenity_name | string | Specific facility name if known (e.g. “Tennis Court 1”). |
start_date | string (Y-m-d) | Beginning of the date range. Defaults to today. |
end_date | string (Y-m-d) | End of the date range. Defaults to 7 days after start. |
Returns available time slots per day for up to 5 matching amenities, capped at 10 slots per day. Requires the SVE Fastbook plugin with SVE_Fastbook_Amenity and SVE_Fastbook_Booking classes available.
Adding a Tool from Another Plugin
SVE Chat uses an extensible provider pattern. Any WordPress plugin can register additional AI tools without modifying the SVE Chat source code. Claude will automatically have access to the new tool and will call it when appropriate.
How it works
SVE Chat defines an abstract base class SVE_Chat_Tool_Provider. You create a class that extends it, implement two methods, then hook it into the sve_chat_tool_providers filter. The executor picks up your provider, merges your tool definitions into the API request, and routes tool calls back to your class.
SVE_Chat_Tool_Providersve_chat_tool_providers filterto Anthropic API
your
execute_tool() runsStep 1 — Create the provider class
Create a PHP file in your plugin. The class must extend SVE_Chat_Tool_Provider and implement two methods:
get_tool_definitions()— returns the Anthropic tool schema array (name, description, input_schema).execute_tool( string $name, array $input )— runs the tool and returns a JSON string result.
The base class also provides a protected parse_date( string $value, string $default ) helper for tools that accept date inputs.
Step 2 — Register the provider
Hook into sve_chat_tool_providers on plugins_loaded. The filter receives an array of provider instances and must return the modified array.
Complete example — Work Order search tool
The following example adds a search_work_orders tool from a hypothetical SVE Maintenance plugin, so residents can ask the chat “Is my fence repair request still open?” or “What maintenance requests are pending in my area?”
<?php
/**
* SVE_Maintenance_Chat_Tool — adds work-order search to SVE Chat.
*
* File: wp-content/plugins/sve-maintenance/includes/class-maintenance-chat-tool.php
*/
defined( 'ABSPATH' ) || exit;
class SVE_Maintenance_Chat_Tool extends SVE_Chat_Tool_Provider {
/**
* Tell Anthropic what this tool does and what inputs it accepts.
*/
public function get_tool_definitions(): array {
return [
[
'name' => 'search_work_orders',
'description' => 'Search SVE maintenance work orders. Use this when a '
. 'resident asks about repair requests, maintenance status, '
. 'or open work orders in the community.',
'input_schema' => [
'type' => 'object',
'properties' => [
'status' => [
'type' => 'string',
'description' => 'Filter by status: open, in_progress, completed, or all.',
],
'location' => [
'type' => 'string',
'description' => 'Optional area name (e.g. "pool", "tennis courts", "gate").',
],
'since_date' => [
'type' => 'string',
'description' => 'Only return work orders submitted after this date (Y-m-d).',
],
],
'required' => [],
],
],
];
}
/**
* Execute the tool and return a JSON string for the model.
*/
public function execute_tool( string $name, array $input ): string {
// Guard: make sure our plugin's class is available.
if ( ! class_exists( 'SVE_Work_Order' ) ) {
return wp_json_encode( [ 'error' => 'Maintenance plugin is not active.' ] );
}
$status = sanitize_key( $input['status'] ?? 'open' );
$location = sanitize_text_field( $input['location'] ?? '' );
$since = $this->parse_date( $input['since_date'] ?? '', '' );
// Query work orders from the maintenance plugin.
$orders = SVE_Work_Order::query( [
'status' => $status,
'location' => $location,
'since' => $since,
'limit' => 15,
] );
if ( empty( $orders ) ) {
return wp_json_encode( [
'message' => 'No work orders found matching your criteria.',
'orders' => [],
] );
}
$results = array_map( static fn( $o ) => [
'id' => $o->id,
'title' => $o->title,
'status' => $o->status,
'location' => $o->location,
'submitted' => $o->submitted_at,
'description' => mb_substr( $o->description, 0, 200 ),
], $orders );
return wp_json_encode( [ 'work_orders' => $results ] );
}
}
Then register the provider in your plugin’s main file:
// In sve-maintenance.php (or wherever your plugin bootstraps)
add_action( 'plugins_loaded', function (): void {
// Only register if SVE Chat is active.
if ( ! class_exists( 'SVE_Chat_Tool_Provider' ) ) {
return;
}
require_once __DIR__ . '/includes/class-maintenance-chat-tool.php';
add_filter( 'sve_chat_tool_providers', function ( array $providers ): array {
$providers[] = new SVE_Maintenance_Chat_Tool();
return $providers;
} );
} );
That’s all. No changes to SVE Chat are required. Once registered, Claude will automatically consider calling search_work_orders whenever a resident’s question is relevant to maintenance.
execute_tool() and return a descriptive JSON error if they don’t. Claude will relay that error to the resident gracefully rather than crashing the request.Rules for tool definitions
- Tool names must be unique across all providers. Use a plugin-specific prefix (e.g.
myplugin_search_foo) to avoid collisions. - Descriptions matter. Claude decides whether to call a tool based entirely on its description. Write it from the resident’s perspective — describe the kinds of questions that should trigger the tool.
- Keep results compact. Tool results are inserted back into the Claude context window. Truncate long text fields, cap list sizes, and avoid returning binary data.
- Always return valid JSON. Use
wp_json_encode(). An invalid return value will cause the agentic loop to fail.
Configuration Constants
These constants in includes/class-chat-handler.php control core AI behavior. Edit them to tune performance and cost.
| Constant | Default | Description |
|---|---|---|
PROVIDER | anthropic | LLM provider. Options: anthropic or openai. Tool use only applies when anthropic is set. |
ANTHROPIC_MODEL | claude-sonnet-4-5-20250929 | Anthropic model ID. Update to use a newer model — this is the field that drives billing. |
OPENAI_MODEL | gpt-4o-mini | OpenAI model ID. Only used when PROVIDER is openai. |
SEARCH_LIMIT | 10 | Number of document chunks retrieved from pgvector per question. |
MIN_SCORE | 0.35 | Minimum cosine similarity score for a chunk to be included in context. Lower values include more (potentially less relevant) chunks. |
MAX_CONTEXT_CHARS | 9000 | Maximum characters of document context sent to the LLM (~2 250 tokens). Limits per-request cost. |
TEMPERATURE | 0.0 | LLM temperature. 0.0 = fully deterministic. Increase slightly for more conversational responses. |
MAX_TOOL_ITERATIONS | 5 | Maximum number of tool-call rounds before the agentic loop gives up. |
Actions & Filters
sve_chat_tool_providers filter
Allows plugins to register additional AI tool providers. The filter receives an array of SVE_Chat_Tool_Provider instances (the two built-in providers are always present) and must return the modified array. See Adding a Tool for full details and a worked example.
| Parameter | Type | Description |
|---|---|---|
$providers | SVE_Chat_Tool_Provider[] | Array of registered tool providers. Append your provider and return the array. |
add_filter( 'sve_chat_tool_providers', function( array $providers ): array {
$providers[] = new My_Plugin_Chat_Tool_Provider();
return $providers;
} );
sve_chat_unanswered_question action
Fired when the AI returns a response indicating it could not answer the question from available sources. Use this hook to trigger additional workflows — for example, sending an admin notification or creating a support ticket.
| Parameter | Type | Description |
|---|---|---|
$question | string | The resident’s original question text. |
$user_id | int|null | WordPress user ID, or null for guests. |
$user_ip | string | The requester’s IP address. |
add_action( 'sve_chat_unanswered_question', function( string $question, ?int $user_id, string $ip ): void {
// Send an admin notification, log to Slack, create a ticket, etc.
}, 10, 3 );
