Chatbook Features API Documentation
February 27, 2026 · View on GitHub
Overview
This document describes the current, implemented API surface for Chatbook-adjacent features in the multi-user API: Chat Dictionaries, World Books (lorebooks), Document Generator, and Chatbooks (import/export). It reflects the code as of v0.1.0 in tldw_Server_API and corrects any previously published mismatches.
Auth + Rate Limits
- Single-user:
X-API-KEY: <key> - Multi-user:
Authorization: Bearer <JWT> - Standard limits apply; background jobs (export/import, document generator) may have additional concurrency limits.
Notes on conventions used here:
- Base API prefix is
/api/v1. - Authentication uses either
X-API-KEY(single-user) orAuthorization: Bearer <JWT>(multi-user). - Pagination uses
limitandoffsetwhere applicable and responses include atotalfield in the body (no page/per_page headers). - Rate limits are applied via RG ingress policies and may differ by route.
Table of Contents
- Chat Dictionary API
- World Book Manager API
- Chat Tools (Slash Commands)
- Document Generator API
- Chatbooks Import/Export API
Chat Dictionary API
Pattern-based text replacement for conversations. Supports literal and regex patterns with probability and optional grouping.
Base URL
/api/v1/chat/dictionaries
Endpoints
1. Create Dictionary
POST /api/v1/chat/dictionaries
Creates a new chat dictionary for the authenticated user.
Request body:
{
"name": "Fantasy Terms",
"description": "Convert modern terms to fantasy equivalents"
}
Response body (ChatDictionaryResponse):
{
"id": 1,
"name": "Fantasy Terms",
"description": "Convert modern terms to fantasy equivalents",
"is_active": true,
"version": 1,
"entry_count": 0,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
2. List Dictionaries
GET /api/v1/chat/dictionaries
Lists all dictionaries for the authenticated user.
Query parameters:
include_inactive(boolean): Include inactive dictionaries (default: false)
Response body:
{
"dictionaries": [
{
"id": 1,
"name": "Fantasy Terms",
"description": "Convert modern terms to fantasy equivalents",
"is_active": true,
"version": 1,
"entry_count": 25,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
],
"total": 1,
"active_count": 1,
"inactive_count": 0
}
3. Get Dictionary (with entries)
GET /api/v1/chat/dictionaries/{dictionary_id}
Response body:
{
"id": 1,
"name": "Fantasy Terms",
"description": "Convert modern terms to fantasy equivalents",
"is_active": true,
"entries": [
{
"id": 1,
"pattern": "car",
"replacement": "carriage",
"type": "literal",
"probability": 1.0,
"max_replacements": 0,
"enabled": true,
"case_sensitive": true,
"group": null,
"timed_effects": null
}
],
"created_at": "2024-01-01T00:00:00Z"
}
4. Add Entry
POST /api/v1/chat/dictionaries/{dictionary_id}/entries
Notes:
typemust beliteralorregex.probabilityis a float in [0.0, 1.0].case_sensitiveapplies to literal matching.max_replacementsof 0 means “unlimited”.timed_effectssupports{ sticky, cooldown, delay }in seconds (optional).
Request body:
{
"pattern": "phone",
"replacement": "sending stone",
"type": "literal",
"probability": 1.0,
"max_replacements": 0,
"enabled": true,
"case_sensitive": true
}
Response body:
{
"id": 2,
"dictionary_id": 1,
"pattern": "phone",
"replacement": "sending stone",
"probability": 1.0,
"group": null,
"timed_effects": null,
"max_replacements": 0,
"type": "literal",
"enabled": true,
"case_sensitive": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
5. Update Entry
PUT /api/v1/chat/dictionaries/entries/{entry_id}
Request body (all fields optional):
{
"pattern": "telephone",
"replacement": "communication crystal",
"probability": 0.9,
"type": "literal",
"enabled": true,
"case_sensitive": true,
"group": "tech",
"max_replacements": 0
}
6. Delete Entry
DELETE /api/v1/chat/dictionaries/entries/{entry_id}
7. Process Text
POST /api/v1/chat/dictionaries/process
Request body:
{
"text": "I'll call you on my phone from the car",
"token_budget": 1000,
"dictionary_id": 1,
"max_iterations": 5
}
Response body:
{
"original_text": "I'll call you on my phone from the car",
"processed_text": "I'll call you on my sending stone from the carriage",
"replacements": 2,
"iterations": 1,
"entries_used": [3, 5],
"token_budget_exceeded": false,
"processing_time_ms": 2.4
}
8. List Entries
GET /api/v1/chat/dictionaries/{dictionary_id}/entries
Query parameters:
group(string, optional)
Response body:
{
"entries": [
{
"id": 1,
"dictionary_id": 1,
"pattern": "car",
"replacement": "carriage",
"probability": 1.0,
"group": null,
"timed_effects": null,
"max_replacements": 0,
"type": "literal",
"enabled": true,
"case_sensitive": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
],
"total": 1,
"dictionary_id": 1,
"group": null
}
9. Import Dictionary (Markdown)
POST /api/v1/chat/dictionaries/import
Notes:
- Markdown import is intended for lightweight interoperability and may not preserve all advanced entry settings.
- Use JSON import/export for full-fidelity round trips.
Request body:
{
"name": "Fantasy Terms",
"content": "# Fantasy Terms\n\n## Entry: AI\n- **Type**: literal\n- **Replacement**: Artificial Intelligence\n- **Enabled**: true\n",
"activate": true
}
10. Import Dictionary (JSON)
POST /api/v1/chat/dictionaries/import/json
Request body:
{
"data": {
"name": "Fantasy Terms",
"entries": [
{"pattern": "car", "replacement": "carriage", "type": "literal"}
]
},
"activate": true
}
11. Export Dictionary (Markdown)
GET /api/v1/chat/dictionaries/{dictionary_id}/export
Notes:
- Markdown export is human-readable, but advanced fields such as timed effects,
max_replacements, and other non-standard metadata may not round-trip fully. - Prefer JSON export when you need guaranteed full-fidelity backup/restore behavior.
Response body:
{
"name": "Fantasy Terms",
"content": "# Fantasy Terms\n\ncar: carriage\nphone: sending stone\n",
"entry_count": 25,
"group_count": 3
}
12. Export Dictionary (JSON)
GET /api/v1/chat/dictionaries/{dictionary_id}/export/json
Notes:
- JSON export is the canonical full-fidelity format for dictionary backup, migration, and re-import.
Response body:
{
"name": "Fantasy Terms",
"description": "Convert modern terms to fantasy equivalents",
"entries": [
{"pattern": "car", "replacement": "carriage", "type": "literal", "probability": 1.0}
]
}
13. Update Dictionary
PUT /api/v1/chat/dictionaries/{dictionary_id}
Update dictionary metadata (name, description, is_active).
14. Delete Dictionary
DELETE /api/v1/chat/dictionaries/{dictionary_id}
15. Dictionary Statistics
GET /api/v1/chat/dictionaries/{dictionary_id}/statistics
Aggregate statistics for a dictionary (counts by type, groups, average probability, usage if available).
16. Validate Dictionary (New)
POST /api/v1/chat/dictionaries/validate
Validate dictionary structure, regex safety, and template syntax. Returns a structured report.
Request body:
{
"data": {
"name": "Example",
"entries": [
{"type": "literal", "pattern": "today", "replacement": "It is {{ now('%B %d') }}."},
{"type": "regex", "pattern": "User:(\\w+)", "replacement": "Hello, {{ match.group(1) }}!"}
]
},
"schema_version": 1,
"strict": false
}
Response body:
{
"ok": true,
"schema_version": 1,
"errors": [],
"warnings": [{"code": "regex_ambiguous", "field": "entries[1].pattern", "message": "…"}],
"entry_stats": {"total": 2, "regex": 1, "literal": 1},
"suggested_fixes": []
}
Semantics:
strict=false(default) returns a report witherrorsandwarningsbut does not cause the API call itself to fail; callers decide how to handle issues.strict=trueis intended for server-side workflows (e.g., Chatbooks import) where certain error classes (schema, regex safety/timeouts, template parse/forbidden constructs, output/size limits) should be treated as fatal.- Unknown or unsupported
schema_versionvalues still return HTTP 200 with aschema_invaliderror code in the response payload; HTTP 400 is reserved for malformed request bodies that do not matchValidateDictionaryRequest.
Planned additions (not yet implemented): Clone dictionary, toggle active status, bulk add/update entries, search entries across dictionaries.
World Book Manager API
Contextual lore injection for character conversations. Supports keyword-based entry matching and character-specific attachments.
Base URL
/api/v1/characters/world-books
Endpoints
1. Create World Book
POST /api/v1/characters/world-books
Request body:
{
"name": "Fantasy Campaign",
"description": "D&D campaign setting",
"scan_depth": 3,
"token_budget": 1000,
"recursive_scanning": true,
"enabled": true
}
Response body:
{
"id": 1,
"name": "Fantasy Campaign",
"description": "D&D campaign setting",
"scan_depth": 3,
"token_budget": 1000,
"recursive_scanning": true,
"enabled": true,
"version": 1,
"entry_count": 0,
"created_at": "2024-01-01T00:00:00Z",
"last_modified": "2024-01-01T00:00:00Z"
}
2. List World Books
GET /api/v1/characters/world-books
Query parameters:
include_disabled(boolean): Include disabled world books
Response body:
{
"world_books": [
{
"id": 1,
"name": "Fantasy Campaign",
"description": "D&D campaign setting",
"entry_count": 50,
"enabled": true,
"created_at": "2024-01-01T00:00:00Z"
}
],
"total": 1,
"enabled_count": 1,
"disabled_count": 0
}
3. Get World Book
GET /api/v1/characters/world-books/{world_book_id}
Response body:
{
"id": 1,
"name": "Fantasy Campaign",
"entries": [
{
"id": 1,
"keywords": ["dragon", "wyrm"],
"content": "Dragons are ancient magical beings",
"priority": 100,
"enabled": true
}
]
}
4. Add Entry
POST /api/v1/characters/world-books/{world_book_id}/entries
Request body:
{
"keywords": ["magic", "wizard", "spell"],
"content": "Magic in this world comes from ley lines",
"priority": 90,
"enabled": true
}
5. Update Entry
PUT /api/v1/characters/world-books/entries/{entry_id}
6. Delete Entry
DELETE /api/v1/characters/world-books/entries/{entry_id}
7. Attach to Character
POST /api/v1/characters/{character_id}/world-books
Request body:
{
"world_book_id": 1,
"enabled": true,
"priority": 0
}
8. Detach from Character
DELETE /api/v1/characters/{character_id}/world-books/{world_book_id}
9. Get Character World Books
GET /api/v1/characters/{character_id}/world-books
10. Process Context
POST /api/v1/characters/world-books/process
Request body:
{
"text": "Tell me about dragons and magic",
"character_id": 1,
"max_tokens": 1000
}
Response body:
{
"injected_content": "[World Info: Dragons are ancient magical beings...]\n[World Info: Magic in this world comes from ley lines...]",
"entries_matched": 2,
"tokens_used": 200,
"books_used": 1,
"entry_ids": [1, 2]
}
2. Attach World Book to Character
POST /api/v1/characters/{character_id}/world-books
Body:
{ "world_book_id": 10, "enabled": true, "priority": 100 }
3. Detach World Book from Character
DELETE /api/v1/characters/{character_id}/world-books/{world_book_id}
11. Search Entries
Not implemented. (Planned)
12. Import World Book
POST /api/v1/characters/world-books/import
Request body:
{
"world_book": {"name": "Imported World", "description": "Imported lore"},
"entries": [
{"keywords": ["test"], "content": "Test content", "priority": 100}
],
"merge_on_conflict": false
}
13. Export World Book
GET /api/v1/characters/world-books/{world_book_id}/export
14. Clone World Book
Not implemented. (Planned)
15. Delete World Book
DELETE /api/v1/characters/world-books/{world_book_id}
16. Bulk Update Entries
POST /api/v1/characters/world-books/entries/bulk
Request body:
{
"entry_ids": [1, 2, 3],
"operation": "disable"
}
17. Get Statistics
GET /api/v1/characters/world-books/{world_book_id}/statistics
Document Generator API
Creates structured documents from conversations. Supports multiple document types and async job management.
Base URL
/api/v1/chat/documents
Document Types
timelinestudy_guidebriefingsummaryq_and_ameeting_notes
Endpoints
1. Generate Document
POST /api/v1/chat/documents/generate
Request body (GenerateDocumentRequest):
{
"conversation_id": 123,
"document_type": "timeline",
"provider": "openai",
"model": "gpt-4o",
"api_key": "...",
"specific_message": null,
"custom_prompt": "Focus on technical decisions",
"stream": false,
"async_generation": false
}
Response (synchronous):
{
"document_id": 42,
"conversation_id": 123,
"document_type": "timeline",
"title": "Conversation Timeline",
"content": "Timeline...",
"provider": "openai",
"model": "gpt-4o",
"generation_time_ms": 2500,
"created_at": "2024-01-01T00:00:00Z"
}
Response (asynchronous):
{
"job_id": "job_456",
"status": "pending",
"conversation_id": 123,
"document_type": "timeline",
"message": "Document generation job created",
"created_at": "2024-01-01T00:00:00Z"
}
2. Get Document
GET /api/v1/chat/documents/{document_id}
3. List Documents
GET /api/v1/chat/documents
4. Delete Document
DELETE /api/v1/chat/documents/{document_id}
5. Get Generation Job Status
GET /api/v1/chat/documents/jobs/{job_id}
6. Cancel Generation Job
DELETE /api/v1/chat/documents/jobs/{job_id}
7. Save Prompt Configuration
POST /api/v1/chat/documents/prompts
8. Get Prompt Configuration
GET /api/v1/chat/documents/prompts/{document_type}
Query parameters:
conversation_id(integer, optional)document_type(enum, optional)limit(integer, default 50)
4. Delete Document
DELETE /api/v1/chat/documents/{document_id}
5. Bulk Generate
POST /api/v1/chat/documents/bulk
Request body (BulkGenerateRequest):
{
"conversation_ids": [123, 456],
"document_types": ["timeline", "summary", "q_and_a"],
"provider": "openai",
"model": "gpt-4o",
"api_key": "...",
"async_generation": true
}
6. Get Job Status
GET /api/v1/chat/documents/jobs/{job_id}
Response body (JobStatusResponse):
{
"job_id": "job_456",
"status": "completed",
"conversation_id": 123,
"document_type": "timeline",
"provider": "openai",
"model": "gpt-4o",
"result_content": "...",
"created_at": "2024-01-01T00:00:00Z",
"started_at": "2024-01-01T00:00:01Z",
"completed_at": "2024-01-01T00:00:05Z",
"progress_percentage": 100
}
7. Cancel Job
DELETE /api/v1/chat/documents/jobs/{job_id}
8. Save Prompt Config
POST /api/v1/chat/documents/prompts
Request body:
{
"document_type": "timeline",
"system_prompt": "You are a helpful document generator...",
"user_prompt": "Write a timeline...",
"temperature": 0.7,
"max_tokens": 2000
}
9. Get Prompt Config
GET /api/v1/chat/documents/prompts/{document_type}
10. Get Statistics
GET /api/v1/chat/documents/statistics
Chatbooks Import/Export API
Export/import collections of chat-related content with job management and secure downloads.
Interplay with Chatbook Tools (Dictionaries & Templates)
Chatbooks can include chat dictionaries and other template-aware content whose behavior is defined in the Chatbook Tools PRD and related APIs:
-
Embedded dictionaries are validated during
POST /api/v1/chatbooks/importusing the same validator exposed atPOST /api/v1/chat/dictionaries/validate. Validation findings (schema/regex/template issues) appear as per-item warnings/errors in Chatbook import job results. -
The
strictflag in/chat/dictionaries/validateis not forwarded directly from Chatbooks; instead, import always calls the validator withstrict=falseand uses theCHATBOOKS_IMPORT_DICT_STRICTenvironment flag to decide whether dictionaries with fatal errors are skipped or imported with warnings. -
Template-related manifest metadata (
metadata.template_mode,metadata.template_defaults,metadata.template_timezone,metadata.template_locale) controls template evaluation during Chatbook exports and imports. Thetemplate_modefield accepts three values:pass_through(default) — template expressions (e.g.{{ project }}) are preserved verbatim in the artifact. No rendering occurs.render_on_export— template expressions are evaluated at export time using the variables intemplate_defaults, the timezone fromtemplate_timezone(defaultUTC), and the locale fromtemplate_locale. The rendered result replaces the raw template in-place in the exported artifact (note markdown files, dictionary JSON files); the original raw template text is not retained alongside the rendered output.render_on_import— same rendering behavior, but applied at import time. The content stored in the database contains the rendered text, not the raw template.
Affected fields: note titles and content, dictionary names, descriptions, and entry
replacement/contentvalues. For dictionary entry rendering, theCHAT_DICT_TEMPLATES_ENABLEDenvironment flag must also be set totrue.Failure semantics: rendering uses a fail-safe strategy. If template evaluation fails for any reason (syntax error, undefined variable, timeout, output exceeding the size cap), the original raw template text is preserved unchanged in the artifact — the export or import is never aborted due to a render failure. Failures are logged at
DEBUGlevel and tracked via thetemplate_render_failure_totalmetrics counter (labeled by source and reason), but no error codes, warnings, or error metadata are surfaced to the client in the job result. To detect silent render failures, operators should monitor thetemplate_render_failure_totalandtemplate_render_timeout_totalmetrics.
Base URL
/api/v1/chatbooks
Endpoints
1. Export Chatbook
POST /api/v1/chatbooks/export
Request body (CreateChatbookRequest):
{
"name": "My Chatbook Export",
"description": "Backup of my conversations",
"content_selections": {
"conversation": ["conv123", "conv456"],
"note": ["note789"],
"character": ["char001"],
"world_book": [1],
"dictionary": [2],
"generated_document": [42]
},
"author": "Jane Doe",
"include_media": false,
"media_quality": "compressed",
"include_embeddings": false,
"include_generated_content": true,
"tags": ["backup"],
"categories": ["personal"],
"async_mode": true
}
Response body (async mode):
{
"success": true,
"job_id": "0c9d9a3a-6d1c-4c8f-9c84-9a0c2c2d8f77",
"status": "pending",
"message": "Export job created successfully"
}
2. Preview Chatbook (Upload)
POST /api/v1/chatbooks/preview
Preview an uploaded chatbook file (no import).
Request (multipart/form-data):
file: ZIP archive
Response body (manifest summary):
{
"manifest": {
"version": "1.0",
"name": "My Chatbook Export",
"total_conversations": 10,
"total_notes": 5,
"total_world_books": 2,
"total_dictionaries": 1,
"total_documents": 3,
"include_media": false
}
}
3. Get Export Job Status
GET /api/v1/chatbooks/export/jobs/{job_id}
Response body (ExportJobResponse):
{
"job_id": "0c9d9a3a-6d1c-4c8f-9c84-9a0c2c2d8f77",
"status": "completed",
"chatbook_name": "My Chatbook Export",
"download_url": "/api/v1/chatbooks/download/0c9d9a3a-6d1c-4c8f-9c84-9a0c2c2d8f77",
"file_size_bytes": 15900000,
"created_at": "2024-01-01T00:00:00Z",
"completed_at": "2024-01-01T00:00:30Z"
}
4. Download Export
GET /api/v1/chatbooks/download/{job_id}
Returns a ZIP file with secure headers.
5. Import Chatbook
POST /api/v1/chatbooks/import
Request (multipart/form-data):
file: The chatbook archive file (ZIP)- Additional fields (ImportChatbookRequest via form fields):
conflict_resolution: one ofskip,overwrite,rename,mergeprefix_imported: booleanimport_media: booleanimport_embeddings: booleanasync_mode: boolean
Response body (async mode):
{
"success": true,
"job_id": "import_job_456",
"status": "pending",
"message": "Import job created successfully"
}
6. Get Import Job Status
GET /api/v1/chatbooks/import/jobs/{job_id}
Response body (ImportJobResponse):
{
"job_id": "import_job_456",
"status": "completed",
"items_imported": 55,
"conflicts_found": 5,
"successful_items": 50,
"failed_items": 3,
"skipped_items": 2,
"conflicts": [],
"created_at": "2024-01-01T00:00:00Z",
"completed_at": "2024-01-01T00:01:00Z"
}
7. Validate Chatbook
No dedicated /validate endpoint. Use /chatbooks/preview (upload) to inspect a manifest without importing.
8. List Export Jobs
GET /api/v1/chatbooks/export/jobs
Query parameters:
limit(integer, default 100)offset(integer, default 0)
9. List Import Jobs
GET /api/v1/chatbooks/import/jobs
10. Cancel Export Job
DELETE /api/v1/chatbooks/export/jobs/{job_id}
11. Cancel Import Job
DELETE /api/v1/chatbooks/import/jobs/{job_id}
12. Remove Export Job
DELETE /api/v1/chatbooks/export/jobs/{job_id}/remove
13. Remove Import Job
DELETE /api/v1/chatbooks/import/jobs/{job_id}/remove
14. Clean Old Exports
POST /api/v1/chatbooks/cleanup
15. Service Health
GET /api/v1/chatbooks/health
Lightweight health indicator for the Chatbooks subsystem.
Error Responses
Endpoints return standard FastAPI error responses with meaningful HTTP status codes and a detail message. Some success responses include a success boolean for convenience (e.g., Chatbooks export/import). Domain-specific errors may include additional fields (see response schemas).
Rate Limiting
Endpoint-specific limits are enforced with RG policies where applied:
- Chatbooks
POST /export: 5/minute - Chatbooks
POST /import: 5/minute - Chatbooks
POST /preview: 10/minute - Chatbooks
GET /download/{job_id}: 20/minute
A global limiter may also be active depending on environment. When rate limits are hit, a 429 is returned.
Pagination
List endpoints use limit and offset query parameters and include a total count in the response body.
Webhooks
Webhook notifications for Chatbooks are planned but not yet implemented. See the Chatbook Developer Guide for design notes.
SDK Examples
Python
import json
from urllib.request import Request, urlopen
class ChatbookAPI:
def __init__(self, base_url, token):
self.base_url = base_url.rstrip("/")
self.headers = {"Authorization": f"Bearer {token}"}
def _request_json(self, method, path, payload):
url = f"{self.base_url}{path}"
data = json.dumps(payload).encode("utf-8")
headers = {"Content-Type": "application/json", **self.headers}
req = Request(url, data=data, headers=headers, method=method)
with urlopen(req) as resp:
return json.loads(resp.read().decode("utf-8"))
def create_dictionary(self, name, description):
return self._request_json(
"POST",
"/api/v1/chat/dictionaries",
{"name": name, "description": description},
)
def process_text(self, text, token_budget=1000, dictionary_id=None):
return self._request_json(
"POST",
"/api/v1/chat/dictionaries/process",
{"text": text, "token_budget": token_budget, "dictionary_id": dictionary_id},
)
JavaScript
class ChatbookAPI {
constructor(baseUrl, token) {
this.baseUrl = baseUrl;
this.headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
}
async exportChatbook(req) {
const response = await fetch(`${this.baseUrl}/api/v1/chatbooks/export`, {
method: 'POST',
headers: this.headers,
body: JSON.stringify(req)
});
return response.json();
}
async getExportStatus(jobId) {
const response = await fetch(
`${this.baseUrl}/api/v1/chatbooks/export/jobs/${jobId}`,
{ headers: this.headers }
);
return response.json();
}
}
Migration Guide
For users migrating from the TUI application:
- Authentication is required for all API calls.
- User content is isolated per-user (per-user DBs, per-user export/import paths).
- Large operations support async jobs with status polling and secure download URLs.
- Import conflict resolution supports
skip,overwrite,rename, andmerge. - Endpoint-level rate limiting is enforced; plan for 429 handling.
Chat Tools (Slash Commands)
Discovery endpoint for slash commands that run before LLM dispatch (e.g., /time, /weather, /skills, /skill).
Injection behavior (configurable):
CHAT_COMMAND_INJECTION_MODE=system(default): insert command result as a separatesystemmessage and strip the/commandtoken from the user's text.CHAT_COMMAND_INJECTION_MODE=preface: prefix the user's text with the command result.CHAT_COMMAND_INJECTION_MODE=replace: replace the user's text entirely with the command result.
List Commands (New)
GET /api/v1/chat/commands
Returns available commands (RBAC-filtered where applicable).
Response body:
{
"commands": [
{
"name": "time",
"description": "Show the current time (optional TZ).",
"required_permission": "chat.commands.time",
"usage": "/time [timezone]",
"args": ["timezone"],
"requires_api_key": true,
"rate_limit": "per-user 10/min, global 100/min",
"rbac_required": true
},
{
"name": "weather",
"description": "Show current weather for a location.",
"required_permission": "chat.commands.weather",
"usage": "/weather [location]",
"args": ["location"],
"requires_api_key": true,
"rate_limit": "per-user 10/min, global 100/min",
"rbac_required": true
},
{
"name": "skills",
"description": "List invocable skills for this user.",
"required_permission": "chat.commands.skills",
"usage": "/skills [filter]",
"args": ["filter"],
"requires_api_key": true,
"rate_limit": "per-user 10/min, global 100/min",
"rbac_required": true
},
{
"name": "skill",
"description": "Execute an invocable skill by name.",
"required_permission": "chat.commands.skill",
"usage": "/skill <name> [args]",
"args": ["name", "args"],
"requires_api_key": true,
"rate_limit": "per-user 10/min, global 100/min",
"rbac_required": true
}
]
}
Field definitions:
requires_api_key— whether invoking this command requires authenticated API access.
Notes:
- The
commandslist is filtered per-user based on AuthNZ/RBAC and deployment configuration. /skillsonly lists invocable skills (user_invocable=trueanddisable_model_invocation=false) for the authenticated user./skillreturns explicit error text for missing name, unknown skills, and non-invocable skills.- Clients should treat
GET /api/v1/chat/commandsas the per-session source of truth and avoid caching the list long-term, since RBAC or configuration changes can add or remove commands at any time.