Configuration
AIO Agent is configured through aio_agent. If the Athena dashboard is enabled,
use the dashboard first because the live config may be stored in MongoDB instead
of only reading configuration/aio_agent.json5.
AIO Agent can run Discord actions for trusted users. Set owner_id, review
every user ID list, and keep destructive actions confirmed before using it on
a customer server.
How Values Are Entered
Most customer-specific fields are free text in the dashboard so you can enter real values instead of being limited to a dropdown. This includes model names, API base URLs, docs URLs, knowledgebase paths, prompt file names, timezone values, locale values, and the forum thread header template.
Dropdowns are used only for true fixed choices such as mode, llm_provider,
permission tiers, personality, moderation mode, moderation sensitivity, boolean
toggles, and other enum-style settings.
Use Discord snowflake IDs for users, roles, and channels. Enable Developer Mode in Discord, right-click the item, then copy the ID.
Addon Configuration
Customer-specific addon configuration belongs under:
plugins/aio_agent/data/addons/<addon-id>/config.json5Addon defaults are applied only when the normal AIO config does not already set that value. Dashboard/config values win over addon defaults. This lets updates keep customer addons intact while still letting server owners override settings from the normal AIO config.
See Addons for the addon manifest, API, and update rules.
Core
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Master switch. When false, AIO Agent ignores all events. |
mode | enum | "general" | Feature mode: general, chat, support, or owner_only. |
permissions.aio_command | string | "management" | Athena permission level required for /aio. Must match configuration/permission.json5. |
mode behavior:
| Mode | What runs |
|---|---|
general | Tickets, chat, owner/admin pings, moderation, member events, FAQ, and anti-raid. |
chat | Chat replies only. No tickets, owner tools, moderation, or member automation. |
support | Ticket/support flows only. Owner pings only work inside support context. |
owner_only | Only owner_id can talk to the agent. No tickets, chat, or automation. |
LLM Provider
| Option | Type | Default | Description |
|---|---|---|---|
llm_provider | enum | "gemini" | Provider to use: gemini, openai, anthropic, openrouter, or custom. |
llm_api_key | string | "" | Provider API key. Leave blank to use environment variables. |
llm_model | string | "" | Exact model name to send to the selected provider. Empty uses provider default. |
llm_api_base_url | string | "" | Required for custom; optional override for OpenAI-compatible providers. |
gemini_api_key | string | "" | Legacy Gemini-only key. Used when provider is gemini and llm_api_key is blank. |
gemini_model | string | "gemini-2.5-flash" | Legacy Gemini model fallback. Used when provider is gemini and llm_model is blank. |
llm_max_output_tokens | number | 4096 | Maximum output tokens for owner/tool and ticket calls. |
llm_temperature_ticket | number | 0.7 | Creativity for ticket support replies. |
llm_temperature_owner | number | 0.8 | Creativity for owner/admin tool-calling replies. |
llm_temperature_chat | number | 0.9 | Creativity for general chat. |
llm_temperature_moderation | number | 0.2 | Moderation decision temperature. Keep low for consistency. |
gemini_max_output_tokens | number | 4096 | Legacy alias. New llm_max_output_tokens wins. |
gemini_temperature_ticket | number | 0.7 | Legacy alias. New llm_temperature_ticket wins. |
gemini_temperature_owner | number | 0.8 | Legacy alias. New llm_temperature_owner wins. |
gemini_temperature_chat | number | 0.9 | Legacy alias. New llm_temperature_chat wins. |
gemini_temperature_moderation | number | 0.2 | Legacy alias. New llm_temperature_moderation wins. |
llm_retry_attempts | number | 2 | Number of retries for temporary provider failures such as 429, 500, 502, 503, and 504. |
llm_retry_base_delay_ms | number | 800 | Base delay between retries. Delay increases by attempt number. |
usage_pricing_input_per_million | number | 0.30 | Estimated input-token cost per 1M tokens for /aio usage. |
usage_pricing_output_per_million | number | 2.50 | Estimated output-token cost per 1M tokens for /aio usage. |
Separate reasoning profile
The reasoning profile can use a second provider, model, base URL, and API key
for heavier tasks while normal chat and ticket replies continue using the
primary profile. Blank provider/model/base URL values inherit the primary
settings. A blank reasoning key uses AIO_AGENT_REASONING_API_KEY, the matching
provider environment variable, or the primary key.
| Option | Type | Default | Description |
|---|---|---|---|
reasoning_llm.enabled | boolean | false | Enables the optional second LLM profile. |
reasoning_llm.provider | enum/string | "" | gemini, openai, anthropic, openrouter, or custom. Empty inherits the primary provider. |
reasoning_llm.api_key | string | "" | Separate API key. Empty uses the environment/key fallback described above. |
reasoning_llm.model | string | "" | Separate model. Empty inherits the primary model. |
reasoning_llm.api_base_url | string | "" | Separate compatible endpoint. Empty inherits the primary base URL. |
reasoning_llm.use_for_owner_tools | boolean | true | Uses this profile for multi-step owner/admin agent tools. |
reasoning_llm.use_for_self_improvement | boolean | true | Uses this profile to evaluate confirmed-memory proposals. |
reasoning_llm.use_for_response_classifier | boolean | false | Uses this profile for ambiguous Smart reply decisions. |
reasoning_llm.use_for_knowledgebase_search | boolean | true | Uses this profile for embedding-backed knowledgebase search when supported. |
Prompt caching
Prompt caching depends on the provider and model. These options apply to the primary LLM and the optional reasoning profile according to the provider used for each request.
| Option | Type | Default | Description |
|---|---|---|---|
prompt_caching.enabled | boolean | false | Lets AIO send or manage the provider-specific controls below. Turning it off does not disable implicit caching performed by the provider. |
prompt_caching.openai.mode | enum | "automatic" | automatic uses provider-managed breakpoints. explicit marks AIO’s system prompt and requires GPT-5.6 or later. |
prompt_caching.openai.cache_key | string | "" | Optional stable routing key for requests that share the same long prompt prefix. |
prompt_caching.anthropic.mode | enum | "automatic" | automatic follows the growing conversation. explicit caches the system prompt. |
prompt_caching.anthropic.ttl | enum | "5m" | Claude cache lifetime: 5m or 1h. |
prompt_caching.gemini.mode | enum | "automatic" | automatic uses Gemini implicit caching. explicit creates a managed cache for the stable system prompt and active tool definitions. |
prompt_caching.gemini.ttl_seconds | number | 300 | Gemini explicit-cache lifetime from 60 to 86400 seconds. |
OpenAI uses a fixed 30-minute TTL for explicit caching. If explicit mode is selected with an older OpenAI model, AIO safely uses automatic caching instead. Gemini also falls back to an ordinary request when its provider rejects an explicit cache, including prompts below the model’s minimum cache size.
/aio usage shows cached-input and cache-write token counts. The dollar
estimate uses the configured base input/output prices and does not include
provider-specific cache discounts, write premiums, or cache-storage charges.
Environment variable priority:
AIO_AGENT_LLM_API_KEY- Provider-specific variable such as
AIO_AGENT_OPENAI_API_KEY llm_api_keygemini_api_keywhen using Gemini
Provider-specific variables:
AIO_AGENT_LLM_API_KEY=...
AIO_AGENT_GEMINI_API_KEY=...
AIO_AGENT_OPENAI_API_KEY=...
AIO_AGENT_ANTHROPIC_API_KEY=...
AIO_AGENT_OPENROUTER_API_KEY=...Recommended starting models:
| Provider | Model example | Notes |
|---|---|---|
gemini | gemini-2.5-flash | Best default for low-cost support and knowledgebase answers. |
openai | gpt-4o-mini | Good OpenAI-compatible default. |
anthropic | claude-3-5-haiku-latest | Fast Claude option. |
openrouter | openai/gpt-4o-mini | Route to many providers with one key. |
custom | provider-specific | Use the exact OpenAI-compatible model name required by your endpoint. |
Never publish real API keys in screenshots, docs, support tickets, or Discord messages. Use environment variables for production whenever possible.
Identity And Branding
| Option | Type | Default | Description |
|---|---|---|---|
brand_name | string | "" | Brand inserted into prompts as the brand_name placeholder. Empty uses the Discord server name where available. |
owner_display_name | string | "" | Friendly owner name inserted into prompts as the owner_display_name placeholder. |
docs_url | string | "https://docs.iynxdev.com/" | Public documentation link the bot returns when users ask where docs are. |
owner_id | string | "" | Discord user ID with full owner-level tool access. Required for privileged tool use. |
Permission Tiers
AIO Agent resolves each speaker into one tier.
| Tier | Config source | Access |
|---|---|---|
| Owner | owner_id | All tools, including sensitive owner-only tools. |
| Admin | admin_users | Most server-management and moderation tools, excluding sensitive owner-only tools. |
| Moderator | moderator_users | Moderation tools, role assignment/removal, channel lock/unlock, slowmode, nicknames, and ticket close when allowed. |
| Allowed | allowed_users | Conversation only. No tools. |
| None | not listed | Cannot use privileged owner-ping flows. |
| Blocked | blocked_users | Ignored by AIO Agent. |
| Option | Type | Default | Description |
|---|---|---|---|
admin_users | string[] | [] | Discord user IDs with admin tool access. |
moderator_users | string[] | [] | Discord user IDs with moderator tool access. |
allowed_users | string[] | [] | Discord user IDs allowed to chat without tool access. |
blocked_users | string[] | [] | Discord user IDs the bot ignores everywhere. |
Abuse Protection
| Option | Type | Default | Description |
|---|---|---|---|
max_message_length | number | 1500 | User messages longer than this are truncated before the model sees them. Extreme lengths add abuse strikes. |
max_requests_per_user_per_hour | number | 15 | Rolling hourly request cap for non-privileged users. |
Repeated rate-limit, spam, or extreme-length strikes can automatically add a
user to blocked_users.
Confirmations And Audit Logging
| Option | Type | Default | Description |
|---|---|---|---|
require_confirmation_for | string[] | destructive defaults | Tool names that always require an Approve/Cancel button before execution. |
confirm_destructive_tools | boolean | true | Also require confirmation for any tool marked destructive by the plugin. |
confirmation_approver_user_ids | string[] | [] | Extra Discord user IDs allowed to approve AI action confirmations. |
confirmation_approver_role_ids | string[] | [] | Role IDs allowed to approve AI action confirmations. |
confirmation_timeout_seconds | number | 30 | How long confirmation buttons remain valid. |
action_audit_log_channel_id | string | "" | Optional channel ID where AI tool attempts are logged. |
action_audit_include_args | boolean | true | Include tool arguments in audit logs. |
action_audit_include_result | boolean | true | Include tool result in audit logs. |
Recommended confirmed tools:
require_confirmation_for: [
"ban_user",
"unban_user",
"kick_user",
"delete_messages",
"delete_role",
"remove_warning",
"set_channel_permissions",
"delete_channel",
"close_ticket",
"run_athena_command"
]For normal AI tool confirmations, only a valid button click approves the action.
Plain text such as ok after a timeout does not approve an expired action.
Multi-Step Agent Limits
| Option | Type | Default | Description |
|---|---|---|---|
tool_execution.max_iterations | number | 12 | Maximum planning/tool rounds for one agent request. |
tool_execution.max_actions_per_request | number | 40 | Maximum individual actions across all rounds in one request. |
When a request reaches either limit, AIO stops safely and reports what it completed instead of claiming the entire task finished.
Personality And Context
| Option | Type | Default | Description |
|---|---|---|---|
personality | enum | "professional_casual" | Global personality: professional, professional_casual, casual, or custom. |
custom_personality | string | "" | Free-form personality instructions when personality is custom. |
max_context_messages | number | 30 | Recent channel messages included as model history. Workflow embeds and bot action messages are filtered out. |
Reply Modes And Smart Gate
Chat and tickets can use separate reply modes:
| Mode | Behavior |
|---|---|
smart | Ignores normal conversation and acknowledgements, answers clear help and direct bot-name calls locally, and classifies only ambiguous questions. In tickets, it also stays quiet while another human is handling the customer. |
always | Answers every eligible message in a watched chat channel or every customer message in an active ticket. |
mentions | Answers only a real bot mention or a Discord reply to the bot. Typing the bot name or a configured alias does not count in this mode. |
Smart is the default for both chat.response_mode and
tickets.response_mode. It uses local rules first, so normal conversation,
clear help, and direct calls using the bot’s username, nickname, or a configured
alias do not require a classifier request. If an ambiguous message does need
classification, AIO sends a short JSON-only request with limited history and
fails closed when the provider is unavailable or unsure.
| Option | Type | Default | Description |
|---|---|---|---|
response_gate.use_llm_classifier | boolean | true | Allows a small LLM check for ambiguous questions. When false, ambiguous messages are ignored. |
response_gate.classifier_model | string | "" | Optional lower-cost model used only for the response gate. Empty uses the main configured model. |
response_gate.context_messages | number | 8 | Recent messages included so the classifier can tell who a question is aimed at. Range: 2-20. |
response_gate.confidence_threshold | number | 0.72 | Minimum confidence required before AIO joins an ambiguous conversation. Range: 0.5-0.95. |
response_gate.max_output_tokens | number | 80 | Maximum output tokens for the JSON-only decision. Range: 32-160. |
response_gate.max_message_chars | number | 1200 | Maximum characters from the latest message sent to the classifier. Range: 200-4000. |
response_gate.cache_ttl_seconds | number | 120 | How long a decision for the same Discord message is reused. Range: 10-600. |
response_gate.max_checks_per_user_per_hour | number | 12 | Hourly cap on ambiguous-message classifier requests for each user. Range: 1-100. |
Classifier calls are included in /aio usage. The normal chat request limit
still applies after Smart decides to answer. Direct mentions and intentional
bot-name calls bypass the channel cooldown so they are not dropped behind an
earlier response; per-user limits still apply.
Knowledgebase
AIO Agent can load knowledge from three places:
.mdand.txtfiles inknowledgebase_dir- Built-in AthenaBot docs when
athenabot_brain_enabledis true - Configured channel or forum snapshots from
knowledgebase_channels
The plugin reads the sources on startup or /aio reload, stores them in memory,
then builds a knowledgebase_block for each AI request. The request does
not read the filesystem again unless you reload or restart.
| Option | Type | Default | Description |
|---|---|---|---|
knowledgebase_channels | string[] | [] | Channel IDs to ingest as extra knowledge. Forum threads are supported. |
knowledgebase_dir | string | "knowledgebase" | Folder for .md and .txt files. Relative paths resolve under plugins/aio_agent/data/; absolute paths are allowed. |
knowledgebase_recursive | boolean | false | Scan subfolders under knowledgebase_dir. |
knowledgebase_max_depth | number | 8 | Maximum folder depth when recursive loading is enabled. |
athenabot_brain_enabled | boolean | true | Loads built-in AthenaBot documentation, config references, FAQ, and common errors. |
forum_thread_header_template | string | --- Thread: {{thread_name}} | Author: {{author_name}} --- | Header added before imported forum thread content. Supports thread_name and author_name placeholders. |
Retrieval Mode
| Option | Type | Default | Description |
|---|---|---|---|
knowledgebase_mode | enum | "search" | off, full, search, or hybrid. |
knowledgebase_full_max_chars | number | 120000 | Character cap for full mode. |
knowledgebase_search_top_k | number | 6 | Number of chunks selected in search or hybrid mode. |
knowledgebase_search_max_chars | number | 12000 | Total character cap for selected chunks. |
knowledgebase_search_min_score | number | 0.05 | Minimum local-search score before a chunk is included. |
knowledgebase_search_fallback_full | boolean | false | If search finds nothing, fall back to full mode. Use carefully because this can be expensive. |
knowledgebase_chunk_max_chars | number | 1800 | Target maximum size for each searchable chunk. |
knowledgebase_chunk_overlap_chars | number | 150 | Character overlap between split chunks. |
knowledgebase_always_include_sources | string[] | [] | Source path/title substrings that are always included when matched. Useful for policies or pricing docs. |
Mode guide:
| Mode | What gets sent to the model | Use when |
|---|---|---|
off | No knowledgebase block. | You want pure model behavior or only prompt files. |
full | One large block with all loaded knowledge, capped by knowledgebase_full_max_chars. | Small knowledgebases where every request needs the same context. |
search | Only locally scored chunks relevant to the user’s latest request. | Default choice for most customers. Lower cost than full mode. |
hybrid | Local search selects candidates, then embeddings rerank them when configured. | Large or messy knowledgebases where word matching alone misses relevant pages. |
Embeddings
Embeddings are optional. With the default config, search mode uses local token
matching only and does not call a separate embedding API. Turn embeddings on when
the knowledgebase is large enough that semantic matching is worth the extra API
calls.
| Option | Type | Default | Description |
|---|---|---|---|
knowledgebase_embeddings_enabled | boolean | false | Enables embedding rerank in search or hybrid mode. |
knowledgebase_embedding_provider | enum/string | "llm" | llm, gemini, openai, openrouter, or custom. llm reuses llm_provider. |
knowledgebase_embedding_model | string | "" | Exact embedding model name. Empty uses provider defaults. |
knowledgebase_embedding_api_key | string | "" | Optional embedding-specific API key. Empty reuses the effective LLM key. |
knowledgebase_embedding_api_base_url | string | "" | Optional embedding-specific OpenAI-compatible base URL. |
knowledgebase_embedding_candidate_count | number | 30 | Number of local-search candidates to embed/rerank before selecting top chunks. |
knowledgebase_embedding_max_chars | number | 3000 | Max characters embedded per chunk/query. |
knowledgebase_hybrid_local_weight | number | 0.35 | Local-search score weight in hybrid rerank. |
knowledgebase_hybrid_embedding_weight | number | 0.65 | Embedding similarity score weight in hybrid rerank. |
Default embedding models:
| Provider | Default embedding model |
|---|---|
| Gemini | text-embedding-004 |
| OpenAI | text-embedding-3-small |
| OpenRouter | text-embedding-3-small unless your route requires another model |
| Custom | You should set knowledgebase_embedding_model |
Embedding vectors are cached in plugins/aio_agent/data/cache/knowledgebase-embeddings.json.
If the content changes, the source hash changes and stale cached vectors are not
reused.
Recommended setups:
// Small knowledgebase, lowest complexity
knowledgebase_mode: "full"
// Normal customer knowledgebase
knowledgebase_mode: "search"
knowledgebase_search_top_k: 6
knowledgebase_search_max_chars: 12000
// Large knowledgebase with semantic rerank
knowledgebase_mode: "hybrid"
knowledgebase_embeddings_enabled: true
knowledgebase_embedding_provider: "llm"
knowledgebase_embedding_candidate_count: 30Run this after changing files or channel knowledge:
/aio reloadConfirmed Memory
Confirmed memory lets authorized users say remember this, or lets AIO propose
useful server facts from configured conversations. Every proposal is posted to
the review channel and must be approved before it is written to the configured
knowledgebase file. It only updates AIO’s own knowledge, terminology,
personality, server facts, and support guidance; it cannot edit code,
configuration, permissions, or unrelated systems.
| Option | Type | Default | Description |
|---|---|---|---|
self_improvement.enabled | boolean | false | Enables authorized remember-this requests and memory review. |
self_improvement.auto_detect | boolean | false | Allows eligible chats to create review proposals. Nothing is saved automatically. |
self_improvement.source_scope | enum | "selected" | Sources for automatic proposals: all, staff, or selected. |
self_improvement.channel_ids | string[] | [] | Channels included when scope is selected. |
self_improvement.category_ids | string[] | [] | Categories included when scope is selected. |
self_improvement.excluded_channel_ids | string[] | [] | Channels always excluded from automatic proposals. |
self_improvement.review_channel_id | string | "" | Required review/log channel for proposals, approvals, rejections, and save results. |
self_improvement.approver_user_ids | string[] | [] | Extra users allowed to approve or reject memory proposals. |
self_improvement.approver_role_ids | string[] | [] | Roles allowed to approve or reject memory proposals. |
self_improvement.minimum_requester_tier | enum | "ADMIN" | Minimum AIO tier allowed to request remember this. |
self_improvement.memory_file | string | "agent-memory.md" | Safe .md or .txt file inside the AIO knowledgebase directory. |
self_improvement.min_confidence | number | 0.88 | Minimum confidence for automatic proposals. |
self_improvement.max_entry_chars | number | 1000 | Maximum saved characters per approved entry. |
self_improvement.cooldown_seconds | number | 60 | Per-channel automatic proposal cooldown. |
self_improvement.max_proposals_per_hour | number | 10 | Global hourly automatic proposal limit. |
self_improvement.review_timeout_minutes | number | 30 | How long review buttons remain active. |
After approval, AIO writes the memory safely and reloads its knowledgebase so new conversations can use it immediately.
Tickets
Ticket support requires AthenaBot’s tickets plugin.
| Option | Type | Default | Description |
|---|---|---|---|
tickets.enabled | boolean | true | Enables AI responses inside ticket channels. |
tickets.response_mode | enum | "smart" | Ticket reply behavior: smart, always, or mentions. Smart avoids interrupting active staff. |
tickets.auto_activate | boolean | true | Automatically starts an AI ticket session when a customer messages. Use /aio handle instead if you want manual activation. |
tickets.auto_activate_categories | array | [] | Ticket category indexes that auto-activate. Empty means all categories. |
tickets.external_ticket_fallback.enabled | boolean | false | Allows AIO to create a ticket session in third-party ticket bot channels when a customer mentions the bot and the channel matches configured markers. |
tickets.external_ticket_fallback.require_bot_mention | boolean | true | Require the customer to mention the AIO bot before external fallback starts a session. |
tickets.external_ticket_fallback.channel_name_patterns | string[] | ["ticket", "order"] | Channel name substrings or /regex/ patterns treated as external ticket channels. |
tickets.external_ticket_fallback.recent_message_limit | number | 12 | Number of recent messages scanned for external ticket form markers. |
tickets.external_ticket_fallback.form_text_contains | string[] | Tickets v2 form text | Text fragments that identify a third-party ticket form message. |
tickets.human_phrases | string[] | common phrases | Customer phrases that pause the AI and hand off to staff. |
tickets.owner_stop_phrases | string[] | common phrases | Owner/admin phrases that pause the AI inside a ticket. |
tickets.cooldown_seconds | number | 2 | Minimum channel delay between ticket AI replies. |
tickets.allow_ai_ticket_close | boolean | false | Master switch for AI/staff-triggered ticket closing. |
tickets.ticket_close_requires_confirmation | boolean | true | Require a Discord button flow before closing. |
tickets.ticket_close_minimum_tier | enum | "MODERATOR" | Minimum AIO tier allowed to request/approve AI ticket closing: OWNER, ADMIN, or MODERATOR. |
tickets.ticket_close_allow_creator | boolean | false | Lets the ticket creator approve an AI close request through Athena’s native ticket close buttons. |
tickets.ticket_close_commands | string[] | close aliases | Athena command names treated as ticket-close commands when using run_athena_command. |
tickets.ticket_close_approver_role_ids | string[] | [] | Role IDs that can approve AI ticket-close confirmations. |
tickets.staff_notify_enabled | boolean | true | Allows the AI to trigger a real staff notification marker instead of only saying it notified staff. |
tickets.staff_notify_marker | string | "[STAFF_NOTIFY]" | Marker the AI emits when it wants staff notified. |
tickets.staff_notify_channel_id | string | "" | Channel ID for staff notifications. Empty posts in the ticket channel. |
tickets.staff_notify_user_ids | string[] | [] | User IDs mentioned on staff notification. |
tickets.staff_notify_role_ids | string[] | [] | Role IDs mentioned on staff notification. |
tickets.staff_notify_fallback_to_owner | boolean | true | Mention owner_id if no explicit staff users/roles are configured. |
tickets.staff_notify_on_handoff | boolean | true | Notify staff when a customer uses a human handoff phrase. |
tickets.staff_notify_pause_session | boolean | true | Pause the AI session after staff notification. |
tickets.staff_notify_context_messages | number | 6 | Recent ticket messages included in staff notification embeds. |
tickets.strict_workflow.enabled | boolean | true | Runs deterministic ticket intake before the LLM. |
tickets.strict_workflow.notify_requires_customer_approval | boolean | true | After the customer confirms the brief, ask separately before notifying staff. |
tickets.strict_workflow.pause_after_notify | boolean | true | Pause the ticket AI after a real staff notification is sent. |
tickets.strict_workflow.use_llm_extractor | boolean | false | Optional JSON-only field extraction helper. Failed extraction falls back to asking the next configured field. |
tickets.strict_workflow.required_fields | array | service/title/description/deadline/budget/references | Required intake fields. Each field supports key, label, question, and aliases. |
tickets.strict_workflow.replies | object | built-in strict replies | Reply templates for checklist, missing fields, brief summary, confirmation request, notify approval, notify success, skipped notify, and failures. |
tickets.category_settings | array | [] | Per-ticket-category overrides. See below. |
tickets.enable_spec_confirmation_flow | boolean | false | Enables marker-based commission/spec confirmation flow. |
tickets.spec_confirmation_marker | string | "[SPEC_CONFIRMED]" | Marker emitted by the model when a spec is confirmed. |
tickets.ticket_form_embed_title_contains | string[] | ["Ticket questions"] | Embed title substrings used to detect new ticket form data. |
tickets.catchup_enabled | boolean | false | On startup, scan missed tickets and create sessions when needed. |
tickets.catchup_min_channel_created_at | string | "" | ISO timestamp limiting catch-up to newer channels. Empty uses current time on first boot. |
Per-category overrides:
tickets: {
category_settings: [
{
category_index: 0,
tone: "friendly",
custom_tone: "",
handoff_phrases: ["staff please"],
staff_notify_channel_id: "123456789012345678",
staff_notify_user_ids: [],
staff_notify_role_ids: ["123456789012345678"],
staff_notify_on_handoff: true,
staff_notify_pause_session: true,
allow_ai_ticket_close: true,
ticket_close_requires_confirmation: true,
ticket_close_minimum_tier: "MODERATOR",
ticket_close_allow_creator: true,
ticket_close_approver_role_ids: []
}
]
}Ticket close behavior:
| Setup | Result |
|---|---|
allow_ai_ticket_close: false | AI can answer tickets but cannot close them. |
allow_ai_ticket_close: true and ticket_close_requires_confirmation: true and ticket_close_allow_creator: true | A creator close request such as close ticket or !tclose uses Athena’s native close-request buttons. |
allow_ai_ticket_close: true and ticket_close_requires_confirmation: true and creator close disabled | AIO posts an AI action confirmation for staff/approved users. |
allow_ai_ticket_close: true and ticket_close_requires_confirmation: false | The ticket closes directly through the tickets plugin with reason [aio-agent] close_ticket. |
Expired close prompts cannot be approved with plain text. A user must send a new explicit close intent or click a fresh native button.
Strict Workflow
Strict workflow keeps ticket intake and staff notification deterministic. The model may still help with normal support replies, but it does not decide whether a brief is complete, whether staff were notified, or whether a handoff happened.
Default flow:
- Customer asks what information is needed.
- AIO sends the configured checklist and asks the first missing field.
- Customer answers one field at a time or sends a larger brief.
- AIO stores answers in
workflowData.fields. - Once all
required_fieldsare filled, AIO sendsbrief_summary. - Customer confirms the brief.
- AIO asks whether to notify staff.
- Only explicit notify approval sends the real staff notification.
- If
pause_after_notifyis true, the AI pauses after notifying staff.
Example required field:
{
key: "deadline",
label: "Deadline / urgency",
question: "What is the deadline or urgency?",
aliases: ["deadline", "urgency", "deadline / urgency", "due", "due date"]
}Example strict workflow config:
tickets: {
strict_workflow: {
enabled: true,
notify_requires_customer_approval: true,
pause_after_notify: true,
use_llm_extractor: false,
required_fields: [
{ key: "service", label: "Service", question: "What type of service do you need?", aliases: ["service", "type of service"] },
{ key: "title", label: "Project title or text", question: "What is the project title or exact text?", aliases: ["project title", "title", "text"] },
{ key: "description", label: "Description", question: "Please describe the project, style, and important details.", aliases: ["description", "details", "theme", "style"] },
{ key: "deadline", label: "Deadline / urgency", question: "What is the deadline or urgency?", aliases: ["deadline", "urgency"] },
{ key: "budget", label: "Budget range", question: "What is the budget range?", aliases: ["budget", "budget range"] },
{ key: "references", label: "References", question: "Do you have any references, links, or images?", aliases: ["references", "links", "images"] }
]
}
}Plain answers are applied to the last field AIO asked for. For example, if AIO
asks for deadline and the customer replies take your time, that becomes the
deadline value.
External Ticket Bot Fallback
Use this only when another ticket system creates the ticket channel and
AthenaBot’s native tickets plugin cannot resolve the channel.
tickets: {
external_ticket_fallback: {
enabled: true,
require_bot_mention: true,
channel_name_patterns: ["ticket", "order"],
recent_message_limit: 12,
form_text_contains: [
"Your order ticket has been created",
"While you are waiting, please fill out this question form",
"Question 1",
"Question 2",
"Question 3",
"Powered by tickets.bot"
]
}
}When enabled, AIO starts a session only when:
- the message is from a human
- the customer mentions the bot, unless
require_bot_mentionis false - the message looks related to the strict ticket workflow
- the channel name or recent bot ticket form messages match the fallback config
The first matching human is treated as the ticket creator for the AIO session.
Chat
| Option | Type | Default | Description |
|---|---|---|---|
chat.enabled | boolean | false | Enables general chat mode. |
chat.channels | string[] | [] | Channel IDs where the bot can chat without being mentioned. |
chat.respond_to_mentions | boolean | true | Allows replies when the bot is mentioned outside configured chat channels. |
chat.respond_to_name | boolean | true | Replies immediately when someone directly calls the bot by its Discord username or server nickname. Ordinary references to the name remain ignored. |
chat.wake_words | string[] | [] | Optional extra bot names or phrases that count as direct calls in Smart mode. |
chat.response_mode | enum | "smart" | Chat reply behavior: smart, always, or mentions. |
chat.personality | string | "" | Chat-only personality override. Empty inherits global personality. |
chat.custom_personality | string | "" | Chat-only custom personality text. |
chat.allowed_topics | string | "" | Optional topic boundary for chat. |
chat.max_messages_per_user_per_hour | number | 20 | Chat-only hourly cap for non-admin users. |
chat.cooldown_seconds | number | 3 | Channel cooldown between chat replies. |
Moderation
| Option | Type | Default | Description |
|---|---|---|---|
moderation.enabled | boolean | false | Enables AI moderation checks. |
moderation.mode | enum | "ask" | off, ask, or instant. Start with ask. |
moderation.review_channel_id | string | "" | Channel where review embeds are posted in ask mode. |
moderation.server_rules | string | "" | Rules the AI evaluates against. Be specific. |
moderation.enforce_discord_tos | boolean | true | Also enforce Discord ToS/community guidelines. |
moderation.sensitivity | enum | "medium" | low, medium, or high. |
moderation.actions.warn | boolean | true | Allows warnings through Athena’s moderation plugin, including its history, thresholds, notifications, and log. |
moderation.actions.timeout | boolean | true | Allows timeouts. |
moderation.actions.timeout_max_minutes | number | 60 | Maximum timeout duration. |
moderation.actions.kick | boolean | false | Allows kicks. Keep disabled until reviewed. |
moderation.actions.ban | boolean | false | Allows bans. Keep disabled until reviewed. |
moderation.actions.delete_message | boolean | true | Allows deleting violating messages. |
moderation.monitored_channels | string[] | [] | Empty means all channels except excluded channels. |
moderation.excluded_channels | string[] | [] | Channels skipped by moderation. |
moderation.immune_roles | string[] | [] | Role IDs exempt from moderation. |
moderation.immune_users | string[] | [] | User IDs exempt from moderation. |
moderation.min_confidence | number | 0.75 | Minimum confidence required to act or request review. |
moderation.review_timeout_minutes | number | 10 | How long review embeds remain actionable. |
moderation.cooldown_per_user_seconds | number | 5 | Per-user moderation-call cooldown. |
moderation.context_messages | number | 5 | Recent messages supplied to the moderation prompt. |
Scam Detection
Scam detection is separate from text moderation and is disabled by default. It can scan image attachments, links, sender age, join age, roles, trust lists, and recent context before normal AIO replies.
| Option | Type | Default | Description |
|---|---|---|---|
scam_detection.enabled | boolean | false | Enables scam scanning. |
scam_detection.mode | enum | "ask" | off, ask, or instant. Start with ask. |
scam_detection.min_confidence | number | 0.82 | Minimum confidence required for review or action. |
scam_detection.auto_delete_confidence | number | 0.94 | High-confidence threshold for delete actions when allowed. |
scam_detection.scan_images | boolean | true | Sends image attachments to a vision-capable model. |
scam_detection.scan_links | boolean | true | Checks message links and domains. |
scam_detection.scan_new_accounts_more_strictly | boolean | true | Applies stricter judgment for new accounts and recent joins. |
scam_detection.review_channel_id | string | "" | Channel for scam review embeds. Empty uses the moderation review channel. |
scam_detection.log_channel_id | string | "" | Optional channel for scam evidence and decisions. Athena’s moderation plugin owns punishment history and moderation logs. |
scam_detection.monitored_channels | string[] | [] | Empty means all non-excluded channels. |
scam_detection.excluded_channels | string[] | [] | Channels skipped by scam scanning. |
scam_detection.ignored_users | string[] | [] | User IDs skipped by scam scanning. |
scam_detection.ignored_roles | string[] | [] | Role IDs skipped by scam scanning. |
scam_detection.trusted_domains | string[] | [] | Domains that should not trigger scans by themselves. |
scam_detection.trusted_users | string[] | [] | User IDs trusted by scam scanning. |
scam_detection.trusted_image_hashes | string[] | [] | SHA-256 image hashes ignored by future scans. |
scam_detection.max_image_bytes | number | 4194304 | Maximum image size sent to the model. |
scam_detection.max_images_per_message | number | 2 | Maximum image attachments scanned per message. |
scam_detection.context_messages | number | 6 | Recent messages supplied as context. |
scam_detection.cache_ttl_minutes | number | 360 | How long image hash scan results are reused. |
scam_detection.review_timeout_minutes | number | 30 | How long review buttons stay active. |
scam_detection.actions.delete_message | boolean | true | Allows deleting scam messages. |
scam_detection.actions.auto_delete_high_confidence | boolean | false | Allows high-confidence auto-delete while in ask mode. |
scam_detection.actions.warn | boolean | true | Allows warning users. |
scam_detection.actions.timeout | boolean | true | Allows timing out users. |
scam_detection.actions.timeout_minutes | number | 60 | Timeout duration for scam actions. |
scam_detection.actions.kick | boolean | false | Allows kicks. Keep disabled until reviewed. |
scam_detection.actions.ban | boolean | false | Allows bans. Keep disabled until reviewed. |
Raw images are not stored locally. AIO stores image hashes, attachment URLs, domains, scores, decisions, and short evidence text in AIOScamScanLog.
See Scam Detection for setup steps, provider requirements, and review behavior.
Member Events
| Option | Type | Default | Description |
|---|---|---|---|
member_events.enabled | boolean | false | Enables welcome, goodbye, auto-role, and member log features. |
member_events.welcome_channel_id | string | "" | Channel for welcome messages. |
member_events.welcome_message | string | "" | Template supporting username, user_mention, server_name, and member_count placeholders. |
member_events.welcome_ai_personalize | boolean | false | Uses the LLM to generate a short unique welcome. |
member_events.welcome_ai_language | string | "English" | Language for the AI continuation, such as Dutch or nl-NL. Blank uses English. Translate the prefix separately. |
member_events.welcome_ai_prefix | string | "" | Text before the AI continuation. Blank keeps the English greeting. Supports {{username}}, {{user_mention}}, {{server_name}}, and {{member_count}}. |
member_events.welcome_mention_mode | enum | "user" | user adds a safe user mention outside the AI text; none sends no mention. |
member_events.welcome_delay_seconds | number | 0 | Delay before sending welcome messages. |
member_events.welcome_wait_for_any_role | boolean | false | Wait until the member receives any non-@everyone role before welcoming. |
member_events.welcome_wait_for_role_ids | string[] | [] | Specific role IDs that can unlock the welcome when any one is found. |
member_events.welcome_wait_timeout_seconds | number | 60 | Maximum time to wait for role requirements before skipping the welcome. |
member_events.goodbye_channel_id | string | "" | Channel for goodbye messages. |
member_events.goodbye_message | string | "" | Goodbye template. |
member_events.auto_roles | string[] | [] | Role IDs assigned when a member joins. |
member_events.log_channel_id | string | "" | Channel for join/leave log embeds. Empty disables logs. |
Welcome Language
In v1.4.2, both dashboards expose AI Welcome Language and AI Welcome Prefix under Member Events. Enable AI Personalize Welcome to use them.
For Dutch welcomes, set the language to Dutch and the prefix to
Welkom bij {{server_name}}!. The bot adds the member mention, then asks the
AI for a short continuation in Dutch. The language setting affects only the
AI sentence; it does not translate the prefix or change chat/ticket languages.
With AI Welcome Mention set to No mention, the bot does not add a
mention, and a {{user_mention}} placeholder in the prefix becomes the username.
Role and everyone mentions cannot notify anyone. If the provider fails or
returns no usable text, the bot sends only the configured prefix.
Existing configurations keep the English defaults. For a fixed translated message, disable AI Personalize Welcome and edit Welcome Message instead. See the Dutch setup example.
Anti-Raid
| Option | Type | Default | Description |
|---|---|---|---|
anti_raid.enabled | boolean | false | Enables join-burst monitoring. |
anti_raid.join_threshold | number | 10 | Number of joins required to trigger. |
anti_raid.join_window_seconds | number | 30 | Time window for the join threshold. |
anti_raid.action | enum | "alert" | alert or lockdown. Lockdown delegates to Athena’s security plugin so its exclusions, snapshots, and recovery flow remain authoritative. |
anti_raid.alert_channel_id | string | "" | Channel where anti-raid alerts are sent. |
FAQ
FAQ replies are matched before an LLM request. Use FAQ entries for fixed answers such as docs links, pricing links, or server IPs.
| Option | Type | Default | Description |
|---|---|---|---|
faq.enabled | boolean | false | Enables fast non-LLM FAQ replies. |
faq.entries | array | [] | Entries shaped as { triggers: [...], answer: "..." }. |
Example:
faq: {
enabled: true,
entries: [
{
triggers: ["docs", "documentation", "where are the docs"],
answer: "You can find the docs at https://docs.havendevelopment.net/"
}
]
}Prompt Files
Prompt files live under plugins/aio_agent/data/prompts/ unless you provide an
absolute path. They are re-read when prompts are built, so reload/restart after
editing them if you are unsure which config backend is active.
| Option | Default | Description |
|---|---|---|
prompt_files.ticket | "ticket-system.md" | Ticket support system prompt. |
prompt_files.owner | "owner-system.md" | Owner/admin tool-calling prompt. |
prompt_files.chat | "chat-system.md" | General chat prompt. |
prompt_files.moderation | "moderation-system.md" | Moderation JSON decision prompt. |
prompt_files.ticket_role_body | "ticket-role-body-default.md" | Ticket role/persona body when spec flow is enabled. |
prompt_files.ticket_role_body_no_spec | "ticket-role-body-no-spec.md" | Ticket role/persona body without spec flow. |
prompt_files.ticket_important_context | "ticket-important-context-default.md" | Extra ticket context block. |
prompt_files.owner_ticket_role_body | "owner-ticket-role-default.md" | Owner assistant ticket context body. |
prompt_files.security_preamble | "security-preamble.md" | Safety and anti-abuse prompt preamble. |
Prompt Variables And Appends
| Option | Type | Default | Description |
|---|---|---|---|
prompt_variables | object | {} | Custom string placeholders available inside prompt templates. |
prompt_append_ticket | string | "" | Text appended to the ticket system prompt. |
prompt_append_owner | string | "" | Text appended to the owner system prompt. |
prompt_append_chat | string | "" | Text appended to the chat system prompt. |
Built-in prompt variables include:
| Variable | Meaning |
|---|---|
{{brand_name}} | Configured brand or server name. |
{{owner_display_name}} | Configured owner display name. |
{{docs_url}} | Public docs URL. |
{{current_datetime}} | Current formatted time. |
{{datetime_timezone}} | IANA timezone. |
{{datetime_timezone_label}} | Human-readable timezone label. |
{{knowledgebase_block}} | Knowledgebase content selected for the current request. |
Time And Locale
| Option | Type | Default | Description |
|---|---|---|---|
datetime_timezone | string | "UTC" | IANA timezone used in prompts, such as America/Winnipeg or Europe/London. |
datetime_locale | string | "en-US" | Locale used for formatted dates, such as en-US, en-CA, or fr-FR. |
datetime_timezone_label | string | "UTC" | Human-readable timezone label shown to the model, such as Central Time. |
What To Restart Or Reload
| Change | What to do |
|---|---|
| API keys or environment variables | Restart AthenaBot. |
| Dashboard config values | Save in dashboard, then restart if the feature does not update live. |
| Prompt caching settings | Save in dashboard; new LLM requests use the updated settings. Existing Gemini managed caches expire on their configured TTL. |
| Knowledgebase files | Run /aio reload. |
| Knowledgebase channels/forums | Run /aio reload; restart if channel permissions changed. |
| Prompt files | Run /aio reload or restart. |
| Plugin code or dependencies | Restart AthenaBot. |