Updated to version 1.2.6
This commit is contained in:
+154
-108
@@ -23,7 +23,12 @@
|
||||
<li><a href="#chat-badges">Capability Badges</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#files">Files</a></li>
|
||||
<li>
|
||||
<a href="#files">Files</a>
|
||||
<ul>
|
||||
<li><a href="#files-upload">Uploading Files</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#agents">Agents</a>
|
||||
<ul>
|
||||
@@ -92,7 +97,7 @@
|
||||
oAI-Web (agent name: <strong>{{ agent_name }}</strong>) is a secure, self-hosted personal AI agent
|
||||
built on the Claude API with full tool-use support. It runs on your home server and exposes a clean
|
||||
web interface for use inside your local network. The agent can read email, browse the web, manage
|
||||
calendar events, read and write files, send push notifications, generate images, and more — all via
|
||||
calendar events, read and write files, send push notifications, generate images, and more - all via
|
||||
a structured tool-use loop with optional confirmation prompts before side-effects.
|
||||
</p>
|
||||
|
||||
@@ -100,7 +105,7 @@
|
||||
<ul>
|
||||
<li>An API key for at least one AI provider: <strong>Anthropic</strong> or <strong>OpenRouter</strong></li>
|
||||
<li>Python 3.12+ (or Docker)</li>
|
||||
<li><strong>PostgreSQL</strong> (with asyncpg) — the main application database</li>
|
||||
<li><strong>PostgreSQL</strong> (with asyncpg) - the main application database</li>
|
||||
<li>PostgreSQL + <strong>pgvector</strong> extension only required if you use the <em>2nd Brain</em> feature (can be the same server)</li>
|
||||
</ul>
|
||||
|
||||
@@ -111,7 +116,7 @@
|
||||
<li>On first boot with zero users, you are redirected to <code>/setup</code> to create the first admin account</li>
|
||||
<li>Open <a href="/settings">Settings</a> → <strong>Credentials</strong> and add any additional credentials (CalDAV, email, Pushover, etc.)</li>
|
||||
<li>Add email recipients via <strong>Settings → Whitelists → Email Whitelist</strong></li>
|
||||
<li>Add filesystem directories via <strong>Settings → Whitelists → Filesystem Sandbox</strong> — the agent cannot touch any path outside these directories</li>
|
||||
<li>Add filesystem directories via <strong>Settings → Whitelists → Filesystem Sandbox</strong> - the agent cannot touch any path outside these directories</li>
|
||||
<li>Optionally set <code>system:users_base_folder</code> in Credentials to enable per-user file storage (e.g. <code>/data/users</code>)</li>
|
||||
<li>Optionally configure email accounts and Telegram via their respective Settings tabs</li>
|
||||
</ol>
|
||||
@@ -119,7 +124,7 @@
|
||||
<h2>Key Concepts</h2>
|
||||
<dl>
|
||||
<dt>Agent</dt>
|
||||
<dd>A configured AI persona with a model, system prompt, optional schedule, and restricted tool set. Agents run headlessly — no confirmation prompts, results logged in run history.</dd>
|
||||
<dd>A configured AI persona with a model, system prompt, optional schedule, and restricted tool set. Agents run headlessly - no confirmation prompts, results logged in run history.</dd>
|
||||
<dt>Tool</dt>
|
||||
<dd>A capability the AI can invoke: read a file, send an email, fetch a web page, generate an image, etc. Every tool call is logged in the Audit Log.</dd>
|
||||
<dt>Confirmation</dt>
|
||||
@@ -127,7 +132,7 @@
|
||||
<dt>Audit Log</dt>
|
||||
<dd>An append-only record of every tool call, its arguments, and outcome. Never auto-deleted unless you configure a retention period.</dd>
|
||||
<dt>Credential Store</dt>
|
||||
<dd>An AES-256-GCM encrypted key-value store in PostgreSQL. All secrets (API keys, passwords) live here — never in the agent's context window.</dd>
|
||||
<dd>An AES-256-GCM encrypted key-value store in PostgreSQL. All secrets (API keys, passwords) live here - never in the agent's context window.</dd>
|
||||
<dt>User Folder</dt>
|
||||
<dd>When <code>system:users_base_folder</code> is set, each user gets a personal folder at <code>{base}/{username}/</code>. Agents and the Files page scope all file access to this folder automatically.</dd>
|
||||
</dl>
|
||||
@@ -143,7 +148,7 @@
|
||||
<h2>Sending Messages</h2>
|
||||
<p>
|
||||
Press <kbd>Enter</kbd> to send. Use <kbd>Shift+Enter</kbd> for a newline within your message.
|
||||
The <strong>Clear History</strong> button (✕) in the status bar wipes the in-memory conversation for the current session — the agent starts fresh.
|
||||
The <strong>Clear History</strong> button (✕) in the status bar wipes the in-memory conversation for the current session - the agent starts fresh.
|
||||
</p>
|
||||
|
||||
<h2 id="chat-attachments">File Attachments</h2>
|
||||
@@ -151,7 +156,7 @@
|
||||
The <strong>paperclip button</strong> (📎) in the input bar opens a file picker. Only shown when the active model supports vision or documents. Supported formats:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Images</strong>: JPEG, PNG, GIF, WebP, AVIF — shown as thumbnails in the preview strip</li>
|
||||
<li><strong>Images</strong>: JPEG, PNG, GIF, WebP, AVIF - shown as thumbnails in the preview strip</li>
|
||||
<li><strong>PDF</strong>: shown as a file chip with the filename in the preview strip</li>
|
||||
</ul>
|
||||
<p>
|
||||
@@ -169,18 +174,18 @@
|
||||
<h2 id="chat-badges">Capability Badges</h2>
|
||||
<p>Small badges in the status bar show what the active model supports:</p>
|
||||
<ul>
|
||||
<li>🎨 <strong>Image Gen</strong> — can generate images (use via the <code>image_gen</code> tool in agents)</li>
|
||||
<li>👁 <strong>Vision</strong> — can read images and PDFs; the attachment button is shown</li>
|
||||
<li>🔧 <strong>Tools</strong> — supports tool/function calling</li>
|
||||
<li>🌐 <strong>Online</strong> — has live web access built in</li>
|
||||
<li>🎨 <strong>Image Gen</strong> - can generate images (use via the <code>image_gen</code> tool in agents)</li>
|
||||
<li>👁 <strong>Vision</strong> - can read images and PDFs; the attachment button is shown</li>
|
||||
<li>🔧 <strong>Tools</strong> - supports tool/function calling</li>
|
||||
<li>🌐 <strong>Online</strong> - has live web access built in</li>
|
||||
</ul>
|
||||
|
||||
<h2>Tool Indicators</h2>
|
||||
<p>While the agent is working, small badges appear below each message:</p>
|
||||
<ul>
|
||||
<li><span style="color:var(--accent)">●</span> <strong>Pulsing blue</strong> — tool is currently running</li>
|
||||
<li><span style="color:var(--green)">●</span> <strong>Solid green</strong> — tool completed successfully</li>
|
||||
<li><span style="color:var(--red)">●</span> <strong>Solid red</strong> — tool failed or returned an error</li>
|
||||
<li><span style="color:var(--accent)">●</span> <strong>Pulsing blue</strong> - tool is currently running</li>
|
||||
<li><span style="color:var(--green)">●</span> <strong>Solid green</strong> - tool completed successfully</li>
|
||||
<li><span style="color:var(--red)">●</span> <strong>Solid red</strong> - tool failed or returned an error</li>
|
||||
</ul>
|
||||
|
||||
<h2>Confirmation Modal</h2>
|
||||
@@ -210,16 +215,38 @@
|
||||
|
||||
<h2>Downloading</h2>
|
||||
<ul>
|
||||
<li><strong>Download</strong> — downloads an individual file.</li>
|
||||
<li><strong>↓ ZIP</strong> — downloads an entire folder (and its contents) as a ZIP archive. The <strong>Download folder as ZIP</strong> button in the header always downloads the current folder.</li>
|
||||
<li><strong>Download</strong> - downloads an individual file.</li>
|
||||
<li><strong>↓ ZIP</strong> - downloads an entire folder (and its contents) as a ZIP archive. The <strong>Download folder as ZIP</strong> button in the header always downloads the current folder.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="files-upload">Uploading Files</h2>
|
||||
<p>
|
||||
The <strong>Upload</strong> button (↑ arrow icon) in the header lets you upload one or more files directly into your current folder.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Click <strong>Upload</strong> and select one or more files from your device.</li>
|
||||
<li>Files are uploaded to whichever folder you are currently browsing - navigate to the target folder first.</li>
|
||||
<li>If a file with the same name already exists it will be overwritten without a prompt, so check the folder contents before uploading.</li>
|
||||
<li>The file list refreshes automatically once the upload completes.</li>
|
||||
</ul>
|
||||
<h3>Upload limits</h3>
|
||||
<p>Uploads are restricted by a policy configurable by your administrator under <strong>Settings → Security → File Upload Policy</strong>:</p>
|
||||
<ul>
|
||||
<li><strong>Allowed types</strong>: only common text/code files, images (JPG, PNG, GIF, WebP, SVG, …), and PDF are accepted by default. Files with other extensions are rejected.</li>
|
||||
<li><strong>Max file size</strong>: 50 MB per file (default).</li>
|
||||
<li><strong>Max files per upload</strong>: 20 files at once (default).</li>
|
||||
</ul>
|
||||
<p>Both limits are checked in the browser before the upload starts, and enforced again on the server. Rejected files are listed in a flash notification; accepted files in the same batch are still uploaded.</p>
|
||||
<p class="help-note">
|
||||
The Upload button is only shown when a data folder is configured for your account. If it is missing, ask your administrator to set <code>system:users_base_folder</code>.
|
||||
</p>
|
||||
|
||||
<h2>Deleting Files</h2>
|
||||
<p>
|
||||
A red <strong>Delete</strong> button appears next to downloadable files. Clicking it shows a confirmation dialog before the file is permanently removed. Deletion is instant and cannot be undone.
|
||||
</p>
|
||||
<p class="help-note">
|
||||
<strong>Protected files</strong>: files whose names start with <code>memory_</code> or <code>reasoning_</code> cannot be deleted from the UI. These are agent memory and decision logs maintained by email handling agents — deleting them would disrupt the agent's continuity.
|
||||
<strong>Protected files</strong>: files whose names start with <code>memory_</code> or <code>reasoning_</code> cannot be deleted from the UI. These are agent memory and decision logs maintained by email handling agents - deleting them would disrupt the agent's continuity.
|
||||
</p>
|
||||
|
||||
<h2>No Folder Configured?</h2>
|
||||
@@ -232,7 +259,7 @@
|
||||
<section id="agents" data-section>
|
||||
<h1>Agents</h1>
|
||||
<p>
|
||||
Agents are headless AI personas with a fixed system prompt, model, and optional cron schedule. Unlike interactive chat, agents run without confirmation modals — their allowed tools are declared at creation time. Results and token usage are logged per-run in the <a href="/agents">Agents</a> page.
|
||||
Agents are headless AI personas with a fixed system prompt, model, and optional cron schedule. Unlike interactive chat, agents run without confirmation modals - their allowed tools are declared at creation time. Results and token usage are logged per-run in the <a href="/agents">Agents</a> page.
|
||||
</p>
|
||||
<p class="help-note">
|
||||
Email handling agents (created automatically by Email Accounts setup) are hidden from the Agents list and Status tab. They are managed exclusively via <strong>Settings → Email Accounts</strong>.
|
||||
@@ -241,18 +268,18 @@
|
||||
<h2 id="agents-creating">Creating an Agent</h2>
|
||||
<p>Click <strong>New Agent</strong> on the Agents page. Required fields:</p>
|
||||
<ul>
|
||||
<li><strong>Name</strong> — displayed in the UI and logs</li>
|
||||
<li><strong>Model</strong> — any model from a configured provider</li>
|
||||
<li><strong>Prompt</strong> — the agent's task description or system prompt (see Prompt Modes below)</li>
|
||||
<li><strong>Name</strong> - displayed in the UI and logs</li>
|
||||
<li><strong>Model</strong> - any model from a configured provider</li>
|
||||
<li><strong>Prompt</strong> - the agent's task description or system prompt (see Prompt Modes below)</li>
|
||||
</ul>
|
||||
<p>Optional fields:</p>
|
||||
<ul>
|
||||
<li><strong>Description</strong> — shown in the agent list for reference</li>
|
||||
<li><strong>Schedule</strong> — cron expression for automatic runs</li>
|
||||
<li><strong>Allowed Tools</strong> — restrict which tools the agent may use</li>
|
||||
<li><strong>Max Tool Calls</strong> — per-run limit (overrides the system default)</li>
|
||||
<li><strong>Sub-agents</strong> — toggle to allow this agent to create child agents</li>
|
||||
<li><strong>Prompt Mode</strong> — controls how the prompt is composed (see below)</li>
|
||||
<li><strong>Description</strong> - shown in the agent list for reference</li>
|
||||
<li><strong>Schedule</strong> - cron expression for automatic runs</li>
|
||||
<li><strong>Allowed Tools</strong> - restrict which tools the agent may use</li>
|
||||
<li><strong>Max Tool Calls</strong> - per-run limit (overrides the system default)</li>
|
||||
<li><strong>Sub-agents</strong> - toggle to allow this agent to create child agents</li>
|
||||
<li><strong>Prompt Mode</strong> - controls how the prompt is composed (see below)</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="agents-schedule">Scheduling</h2>
|
||||
@@ -260,10 +287,10 @@
|
||||
<pre>minute hour day-of-month month day-of-week</pre>
|
||||
<p>Examples:</p>
|
||||
<ul>
|
||||
<li><code>0 8 * * 1-5</code> — weekdays at 08:00</li>
|
||||
<li><code>*/15 * * * *</code> — every 15 minutes</li>
|
||||
<li><code>0 9 * * 1</code> — every Monday at 09:00</li>
|
||||
<li><code>30 18 * * *</code> — every day at 18:30</li>
|
||||
<li><code>0 8 * * 1-5</code> - weekdays at 08:00</li>
|
||||
<li><code>*/15 * * * *</code> - every 15 minutes</li>
|
||||
<li><code>0 9 * * 1</code> - every Monday at 09:00</li>
|
||||
<li><code>30 18 * * *</code> - every day at 18:30</li>
|
||||
</ul>
|
||||
<p>
|
||||
Use the <strong>Enable / Disable</strong> toggle to pause a schedule without deleting the agent.
|
||||
@@ -278,12 +305,12 @@
|
||||
<dt>System only</dt>
|
||||
<dd>The standard system prompt is used as-is; the agent prompt becomes the task message sent to the agent. Useful when you want {{ agent_name }}'s full personality but just need to specify a recurring task.</dd>
|
||||
<dt>Agent only</dt>
|
||||
<dd>The agent prompt <em>fully replaces</em> the system prompt — no SOUL.md, no security rules, no USER.md context. Use with caution. Suitable for specialized agents with a completely different persona.</dd>
|
||||
<dd>The agent prompt <em>fully replaces</em> the system prompt - no SOUL.md, no security rules, no USER.md context. Use with caution. Suitable for specialized agents with a completely different persona.</dd>
|
||||
</dl>
|
||||
|
||||
<h2 id="agents-tools">Tool Restrictions</h2>
|
||||
<p>
|
||||
Leave <strong>Allowed Tools</strong> blank to give the agent access to all tools. Select specific tools to restrict — only those tool schemas are sent to the model, making it structurally impossible to use undeclared tools.
|
||||
Leave <strong>Allowed Tools</strong> blank to give the agent access to all tools. Select specific tools to restrict - only those tool schemas are sent to the model, making it structurally impossible to use undeclared tools.
|
||||
</p>
|
||||
<p>
|
||||
MCP server tools appear as a single server-level toggle (e.g. <code>Gitea MCP</code>), which enables all tools from that server. Individual built-in tools are listed separately.
|
||||
@@ -297,7 +324,7 @@
|
||||
|
||||
<h2>Image Generation in Agents</h2>
|
||||
<p>
|
||||
Agents can generate images using the <code>image_gen</code> tool. Important: the <strong>agent model must be a text/tool-use model</strong> (e.g. Claude Sonnet), not an image-generation model. The <code>image_gen</code> tool calls the image-gen model internally, saves the result to disk, and returns the file path. The default image-gen model is <code>openrouter:openai/gpt-5-image</code> — override via the <code>system:default_image_gen_model</code> credential.
|
||||
Agents can generate images using the <code>image_gen</code> tool. Important: the <strong>agent model must be a text/tool-use model</strong> (e.g. Claude Sonnet), not an image-generation model. The <code>image_gen</code> tool calls the image-gen model internally, saves the result to disk, and returns the file path. The default image-gen model is <code>openrouter:openai/gpt-5-image</code> - override via the <code>system:default_image_gen_model</code> credential.
|
||||
</p>
|
||||
<p>
|
||||
Generated images are saved to the agent's user folder. The file path is returned as the tool result so the agent can reference it.
|
||||
@@ -308,7 +335,7 @@
|
||||
<section id="monitors" data-section>
|
||||
<h1>Monitors</h1>
|
||||
<p>
|
||||
The <a href="/monitors">Monitors</a> page lets you watch web pages and RSS feeds for changes, then automatically dispatch an agent or send a Pushover notification when something new appears. Monitors run on a schedule in the background — no manual checking needed.
|
||||
The <a href="/monitors">Monitors</a> page lets you watch web pages and RSS feeds for changes, then automatically dispatch an agent or send a Pushover notification when something new appears. Monitors run on a schedule in the background - no manual checking needed.
|
||||
</p>
|
||||
|
||||
<h2 id="monitors-pages">Page Watchers</h2>
|
||||
@@ -317,18 +344,18 @@
|
||||
</p>
|
||||
<p>Fields when creating a page watcher:</p>
|
||||
<ul>
|
||||
<li><strong>Name</strong> — displayed in the monitor list</li>
|
||||
<li><strong>URL</strong> — the page to watch</li>
|
||||
<li><strong>Schedule</strong> — cron expression (e.g. <code>0 * * * *</code> = every hour)</li>
|
||||
<li><strong>CSS Selector</strong> — optional; restricts the hash to a specific element on the page (e.g. <code>#price</code> or <code>.headline</code>). Leave blank to watch the entire page.</li>
|
||||
<li><strong>Agent</strong> — agent to dispatch when a change is detected</li>
|
||||
<li><strong>Notification mode</strong> — <code>agent</code> (dispatch the agent), <code>pushover</code> (send a push notification), or <code>both</code></li>
|
||||
<li><strong>Name</strong> - displayed in the monitor list</li>
|
||||
<li><strong>URL</strong> - the page to watch</li>
|
||||
<li><strong>Schedule</strong> - cron expression (e.g. <code>0 * * * *</code> = every hour)</li>
|
||||
<li><strong>CSS Selector</strong> - optional; restricts the hash to a specific element on the page (e.g. <code>#price</code> or <code>.headline</code>). Leave blank to watch the entire page.</li>
|
||||
<li><strong>Agent</strong> - agent to dispatch when a change is detected</li>
|
||||
<li><strong>Notification mode</strong> - <code>agent</code> (dispatch the agent), <code>pushover</code> (send a push notification), or <code>both</code></li>
|
||||
</ul>
|
||||
<p>
|
||||
The table shows <strong>Last checked</strong> and <strong>Last changed</strong> timestamps. Use the <strong>Check now</strong> button to force an immediate check outside the schedule.
|
||||
</p>
|
||||
<p class="help-note">
|
||||
Page watchers use plain HTTP (not a real browser). For JavaScript-heavy pages where the interesting content is rendered client-side, the CSS selector approach may not work — the agent's browser tool is better suited for those.
|
||||
Page watchers use plain HTTP (not a real browser). For JavaScript-heavy pages where the interesting content is rendered client-side, the CSS selector approach may not work - the agent's browser tool is better suited for those.
|
||||
</p>
|
||||
|
||||
<h2 id="monitors-rss">RSS Feeds</h2>
|
||||
@@ -337,12 +364,12 @@
|
||||
</p>
|
||||
<p>Fields when creating an RSS monitor:</p>
|
||||
<ul>
|
||||
<li><strong>Name</strong> — displayed in the monitor list</li>
|
||||
<li><strong>Feed URL</strong> — any RSS or Atom feed URL</li>
|
||||
<li><strong>Schedule</strong> — cron expression (e.g. <code>0 */4 * * *</code> = every 4 hours)</li>
|
||||
<li><strong>Agent</strong> — agent to dispatch for new items</li>
|
||||
<li><strong>Max items per run</strong> — cap on how many new items trigger the agent in one run (default: 5)</li>
|
||||
<li><strong>Notification mode</strong> — <code>agent</code>, <code>pushover</code>, or <code>both</code></li>
|
||||
<li><strong>Name</strong> - displayed in the monitor list</li>
|
||||
<li><strong>Feed URL</strong> - any RSS or Atom feed URL</li>
|
||||
<li><strong>Schedule</strong> - cron expression (e.g. <code>0 */4 * * *</code> = every 4 hours)</li>
|
||||
<li><strong>Agent</strong> - agent to dispatch for new items</li>
|
||||
<li><strong>Max items per run</strong> - cap on how many new items trigger the agent in one run (default: 5)</li>
|
||||
<li><strong>Notification mode</strong> - <code>agent</code>, <code>pushover</code>, or <code>both</code></li>
|
||||
</ul>
|
||||
<p>
|
||||
Already-seen item IDs are tracked so the same item never triggers twice. The monitor sends <code>ETag</code> / <code>If-Modified-Since</code> headers to avoid downloading unchanged feeds unnecessarily. Use the <strong>Fetch now</strong> button to force an immediate run.
|
||||
@@ -362,7 +389,7 @@
|
||||
<li>Expose an SSE endpoint at <code>/sse</code></li>
|
||||
<li>Use <strong>SSE transport</strong> (not stdio)</li>
|
||||
<li>Be compatible with <code>mcp==1.26.*</code></li>
|
||||
<li>If built with Python FastMCP: use <code>uvicorn.run(mcp.sse_app(), host=..., port=...)</code> — <strong>not</strong> <code>mcp.run(host=..., port=...)</code> (the latter ignores <code>host</code>/<code>port</code> in mcp 1.26)</li>
|
||||
<li>If built with Python FastMCP: use <code>uvicorn.run(mcp.sse_app(), host=..., port=...)</code> - <strong>not</strong> <code>mcp.run(host=..., port=...)</code> (the latter ignores <code>host</code>/<code>port</code> in mcp 1.26)</li>
|
||||
<li>If connecting from a non-localhost IP (e.g. <code>192.168.x.x</code>): disable DNS rebinding protection:
|
||||
<pre>from mcp.server.transport_security import TransportSecuritySettings
|
||||
mcp = FastMCP(
|
||||
@@ -373,7 +400,7 @@ mcp = FastMCP(
|
||||
)</pre>
|
||||
Without this, the server rejects requests with a <code>421 Misdirected Request</code> error.
|
||||
</li>
|
||||
<li>oAI-Web connects per-call (open → use → close), <em>not</em> persistent — the server must handle this gracefully</li>
|
||||
<li>oAI-Web connects per-call (open → use → close), <em>not</em> persistent - the server must handle this gracefully</li>
|
||||
</ul>
|
||||
|
||||
<h2>Adding an MCP Server</h2>
|
||||
@@ -382,10 +409,10 @@ mcp = FastMCP(
|
||||
<li>Click <strong>Add Server</strong></li>
|
||||
<li>Enter:
|
||||
<ul>
|
||||
<li><strong>Name</strong> — display name; also used for tool namespacing (slugified)</li>
|
||||
<li><strong>URL</strong> — full SSE endpoint, e.g. <code>http://192.168.1.72:8812/sse</code></li>
|
||||
<li><strong>Transport</strong> — select <code>sse</code></li>
|
||||
<li><strong>API Key</strong> — optional bearer token if the server requires authentication</li>
|
||||
<li><strong>Name</strong> - display name; also used for tool namespacing (slugified)</li>
|
||||
<li><strong>URL</strong> - full SSE endpoint, e.g. <code>http://192.168.1.72:8812/sse</code></li>
|
||||
<li><strong>Transport</strong> - select <code>sse</code></li>
|
||||
<li><strong>API Key</strong> - optional bearer token if the server requires authentication</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Click <strong>Save</strong></li>
|
||||
@@ -395,7 +422,7 @@ mcp = FastMCP(
|
||||
<h2>Tool Namespacing</h2>
|
||||
<p>
|
||||
A server named <code>Gitea MCP</code> (slugified: <code>gitea_mcp</code>) exposes tools as <code>mcp__gitea_mcp__list_repos</code>, <code>mcp__gitea_mcp__create_issue</code>, etc.
|
||||
In the agent tool picker, the entire server appears as a single toggle — enabling it grants access to all of its tools.
|
||||
In the agent tool picker, the entire server appears as a single toggle - enabling it grants access to all of its tools.
|
||||
</p>
|
||||
|
||||
<h2>Refreshing Tool Discovery</h2>
|
||||
@@ -412,7 +439,7 @@ mcp = FastMCP(
|
||||
<h2 id="settings-general">General <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
||||
<ul>
|
||||
<li><strong>Agent Control</strong>: Pause / Resume the global kill switch</li>
|
||||
<li><strong>Runtime Limits</strong>: Max Tool Calls (per run) and Max Autonomous Runs per Hour — stored in the credential store for live override without restart</li>
|
||||
<li><strong>Runtime Limits</strong>: Max Tool Calls (per run) and Max Autonomous Runs per Hour - stored in the credential store for live override without restart</li>
|
||||
<li><strong>Trusted Proxy IPs</strong>: Comma-separated IPs for <code>X-Forwarded-For</code> trust (requires restart)</li>
|
||||
<li><strong>Users Base Folder</strong>: Set <code>system:users_base_folder</code> to an absolute path (e.g. <code>/data/users</code>) to enable per-user file storage. Each user's folder at <code>{base}/{username}/</code> is created automatically.</li>
|
||||
<li><strong>Audit Log Retention</strong>: Set a retention period in days (0 = keep forever); manual clear available</li>
|
||||
@@ -427,17 +454,17 @@ mcp = FastMCP(
|
||||
|
||||
<h2 id="settings-credentials">Credentials <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
||||
<p>
|
||||
A generic AES-256-GCM encrypted key-value store for API keys and other secrets. Keys use a <code>namespace:key</code> convention. Service-specific credentials (CalDAV, CardDAV, Pushover) are managed in their own dedicated tabs — they do not appear here. See the <a href="#credentials">Credential Key Reference</a> for a full list of system keys.
|
||||
A generic AES-256-GCM encrypted key-value store for API keys and other secrets. Keys use a <code>namespace:key</code> convention. Service-specific credentials (CalDAV, CardDAV, Pushover) are managed in their own dedicated tabs - they do not appear here. See the <a href="#credentials">Credential Key Reference</a> for a full list of system keys.
|
||||
</p>
|
||||
|
||||
<h2 id="settings-dav">DAV (CalDAV & CardDAV) <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
||||
<p>
|
||||
Configure CalDAV and CardDAV for the admin user. There is no system-wide fallback — every user configures their own credentials independently via this tab (admin) or the <strong>CalDAV / CardDAV</strong> tab (regular users).
|
||||
Configure CalDAV and CardDAV for the admin user. There is no system-wide fallback - every user configures their own credentials independently via this tab (admin) or the <strong>CalDAV / CardDAV</strong> tab (regular users).
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>CalDAV</strong>: server URL, username, password, and calendar name. Bare hostnames (e.g. <code>mail.example.com</code>) are accepted — <code>https://</code> is prepended automatically.</li>
|
||||
<li><strong>CalDAV</strong>: server URL, username, password, and calendar name. Bare hostnames (e.g. <code>mail.example.com</code>) are accepted - <code>https://</code> is prepended automatically.</li>
|
||||
<li><strong>CardDAV</strong>: tick <em>Same server as CalDAV</em> to reuse the same credentials, or enter a separate URL, username, and password. The SOGo URL pattern (<code>/SOGo/dav/{user}/Contacts/personal/</code>) is built automatically.</li>
|
||||
<li><strong>Allow contact writes</strong>: when enabled, agents can create, update, and delete contacts (not just read them). This is per-user — enabling it for your account does not affect other users.</li>
|
||||
<li><strong>Allow contact writes</strong>: when enabled, agents can create, update, and delete contacts (not just read them). This is per-user - enabling it for your account does not affect other users.</li>
|
||||
<li><strong>Test buttons</strong>: verify CalDAV and CardDAV connectivity without saving.</li>
|
||||
</ul>
|
||||
|
||||
@@ -446,7 +473,7 @@ mcp = FastMCP(
|
||||
Pushover sends push notifications to iOS and Android devices.
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>App Token</strong>: registered once at <a href="https://pushover.net" target="_blank">pushover.net</a> for this oAI-Web installation. Shared by all users — they cannot see or change it.</li>
|
||||
<li><strong>App Token</strong>: registered once at <a href="https://pushover.net" target="_blank">pushover.net</a> for this oAI-Web installation. Shared by all users - they cannot see or change it.</li>
|
||||
<li><strong>User Key</strong>: the admin's personal Pushover user key, shown on your pushover.net dashboard. Each user sets their own User Key in <strong>Settings → Pushover</strong>.</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
@@ -457,7 +484,7 @@ mcp = FastMCP(
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Trigger Rules</strong>: keyword phrases that, when matched in an incoming email subject/body, dispatch a specific agent and optionally send an auto-reply</li>
|
||||
<li>Matching is case-insensitive and order-independent — all tokens in the phrase must appear somewhere in the message</li>
|
||||
<li>Matching is case-insensitive and order-independent - all tokens in the phrase must appear somewhere in the message</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="settings-emailaccounts">Email Accounts</h2>
|
||||
@@ -491,10 +518,10 @@ mcp = FastMCP(
|
||||
{% if not (current_user and current_user.is_admin) %}
|
||||
<h2 id="settings-caldav">CalDAV / CardDAV</h2>
|
||||
<p>
|
||||
Configure your personal CalDAV and CardDAV connection. There is no system-wide fallback — if you don't configure it, the tools are unavailable to you.
|
||||
Configure your personal CalDAV and CardDAV connection. There is no system-wide fallback - if you don't configure it, the tools are unavailable to you.
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>CalDAV</strong>: server URL, username, password, and calendar name. Bare hostnames are accepted — <code>https://</code> is added automatically.</li>
|
||||
<li><strong>CalDAV</strong>: server URL, username, password, and calendar name. Bare hostnames are accepted - <code>https://</code> is added automatically.</li>
|
||||
<li><strong>CardDAV</strong>: tick <em>Same server as CalDAV</em> to reuse credentials, or enter separate details.</li>
|
||||
<li><strong>Allow contact writes</strong>: when enabled, agents can create, update, and delete contacts.</li>
|
||||
<li><strong>Test buttons</strong>: verify connectivity before saving.</li>
|
||||
@@ -502,18 +529,18 @@ mcp = FastMCP(
|
||||
|
||||
<h2 id="settings-pushover">Pushover</h2>
|
||||
<p>
|
||||
Set your personal <strong>User Key</strong> to receive push notifications on your Pushover-connected devices. Your User Key is shown on your <a href="https://pushover.net" target="_blank">pushover.net</a> dashboard. The App Token (the shared application credential) is managed by the admin — you only need your own User Key.
|
||||
Set your personal <strong>User Key</strong> to receive push notifications on your Pushover-connected devices. Your User Key is shown on your <a href="https://pushover.net" target="_blank">pushover.net</a> dashboard. The App Token (the shared application credential) is managed by the admin - you only need your own User Key.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<h2 id="settings-webhooks">Webhooks</h2>
|
||||
<p>
|
||||
Inbound webhooks let external services trigger agents via HTTP — useful for iOS Shortcuts, GitHub actions, Home Assistant automations, or any tool that can send an HTTP request.
|
||||
Inbound webhooks let external services trigger agents via HTTP - useful for iOS Shortcuts, GitHub actions, Home Assistant automations, or any tool that can send an HTTP request.
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Create a webhook</strong>: assign a name, description, and target agent. The secret token is shown <strong>once</strong> at creation — copy it immediately. Use <em>Rotate Token</em> to generate a new one if it is ever compromised.</li>
|
||||
<li><strong>Create a webhook</strong>: assign a name, description, and target agent. The secret token is shown <strong>once</strong> at creation - copy it immediately. Use <em>Rotate Token</em> to generate a new one if it is ever compromised.</li>
|
||||
<li><strong>Trigger via POST</strong>: <code>POST /webhook/{token}</code> with body <code>{"message": "..."}</code></li>
|
||||
<li><strong>Trigger via GET</strong>: <code>GET /webhook/{token}?q=your+message</code> — useful for iOS Shortcuts URL actions</li>
|
||||
<li><strong>Trigger via GET</strong>: <code>GET /webhook/{token}?q=your+message</code> - useful for iOS Shortcuts URL actions</li>
|
||||
<li><strong>Enable/disable</strong>: toggle a webhook on/off without deleting it</li>
|
||||
</ul>
|
||||
<p>The <strong>Outbound Targets</strong> section (same tab) manages named URLs that agents can send JSON payloads to via the <code>webhook</code> tool.</p>
|
||||
@@ -527,11 +554,26 @@ mcp = FastMCP(
|
||||
<li><strong>Two-Factor Authentication (TOTP)</strong>: enable/disable TOTP-based MFA. On setup, a QR code is shown to scan with any authenticator app (e.g. Aegis, Google Authenticator). Once enabled, every login requires a 6-digit code.</li>
|
||||
<li><strong>Data Folder</strong>: shows the path of your auto-provisioned personal folder (set by admin via <code>system:users_base_folder</code>). This folder is where the Files page browses and where agent memory files are stored.</li>
|
||||
<li><strong>Telegram Bot Token</strong>: per-user Telegram bot token (optional). Overrides the global token for your sessions.</li>
|
||||
<li><strong>SSH Key</strong>: generate a personal ed25519 SSH key pair stored in your data folder. See below.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="settings-ssh-key">SSH Key</h3>
|
||||
<p>
|
||||
The SSH Key section lets you generate an <strong>ed25519 key pair</strong> directly from the browser. The private key is stored in your data folder (<code>{your_folder}/.ssh/id_ed25519</code>) and never leaves the server. The public key is displayed so you can copy it to any remote server's <code>~/.ssh/authorized_keys</code>.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Click <strong>Generate SSH Key</strong> to create a new key pair. The registered email address is used as the key comment.</li>
|
||||
<li>If a key already exists, the button changes to <strong>Regenerate</strong> - doing so replaces the existing key pair. Any remote servers that trusted the old public key will need to be updated.</li>
|
||||
<li>Use the <strong>Copy</strong> button to copy the public key to the clipboard, then paste it into <code>~/.ssh/authorized_keys</code> on the remote server.</li>
|
||||
<li>Agents with bash tool access can use this key to run <code>scp</code> or <code>ssh</code> commands against remote servers that have the public key in their <code>authorized_keys</code>.</li>
|
||||
</ul>
|
||||
<p class="help-note">
|
||||
The SSH Key section only appears when a data folder is configured for your account. The global <code>~/.ssh/known_hosts</code> file (mounted from the host system) is still used for host key verification - if you get a host key error, connect manually from the server once to accept it.
|
||||
</p>
|
||||
|
||||
<h2 id="settings-personality">Personality</h2>
|
||||
<p>
|
||||
Edit <strong>SOUL.md</strong> (agent identity, values, communication style) and <strong>USER.md</strong> (owner context: name, location, preferences) directly in the browser. Changes take effect immediately — no restart required.
|
||||
Edit <strong>SOUL.md</strong> (agent identity, values, communication style) and <strong>USER.md</strong> (owner context: name, location, preferences) directly in the browser. Changes take effect immediately - no restart required.
|
||||
Both files are injected into every system prompt in order: SOUL.md → date/time → USER.md → security rules.
|
||||
</p>
|
||||
|
||||
@@ -563,15 +605,15 @@ mcp = FastMCP(
|
||||
<h2 id="settings-apikey">API Key <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
||||
<p>
|
||||
Protects the REST API for external programmatic access (scripts, home automations, other services, Swagger).
|
||||
The <strong>web UI always works without a key</strong> — a signed session cookie is set automatically on login.
|
||||
The <strong>web UI always works without a key</strong> - a signed session cookie is set automatically on login.
|
||||
The API key is only required for:
|
||||
</p>
|
||||
<ul>
|
||||
<li>External tools and scripts calling <code>/api/*</code> directly</li>
|
||||
<li>Swagger UI (<a href="/docs">/docs</a>) — click <strong>Authorize</strong> and enter the key</li>
|
||||
<li>Swagger UI (<a href="/docs">/docs</a>) - click <strong>Authorize</strong> and enter the key</li>
|
||||
</ul>
|
||||
<p>
|
||||
The raw key is shown <strong>once</strong> at generation time — copy it to your external tool. Only a SHA-256 hash is stored server-side. Regenerating invalidates the previous key immediately.
|
||||
The raw key is shown <strong>once</strong> at generation time - copy it to your external tool. Only a SHA-256 hash is stored server-side. Regenerating invalidates the previous key immediately.
|
||||
</p>
|
||||
<p>
|
||||
Use header <code>X-API-Key: <key></code> or <code>Authorization: Bearer <key></code> in external requests.
|
||||
@@ -606,7 +648,7 @@ mcp = FastMCP(
|
||||
|
||||
<h2>MFA Management</h2>
|
||||
<p>
|
||||
Users set up their own TOTP in <strong>Settings → Profile → Two-Factor Authentication</strong>. As admin, you can clear any user's MFA from the Users page (useful if they lose their authenticator). The <strong>Clear MFA</strong> button resets their TOTP secret — they must set it up again on next login.
|
||||
Users set up their own TOTP in <strong>Settings → Profile → Two-Factor Authentication</strong>. As admin, you can clear any user's MFA from the Users page (useful if they lose their authenticator). The <strong>Clear MFA</strong> button resets their TOTP secret - they must set it up again on next login.
|
||||
</p>
|
||||
|
||||
<h2>User Filesystem Scoping</h2>
|
||||
@@ -626,7 +668,7 @@ mcp = FastMCP(
|
||||
<table class="help-api-table">
|
||||
<thead><tr><th>Key</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>system:paused</code></td><td>Kill switch — set to <code>"1"</code> to pause all agent activity</td></tr>
|
||||
<tr><td><code>system:paused</code></td><td>Kill switch - set to <code>"1"</code> to pause all agent activity</td></tr>
|
||||
<tr><td><code>system:max_tool_calls</code></td><td>Live override of MAX_TOOL_CALLS env var</td></tr>
|
||||
<tr><td><code>system:max_autonomous_runs_per_hour</code></td><td>Live override of MAX_AUTONOMOUS_RUNS_PER_HOUR</td></tr>
|
||||
<tr><td><code>system:audit_retention_days</code></td><td>Days to keep audit entries (0 = keep forever)</td></tr>
|
||||
@@ -641,7 +683,7 @@ mcp = FastMCP(
|
||||
<tr><td><code>system:canary_rotated_at</code></td><td>Timestamp of last canary rotation (read-only)</td></tr>
|
||||
<tr><td><code>system:security_llm_screen_enabled</code></td><td>Option 3: LLM content screening enabled</td></tr>
|
||||
<tr><td><code>system:security_llm_screen_model</code></td><td>Model for LLM screening (default: google/gemini-flash-1.5)</td></tr>
|
||||
<tr><td><code>system:security_llm_screen_block</code></td><td>Option 3 block mode — block vs flag on UNSAFE verdict</td></tr>
|
||||
<tr><td><code>system:security_llm_screen_block</code></td><td>Option 3 block mode - block vs flag on UNSAFE verdict</td></tr>
|
||||
<tr><td><code>system:security_output_validation_enabled</code></td><td>Option 4: output validation for inbox sessions</td></tr>
|
||||
<tr><td><code>system:security_truncation_enabled</code></td><td>Option 5: content truncation</td></tr>
|
||||
<tr><td><code>system:security_max_web_chars</code></td><td>Max chars from web fetch (default: 20 000)</td></tr>
|
||||
@@ -650,7 +692,7 @@ mcp = FastMCP(
|
||||
<tr><td><code>system:security_max_subject_chars</code></td><td>Max chars of email subject (default: 200)</td></tr>
|
||||
<tr><td><code>telegram:bot_token</code></td><td>Global Telegram bot API token</td></tr>
|
||||
<tr><td><code>telegram:default_agent_id</code></td><td>UUID of agent for unmatched Telegram messages</td></tr>
|
||||
<tr><td><code>pushover_app_token</code></td><td>Pushover App Token — managed via <strong>Settings → Pushover</strong>, not this tab</td></tr>
|
||||
<tr><td><code>pushover_app_token</code></td><td>Pushover App Token - managed via <strong>Settings → Pushover</strong>, not this tab</td></tr>
|
||||
<tr><td><code>brain:mcp_key</code></td><td>2nd Brain MCP authentication key</td></tr>
|
||||
<tr><td><code>system:api_key_hash</code></td><td>SHA-256 hash of the external API key (raw key never stored)</td></tr>
|
||||
<tr><td><code>system:api_key_created_at</code></td><td>Timestamp of last API key generation</td></tr>
|
||||
@@ -705,8 +747,8 @@ mcp = FastMCP(
|
||||
<table class="help-api-table">
|
||||
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/api-key</code></td><td>Returns <code>{configured: bool, created_at}</code> — never returns the raw key</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/api-key</code></td><td>Generate a new key — returns <code>{key}</code> once only; invalidates previous key</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/api-key</code></td><td>Returns <code>{configured: bool, created_at}</code> - never returns the raw key</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/api-key</code></td><td>Generate a new key - returns <code>{key}</code> once only; invalidates previous key</td></tr>
|
||||
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/settings/api-key</code></td><td>Revoke the current key</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -849,6 +891,8 @@ mcp = FastMCP(
|
||||
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/files</code></td><td>Delete a file; param: <code>?path=</code>. Protected names (<code>memory_*</code>, <code>reasoning_*</code>) return 403.</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/files/download</code></td><td>Download a single file; param: <code>?path=</code></td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/files/download-zip</code></td><td>Download a folder as ZIP; param: <code>?path=</code></td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/files/upload</code></td><td>Upload one or more files to the user's folder; param: <code>?path=</code>, multipart form body</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/files/view</code></td><td>Return text file contents (max 512 KB); param: <code>?path=</code></td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/data-folder</code></td><td>Return the user's provisioned data folder path</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -864,7 +908,7 @@ mcp = FastMCP(
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/theme</code></td><td>Get current theme</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/theme</code></td><td>Set theme <code>{theme_id}</code></td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/mfa/status</code></td><td>Whether MFA is enabled for the current user</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/mfa/setup/begin</code></td><td>Start MFA setup — returns QR code PNG (base64) and provisioning URI</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/mfa/setup/begin</code></td><td>Start MFA setup - returns QR code PNG (base64) and provisioning URI</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/mfa/setup/confirm</code></td><td>Confirm setup with a valid TOTP code <code>{code}</code></td></tr>
|
||||
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/mfa/disable</code></td><td>Disable MFA for the current user</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/caldav/config</code></td><td>Get per-user CalDAV & CardDAV config</td></tr>
|
||||
@@ -876,6 +920,8 @@ mcp = FastMCP(
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/pushover</code></td><td>Save personal User Key <code>{user_key}</code></td></tr>
|
||||
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/pushover</code></td><td>Remove personal User Key</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/telegram/whitelisted-chats</code></td><td>List Telegram chat IDs whitelisted for the current user</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/ssh/pubkey</code></td><td>Return the user's SSH public key (or <code>{exists: false}</code> if not generated yet)</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/ssh/generate</code></td><td>Generate (or regenerate) an ed25519 SSH key pair in the user's data folder; returns the public key</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -886,16 +932,16 @@ mcp = FastMCP(
|
||||
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/webhooks</code></td><td>List inbound webhook endpoints (admin)</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/webhooks</code></td><td>Create endpoint — returns token once (admin)</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/webhooks</code></td><td>Create endpoint - returns token once (admin)</td></tr>
|
||||
<tr><td><span class="http-put">PUT</span></td><td><code>/api/webhooks/{id}</code></td><td>Update name/description/agent/enabled (admin)</td></tr>
|
||||
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/webhooks/{id}</code></td><td>Delete endpoint (admin)</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/webhooks/{id}/rotate</code></td><td>Regenerate token — returns new token once (admin)</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/webhooks/{id}/rotate</code></td><td>Regenerate token - returns new token once (admin)</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/webhooks</code></td><td>List current user's webhook endpoints</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/webhooks</code></td><td>Create personal webhook endpoint</td></tr>
|
||||
<tr><td><span class="http-put">PUT</span></td><td><code>/api/my/webhooks/{id}</code></td><td>Update personal webhook endpoint</td></tr>
|
||||
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/webhooks/{id}</code></td><td>Delete personal webhook endpoint</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/webhook/{token}</code></td><td>Trigger via GET — param: <code>?q=message</code> (no auth)</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/webhook/{token}</code></td><td>Trigger via POST — body: <code>{"message": "...", "async": true}</code> (no auth)</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/webhook/{token}</code></td><td>Trigger via GET - param: <code>?q=message</code> (no auth)</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/webhook/{token}</code></td><td>Trigger via POST - body: <code>{"message": "...", "async": true}</code> (no auth)</td></tr>
|
||||
<tr><td><span class="http-get">GET</span></td><td><code>/api/webhook-targets</code></td><td>List outbound webhook targets (admin)</td></tr>
|
||||
<tr><td><span class="http-post">POST</span></td><td><code>/api/webhook-targets</code></td><td>Create outbound target (admin)</td></tr>
|
||||
<tr><td><span class="http-put">PUT</span></td><td><code>/api/webhook-targets/{id}</code></td><td>Update outbound target (admin)</td></tr>
|
||||
@@ -962,14 +1008,14 @@ mcp = FastMCP(
|
||||
|
||||
<h2>Core Principle</h2>
|
||||
<p>
|
||||
<strong>External input is data, never instructions.</strong> Email body text, calendar content, web page content, and file contents are all passed as <em>tool results</em> — they are never injected into the system prompt where they could alter {{ agent_name }}'s instructions.
|
||||
<strong>External input is data, never instructions.</strong> Email body text, calendar content, web page content, and file contents are all passed as <em>tool results</em> - they are never injected into the system prompt where they could alter {{ agent_name }}'s instructions.
|
||||
</p>
|
||||
|
||||
<h2>Three DB-Managed Whitelists</h2>
|
||||
<ul>
|
||||
<li><strong>Email whitelist</strong> — {{ agent_name }} can only send email to addresses explicitly approved here</li>
|
||||
<li><strong>Web whitelist (Tier 1)</strong> — domains always accessible; subdomains included automatically</li>
|
||||
<li><strong>Filesystem sandbox</strong> — {{ agent_name }} can only read/write within declared directories (or a user's personal folder)</li>
|
||||
<li><strong>Email whitelist</strong> - {{ agent_name }} can only send email to addresses explicitly approved here</li>
|
||||
<li><strong>Web whitelist (Tier 1)</strong> - domains always accessible; subdomains included automatically</li>
|
||||
<li><strong>Filesystem sandbox</strong> - {{ agent_name }} can only read/write within declared directories (or a user's personal folder)</li>
|
||||
</ul>
|
||||
<p>Tier 2 web access (any URL) is only available in user-initiated chat sessions, never in autonomous agent runs.</p>
|
||||
|
||||
@@ -980,21 +1026,21 @@ mcp = FastMCP(
|
||||
|
||||
<h2>Confirmation Flow</h2>
|
||||
<p>
|
||||
In interactive chat, any tool with side effects (send email, write/delete files, send notifications, create/delete calendar events) triggers a confirmation modal. The agent pauses until you approve or deny. Agents running headlessly skip confirmations — their scope is declared at creation time.
|
||||
In interactive chat, any tool with side effects (send email, write/delete files, send notifications, create/delete calendar events) triggers a confirmation modal. The agent pauses until you approve or deny. Agents running headlessly skip confirmations - their scope is declared at creation time.
|
||||
</p>
|
||||
|
||||
<h2>Five Security Options</h2>
|
||||
<ol>
|
||||
<li><strong>Enhanced Sanitization</strong> — removes known prompt-injection patterns from all external content before it reaches the agent</li>
|
||||
<li><strong>Canary Token</strong> — a daily-rotating secret in the system prompt; any tool call argument containing the canary is blocked and triggers a Pushover alert, detecting prompt-injection exfiltration attempts</li>
|
||||
<li><strong>LLM Content Screening</strong> — a cheap secondary model screens fetched content for malicious instructions; operates in flag or block mode</li>
|
||||
<li><strong>Output Validation</strong> — prevents inbox auto-reply loops by blocking outbound emails back to the triggering sender</li>
|
||||
<li><strong>Content Truncation</strong> — enforces maximum character limits on web fetch, email, and file content to limit the attack surface of large malicious documents</li>
|
||||
<li><strong>Enhanced Sanitization</strong> - removes known prompt-injection patterns from all external content before it reaches the agent</li>
|
||||
<li><strong>Canary Token</strong> - a daily-rotating secret in the system prompt; any tool call argument containing the canary is blocked and triggers a Pushover alert, detecting prompt-injection exfiltration attempts</li>
|
||||
<li><strong>LLM Content Screening</strong> - a cheap secondary model screens fetched content for malicious instructions; operates in flag or block mode</li>
|
||||
<li><strong>Output Validation</strong> - prevents inbox auto-reply loops by blocking outbound emails back to the triggering sender</li>
|
||||
<li><strong>Content Truncation</strong> - enforces maximum character limits on web fetch, email, and file content to limit the attack surface of large malicious documents</li>
|
||||
</ol>
|
||||
|
||||
<h2>Audit Log</h2>
|
||||
<p>
|
||||
Every tool call — arguments, result summary, confirmation status, session ID, task ID — is written to an append-only audit log. Logs are never auto-deleted unless you configure a retention period. View them at <a href="/audit">Audit Log</a>.
|
||||
Every tool call - arguments, result summary, confirmation status, session ID, task ID - is written to an append-only audit log. Logs are never auto-deleted unless you configure a retention period. View them at <a href="/audit">Audit Log</a>.
|
||||
</p>
|
||||
|
||||
<h2>Kill Switch</h2>
|
||||
@@ -1004,7 +1050,7 @@ mcp = FastMCP(
|
||||
|
||||
<h2>No Credentials in Agent Context</h2>
|
||||
<p>
|
||||
API keys, passwords, and tokens are only accessed by the server-side tool implementations. The agent itself never sees a raw credential — it only receives structured results (e.g. a list of calendar events, a fetched page).
|
||||
API keys, passwords, and tokens are only accessed by the server-side tool implementations. The agent itself never sees a raw credential - it only receives structured results (e.g. a list of calendar events, a fetched page).
|
||||
</p>
|
||||
</section>
|
||||
|
||||
@@ -1036,16 +1082,16 @@ mcp = FastMCP(
|
||||
</p>
|
||||
<p>Built-in sub-commands (e.g. for keyword <code>work</code>):</p>
|
||||
<ul>
|
||||
<li><code>/work pause</code> — temporarily pause the email account's listener</li>
|
||||
<li><code>/work resume</code> — resume the listener</li>
|
||||
<li><code>/work status</code> — show the account's current status</li>
|
||||
<li><code>/work <any message></code> — pass the message to the handling agent</li>
|
||||
<li><code>/work pause</code> - temporarily pause the email account's listener</li>
|
||||
<li><code>/work resume</code> - resume the listener</li>
|
||||
<li><code>/work status</code> - show the account's current status</li>
|
||||
<li><code>/work <any message></code> - pass the message to the handling agent</li>
|
||||
</ul>
|
||||
<p class="help-note">
|
||||
Only the Telegram chat ID associated with the email account can use its keyword commands. Other chat IDs are rejected.
|
||||
</p>
|
||||
|
||||
<h2>Email Inbox — Trigger Accounts</h2>
|
||||
<h2>Email Inbox - Trigger Accounts</h2>
|
||||
<p>
|
||||
Trigger accounts use IMAP IDLE for instant push notification. When a new email arrives:
|
||||
</p>
|
||||
@@ -1064,15 +1110,15 @@ mcp = FastMCP(
|
||||
<li>Non-whitelisted sender + no trigger → <strong>silently dropped</strong> (reveals nothing to the sender)</li>
|
||||
</ul>
|
||||
|
||||
<h2>Email Inbox — Handling Accounts</h2>
|
||||
<h2>Email Inbox - Handling Accounts</h2>
|
||||
<p>
|
||||
Handling accounts poll every 60 seconds. A dedicated AI agent reads each new email and decides how to handle it. The agent has access to:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Email tool</strong> — list, read, mark as read, move, create folders</li>
|
||||
<li><strong>Filesystem tool</strong> — scoped to the user's data folder (if configured)</li>
|
||||
<li><strong>Memory files</strong> — <code>memory_<username>.md</code> (persistent notes) and <code>reasoning_<username>.md</code> (append-only decision log) are injected into each run</li>
|
||||
<li><strong>Telegram tool</strong> (optional) — bound to the account's associated chat ID; reply messages automatically include a <code>/keyword <reply></code> footer for easy follow-up</li>
|
||||
<li><strong>Email tool</strong> - list, read, mark as read, move, create folders</li>
|
||||
<li><strong>Filesystem tool</strong> - scoped to the user's data folder (if configured)</li>
|
||||
<li><strong>Memory files</strong> - <code>memory_<username>.md</code> (persistent notes) and <code>reasoning_<username>.md</code> (append-only decision log) are injected into each run</li>
|
||||
<li><strong>Telegram tool</strong> (optional) - bound to the account's associated chat ID; reply messages automatically include a <code>/keyword <reply></code> footer for easy follow-up</li>
|
||||
<li><strong>Pushover tool</strong> (optional, admin only)</li>
|
||||
</ul>
|
||||
|
||||
@@ -1081,8 +1127,8 @@ mcp = FastMCP(
|
||||
Both Telegram and email inbox use the same trigger-matching algorithm:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Case-insensitive</strong> — <code>URGENT</code> matches <code>urgent</code></li>
|
||||
<li><strong>Order-independent</strong> — all tokens in the trigger phrase must appear somewhere in the message, but not necessarily in sequence</li>
|
||||
<li><strong>Case-insensitive</strong> - <code>URGENT</code> matches <code>urgent</code></li>
|
||||
<li><strong>Order-independent</strong> - all tokens in the trigger phrase must appear somewhere in the message, but not necessarily in sequence</li>
|
||||
<li>Example: trigger phrase <code>daily report</code> matches <em>"Send me the report for the daily standup"</em> but also <em>"Daily summary report please"</em></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user